Linux内核的学习(三)之字符设备驱动的设备号
用户进程是通过什么来调用驱动?
系统编程,经常用open,read write 来操作设备文件来调用驱动。
crw-rw---- 1 root video 10, 175 Dec 11 17:45 agpgart
crw------T 1 root root 10, 235 Dec 11 17:45 autofs
drwxr-xr-x 2 root root 660 Dec 11 17:45 block
drwxr-xr-x 2 root root 100 Dec 11 17:45 bsg
crw------T 1 root root 10, 234 Dec 11 17:45 btrfs-control
设备文件名字不重要,设备号才是最重要的。设备号是由主设备号和次设备号组成一个字符设备。
如autofs 的主设备号是10 , 次设备号是175;
crw--w---- 1 root tty 4, 11 Dec 11 17:45 tty11
crw--w---- 1 root tty 4, 12 Dec 11 17:45 tty12
crw--w---- 1 root tty 4, 13 Dec 11 17:45 tty13
crw--w---- 1 root tty 4, 14 Dec 11 17:45 tty14
crw--w---- 1 root tty 4, 15 Dec 11 17:45 tty15
第一个字符’c’表示字符设备文件
主设备号通常表示一个字符设备驱动,上面5个设备它们驱动方法是一样的, 可以同用一个驱动。
在驱动里可通过次设备号来区分不同的硬件接口。
设备号很重要,在系统里是不可以重用的资源。注意是设备号不能重用,但主设备号可以重用
Linux 是用类型“dev_t(unsigned int )” 来表示一个设备号,dev_t是32位,高12位用于存放主设备号,低20位用于存放次设备号。 #incude <linux/kdev_t.h> #define MINORBITS 20 #define MINORMASK ((1U << MINORBITS) - 1) #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) // 提供了设备号的宏操作
设备号像GPIO一样,使用前需要向内核申请,使用完后需返还内核。
#include <linux/fs.h> int register_chrdev_region(dev_t from, unsigned count , const char *name); //静态:申请设备号,from为设备号, count 指定使用该驱动有多少个设备(次设备号), name(名字,长度不能大于64字节) int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count , const char *name) //动态申请设备号,由内核分配没有使用的主设备号,分配好的设备号存在dev(不需要初始化) baseminor指次设备号从多少开始,count多少个, 名字 void unregister_chrdev_region(dev_t from , unsigned count ); //释放设备号 //可通过”cat /proc/devices”查看系统里主设备号的使用状况
步骤:
- 申请一个dev_t的对象 dev_t devid;
- devid = MKDEV(123, 321); 组合成一个设备号;
- 内核申请设备号,register_chrdev_region(devid, 3, "mydev");
- 使用完后需要回收设备号 unregister_chrdev_region(devid , 3);
编译后加载模块后 :
cat /proc/devices
浙公网安备 33010602011771号