当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));
- }
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);
- }
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);
- }
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);
- }
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));
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口状态变化
- if (!test_and_clear_bit(i, hub->event_bits) &&!connect_change)
- continue;
- ret = hub_port_status(hub, i,&portstatus, &portchange);
- if (ret < 0)
- continue;
- if (portchange & USB_PORT_STAT_C_CONNECTION) { //hub口连接上设备
- clear_port_feature(hdev, i,USB_PORT_FEAT_C_CONNECTION);
- connect_change = 1;
- }
- if (portchange & USB_PORT_STAT_C_ENABLE) { //hub口的设备使能
- if (!connect_change)
- dev_dbg (hub_dev,"port %d enable change,status %08x\n",i, portstatus);
- clear_port_feature(hdev, i,USB_PORT_FEAT_C_ENABLE);
- if (!(portstatus & USB_PORT_STAT_ENABLE)&& !connect_change&& hdev->children[i-1]) {
- dev_err (hub_dev,"port %i disabled by hub (EMI?),re-enabling...\n",i);
- connect_change = 1;
- }
- }
- if (portchange & USB_PORT_STAT_C_SUSPEND) { //hub口的设备挂起
- struct usb_device *udev;
- clear_port_feature(hdev, i,USB_PORT_FEAT_C_SUSPEND);
- udev = hdev->children[i-1];
- if (udev) {
- msleep(10);
- usb_lock_device(udev);
- ret = usb_remote_wakeup(hdev->children[i-1]);
- usb_unlock_device(udev);
- if (ret < 0)
- connect_change = 1;
- } else {
- ret = -ENODEV;
- hub_port_disable(hub, i, 1);
- }
- dev_dbg (hub_dev,"resume on port %d, status %d\n",i, ret);
- }
- if (portchange & USB_PORT_STAT_C_OVERCURRENT) { //hub口设备过流
- dev_err (hub_dev,"over-current change on port %d\n",i);
- clear_port_feature(hdev, i,USB_PORT_FEAT_C_OVER_CURRENT);
- hub_power_on(hub, true);
- }
- if (portchange & USB_PORT_STAT_C_RESET) { //hub口设备重置
- dev_dbg (hub_dev,"reset change on port %d\n",i);
- clear_port_feature(hdev, i,USB_PORT_FEAT_C_RESET);
- }
- if (connect_change) //hub口有变化(设备插入肯定有变化)
- hub_port_connect_change(hub, i,portstatus, portchange); //hub口变化处理
- }
- if (test_and_clear_bit(0, hub->event_bits) == 0)
- ;
- else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
- dev_err (hub_dev, "get_hub_status failed\n");
- else {
- if (hubchange & HUB_CHANGE_LOCAL_POWER) {
- dev_dbg (hub_dev, "power change\n");
- clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
- if (hubstatus & HUB_STATUS_LOCAL_POWER)
- hub->limited_power = 1;
- else
- hub->limited_power = 0;
- }
- if (hubchange & HUB_CHANGE_OVERCURRENT) {
- dev_dbg (hub_dev, "overcurrent change\n");
- msleep(500);
- clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
- hub_power_on(hub, true);
- }
- }
- loop_autopm:
- usb_autopm_put_interface_no_suspend(intf);
- loop:
- usb_autopm_put_interface(intf);
- loop_disconnected:
- usb_unlock_device(hdev);
- kref_put(&hub->kref, hub_release);
- }
- }
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口状态变化
if (!test_and_clear_bit(i, hub->event_bits) &&!connect_change)
continue;
ret = hub_port_status(hub, i,&portstatus, &portchange);
if (ret < 0)
continue;
if (portchange & USB_PORT_STAT_C_CONNECTION) { //hub口连接上设备
clear_port_feature(hdev, i,USB_PORT_FEAT_C_CONNECTION);
connect_change = 1;
}
if (portchange & USB_PORT_STAT_C_ENABLE) { //hub口的设备使能
if (!connect_change)
dev_dbg (hub_dev,"port %d enable change,status %08x\n",i, portstatus);
clear_port_feature(hdev, i,USB_PORT_FEAT_C_ENABLE);
if (!(portstatus & USB_PORT_STAT_ENABLE)&& !connect_change&& hdev->children[i-1]) {
dev_err (hub_dev,"port %i disabled by hub (EMI?),re-enabling...\n",i);
connect_change = 1;
}
}
if (portchange & USB_PORT_STAT_C_SUSPEND) { //hub口的设备挂起
struct usb_device *udev;
clear_port_feature(hdev, i,USB_PORT_FEAT_C_SUSPEND);
udev = hdev->children[i-1];
if (udev) {
msleep(10);
usb_lock_device(udev);
ret = usb_remote_wakeup(hdev->children[i-1]);
usb_unlock_device(udev);
if (ret < 0)
connect_change = 1;
} else {
ret = -ENODEV;
hub_port_disable(hub, i, 1);
}
dev_dbg (hub_dev,"resume on port %d, status %d\n",i, ret);
}
if (portchange & USB_PORT_STAT_C_OVERCURRENT) { //hub口设备过流
dev_err (hub_dev,"over-current change on port %d\n",i);
clear_port_feature(hdev, i,USB_PORT_FEAT_C_OVER_CURRENT);
hub_power_on(hub, true);
}
if (portchange & USB_PORT_STAT_C_RESET) { //hub口设备重置
dev_dbg (hub_dev,"reset change on port %d\n",i);
clear_port_feature(hdev, i,USB_PORT_FEAT_C_RESET);
}
if (connect_change) //hub口有变化(设备插入肯定有变化)
hub_port_connect_change(hub, i,portstatus, portchange); //hub口变化处理
}
if (test_and_clear_bit(0, hub->event_bits) == 0)
;
else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
dev_err (hub_dev, "get_hub_status failed\n");
else {
if (hubchange & HUB_CHANGE_LOCAL_POWER) {
dev_dbg (hub_dev, "power change\n");
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
if (hubstatus & HUB_STATUS_LOCAL_POWER)
hub->limited_power = 1;
else
hub->limited_power = 0;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (hub_dev, "overcurrent change\n");
msleep(500);
clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
hub_power_on(hub, true);
}
}
loop_autopm:
usb_autopm_put_interface_no_suspend(intf);
loop:
usb_autopm_put_interface(intf);
loop_disconnected:
usb_unlock_device(hdev);
kref_put(&hub->kref, hub_release);
}
}
hub口状态变化处理函数
- static void hub_port_connect_change(struct usb_hub *hub, int port1,u16 portstatus, u16 portchange)
- {
- struct usb_device *hdev = hub->hdev;
- struct device *hub_dev = hub->intfdev;
- struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
- unsigned wHubCharacteristics =le16_to_cpu(hub->descriptor->wHubCharacteristics);
- struct usb_device *udev;
- int status, i;
- dev_dbg (hub_dev,"port %d, status %04x, change %04x, %s\n",port1, portstatus, portchange, portspeed (portstatus));
- if (hub->has_indicators) {
- set_port_led(hub, port1, HUB_LED_AUTO);
- hub->indicator[port1-1] = INDICATOR_AUTO;
- }
- #ifdef CONFIG_USB_OTG
- if (hdev->bus->is_b_host)
- portchange &= ~(USB_PORT_STAT_C_CONNECTION |USB_PORT_STAT_C_ENABLE);
- #endif
- udev = hdev->children[port1-1]; //获取usb_device
- if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&udev->state != USB_STATE_NOTATTACHED) {
- usb_lock_device(udev);
- if (portstatus & USB_PORT_STAT_ENABLE) {
- status = 0;
- #ifdef CONFIG_USB_SUSPEND
- } else if (udev->state == USB_STATE_SUSPENDED &&udev->persist_enabled) {
- status = usb_remote_wakeup(udev);
- #endif
- } else {
- status = -ENODEV;
- }
- usb_unlock_device(udev);
- if (status == 0) {
- clear_bit(port1, hub->change_bits);
- return;
- }
- }
- if (udev)
- usb_disconnect(&hdev->children[port1-1]);
- clear_bit(port1, hub->change_bits); //清除标志位
- if (!(portstatus & USB_PORT_STAT_CONNECTION) ||(portchange & USB_PORT_STAT_C_CONNECTION))
- clear_bit(port1, hub->removed_bits);
- if (portchange & (USB_PORT_STAT_C_CONNECTION |USB_PORT_STAT_C_ENABLE)) {
- status = hub_port_debounce(hub, port1);
- if (status < 0) {
- if (printk_ratelimit())
- dev_err(hub_dev, "connect-debounce failed,port %d disabled\n", port1);
- portstatus &= ~USB_PORT_STAT_CONNECTION;
- } else {
- portstatus = status;
- }
- }
- if (!(portstatus & USB_PORT_STAT_CONNECTION) ||test_bit(port1, hub->removed_bits)) {
- if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2&& !(portstatus & USB_PORT_STAT_POWER))
- set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
- if (portstatus & USB_PORT_STAT_ENABLE)
- goto done;
- return;
- }
- for (i = 0; i < SET_CONFIG_TRIES; i++) { //配置usb设备
- udev = usb_alloc_dev(hdev, hdev->bus, port1); //分配usb_device
- if (!udev) {
- dev_err (hub_dev,"couldn't allocate port %d usb_device\n",port1);
- goto done;
- }
- usb_set_device_state(udev, USB_STATE_POWERED); //设置usb设备为得电态
- udev->bus_mA = hub->mA_per_port; //指定其电流限额
- udev->level = hdev->level + 1; //层数为所属的hub的层数+1
- udev->wusb = hub_is_wusb(hub);
- if (!(hcd->driver->flags & HCD_USB3)) //usb设备速度
- udev->speed = USB_SPEED_UNKNOWN;
- else if ((hdev->parent == NULL) &&(portstatus & USB_PORT_STAT_SUPER_SPEED))
- udev->speed = USB_SPEED_SUPER;
- else
- udev->speed = USB_SPEED_UNKNOWN;
- choose_address(udev); //选择一个usb设备地址
- if (udev->devnum <= 0) {
- status = -ENOTCONN; /* Don't retry */
- goto loop;
- }
- status = hub_port_init(hub, udev, port1, i); //初始化hub端口,枚举
- if (status < 0)
- goto loop;
- usb_detect_quirks(udev);
- if (udev->quirks & USB_QUIRK_DELAY_INIT)
- msleep(1000);
- if (udev->descriptor.bDeviceClass == USB_CLASS_HUB&& udev->bus_mA <= 100) { //若插进来的也是hub
- u16 devstat;
- status = usb_get_status(udev, USB_RECIP_DEVICE, 0,&devstat);
- if (status < 2) {
- dev_dbg(&udev->dev, "get status %d ?\n", status);
- goto loop_disable;
- }
- le16_to_cpus(&devstat);
- if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
- dev_err(&udev->dev,"can't connect bus-powered hub to this port\n");
- if (hub->has_indicators) {
- hub->indicator[port1-1] =INDICATOR_AMBER_BLINK;
- schedule_delayed_work (&hub->leds, 0);
- }
- status = -ENOTCONN;
- goto loop_disable;
- }
- }
- if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200&& udev->speed == USB_SPEED_FULL&& highspeed_hubs != 0)
- check_highspeed (hub, udev, port1);
- status = 0;
- spin_lock_irq(&device_state_lock);
- if (hdev->state == USB_STATE_NOTATTACHED)
- status = -ENOTCONN;
- else
- hdev->children[port1-1] = udev; //设置hub usb设备的子设备
- spin_unlock_irq(&device_state_lock);
- if (!status) {
- status = usb_new_device(udev); //usb添加新设备
- if (status) {
- spin_lock_irq(&device_state_lock);
- hdev->children[port1-1] = NULL;
- spin_unlock_irq(&device_state_lock);
- }
- }
- if (status)
- goto loop_disable;
- status = hub_power_remaining(hub);
- if (status)
- dev_dbg(hub_dev, "%dmA power budget left\n", status);
- return;
- loop_disable:
- hub_port_disable(hub, port1, 1);
- loop:
- usb_ep0_reinit(udev);
- release_address(udev);
- hub_free_dev(udev);
- usb_put_dev(udev);
- if ((status == -ENOTCONN) || (status == -ENOTSUPP))
- break;
- }
- if (hub->hdev->parent ||!hcd->driver->port_handed_over ||!(hcd->driver->port_handed_over)(hcd, port1))
- dev_err(hub_dev, "unable to enumerate USB device on port %d\n",port1);
- done:
- hub_port_disable(hub, port1, 1);
- if (hcd->driver->relinquish_port && !hub->hdev->parent)
- hcd->driver->relinquish_port(hcd, port1);
- }
static void hub_port_connect_change(struct usb_hub *hub, int port1,u16 portstatus, u16 portchange)
{
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
unsigned wHubCharacteristics =le16_to_cpu(hub->descriptor->wHubCharacteristics);
struct usb_device *udev;
int status, i;
dev_dbg (hub_dev,"port %d, status %04x, change %04x, %s\n",port1, portstatus, portchange, portspeed (portstatus));
if (hub->has_indicators) {
set_port_led(hub, port1, HUB_LED_AUTO);
hub->indicator[port1-1] = INDICATOR_AUTO;
}
#ifdef CONFIG_USB_OTG
if (hdev->bus->is_b_host)
portchange &= ~(USB_PORT_STAT_C_CONNECTION |USB_PORT_STAT_C_ENABLE);
#endif
udev = hdev->children[port1-1]; //获取usb_device
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&udev->state != USB_STATE_NOTATTACHED) {
usb_lock_device(udev);
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0;
#ifdef CONFIG_USB_SUSPEND
} else if (udev->state == USB_STATE_SUSPENDED &&udev->persist_enabled) {
status = usb_remote_wakeup(udev);
#endif
} else {
status = -ENODEV;
}
usb_unlock_device(udev);
if (status == 0) {
clear_bit(port1, hub->change_bits);
return;
}
}
if (udev)
usb_disconnect(&hdev->children[port1-1]);
clear_bit(port1, hub->change_bits); //清除标志位
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||(portchange & USB_PORT_STAT_C_CONNECTION))
clear_bit(port1, hub->removed_bits);
if (portchange & (USB_PORT_STAT_C_CONNECTION |USB_PORT_STAT_C_ENABLE)) {
status = hub_port_debounce(hub, port1);
if (status < 0) {
if (printk_ratelimit())
dev_err(hub_dev, "connect-debounce failed,port %d disabled\n", port1);
portstatus &= ~USB_PORT_STAT_CONNECTION;
} else {
portstatus = status;
}
}
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||test_bit(port1, hub->removed_bits)) {
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2&& !(portstatus & USB_PORT_STAT_POWER))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
if (portstatus & USB_PORT_STAT_ENABLE)
goto done;
return;
}
for (i = 0; i < SET_CONFIG_TRIES; i++) { //配置usb设备
udev = usb_alloc_dev(hdev, hdev->bus, port1); //分配usb_device
if (!udev) {
dev_err (hub_dev,"couldn't allocate port %d usb_device\n",port1);
goto done;
}
usb_set_device_state(udev, USB_STATE_POWERED); //设置usb设备为得电态
udev->bus_mA = hub->mA_per_port; //指定其电流限额
udev->level = hdev->level + 1; //层数为所属的hub的层数+1
udev->wusb = hub_is_wusb(hub);
if (!(hcd->driver->flags & HCD_USB3)) //usb设备速度
udev->speed = USB_SPEED_UNKNOWN;
else if ((hdev->parent == NULL) &&(portstatus & USB_PORT_STAT_SUPER_SPEED))
udev->speed = USB_SPEED_SUPER;
else
udev->speed = USB_SPEED_UNKNOWN;
choose_address(udev); //选择一个usb设备地址
if (udev->devnum <= 0) {
status = -ENOTCONN; /* Don't retry */
goto loop;
}
status = hub_port_init(hub, udev, port1, i); //初始化hub端口,枚举
if (status < 0)
goto loop;
usb_detect_quirks(udev);
if (udev->quirks & USB_QUIRK_DELAY_INIT)
msleep(1000);
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB&& udev->bus_mA <= 100) { //若插进来的也是hub
u16 devstat;
status = usb_get_status(udev, USB_RECIP_DEVICE, 0,&devstat);
if (status < 2) {
dev_dbg(&udev->dev, "get status %d ?\n", status);
goto loop_disable;
}
le16_to_cpus(&devstat);
if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_err(&udev->dev,"can't connect bus-powered hub to this port\n");
if (hub->has_indicators) {
hub->indicator[port1-1] =INDICATOR_AMBER_BLINK;
schedule_delayed_work (&hub->leds, 0);
}
status = -ENOTCONN;
goto loop_disable;
}
}
if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200&& udev->speed == USB_SPEED_FULL&& highspeed_hubs != 0)
check_highspeed (hub, udev, port1);
status = 0;
spin_lock_irq(&device_state_lock);
if (hdev->state == USB_STATE_NOTATTACHED)
status = -ENOTCONN;
else
hdev->children[port1-1] = udev; //设置hub usb设备的子设备
spin_unlock_irq(&device_state_lock);
if (!status) {
status = usb_new_device(udev); //usb添加新设备
if (status) {
spin_lock_irq(&device_state_lock);
hdev->children[port1-1] = NULL;
spin_unlock_irq(&device_state_lock);
}
}
if (status)
goto loop_disable;
status = hub_power_remaining(hub);
if (status)
dev_dbg(hub_dev, "%dmA power budget left\n", status);
return;
loop_disable:
hub_port_disable(hub, port1, 1);
loop:
usb_ep0_reinit(udev);
release_address(udev);
hub_free_dev(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
if (hub->hdev->parent ||!hcd->driver->port_handed_over ||!(hcd->driver->port_handed_over)(hcd, port1))
dev_err(hub_dev, "unable to enumerate USB device on port %d\n",port1);
done:
hub_port_disable(hub, port1, 1);
if (hcd->driver->relinquish_port && !hub->hdev->parent)
hcd->driver->relinquish_port(hcd, port1);
}
hub端口初始化
- static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,int retry_counter)
- {
- static DEFINE_MUTEX(usb_address0_mutex);
- struct usb_device *hdev = hub->hdev;
- struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
- int i, j, retval;
- unsigned delay = HUB_SHORT_RESET_TIME;
- enum usb_device_speed oldspeed = udev->speed;
- char *speed, *type;
- int devnum = udev->devnum;
- if (!hdev->parent) {
- delay = HUB_ROOT_RESET_TIME;
- if (port1 == hdev->bus->otg_port)
- hdev->bus->b_hnp_enable = 0;
- }
- if (oldspeed == USB_SPEED_LOW)
- delay = HUB_LONG_RESET_TIME;
- mutex_lock(&usb_address0_mutex);
- if (!udev->config && oldspeed == USB_SPEED_SUPER) {
- usb_set_device_state(udev, USB_STATE_DEFAULT);
- } else {
- retval = hub_port_reset(hub, port1, udev, delay);
- if (retval < 0)
- goto fail;
- }
- retval = -ENODEV;
- if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
- dev_dbg(&udev->dev, "device reset changed speed!\n");
- goto fail;
- }
- oldspeed = udev->speed;
- switch (udev->speed) {
- case USB_SPEED_SUPER:
- case USB_SPEED_WIRELESS:
- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
- break;
- case USB_SPEED_HIGH:
- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
- break;
- case USB_SPEED_FULL:
- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
- break;
- case USB_SPEED_LOW:
- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
- break;
- default:
- goto fail;
- }
- type = "";
- switch (udev->speed) {
- case USB_SPEED_LOW: speed = "low"; break;
- case USB_SPEED_FULL: speed = "full"; break;
- case USB_SPEED_HIGH: speed = "high"; break;
- case USB_SPEED_SUPER: speed = "super"; break;
- case USB_SPEED_WIRELESS: speed = "variable"; type = "Wireless "; break;
- default: speed = "?"; break;
- }
- if (udev->speed != USB_SPEED_SUPER)
- dev_info(&udev->dev,"%s %s speed %sUSB device using %s and address %d\n",
- (udev->config) ? "reset" : "new", speed, type,udev->bus->controller->driver->name, devnum);
- if (hdev->tt) {
- udev->tt = hdev->tt;
- udev->ttport = hdev->ttport;
- } else if (udev->speed != USB_SPEED_HIGH&& hdev->speed == USB_SPEED_HIGH) {
- udev->tt = &hub->tt;
- udev->ttport = port1;
- }
- for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
- if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
- struct usb_device_descriptor *buf;
- int r = 0;
- #define GET_DESCRIPTOR_BUFSIZE 64
- buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
- if (!buf) {
- retval = -ENOMEM;
- continue;
- }
- for (j = 0; j < 3; ++j) {
- buf->bMaxPacketSize0 = 0;
- r = usb_control_msg(udev, usb_rcvaddr0pipe(),USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
- USB_DT_DEVICE << 8, 0,buf, GET_DESCRIPTOR_BUFSIZE,initial_descriptor_timeout);
- //获取描述符
- switch (buf->bMaxPacketSize0) {
- case 8: case 16: case 32: case 64: case 255:
- if (buf->bDescriptorType == USB_DT_DEVICE) {
- r = 0;
- break;
- }
- default:
- if (r == 0)
- r = -EPROTO;
- break;
- }
- if (r == 0)
- break;
- }
- udev->descriptor.bMaxPacketSize0 = buf->bMaxPacketSize0;
- kfree(buf);
- retval = hub_port_reset(hub, port1, udev, delay);
- if (retval < 0)
- goto fail;
- if (oldspeed != udev->speed) {
- dev_dbg(&udev->dev,"device reset changed speed!\n");
- retval = -ENODEV;
- goto fail;
- }
- if (r) {
- dev_err(&udev->dev,"device descriptor read/64, error %d\n",r);
- retval = -EMSGSIZE;
- continue;
- }
- #undef GET_DESCRIPTOR_BUFSIZE
- }
- if (udev->wusb == 0) {
- for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
- retval = hub_set_address(udev, devnum); //hub设置usb地址并告诉usb设备
- if (retval >= 0)
- break;
- msleep(200);
- }
- if (retval < 0) {
- dev_err(&udev->dev,"device not accepting address %d, error %d\n",devnum, retval);
- goto fail;
- }
- if (udev->speed == USB_SPEED_SUPER) {
- devnum = udev->devnum;
- dev_info(&udev->dev,"%s SuperSpeed USB device using %s and address %d\n",
- (udev->config) ? "reset" : "new",udev->bus->controller->driver->name, devnum);
- }
- msleep(10);
- if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
- break;
- }
- retval = usb_get_device_descriptor(udev, 8); //获取设备描述符先读8字节
- if (retval < 8) {
- dev_err(&udev->dev,"device descriptor read/8, error %d\n",retval);
- if (retval >= 0)
- retval = -EMSGSIZE;
- } else {
- retval = 0;
- break;
- }
- }
- if (retval)
- goto fail;
- if (udev->descriptor.bMaxPacketSize0 == 0xff ||
- udev->speed == USB_SPEED_SUPER)
- i = 512;
- else
- i = udev->descriptor.bMaxPacketSize0;
- if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
- if (udev->speed == USB_SPEED_LOW ||!(i == 8 || i == 16 || i == 32 || i == 64)) {
- dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
- retval = -EMSGSIZE;
- goto fail;
- }
- if (udev->speed == USB_SPEED_FULL)
- dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
- else
- dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
- udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
- usb_ep0_reinit(udev);
- }
- retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); //再次获取设备描述符
- if (retval < (signed)sizeof(udev->descriptor)) {
- dev_err(&udev->dev, "device descriptor read/all, error %d\n",
- retval);
- if (retval >= 0)
- retval = -ENOMSG;
- goto fail;
- }
- retval = 0;
- if (hcd->driver->update_device)
- hcd->driver->update_device(hcd, udev);
- fail:
- if (retval) {
- hub_port_disable(hub, port1, 0);
- update_address(udev, devnum); /* for disconnect processing */
- }
- mutex_unlock(&usb_address0_mutex);
- return retval;
- }
static int hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,int retry_counter)
{
static DEFINE_MUTEX(usb_address0_mutex);
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
int devnum = udev->devnum;
if (!hdev->parent) {
delay = HUB_ROOT_RESET_TIME;
if (port1 == hdev->bus->otg_port)
hdev->bus->b_hnp_enable = 0;
}
if (oldspeed == USB_SPEED_LOW)
delay = HUB_LONG_RESET_TIME;
mutex_lock(&usb_address0_mutex);
if (!udev->config && oldspeed == USB_SPEED_SUPER) {
usb_set_device_state(udev, USB_STATE_DEFAULT);
} else {
retval = hub_port_reset(hub, port1, udev, delay);
if (retval < 0)
goto fail;
}
retval = -ENODEV;
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
dev_dbg(&udev->dev, "device reset changed speed!\n");
goto fail;
}
oldspeed = udev->speed;
switch (udev->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_WIRELESS:
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
break;
case USB_SPEED_HIGH:
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
break;
case USB_SPEED_FULL:
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
break;
case USB_SPEED_LOW:
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
break;
default:
goto fail;
}
type = "";
switch (udev->speed) {
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
case USB_SPEED_SUPER: speed = "super"; break;
case USB_SPEED_WIRELESS: speed = "variable"; type = "Wireless "; break;
default: speed = "?"; break;
}
if (udev->speed != USB_SPEED_SUPER)
dev_info(&udev->dev,"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,udev->bus->controller->driver->name, devnum);
if (hdev->tt) {
udev->tt = hdev->tt;
udev->ttport = hdev->ttport;
} else if (udev->speed != USB_SPEED_HIGH&& hdev->speed == USB_SPEED_HIGH) {
udev->tt = &hub->tt;
udev->ttport = port1;
}
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
struct usb_device_descriptor *buf;
int r = 0;
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
if (!buf) {
retval = -ENOMEM;
continue;
}
for (j = 0; j < 3; ++j) {
buf->bMaxPacketSize0 = 0;
r = usb_control_msg(udev, usb_rcvaddr0pipe(),USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,buf, GET_DESCRIPTOR_BUFSIZE,initial_descriptor_timeout);
//获取描述符
switch (buf->bMaxPacketSize0) {
case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType == USB_DT_DEVICE) {
r = 0;
break;
}
default:
if (r == 0)
r = -EPROTO;
break;
}
if (r == 0)
break;
}
udev->descriptor.bMaxPacketSize0 = buf->bMaxPacketSize0;
kfree(buf);
retval = hub_port_reset(hub, port1, udev, delay);
if (retval < 0)
goto fail;
if (oldspeed != udev->speed) {
dev_dbg(&udev->dev,"device reset changed speed!\n");
retval = -ENODEV;
goto fail;
}
if (r) {
dev_err(&udev->dev,"device descriptor read/64, error %d\n",r);
retval = -EMSGSIZE;
continue;
}
#undef GET_DESCRIPTOR_BUFSIZE
}
if (udev->wusb == 0) {
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
retval = hub_set_address(udev, devnum); //hub设置usb地址并告诉usb设备
if (retval >= 0)
break;
msleep(200);
}
if (retval < 0) {
dev_err(&udev->dev,"device not accepting address %d, error %d\n",devnum, retval);
goto fail;
}
if (udev->speed == USB_SPEED_SUPER) {
devnum = udev->devnum;
dev_info(&udev->dev,"%s SuperSpeed USB device using %s and address %d\n",
(udev->config) ? "reset" : "new",udev->bus->controller->driver->name, devnum);
}
msleep(10);
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
break;
}
retval = usb_get_device_descriptor(udev, 8); //获取设备描述符先读8字节
if (retval < 8) {
dev_err(&udev->dev,"device descriptor read/8, error %d\n",retval);
if (retval >= 0)
retval = -EMSGSIZE;
} else {
retval = 0;
break;
}
}
if (retval)
goto fail;
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
udev->speed == USB_SPEED_SUPER)
i = 512;
else
i = udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed == USB_SPEED_LOW ||!(i == 8 || i == 16 || i == 32 || i == 64)) {
dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
retval = -EMSGSIZE;
goto fail;
}
if (udev->speed == USB_SPEED_FULL)
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
else
dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
usb_ep0_reinit(udev);
}
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); //再次获取设备描述符
if (retval < (signed)sizeof(udev->descriptor)) {
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
retval);
if (retval >= 0)
retval = -ENOMSG;
goto fail;
}
retval = 0;
if (hcd->driver->update_device)
hcd->driver->update_device(hcd, udev);
fail:
if (retval) {
hub_port_disable(hub, port1, 0);
update_address(udev, devnum); /* for disconnect processing */
}
mutex_unlock(&usb_address0_mutex);
return retval;
}
usb_new_device
- int usb_new_device(struct usb_device *udev)
- {
- int err;
- if (udev->parent) {
- device_init_wakeup(&udev->dev, 0);
- }
- pm_runtime_set_active(&udev->dev);
- pm_runtime_enable(&udev->dev);
- err = usb_enumerate_device(udev); //读取usb设备的描述符信息
- if (err < 0)
- goto fail;
- dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",udev->devnum, udev->bus->busnum,
- (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
- udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,(((udev->bus->busnum-1) * 128) + (udev->devnum-1))); //分配设备号
- announce_device(udev); //打印usb设备厂商啊啥的信息
- device_enable_async_suspend(&udev->dev);
- err = device_add(&udev->dev); //添加设备(至此usb枚举完了)-->usb设备与驱动的匹配
- if (err) {
- dev_err(&udev->dev, "can't device_add, error %d\n", err);
- goto fail;
- }
- (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
- return err;
- fail:
- usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- pm_runtime_disable(&udev->dev);
- pm_runtime_set_suspended(&udev->dev);
- return err;
- }
int usb_new_device(struct usb_device *udev)
{
int err;
if (udev->parent) {
device_init_wakeup(&udev->dev, 0);
}
pm_runtime_set_active(&udev->dev);
pm_runtime_enable(&udev->dev);
err = usb_enumerate_device(udev); //读取usb设备的描述符信息
if (err < 0)
goto fail;
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",udev->devnum, udev->bus->busnum,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,(((udev->bus->busnum-1) * 128) + (udev->devnum-1))); //分配设备号
announce_device(udev); //打印usb设备厂商啊啥的信息
device_enable_async_suspend(&udev->dev);
err = device_add(&udev->dev); //添加设备(至此usb枚举完了)-->usb设备与驱动的匹配
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
pm_runtime_disable(&udev->dev);
pm_runtime_set_suspended(&udev->dev);
return err;
}
usb_enumerate_device
- static int usb_enumerate_device(struct usb_device *udev)
- {
- int err;
- if (udev->config == NULL) {
- err = usb_get_configuration(udev); //usb获取配置描述符
- if (err < 0) {
- dev_err(&udev->dev, "can't read configurations, error %d\n",err);
- goto fail;
- }
- }
- if (udev->wusb == 1 && udev->authorized == 0) {
- udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- }
- else {
- udev->product = usb_cache_string(udev, udev->descriptor.iProduct); //设置产品id
- udev->manufacturer = usb_cache_string(udev,udev->descriptor.iManufacturer); //设置厂商id
- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); //设置产品序列号
- }
- err = usb_enumerate_device_otg(udev);
- fail:
- return err;
- }
static int usb_enumerate_device(struct usb_device *udev)
{
int err;
if (udev->config == NULL) {
err = usb_get_configuration(udev); //usb获取配置描述符
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",err);
goto fail;
}
}
if (udev->wusb == 1 && udev->authorized == 0) {
udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
}
else {
udev->product = usb_cache_string(udev, udev->descriptor.iProduct); //设置产品id
udev->manufacturer = usb_cache_string(udev,udev->descriptor.iManufacturer); //设置厂商id
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); //设置产品序列号
}
err = usb_enumerate_device_otg(udev);
fail:
return err;
}
device_add函数会出发总线的通知链发送通知,最终会调用总线的match方法
usb设备和驱动一旦match,则会调用驱动的drvwrap.driver.probe方法
若是设备则调用usb_probe_device
若是接口则调用usb_probe_interface
这里我们调用的是usb接口的,也就是usb_probe_interface
- static int usb_probe_interface(struct device *dev)
- {
- struct usb_driver *driver = to_usb_driver(dev->driver);
- struct usb_interface *intf = to_usb_interface(dev);
- struct usb_device *udev = interface_to_usbdev(intf);
- const struct usb_device_id *id;
- int error = -ENODEV;
- dev_dbg(dev, "%s\n", __func__);
- intf->needs_binding = 0;
- if (usb_device_is_owned(udev))
- return error;
- if (udev->authorized == 0) {
- dev_err(&intf->dev, "Device is not authorized for usage\n");
- return error;
- }
- id = usb_match_id(intf, driver->id_table); //静态id匹配
- if (!id)
- id = usb_match_dynamic_id(intf, driver); //动态id匹配
- if (!id)
- return error;
- dev_dbg(dev, "%s - got id\n", __func__);
- error = usb_autoresume_device(udev);
- if (error)
- return error;
- intf->condition = USB_INTERFACE_BINDING;
- pm_runtime_set_active(dev);
- pm_suspend_ignore_children(dev, false);
- if (driver->supports_autosuspend)
- pm_runtime_enable(dev);
- if (intf->needs_altsetting0) {
- error = usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
- if (error < 0)
- goto err;
- intf->needs_altsetting0 = 0;
- }
- error = driver->probe(intf, id); //最终调用usb驱动的probe方法
- if (error)
- goto err;
- intf->condition = USB_INTERFACE_BOUND;
- usb_autosuspend_device(udev);
- return error;
- err:
- intf->needs_remote_wakeup = 0;
- intf->condition = USB_INTERFACE_UNBOUND;
- usb_cancel_queued_reset(intf);
- if (driver->supports_autosuspend)
- pm_runtime_disable(dev);
- pm_runtime_set_suspended(dev);
- usb_autosuspend_device(udev);
- return error;
- }
static int usb_probe_interface(struct device *dev)
{
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
dev_dbg(dev, "%s\n", __func__);
intf->needs_binding = 0;
if (usb_device_is_owned(udev))
return error;
if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
return error;
}
id = usb_match_id(intf, driver->id_table); //静态id匹配
if (!id)
id = usb_match_dynamic_id(intf, driver); //动态id匹配
if (!id)
return error;
dev_dbg(dev, "%s - got id\n", __func__);
error = usb_autoresume_device(udev);
if (error)
return error;
intf->condition = USB_INTERFACE_BINDING;
pm_runtime_set_active(dev);
pm_suspend_ignore_children(dev, false);
if (driver->supports_autosuspend)
pm_runtime_enable(dev);
if (intf->needs_altsetting0) {
error = usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
if (error < 0)
goto err;
intf->needs_altsetting0 = 0;
}
error = driver->probe(intf, id); //最终调用usb驱动的probe方法
if (error)
goto err;
intf->condition = USB_INTERFACE_BOUND;
usb_autosuspend_device(udev);
return error;
err:
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
if (driver->supports_autosuspend)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
usb_autosuspend_device(udev);
return error;
}
一般在usb设备驱动的probe方法中会调用usb_alloc_urb分配urb
用
usb_fill_int_urb
usb_fill_bulk_urb
usb_fill_control_urb
填充urb
然后用usb_submit_urb提交urb
- int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
- {
- int xfertype, max;
- struct usb_device *dev;
- struct usb_host_endpoint *ep;
- int is_out;
- if (!urb || urb->hcpriv || !urb->complete)
- return -EINVAL;
- dev = urb->dev;
- if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
- return -ENODEV;
- ep = usb_pipe_endpoint(dev, urb->pipe); //获取端点
- if (!ep)
- return -ENOENT;
- urb->ep = ep; //设置端点
- urb->status = -EINPROGRESS;
- urb->actual_length = 0;
- xfertype = usb_endpoint_type(&ep->desc);
- if (xfertype == USB_ENDPOINT_XFER_CONTROL) { //控制传输
- struct usb_ctrlrequest *setup =(struct usb_ctrlrequest *) urb->setup_packet; //设置setup包
- if (!setup)
- return -ENOEXEC;
- is_out = !(setup->bRequestType & USB_DIR_IN) ||!setup->wLength;
- } else {
- is_out = usb_endpoint_dir_out(&ep->desc);
- }
- urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
- URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |URB_DMA_SG_COMBINED);
- urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN); //输入还是输出端点
- if (xfertype != USB_ENDPOINT_XFER_CONTROL &&dev->state < USB_STATE_CONFIGURED)
- return -ENODEV;
- max = le16_to_cpu(ep->desc.wMaxPacketSize);
- if (max <= 0) {
- dev_dbg(&dev->dev,"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_endpoint_num(&ep->desc), is_out ? "out" : "in",__func__, max);
- return -EMSGSIZE;
- }
- if (xfertype == USB_ENDPOINT_XFER_ISOC) { //同步传输
- int n, len;
- if (dev->speed == USB_SPEED_HIGH) {
- int mult = 1 + ((max >> 11) & 0x03);
- max &= 0x07ff;
- max *= mult;
- }
- if (urb->number_of_packets <= 0)
- return -EINVAL;
- for (n = 0; n < urb->number_of_packets; n++) {
- len = urb->iso_frame_desc[n].length;
- if (len < 0 || len > max)
- return -EMSGSIZE;
- urb->iso_frame_desc[n].status = -EXDEV;
- urb->iso_frame_desc[n].actual_length = 0;
- }
- }
- if (urb->transfer_buffer_length > INT_MAX)
- return -EMSGSIZE;
- switch (xfertype) { //传输类型
- case USB_ENDPOINT_XFER_ISOC: //同步传输
- case USB_ENDPOINT_XFER_INT: //中断传输
- switch (dev->speed) {
- case USB_SPEED_WIRELESS: //无线?
- if (urb->interval < 6)
- return -EINVAL;
- break;
- default:
- if (urb->interval <= 0)
- return -EINVAL;
- break;
- }
- switch (dev->speed) {
- case USB_SPEED_SUPER: //超速设备
- if (urb->interval > (1 << 15))
- return -EINVAL;
- max = 1 << 15;
- break;
- case USB_SPEED_WIRELESS: //无线?
- if (urb->interval > 16)
- return -EINVAL;
- break;
- case USB_SPEED_HIGH: //高速设备
- if (urb->interval > (1024 * 8))
- urb->interval = 1024 * 8;
- max = 1024 * 8;
- break;
- case USB_SPEED_FULL: //全速
- case USB_SPEED_LOW: //低速
- if (xfertype == USB_ENDPOINT_XFER_INT) {
- if (urb->interval > 255)
- return -EINVAL;
- max = 128;
- } else {
- if (urb->interval > 1024)
- urb->interval = 1024;
- max = 1024;
- }
- break;
- default:
- return -EINVAL;
- }
- if (dev->speed != USB_SPEED_WIRELESS) {
- urb->interval = min(max, 1 << ilog2(urb->interval));
- }
- }
- return usb_hcd_submit_urb(urb, mem_flags);
- }
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int xfertype, max;
struct usb_device *dev;
struct usb_host_endpoint *ep;
int is_out;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
dev = urb->dev;
if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
return -ENODEV;
ep = usb_pipe_endpoint(dev, urb->pipe); //获取端点
if (!ep)
return -ENOENT;
urb->ep = ep; //设置端点
urb->status = -EINPROGRESS;
urb->actual_length = 0;
xfertype = usb_endpoint_type(&ep->desc);
if (xfertype == USB_ENDPOINT_XFER_CONTROL) { //控制传输
struct usb_ctrlrequest *setup =(struct usb_ctrlrequest *) urb->setup_packet; //设置setup包
if (!setup)
return -ENOEXEC;
is_out = !(setup->bRequestType & USB_DIR_IN) ||!setup->wLength;
} else {
is_out = usb_endpoint_dir_out(&ep->desc);
}
urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE |URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL |
URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |URB_DMA_SG_COMBINED);
urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN); //输入还是输出端点
if (xfertype != USB_ENDPOINT_XFER_CONTROL &&dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
max = le16_to_cpu(ep->desc.wMaxPacketSize);
if (max <= 0) {
dev_dbg(&dev->dev,"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_endpoint_num(&ep->desc), is_out ? "out" : "in",__func__, max);
return -EMSGSIZE;
}
if (xfertype == USB_ENDPOINT_XFER_ISOC) { //同步传输
int n, len;
if (dev->speed == USB_SPEED_HIGH) {
int mult = 1 + ((max >> 11) & 0x03);
max &= 0x07ff;
max *= mult;
}
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
urb->iso_frame_desc[n].status = -EXDEV;
urb->iso_frame_desc[n].actual_length = 0;
}
}
if (urb->transfer_buffer_length > INT_MAX)
return -EMSGSIZE;
switch (xfertype) { //传输类型
case USB_ENDPOINT_XFER_ISOC: //同步传输
case USB_ENDPOINT_XFER_INT: //中断传输
switch (dev->speed) {
case USB_SPEED_WIRELESS: //无线?
if (urb->interval < 6)
return -EINVAL;
break;
default:
if (urb->interval <= 0)
return -EINVAL;
break;
}
switch (dev->speed) {
case USB_SPEED_SUPER: //超速设备
if (urb->interval > (1 << 15))
return -EINVAL;
max = 1 << 15;
break;
case USB_SPEED_WIRELESS: //无线?
if (urb->interval > 16)
return -EINVAL;
break;
case USB_SPEED_HIGH: //高速设备
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
max = 1024 * 8;
break;
case USB_SPEED_FULL: //全速
case USB_SPEED_LOW: //低速
if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
max = 1024;
}
break;
default:
return -EINVAL;
}
if (dev->speed != USB_SPEED_WIRELESS) {
urb->interval = min(max, 1 << ilog2(urb->interval));
}
}
return usb_hcd_submit_urb(urb, mem_flags);
}
调用主控器usb_hcd_submit_urb
- int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
- {
- int status;
- struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
- usb_get_urb(urb);
- atomic_inc(&urb->use_count);
- atomic_inc(&urb->dev->urbnum);
- usbmon_urb_submit(&hcd->self, urb);
- if (is_root_hub(urb->dev)) { //这次不是根hub
- status = rh_urb_enqueue(hcd, urb);
- } else {
- status = map_urb_for_dma(hcd, urb, mem_flags);
- if (likely(status == 0)) {
- status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); //调用主控器的urb_enqueue方法
- if (unlikely(status))
- unmap_urb_for_dma(hcd, urb);
- }
- }
- if (unlikely(status)) {
- usbmon_urb_submit_error(&hcd->self, urb, status);
- urb->hcpriv = NULL;
- INIT_LIST_HEAD(&urb->urb_list);
- atomic_dec(&urb->use_count);
- atomic_dec(&urb->dev->urbnum);
- if (atomic_read(&urb->reject))
- wake_up(&usb_kill_urb_queue);
- usb_put_urb(urb);
- }
- return status;
- }