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);
-
}
hub_events的调用依赖于hub_events_list不为空,代码如下:
-
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_events的执行就是往
hub_events_list添加事件,这里指出
hub_irq来
完成这个事情:
-
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设备。
阅读(2883) | 评论(0) | 转发(0) |