第十三章,块设备驱动
块设备的file_ops中没有read(), write(),但是有media_changed(), getgeo()用来获取磁盘的状态和信息。使用struct gendisk来表示一个磁盘,操作函数包括alloc_disk(), add_disk(), del_gendisk()等, get_disk()/put_disk()用于计数。对块的操作通过bio,request和request_queue来。结构struct bio中bi_rw表示读写,bi_flags表示命令和状态,bi_iter指明地址和长度(单位为sector)。I/O调度器将bio调整合并后,成为一个request,每个块设备有自己的request_queue。操作函数包括blk_init_queue(), blk_alloc_queue(),blk_peek_queue(), blk_start_request(), bio遍历(bio_for_each_segment), blk_end_request_all(),blk_endio()等。调度器包括Noop, DEADLINE和CFQ。
块设备初始化register_blkdev,其中包括init request queue和添加disk。
MMC驱动包括card(对接块设备子系统), core(负责协议)和host(对接SoC中的controller)三部分。函数mmc_init_queue()绑定了mmc_request_fn(),后者会唤醒线程mmc_queue_thread来处理mq->issue_fn,也就是mmc_blk_issue_req(),从而调用mmc_start_req(),后者调用host_ops定义的函数,操作MMC。大多数MMC controller也就是SDHCI,可以直接用drivers/mmc/host/sdhci.c驱动。
第十四章,网络设备驱动
上层调用dev_queue_xmit()发包,调用netif_rx()收包。数据结构为struct sk_buff(socket buffer)。操作函数为alloc_skb(), kfree_skb(), skb_put(往后加), skb_push(往前推), skb_reserve(腾出头部空间)等。Struct net_device和net_device_ops。其中有收发的函数,还有收发时戳。发包时,驱动可以通过netif_stop_queue()让上层停止发送,通过netif_wake_queue()继续发送。发包时,如果失败(timeout),会有一个callback函数,可以retry。
收包是通过中断实现的。可以通过中断+轮询的方式收包,叫做NAPI,调用netif_napi_add()添加一个poll函数。收到中断通知后,关闭中断,用poll方式连续收包,收完后,再打开中断。
驱动还提供一些函数用于查询链路状态(link status),设置MAC地址,统计收发数据等。
第十五章,I2C核心、总线和设备驱动
所有的I2C设备可以在/sys/bus/i2c下面看到。代码在drviers/i2c目录下。头文件i2c.h中定义了4个数据结构:i2c_adapter, i2c_algorithm, i2c_driver和i2c_client。其中i2c_adapter对应于一个物理上的适配器,而i2c_algorithm对应一套通信方法,其关键函数是master_xfer(),发送i2c_msg。i2c_driver对应于一套驱动方法,主要成员有probe(), remove(), suspend(), resume()等,同时提供一个id_table用于匹配。I2c_client对应于真实的物理设备。I2c_driver只是实现设备与总线的挂接,而挂接的设备则种类多样。
核心的函数包括,i2c_add_adapter(), i2c_register_driver(),i2c_transfer(), i2c_master_send()/recv()等。
适配器可以看作是platform总线上的一个客户,通过module_platform_driver(xxx_i2c_driver)来声明一个驱动。
设备驱动主要就是填充i2c_driver和i2c_client两个结构,通过i2c_add_driver()来添加。
代码i2c-dev.c实现了主设备号为89的/dev/i2c-x的设备,用户空间的程序可以打开此设备,读写i2c寄存器。可以通过read()/write()读写,也可以ioctl()读写。