Driving Me Nuts - Device Classes

More necessary instructions for making your new device driver play nice in the 2.6 kernel.

First, the struct class_device variable (embedded in the struct i2c_adapter variable) is initialized to zero. All driver model structures need to have all variables set to zero before they are registered, in order for the driver core to use them properly.

Then the dev variable is set to point to the i2c_adapter's struct device variable; in this case, the same structure, struct i2c_adapter, contains both a struct device and a struct class_device. The class variable is set to the address of the i2c_adapter_class variable, and then the class_id variable is set to the same value as the device's bus_id. Because the i2c_adapter device's bus_id is unique, it also ensures that the i2c_adapter class_device's class_id is unique. Finally, the class device structure is registered with the kernel driver core by a call to the class_device_register function.

With the above code and two i2c adapters loaded on a test machine, the /sys/class/i2c_adapter tree might look like the following:


$ tree /sys/class/i2c-adapter/
/sys/class/i2c-adapter/
|-- i2c-0
|   |-- device -> ../../../devices/pci0/00:07.3/i2c-0
|   `-- driver -> ../../../bus/i2c/drivers/i2c_adapter
`-- i2c-2
    |-- device -> ../../../devices/legacy/i2c-2
    `-- driver -> ../../../bus/i2c/drivers/i2c_adapter

As you can see by the above tree output, a device and driver symbolic link are created automatically by the driver core to point to the proper place within the sysfs tree that represents those values. If the dev pointer was not set to point to a struct device, those symbolic links would not have been created. If you look in the /sys/class/tty directory, the majority of those class device entries do not have a corresponding struct device, so those symbolic links are not present.

Class Interfaces

Class interfaces simply are a way for your code to be notified whenever a struct class_device is registered or unregistered from a specific class. A class interface is defined with the struct class_interface structure. This structure is simple and looks like:


struct class_interface {
    struct list_head  node;
    struct class      *class;
    int (*add)        (struct class_device *);
    void (*remove)    (struct class_device *);
};

The class variable needs to be set to the class about which we want to be notified. The add and remove variables should be set to a function that is called when any devices are added or removed, respectively, from that class. It is not necessary to set both the add and remove variables if you do not want to be notified about one of those events.

To register a class interface with the kernel, the class_interface_register function is called. Likewise, to unregister a class interface, the class_interface_unregister function is called. An example of code that uses class interfaces is the CPU frequency core; this code can be found at kernel/cpufreq.c in the kernel source tree.

Creating Files

As described above, the i2c-adapter class is useful for easily determining all of the different i2c adapters present in the system and their specific location in the driver tree. But i2c adapters are not directly addressable by a user. To talk to an i2c adapter, an i2c chip driver needs to be loaded, or the i2c-dev driver can be used. The i2c-dev driver provides a character driver interface to all i2c adapters present in the system. Because it is useful to determine exactly which i2c-dev devices are attached to which i2c adapters, a i2c-dev class was created:


static struct class i2c_dev_class = {
    .name	= "i2c-dev"
};

Then, when every i2c adapter is found by the i2c-dev driver, a new i2c class device is added to the driver core. This addition is done in the i2c_add_class_device function:


static void
i2c_add_class_device(char *name, int minor,
                     struct i2c_adapter *adap)
{
   struct i2c_dev *i2c_dev;
   int retval;

   i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL);
   if (!i2c_dev)
       return;
   memset(i2c_dev, 0x00, sizeof(*i2c_dev));

   if (adap->dev.parent == &legacy_bus)
       i2c_dev->class_dev.dev = &adap->dev;
   else
       i2c_dev->class_dev.dev = adap->dev.parent;
   i2c_dev->class_dev.class = &i2c_dev_class;
   snprintf(i2c_dev->class_dev.class_id,
            BUS_ID_SIZE, "%s", name);
   retval =
       class_device_register(&i2c_dev->class_dev);
   if (retval)
       goto error;
   class_device_create_file (&i2c_dev->class_dev,
                             &class_device_attr_dev);
   i2c_dev->minor = minor;
   spin_lock(&i2c_dev_list_lock);
   list_add(&i2c_dev->node, &i2c_dev_list);
   spin_unlock(&i2c_dev_list_lock);
   return;
error:
   kfree(i2c_dev);
}

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Re: Device Classes

Anonymous's picture

Cool description of sysfs, i wonder if it is possible to describe how a user-space app (kde, gnome, etc) could use it to some benefit for it

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState