总结字符设备驱动程序
- 查询方式:在读函数中返回引脚状态,比较前后值。(cpu占用太高)
- 休眠唤醒:用户读驱动读,没有数据休眠,有数据被中断服务程序唤醒然后copy_to_user。(没有数据则一直休眠)
- poll机制:休眠时定时器也开始了,如果在预定时间内没有数据,时间超出将唤醒。(休眠,加闹钟)
- 异步通知:最好的方法(发信号)
但是只有以上 写出的代码只能自己用,要融合到别人的代码需要 输入子系统。或者总线驱动设备模型。
输入子系统 或者 总线驱动设备模型,也是用到了前面四种方法写的。
块设备驱动程序
- 硬盘,磁头、柱面、扇区。读写不能按照用户的顺序,会导致效率极低,顺序需要优化。(调整读写顺序)
- Flash,块、扇区。读出-修改-擦除-烧写。(合并 读写擦除修改)
块设备不能像字符设备 直接提供读写函数,需要把读写放入队列优化后再执行。
块设备驱动程序框架
app:open read write “xxx.txt”
= = = = = = = = = = = = = = = = = = = = = = = = 文件的读写
文件系统:vfat、ext2、ext3、yaffs2、jffs2 (把文件的读写转换成对扇区的读写)
= = = = = = = = = ll_rw_block = = = = = = = = = 扇区的读写
1.把读写放入队列,
2.调用队列的处理函数(调顺序、合并等优化)
块设备驱动程序
= = = = = = = = = = = = = = = = = = = = = = = =
硬件: 硬盘、Flash
app:open read write "xxx.txt"
= = = = = = = = = = = = = = = = = = = = = = = = 文件的读写
文件系统:vfat、ext2、ext3、yaffs2、jffs2 (把文件的读写转换成对扇区的读写)
= = = = = = = = = ll_rw_block = = = = = = = = = 扇区的读写
1.把读写放入队列,
2.调用队列的处理函数(调顺序、合并等优化)
块设备驱动程序
= = = = = = = = = = = = = = = = = = = = = = = =
硬件: 硬盘、Flash
从ll_rw_block 开始分析 low level read-write block底层读写块
在fs\buffer.c中,
void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
{ // rw读还是写 nr数组有多少项 bhs数据传输的目地
int i;
for (i = 0; i < nr; i++) {
struct buffer_head *bh = bhs[i];
submit_bh(WRITE, bh); // 调用下面的
struct bio *bio; // 使用bh来构造bio (block input/output)
submit_bio(rw, bio); // block\ll_rw_blk.c
generic_make_request(bio); // 通用的构造请求 block\ll_rw_blk.c
__generic_make_request(bio); // block\ll_rw_blk.c
request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列
// 调用队列的函数 “构造请求函数”。当然也有默认函数
ret = q->make_request_fn(q, bio);
// 默认的函数是__make_request
__make_request
el_ret = elv_merge(q, &req, bio);// 电梯调度算法 (优化合并请求)将bio合并到队列
init_request_from_bio(req, bio);// 如果合并不成功,则使用bio构造请求
add_request(q, req); // 把请求放入到队列
__generic_unplug_device(q); // 执行队列
q->request_fn(q); // 调用队列的“处理函数”
怎么写块设备驱动程序
- 分配gendisk
- 设置
2.1 分配/设置队列:request_queue_t // 提供读写能力
blk_init_queue
2.2 设置gendisk其他信息 // 它提供属性,如容量 - 注册:add_disk