diff --git a/bus/usb/usb.c b/bus/usb/usb.c index 79a79e644..9a78f2c4a 100644 --- a/bus/usb/usb.c +++ b/bus/usb/usb.c @@ -24,6 +24,7 @@ #include static grub_usb_controller_dev_t grub_usb_list; +struct grub_usb_attach_desc *attach_hooks; void grub_usb_controller_dev_register (grub_usb_controller_dev_t usb) @@ -224,6 +225,25 @@ grub_usb_device_initialize (grub_usb_device_t dev) } } + /* XXX: Just check configuration 0 for now. */ + for (i = 0; i < dev->config[0].descconf->numif; i++) + { + struct grub_usb_desc_if *interf; + struct grub_usb_attach_desc *desc; + + interf = dev->config[0].interf[i].descif; + + grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n", + i, interf->class, interf->subclass, interf->protocol); + + if (dev->config[0].interf[i].attached) + continue; + + for (desc = attach_hooks; desc; desc = desc->next) + if (interf->class == desc->class && desc->hook (dev, 0, i)) + dev->config[0].interf[i].attached = 1; + } + return GRUB_USB_ERR_NONE; fail: @@ -234,8 +254,6 @@ grub_usb_device_initialize (grub_usb_device_t dev) return err; } -struct grub_usb_attach_desc *attach_hooks; - void grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc) { diff --git a/bus/usb/usbhub.c b/bus/usb/usbhub.c index 523abf93e..48e3ce592 100644 --- a/bus/usb/usbhub.c +++ b/bus/usb/usbhub.c @@ -21,10 +21,22 @@ #include #include #include +#include /* USB Supports 127 devices, with device 0 as special case. */ static struct grub_usb_device *grub_usb_devs[128]; +struct grub_usb_hub +{ + struct grub_usb_hub *next; + grub_usb_controller_t controller; + int nports; + grub_usb_speed_t *speed; + grub_usb_device_t dev; +}; + +struct grub_usb_hub *hubs; + /* Add a device that currently has device number 0 and resides on CONTROLLER, the Hub reported that the device speed is SPEED. */ static grub_usb_device_t @@ -137,43 +149,98 @@ grub_usb_add_hub (grub_usb_device_t dev) return GRUB_ERR_NONE; } +static void +attach_root_port (grub_usb_controller_t controller, int portno, + grub_usb_speed_t speed) +{ + grub_usb_device_t dev; + grub_err_t err; + + /* Enable the port. */ + err = controller->dev->portstatus (controller, portno, 0); + if (err) + return; + + /* Enable the port. */ + err = controller->dev->portstatus (controller, portno, 1); + if (err) + return; + + /* Enable the port and create a device. */ + dev = grub_usb_hub_add_dev (controller, speed); + if (! dev) + return; + + /* If the device is a Hub, scan it for more devices. */ + if (dev->descdev.class == 0x09) + grub_usb_add_hub (dev); +} + grub_usb_err_t grub_usb_root_hub (grub_usb_controller_t controller) { - grub_err_t err; - int ports; int i; + struct grub_usb_hub *hub; + + hub = grub_malloc (sizeof (*hub)); + if (!hub) + return GRUB_USB_ERR_INTERNAL; + + hub->next = hubs; + hubs = hub; + hub->controller = grub_malloc (sizeof (*controller)); + if (!hub->controller) + return GRUB_USB_ERR_INTERNAL; + + grub_memcpy (hub->controller, controller, sizeof (*controller)); + hub->dev = 0; /* Query the number of ports the root Hub has. */ - ports = controller->dev->hubports (controller); - - for (i = 0; i < ports; i++) + hub->nports = controller->dev->hubports (controller); + hub->speed = grub_malloc (sizeof (hub->speed[0]) * hub->nports); + if (!hub->speed) { - grub_usb_speed_t speed = controller->dev->detect_dev (controller, i); + grub_free (hub); + return GRUB_USB_ERR_INTERNAL; + } - if (speed != GRUB_USB_SPEED_NONE) - { - grub_usb_device_t dev; + for (i = 0; i < hub->nports; i++) + { + hub->speed[i] = controller->dev->detect_dev (hub->controller, i); - /* Enable the port. */ - err = controller->dev->portstatus (controller, i, 1); - if (err) - continue; - - /* Enable the port and create a device. */ - dev = grub_usb_hub_add_dev (controller, speed); - if (! dev) - continue; - - /* If the device is a Hub, scan it for more devices. */ - if (dev->descdev.class == 0x09) - grub_usb_add_hub (dev); - } + if (hub->speed[i] != GRUB_USB_SPEED_NONE) + attach_root_port (hub->controller, i, hub->speed[i]); } return GRUB_USB_ERR_NONE; } +void +grub_usb_poll_devices (void) +{ + struct grub_usb_hub *hub; + + for (hub = hubs; hub; hub = hub->next) + { + int i; + /* Do we have to recheck number of ports? */ + for (i = 0; i < hub->nports; i++) + { + grub_usb_speed_t speed; + + speed = hub->controller->dev->detect_dev (hub->controller, i); + + if (speed == hub->speed[i]) + continue; + + if (hub->speed[i] == GRUB_USB_SPEED_NONE + && speed != GRUB_USB_SPEED_NONE) + attach_root_port (hub->controller, i, speed); + hub->speed[i] = speed; + } + } +} + int grub_usb_iterate (int (*hook) (grub_usb_device_t dev)) { diff --git a/disk/usbms.c b/disk/usbms.c index 84597aa01..5550ff770 100644 --- a/disk/usbms.c +++ b/disk/usbms.c @@ -209,6 +209,8 @@ grub_usbms_iterate (int (*hook) (const char *name, int luns)) { unsigned i; + grub_usb_poll_devices (); + for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++) if (grub_usbms_devices[i]) { @@ -389,6 +391,9 @@ grub_usbms_open (const char *name, struct grub_scsi *scsi) "not a USB Mass Storage device"); devnum = grub_strtoul (name + 3, NULL, 10); + + grub_usb_poll_devices (); + if (!grub_usbms_devices[devnum]) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a USB Mass Storage device"); diff --git a/include/grub/usb.h b/include/grub/usb.h index 239905623..7c9dba12a 100644 --- a/include/grub/usb.h +++ b/include/grub/usb.h @@ -227,4 +227,6 @@ struct grub_usb_attach_desc void grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc); void grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc); +void grub_usb_poll_devices (void); + #endif /* GRUB_USB_H */