USB驅動框架分析3

本文主要分析hub驅動的probe過程,如何判斷hub端口的變化。

直接看hub_probe函數

  1. static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)  
  2. {  
  3.     struct usb_host_interface *desc;  
  4.     struct usb_endpoint_descriptor *endpoint;  
  5.     struct usb_device *hdev;  
  6.     struct usb_hub *hub;  
  7.   
  8.     desc = intf->cur_altsetting;  
  9.     hdev = interface_to_usbdev(intf);  
  10.   
  11.     /* Hubs have proper suspend/resume support.  USB 3.0 device suspend is 
  12.      * different from USB 2.0/1.1 device suspend, and unfortunately we 
  13.      * don't support it yet.  So leave autosuspend disabled for USB 3.0 
  14.      * external hubs for now.  Enable autosuspend for USB 3.0 roothubs, 
  15.      * since that isn't a "real" hub. 
  16.      */  
  17.     if (!hub_is_superspeed(hdev) || !hdev->parent)  
  18.         usb_disable_autosuspend(hdev);  
  19.   
  20.     if (hdev->level == MAX_TOPO_LEVEL) {  
  21.         dev_err(&intf->dev,  
  22.             "Unsupported bus topology: hub nested too deep\n");  
  23.         return -E2BIG;  
  24.     }  
  25.   
  26. #ifdef  CONFIG_USB_OTG_BLACKLIST_HUB  
  27.     if (hdev->parent) {  
  28.         dev_warn(&intf->dev, "ignoring external hub\n");  
  29.         return -ENODEV;  
  30.     }  
  31. #endif  
  32.   
  33.     /* Some hubs have a subclass of 1, which AFAICT according to the */  
  34.     /*  specs is not defined, but it works */  
  35.     if ((desc->desc.bInterfaceSubClass != 0) &&  
  36.         (desc->desc.bInterfaceSubClass != 1)) {  
  37. descriptor_error:  
  38.         dev_err (&intf->dev, "bad descriptor, ignoring hub\n");  
  39.         return -EIO;  
  40.     }  
  41.   
  42.     /* Multiple endpoints? What kind of mutant ninja-hub is this? */  
  43.     if (desc->desc.bNumEndpoints != 1)  
  44.         goto descriptor_error;  
  45.   
  46.     endpoint = &desc->endpoint[0].desc;  
  47.   
  48.     /* If it's not an interrupt in endpoint, we'd better punt! */  
  49.     if (!usb_endpoint_is_int_in(endpoint))  
  50.         goto descriptor_error;  
  51.   
  52.     /* We found a hub */  
  53.     dev_info (&intf->dev, "USB hub found\n");  
  54.   
  55.     hub = kzalloc(sizeof(*hub), GFP_KERNEL);    //分配一個usb_hub  
  56.     if (!hub) {  
  57.         dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");  
  58.         return -ENOMEM;  
  59.     }  
  60.   
  61.     kref_init(&hub->kref);  
  62.     INIT_LIST_HEAD(&hub->event_list);  
  63.     hub->intfdev = &intf->dev;  
  64.     hub->hdev = hdev;  
  65.     INIT_DELAYED_WORK(&hub->leds, led_work);  
  66.     INIT_DELAYED_WORK(&hub->init_work, NULL);  
  67.     usb_get_intf(intf);  
  68.   
  69.     usb_set_intfdata (intf, hub);  
  70.     intf->needs_remote_wakeup = 1;  
  71.   
  72.     if (hdev->speed == USB_SPEED_HIGH)  
  73.         highspeed_hubs++;  
  74.   
  75.     if (hub_configure(hub, endpoint) >= 0)   //對hub進行配置  
  76.         return 0;  
  77.   
  78.     hub_disconnect (intf);  
  79.     return -ENODEV;  
  80. }  
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_host_interface *desc;
	struct usb_endpoint_descriptor *endpoint;
	struct usb_device *hdev;
	struct usb_hub *hub;

	desc = intf->cur_altsetting;
	hdev = interface_to_usbdev(intf);

	/* Hubs have proper suspend/resume support.  USB 3.0 device suspend is
	 * different from USB 2.0/1.1 device suspend, and unfortunately we
	 * don't support it yet.  So leave autosuspend disabled for USB 3.0
	 * external hubs for now.  Enable autosuspend for USB 3.0 roothubs,
	 * since that isn't a "real" hub.
	 */
	if (!hub_is_superspeed(hdev) || !hdev->parent)
		usb_disable_autosuspend(hdev);

	if (hdev->level == MAX_TOPO_LEVEL) {
		dev_err(&intf->dev,
			"Unsupported bus topology: hub nested too deep\n");
		return -E2BIG;
	}

#ifdef	CONFIG_USB_OTG_BLACKLIST_HUB
	if (hdev->parent) {
		dev_warn(&intf->dev, "ignoring external hub\n");
		return -ENODEV;
	}
#endif

	/* Some hubs have a subclass of 1, which AFAICT according to the */
	/*  specs is not defined, but it works */
	if ((desc->desc.bInterfaceSubClass != 0) &&
	    (desc->desc.bInterfaceSubClass != 1)) {
descriptor_error:
		dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
		return -EIO;
	}

	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
	if (desc->desc.bNumEndpoints != 1)
		goto descriptor_error;

	endpoint = &desc->endpoint[0].desc;

	/* If it's not an interrupt in endpoint, we'd better punt! */
	if (!usb_endpoint_is_int_in(endpoint))
		goto descriptor_error;

	/* We found a hub */
	dev_info (&intf->dev, "USB hub found\n");

	hub = kzalloc(sizeof(*hub), GFP_KERNEL);	//分配一個usb_hub
	if (!hub) {
		dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
		return -ENOMEM;
	}

	kref_init(&hub->kref);
	INIT_LIST_HEAD(&hub->event_list);
	hub->intfdev = &intf->dev;
	hub->hdev = hdev;
	INIT_DELAYED_WORK(&hub->leds, led_work);
	INIT_DELAYED_WORK(&hub->init_work, NULL);
	usb_get_intf(intf);

	usb_set_intfdata (intf, hub);
	intf->needs_remote_wakeup = 1;

	if (hdev->speed == USB_SPEED_HIGH)
		highspeed_hubs++;

	if (hub_configure(hub, endpoint) >= 0)	//對hub進行配置
		return 0;

	hub_disconnect (intf);
	return -ENODEV;
}
hub _configure這個函數很長,主要乾了兩件事:

(1)usb_alloc_urb分配一個urb,調用usb_fill_int_urb 填充該urb結構,並且回調函數爲hub_irq,hub_irq函數比較重要

(2)hub_activate(hub, HUB_INIT)激活hub


hub_activate函數也很長,主要乾了兩件事:

(1)usb_submit_urb(hub->urb, GFP_NOIO),向主機控制器層提交urb。

(2)kick_khubd(hub),喚醒處於睡眠中的khubd內核線程。

  1. static void hub_irq(struct urb *urb)  
  2. {  
  3.     struct usb_hub *hub = urb->context;  
  4.     int status = urb->status;  
  5.     unsigned i;  
  6.     unsigned long bits;  
  7.   
  8.     switch (status) {  
  9.     case -ENOENT:       /* synchronous unlink */  
  10.     case -ECONNRESET:   /* async unlink */  
  11.     case -ESHUTDOWN:    /* hardware going away */  
  12.         return;  
  13.   
  14.     default:        /* presumably an error */  
  15.         /* Cause a hub reset after 10 consecutive errors */  
  16.         dev_dbg (hub->intfdev, "transfer --> %d\n", status);  
  17.         if ((++hub->nerrors < 10) || hub->error)  
  18.             goto resubmit;  
  19.         hub->error = status;  
  20.         /* FALL THROUGH */  
  21.   
  22.     /* let khubd handle things */  
  23.     case 0:         /* we got data:  port status changed */  
  24.         bits = 0;  
  25.         for (i = 0; i < urb->actual_length; ++i)  
  26.             bits |= ((unsigned long) ((*hub->buffer)[i]))  
  27.                     << (i*8);  
  28.         hub->event_bits[0] = bits;  
  29.         break;  
  30.     }  
  31.   
  32.     hub->nerrors = 0;  
  33.   
  34.     /* Something happened, let khubd figure it out */  
  35.     kick_khubd(hub);    //hub_irq也調用了kick_khubd函數  
  36.   
  37. resubmit:  
  38.     if (hub->quiescing)  
  39.         return;  
  40.   
  41.     if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0  
  42.             && status != -ENODEV && status != -EPERM)  
  43.         dev_err (hub->intfdev, "resubmit --> %d\n", status);  
  44. }  
  45. static void kick_khubd(struct usb_hub *hub)  
  46. {  
  47.     unsigned long   flags;  
  48.   
  49.     spin_lock_irqsave(&hub_event_lock, flags);  
  50.     if (!hub->disconnected && list_empty(&hub->event_list)) {  
  51.         list_add_tail(&hub->event_list, &hub_event_list);    //添加到hub_event_list  
  52.   
  53.         /* Suppress autosuspend until khubd runs */  
  54.         usb_autopm_get_interface_no_resume(  
  55.                 to_usb_interface(hub->intfdev));  
  56.         wake_up(&khubd_wait);   //喚醒khubd  
  57.     }  
  58.     spin_unlock_irqrestore(&hub_event_lock, flags);  
  59. }  
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:		/* synchronous unlink */
	case -ECONNRESET:	/* async unlink */
	case -ESHUTDOWN:	/* hardware going away */
		return;

	default:		/* presumably an error */
		/* Cause a hub reset after 10 consecutive errors */
		dev_dbg (hub->intfdev, "transfer --> %d\n", status);
		if ((++hub->nerrors < 10) || hub->error)
			goto resubmit;
		hub->error = status;
		/* FALL THROUGH */

	/* let khubd handle things */
	case 0:			/* we got data:  port status changed */
		bits = 0;
		for (i = 0; i < urb->actual_length; ++i)
			bits |= ((unsigned long) ((*hub->buffer)[i]))
					<< (i*8);
		hub->event_bits[0] = bits;
		break;
	}

	hub->nerrors = 0;

	/* Something happened, let khubd figure it out */
	kick_khubd(hub);	//hub_irq也調用了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 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);	//添加到hub_event_list

		/* Suppress autosuspend until khubd runs */
		usb_autopm_get_interface_no_resume(
				to_usb_interface(hub->intfdev));
		wake_up(&khubd_wait);	//喚醒khubd
	}
	spin_unlock_irqrestore(&hub_event_lock, flags);
}

看khubd線程幹了什麼事情,應該是等某個事情處於睡眠狀態,等待被喚醒。

  1. static int hub_thread(void *__unused)  
  2. {  
  3.     /* khubd needs to be freezable to avoid intefering with USB-PERSIST 
  4.      * port handover.  Otherwise it might see that a full-speed device 
  5.      * was gone before the EHCI controller had handed its port over to 
  6.      * the companion full-speed controller. 
  7.      */  
  8.     set_freezable();  
  9.   
  10.     do {  
  11.         hub_events();  
  12.         wait_event_freezable(khubd_wait,  
  13.                 !list_empty(&hub_event_list) ||  
  14.                 kthread_should_stop());  
  15.     } while (!kthread_should_stop() || !list_empty(&hub_event_list));  
  16.   
  17.     pr_debug("%s: khubd exiting\n", usbcore_name);  
  18.     return 0;  
  19. }  
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函數。

  1. static void hub_events(void)  
  2. {  
  3.     struct list_head *tmp;  
  4.     struct usb_device *hdev;  
  5.     struct usb_interface *intf;  
  6.     struct usb_hub *hub;  
  7.     struct device *hub_dev;  
  8.     u16 hubstatus;  
  9.     u16 hubchange;  
  10.     u16 portstatus;  
  11.     u16 portchange;  
  12.     int i, ret;  
  13.     int connect_change;  
  14.   
  15.     /* 
  16.      *  We restart the list every time to avoid a deadlock with 
  17.      * deleting hubs downstream from this one. This should be 
  18.      * safe since we delete the hub from the event list. 
  19.      * Not the most efficient, but avoids deadlocks. 
  20.      */  
  21.     while (1) {  
  22.   
  23.         /* Grab the first entry at the beginning of the list */  
  24.         spin_lock_irq(&hub_event_lock);  
  25.         if (list_empty(&hub_event_list)) {  //如果hub_event_list爲空跳出循環  
  26.             spin_unlock_irq(&hub_event_lock);  
  27.             break;  
  28.         }  
  29.   
  30.         tmp = hub_event_list.next;  //取出一項  
  31.         list_del_init(tmp);  
  32.   
  33.         hub = list_entry(tmp, struct usb_hub, event_list);  //得到usb_hub結構  
  34.         kref_get(&hub->kref);  
  35.         spin_unlock_irq(&hub_event_lock);  
  36.   
  37.         hdev = hub->hdev;  
  38.         hub_dev = hub->intfdev;  
  39.         intf = to_usb_interface(hub_dev);  
  40.         dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",  
  41.                 hdev->state, hub->descriptor  
  42.                     ? hub->descriptor->bNbrPorts  
  43.                     : 0,  
  44.                 /* NOTE: expects max 15 ports... */  
  45.                 (u16) hub->change_bits[0],  
  46.                 (u16) hub->event_bits[0]);  
  47.   
  48.         /* Lock the device, then check to see if we were 
  49.          * disconnected while waiting for the lock to succeed. */  
  50.         usb_lock_device(hdev);  
  51.         if (unlikely(hub->disconnected)) //是否在鏈接  
  52.             goto loop_disconnected;  
  53.   
  54.         /* If the hub has died, clean up after it */    //如果處於NOTATTACHED狀態  
  55.         if (hdev->state == USB_STATE_NOTATTACHED) {  
  56.             hub->error = -ENODEV;  
  57.             hub_quiesce(hub, HUB_DISCONNECT);  
  58.             goto loop;  
  59.         }  
  60.   
  61.         /* Autoresume */  
  62.         ret = usb_autopm_get_interface(intf);  
  63.         if (ret) {  
  64.             dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);  
  65.             goto loop;  
  66.         }  
  67.   
  68.         /* If this is an inactive hub, do nothing */  
  69.         if (hub->quiescing)  
  70.             goto loop_autopm;  
  71.         //如果有錯誤  
  72.         if (hub->error) {  
  73.             dev_dbg (hub_dev, "resetting for error %d\n",  
  74.                 hub->error);  
  75.   
  76.             ret = usb_reset_device(hdev);   //如果有錯誤重啓hub  
  77.             if (ret) {  
  78.                 dev_dbg (hub_dev,  
  79.                     "error resetting hub: %d\n", ret);  
  80.                 goto loop_autopm;  
  81.             }  
  82.   
  83.             hub->nerrors = 0;  
  84.             hub->error = 0;  
  85.         }  
  86.   
  87.         /* deal with port status changes */  
  88.         for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {  
  89.             if (test_bit(i, hub->busy_bits)) //如果port處於resume或reset狀態,跳過  
  90.                 continue;  
  91.             connect_change = test_bit(i, hub->change_bits);  
  92.             //如果event_bits爲0,change_bits也爲0,也跳過  
  93.             if (!test_and_clear_bit(i, hub->event_bits) &&  
  94.                     !connect_change)  
  95.                 continue;  
  96.             //獲取portstatus,portchange  
  97.             ret = hub_port_status(hub, i,  
  98.                     &portstatus, &portchange);  
  99.             if (ret < 0)  
  100.                 continue;  
  101.             //連接狀態發生變化  
  102.             if (portchange & USB_PORT_STAT_C_CONNECTION) {  
  103.                 clear_port_feature(hdev, i,  
  104.                     USB_PORT_FEAT_C_CONNECTION);  
  105.                 connect_change = 1;  
  106.             }  
  107.             //使能狀態發生變化  
  108.             if (portchange & USB_PORT_STAT_C_ENABLE) {  
  109.                 if (!connect_change)  
  110.                     dev_dbg (hub_dev,  
  111.                         "port %d enable change, "  
  112.                         "status %08x\n",  
  113.                         i, portstatus);  
  114.                 clear_port_feature(hdev, i,  
  115.                     USB_PORT_FEAT_C_ENABLE);  
  116.   
  117.                 /* 
  118.                  * EM interference sometimes causes badly 
  119.                  * shielded USB devices to be shutdown by 
  120.                  * the hub, this hack enables them again. 
  121.                  * Works at least with mouse driver.  
  122.                  */  
  123.                 //EMI引起的狀態變化  
  124.                 if (!(portstatus & USB_PORT_STAT_ENABLE)  
  125.                     && !connect_change  
  126.                     && hdev->children[i-1]) {  
  127.                     dev_err (hub_dev,  
  128.                         "port %i "  
  129.                         "disabled by hub (EMI?), "  
  130.                         "re-enabling...\n",  
  131.                         i);  
  132.                     connect_change = 1;  
  133.                 }  
  134.             }  
  135.             //suspend狀態發生變化  
  136.             if (portchange & USB_PORT_STAT_C_SUSPEND) {  
  137.                 struct usb_device *udev;  
  138.   
  139.                 clear_port_feature(hdev, i,  
  140.                     USB_PORT_FEAT_C_SUSPEND);  
  141.                 udev = hdev->children[i-1];  
  142.                 if (udev) {  
  143.                     /* TRSMRCY = 10 msec */  
  144.                     msleep(10);  
  145.   
  146.                     usb_lock_device(udev);  
  147.                     ret = usb_remote_wakeup(hdev->  
  148.                             children[i-1]);  
  149.                     usb_unlock_device(udev);  
  150.                     if (ret < 0)  
  151.                         connect_change = 1;  
  152.                 } else {  
  153.                     ret = -ENODEV;  
  154.                     hub_port_disable(hub, i, 1);  
  155.                 }  
  156.                 dev_dbg (hub_dev,  
  157.                     "resume on port %d, status %d\n",  
  158.                     i, ret);  
  159.             }  
  160.             //port的過流發生變化  
  161.             if (portchange & USB_PORT_STAT_C_OVERCURRENT) {  
  162.                 u16 status = 0;  
  163.                 u16 unused;  
  164.   
  165.                 dev_dbg(hub_dev, "over-current change on port "  
  166.                     "%d\n", i);  
  167.                 clear_port_feature(hdev, i,  
  168.                     USB_PORT_FEAT_C_OVER_CURRENT);  
  169.                 msleep(100);    /* Cool down */  
  170.                 hub_power_on(hub, true);  
  171.                 hub_port_status(hub, i, &status, &unused);  
  172.                 if (status & USB_PORT_STAT_OVERCURRENT)  
  173.                     dev_err(hub_dev, "over-current "  
  174.                         "condition on port %d\n", i);  
  175.             }  
  176.             //port reset完成  
  177.             if (portchange & USB_PORT_STAT_C_RESET) {  
  178.                 dev_dbg (hub_dev,  
  179.                     "reset change on port %d\n",  
  180.                     i);  
  181.                 clear_port_feature(hdev, i,  
  182.                     USB_PORT_FEAT_C_RESET);  
  183.             }  
  184.             if ((portchange & USB_PORT_STAT_C_BH_RESET) &&  
  185.                     hub_is_superspeed(hub->hdev)) {  
  186.                 dev_dbg(hub_dev,  
  187.                     "warm reset change on port %d\n",  
  188.                     i);  
  189.                 clear_port_feature(hdev, i,  
  190.                     USB_PORT_FEAT_C_BH_PORT_RESET);  
  191.             }  
  192.             if (portchange & USB_PORT_STAT_C_LINK_STATE) {  
  193.                 clear_port_feature(hub->hdev, i,  
  194.                         USB_PORT_FEAT_C_PORT_LINK_STATE);  
  195.             }  
  196.             if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {  
  197.                 dev_warn(hub_dev,  
  198.                     "config error on port %d\n",  
  199.                     i);  
  200.                 clear_port_feature(hub->hdev, i,  
  201.                         USB_PORT_FEAT_C_PORT_CONFIG_ERROR);  
  202.             }  
  203.   
  204.             /* Warm reset a USB3 protocol port if it's in 
  205.              * SS.Inactive state. 
  206.              */  
  207.             if (hub_is_superspeed(hub->hdev) &&  
  208.                 (portstatus & USB_PORT_STAT_LINK_STATE)  
  209.                     == USB_SS_PORT_LS_SS_INACTIVE) {  
  210.                 dev_dbg(hub_dev, "warm reset port %d\n", i);  
  211.                 hub_port_warm_reset(hub, i);  
  212.             }  
  213.             //如果發生變化,調用hub_port_connect_change函數  
  214.             if (connect_change)  
  215.                 hub_port_connect_change(hub, i,  
  216.                         portstatus, portchange);  
  217.         } /* end for i */  
  218.   
  219.         /* deal with hub status changes */  
  220.         if (test_and_clear_bit(0, hub->event_bits) == 0)  
  221.             ;   /* do nothing */  
  222.         else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)  
  223.             dev_err (hub_dev, "get_hub_status failed\n");  
  224.         else {  
  225.             if (hubchange & HUB_CHANGE_LOCAL_POWER) {  
  226.                 dev_dbg (hub_dev, "power change\n");  
  227.                 clear_hub_feature(hdev, C_HUB_LOCAL_POWER);  
  228.                 if (hubstatus & HUB_STATUS_LOCAL_POWER)  
  229.                     /* FIXME: Is this always true? */  
  230.                     hub->limited_power = 1;  
  231.                 else  
  232.                     hub->limited_power = 0;  
  233.             }  
  234.             if (hubchange & HUB_CHANGE_OVERCURRENT) {  
  235.                 u16 status = 0;  
  236.                 u16 unused;  
  237.   
  238.                 dev_dbg(hub_dev, "over-current change\n");  
  239.                 clear_hub_feature(hdev, C_HUB_OVER_CURRENT);  
  240.                 msleep(500);    /* Cool down */  
  241.                             hub_power_on(hub, true);  
  242.                 hub_hub_status(hub, &status, &unused);  
  243.                 if (status & HUB_STATUS_OVERCURRENT)  
  244.                     dev_err(hub_dev, "over-current "  
  245.                         "condition\n");  
  246.             }  
  247.         }  
  248.   
  249.  loop_autopm:  
  250.         /* Balance the usb_autopm_get_interface() above */  
  251.         usb_autopm_put_interface_no_suspend(intf);  
  252.  loop:  
  253.         /* Balance the usb_autopm_get_interface_no_resume() in 
  254.          * kick_khubd() and allow autosuspend. 
  255.          */  
  256.         usb_autopm_put_interface(intf);  
  257.  loop_disconnected:  
  258.         usb_unlock_device(hdev);  
  259.         kref_put(&hub->kref, hub_release);  
  260.   
  261.         } /* end while (1) */  
  262. }  
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;

	/*
	 *  We restart the list every time to avoid a deadlock with
	 * deleting hubs downstream from this one. This should be
	 * safe since we delete the hub from the event list.
	 * Not the most efficient, but avoids deadlocks.
	 */
	while (1) {

		/* Grab the first entry at the beginning of the list */
		spin_lock_irq(&hub_event_lock);
		if (list_empty(&hub_event_list)) {	//如果hub_event_list爲空跳出循環
			spin_unlock_irq(&hub_event_lock);
			break;
		}

		tmp = hub_event_list.next;	//取出一項
		list_del_init(tmp);

		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_dev = hub->intfdev;
		intf = to_usb_interface(hub_dev);
		dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
				hdev->state, hub->descriptor
					? hub->descriptor->bNbrPorts
					: 0,
				/* NOTE: expects max 15 ports... */
				(u16) hub->change_bits[0],
				(u16) hub->event_bits[0]);

		/* Lock the device, then check to see if we were
		 * disconnected while waiting for the lock to succeed. */
		usb_lock_device(hdev);
		if (unlikely(hub->disconnected))	//是否在鏈接
			goto loop_disconnected;

		/* If the hub has died, clean up after it */	//如果處於NOTATTACHED狀態
		if (hdev->state == USB_STATE_NOTATTACHED) {
			hub->error = -ENODEV;
			hub_quiesce(hub, HUB_DISCONNECT);
			goto loop;
		}

		/* Autoresume */
		ret = usb_autopm_get_interface(intf);
		if (ret) {
			dev_dbg(hub_dev, "Can't autoresume: %d\n", ret);
			goto loop;
		}

		/* If this is an inactive hub, do nothing */
		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);	//如果有錯誤重啓hub
			if (ret) {
				dev_dbg (hub_dev,
					"error resetting hub: %d\n", ret);
				goto loop_autopm;
			}

			hub->nerrors = 0;
			hub->error = 0;
		}

		/* deal with port status changes */
		for (i = 1; i <= hub->descriptor->bNbrPorts; i++) {
			if (test_bit(i, hub->busy_bits))	//如果port處於resume或reset狀態,跳過
				continue;
			connect_change = test_bit(i, hub->change_bits);
			//如果event_bits爲0,change_bits也爲0,也跳過
			if (!test_and_clear_bit(i, hub->event_bits) &&
					!connect_change)
				continue;
			//獲取portstatus,portchange
			ret = hub_port_status(hub, i,
					&portstatus, &portchange);
			if (ret < 0)
				continue;
			//連接狀態發生變化
			if (portchange & USB_PORT_STAT_C_CONNECTION) {
				clear_port_feature(hdev, i,
					USB_PORT_FEAT_C_CONNECTION);
				connect_change = 1;
			}
			//使能狀態發生變化
			if (portchange & USB_PORT_STAT_C_ENABLE) {
				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);

				/*
				 * EM interference sometimes causes badly
				 * shielded USB devices to be shutdown by
				 * the hub, this hack enables them again.
				 * Works at least with mouse driver. 
				 */
				//EMI引起的狀態變化
				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;
				}
			}
			//suspend狀態發生變化
			if (portchange & USB_PORT_STAT_C_SUSPEND) {
				struct usb_device *udev;

				clear_port_feature(hdev, i,
					USB_PORT_FEAT_C_SUSPEND);
				udev = hdev->children[i-1];
				if (udev) {
					/* TRSMRCY = 10 msec */
					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);
			}
			//port的過流發生變化
			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
				u16 status = 0;
				u16 unused;

				dev_dbg(hub_dev, "over-current change on port "
					"%d\n", i);
				clear_port_feature(hdev, i,
					USB_PORT_FEAT_C_OVER_CURRENT);
				msleep(100);	/* Cool down */
				hub_power_on(hub, true);
				hub_port_status(hub, i, &status, &unused);
				if (status & USB_PORT_STAT_OVERCURRENT)
					dev_err(hub_dev, "over-current "
						"condition on port %d\n", i);
			}
			//port reset完成
			if (portchange & USB_PORT_STAT_C_RESET) {
				dev_dbg (hub_dev,
					"reset change on port %d\n",
					i);
				clear_port_feature(hdev, i,
					USB_PORT_FEAT_C_RESET);
			}
			if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
					hub_is_superspeed(hub->hdev)) {
				dev_dbg(hub_dev,
					"warm reset change on port %d\n",
					i);
				clear_port_feature(hdev, i,
					USB_PORT_FEAT_C_BH_PORT_RESET);
			}
			if (portchange & USB_PORT_STAT_C_LINK_STATE) {
				clear_port_feature(hub->hdev, i,
						USB_PORT_FEAT_C_PORT_LINK_STATE);
			}
			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
				dev_warn(hub_dev,
					"config error on port %d\n",
					i);
				clear_port_feature(hub->hdev, i,
						USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
			}

			/* Warm reset a USB3 protocol port if it's in
			 * SS.Inactive state.
			 */
			if (hub_is_superspeed(hub->hdev) &&
				(portstatus & USB_PORT_STAT_LINK_STATE)
					== USB_SS_PORT_LS_SS_INACTIVE) {
				dev_dbg(hub_dev, "warm reset port %d\n", i);
				hub_port_warm_reset(hub, i);
			}
			//如果發生變化,調用hub_port_connect_change函數
			if (connect_change)
				hub_port_connect_change(hub, i,
						portstatus, portchange);
		} /* end for i */

		/* deal with hub status changes */
		if (test_and_clear_bit(0, hub->event_bits) == 0)
			;	/* do nothing */
		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)
					/* FIXME: Is this always true? */
					hub->limited_power = 1;
				else
					hub->limited_power = 0;
			}
			if (hubchange & HUB_CHANGE_OVERCURRENT) {
				u16 status = 0;
				u16 unused;

				dev_dbg(hub_dev, "over-current change\n");
				clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
				msleep(500);	/* Cool down */
                        	hub_power_on(hub, true);
				hub_hub_status(hub, &status, &unused);
				if (status & HUB_STATUS_OVERCURRENT)
					dev_err(hub_dev, "over-current "
						"condition\n");
			}
		}

 loop_autopm:
		/* Balance the usb_autopm_get_interface() above */
		usb_autopm_put_interface_no_suspend(intf);
 loop:
		/* Balance the usb_autopm_get_interface_no_resume() in
		 * kick_khubd() and allow autosuspend.
		 */
		usb_autopm_put_interface(intf);
 loop_disconnected:
		usb_unlock_device(hdev);
		kref_put(&hub->kref, hub_release);

        } /* end while (1) */
}
  1. static void hub_port_connect_change(struct usb_hub *hub, int port1,  
  2.                     u16 portstatus, u16 portchange)  
  3. {  
  4.     struct usb_device *hdev = hub->hdev;  
  5.     struct device *hub_dev = hub->intfdev;  
  6.     struct usb_hcd *hcd = bus_to_hcd(hdev->bus);  
  7.     unsigned wHubCharacteristics =  
  8.             le16_to_cpu(hub->descriptor->wHubCharacteristics);  
  9.     struct usb_device *udev;  
  10.     int status, i;  
  11.   
  12.     dev_dbg (hub_dev,  
  13.         "port %d, status %04x, change %04x, %s\n",  
  14.         port1, portstatus, portchange, portspeed(hub, portstatus));  
  15.     //hub支持indicator指示燈  
  16.     if (hub->has_indicators) {  
  17.         set_port_led(hub, port1, HUB_LED_AUTO);  
  18.         hub->indicator[port1-1] = INDICATOR_AUTO;  
  19.     }  
  20.   
  21. #ifdef  CONFIG_USB_OTG  
  22.     /* during HNP, don't repeat the debounce */  
  23.     if (hdev->bus->is_b_host)  
  24.         portchange &= ~(USB_PORT_STAT_C_CONNECTION |  
  25.                 USB_PORT_STAT_C_ENABLE);  
  26. #endif  
  27.   
  28.     /* Try to resuscitate an existing device */  
  29.     //試着喚醒一些處於suspend的設備  
  30.     udev = hdev->children[port1-1];  
  31.     if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&  
  32.             udev->state != USB_STATE_NOTATTACHED) {  
  33.         usb_lock_device(udev);  
  34.         if (portstatus & USB_PORT_STAT_ENABLE) {    //已經使能  
  35.             status = 0;     /* Nothing to do */  
  36.   
  37. #ifdef CONFIG_USB_SUSPEND  
  38.         } else if (udev->state == USB_STATE_SUSPENDED &&  
  39.                 udev->persist_enabled) { //處於suspend狀態  
  40.             /* For a suspended device, treat this as a 
  41.              * remote wakeup event. 
  42.              */  
  43.             status = usb_remote_wakeup(udev);  
  44. #endif  
  45.   
  46.         } else {  
  47.             status = -ENODEV;   /* Don't resuscitate */  
  48.         }  
  49.         usb_unlock_device(udev);  
  50.   
  51.         if (status == 0) {  
  52.             clear_bit(port1, hub->change_bits);  
  53.             return;  
  54.         }  
  55.     }  
  56.   
  57.     /* Disconnect any existing devices under this port */  
  58.     if (udev)   //把一些處於NOTATTACHED的設備從hub斷開  
  59.         usb_disconnect(&hdev->children[port1-1]);  
  60.     clear_bit(port1, hub->change_bits);  
  61.   
  62.     /* We can forget about a "removed" device when there's a physical 
  63.      * disconnect or the connect status changes. 
  64.      */  
  65.     if (!(portstatus & USB_PORT_STAT_CONNECTION) ||  
  66.             (portchange & USB_PORT_STAT_C_CONNECTION))  
  67.         clear_bit(port1, hub->removed_bits);  
  68.   
  69.     if (portchange & (USB_PORT_STAT_C_CONNECTION |  
  70.                 USB_PORT_STAT_C_ENABLE)) {  
  71.         status = hub_port_debounce(hub, port1); //防抖處理  
  72.         if (status < 0) {  
  73.             if (printk_ratelimit())  
  74.                 dev_err(hub_dev, "connect-debounce failed, "  
  75.                         "port %d disabled\n", port1);  
  76.             portstatus &= ~USB_PORT_STAT_CONNECTION;  
  77.         } else {  
  78.             portstatus = status;  
  79.         }  
  80.     }  
  81.   
  82.     /* Return now if debouncing failed or nothing is connected or 
  83.      * the device was "removed". 
  84.      */  
  85.     if (!(portstatus & USB_PORT_STAT_CONNECTION) ||  
  86.             test_bit(port1, hub->removed_bits)) {  
  87.   
  88.         /* maybe switch power back on (e.g. root hub was reset) */  
  89.         if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2  
  90.                 && !port_is_power_on(hub, portstatus))  
  91.             set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);  
  92.   
  93.         if (portstatus & USB_PORT_STAT_ENABLE)  
  94.             goto done;  
  95.         return;  
  96.     }  
  97.     //對於一個新插入的設備,爲這個usb設備枚舉  
  98.     for (i = 0; i < SET_CONFIG_TRIES; i++) {  
  99.   
  100.         /* reallocate for each attempt, since references 
  101.          * to the previous one can escape in various ways 
  102.          */  
  103.         udev = usb_alloc_dev(hdev, hdev->bus, port1);    //分配usb_device結構  
  104.         if (!udev) {  
  105.             dev_err (hub_dev,  
  106.                 "couldn't allocate port %d usb_device\n",  
  107.                 port1);  
  108.             goto done;  
  109.         }  
  110.   
  111.         usb_set_device_state(udev, USB_STATE_POWERED);  
  112.         udev->bus_mA = hub->mA_per_port;  //可以從port上獲取的電量  
  113.         udev->level = hdev->level + 1;    //等級  
  114.         udev->wusb = hub_is_wusb(hub);  
  115.   
  116.         /* Only USB 3.0 devices are connected to SuperSpeed hubs. */  
  117.         if (hub_is_superspeed(hub->hdev))  
  118.             udev->speed = USB_SPEED_SUPER;  
  119.         else  
  120.             udev->speed = USB_SPEED_UNKNOWN;  
  121.   
  122.         choose_devnum(udev);    //獲取一個usb地址  
  123.         if (udev->devnum <= 0) {  
  124.             status = -ENOTCONN; /* Don't retry */  
  125.             goto loop;  
  126.         }  
  127.   
  128.         /* reset (non-USB 3.0 devices) and get descriptor */  
  129.         status = hub_port_init(hub, udev, port1, i);    //對hub設備進行reset  
  130.         if (status < 0)  
  131.             goto loop;  
  132.   
  133.         usb_detect_quirks(udev);  
  134.         if (udev->quirks & USB_QUIRK_DELAY_INIT)  
  135.             msleep(1000);  
  136.   
  137.         /* consecutive bus-powered hubs aren't reliable; they can 
  138.          * violate the voltage drop budget.  if the new child has 
  139.          * a "powered" LED, users should notice we didn't enable it 
  140.          * (without reading syslog), even without per-port LEDs 
  141.          * on the parent. 
  142.          */  
  143.         //如果該usb_device是class_hub  
  144.         if (udev->descriptor.bDeviceClass == USB_CLASS_HUB  
  145.                 && udev->bus_mA <= 100) {  
  146.             u16 devstat;  
  147.   
  148.             status = usb_get_status(udev, USB_RECIP_DEVICE, 0,  
  149.                     &devstat);  
  150.             if (status < 2) {  
  151.                 dev_dbg(&udev->dev, "get status %d ?\n", status);  
  152.                 goto loop_disable;  
  153.             }  
  154.             le16_to_cpus(&devstat);  
  155.             if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {  
  156.                 dev_err(&udev->dev,  
  157.                     "can't connect bus-powered hub "  
  158.                     "to this port\n");  
  159.                 if (hub->has_indicators) {  
  160.                     hub->indicator[port1-1] =  
  161.                         INDICATOR_AMBER_BLINK;  
  162.                     schedule_delayed_work (&hub->leds, 0);  
  163.                 }  
  164.                 status = -ENOTCONN; /* Don't retry */  
  165.                 goto loop_disable;  
  166.             }  
  167.         }  
  168.    
  169.         /* check for devices running slower than they could */  
  170.         if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200  
  171.                 && udev->speed == USB_SPEED_FULL  
  172.                 && highspeed_hubs != 0)  
  173.             check_highspeed (hub, udev, port1);  
  174.   
  175.         /* Store the parent's children[] pointer.  At this point 
  176.          * udev becomes globally accessible, although presumably 
  177.          * no one will look at it until hdev is unlocked. 
  178.          */  
  179.         status = 0;  
  180.   
  181.         /* We mustn't add new devices if the parent hub has 
  182.          * been disconnected; we would race with the 
  183.          * recursively_mark_NOTATTACHED() routine. 
  184.          */  
  185.         spin_lock_irq(&device_state_lock);  
  186.         if (hdev->state == USB_STATE_NOTATTACHED)  
  187.             status = -ENOTCONN;  
  188.         else  
  189.             hdev->children[port1-1] = udev;  //設置子usb_device指針  
  190.         spin_unlock_irq(&device_state_lock);  
  191.   
  192.         /* Run it through the hoops (find a driver, etc) */  
  193.         if (!status) {  
  194.             status = usb_new_device(udev);  //添加到系統中  
  195.             if (status) {  
  196.                 spin_lock_irq(&device_state_lock);  
  197.                 hdev->children[port1-1] = NULL;  
  198.                 spin_unlock_irq(&device_state_lock);  
  199.             }  
  200.         }  
  201.   
  202.         if (status)  
  203.             goto loop_disable;  
  204.   
  205.         status = hub_power_remaining(hub);  
  206.         if (status)  
  207.             dev_dbg(hub_dev, "%dmA power budget left\n", status);  
  208.   
  209.         return;  
  210.   
  211. loop_disable:  
  212.         hub_port_disable(hub, port1, 1);  
  213. loop:  
  214.         usb_ep0_reinit(udev);  
  215.         release_devnum(udev);  
  216.         hub_free_dev(udev);  
  217.         usb_put_dev(udev);  
  218.         if ((status == -ENOTCONN) || (status == -ENOTSUPP))  
  219.             break;  
  220.     }  
  221.     if (hub->hdev->parent ||  
  222.             !hcd->driver->port_handed_over ||  
  223.             !(hcd->driver->port_handed_over)(hcd, port1))  
  224.         dev_err(hub_dev, "unable to enumerate USB device on port %d\n",  
  225.                 port1);  
  226.    
  227. done:  
  228.     hub_port_disable(hub, port1, 1);  
  229.     if (hcd->driver->relinquish_port && !hub->hdev->parent)  
  230.         hcd->driver->relinquish_port(hcd, port1);  
  231. }  
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(hub, portstatus));
	//hub支持indicator指示燈
	if (hub->has_indicators) {
		set_port_led(hub, port1, HUB_LED_AUTO);
		hub->indicator[port1-1] = INDICATOR_AUTO;
	}

#ifdef	CONFIG_USB_OTG
	/* during HNP, don't repeat the debounce */
	if (hdev->bus->is_b_host)
		portchange &= ~(USB_PORT_STAT_C_CONNECTION |
				USB_PORT_STAT_C_ENABLE);
#endif

	/* Try to resuscitate an existing device */
	//試着喚醒一些處於suspend的設備
	udev = hdev->children[port1-1];
	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
			udev->state != USB_STATE_NOTATTACHED) {
		usb_lock_device(udev);
		if (portstatus & USB_PORT_STAT_ENABLE) {	//已經使能
			status = 0;		/* Nothing to do */

#ifdef CONFIG_USB_SUSPEND
		} else if (udev->state == USB_STATE_SUSPENDED &&
				udev->persist_enabled) {	//處於suspend狀態
			/* For a suspended device, treat this as a
			 * remote wakeup event.
			 */
			status = usb_remote_wakeup(udev);
#endif

		} else {
			status = -ENODEV;	/* Don't resuscitate */
		}
		usb_unlock_device(udev);

		if (status == 0) {
			clear_bit(port1, hub->change_bits);
			return;
		}
	}

	/* Disconnect any existing devices under this port */
	if (udev)	//把一些處於NOTATTACHED的設備從hub斷開
		usb_disconnect(&hdev->children[port1-1]);
	clear_bit(port1, hub->change_bits);

	/* We can forget about a "removed" device when there's a physical
	 * disconnect or the connect status changes.
	 */
	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;
		}
	}

	/* Return now if debouncing failed or nothing is connected or
	 * the device was "removed".
	 */
	if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
			test_bit(port1, hub->removed_bits)) {

		/* maybe switch power back on (e.g. root hub was reset) */
		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
				&& !port_is_power_on(hub, portstatus))
			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);

		if (portstatus & USB_PORT_STAT_ENABLE)
  			goto done;
		return;
	}
	//對於一個新插入的設備,爲這個usb設備枚舉
	for (i = 0; i < SET_CONFIG_TRIES; i++) {

		/* reallocate for each attempt, since references
		 * to the previous one can escape in various ways
		 */
		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);
 		udev->bus_mA = hub->mA_per_port;	//可以從port上獲取的電量
		udev->level = hdev->level + 1;	//等級
		udev->wusb = hub_is_wusb(hub);

		/* Only USB 3.0 devices are connected to SuperSpeed hubs. */
		if (hub_is_superspeed(hub->hdev))
			udev->speed = USB_SPEED_SUPER;
		else
			udev->speed = USB_SPEED_UNKNOWN;

		choose_devnum(udev);	//獲取一個usb地址
		if (udev->devnum <= 0) {
			status = -ENOTCONN;	/* Don't retry */
			goto loop;
		}

		/* reset (non-USB 3.0 devices) and get descriptor */
		status = hub_port_init(hub, udev, port1, i);	//對hub設備進行reset
		if (status < 0)
			goto loop;

		usb_detect_quirks(udev);
		if (udev->quirks & USB_QUIRK_DELAY_INIT)
			msleep(1000);

		/* consecutive bus-powered hubs aren't reliable; they can
		 * violate the voltage drop budget.  if the new child has
		 * a "powered" LED, users should notice we didn't enable it
		 * (without reading syslog), even without per-port LEDs
		 * on the parent.
		 */
		//如果該usb_device是class_hub
		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
				&& udev->bus_mA <= 100) {
			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;	/* Don't retry */
				goto loop_disable;
			}
		}
 
		/* check for devices running slower than they could */
		if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
				&& udev->speed == USB_SPEED_FULL
				&& highspeed_hubs != 0)
			check_highspeed (hub, udev, port1);

		/* Store the parent's children[] pointer.  At this point
		 * udev becomes globally accessible, although presumably
		 * no one will look at it until hdev is unlocked.
		 */
		status = 0;

		/* We mustn't add new devices if the parent hub has
		 * been disconnected; we would race with the
		 * recursively_mark_NOTATTACHED() routine.
		 */
		spin_lock_irq(&device_state_lock);
		if (hdev->state == USB_STATE_NOTATTACHED)
			status = -ENOTCONN;
		else
			hdev->children[port1-1] = udev;	//設置子usb_device指針
		spin_unlock_irq(&device_state_lock);

		/* Run it through the hoops (find a driver, etc) */
		if (!status) {
			status = usb_new_device(udev);	//添加到系統中
			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_devnum(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_port_connect_change主要調用了3個函數:

usb_alloc_dev分配usb_device結構,hub_port_init重置該usb_device,usb_new_device(框架分析2中已經分析過)添加到系統中。接下來分析hub_port_init函數:

  1. static int  
  2. hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  
  3.         int retry_counter)  
  4. {  
  5.     static DEFINE_MUTEX(usb_address0_mutex);  
  6.   
  7.     struct usb_device   *hdev = hub->hdev;  
  8.     struct usb_hcd      *hcd = bus_to_hcd(hdev->bus);  
  9.     int         i, j, retval;  
  10.     unsigned        delay = HUB_SHORT_RESET_TIME;  
  11.     enum usb_device_speed   oldspeed = udev->speed;  
  12.     char            *speed, *type;  
  13.     int         devnum = udev->devnum;  
  14.   
  15.     /* root hub ports have a slightly longer reset period 
  16.      * (from USB 2.0 spec, section 7.1.7.5) 
  17.      */  
  18.     //root hub的處理  
  19.     if (!hdev->parent) {  
  20.         delay = HUB_ROOT_RESET_TIME;  
  21.         if (port1 == hdev->bus->otg_port)  
  22.             hdev->bus->b_hnp_enable = 0;  
  23.     }  
  24.   
  25.     /* Some low speed devices have problems with the quick delay, so */  
  26.     /*  be a bit pessimistic with those devices. RHbug #23670 */  
  27.     if (oldspeed == USB_SPEED_LOW)  
  28.         delay = HUB_LONG_RESET_TIME;    //低速設備需要200ms  
  29.   
  30.     mutex_lock(&usb_address0_mutex);  
  31.   
  32.     /* Reset the device; full speed may morph to high speed */  
  33.     /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */  
  34.     retval = hub_port_reset(hub, port1, udev, delay);   //reset設備  
  35.     if (retval < 0)      /* error or disconnect */  
  36.         goto fail;  
  37.     /* success, speed is known */  
  38.   
  39.     retval = -ENODEV;  
  40.   
  41.     if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {  
  42.         dev_dbg(&udev->dev, "device reset changed speed!\n");  
  43.         goto fail;  
  44.     }  
  45.     oldspeed = udev->speed;  
  46.   
  47.     /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... 
  48.      * it's fixed size except for full speed devices. 
  49.      * For Wireless USB devices, ep0 max packet is always 512 (tho 
  50.      * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. 
  51.      */  
  52.     //根據usb速度初始化endpoint0的最大發送數據長度  
  53.     switch (udev->speed) {  
  54.     case USB_SPEED_SUPER:  
  55.     case USB_SPEED_WIRELESS:    /* fixed at 512 */  
  56.         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);  
  57.         break;  
  58.     case USB_SPEED_HIGH:        /* fixed at 64 */  
  59.         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);  
  60.         break;  
  61.     case USB_SPEED_FULL:        /* 8, 16, 32, or 64 */  
  62.         /* to determine the ep0 maxpacket size, try to read 
  63.          * the device descriptor to get bMaxPacketSize0 and 
  64.          * then correct our initial guess. 
  65.          */  
  66.         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);  
  67.         break;  
  68.     case USB_SPEED_LOW:     /* fixed at 8 */  
  69.         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);  
  70.         break;  
  71.     default:  
  72.         goto fail;  
  73.     }  
  74.    
  75.     type = "";  
  76.     switch (udev->speed) {  
  77.     case USB_SPEED_LOW: speed = "low";  break;  
  78.     case USB_SPEED_FULL:    speed = "full"break;  
  79.     case USB_SPEED_HIGH:    speed = "high"break;  
  80.     case USB_SPEED_SUPER:  
  81.                 speed = "super";  
  82.                 break;  
  83.     case USB_SPEED_WIRELESS:  
  84.                 speed = "variable";  
  85.                 type = "Wireless ";  
  86.                 break;  
  87.     default:        speed = "?";    break;  
  88.     }  
  89.     if (udev->speed != USB_SPEED_SUPER)  
  90.         dev_info(&udev->dev,  
  91.                 "%s %s speed %sUSB device number %d using %s\n",  
  92.                 (udev->config) ? "reset" : "new", speed, type,  
  93.                 devnum, udev->bus->controller->driver->name);  
  94.   
  95.     /* Set up TT records, if needed  */  
  96.     if (hdev->tt) {  
  97.         udev->tt = hdev->tt;  
  98.         udev->ttport = hdev->ttport;  
  99.     } else if (udev->speed != USB_SPEED_HIGH  
  100.             && hdev->speed == USB_SPEED_HIGH) {  
  101.         if (!hub->tt.hub) {  
  102.             dev_err(&udev->dev, "parent hub has no TT\n");  
  103.             retval = -EINVAL;  
  104.             goto fail;  
  105.         }  
  106.         udev->tt = &hub->tt;  
  107.         udev->ttport = port1;  
  108.     }  
  109.    
  110.     /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? 
  111.      * Because device hardware and firmware is sometimes buggy in 
  112.      * this area, and this is how Linux has done it for ages. 
  113.      * Change it cautiously. 
  114.      * 
  115.      * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing 
  116.      * a 64-byte GET_DESCRIPTOR request.  This is what Windows does, 
  117.      * so it may help with some non-standards-compliant devices. 
  118.      * Otherwise we start with SET_ADDRESS and then try to read the 
  119.      * first 8 bytes of the device descriptor to get the ep0 maxpacket 
  120.      * value. 
  121.      */  
  122.     //通過獲取usb設備描述符來得到usb設備的endpoint0的最大發送數據長度  
  123.     for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {  
  124.         if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {  
  125.             struct usb_device_descriptor *buf;  
  126.             int r = 0;  
  127.   
  128. #define GET_DESCRIPTOR_BUFSIZE  64  
  129.             buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);  
  130.             if (!buf) {  
  131.                 retval = -ENOMEM;  
  132.                 continue;  
  133.             }  
  134.   
  135.             /* Retry on all errors; some devices are flakey. 
  136.              * 255 is for WUSB devices, we actually need to use 
  137.              * 512 (WUSB1.0[4.8.1]). 
  138.              */  
  139.             for (j = 0; j < 3; ++j) {  
  140.                 buf->bMaxPacketSize0 = 0;  
  141.                 r = usb_control_msg(udev, usb_rcvaddr0pipe(),  
  142.                     USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,  
  143.                     USB_DT_DEVICE << 8, 0,  
  144.                     buf, GET_DESCRIPTOR_BUFSIZE,  
  145.                     initial_descriptor_timeout);  
  146.                 switch (buf->bMaxPacketSize0) {  
  147.                 case 8: case 16: case 32: case 64: case 255:  
  148.                     if (buf->bDescriptorType ==  
  149.                             USB_DT_DEVICE) {  
  150.                         r = 0;  
  151.                         break;  
  152.                     }  
  153.                     /* FALL THROUGH */  
  154.                 default:  
  155.                     if (r == 0)  
  156.                         r = -EPROTO;  
  157.                     break;  
  158.                 }  
  159.                 if (r == 0)  
  160.                     break;  
  161.             }  
  162.             udev->descriptor.bMaxPacketSize0 =  
  163.                     buf->bMaxPacketSize0;  
  164.             kfree(buf);  
  165.   
  166.             retval = hub_port_reset(hub, port1, udev, delay);  
  167.             if (retval < 0)      /* error or disconnect */  
  168.                 goto fail;  
  169.             if (oldspeed != udev->speed) {  
  170.                 dev_dbg(&udev->dev,  
  171.                     "device reset changed speed!\n");  
  172.                 retval = -ENODEV;  
  173.                 goto fail;  
  174.             }  
  175.             if (r) {  
  176.                 dev_err(&udev->dev,  
  177.                     "device descriptor read/64, error %d\n",  
  178.                     r);  
  179.                 retval = -EMSGSIZE;  
  180.                 continue;  
  181.             }  
  182. #undef GET_DESCRIPTOR_BUFSIZE  
  183.         }  
  184.   
  185.         /* 
  186.          * If device is WUSB, we already assigned an 
  187.          * unauthorized address in the Connect Ack sequence; 
  188.          * authorization will assign the final address. 
  189.          */  
  190.         if (udev->wusb == 0) {  
  191.             for (j = 0; j < SET_ADDRESS_TRIES; ++j) {  
  192.                 retval = hub_set_address(udev, devnum);  
  193.                 if (retval >= 0)  
  194.                     break;  
  195.                 msleep(200);  
  196.             }  
  197.             if (retval < 0) {  
  198.                 dev_err(&udev->dev,  
  199.                     "device not accepting address %d, error %d\n",  
  200.                     devnum, retval);  
  201.                 goto fail;  
  202.             }  
  203.             if (udev->speed == USB_SPEED_SUPER) {  
  204.                 devnum = udev->devnum;  
  205.                 dev_info(&udev->dev,  
  206.                         "%s SuperSpeed USB device number %d using %s\n",  
  207.                         (udev->config) ? "reset" : "new",  
  208.                         devnum, udev->bus->controller->driver->name);  
  209.             }  
  210.   
  211.             /* cope with hardware quirkiness: 
  212.              *  - let SET_ADDRESS settle, some device hardware wants it 
  213.              *  - read ep0 maxpacket even for high and low speed, 
  214.              */  
  215.             msleep(10);  
  216.             if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))  
  217.                 break;  
  218.         }  
  219.   
  220.         retval = usb_get_device_descriptor(udev, 8);    //獲取設備描述符,8個字節  
  221.         if (retval < 8) {  
  222.             dev_err(&udev->dev,  
  223.                     "device descriptor read/8, error %d\n",  
  224.                     retval);  
  225.             if (retval >= 0)  
  226.                 retval = -EMSGSIZE;  
  227.         } else {  
  228.             retval = 0;  
  229.             break;  
  230.         }  
  231.     }  
  232.     if (retval)  
  233.         goto fail;  
  234.     //對於無線usb設備和超速usb設備  
  235.     if (udev->descriptor.bMaxPacketSize0 == 0xff ||  
  236.             udev->speed == USB_SPEED_SUPER)  
  237.         i = 512;  
  238.     else  
  239.         i = udev->descriptor.bMaxPacketSize0;  
  240.     //初始化時設置的maxpacketsize和設備描述符的不一樣,修正  
  241.     if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {  
  242.         if (udev->speed == USB_SPEED_LOW ||  
  243.                 !(i == 8 || i == 16 || i == 32 || i == 64)) {  
  244.             dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);  
  245.             retval = -EMSGSIZE;  
  246.             goto fail;  
  247.         }  
  248.         if (udev->speed == USB_SPEED_FULL)  
  249.             dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);  
  250.         else  
  251.             dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);  
  252.         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);  
  253.         usb_ep0_reinit(udev);  
  254.     }  
  255.     
  256.     retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);   //獲取完整的設備描述符  
  257.     if (retval < (signed)sizeof(udev->descriptor)) {  
  258.         dev_err(&udev->dev, "device descriptor read/all, error %d\n",  
  259.             retval);  
  260.         if (retval >= 0)  
  261.             retval = -ENOMSG;  
  262.         goto fail;  
  263.     }  
  264.   
  265.     retval = 0;  
  266.     /* notify HCD that we have a device connected and addressed */  
  267.     if (hcd->driver->update_device)  
  268.         hcd->driver->update_device(hcd, udev);  
  269. fail:  
  270.     if (retval) {  
  271.         hub_port_disable(hub, port1, 0);  
  272.         update_devnum(udev, devnum);    /* for disconnect processing */  
  273.     }  
  274.     mutex_unlock(&usb_address0_mutex);  
  275.     return retval;  
  276. }  
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;

	/* root hub ports have a slightly longer reset period
	 * (from USB 2.0 spec, section 7.1.7.5)
	 */
	//root hub的處理
	if (!hdev->parent) {
		delay = HUB_ROOT_RESET_TIME;
		if (port1 == hdev->bus->otg_port)
			hdev->bus->b_hnp_enable = 0;
	}

	/* Some low speed devices have problems with the quick delay, so */
	/*  be a bit pessimistic with those devices. RHbug #23670 */
	if (oldspeed == USB_SPEED_LOW)
		delay = HUB_LONG_RESET_TIME;	//低速設備需要200ms

	mutex_lock(&usb_address0_mutex);

	/* Reset the device; full speed may morph to high speed */
	/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
	retval = hub_port_reset(hub, port1, udev, delay);	//reset設備
	if (retval < 0)		/* error or disconnect */
		goto fail;
	/* success, speed is known */

	retval = -ENODEV;

	if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
		dev_dbg(&udev->dev, "device reset changed speed!\n");
		goto fail;
	}
	oldspeed = udev->speed;

	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
	 * it's fixed size except for full speed devices.
	 * For Wireless USB devices, ep0 max packet is always 512 (tho
	 * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
	 */
	//根據usb速度初始化endpoint0的最大發送數據長度
	switch (udev->speed) {
	case USB_SPEED_SUPER:
	case USB_SPEED_WIRELESS:	/* fixed at 512 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
		break;
	case USB_SPEED_HIGH:		/* fixed at 64 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
		break;
	case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
		/* to determine the ep0 maxpacket size, try to read
		 * the device descriptor to get bMaxPacketSize0 and
		 * then correct our initial guess.
		 */
		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
		break;
	case USB_SPEED_LOW:		/* fixed at 8 */
		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 number %d using %s\n",
				(udev->config) ? "reset" : "new", speed, type,
				devnum, udev->bus->controller->driver->name);

	/* Set up TT records, if needed  */
	if (hdev->tt) {
		udev->tt = hdev->tt;
		udev->ttport = hdev->ttport;
	} else if (udev->speed != USB_SPEED_HIGH
			&& hdev->speed == USB_SPEED_HIGH) {
		if (!hub->tt.hub) {
			dev_err(&udev->dev, "parent hub has no TT\n");
			retval = -EINVAL;
			goto fail;
		}
		udev->tt = &hub->tt;
		udev->ttport = port1;
	}
 
	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
	 * Because device hardware and firmware is sometimes buggy in
	 * this area, and this is how Linux has done it for ages.
	 * Change it cautiously.
	 *
	 * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing
	 * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,
	 * so it may help with some non-standards-compliant devices.
	 * Otherwise we start with SET_ADDRESS and then try to read the
	 * first 8 bytes of the device descriptor to get the ep0 maxpacket
	 * value.
	 */
	//通過獲取usb設備描述符來得到usb設備的endpoint0的最大發送數據長度
	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;
			}

			/* Retry on all errors; some devices are flakey.
			 * 255 is for WUSB devices, we actually need to use
			 * 512 (WUSB1.0[4.8.1]).
			 */
			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;
					}
					/* FALL THROUGH */
				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)		/* error or disconnect */
				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 device is WUSB, we already assigned an
 		 * unauthorized address in the Connect Ack sequence;
 		 * authorization will assign the final address.
 		 */
		if (udev->wusb == 0) {
			for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
				retval = hub_set_address(udev, devnum);
				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 number %d using %s\n",
						(udev->config) ? "reset" : "new",
						devnum, udev->bus->controller->driver->name);
			}

			/* cope with hardware quirkiness:
			 *  - let SET_ADDRESS settle, some device hardware wants it
			 *  - read ep0 maxpacket even for high and low speed,
			 */
			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;
	//對於無線usb設備和超速usb設備
	if (udev->descriptor.bMaxPacketSize0 == 0xff ||
			udev->speed == USB_SPEED_SUPER)
		i = 512;
	else
		i = udev->descriptor.bMaxPacketSize0;
	//初始化時設置的maxpacketsize和設備描述符的不一樣,修正
	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;
	/* notify HCD that we have a device connected and addressed */
	if (hcd->driver->update_device)
		hcd->driver->update_device(hcd, udev);
fail:
	if (retval) {
		hub_port_disable(hub, port1, 0);
		update_devnum(udev, devnum);	/* for disconnect processing */
	}
	mutex_unlock(&usb_address0_mutex);
	return retval;
}
這裏把上節略過,這一節又遇到的函數usb_enumerate_device的函數調用說下:

usb_enumerate_device

usb_get_configuration

usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,desc, USB_DT_CONFIG_SIZE);

usb_parse_configuration

usb_parse_interface

usb_parse_endpoint

就是對設備描述符一級一級的解析並且分配相應的數據結構

發佈了3 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章