linux下有三大设备:字符设备,块设备,网卡设备
字符设备的控制流程
字符设备程序编写流程:
- 主设备号
- file_operation()
- register_chrdev()
- 入口函数
- 出口函数
应用层对字符设备的操作方式有:
- 查询方式:应用层不断查询状态的改变,(太累)
- 休眠-唤醒:在状态未改变的情况下,应用层休眠,当状态发生改变时,发出中断对应用层进行唤醒。
- poll机制:设置一个定时器,应用层定时查询状态的改变情况,未改变继续休眠
- 异步通知:字符设备状态发生改变时,发出信号告诉应用层,应用层处理,在其他状况下,应用层可以干其他的活,不像上面的需要休眠。
- input子系统:是一种代码的规范,我需要将自己的代码融入其中,而且input子系统使用也是上面4种机制写成。
硬盘的修改,擦除,烧写过程
FLASH的修改,擦除,烧写过程
通过以上的分析之后,块设备需要①把“读写”放入队列;②优化后在执行
块设备框架
<LINUX内核源代码情景分析>
分析ll_rw_block(作用:1、把读写放入队列;2、调用队列的处理函数,电梯调度算法(优化/调顺序/合并))
for (i = 0; i < nr; i++) {
struct buffer_head *bh = bhs[i];
submit_bh(rw, bh);
struct bio *bio; // 使用bh来构造bio (block input/output)
submit_bio(rw, bio);
// 通用的构造请求: 使用bio来构造请求(request)
generic_make_request(bio);
__generic_make_request(bio);
request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列
// 调用队列的"构造请求函数"
ret = q->make_request_fn(q, bio);
// 默认的函数是__make_request
__make_request
// 先尝试合并
elv_merge(q, &req, bio);
// 如果合并不成,使用bio构造请求
init_request_from_bio(req, bio);
// 把请求放入队列
add_request(q, req);
// 执行队列
__generic_unplug_device(q);
// 调用队列的"处理函数"
q->request_fn(q);
块设备驱动程序的书写
- 分配gendisk: alloc_disk
- 设置
2.1 分配/设置队列: request_queue_t // 它提供读写能力
blk_init_queue
2.2 设置gendisk其他信息 // 它提供属性: 比如容量 - 注册: add_disk