]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
USB hot-plugging
authorstarous <starous@pracovna>
Thu, 8 Jul 2010 20:54:35 +0000 (22:54 +0200)
committerstarous <starous@pracovna>
Thu, 8 Jul 2010 20:54:35 +0000 (22:54 +0200)
bus/usb/ohci.c
bus/usb/uhci.c
bus/usb/usb.c
bus/usb/usbhub.c
include/grub/usb.h
include/grub/usbtrans.h

index fed82d12956b9bf4892e3561be41da40740b2178..36bb5dd4450c86433498ec55474aabb5f39847f4 100644 (file)
@@ -148,6 +148,7 @@ typedef enum
 #define GRUB_OHCI_REG_CONTROL_BULK_ENABLE (1 << 5)
 #define GRUB_OHCI_REG_CONTROL_CONTROL_ENABLE (1 << 4)
 
+#define GRUB_OHCI_RESET_CONNECT_CHANGE (1 << 16)
 #define GRUB_OHCI_CTRL_EDS 16
 #define GRUB_OHCI_BULK_EDS 16
 #define GRUB_OHCI_TDS 256
@@ -420,23 +421,8 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
                        (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA)
                         & ~GRUB_OHCI_RHUB_PORT_POWER_MASK)
                        | GRUB_OHCI_RHUB_PORT_ALL_POWERED);
-  /* Wait for stable power (100ms) and stable attachment (100ms) */
-  /* I.e. minimum wait time should be probably 200ms. */
-  /* We assume that device is attached when ohci is loaded. */
-  /* Some devices take long time to power-on or indicate attach. */
-  /* Here is some experimental value which should probably mostly work. */
-  /* Cameras with manual USB mode selection and maybe some other similar
-   * devices will not work in some cases - they are repowered during
-   * ownership change and then they are starting slowly and mostly they
-   * are wanting select proper mode again...
-   * The same situation can be on computers where BIOS not set-up OHCI
-   * to be at least powered USB bus (maybe it is Yeelong case...?)
-   * Possible workaround could be for example some prompt
-   * for user with confirmation of proper USB device connection.
-   * Another workaround - "rmmod usbms", "rmmod ohci", proper start
-   * and configuration of USB device and then "insmod ohci"
-   * and "insmod usbms". */
-  grub_millisleep (500);       
+  /* Now we have hot-plugging, we need to wait for stable power only */
+  grub_millisleep (100);
 
   /* Link to ohci now that initialisation is successful.  */
   o->next = ohci;
@@ -998,6 +984,15 @@ grub_ohci_transfer (grub_usb_controller_t dev,
             }
         }
 
+      /* Even if we have "good" OHCI, in some cases
+       * tderr_phys can be zero, check it */
+      else if ( !tderr_phys )
+        { /* Retired TD with error should be previous TD to ED->td_head */
+          tderr_phys = GRUB_OHCI_TD_PHYS2VIRT (o,
+                         grub_le_to_cpu32 ( ed_virt->td_head) & ~0xf )
+                       ->prev_td_phys;
+        }
+
       /* Prepare pointer to last processed TD and get error code */
       tderr_virt = GRUB_OHCI_TD_PHYS2VIRT (o, tderr_phys);
       /* Set index of last processed TD */
@@ -1095,8 +1090,6 @@ grub_ohci_transfer (grub_usb_controller_t dev,
          break;
        }
 
-      /* Set empty ED - set HEAD = TAIL = last (not processed) TD */
-      ed_virt->td_head = ed_virt->td_tail & ~0xf; 
     }
         
   else if (err_unrec)      
@@ -1117,7 +1110,6 @@ grub_ohci_transfer (grub_usb_controller_t dev,
       grub_dprintf ("ohci", "Unrecoverable error - OHCI reset\n");
 
       /* Misc. resets. */
-      ed_virt->td_head = ed_virt->td_tail & ~0xf; /* Set empty ED - set HEAD = TAIL = last (not processed) TD */
       o->hcca->donehead = 0;
       grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, 0x7f); /* Clears everything */
       grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, o->ed_ctrl_addr);
@@ -1160,10 +1152,12 @@ grub_ohci_transfer (grub_usb_controller_t dev,
       else
         transfer->last_trans = -1;
 
-      /* Set empty ED - set HEAD = TAIL = last (not processed) TD */
-      ed_virt->td_head = ed_virt->td_tail & ~0xf; 
     }
 
+    /* Set empty ED - set HEAD = TAIL = last (not processed) TD */
+    ed_virt->td_head = grub_cpu_to_le32 ( grub_le_to_cpu32 (
+                                            ed_virt->td_tail) & ~0xf); 
+
   /* At this point always should be:
    * ED has skip bit set and halted or empty or after next SOF,
    *    i.e. it is safe to free all TDs except last not processed
@@ -1198,10 +1192,28 @@ grub_ohci_portstatus (grub_usb_controller_t dev,
                      unsigned int port, unsigned int enable)
 {
    struct grub_ohci *o = (struct grub_ohci *) dev->data;
+   grub_uint64_t endtime;
 
    grub_dprintf ("ohci", "begin of portstatus=0x%02x\n",
                  grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port));
 
+   if (!enable) /* We don't need reset port */
+     {
+       /* Disable the port and wait for it. */
+       grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
+                             GRUB_OHCI_CLEAR_PORT_ENABLE);
+       endtime = grub_get_time_ms () + 1000;
+       while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)
+               & (1 << 1)))
+         if (grub_get_time_ms () > endtime)
+           return grub_error (GRUB_ERR_IO, "OHCI Timed out - disable");
+
+       grub_dprintf ("ohci", "end of portstatus=0x%02x\n",
+         grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port));
+       return GRUB_ERR_NONE;
+     }
+     
+   /* Reset the port */
    grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
                         GRUB_OHCI_SET_PORT_RESET);
    grub_millisleep (50); /* For root hub should be nominaly 50ms */
@@ -1211,14 +1223,21 @@ grub_ohci_portstatus (grub_usb_controller_t dev,
                         GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE);
    grub_millisleep (10);
 
-   if (enable)
-     grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
-                          GRUB_OHCI_SET_PORT_ENABLE);
-   else
-     grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
-                          GRUB_OHCI_CLEAR_PORT_ENABLE);
+   /* Enable the port and wait for it. */
+   grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
+                         GRUB_OHCI_SET_PORT_ENABLE);
+   endtime = grub_get_time_ms () + 1000;
+   while (! (grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port)
+           & (1 << 1)))
+     if (grub_get_time_ms () > endtime)
+       return grub_error (GRUB_ERR_IO, "OHCI Timed out - enable");
+
    grub_millisleep (10);
 
+   /* Reset bit Connect Status Change */
+   grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
+                         GRUB_OHCI_RESET_CONNECT_CHANGE);
+
    grub_dprintf ("ohci", "end of portstatus=0x%02x\n",
                 grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port));
  
@@ -1226,7 +1245,7 @@ grub_ohci_portstatus (grub_usb_controller_t dev,
 }
 
 static grub_usb_speed_t
-grub_ohci_detect_dev (grub_usb_controller_t dev, int port)
+grub_ohci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
 {
    struct grub_ohci *o = (struct grub_ohci *) dev->data;
    grub_uint32_t status;
@@ -1235,6 +1254,9 @@ grub_ohci_detect_dev (grub_usb_controller_t dev, int port)
 
    grub_dprintf ("ohci", "detect_dev status=0x%02x\n", status);
 
+  /* Connect Status Change bit - it detects change of connection */
+  *changed = ((status & GRUB_OHCI_RESET_CONNECT_CHANGE) != 0);
+
    if (! (status & 1))
      return GRUB_USB_SPEED_NONE;
    else if (status & (1 << 9))
@@ -1253,7 +1275,6 @@ grub_ohci_hubports (grub_usb_controller_t dev)
 
   grub_dprintf ("ohci", "root hub ports=%d\n", portinfo & 0xFF);
 
-  /* The root hub has exactly two ports.  */
   return portinfo & 0xFF;
 }
 
index e85f07a6faf8c948b2cb8f2c9016ed5bc5a09360..efdf3aceb66fd278d2d54fe6377fde1378859960 100644 (file)
@@ -644,10 +644,14 @@ grub_uhci_portstatus (grub_usb_controller_t dev,
   grub_dprintf ("uhci", "waiting for the port to be enabled\n");
 
   endtime = grub_get_time_ms () + 1000;
-  while (! (grub_uhci_readreg16 (u, reg) & (1 << 2)))
+  while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2)))
     if (grub_get_time_ms () > endtime)
       return grub_error (GRUB_ERR_IO, "UHCI Timed out");
 
+  /* Reset bit Connect Status Change */
+  grub_uhci_writereg16 (u, reg, status | (1 << 1));
+
+  /* Read final port status */
   status = grub_uhci_readreg16 (u, reg);
   grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
 
@@ -656,7 +660,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev,
 }
 
 static grub_usb_speed_t
-grub_uhci_detect_dev (grub_usb_controller_t dev, int port)
+grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
 {
   struct grub_uhci *u = (struct grub_uhci *) dev->data;
   int reg;
@@ -676,6 +680,9 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port)
 
   grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port);
 
+  /* Connect Status Change bit - it detects change of connection */
+  *changed = ((status & (1 << 1)) != 0);
+    
   if (! (status & 1))
     return GRUB_USB_SPEED_NONE;
   else if (status & (1 << 8))
index 4f6f9e54ce0d6d544941765dbdacc350e34fc125..f6a0a8b569abb7a68e0b19d70386f54b15dbbcbe 100644 (file)
@@ -225,6 +225,20 @@ grub_usb_device_initialize (grub_usb_device_t dev)
        }
     }
 
+  return GRUB_USB_ERR_NONE;
+
+ fail:
+
+  for (i = 0; i < 8; i++)
+    grub_free (dev->config[i].descconf);
+
+  return err;
+}
+
+void grub_usb_device_attach (grub_usb_device_t dev)
+{
+  int i;
+  
   /* XXX: Just check configuration 0 for now.  */
   for (i = 0; i < dev->config[0].descconf->numif; i++)
     {
@@ -243,15 +257,6 @@ grub_usb_device_initialize (grub_usb_device_t dev)
        if (interf->class == desc->class && desc->hook (dev, 0, i))
          dev->config[0].interf[i].attached = 1;
     }
-
-  return GRUB_USB_ERR_NONE;
-
- fail:
-
-  for (i = 0; i < 8; i++)
-    grub_free (dev->config[i].descconf);
-
-  return err;
 }
 
 void
index f504180699448145678fd65dcea03eadba9ff7c6..6c14f4b8de6000273f3bedbea6c3628f90a0cf3d 100644 (file)
 #include <grub/misc.h>
 #include <grub/time.h>
 
+#define GRUB_USBHUB_MAX_DEVICES 128
+
 /* USB Supports 127 devices, with device 0 as special case.  */
-static struct grub_usb_device *grub_usb_devs[128];
+static struct grub_usb_device *grub_usb_devs[GRUB_USBHUB_MAX_DEVICES];
 
 struct grub_usb_hub
 {
@@ -44,6 +46,7 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed)
 {
   grub_usb_device_t dev;
   int i;
+  grub_usb_err_t err;
 
   dev = grub_zalloc (sizeof (struct grub_usb_device));
   if (! dev)
@@ -52,31 +55,51 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller, grub_usb_speed_t speed)
   dev->controller = *controller;
   dev->speed = speed;
 
-  grub_usb_device_initialize (dev);
+  err = grub_usb_device_initialize (dev);
+  if (err)
+    {
+      grub_free (dev);
+      return NULL;
+    }
 
   /* Assign a new address to the device.  */
-  for (i = 1; i < 128; i++)
+  for (i = 1; i < GRUB_USBHUB_MAX_DEVICES; i++)
     {
       if (! grub_usb_devs[i])
        break;
     }
-  if (i == 128)
+  if (i == GRUB_USBHUB_MAX_DEVICES)
     {
       grub_error (GRUB_ERR_IO, "can't assign address to USB device");
+      for (i = 0; i < 8; i++)
+        grub_free (dev->config[i].descconf);
+      grub_free (dev);
       return NULL;
     }
 
-  grub_usb_control_msg (dev,
-                       (GRUB_USB_REQTYPE_OUT
-                        | GRUB_USB_REQTYPE_STANDARD
-                        | GRUB_USB_REQTYPE_TARGET_DEV),
-                       GRUB_USB_REQ_SET_ADDRESS,
-                       i, 0, 0, NULL);
+  err = grub_usb_control_msg (dev,
+                             (GRUB_USB_REQTYPE_OUT
+                              | GRUB_USB_REQTYPE_STANDARD
+                              | GRUB_USB_REQTYPE_TARGET_DEV),
+                             GRUB_USB_REQ_SET_ADDRESS,
+                             i, 0, 0, NULL);
+  if (err)
+    {
+      for (i = 0; i < 8; i++)
+        grub_free (dev->config[i].descconf);
+      grub_free (dev);
+      return NULL;
+    }
 
   dev->addr = i;
   dev->initialized = 1;
   grub_usb_devs[i] = dev;
 
+  /* Wait "recovery interval", spec. says 2ms */
+  grub_millisleep (2);
+  
+  grub_usb_device_attach (dev);
+  
   return dev;
 }
 
@@ -144,7 +167,7 @@ grub_usb_add_hub (grub_usb_device_t dev)
       if (err)
        continue;
       grub_dprintf ("usb", "Hub port %d status: 0x%02x\n", i, status);
-           
+
       /* If connected, reset and enable the port.  */
       if (status & GRUB_USB_HUB_STATUS_CONNECTED)
        {
@@ -191,7 +214,22 @@ grub_usb_add_hub (grub_usb_device_t dev)
                  (grub_get_time_ms() < timeout) );
           if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) )
             continue;
+
+          /* Wait a recovery time after reset, spec. says 10ms */
+          grub_millisleep (10);
    
+          /* Do reset of connection change bit */
+          err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
+                                            | GRUB_USB_REQTYPE_CLASS
+                                            | GRUB_USB_REQTYPE_TARGET_OTHER),
+                                      GRUB_USB_REQ_CLEAR_FEATURE,
+                                     GRUB_USB_HUB_FEATURE_C_CONNECTED,
+                                     i, 0, 0);
+          /* Just ignore the device if the Hub reports some error */
+          if (err)
+            continue;
+          grub_dprintf ("usb", "Hub port - cleared connection change\n");
+
          /* Add the device and assign a device address to it.  */
           grub_dprintf ("usb", "Call hub_add_dev - port %d\n", i);
          next_dev = grub_usb_hub_add_dev (&dev->controller, speed);
@@ -239,6 +277,7 @@ grub_usb_root_hub (grub_usb_controller_t controller)
 {
   int i;
   struct grub_usb_hub *hub;
+  int changed=0;
 
   hub = grub_malloc (sizeof (*hub));
   if (!hub)
@@ -248,7 +287,10 @@ grub_usb_root_hub (grub_usb_controller_t controller)
   hubs = hub;
   hub->controller = grub_malloc (sizeof (*controller));
   if (!hub->controller)
-    return GRUB_USB_ERR_INTERNAL;
+    {
+      grub_free (hub);
+      return GRUB_USB_ERR_INTERNAL;
+    }
 
   grub_memcpy (hub->controller, controller, sizeof (*controller));
   hub->dev = 0;
@@ -258,13 +300,15 @@ grub_usb_root_hub (grub_usb_controller_t controller)
   hub->speed = grub_malloc (sizeof (hub->speed[0]) * hub->nports);
   if (!hub->speed)
     {
+      grub_free (hub->controller);
       grub_free (hub);
       return GRUB_USB_ERR_INTERNAL;
     }
 
   for (i = 0; i < hub->nports; i++)
     {
-      hub->speed[i] = controller->dev->detect_dev (hub->controller, i);
+      hub->speed[i] = controller->dev->detect_dev (hub->controller, i,
+                                                   &changed);
 
       if (hub->speed[i] != GRUB_USB_SPEED_NONE)
        attach_root_port (hub->controller, i, hub->speed[i]);
@@ -273,30 +317,157 @@ grub_usb_root_hub (grub_usb_controller_t controller)
   return GRUB_USB_ERR_NONE;
 }
 
+static void
+poll_nonroot_hub (grub_usb_device_t dev)
+{
+  struct grub_usb_usb_hubdesc hubdesc;
+  grub_err_t err;
+  int i;
+  grub_uint64_t timeout;
+  grub_usb_device_t next_dev;
+  
+  err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
+                                   | GRUB_USB_REQTYPE_CLASS
+                                   | GRUB_USB_REQTYPE_TARGET_DEV),
+                              GRUB_USB_REQ_GET_DESCRIPTOR,
+                             (GRUB_USB_DESCRIPTOR_HUB << 8) | 0,
+                             0, sizeof (hubdesc), (char *) &hubdesc);
+  if (err)
+    return;
+    
+  /* Iterate over the Hub ports.  */
+  for (i = 1; i <= hubdesc.portcnt; i++)
+    {
+      grub_uint32_t status;
+
+      /* Get the port status.  */
+      err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
+                                       | GRUB_USB_REQTYPE_CLASS
+                                       | GRUB_USB_REQTYPE_TARGET_OTHER),
+                                 GRUB_USB_REQ_GET_STATUS,
+                                 0, i, sizeof (status), (char *) &status);
+      /* Just ignore the device if the Hub does not report the
+        status.  */
+      if (err)
+       continue;
+           
+      /* Connected and status of connection changed ? */
+      if ((status & GRUB_USB_HUB_STATUS_CONNECTED)
+          && (status & GRUB_USB_HUB_STATUS_C_CONNECTED))
+       {
+         grub_usb_speed_t speed;
+
+         /* Determine the device speed.  */
+         if (status & GRUB_USB_HUB_STATUS_LOWSPEED)
+           speed = GRUB_USB_SPEED_LOW;
+         else
+           {
+             if (status & GRUB_USB_HUB_STATUS_HIGHSPEED)
+               speed = GRUB_USB_SPEED_HIGH;
+             else
+               speed = GRUB_USB_SPEED_FULL;
+           }
+
+         /* A device is actually connected to this port.
+          * Now do reset of port. */
+         err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
+                                           | GRUB_USB_REQTYPE_CLASS
+                                           | GRUB_USB_REQTYPE_TARGET_OTHER),
+                                     GRUB_USB_REQ_SET_FEATURE,
+                                     GRUB_USB_HUB_FEATURE_PORT_RESET,
+                                     i, 0, 0);
+         /* If the Hub does not cooperate for this port, just skip
+            the port.  */
+         if (err)
+           continue;
+
+          /* Wait for reset procedure done */
+          timeout = grub_get_time_ms () + 1000;
+          do
+            {
+              /* Get the port status.  */
+              err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
+                                               | GRUB_USB_REQTYPE_CLASS
+                                               | GRUB_USB_REQTYPE_TARGET_OTHER),
+                                         GRUB_USB_REQ_GET_STATUS,
+                                         0, i, sizeof (status), (char *) &status);
+            }
+          while (!err &&
+                 !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) &&
+                 (grub_get_time_ms() < timeout) );
+          if (err || !(status & GRUB_USB_HUB_STATUS_C_PORT_RESET) )
+            continue;
+
+          /* Wait a recovery time after reset, spec. says 10ms */
+          grub_millisleep (10);
+
+          /* Do reset of connection change bit */
+          err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
+                                            | GRUB_USB_REQTYPE_CLASS
+                                            | GRUB_USB_REQTYPE_TARGET_OTHER),
+                                      GRUB_USB_REQ_CLEAR_FEATURE,
+                                     GRUB_USB_HUB_FEATURE_C_CONNECTED,
+                                     i, 0, 0);
+          /* Just ignore the device if the Hub reports some error */
+          if (err)
+            continue;
+
+         /* Add the device and assign a device address to it.  */
+         next_dev = grub_usb_hub_add_dev (&dev->controller, speed);
+          if (! next_dev)
+            continue;
+
+          /* If the device is a Hub, scan it for more devices.  */
+          if (next_dev->descdev.class == 0x09)
+            grub_usb_add_hub (next_dev);
+       }
+    }
+
+  return;
+}
+
 void
 grub_usb_poll_devices (void)
 {
   struct grub_usb_hub *hub;
+  int i;
 
   for (hub = hubs; hub; hub = hub->next)
     {
-      int i;
+      int changed=0;
       /* Do we have to recheck number of ports?  */
+      /* No, it should be never changed, it should be constant. */
       for (i = 0; i < hub->nports; i++)
        {
          grub_usb_speed_t speed;
 
-         speed = hub->controller->dev->detect_dev (hub->controller, i);
+         speed = hub->controller->dev->detect_dev (hub->controller, i,
+                                                   &changed);
 
-         if (speed == hub->speed[i])
-           continue;
+         if (speed != GRUB_USB_SPEED_NONE)
+           {
+              if (changed)
+                attach_root_port (hub->controller, i, speed);
+           }
 
-         if (hub->speed[i] == GRUB_USB_SPEED_NONE
-             && speed != GRUB_USB_SPEED_NONE)
-           attach_root_port (hub->controller, i, speed);
+          /* XXX: There should be also handling
+           * of disconnected devices. */
+           
          hub->speed[i] = speed;
        }
     }
+
+  /* We should check changes of non-root hubs too. */
+  for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++)
+    {
+      grub_usb_device_t dev = grub_usb_devs[i];
+
+      if (dev && dev->descdev.class == 0x09)
+       {
+          poll_nonroot_hub (dev);
+       }
+    }
+
 }
 
 int
@@ -304,7 +475,7 @@ grub_usb_iterate (int (*hook) (grub_usb_device_t dev))
 {
   int i;
 
-  for (i = 0; i < 128; i++)
+  for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++)
     {
       if (grub_usb_devs[i])
        {
index 7c9dba12a6710bba1b823d2e5641617bc557678d..3c17318fc2595e1dac39f34f10eafe3a68ae4486 100644 (file)
@@ -104,7 +104,7 @@ struct grub_usb_controller_dev
   grub_err_t (*portstatus) (grub_usb_controller_t dev, unsigned int port,
                            unsigned int enable);
 
-  grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port);
+  grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed);
 
   /* The next host controller.  */
   struct grub_usb_controller_dev *next;
@@ -229,4 +229,6 @@ void grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc);
 
 void grub_usb_poll_devices (void);
 
+void grub_usb_device_attach (grub_usb_device_t dev);
+
 #endif /* GRUB_USB_H */
index 8f49c246f77ae67069a273ae5292d62426593b41..e68698c1de2f7bd40dc16872a8dbf1d3ab289e1e 100644 (file)
@@ -93,10 +93,12 @@ typedef struct grub_usb_transfer *grub_usb_transfer_t;
 
 #define GRUB_USB_HUB_FEATURE_PORT_RESET   0x04
 #define GRUB_USB_HUB_FEATURE_PORT_POWER   0x08
+#define GRUB_USB_HUB_FEATURE_C_CONNECTED  0x10
 
 #define GRUB_USB_HUB_STATUS_CONNECTED   (1 << 0)
 #define GRUB_USB_HUB_STATUS_LOWSPEED    (1 << 9)
 #define GRUB_USB_HUB_STATUS_HIGHSPEED   (1 << 10)
+#define GRUB_USB_HUB_STATUS_C_CONNECTED  (1 << 16)
 #define GRUB_USB_HUB_STATUS_C_PORT_RESET (1 << 20)
 
 struct grub_usb_packet_setup