赞
踩
字符设备:能够像字节流一样被访问的设备,当对字符设备发出读写请求,相应的I/O操作立即发生。例,字符终端、串口、键盘、鼠标等;
块设备 :Linux系统中进行I/O操作时必须以块为单位进行访问的设备,块设备能够安装文件系统。块设备驱动会利用一块系统内存作为缓冲区,因此对块设备发出读写访问,并不一定立即产生硬件I/O操作。例,硬盘、软驱等;
网络设备:既可以是网卡这样的硬件设备,也可以是一个纯软件设备如回环设备。网络设备由Linux的网络子系统驱动,负责数据包的发送和接收,而不是面向流设备,因此在Linux系统文件系统中网络设备没有节点,对网络设备的访问是通过socket调用产生。
dev_t类型来保存设备编号(包括主设备号和次设备号)。
在 2.62.6 版本的Linux内核中,dev_t 是一个 32 位数,高12位是主设备号,低20位是次设备号(从设备号)。
1、主设备号:
如果多个设备使用同一个驱动程序,则它们拥有相同的主设备号。主设备号由系统来维护,但是在使用主设备号的时候,注意一定不要使用系统已经的主设备号。
一般来说,231~239这几个设备是系统没有分配的,用户可以自行安排使用。cat /proc/devices查看运行系统占用了哪些主设备号。
2、次设备号:
用于确定该文件所指定的设备,如果一个设备驱动可以驱动一组相似的设备,此时就需要依赖于次设备号对这些外进行区分。
从dev_t获取。应当使用 <linux/kdev_t.h>中定义的 宏,而不应当对设备号位数和表述结构做任何假设,因为这样会导致不兼容以前的内核,或者未来版本设备号结构和表述方式发生变化。例如获取一个设备dev的主次设备号,可用:
#include<linux/kdev_t.h>
MAJOR(dev_t dev); //获取主设备号
MINOR(dev_t dev); //获取次设备号
如果已知一个设备的主次设备号,要转换成dev_t类型的设备编号,则应当使用:
MKDEV(int major,int minor);
1)静态获取主设备:
只在特定系统运行,且系统设备号使用情况明确;系统应用所要求;如为了快速启动等。
#include<linux/fs.h>
int register_chrdev_region(dev_t first,unsigned int count,char *name); //向系统注册1个或多个设备号
//first是起始编号;
//count是主设备号的数量;
//name是设备名称
/*注册成功返回0,否则返回错误码*/
2)动态获取主设备号:
如果事先不知道设备的设备号,或者一个驱动可能在多个系统上运行,为了避免出现设备号冲突,必须采用动态设备号。
#include<linux/fs.h>
alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);//该函数可以从系统动态获得一个或者多个主设备号
//dev用于保存已经获得的编号范围的第一个值;
//firstminor是第一个次设备号,通常是0;
//count是获得的编号数量;
//name是设备名称;
动态获取得到的设备号,一定要用一个全局变量保存下来以便卸载使用,否则该设备号将不能被释放。
在设备注销的时候必须释放占用的主设备号,调在unregister_chrdev_region 可以释放设备号。函数原型:
void unregister_chrdev_region(dev_t from,unsigned count);
//from要释放的设备号,与注册的设备号一致;
//count释放设备号的个数;
#include<linux/module.h> #include<linux/init.h> #include<linux/fs.h> #include<linux/cdev.h> #include<linux/device.h> static int dev_major; static int dev_minor; module_param(dev_major,int,S_IRUGO); module_param(dev_minor,int,S_IRUGO); dev_t dev_no; //dev number #define DEVICE_NAME "cdev_hello" #define MINOR_NUM 0 #define DEVICE_COUNT 1 static int __init hello_init(void) { int ret; printk("Hello init!Get number is %d\n",dev_major); if(dev_major > 0) //Static gain { dev_no = MKDEV(dev_major, dev_minor); //Get the dev_t type. ret = register_chrdev_region (dev_no, DEVICE_COUNT, DEVICE_NAME);//Static acquisition device if(ret < 0) { printk("static no error!\n"); //Fail to get return ret; } printk("static is ok!\n"); //Gain success printk("major = %d,minor = %d\n",dev_major,dev_minor); } else //Dynamic acquisition { alloc_chrdev_region(&dev_no, MINOR_NUM, DEVICE_COUNT, DEVICE_NAME); dev_major = MAJOR(dev_no); //Get major dev_minor = MINOR(dev_no); //Get minor printk("Dynamic is ok!\n"); printk("major = %d,minor = %d\n",dev_major,dev_minor); } return 0; } static void __exit hello_exit(void) { unregister_chrdev_region(dev_no,DEVICE_COUNT); //设备个数设置为宏定义后才能取消设备号?? printk("Hello exit!\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");
测试结果
1、
2、
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。