開始學習驅動的時候,是將驅動程式編譯成模組然後用mknod命令手動建立裝置節點以提供給應用程式調用。這對於剛開始調試驅動程式的時候常用的一種方法。但是,當有種需要必須在系統啟動的時候就將驅動程式就緒,來供應用程式層程式調用。這時就不能再手動的建立裝置節點了,而必須自動的建立裝置節點(不需要人為的操作)。
★註冊類
註冊類的目的是為了使mdev可以在/dev/目錄下建立裝置節點。
首先要定義一個類,利用struct class結構體。這個結構體定義在標頭檔include/linux/device.h中
struct class {const char* name;struct module* owner;struct subsystemsubsys;struct list_headchildren;struct list_headdevices;struct list_headinterfaces;struct semaphoresem;/* 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 //Msint 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);