接上一篇: usb-skeleton.c到 usb core层的分析
对于存储设备的USB,Linux源码中有关于USB MASS Storage 的驱动程序(/drivers/usb/storage下),其中/drivers/usb/storage/usb.c 实现了驱动初始化,和usb-skeleton.c 例子以一样,调用 retval = usb_register(&usb_storage_driver); 注册usb设备,
static struct usb_driver usb_storage_driver = {
.name = "usb-storage",
.probe = storage_probe,
.disconnect = storage_disconnect,
#ifdef CONFIG_PM
.suspend = storage_suspend,
.resume = storage_resume,
.reset_resume = storage_reset_resume,
#endif
.pre_reset = storage_pre_reset,
.post_reset = storage_post_reset,
.id_table = storage_usb_ids,
.soft_unbind = 1,
};
static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
.....................
/*
* Ask the SCSI layer to allocate a host structure, with extra
* space at the end for our private us_data structure.
*/
host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
if (!host) {
printk(KERN_WARNING USB_STORAGE
"Unable to allocate the scsi host\n");
return -ENOMEM;
}
result = get_device_info(us, id);
if (result)
goto BadDevice;
result = get_transport(us); //获得usb设备端的的数据,并进行相应设置,见下面
if (result)
goto BadDevice;
result = get_protocol(us); //获得usb设备端协议的数据,并进行相应设置,见下面
if (result)
goto BadDevice;
result = get_pipes(us); //获得endpoint管道的数据,并进行相应设置,见下面
if (result)
goto BadDevice;
.........................
result = usb_stor_acquire_resources(us); //获得资源,开启了一个控制内核的线程static int usb_stor_control_thread(void * __us),用于接收上层命令,该线程会在有命令的时候(休眠等待),调用struct us_data(在storage中定义的数据)中的proto_handler方法,从而调用transport,向usbcore发送命令。非常重要,见下面代码
if (result)
goto BadDevice;
result = scsi_add_host(host, &intf->dev); 增加到SCSI host
if (result) {
printk(KERN_WARNING USB_STORAGE
"Unable to add the scsi host\n");
goto BadDevice;
}
/* Start up the thread for delayed SCSI-device scanning */
th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
}
流程结构图:
以下是进行usb设备端信息获取,同时设置us参数的函数get_transport()、get_protocal()、getPipes(),对应着上图中的Protocal Layer 和 Transfer Layer,分别在/drivers/usb/storage/protocal.c、transport.c中实现。初始化完成了交给SCSI层的接口后就由上层处理。
static int get_transport(struct us_data *us)
{
switch (us->protocol) {
case US_PR_CB:
us->transport_name = "Control/Bulk";
us->transport = usb_stor_CB_transport;
us->transport_reset = <