Linux驱动学习-新字符设备驱动

Linux驱动学习-新字符设备驱动

之前学习的是使用register_chrdev函数注册字符设备,使用unregister_dev注销字符设备,驱动模块加载成功以后还需要手动使用 mknod 命令创建设备节点。
在新的字符设备驱动已经不再使用这两个函数,而是使用Linux内核推荐的新字符设备驱动API函数。

1、新字符设备驱动原理
①分配和释放设备号
使用 register_chrdev 函数注册字符设备的时候只需要给定一个主设备号即可,但是这样会
带来两个问题:
①、需要我们事先确定好哪些主设备号没有使用。
②、会将一个主设备号下的所有次设备号都使用掉,比如现在设置 LED 这个主设备号为
200,那么 0~1048575(2^20-1)这个区间的次设备号就全部都被 LED 一个设备分走了。这样太浪
费次设备号了!一个 LED 设备肯定只能有一个主设备号,一个次设备号。

新字符设备驱动 会在需要使用设备号的时候像Linux内核申请,这样就不会出现上述的问题
如果没有申请主设备号,就使用alloc_chrdev_region申请设备号,*dev返回设备号信息
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

如果给定了设备的主设备号和此设备号,指定注册可以使用下面函数
int register_chrdev_region(dev_t from, unsigned count, const char *name)
参数 from 是要申请的起始设备号,也就是给定的设备号;参数 count 是要申请的数量,一
般都是一个;参数 name 是设备名字。

通用的代码如下:

int major;			/* main dev*/
int minor;			/* sub dev */
dev_t devid			/* dev */

if(major)
{
	devid = MKDEV(major, 0);	/* sub dev = 0 */
	register_chrdev_region(devid, 1, "test");
}
else
{
	alloc_chrdev_region(&devid, 0, 1, "test");
	major = MAJOR(devid);		/* get main dev */
	minor = MINOR(devid);		/* get sub dev  */
}

上面三个全局变量可以用结构体来实现,代码可读性更强。

②新字符设备的注册方法
在 Linux 中使用 cdev 结构体表示一个字符设备

->字符设备结构

struct cdev 
{
	struct module *owner;
	const struct file_operations *ops;
	dev_t dev;
}

->cdev_init函数
定义好 cdev 变量以后就要使用 cdev_init 函数对其进行初始化,cdev_init 函数原型如下:
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
~~把 file_operations 赋给 cdev.xxx

->code_add函数
cdev_add 函数用于向 Linux 系统添加字符设备(cdev 结构体变量),首先使用 cdev_init 函数完成对 cdev 结构体变量的初始化,然后使用 cdev_add 函数向 Linux 系统添加这个字符设备。
cdev_add 函数原型如下:
int cdev_add(struct cdev *p, dev_t dev, unsigned count)

testcdev.owner = THIS_MODULE;
cdev_init(&testcdev, &test_fops); /* 初始化 cdev 结构体变量 */
cdev_add(&testcdev, devid, 1); /* 添加字符设备 */

Linux 内核中大量的字符设备驱动都是采用这种方法向 Linux 内核添加字符设备。
就它们一起实现的就是函数 register_chrdev 的功能。

->cdev_del 函数
卸载驱动的时候一定要使用 cdev_del 函数从 Linux 内核中删除相应的字符设备,cdev_del
函数原型如下:
void cdev_del(struct cdev *p)

cdev_del 和 unregister_chrdev_region 这两个函数合起来的功能相当于 unregister_chrdev 函
数。

2、自动创建设备节点
1>mdev 机制
udev 是一个用户程序,在 Linux 下通过 udev 来实现设备文件的创建与删除。
busybox 会创建一个 udev 的简化版本—mdev,在嵌入式 Linux 中我们使用mdev 来实现设备节点文件的自动创建与删除,Linux 系统中的热插拔事件也由 mdev 管理,在/etc/init.d/rcS 文件中如下语句:
echo /sbin/mdev > /proc/sys/kernel/hotplug

2>创建和删除类
自动创建设备节点的工作是在驱动程序的入口函数中完成的,一般在 cdev_add 函数后面添加自动创建设备节点相关代码。
class_create
struct class *class_create (struct module *owner, const char *name)
class_destroy
void class_destroy(struct class *cls)

3>创建设备和删除设备
创建好类以后还不能实现自动创建设备节点,我们还需要在这个类下创建一个设备。
device_create
struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, …)
device_destroy
void device_destroy(struct class *class, dev_t devt)

4>设置文件私有数据

typedef struct
{
    dev_t devid;            /*  */
    struct cdev cdev;       /* cdev(加载和卸载驱动) */
    struct class *class;    /* 类(设备节点) */
    struct device *device;  /* 设备(设备节点) */
    int major;              /* 主设备号 */
    int minor;              /* 次设备号 */
}newchardev_dev;

编写驱动 open 函数的时候将设备结构体作为私有数据添加到设备文件中,如下所示:

static int newchrdev_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &newchrdev;        /* 设置私有数据 */
    return 0;
}

在 open 函数里面设置好私有数据以后,在 write、read、close 等函数中直接读取 private_data即可得到设备结构体。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值