当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口状态变化 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); }
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; }
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; }
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; }
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; }
一般在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); }
调用主控器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; }
<---usb设备注册