主次设备号
字符设备通过字符设备文件来存取。字符设备文件由使用ls -l 的输出的第一列的“C”标识。如果使用ls -l命令,会看到在设备文件项中有两个数(由一个逗号分隔),这些数字就是设备文件的主次设备编号。(举例查看 /dev)
设备号作用
主设备号用来标识与设备文件相连的驱动程序。次设备号被驱动用来决定操作的是哪个设备。
** 主设备号用来体现设备类型
** 次设备号用来体现某种设备类型中的第几个
Q: 内核中如何描述设备号
A:struct dev_t ,实质为unsigned int 32位整数,其中高12为主设备号,低20位为次设备号。
Q: 如何从kdev_t结构体分解主设备号
A: MAJOR(dev_t dev)
Q: 如何从kdev_t结构体 中分解出次设备号
A: MINOR(dev_t dev)
Q: 如何构造设备号
A: dev_t MKDEV(unsigned int major, unsigned int minor)
分配设备号
Q:Linux内核如何给设备分配设备号
A : 可以采用静态分配、动态分配两种方法
静态分配
1、根据documentation/devices.txt, 找到一个没有使用的设备号,并手动指定。
2、使用register_chrdev_region函数注册
dev = MKDEV(devmajor,devminor); //获得设备号
result = register_chrdev_region(dev,1,"demo");//分配设备号
3、缺点:一旦驱动更广泛的被使用,一个随机获取的主设备号将导致冲突。
静态申请
int register_chrdev_region(dev_t from, unsigned count, const char *name)
功能:
申请使用从 from 开始的 count 个设备号(主设备号
不变,次设备号增加)
参数:
from:希望申请使用的设备号
count:希望申请使用设备号数目
name:设备名(体现在/proc/devices)
动态分配
方法:使用alloc_chrdev_region分配设备号
优点:
简单,易于驱动推广
缺点:
无法在安装驱动前创建设备文件,因为还没有分配到主设备号。
解决办法:
一旦驱动程序安装、主设备号分配了, 可从 /proc/devices 中查询到
result = alloc_chrdev_region(&dev, devminor, 1, “led”);//2 动态分配设备编号
devmajor = MAJOR(dev);
动态申请
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
功能:
请求内核动态分配 count 个设备号,且次设备号从baseminor开始。
参数:
dev:分配到的设备号
baseminor:起始次设备号
count:需要分配的设备号数目
name:设备名(体现在/proc/devices)
注销设备号
不论使用何种方法分配设备号,都应该在不再使用它们时释放这些设备号。
void unregister_chrdev_region(dev_t from,unsigned count)
功能:
释放从from开始的count个设备号
设备驱动安装
安装一个字符设备驱动的方法:
设备号手工指定:
register_chrdev_region(dev_t first,unsigned int count,char *name)
first :要分配的设备编号范围的初始值(次设备号常设为0);
count:连续编号范围.
name:编号相关联的设备名称. (可查看:cat /proc/devices);
设备号自动获取:
Int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
firstminor : 通常为0;
*dev:存放返回的设备号;
卸载一个字符设备驱动的方法:
void unregister_chrdev_region(dev_t first, unsigned int count);
驱动注册示例代码
if (scull_major)
{
dev = MKDEV(scull_major, scull_minor);
result = register_chrdev_region(dev, scull_nr_devs, "scull");
} else
{
result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");
scull_major = MAJOR(dev);
}
if (result < 0)
{
printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
return result;
}
创建设备文件
1、使用mknod命令手动创建
2、使用devfs提供的函数在驱动程序中自动创建
mknod 用法:
# mknod filename type major minor
Filename:设备文件名
Type: 设备文件类型
Major: 主设备号
Minor: 次设备号
例: mknod /dev/serial0 c 100 0
自动创建
设备文件系统有:devfs、udev、mdev等。 不同的设备文件系统的创建节点的方法不同。2.6.12( devfs ),2.6.13以后就很少使用了。
#ifdef CONFIG_DEVFS_FS
devfs_mk_cdev(dev, S_IFCHR|S_IRUGO|S_IWUSR, "led_su");
#endif
2.6.32( mdev,是udev的简化,用于嵌入式 ),Udev用于PC机,
struct class *led_class;
/* create your own class under /sysfs 2.6.32*/
led_class = class_create(THIS_MODULE, "led_class");
if(IS_ERR(led_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
/* register your own device in sysfs, and this will cause udev to create corresponding device node */
device_create( led_class, NULL, MKDEV(devmajor, 0), NULL, "led_su");