Hi, included patch should make USB hubs operational.
It works in the same simple way as whole GRUB2 USB support, i.e. USB hub and device must be connected to computer BEFORE uhci/ohci module is loaded. Note (mainly for Vladimir): Via hub are normally working also devices which I reported to be not functional on UHCI. So, from my point of view it looks like there is surely some problem in powering of UHCI root hubs on my computer. But I still don't know why only some devices are sensitive to this problem (all of them are not big consumers of power). Best regards Ales
diff -urB ./usb/bus/usb/usbhub.c ./usb_patched/bus/usb/usbhub.c --- ./usb/bus/usb/usbhub.c 2010-06-20 10:20:58.000000000 +0200 +++ ./usb_patched/bus/usb/usbhub.c 2010-06-18 22:34:56.000000000 +0200 @@ -87,14 +87,47 @@ 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 err; + grub_dprintf ("usb", "Hub descriptor:\n\t\t len:%d, typ:0x%02x, cnt:%d, char:0x%02x, pwg:%d, curr:%d\n", + hubdesc.length, hubdesc.type, hubdesc.portcnt, + hubdesc.characteristics, hubdesc.pwdgood, + hubdesc.current); + + /* Activate the first configuration. Hubs should have only one conf. */ + grub_dprintf ("usb", "Hub set configuration\n"); + grub_usb_set_configuration (dev, 1); - 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); - + /* Power on all Hub ports. */ + for (i = 1; i <= hubdesc.portcnt; i++) + { + grub_dprintf ("usb", "Power on - port %d\n", i); + /* Power on the port and wait for possible device connect */ + 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_POWER, + i, 0, NULL); + /* Just ignore the device if some error happened */ + if (err) + continue; + } + /* Wait for port power-on */ + if (hubdesc.pwdgood >= 50) + grub_millisleep (hubdesc.pwdgood * 2); + else + grub_millisleep (100); + /* Iterate over the Hub ports. */ for (i = 1; i <= hubdesc.portcnt; i++) { @@ -104,9 +137,8 @@ err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_TARGET_OTHER), - GRUB_USB_REQ_HUB_GET_PORT_STATUS, + 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) @@ -111,7 +143,8 @@ status. */ 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) { @@ -128,21 +161,46 @@ speed = GRUB_USB_SPEED_FULL; } - /* A device is actually connected to this port, not enable - the port. XXX: Why 0x03? According to some docs it - should be 0x0. Check the specification! */ + /* A device is actually connected to this port. + * Now do reset of port. */ + grub_dprintf ("usb", "Reset hub port - port %d\n", i); err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT | GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_TARGET_OTHER), - 0x3, 0x4, i, 0, 0); - + 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; + /* Add the device and assign a device address to it. */ - grub_usb_hub_add_dev (&dev->controller, speed); + grub_dprintf ("usb", "Call hub_add_dev - port %d\n", i); + 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); } } @@ -156,7 +214,7 @@ grub_usb_device_t dev; grub_err_t err; - /* Enable the port. */ + /* Disable the port. XXX: Why? */ err = controller->dev->portstatus (controller, portno, 0); if (err) return; diff -urB ./usb/include/grub/usbtrans.h ./usb_patched/include/grub/usbtrans.h --- ./usb/include/grub/usbtrans.h 2010-06-20 10:20:58.000000000 +0200 +++ ./usb_patched/include/grub/usbtrans.h 2010-06-20 10:27:13.000000000 +0200 @@ -87,15 +87,17 @@ #define GRUB_USB_REQ_SET_INTERFACE 0x0B #define GRUB_USB_REQ_SYNC_FRAME 0x0C -#define GRUB_USB_REQ_HUB_GET_PORT_STATUS 0x00 - #define GRUB_USB_FEATURE_ENDP_HALT 0x00 #define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 #define GRUB_USB_FEATURE_TEST_MODE 0x02 -#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_FEATURE_PORT_RESET 0x04 +#define GRUB_USB_HUB_FEATURE_PORT_POWER 0x08 + +#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_PORT_RESET (1 << 20) struct grub_usb_packet_setup {
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel