1. 内核何时去识别一个新的usb设备
内核运行hub_thread线程,hub_thread等待hub_events_list不为空时调用hub_events函数,在Hub_events当中查询usb端口的状态,如状态发生变化就根据情况添加usb设备。
- usb_init()->usb_hub_init() drivers/usb/core/usb.c
- usb_hub_init()->kthread_run(hub_thread……); drivers/usb/core/hub.c
- hub_thread->hub_events(); drivers/usb/core/hub.c
- hub_events->hub_port_status(); drivers/usb/core/hub.c
hub_events->hub_port_connect_change(); drivers/usb/core/hub.c
hub_events检测端口状态,添加usb新设备代码如下:
- /* deal with port status changes */
- for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
- if (test_bit(i, hub->busy_bits))
- continue;
- connect_change = test_bit(i, hub->change_bits);
- if (!test_and_clear_bit(i, hub->event_bits) &&
- !connect_change)
- continue;
- ret = hub_port_status(hub, i,
- &portstatus, &portchange);
- ......省略
- ......
- if (connect_change)
- hub_port_connect_change(hub, i,
- portstatus, portchange);
- }
- static int hub_thread(void *__unused)
- {
- /* khubd needs to be freezable to avoid intefering with USB-PERSIST
- * port handover. Otherwise it might see that a full-speed device
- * was gone before the EHCI controller had handed its port over to
- * the companion full-speed controller.
- */
- set_freezable();
- do {
- hub_events();
- wait_event_freezable(khubd_wait,
- !list_empty(&hub_event_list) ||
- kthread_should_stop());
- } while (!kthread_should_stop() || !list_empty(&hub_event_list));
- pr_debug("%s: khubd exiting\n", usbcore_name);
- return 0;
- }
- Hub_irq()->kick_khubd(hub) drivers/usb/core/hub.c
- kick_khubd(hub)->list_add_tail(&hub->event_list, &hub_event_list); drivers/usb/core/hub.c
Kick_khubd添加事件代码如下:
- static void kick_khubd(struct usb_hub *hub)
- {
- unsigned long flags;
- spin_lock_irqsave(&hub_event_lock, flags);
- if (!hub->disconnected && list_empty(&hub->event_list)) {
- list_add_tail(&hub->event_list, &hub_event_list);
- /* Suppress autosuspend until khubd runs */
- usb_autopm_get_interface_no_resume(
- to_usb_interface(hub->intfdev));
- wake_up(&khubd_wait);
- }
- spin_unlock_irqrestore(&hub_event_lock, flags);
- }
那么Hub_irq又是在什么时候调用的。
2. Hub_irq是在何时被调用
Hub_irq作为hub->urb的回调函数:usb_fill_int_urb(hub->urb......hub_irq),是在usb控制器驱动程序调用usb_add_hcd添加一个hub之后,完成usb总线匹配进而调用hub_probe来调用一系列函数之后完成回调的。
- Hub_probe->Hub_configure(); drivers/usb/core/hub.c
- Hub_configure()->hub_activate() drivers/usb/core/hub.c
- Hub_activate()->usb_submit_urb(hub->urb……) drivers/usb/core/hub.c
- usb_submit_urb-> usb_hcd_submit_urb drivers/usb/core/hub.c
- usb_hcd_submit_urb-> rh_urb_enqueue drivers/usb/core/hcd.c
- rh_urb_enqueue-> rh_queue_status drivers/usb/core/hcd.c
- rh_queue_status ->usb_hcd_poll_rh_status drivers/usb/core/hcd.c
- usb_hcd_poll_rh_status ->usb_hcd_giveback_urb drivers/usb/core/hcd.c
- usb_hcd_giveback_urb->(urb->complete=hub_irq) drivers/usb/core/hcd.c
在usb_hcd_poll_rh_status当中不是马上完成对usb_hcd_give_back_urb的调用的,而是在一直调用控制器提供的hub_status_data接口获取usb端口的状态,直到获取端口状态发生改变才会执行回调函数。
- void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
- {
- struct urb *urb;
- int length;
- unsigned long flags;
- char buffer[6]; /* Any root hubs with > 31 ports? */
- if (unlikely(!hcd->rh_pollable))
- return;
- if (!hcd->uses_new_polling && !hcd->status_urb)
- return;
- length = hcd->driver->hub_status_data(hcd, buffer);
- if (length > 0) {
- /* try to complete the status urb */
- spin_lock_irqsave(&hcd_root_hub_lock, flags);
- urb = hcd->status_urb;
- if (urb) {
- clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
- hcd->status_urb = NULL;
- urb->actual_length = length;
- memcpy(urb->transfer_buffer, buffer, length);
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock(&hcd_root_hub_lock);
- usb_hcd_giveback_urb(hcd, urb, 0)
3. 总结
从整个过程来看是内核移植在等待一个事件,这个事件产生条件是:控制器驱动调用usb_add_hcd添加一个hub,触发hub_probe函数,进而submit一个urb请求,在这个请求中会间隔轮询usb的状态,一旦usb的状态发生变化则产生事件。这个事件被内核识别到,最后来获取usb相关信息,为内核添加一个usb设备。