字符设备驱动:驱动是为用户(应用层)服务的(操作硬件是过程,目的是用户)。
字符驱动在软件架构中的位置:
设备号: 当用户访问 文件节点的时候,比如 open (/dev/)
u32无符号整型(可对应2^32个设备),其中高12bit称为主设备号,低20bit称为此设备号。 字符设备驱动(文件对象),有哪些东西:
(1)、 属性:设备号(2)、方法:open /read/write/close/ioctl
如何编写 字符设备驱动程序:
1、向设备申请一个设备号c’d
2、实现 一个字符设备驱动对象: devno open read write close
(初始化内部成员,指定方法;添加驱动对象到内核中,并指定设备号)
3、创建一个文件节点(创建一个分类;在该类下创建一个节点)
内核的同步(即互斥):锁
解决同时访问同一个共享资源的问题。
字符设备的文件节点可能会被 同时多个进程访问
锁:内核提供了几种锁
(1)、原子变量:他本质上 不属于锁
int i = 5; i++ ;(一个/多个进程 同时访问,会出问题即:编译时,从RAM–>寄存器,读,加,回过程中,过程被其他进程打断;但用上千行代码指令进行加锁保护该3条指令不划算,故引入原子变量 )
原子变量,本质上是一个整数; 原子变量,主要用于计数,只有加减。
(2)、互斥锁 (节约空间,但实时性差,不能用于中断)
为共享资源准备一把锁:定义并初始化 互斥锁(特殊-在模块入口非open)
struct mutex mlock; void mutex_init(struct mutex *mlock)
使用之前加锁: mutex_lock(struct mutex * lock)
使用完毕解锁:mutex_unlock(struct mutex * lock)
(3)、自旋锁 (很耗CPU,但实时性强,用在中断,实时性高度的进程中)
IO模型 (在驱动中用于内核对桌面鼠标位置数据包的接受等)
IO : input out通信模型
通信过程中 会有哪些问题???
用户进程去内核访问数据,发现驱动中没有数据时:
阻塞(iomode) …. ,进程(fork)主动睡眠等待…当有数据的时候(产生中断)唤醒该进程 ,
进程获取数据, 返回用户层 (重要)
流程: 1、定义并初始化一个等待队列
wait_queue_head_t wq_head; void init_waitqueue_head (wait_queue_head_t *q)
2、进程发现内核没有数据,于是去 等待队列上睡眠
wait_event_ininterruptible(wq,int condition) wq,等待队列
注意,参数是一个变量,不是指针, 因为整个 wait-event_interruptible,都是宏参数
直接替换到当前位置 ,没有发生任何函数调用condtion: 函数内部自带判断 数据有和无。
3、中断唤醒等待队列上的进程
即:当送来数据,另一个执行单元(中断 –另一个进程)唤醒 等待队列上的进程
wake_up_interruptable()
非阻塞 ….,进程立即返回,去做其他工作,后续会反复访问内核数据….(fcntl=iocntl-获取文件:..) 阻塞与非阻塞由用户决定
如何实现非阻塞呢??? 如何实现非阻塞呢????
当open一个文件的时候,返回 int fd; fd在内核中表示struct file{ int f_flags; };
f_flags 有32bit,每一个比特 都表示文件的一种属性 , 某位置一表示文件可写,置零表示不可写
置一表示可读,置零表示不可读 …… ……
其中 有这么一个bit, 置一表示文件时 非阻塞的 ,置零—阻塞的
1. 通过fd获取 f = file::flags
2. 将 f |= 1<<x ;
3. 将f 覆盖 file::flags
异步通知 ….,用户进程平时不关注内核数据,当硬件有了数据(产生中断), 中断中会主动给 进程发信号,进程收到信号之后,再去内核读取数据…..
多路复用 ….,(驱动中没有,一个进程)同时监控多个字符设备 文件节点,任何一个节点有了数据 ,则返回处理