嵌入式Linux设备驱动开发之:块设备驱动编程
3.块设备注册和初始化
块设备的初始化过程要比字符设备复杂,它既需要像字符设备一样在加载内核时完成一定的工作,还需要在内核编译时增加一些内容。块设备驱动程序初始化时,由驱动程序的init()完成。
块设备的初始化过程如图11.6所示。
图11.6块设备驱动程序初始化过程
(1)向内核注册。
使用register_blkdev()函数对设备进行注册。
intregister_blkdev(unsignedintmajor,constchar*name);
其中参数major为要注册的块设备的主设备号,如果其值等于0,则系统动态分配并返回主设备号。参数name为设备名,在/proc/devices中显示。如果出错,则该函数返回负值。
与其对应的块设备的注销函数为unregister_blkdev(),其格式如下所示。
intunregister_blkdev(unsignedintmajor,constchar*name);
其参数必须与注册函数中的参数相同。如果出错则返回负值。
(2)申请并初始化请求队列。
这一步要调用blk_init_queue()函数来申请并初始化请求队列,其格式如下所示。
structrequest_queue*blk_init_queue(request_fn_proc*rfn,spinlock_t*lock)
其中参数rfn是请求队列的处理函数指针,它负责执行块设备的读、写请求。参数lock为自旋锁,用于控制对所分配的队列的访问。
(3)初始化并注册gendisk结构。
内核提供的gendisk结构相关函数如表11-16所示。
表11-16 gendisk结构相关函数
函数格式 | 说明 |
structgendisk*alloc_disk(intminors) | 动态分配gendisk结构,参数为次设备号的个数 |
voidadd_disk(structgendisk*disk) | 向系统注册gendisk结构 |
voiddel_gendisk(structgendisk*disk) | 从系统注销gendisk结构 |
首先使用alloc_disk()函数动态分配gendisk结构,接下来,对gendisk结构的主设备号(major)、次设备号相关成员(first_minor和minors)、块设备操作函数(fops)、请求队列(queue)、可包含的扇区数(capacity)以及设备名称(disk_name)等成员进行初始化。
在完成对gendisk的分配和初始化之后,调用add_disk()函数向系统注册块设备。在卸载gendisk结构的时候,要调用del_gendisk()函数。
4.块设备请求处理
块设备驱动中一般要实现一个请求队列处理函数来处理队列中的请求。从块设备的运行流程,可知请求处理是块设备的基本处理单位,也是最核心的部分。对块设备的读写操作被封装到了每一个请求中。
已经提过调用blk_init_queue()函数来申请并初始化请求队列。表11-17列出了一些与请求处理相关的函数。
表11-17 请求处理相关函数
函数格式 | 说明 |
request_queue_t*blk_alloc_queue(intgfp_mask) | 分配请求队列 |
request_queue_t*blk_init_queue | 分配并初始化请求队列 |
structrequest*blk_get_request | 从队列中获取一个请求 |
voidblk_requeue_request(request_queue_t*q,structrequest*rq) | 将请求再次加入队列 |
voidblk_queue_max_sectors | 设置最大访问扇区数 |
voidblk_queue_max_phys_segments | 设置最大物理段数 |
voidend_request(structrequest*req,intuptodate) | 结束本次请求处理 |
voidblk_queue_hardsect_size | 设置物理扇区大小 |
以上简单地介绍了块设备驱动编程的最基本的概念和流程。更深入的内容不是本书的重点,有兴趣的读者可以参考其他书籍。
linux相关文章:linux教程
评论