USB hub support
This commit is contained in:
parent
e75056f162
commit
1a0742d4e2
2 changed files with 80 additions and 20 deletions
|
@ -75,14 +75,47 @@ 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
|
/* Activate the first configuration. Hubs should have only one conf. */
|
||||||
| GRUB_USB_REQTYPE_CLASS
|
grub_dprintf ("usb", "Hub set configuration\n");
|
||||||
| GRUB_USB_REQTYPE_TARGET_DEV),
|
grub_usb_set_configuration (dev, 1);
|
||||||
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. */
|
/* Iterate over the Hub ports. */
|
||||||
for (i = 1; i <= hubdesc.portcnt; i++)
|
for (i = 1; i <= hubdesc.portcnt; i++)
|
||||||
{
|
{
|
||||||
|
@ -92,14 +125,14 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_STATUS_CONNECTED (1 << 0)
|
#define GRUB_USB_HUB_FEATURE_PORT_RESET 0x04
|
||||||
#define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9)
|
#define GRUB_USB_HUB_FEATURE_PORT_POWER 0x08
|
||||||
#define GRUB_USB_HUB_STATUS_HIGHSPEED (1 << 10)
|
|
||||||
|
#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
|
struct grub_usb_packet_setup
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue