1. 程式人生 > >linux字元驅動之自動建立裝置節點

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_createclass_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]#