[RK3288][Android6.0] USB Mass Storage流程小结

来源:互联网 发布:知乎问题 提问者 编辑:程序博客网 时间:2024/05/19 01:59
Platform: ROCKCHIP
OS: Android 6.0
Kernel: 3.10.92


USB Mass Storage遵循Bulk-Only协议,参见:
http://www.usb.org/developers/docs/devclass_docs/usbmassbulk_10.pdf


传输过程大概如下:
1. 插上设备之后USB Host读取描述符信息,判断是Bulk-Only的Mass Storage之后设置地址进入Bulk-Only传输模式.
2. 一开始使用控制端点,后面传输数据使用Bulk-In和Bulk-Out端点.数据传输协议如下,摘自协议文档.


传输流程图如下:


USB 总线注册:
core/usb.c:
usb_init ->    bus_register
    
struct bus_type usb_bus_type = {
    .name =        "usb",
    .match =    usb_device_match,
    .uevent =    usb_uevent,
};


Mass Storage驱动:
假设已经枚举成功, 然后会调用相应驱动的probe函数.
module_usb_driver ->
    storage_probe ->
        unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;    //减法获得当前设备在表中的偏移,加法获取对应表中的usb设备.
        usb_stor_probe1 ->
            scsi_host_alloc    //分配一个scsi host, 上层通过scsi模块下发命令到usb模块,概念上可以理解为usb controller类似的东西,不过这里的scsi host是虚拟的.
            associate_dev    //初始化us data里相关变量,包括control/setup buffer, dma buffer.
            INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork);    //接下来usb_stor_probe2()马上会用到.
            get_device_info    //获取usb device info.
            get_transport    //获取transport, 这里是"Bulk"
            get_protocol    //获取protrocol, 这里是"Transparent SCSI"
        usb_stor_probe2 ->
            get_pipes    //获取pipe和endpoint
            usb_stor_acquire_resources ->
                usb_alloc_urb    //分配urb
                kthread_run(usb_stor_control_thread, us, "usb-storage");    //创建线程
                    usb_stor_control_thread    -> //负责处理urb事务.
                        wait_for_completion_interruptible(&us->cmnd_ready)    //休眠等待urb请求
            scsi_add_host    //mass storage通过scsi协议和上层通信
            queue_delayed_work(system_freezable_wq, &us->scan_dwork...) ->
                usb_stor_scan_dwork ->
                    usb_stor_Bulk_max_lun    ////获取最大logic number,一个设备可能有多个lun,比如多功能读卡器.
                    scsi_scan_host

URB的工作流程如下图:



usb_stor_control_thread会在两种情况下被唤醒:
1. scsi发命令过来
2. 设备被拔出.
            
关注第一种情况:
scsi_dispatch_cmd -> scsi.c
    host->hostt->queuecommand ->    //usb_stor_probe1()中赋值usb_stor_host_template
        queuecommand -> scsiglue.c 宏定义DEF_SCSI_QCMD(scsi_host.h中)会生成queuecommand()函数,内部调用queuecommand_lck()
            queuecommand_lck ->
                complete(&us->cmnd_ready) ->
                    usb_stor_control_thread    ->     usb.c
                        wait_for_completion_interruptible(&us->cmnd_ready)    //被唤醒
                        us->proto_handler ->    //初始化是get_protocol()中有赋值. 经过前面一系列判断之后开始处理command.
                            usb_stor_transparent_scsi_command ->
                                usb_stor_invoke_transport ->     transport.c //命令发送到transport layer
                                    us->transport ->    初始化时在get_transport()中赋值
                                        usb_stor_Bulk_transport ->    
                                            usb_stor_bulk_transfer_buf ->    //通过ctrl pipe发送command, 根据协议规定,需要发送CBW(command block wrapper.)
                                                usb_fill_bulk_urb    //填充
                                                usb_stor_msg_common    //提交
                                            usb_stor_bulk_srb ->    //真正传输数据的地方
                                                usb_stor_bulk_transfer_sglist ->    //用sglist可以提高传输效率,可以让不连续的buffers通过一次DMA操作完成传输.
                                                    usb_sg_init
                                                    usb_sg_wait    //提交并等待
                                                        usb_submit_urb ->     //大同小异.
                                                        wait_for_completion
                                            usb_stor_bulk_transfer_buf    //根据协议规定,需要读取CSW(command status wrapper.)


参考:

<<Linux那些事儿之我是U盘>>

http://www.csksoft.net/blog/post/linux_storage_mod.html

http://www.crifan.com/files/doc/docbook/usb_disk_driver/release/html/usb_disk_driver.html

http://www.doc88.com/p-7774041096629.html

http://blog.csdn.net/sharecode/article/details/9166077

1 0
原创粉丝点击