驱动设备文件

/* 整理于2012.11.21 于广工大 */

要知道在Linux系统中,一切皆文件,一个底层设备的驱动程序固然也不例外,它以一种有异于普通文件的设备文件的身份幸存在于fs当中,设备文件与保存数据或读取存储数据的普通文件不同,它只提供可调用内核内部函数的信息:设备驱动程序类型(字符型/块型)、主设备号、次设备号。

应用程序为了使用设备,向内核申请控制设备,此时内核利用上述的3种信息中的设备驱动程序类型信息和主设备号,调用相应的设备驱动程序。至于次设备号,它只用作区分同一类设备驱动程序下的不同设备。

应用程序要操纵外部硬件设备,需要像对待普通文件一样,对此硬件对应的设备文件open()read()write(),···一系列的系统调用,从而实现了对外部设备的间接操纵。一个设备驱动往内核中注册后,要想在/dev目录下创建这样的一个相应设备文件,可通过如下两种方式实现:

 

1.手动创建

  insmod xxx.ko装载xxx驱动后,利用mknod命令手动创建相应设备节点:

mknod /dev/xxx c major minor  /* c表示此为字符设备,major –主设备号,minor-次设备号 */

mknod /dev/xxx b major minor  /* b表示此为块设备,major –主设备号,minor-次设备号 */

注意:可查看Documentation/device.txt文件预先确定可用的设备号,或,cat /proc/devices确定哪些设备号已经被用。

mknod 之后,可通过ls /dev查看,如有xxx,代表已经成功创建xxx设备节点。

 

2. 模块加载时候自动创建

内核中定义了struct class结构体,一个struct class结构体类型变量对应着一个类,内核提供了class_create()函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create()函数来在/dev目录下创建相应的设备节点。

这样,加载模块的时候,用户空间中的udev会自动响应device_create()函数,去/sysfs下寻找对应的类从而创建设备节点。

#define class_create(owner, name)           \

({                                    \

    static structlock_class_key __key; \

    __class_create(owner, name,&__key); \

})

 

owner-此类是属于哪个设备的,此值通常为THIS_MODULE,表示调用此函数的模块;

name-此类的名字,随便起;

返回值为struct class *类型,即为要创建的类的指针地址。

紧接着,类下创建相应的节点,通过device_create()函数:

extern struct device *device_create(struct class *cls, struct device*parent,

                             dev_t devt, void *drvdata,

                            const char *fmt, ...)

                             __attribute__((format(printf, 5, 6)));

cls-类的地址,即为此前device_create()返回的struct class *类型值;

parent-父类的地址,有就填,没有父类的,即为NULL值;

devt-设备的主次设备号,即为MKDEV(major,minor)

drvdata-设备值,只用作设备辨别用,有就填,没有就填NULL,有没有倒没多大的影响;

const char *fmt-设备节点的名字,即ls /dev/fmt

 

注意,在2.6较早的内核版本中,device_create()函数名称不同,是class_device_create(),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称不同而已,而且里面的参数设置也有一些微小的变化。

struct classdevice_create()以及device_create()都定义在linux/device.h中,使用的时候一定要包含这个头文件,否则编译器会报错。

 

下面给出一个使用实例:

 

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/fs.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/of_device.h>    

int device_driver_major_number;  /* 设备的主设备号 */
static struct class *user_drv_class;	/* 创建类,系统自动生成设备节点 */
static struct class_device *user_drv_class_dev;	/* 类下创建设备 */

static int user_drv_open(struct inode *inode, struct file *file)
{
}
static ssize_t user_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
}
static ssize_t user_drv_read(struct file *file, char __user *user, size_t size,loff_t*o)
{
}

/* 创建设备结构 file_operations*/
static struct file_operations user_drv_fops = {
	.owner	 = THIS_MODULE,   
	.open	 = user_drv_open,     
	.write	 = user_drv_write,	   
	.read	 = user_drv_read,
};

/* 注册模块 */
static int user_drv_init(void)
{
	/* 注册设备 */
	device_driver_major_number = register_chrdev(0, "user_drv_name", &user_drv_fops); 

	/* 注册类class_drv_name */
	user_drv_class = class_create(THIS_MODULE, "class_drv_name");  

	/* 注册类下设备device_inode_name,/dev/device_inode_name */
	user_drv_class_dev = device_create(user_drv_class, NULL, MKDEV(device_driver_major_number, 0), NULL, "device_inode_name");

	return 0;
}

/* 卸载模块*/
static void user_drv_exit(void)
{
	/* 注销设备 */
	unregister_chrdev(major, "first_drv"); 

	/* 注销类下的设备device_inode_name */
	device_destroy(user_drv_class_dev, MKDEV(major, 0));

	/* 注销类class_drv_name */
	class_destroy(user_drv_class);
}

module_init(user_drv_init);
module_exit(user_drv_exit);
MODULE_LICENSE("GPL");


 

在模块注册module_init(user_drv_init)之时,调用user_drv_init()函数,register_chrdev()注册设备后即在/dev下自动创建相应的设备节点。

 

模块退出时,调用device_destroy()class_destroy即可实现对类,设备文件的自动清除。

你可能感兴趣的:(驱动设备文件)