Driving Me Nuts - Device Classes

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

This function looks almost like the i2c_adapter class registration code, with two exceptions. First, the class_dev.dev field is set to be either the adapter's parent device or the adapter's device. This is done because some i2c adapters do not have a real parent in the global kernel device tree, as they live on a bus that has not been converted to the kernel driver model (like ISA) or they do not really live on a bus at all (like some i2c embedded controllers). When an i2c adapter does not have a place in the kernel device tree, it is assigned to the legacy bus. The legacy bus, located at /sys/devices/legacy, is used for these kinds of devices.

The second thing that is different with this class device is the line:


class_device_create_file (&i2c_dev->class_dev, &class_device_attr_dev);

The class_device_create_file function is used to create a file in the class device's directory. The filename and attributes are defined with the CLASS_DEVICE_ATTR macro as:


static ssize_t
show_dev(struct class_device *class_dev, char *buf)
{
   struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
   return sprintf(buf, "%04x\n",
                  MKDEV(I2C_MAJOR, i2c_dev->minor));
}
static
CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);

The CLASS_DEVICE_ATTR macro is itself defined as:


#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) \
struct class_device_attribute                       \
class_device_attr_##_name = { 	                    \
    .attr  = {.name = __stringify(_name),           \
              .mode = _mode },                      \
    .show  = _show,                                 \
    .store = _store,                                \
};

The arguments within the CLASS_DEVICE_ATTR macro are:

  • _name: both the name of the file to be created in sysfs and part of the variable name that describes this whole attribute.

  • _mode: the file access mode with which the file is created. Use the standard access macros to specify the proper value.

  • _show: points to a function that is called when the file is read from. This function must have the following return value and parameters. This variable does not have to be set if the file is not to be read from.

    ssize_t
    show (struct class_device *class_dev, char *buf);
    

  • _store: points to a function that is called when the file is written to. This function must have the following return value and paramaters. This variable does not have to be set if the file is not to be written to.

    ssize_t
    store (struct device *dev, const char *buf,
           size_t count);
    

Almost all driver model structures have an ATTR() macro that declares a file within the sysfs tree.

In this example, a file named dev is created when the class_device_create_file function is called. This file is created to be read-only by any user. If the file is read from, the show_dev function is called by the driver core. The show_dev function fills in the buffer passed to it with the information it wants to give the user. In this case, the major and minor number for this specific device are passed to the user. All class devices using a major and minor number should have a dev file within their sysfs class device directory.

The class_device_remove_file function can be used to remove any files created by the class_device_create_file function. But it is not necessary to remove manually any file created if the device is about to be removed. When devices are removed from sysfs, all files created in their directories are removed automatically by the sysfs core. So, when the i2c-dev class device is removed from the system, all that is needed is the following:


static void
i2c_remove_class_device(int minor)
{
    struct i2c_dev *i2c_dev = NULL;
    struct list_head *tmp;
    int found = 0;

    spin_lock(&i2c_dev_list_lock);
    list_for_each (tmp, &i2c_dev_list) {
        i2c_dev = list_entry(tmp, struct i2c_dev,
                             node);
        if (i2c_dev->minor == minor) {
            found = 1;
            break;
        }
    }
    if (found) {
        list_del(&i2c_dev->node);
        spin_unlock(&i2c_dev_list_lock);
        class_device_unregister(&i2c_dev->class_dev);
        kfree(i2c_dev);
    } else {
    spin_unlock(&i2c_dev_list_lock);
    }
}

______________________

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