1.1 字符设备:
以字节流的形式进行访问,而且只能顺序访问的设备叫做字符设备(比如键盘、鼠标)
(块设备:有固定访问大小,可以不按顺序访问的设备,比如U盘、硬盘)
针对字符设备编写的驱动叫做字符设备驱动
1.2 当设备驱动注册进内核,内核会分配给当前驱动一个编号,即设备号
设备号=主设备号<<20 | 次设备号 (主设备号左移20个字符,按位或上次设备号)
当注册驱动后得到驱动对应的设备号,基于这个设备号在文件系统中创建了一个文件,完成了设备文件和设备驱动的关联,当在用户空间操作设备时,也就可以访问到设备驱动了。
1.3 字符设备驱动在内核中的注册和注销API
1> int register_chardev(major,"mycdev",&fops)
功能:实现字符设备驱动向内核的注册。这个函数申请了256个设备的资源,次设备号的范围:0~255
major:注册的驱动的主设备号,如果major==0,内核自动分配一个主设备号;
如果major>0,由驱动开发者静态指定一个主设备号
"mycdev":注册的字符设备驱动的名字
fops:操作方法结构体指针
返回值:如果major==0,成功返回注册的驱动的主设备号,失败返回<0的错误码
如果major>0,成功返回0,失败返回<0的错误码
2> void unregister_chrdev(major,"mycdev")
功能:实现字符设备驱动的注销
3> 为字符设备驱动创建设备文件
sudo mknod /dev/mycdev c major 0
/dev/mycdev:创建的设备文件的名字及路径
major:主设备号
0:次设备号(0~255均可)
字符设备驱动的内部实现
2.1 字符设备驱动内部实现原理图:
open函数通过路径打开文件时,虚拟文件系统层的sys_open根据路径找到文件的inode结构体
在struct——inode结构体中有成员i_rev(设备号)和共用体union,union中有结构体参数struct_cdev
struct_cdev中有设备号和struct file_operations结构体,struct file_operations结构体中,open就是操作方法之一
2.2 字符设备驱动分步注册流程及API
1> 为字符设备驱动对象申请空间
无参函数:cdev_alloc();成功返回申请空间首地址,失败返回NULL
2> 字符设备驱动对象的初始化
void cdev_init(cdev,&fops)
cdev:字符设备驱动对象指针 fops:操作方法结构体指针
3> 申请设备号,有两种情况
i> major>0,静态指定设备号
register_chrdev_region(MKDEV(major,minor),n,"myled")
功能:静态指定设备号
MKDEV:要申请的设备号
n:要申请的设备资源的数量(次设备号数量)
"myled":驱动名称
返回值:成功返回0,失败返回错误码
ii> major==0,动态申请一定范围的设备号
alloc_chrdev_region(&devno,minor,n,"myled")
功能:动态申请一定范围的设备号
&devno:申请的设备号在这个变量中
minor:次设备号的起始值
n:申请的设备资源的数量(次设备号数量)
“myled”:驱动名称
4> 将字符设备驱动对象注册进内核
cdev_add(cdev,MKDEV(major,minor),n)
cdev:字符设备启动对象指针
MKDEV:申请的设备号
n:次设备数量
返回值:成功返回0,失败返回错误码
5> 字符设备驱动对象的注销
cdev_del(cdev)
cdev:字符设备驱动对象指针
返回值:无
6> 释放申请的设备号
unregister_chrdev_region(MKDEV(major,minor),n)
MKDEV:申请的设备号
n:设备的数量
7> 释放对象空间
kfree(cdev) cdev:对象空间首地址