USB代码分析和学习心得

时间:2022-09-01 16:26:35
usb_init //USB的第一个初始化入口
=>bus_register(&usb_bus_type);//设备驱动模型,总线注册
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
};
usb_device_match 有两个用途,一个是USB设备的match,触发设备的probe,一个是USB intf的match,触发intf的probe
=>if (is_usb_device(dev))
return 1;//如果是device, 那么触发device的probe函数,也就是usb_probe_device
=>if (is_usb_interface(dev))//匹配后,触发intf的probe函数
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id(intf, usb_drv->id_table);
if (id)
return 1;
id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;

=>usb_hub_init();
=>usb_register(&hub_driver)//注册usb hub intf驱动
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe,
.disconnect = hub_disconnect,
.suspend = hub_suspend,
.resume = hub_resume,
.reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.unlocked_ioctl = hub_ioctl,
.id_table = hub_id_table,
.supports_autosuspend = 1,
};
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
=>kthread_run(hub_thread, NULL, "khubd");
=>hub_thread
=>do while里面调用hub_events();//循环探测usb hub的插入消息
=>hub_port_connect_change(hub, i, portstatus, portchange);//探测到有新的usb device插入
=>usb_alloc_dev(hdev, hdev->bus, port1);
=>hub_port_init(hub, udev, port1, i);//很重要,里面获取设备描述符
=>hub_port_reset(hub, port1, udev, delay);
=>set_port_feature(hub->hdev, port1, USB_PORT_FEAT_RESET);
=>usb_detect_quirks(udev);
=>usb_new_device(udev);//USB device注册会触发usb device driver usb_probe_device
=>usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};
=>new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
new_udriver->drvwrap.driver.probe = usb_probe_device;
new_udriver->drvwrap.driver.remove = usb_unbind_device;
new_udriver->drvwrap.driver.owner = owner;
=> driver_register(&new_udriver->drvwrap.driver);//注册linux device driver

当USB HUB探测到有新的USB device插入后,走usb_device_match函数,触发usb_probe_device
usb_probe_device
=>udriver->probe(udev);
=>generic_probe
=>usb_choose_configuration(udev);
=>usb_set_configuration(udev, c);
=>new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), GFP_NOIO);
=>intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.groups = usb_interface_groups;
device_initialize(&intf->dev);
=>device_add(&intf->dev); //注册usb intf,根据USB 设备驱动模型,将来与usb intf驱动match触发intf的probe函数

假设USB EHCI控制器挂在PCI桥片下
ehci_hcd_init //控制器的初始化函数
=>pci_register_driver(&PCI_DRIVER);
#define PCI_DRIVER ehci_pci_driver

static struct pci_driver ehci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,

.probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove,
.shutdown = usb_hcd_pci_shutdown,
};
static const struct pci_device_id pci_ids [] = { {
/* handle any USB 2.0 EHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0),
.driver_data = (unsigned long) &ehci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};

static const struct hc_driver ehci_pci_hc_driver = {
.description = hcd_name,
.product_desc = "EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),

/*

* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,

/*

* basic lifecycle operations
*/
.reset = ehci_pci_setup,
.start = ehci_run,
#ifdef CONFIG_PM
.pci_suspend = ehci_pci_suspend,
.pci_resume = ehci_pci_resume,
#endif
.stop = ehci_stop,
.shutdown = ehci_shutdown,

/*

* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,

/*

* scheduling support
*/
.get_frame_number = ehci_get_frame,

/*

* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,

/*

* call back when device connected and addressed
*/
.update_device = ehci_update_device,

.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};

usb_hcd_pci_probe
=>driver = (struct hc_driver *)id->driver_data;
=>pci_enable_device(dev)
=>__pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
=>do_pci_enable_device(dev, bars);
=>pcibios_enable_device(dev, bars);
=>pci_enable_resources(dev, mask);
=>if (r->flags & IORESOURCE_IO)//写commnd寄存器使能io和Mem空间
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, cmd);
=>usb_create_hcd(driver, &dev->dev, pci_name(dev));
=>usb_create_shared_hcd(driver, dev, bus_name, NULL);
=>hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);//分配hcd控制器空间
=>usb_bus_init(&hcd->self);//创建hcd总线并初始化
hcd->self.controller = dev;
hcd->self.bus_name = bus_name;
hcd->self.uses_dma = (dev->dma_mask != NULL);
=>init_timer(&hcd->rh_timer);//创建timer
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
=>hcd->rsrc_start = pci_resource_start(dev, 0);//通过pci设备获取基地址大小
hcd->rsrc_len = pci_resource_len(dev, 0);
request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)
=>hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);//对寄存器空间进行虚实地址映射
=>pci_set_master(dev);//可以做主
=>usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
=>hcd_buffer_create(hcd)//申请缓冲池
=>usb_register_bus(&hcd->self)//总线控制器注册
=>rhdev = usb_alloc_dev(NULL, &hcd->self, 0)//申请分配root hub
hcd->self.root_hub = rhdev;
=>hcd->driver->reset(hcd)
=>ehci_pci_setup//根据不同的厂商做一些寄存器的设置
=>usb_hcd_request_irqs(hcd, irqnum, irqflags);
=>hcd->state = HC_STATE_RUNNING;
retval = hcd->driver->start(hcd);
=>ehci_run
=>ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);//设置同步链表
ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);//设置异步链表
=>ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);//使能控制器
ehci->command |= CMD_RUN;
ehci_writel(ehci, ehci->command, &ehci->regs->command);
=>ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
=>register_root_hub(hcd)//注册root hub
=>usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
=>usb_new_device (usb_dev);//注册root hub device

usb_stor_init//usb storage intf 驱动初始化
=>usb_stor_init//usb storage intf 驱动注册
static struct usb_driver usb_storage_driver = {
.name = "usb-storage",
.probe = storage_probe,
.disconnect = usb_stor_disconnect,
.suspend = usb_stor_suspend,
.resume = usb_stor_resume,
.reset_resume = usb_stor_reset_resume,
.pre_reset = usb_stor_pre_reset,
.post_reset = usb_stor_post_reset,
.id_table = usb_storage_usb_ids,
.supports_autosuspend = 1,
.soft_unbind = 1,
};
=>usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
=>new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = (char *) new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
=>retval = driver_register(&new_driver->drvwrap.driver);

usb_probe_interface
=>driver->probe(intf, id);
=>storage_probe
=>usb_stor_probe1
=>scsi_host_alloc(&usb_stor_host_template, sizeof(*us));//分配scsi host控制器
=>associate_dev(us, intf);
=>get_transport(us);
=>get_protocol(us);
=>usb_stor_probe2(us);
=>get_pipes(us);
=>usb_stor_acquire_resources(us);
=>us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
=>th = kthread_run(usb_stor_control_thread, us, "usb-storage");
=>us->ctl_thread = th;
=>scsi_add_host(us_to_host(us), dev);//注册scsi host控制器
=>th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
=>wake_up_process(th);
=>scsi_scan_host(us_to_host(us));

usb_stor_control_thread//for 死循环,用于接受上层scsi发出的命令,该线程会在有命令的时候,调用proto_hander方法,从而调用transport,向usb core发送命令,详见 usb Mass Strorage分析(1) http://blog.csdn.net/sharecode/article/details/9166077
=>wait_for_completion_interruptible(&us->cmnd_ready)//被唤醒的地方的地方详见下文
=>us->proto_handler(us->srb, us);
=>usb_stor_transparent_scsi_command
=>usb_stor_invoke_transport(srb, us);
=>result = us->transport(srb, us);
=>usb_stor_Bulk_transport//3次创建qtd,分别是CBW,DATA和CSW
=>usb_stor_bulk_transfer_buf/* set up the command wrapper */
=>usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
usb_stor_blocking_completion, NULL);
=>usb_stor_msg_common(us, 0);
=>usb_submit_urb(us->current_urb, GFP_NOIO);
=>usb_hcd_submit_urb(urb, mem_flags);
=>status = rh_urb_enqueue(hcd, urb);//如果是root hub
=>hcd->driver->urb_enqueue(hcd, urb, mem_flags);//非root hub
=>ehci_urb_enqueue
=>submit_async(ehci, urb, &qtd_list, mem_flags);
=>qh_append_tds//将qtd加到qh队列里面
=>qh_link_async(ehci, qh);//启动ehci控制器,发送命令和数据,等待控制器返回中断
=>wait_for_completion_interruptible_timeout(
&urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT);
=>wait_for_common(x, timeout, TASK_INTERRUPTIBLE);//urb_done的done域urb->context没有设置位的话就堵塞在里面(死循环),置done位或者超时退出,由urb_hcd_irqd sg_complete置done位
=>interpret_urb_result
=>if (transfer_length)
usb_stor_bulk_srb(us, pipe, srb);/* DATA STAGE */
=>usb_stor_bulk_transfer_buf /* get CSW for device status */

USB命令下发
queuecommand
=>queuecommand_lck
=>srb->scsi_done
=>us->srb = srb;
=>complete(&us->cmnd_ready);//唤醒usb_stor_control_thread

usb_hcd_irq
=>hcd->driver->irq(hcd)
=>ehci_irq
=>ehci_work (ehci);
=>scan_async (ehci);
=>qh_completions(ehci, qh);
=>qtd_copy_status(ehci, urb, qtd->length, token);//从token获取错误状态
=>ehci_urb_done(ehci, last->urb, last_status);
=>usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
=>urb->complete (urb);
从USB的插入开始 http://blog.csdn.net/orz415678659/article/details/8449199

关于usb hub的中断传输,其urb的传输方式可以参考 http://blog.chinaunix.net/uid-26849197-id-3608563.html
uhci应该是上述方式。

另外pci ehci控制器应该用的是中断触发方式,不是轮询方式。与轮询方式,有一个前提,hub驱动先准备一个urb候着(在软件层面),当中断触发,解析status寄存器确认有新设备插入后,进行urb传输。
hub_activate
=>usb_submit_urb(hub->urb, GFP_NOIO);
=>usb_hcd_submit_urb(urb, mem_flags);
=>if (is_root_hub(urb->dev))//root hub的传输流程
status = rh_urb_enqueue(hcd, urb);
=>if (usb_endpoint_xfer_int(&urb->ep->desc))//中断传输
return rh_queue_status (hcd, urb);
=>hcd->status_urb = urb;//urb 候着
urb->hcpriv = hcd; /* indicate it's queued */
if (usb_endpoint_xfer_control(&urb->ep->desc))
return rh_call_control (hcd, urb);
else
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);

当插入usb设备,会触发中断
usb_hcd_irq
=>ehci_irq
=>status = ehci_readl(ehci, &ehci->regs->status); //读取status寄存器
=>if (status & STS_PCD) { /* port change detect */
usb_hcd_poll_rh_status
=>urb = hcd->status_urb; //使用候着的urb准备发送
=>usb_hcd_giveback_urb
=>urb->complete (urb);
=>hub_irq
=>kick_khubd(hub);
=>wake_up(&khubd_wait);//唤醒hub_thread
usb设备插入到hub上会触发中断的缘由如下:
查看ehci控制器芯片资料的描述
when this bit is a one, and the Port Change Detect bit in the USBSTS register is a one, the host controller will issue an interrupt. The interrupt is acknowledged by software clearing the Port Change Detect bit.