linux字元驅動之自動建立裝置節點
上一節中,我們是手工建立裝置節點,大家肯定也會覺得這樣做太麻煩了。
問:能不能讓系統自動建立裝置節點?
答:可以,linux有udev、mdev的機制,而我們的ARM開發板上移植的busybox有mdev機制,那麼就使用mdev機制來自動建立裝置節點。
問:檔案系統裡,在哪裡設定了mdev機制?
答:在etc/init.d/rcS檔案裡有一句:
echo /sbin/mdev > /proc/sys/kernel/hotplug
問:在驅動程式裡面如何編寫程式,讓系統自動建立裝置節點?
答:首先建立一個class類,然後在class類下,建立一個class_device,即類下面建立類的裝置。
詳細請參考驅動原始碼:
注意事項:#include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/module.h> #include <linux/device.h> //class_create static struct class *firstdrv_class; static struct device *firstdrv_device; int major; static int first_drv_open(struct inode * inode, struct file * filp) { printk("first_drv_open\n"); return 0; } static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos) { printk("first_drv_write\n"); return 0; } /* File operations struct for character device */ static const struct file_operations first_drv_fops = { .owner = THIS_MODULE, .open = first_drv_open, .write = first_drv_write, }; /* 驅動入口函式 */ static int first_drv_init(void) { /* 主裝置號設定為0表示由系統自動分配主裝置號 */ major = register_chrdev(0, "first_drv", &first_drv_fops); /* 建立firstdrv類 */ firstdrv_class = class_create(THIS_MODULE, "firstdrv"); /* 在firstdrv類下建立xxx裝置,供應用程式開啟裝置*/ firstdrv_device = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xxx"); return 0; } /* 驅動出口函式 */ static void first_drv_exit(void) { unregister_chrdev(major, "first_drv"); device_unregister(firstdrv_device); //解除安裝類下的裝置 class_destroy(firstdrv_class); //解除安裝類 } module_init(first_drv_init); //用於修飾入口函式 module_exit(first_drv_exit); //用於修飾出口函式 MODULE_AUTHOR("LWJ"); MODULE_DESCRIPTION("Just for Demon"); MODULE_LICENSE("GPL"); //遵循GPL協議
1.因韋老師使用的linux版本跟我使用的linux版本不一致,標頭檔案路徑可能有所變動。
2.使用的函式名可能也不一樣,例如:
韋老師是這樣子建立類和建立類的裝置:
一、定義
static struct class *firstdrv_class;
static struct class_device*firstdrv_class_dev;
二、入口函式裡
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */
三、出口函式裡
class_device_unregister(firstdrv_class_dev);
class_destroy(firstdrv_class);
而在linux2.6.30.4裡,並沒有class_device_create和class_device_unregister函式
我是這樣子建立類和建立類的裝置:
一、定義
static struct class *firstdrv_class;
static struct device *firstdrv_device;
二、入口函式裡
/* 建立firstdrv類 */
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
/* 在firstdrv類下建立xxx裝置,供應用程式開啟裝置*/
firstdrv_device = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xxx");
三、出口函式裡
device_unregister(firstdrv_device); //解除安裝類下的裝置
class_destroy(firstdrv_class);//解除安裝類
linux2.6.30.4使用device_create函式替代class_device_create函式;
使用device_unregister函式替代class_device_unregister函式。
測試程式和Makefile沒有修改,故再不貼。
測試步驟:
[WJ2440]# ls
Qt driver_test lib root udisk
TQLedtest etc linuxrc sbin usr
app_test first_drv.ko mnt sddisk var
bin first_test opt sys web
dev home proc tmp
[WJ2440]# ls -l /dev/xxx
ls: /dev/xxx: No such file or directory
[WJ2440]# insmod first_drv.ko
[WJ2440]# lsmod
first_drv 1912 0 - Live 0xbf000000
[WJ2440]# ls -l /dev/xxx
crw-rw---- 1 root root 252, 0 Jan 1 23:17 /dev/xxx
[WJ2440]# cat proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
14 sound
29 fb
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
180 usb
188 ttyUSB
189 usb_device
204 tq2440_serial
252 first_drv
253 usb_endpoint
254 rtc
Block devices:
259 blkext
7 loop
8 sd
31 mtdblock
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
[WJ2440]# cd /sys/class/
[WJ2440]# ls
bdi i2c-adapter misc scsi_device usb_endpoint
block i2c-dev mmc_host scsi_disk usb_host
firmware ieee80211 mtd scsi_host vc
firstdrv input net sound video4linux
graphics mem rtc tty vtconsole
[WJ2440]# cd firstdrv/
[WJ2440]# ls
xxx
[WJ2440]# cd xxx/
[WJ2440]# ls
dev subsystem uevent
[WJ2440]# cat dev
252:0
[WJ2440]# cat uevent
MAJOR=252
MINOR=0
[WJ2440]# cd /
[WJ2440]# ./first_test
first_drv_open
first_drv_write
[WJ2440]#