常用字符设备入口出口框架_自动创建节点

一、设备号处理及设备注册

1、创建设备结构体

​ 驱动设备号除了直接指定外,还可以让linux内核分配。首先创建设备结构体,结构体内包含的设备的属性:

struct newchrled_dev{
	struct cdev cdev;  //字符设备
	int major;		//主设备号
	int minor;		//次设备号
	dev_t devid;	//设备号
	struct class *class;	//类
	struct device *device;	//设备
};
struct newchrled_dev newchrled;

2、设备号处理方法

​ 在设备入口函数xxx_init中添加设备号处理代码:

/* 获取设备号 */
	if(newchrled.major){		//如果设置了主设备号
		newchrled.devid = MKDEV(newchrled.major, 0);	//定义设备号,次设备号为0
		register_chrdev_region(newchrled.devid, 1, DEVICE_NAME);		//向内核注册设备号
	}
	else{		//没有设置主设备号
		alloc_chrdev_region(&newchrled.devid, 0, 1, DEVICE_NAME);		//申请设备号
		newchrled.major = MAJOR(newchrled.devid);	//可要可不要
		newchrled.minor = MINOR(newchrled.devid);
	}

​ 设备号处理分为两种情况,一是直接指定主设备号(次设备号一般设置为0),然后使用MKDEV这个宏获取dev_t类型的设备号,此类型的设备号包含了主设备号和次设备号信息。最后使用register_chrdev_region函数向内核注册设备号,告知系统此设备号已被占用。该函数第一个参数为设备号;第二个参数为申请的数量,一般为1;第三个参数为设备名。

​ 二是没有指定主设备号,使用alloc_chrdev_region函数向内核申请一个设备号,该函数第一个参数为设备号指针,用来储存申请到的设备号;第二个参数为次设备号;第三个参数为申请的数量,一般为1;第四个参数为设备名。

3、注册设备

​ 设备结构体中有一个cdev的架构体变量,表示一个字符设备,cdev结构体在include/linux/cdev.h文件中的定义如下:

struct cdev { 
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;  //操作函数结构体
    struct list_head list;
    dev_t dev;		//设备号
    unsigned int count;
};

​ 设备注册实质上就是初始化cdev,然后使用cdev进行注册。在设备号处理代码后添加设备注册代码:

/* 注册设备 */
newchrled.cdev.owner = THIS_MODULE;  //初始化cdev中的owner
cdev_init(&newchrled.cdev, &led_fops);	//初始化cdev结构体变量
cdev_add(&newchrled.cdev, newchrled.devid, 1);  //向linux内核添加字符设备

​ 设备注册使用了两个函数:
cdev_init(struct cdev *cdev, const struct file_operations *fops),参数一是要初始化的cdev的指针,参数二是操作函数结构体指针。
int cdev_add(struct cdev *p, dev_t dev, unsigned count),参数一是要注册的cdev的指针,参数二是设备号,参数三是要注册的设备数量。

4、自动创建设备节点

​ 在终端使用应用程序前要使用mkond命令创建驱动设备节点,这一步可以在驱动代码内自动实现,在终端只要使用modprobe加载驱动模块后就会自动创建设备节点。

udev是一个用户程序,在linux下通过udev实现设备文件的创建与删除,比如使用modprobe后自动在/dev下创建设备节点文件,使用rmmod后删除设备节点文件。使用busybox构建根文件系统后,会创建一个udev的简化版mdev,嵌入式linux一般使用mdev。mdev同时也管理热拔插时间,在==/etc/init.d/rcS==中添加如下语句:
echo /sbin/mdev > /proc/sys/kernel/hotplug

​ 自动创建设备节点一般在设备注册代码后

/* 自动创建设备节点 */
newchrled.class = class_create(THIS_MODULE, DEVICE_NAME);  //创建类
newchrled.device = device_create(newchrled.class, NULL, newchrled.devid, NULL, DEVICE_NAME);  //创建设备

​ 1)首先要在设备结构体中创建类和设备结构体指针。类定义在include/linux/device.h里面。
​ 2)然后使用class_create函数创建类,函数原型:struct class *class_create (struct module *owner, const char *name),参数一owner一般为THIS_MODULE,参数二为类的名字,返回值是指向结构体class的指针。
​ 3)最后使用device_create函数创建设备。参数一为设备创建在哪个类下,参数二为父设备,无则NULL,参数三为设备号,参数四为设备可能使用的一些数据,无则NULL,参数五是设备名字,即创建设备节点文件的名字。

二、删除各种注册申请

​ 在驱动出口函数xxx_exit中要删除设备号、设备注册信息、类和自动创建设备,在出口函数中添加代码:

/* 出口函数 */
static void __exit led_exit(void)
{
    ......
    
	/* 删除设备 */
	device_destroy(newchrled.class, newchrled.devid);

	/* 删除类 */
	class_destroy(newchrled.class);

	/* 删除字符设备 */
	cdev_del(&newchrled.cdev);
	
	/* 注销设备号 */
	unregister_chrdev_region(newchrled.devid, 1);
}

​ 在驱动入口函数中先创建的在出口函数中后删除。入口函数中的创建顺序是:设备号——注册字符设备——创建类——创建设备。出口函数中的删除顺序则是:删除设备——删除类——删除字符设备——删除设备号。

三、设置私有数据

​ 设备属性结构体可以作为私有数据来使用,操作函数的参数中有一个file类型的结构体指针filp,该结构体有一个private_data的成员变量,表示私有数据。可在open函数中设置私有数据:

/* open函数 */
static int led_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &newchrled;
	return 0;
}

​ 然后在write、read等其他操作函数中使用:

/* release函数 */
static int led_release(struct inode *inode, struct file *filp)
{
	struct newchrled_dev *dev = filp->private_data;
	printk("major: %d\r\n",dev->major);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值