(一)linux的文件种类:
1、Linux设备一切皆文件,大部分设备是文件。
2、普通文件在硬盘分区,存放文件内容,文件名,文件元信息inode(修改权限,修改时间,创建者...)
3、socket(服务端客户端的地址值)、管道文件(通信机制)没有文件内容。
4、链接文件:软连接另外文件的路径,硬链接是别名。
5、字符设备和块设备没有文件内容。
(二)按驱动程序分类
Linux内核按驱动程序实现模型框架的不同,将设备分为三类:
1、块设备一般不面向应用设备,一般面向文件系统,设备缓存,提高效率,应用程序通过文件系统访问块设备。
2、网络设备:不用文件名命名,另外的命名方式,网卡(有线,无线),蓝牙。
内核用设备号来区分同类里不同的设备,设备号是一个无符号32位整数,数据类型为dev_t,设备号分为两部分:
应用程序打开一个设备文件时,通过设备号来查找定位内核中管理的设备。
1、设备号MKDEV宏
MKDEV宏用来将主设备号和次设备号组合成32位完整的设备号,用法:
dev_t devno;
int major = 251;//主设备号
int minor = 2;//次设备号
devno = MKDEV(major,minor);
主设备号相同,用一套驱动设备,用次设备号区分。
例:驱动多个鼠标,鼠标主设备号相同,次设备号不同。
2、取设备号
MAJOR宏用来从32位设备号中分离出主设备号,用法:
dev_t devno = MKDEV(249,1);
int major = MAJOR(devno);
MINOR宏用来从32位设备号中分离出次设备号,用法:
dev_t devno = MKDEV(249,1);
int minor = MINOR(devno);
3、创建一个设备文件
如果已知一个设备的主次设备号,应用层指定好设备文件名,那么可以用mknod命令在/dev目录创建代表这个设备的文件,即此后应用程序对此文件的操作就是对其代表的设备操作,mknod用法如下:
@ cd /dev
@ mknod 设备文件名 设备种类(c为字符设备,b为块设备) 主设备号 次设备号 //ubuntu下需加sudo执行
在应用程序中如果要创建设备可以调用系统调用函数mknod,其原型如下:
int mknod(const char *pathname,mode_t mode,dev_t dev);
pathname:带路径的设备文件名,无路径默认为当前目录,一般都创建在/dev下
mode:文件权限 位或 S_IFCHR/S_IFBLK
dev:32位设备号
返回值:成功为0,失败-1
(一)申请设备号
字符驱动开发的第一步是通过模块的入口函数向内核添加本设备驱动的代码框架,主要完成:
1、手动申请
int register_chrdev_region(dev_t from, unsigned count, const char *name)
功能:手动分配设备号,先验证设备号是否被占用,如果没有则申请占用该设备号
参数:
from:自己指定的设备号
count:申请的设备数量
name:/proc/devices文件中与该设备对应的名字,方便用户层查询主设备号
返回值:
成功为0,失败负数,绝对值为错误码
2、动态申请
int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count, const char *name)
功能:动态分配设备号,查询内核里未被占用的设备号,如果找到则占用该设备号
参数:
dev:分配设备号成功后用来存放分配到的设备号
baseminior:起始的次设备号,一般为0
count:申请的设备数量
name:/proc/devices文件中与该设备对应的名字,方便用户层查询主次设备号
返回值:
成功为0,失败负数,绝对值为错误码
分配成功后在/proc/devices 可以查看到申请到主设备号和对应的设备名,mknod时参数可以参考查到的此设备信息
void unregister_chrdev_region(dev_t from, unsigned count)
功能:释放设备号
参数:
from:已成功分配的设备号将被释放
count:申请成功的设备数量
释放后/proc/devices文件对应的记录消失
代码:
/fs4412/mydrivercode/mychar
#include
#include
#include
int major = 11;
int minor = 0;
int mychar_num = 1;
int __init mychar_init(void){
int ret = 0;
dev_t devno = MKDEV(major,minor);
ret = register_chrdev_region(devno,mychar_num,"mychar");
if(ret){
ret = alloc_chrdev_region(&devno,minor,mychar_num,"mychar");
if(ret){
printk("get devno failed\n");
return -1;
}
major = MAJOR(devno);//容易遗忘,动态分配后主设备号有可能改变,次设备号为0
}
return 0;
}
void __exit mychar_exit(void)
{
dev_t devno = MKDEV(major,minor);
unregister_chrdev_region(devno,mychar_num);
}
MODULE_LICENSE("GPL");
module_init(mychar_init);
module_exit(mychar_exit);
将编译好的字符设备插入内核模块
字符设备
块设备: