当usb设备插入接口,电压变化会通知到usb主控器,
触发主控器中断,如果主控器不支持中断,那么会使用rh_timer方法,轮询接口
其结果都是调用usb_hcd_poll_rh_status
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); //获取urb数据长度
if (length > 0) {
/* try to complete the status urb */
spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb; //获取要处理的urb
if (urb) {
clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags); //清除urb主控器poll标志
hcd->status_urb = NULL; //清空待处理urb
urb->actual_length = length; //获取urb数据长度
memcpy(urb->transfer_buffer, buffer, length); //复制urb缓冲区
usb_hcd_unlink_urb_from_ep(hcd, urb); //从主控器的端点上解绑urb
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, 0); //处理urb并回传urb给设备
spin_lock(&hcd_root_hub_lock);
} else {
length = 0;
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
}
spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :
(length == 0 && hcd->status_urb != NULL))
mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
}
usb_hcd_giveback_urb函数
void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
urb->hcpriv = NULL;
if (unlikely(urb->unlinked))
status = urb->unlinked;
else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
urb->actual_length < urb->transfer_buffer_length &&
!status))
status = -EREMOTEIO;
unmap_urb_for_dma(hcd, urb);
usbmon_urb_complete(&hcd->self, urb, status);
usb_unanchor_urb(urb);
/* pass ownership to the completion handler */
urb->status = status;
urb->complete (urb); //执行urb回调函数,就是hub_irq
atomic_dec (&urb->use_count);
if (unlikely(atomic_read(&urb->reject)))
wake_up (&usb_kill_urb_queue);
usb_put_urb (urb);
}
hub_irq函数
static void hub_irq(struct urb *urb)
{
struct usb_hub *hub = urb->context;
int status = urb->status;
unsigned i;
unsigned long bits;
switch (status) {
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
return;
default: //错误
dev_dbg (hub->intfdev, "transfer --> %d\n", status);
if ((++hub->nerrors < 10) || hub->error)
goto resubmit;
hub->error = status;
case 0: //端口状态有变化
bits = 0;
for (i = 0; i < urb->actual_length; ++i)
bits |= ((unsigned long) ((*hub->buffer)[i]))<< (i*8);
hub->event_bits[0] = bits; //填充hub->event_bit数组
break;
}
hub->nerrors = 0;
kick_khubd(hub); //调用kick_khubd函数
resubmit:
if (hub->quiescing)
return;
if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0&& status != -ENODEV && status != -EPERM)
dev_err (hub->intfdev, "resubmit --> %d\n", status);
}
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);
usb_autopm_get_interface_no_resume(to_usb_interface(hub->intfdev));
wake_up(&khubd_wait); //唤醒khubd_wait相关的等待队列
}
spin_unlock_irqrestore(&hub_event_lock, flags);
}
这里会触发hub_events函数,原因如下
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));
hub_events函数
static void hub_events(void)
{
struct list_head *tmp;
struct usb_device *hdev;
struct usb_interface *intf;
struct usb_hub *hub;
struct device *hub_dev;
u16 hubstatus;
u16 hubchange;
u16 portstatus;
u16 portchange;
int i, ret;
int connect_change;
//hcd usb主控器的状态由usb主控器的中断例程根据具体硬件状态去设置
while (1) {
spin_lock_irq(&hub_event_lock);
//这次执行假设usb主控器已经注册
if (list_empty(&hub_event_list)) { //usb事件链表不为为空
spin_unlock_irq(&hub_event_lock);
break;
}
tmp = hub_event_list.next; //拿出hub_event链表项
list_del_init(tmp); //从hub_event_list删除其
hub = list_entry(tmp, struct usb_hub, event_list); //根据链表项获取usb_hub
kref_get(&hub->kref); //引用计数
spin_unlock_irq(&hub_event_lock);
hdev = hub->hdev; //获取hub usb设备
hub_dev = hub->intfdev; //获取hub 设备文件
intf = to_usb_interface(hub_dev); //获取hub usb接口
usb_lock_device(hdev);
if (unlikely(hub->disconnected))
goto loop_disconnected;
if (hdev->state == USB_STATE_NOTATTACHED) { //判断是否为USB_STATE_NOTATTACHED状态
hub->error = -ENODEV;
hub_quiesce(hub, HUB_DISCONNECT);
goto loop;
}
ret = usb_autopm_get_interface(intf);
if (ret) {
dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
goto loop;
}
if (hub->quiescing)
goto loop_autopm;
if (hub->error) {
dev_dbg (hub_dev, "resetting for error %d\n",hub->error);
ret = usb_reset_device(hdev);
if (ret) {
dev_dbg (hub_dev,"error resetting hub: %d\n", ret);
goto loop_autopm;
}
hub->nerrors = 0;
hub->error = 0;
}
for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
if (test_bit(i, hub->busy_bits))
continue;
connect_change = test_bit(i, hub->change_bits); //判断是否hub口状态变化