Framework for registering Linux kernel driver as class device / How to add new class to Linux kernel

Following simple driver code shows, how to add a new class with name “hello_as_class” can be added to linux kernel.

#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
 
#include <linux/device.h> // for struct class
 
 
static struct class hello_class = {
        .name = "hello_as_class",
        .owner = THIS_MODULE,
};
 
static int __init hello_init(void) {
 
        class_register(&hello_class);
 
        printk(KERN_INFO "Hello, world\n");
        return 0;
}
 
static void __exit hello_exit(void) {
 
        class_unregister(&hello_class);
 
        printk(KERN_INFO "Goodbye, world\n");
}
 
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

Now, we will write the makefile to get this code compiled as,

 $ vim Makefile 
obj-m += hello.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Compile this driver as,

 $ make 

Now insert the driver as,

 $ sudo insmod ./hello.ko 

We can check whether this driver is inserted or not as,

$ lsmod | grep hello 
hello   16384  0 

This driver will create a directory as, /sys/class/hello_as_class

 $ cd /sys/class/hello_as_class 

Now, if we see kernel source code, struct class has been declared in include/linux/device.h as,

/**
 * struct class - device classes
 * @name:       Name of the class.
 * @owner:      The module owner.
 * @class_attrs: Default attributes of this class.
 * @dev_groups: Default attributes of the devices that belong to the class.
 * @dev_kobj:   The kobject that represents this class and links it into the hierarchy.
 * @dev_uevent: Called when a device is added, removed from this class, or a
 *              few other things that generate uevents to add the environment
 *              variables.
 * @devnode:    Callback to provide the devtmpfs.
 * @class_release: Called to release this class.
 * @dev_release: Called to release the device.
 * @suspend:    Used to put the device to sleep mode, usually to a low power
 *              state.
 * @resume:     Used to bring the device from the sleep mode.
 * @shutdown:   Called at shut-down time to quiesce the device.
 * @ns_type:    Callbacks so sysfs can detemine namespaces.
 * @namespace:  Namespace of the device belongs to this class.
 * @pm:         The default device power management operations of this class.
 * @p:          The private data of the driver core, no one other than the
 *              driver core can touch this.
 *
 * A class is a higher-level view of a device that abstracts out low-level
 * implementation details. Drivers may see a SCSI disk or an ATA disk, but,
 * at the class level, they are all simply disks. Classes allow user space
 * to work with devices based on what they do, rather than how they are
 * connected or how they work.
 */
struct class {
        const char              *name;
        struct module           *owner;

        struct class_attribute          *class_attrs;
        const struct attribute_group    **dev_groups;
        struct kobject                  *dev_kobj;

        int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
        char *(*devnode)(struct device *dev, umode_t *mode);

        void (*class_release)(struct class *class);
        void (*dev_release)(struct device *dev);

        int (*suspend)(struct device *dev, pm_message_t state);
        int (*resume)(struct device *dev);
        int (*shutdown)(struct device *dev);

        const struct kobj_ns_type_operations *ns_type;
        const void *(*namespace)(struct device *dev);

        const struct dev_pm_ops *pm;

        struct subsys_private *p;
};

Reference : Kernel.org

Leave a Comment