Linux USB enumeration Process Analysis Daemon and its wake-up "turn"

Source: Internet
Author: User
Tags goto

Transferred from: http://blog.csdn.net/xuelin273/article/details/38646765

USB Hot plug, that is, USB devices can be Plug and play, like a USB stick, plug into the computer can be used, when not directly removed, this action will not affect the performance of USB devices.

In Linx system, USB hot plug is implemented by two parts, namely kernel space and user space, the kernel is implemented by a daemon process, and user space is implemented by Udev program. In the kernel space, there is a daemon dedicated to monitoring the status of the USB hub, the daemon is waiting for the queue to be implemented, waiting for the queue to handle hibernation, when the status of the USB hub changes (that is, a USB device inserted or unplugged from the USB hub), it will wake up the waiting queue, Then go to implement the USB device enumeration, after the enumeration succeeds, registers the USB device with the Linux system, and notifies the user space through the kobject_event, has the device inserts or pulls out, the user space has one specially for realizes the dynamic loading device node The program Udev, when it receives the kernel notification, The ability to dynamically create USB device nodes, which enables USB hot-swapping.

This article mainly from the USB device enumeration the most basic aspects of the explanation, that is, the USB daemon, how the daemon wakes up, who wakes.

I. Daemon in Linux system, USB is a relatively complex subsystem, so the initialization process of USB subsystem is also relatively complex, involving a number of aspects: USB bus initialization, USB file system initialization, USB hub initialization, USB device driver registration.        In the process of USB hub initialization Usb_hub_init, in addition to registering the USB hub driver with the system, it also creates a daemon hub_thread for monitoring the status of the USB root hub. Hub_thread created and awakened by Kthread_run:
[HTML] view Plaincopy
  1. Khubd_task = Kthread_run (hub_thread, NULL, "khubd");
  2. if (!is_err (Khubd_task))
  3. return 0;
[HTML]View Plaincopy
  1. static int hub_thread (void *__unused)
  2. {
  3. Set_freezable ();
  4. do {
  5. Hub_events ();
  6. Wait_event_freezable (Khubd_wait,
  7. !list_empty (&hub_event_list) | |
  8. Kthread_should_stop ());
  9. } while (!kthread_should_stop () | |!list_empty (&hub_event_list));
  10. Pr_debug ("%s:khubd exiting\n", usbcore_name);
  11. return 0;
  12. }
The set_freezable effect of line 3rd is to clear the pf_nofreeze bit in flags of the current thread, indicating that the current thread can go into suspend or hibernate state. Next is a do...while loop, which ends with the condition that the current thread receives a stop request and the Hub_event_list list is empty, the daemon is created and awakened by Kthread_run, and the thread is stopped when Kthread_stop is called        The Do...while loop will only jump out if you receive Kthread_stop and the Hub_event_list list is empty. In the Do...while loop, there are only two lines of code, hub_events is the core of the USB system, as long as hub_event_list non-empty will run the USB enumeration process, until Hub_event_list is empty, then jump out of hub_events , through wait_event_freezable into hibernation, where khubd_wait is a waiting queue header, which is defined statically:
[HTML] view Plaincopy
  1. Static Declare_wait_queue_head (khubd_wait);
The second parameter in Wait_event_freezable is waiting for the queue to enter the sleep condition condition, only the second argument is false to enter hibernation, that is, the Hub_event_list list is empty and the stop request is not received, here Hub_event_ The list must be empty, so as long as you do not receive the Kthread_stop request, you can enter hibernation, sleep is awakened after the detection of condition when the condition is satisfied, that is, condition is true, hub_event_list is not empty or received a stop request, If you receive a stop request, exit the Do...while loop directly, and if it is because hub_event_list is not empty, run hub_events to implement the USB enumeration. Two. Daemon wakeup when the hub_events is finished, the USB thread enters hibernation through wait_event_freezable until the signal is interrupted or the condition is met, and the USB daemon is awakened by the KICK_KHUBD function. This function is called in several places: [HTML]View Plaincopy
  1. static void Kick_khubd (struct usb_hub *hub)
  2. {
  3. unsigned long flags;
  4. Spin_lock_irqsave (&hub_event_lock, flags);
  5. if (!hub->disconnected && list_empty (&hub->event_list)) {
  6. List_add_tail (&hub->event_list, &hub_event_list);
  7. /* Suppress autosuspend until KHUBD runs * *
  8. Usb_autopm_get_interface_no_resume (
  9. To_usb_interface (hub->intfdev));
  10. WAKE_UP (&khubd_wait);
  11. }
  12. Spin_unlock_irqrestore (&hub_event_lock, flags);
  13. }
Line 6th, only the hub is connected and the event_list in the hub is the initial state, and Line 7th, the event_list of the hub is added to the Hub_event_list list to satisfy the condition when the daemon wakes up.         The 10th line, the automatic mount Count plus 1, stops the hub from entering the suspend state when enumerating.         Line 12th, wake up the dormant USB daemon via wake_up. There are several places where you can call KICK_KHUBD to wake up the USB daemon:

The hub has two ports, control endpoint and interrupt endpoint, where interrupt endpoint is primarily used to query port status changes on the hub. A root hub is created when the controller driver is added, and when a hub insertion is detected on the root hub port, a USB hub is created, which is applied to the root hub or the normal hub when it is configured for interrupt Endpoint application URB Related resources: [HTML]View Plaincopy
    1. hub->urb = usb_alloc_urb (0, Gfp_kernel);
    2. if (!hub->urb) {
    3. ret =-enomem;
    4. Goto fail;
    5. }
    6. Usb_fill_int_urb (hub->urb, Hdev, pipe, *hub->buffer, Maxp, HUB_IRQ, Hub, endpoint->binterval);
The callback function for URB is HUB_IRQ: [HTML]View Plaincopy
  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. Switch (status) {
  8. Case-enoent:/* Synchronous unlink */
  9. Case-econnreset:/* Async unlink */
  10. Case-eshutdown:/* Hardware going away */
  11. Return
  12. Default:/* Presumably an error */
  13. /* cause a hub reset after ten consecutive errors */
  14. dev_dbg (hub->intfdev, "Transfer->%d\n", status);
  15. if ((++hub->nerrors < ) | | hub->error)
  16. Goto resubmit;
  17. hub->error = status;
  18. /* FALL THROUGH */
  19. /* Let KHUBD handle things */
  20. Case 0:/* We got data:port status changed */
  21. bits = 0;
  22. for (i = 0; I < urb->actual_length; ++i)
  23. Bits |= ((unsigned long) ((*hub->buffer) [i] )
  24. << (I*8);
  25. hub->event_bits[0] = bits;
  26. Break
  27. }
  28. hub->nerrors = 0;
  29. /* Something happened, let KHUBD figure it out */
  30. KICK_KHUBD (hub);
  31. Resubmit
  32. if (hub->quiescing)
  33. Return
  34. if (status = usb_submit_urb (hub->urb, gfp_atomic))! = 0
  35. && Status! =-enodev && Status! =-eperm)
  36. Dev_err (hub->intfdev, "resubmit->%d\n", status);
  37. }
As you can see in Hub_irq, if the URB is successfully submitted to the Controller and the port status is successfully obtained, the KICK_KHUBD wake Daemon is called, and for the root hub of the OHCI type, it can be usb_submit_ with the exception of other hubs. URB submits a request to query the hub status, it can also be interrupted to query, when the controller driver is added with USB_ADD_HCD, the controller will be requested to interrupt:
[HTML] view Plaincopy
  1. retval = Usb_hcd_request_irqs (HCD, Irqnum, irqflags);
  2. if (retval)
  3. Goto ERR_REQUEST_IRQ;
For OHCI type controllers, one of the interrupt handler OHCI_IRQ is used to monitor the port status on the root hub: [HTML]View Plaincopy
    1. if  (INTS&NBSP;&&NBSP;OHCI_INTR_RHSC)  {  
    2.     ohci_vdbg (ohci,  "rhsc\n");   
    3.      ohci->next_statechange = JIFFIES&NBSP;+&NBSP;STATECHANGE_DELAY;&NBSP;&NBSP;
    4.      ohci_writel (ohci, ohci_intr_rd | ohci_intr_rhsc, ®s-> Intrstatus);   
    5.     ohci_writel (ohci, ohci_intr_ Rhsc, ®s->intrdisable)   
    6.     usb_hcd_ Poll_rh_status (HCD);   
    7. }&NBSP;&NBSP;
When the state on the port changes, it calls Usb_hcd_poll_rh_status to query the USB root hub port status, and calls the interrupt Urb callback function HUB_IRQ in the hub, eventually to wake up the USB daemon. For the root hub, when it uses USB_SUBMIT_URB to submit query hub status requests, it starts a timer rh_timer to query the root hub state periodically, and if the hub state is successfully obtained and returned through HUB_IRQ, the Hub_ The IRQ will finally automatically call Usb_submit_urb again to get the hub status. If you cannot get or fail to return through HUB_IRQ, you will not call Usb_submit_urb again, and for root hub you can query the port state by proactively calling Usb_submit_urb or through the interrupt of the controller, in addition,        When adding a controller driver to the system, a root hub is created and registered automatically, and the driver will match the hub driver to the root hub and configure it, and it will invoke KICK_KHUBD to wake the Daemon (hub_activate). If a USB hub is found at the time of enumeration, the hub will also be matched to its driver, and if the driver is successfully matched, the hub will be configured and the KICK_KHUBD will be called to wake the daemon when it is successfully configured.

Linux USB enumeration Process Analysis Daemon and its wake-up "turn"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.