開始學習驅動的時候,是將驅動程序編譯成模塊然後用mknod命令手動建立設備節點以提供給應用程序調用。這對於剛開始調試驅動程序的時候常用的一種方法。但是,當有種需要必須在系統啟動的時候就將驅動程序就緒,來供應用層程序調用。這時就不能再手動的建立設備節點了,而必須自動的創建設備節點(不需要人為的操作)。
注冊類的目的是為了使mdev可以在/dev/目錄下建立設備節點。
首先要定義一個類,利用struct class結構體。這個結構體定義在頭文件include/linux/device.h中
struct class { const char * name; struct module * owner; struct subsystem subsys; struct list_head children; struct list_head devices; struct list_head interfaces; struct semaphore sem; /* locks both the children and interfaces lists */ struct kobject *virtual_dir; struct class_attribute * class_attrs; struct class_device_attribute * class_dev_attrs; struct device_attribute * dev_attrs; int (*uevent)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size); int (*dev_uevent)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); void (*release)(struct class_device *dev); void (*class_release)(struct class *class); void (*dev_release)(struct device *dev); int (*suspend)(struct device *, pm_message_t state); int (*resume)(struct device *); }
然後使用
完成對類的注冊。其中第一個參數一般為:THIS_MODULE。第二個參數為:設備節點的名稱
舉個例子:
創建設備節點的函數:
<pre name="code" class="cpp">struct device *device_create(struct class *class, struct device *parent,dev_t devt, const char *fmt, ...) { va_list args; struct device *dev = NULL; int retval = -ENODEV; if (class == NULL || IS_ERR(class)) goto error; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { retval = -ENOMEM; goto error; } dev->devt = devt; dev->class = class; dev->parent = parent; dev->release = device_create_release; va_start(args, fmt); vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); va_end(args); retval = device_register(dev); if (retval) goto error; return dev; error: kfree(dev); return ERR_PTR(retval); }該函數的四個參數從左到右以此為:創建設備節點所屬的類、該設備的父節點(若果沒有就指定為NULL)、設備號、設備名稱、次設備號。
注意不要忘記了還要銷毀類和銷毀設備節點。
銷毀類:參數為用struct class結構體定義的變量
void class_destroy(struct class *cls) { if ((cls == NULL) || (IS_ERR(cls))) return; class_unregister(cls); }銷毀設備節點:
void device_destroy(struct class *class, dev_t devt) { struct device *dev = NULL; struct device *dev_tmp; down(&class->sem); list_for_each_entry(dev_tmp, &class->devices, node) { if (dev_tmp->devt == devt) { dev = dev_tmp; break; } } up(&class->sem); if (dev) device_unregister(dev); }
#include <linux/miscdevice.h> #include <linux/delay.h> #include <asm/irq.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/unistd.h> #include <linux/string.h> #include <linux/fcntl.h> #include <asm/uaccess.h> #include <linux/kdev_t.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/version.h> #include <linux/config.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/sched.h> #include <linux/device.h> #define NAME "ralink_drive_delay" #define RALINK_GPIO_DEVNAME "my_delay" #define delay_us 0 //most least is 10 US #define delay_ms 1 //Ms int delay_MAJOR = 109; MODULE_LICENSE("Dual BSD/GPL"); static long Ralink_delay_ioctl(struct inode * inode, struct file * file, unsigned int cmd,unsigned long arg) { switch(cmd) { case delay_us: udelay(10 * arg); return 0; case delay_ms: udelay(1000); return 0; default: return -1; } } static struct file_operations My_delay_fops = { .owner = THIS_MODULE, .ioctl = Ralink_delay_ioctl, }; static struct class *delay_class; static int __init my_delay_init(void) { int ret = 0; ret = register_chrdev(delay_MAJOR, RALINK_GPIO_DEVNAME,&My_delay_fops); if(ret < 0) { printk("unable to register character device\n"); return ret; } if (delay_MAJOR == 0) { delay_MAJOR = ret; printk(KERN_DEBUG NAME ": got dynamic major %d\n", ret); } //注冊一個類,使mdev可以在"/dev/目錄下建立設備節點" delay_class = class_create(THIS_MODULE, RALINK_GPIO_DEVNAME); if(IS_ERR(delay_class)) { printk("failed in My_led class.\n"); return -1; } device_create(delay_class, NULL, MKDEV(delay_MAJOR, 0),RALINK_GPIO_DEVNAME 0);// //第一個參數是所要創建的設備所從屬的類 //第二個參數是這個設備的父節點,沒有指定就是NULL //第三個參數是設備號 //第四個參數是設備名稱 //第五個參數是從設備號 printk("my_delay driver initialized\n"); return 0; } void __exit my_delay_exit(void) { unregister_chrdev(delay_MAJOR,RALINK_GPIO_DEVNAME); device_destroy(delay_class,MKDEV(delay_MAJOR,0));//注銷設備節點 class_destroy(delay_class);//銷毀類 printk("my_delay driver exited\n"); } module_init(my_delay_init); module_exit(my_delay_exit);