参考资料:《Linux驱动开发入门与实战》
字符驱动开发思维导图:
1、构建设备号dev_t
一个字符设备或块设备都有一个主设备号和一个次设备号。主设备号用来标识与设备文件相连的驱动程序,用来反映设备类型。次设备号被驱动程序用来辨别操作的是哪个设备,用来区分同类型的设备。
linux内核中,设备号用dev_t来描述,2.6.28中定义如下:
typedef u_long dev_t;
在32位机中是4个字节,高12位表示主设备号,低20位表示次设备号。
定义设备号:dev_t devno;
查看主设备号: cat /proc/devices
查看当前设备的主次设备号: ls -l /dev 内核为我们提供了几个方便操作的宏实现dev_t:
1.1 通过major和minor构建设备号
int major = 100;
int minor= 0;
dev_t devno = MKDEV(int major,int minor);
注:这只是构建设备号。并未注册,需要调用register_chrdev_region 静态申请;
1.2 从设备号中提取主次设备号
int major = MAJOR(dev_t devno);
int minor = MINOR(dev_t devno);
2、分配设备号
2.1 静态分配设备号
函数原型:int register_chrdev_region(dev_t from, unsigned count, const char *name);
头文件:#include <linux/cdev.h>
函数功能:申请使用从from开始的count个设备号(主设备号不变,次设备号增加);
参数:
from:要分配的设备号范围的起始值。一般只提供from的主设备号,from的次设备号通常被设置为0;
count:需要申请的连续设备号的个数;
name:和该范围编号关联的设备名称,该名称不能超过64字节;
返回值:成功时返回0,失败时返回一个负的错误码,并且不能为字符设备分配设备号。
源代码如下:
int register_chrdev_region(dev_t from, unsigned count, const char *name)
{
struct char_device_struct *cd;
dev_t to = from + count;
dev_t n, next;
for (n = from; n < to; n = next) {
next = MKDEV(MAJOR(n)+1, 0);
if (next > to)
next = to;
cd = __register_chrdev_region(MAJOR(n), MINOR(n),
next - n, name);
if (IS_ERR(cd))
goto fail;
}
return 0;
fail:
to = n;
for (n = from; n < to; n = next) {
next = MKDEV(MAJOR(n)+1, 0);
kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
}
return PTR_ERR(cd);
}
2.2 动态分配设备号
函数原型:int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name);
头文件:#include <linux/cdev.h>
函数功能:申请使用从from开始的count 个设备号(主设备号不变,次设备号增加);
参数:
dev:dev作为输出参数,在函数成功返回后将保存已经分配的设备号。函数有可能申请一段连续的设备号,这是dev返回的第 一个设备号;
baseminor:要申请的第一个次设备号;
count:次设备的个数;
name:和该范围编号关联的设备名称,该名称不能超过64字节;
返回值:成功返回0,失败返回错误码;
源代码如下:
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)
{
struct char_device_struct *cd;
cd = __register_chrdev_region(0, baseminor, count, name);
if (IS_ERR(cd))
return PTR_ERR(cd);
*dev = MKDEV(cd->major, cd->baseminor);
return 0;
}
2.3 申请设备号举例
int major = 100;
dev_t devno;
if(major)
{
devno= MKDEV(major, 0);
ret = register_chrdev_region(devno, 1, "xxx_dev");
if(ret != 0)
{
printk("[%s] %s %d : failed!\n", __FILE__, __func__, __LINE__);
return -1;
}
}
else
{
ret = alloc_chrdev_region(&devno, 0, 1, "xxx_dev");
if(ret != 0)
{
printk("[%s] %s %d : failed!\n", __FILE__, __func__, __LINE__);
return -1;
}
}
2.4 注销设备号
void unregister_chrdev_region(dev_t from, unsigned count);
from表示要释放的设备号,count表示从from开始要释放的设备号的个数。
3、分配cdev
3.1 静态分配cdev
struct cdev xxx_cdev;
3.2 动态分配cdev
<