Android usb读卡器sd卡热插拔心得
最近跟usb打了一段时间交道,处理了一些storage方面的项目需求,现在记录一些调试思路,同时分享给一些有缘人,希望能够给予一些灵感。 平台是qnx hypervisor,但是这个usb控制器是完全pass给了Android hlos,所以纯Android这么做大概也能行。主要的需求如下介绍:
主机两个usb口,分别插u盘和usb读卡器,同时工作。第一个需求是要让usb读卡器支持sd卡的热插拔;第二个需求是要区分出sd card 和 udisk
先说热插拔的做法
先做对比,发现ubuntu20的电脑支持sd card的热插拔,然后看了看dmesg,没啥有效帮助。 然后是设备上插入读卡器尝试热插拔,发现插拔前后没有变化,看了看dmesg,也没啥帮助。 但是这一对比,发现sd card的热插拔,对于电脑来说只是partition的变化,也就是
插上读卡器会多了一个sda设备,读卡器有卡的时候会再多sda1这些分区,拔掉sd卡这些分区就消失了
以此为切入点去read the fuck code。哦对了,前面提了一嘴ubuntu20,是因为内核版本是5.4 。而我用的设备代码有两套,一套是4.14,一套是5.4.86 。当时以为该需求只是内核版本的问题,后来两个版本都试了热插拔无效。
首先,大概过了一遍probe,个人习惯,无从下手先随便喽一眼,来两套代码流,虽然没得啥子帮助
module_usb_stor_driver
usb_stor_host_template_init.usb_stor_host_template
usb_register(usb_storage_driver)
usb_storage_driver.storage_probe // scsi
usb_stor_probe1 + usb_stor_probe2
sd_probe_async -> sd_revalidate_disk -> sd_spinup_disk -> scsi_execute -> blk_execute_rq -> __blk_run_queue_uncond -> scsi_request_fn -> scsi_dispatch_cmd -> queuecommand_lck -> usb_stor_control_thread
sd_probe_async -> device_add_disk -> register_disk -> blkdev_get -> rescan_partitions
提一嘴, usb storage 、 scsi 、 sd 这三块是联系在一起的。 然后想找找扫描分区的线索,发现了rescan的接口,从class设备节点中尝试rescan发现木得效果(这时是在4.14的os中),于是去看了看代码
static void sd_rescan(struct device *dev)
{
struct scsi_disk *sdkp = dev_get_drvdata(dev);
revalidate_disk(sdkp->disk);
}
肥肠八嘎,就是调用了probe里的 sd_revalidate_disk,没有疗效 接下来接着想办法去搜线索,发现了partprobe这个玩意可以扫描分区
用法:partprobe [选项] [设备]… 将分区表的变更通报操作系统。 -d, --dry-run 并非真的通报操作系统 -s, --summary 印出内容的概要 -h, --help 显示这个说明然后离开 -v, --version 输出版本信息然后离开 如果没有指定任何设备,探查所有分区。
但是设备上没有,去toybox里搜了搜,是它的一个子命令。下一步,展示 这次我在两个版本os都试了, 发现4.14版本会报设备busy,而5.4版本扫描成功,实现目标
跟踪partprobe的函数流,发现其通过IOCTL向块设备做请求,最后走到了check_events, 4.14版本的check_events接口被某些老吊干掉了。重新恢复回来,然后起了一个service 定期扫描sda分区,实现sd卡热插拔。 整体看代码,综合fs、block、sd、scsi、usb_storage就能弄明白这块,有心人可以盘它
再说说区分udisk和sdcard的做法
前面看插拔usb storage全设备log时,打开scsi log开关,得到了一个线索,对这个需求有很大帮助 就是他会有一套交互协议,发送一串cmd
Command INQUIRY (6 bytes) Command TEST_UNIT_READY (6 bytes) Command READ_CAPACITY (10 bytes) Command MODE_SENSE (6 bytes) Command ALLOW_MEDIUM_REMOVAL (6 bytes) Command READ_10 (10 bytes)
而这个INQUIRY能够获取很多基本信息存入了scsi_device中记录。 在sd_probe中利用好这些信息,通过strcmp来比较vendor、model判断读卡器和u盘,固定index来固定sdx偏移量,以及major和minor
vold在通过netlink接收 events时是根据major和minor去/dev/block/vold/下去mknod,然后进行mount挂载。固定了minor就相当于固定了这里的节点,进一步也就能够区别mount出udisk和sdcard各自的路径
|