USB hub support

This commit is contained in:
starous 2010-07-05 19:02:05 +02:00
parent e75056f162
commit 1a0742d4e2
2 changed files with 80 additions and 20 deletions

View file

@ -75,13 +75,46 @@ grub_usb_add_hub (grub_usb_device_t dev)
struct grub_usb_usb_hubdesc hubdesc; struct grub_usb_usb_hubdesc hubdesc;
grub_err_t err; grub_err_t err;
int i; int i;
grub_uint64_t timeout;
grub_usb_device_t next_dev;
grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
| GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_CLASS
| GRUB_USB_REQTYPE_TARGET_DEV), | GRUB_USB_REQTYPE_TARGET_DEV),
GRUB_USB_REQ_GET_DESCRIPTOR, GRUB_USB_REQ_GET_DESCRIPTOR,
(GRUB_USB_DESCRIPTOR_HUB << 8) | 0, (GRUB_USB_DESCRIPTOR_HUB << 8) | 0,
0, sizeof (hubdesc), (char *) &hubdesc); 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);
/* 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. */ /* Iterate over the Hub ports. */
for (i = 1; i <= hubdesc.portcnt; i++) for (i = 1; i <= hubdesc.portcnt; i++)
@ -92,13 +125,13 @@ grub_usb_add_hub (grub_usb_device_t dev)
err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
| GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_CLASS
| GRUB_USB_REQTYPE_TARGET_OTHER), | GRUB_USB_REQTYPE_TARGET_OTHER),
GRUB_USB_REQ_HUB_GET_PORT_STATUS, GRUB_USB_REQ_GET_STATUS,
0, i, sizeof (status), (char *) &status); 0, i, sizeof (status), (char *) &status);
/* Just ignore the device if the Hub does not report the /* Just ignore the device if the Hub does not report the
status. */ status. */
if (err) if (err)
continue; continue;
grub_dprintf ("usb", "Hub port %d status: 0x%02x\n", i, status);
/* If connected, reset and enable the port. */ /* If connected, reset and enable the port. */
if (status & GRUB_USB_HUB_STATUS_CONNECTED) if (status & GRUB_USB_HUB_STATUS_CONNECTED)
@ -116,21 +149,46 @@ grub_usb_add_hub (grub_usb_device_t dev)
speed = GRUB_USB_SPEED_FULL; speed = GRUB_USB_SPEED_FULL;
} }
/* A device is actually connected to this port, not enable /* A device is actually connected to this port.
the port. XXX: Why 0x03? According to some docs it * Now do reset of port. */
should be 0x0. Check the specification! */ grub_dprintf ("usb", "Reset hub port - port %d\n", i);
err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
| GRUB_USB_REQTYPE_CLASS | GRUB_USB_REQTYPE_CLASS
| GRUB_USB_REQTYPE_TARGET_OTHER), | 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 /* If the Hub does not cooperate for this port, just skip
the port. */ the port. */
if (err) if (err)
continue; 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. */ /* 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);
} }
} }

View file

@ -87,15 +87,17 @@ typedef struct grub_usb_transfer *grub_usb_transfer_t;
#define GRUB_USB_REQ_SET_INTERFACE 0x0B #define GRUB_USB_REQ_SET_INTERFACE 0x0B
#define GRUB_USB_REQ_SYNC_FRAME 0x0C #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_ENDP_HALT 0x00
#define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01 #define GRUB_USB_FEATURE_DEV_REMOTE_WU 0x01
#define GRUB_USB_FEATURE_TEST_MODE 0x02 #define GRUB_USB_FEATURE_TEST_MODE 0x02
#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_CONNECTED (1 << 0)
#define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9) #define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9)
#define GRUB_USB_HUB_STATUS_HIGHSPEED (1 << 10) #define GRUB_USB_HUB_STATUS_HIGHSPEED (1 << 10)
#define GRUB_USB_HUB_STATUS_C_PORT_RESET (1 << 20)
struct grub_usb_packet_setup struct grub_usb_packet_setup
{ {