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

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix