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)
+ if (status & GRUB_USB_HUB_STATUS_PORT_CONNECTED)
{
grub_usb_speed_t speed;
/* Determine the device speed. */
- if (status & GRUB_USB_HUB_STATUS_LOWSPEED)
+ if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED)
speed = GRUB_USB_SPEED_LOW;
else
{
- if (status & GRUB_USB_HUB_STATUS_HIGHSPEED)
+ if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED)
speed = GRUB_USB_SPEED_HIGH;
else
speed = GRUB_USB_SPEED_FULL;
| GRUB_USB_REQTYPE_CLASS
| GRUB_USB_REQTYPE_TARGET_OTHER),
GRUB_USB_REQ_CLEAR_FEATURE,
- GRUB_USB_HUB_FEATURE_C_CONNECTED,
+ GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED,
i, 0, 0);
/* Just ignore the device if the Hub reports some error */
if (err)
}
}
+ for (i = 0; i < dev->config[0].interf[0].descif->endpointcnt;
+ i++)
+ {
+ struct grub_usb_desc_endp *endp = NULL;
+ endp = &dev->config[0].interf[0].descendp[i];
+
+ if ((endp->endp_addr & 128) && grub_usb_get_ep_type(endp)
+ == GRUB_USB_EP_INTERRUPT)
+ {
+ dev->hub_endpoint = endp;
+ dev->hub_transfer
+ = grub_usb_bulk_read_background (dev, endp->endp_addr,
+ grub_min (endp->maxpacket,
+ sizeof (dev->statuschange)),
+ (char *) &dev->statuschange);
+ break;
+ }
+ }
+
return GRUB_ERR_NONE;
}
return;
if (dev->descdev.class == GRUB_USB_CLASS_HUB)
{
+ if (dev->hub_transfer)
+ grub_usb_cancel_transfer (dev->hub_transfer);
+
for (i = 0; i < dev->nports; i++)
detach_device (dev->children[i]);
grub_free (dev->children);
grub_uint64_t timeout;
grub_usb_device_t next_dev;
grub_usb_device_t *attached_devices = dev->children;
-
+ grub_uint8_t changed;
+ grub_size_t actual;
+
+ if (!dev->hub_transfer)
+ return;
+
+ err = grub_usb_check_transfer (dev->hub_transfer, &actual);
+
+ if (err == GRUB_USB_ERR_WAIT)
+ return;
+
+ changed = dev->statuschange;
+
+ dev->hub_transfer
+ = grub_usb_bulk_read_background (dev, dev->hub_endpoint->endp_addr,
+ grub_min (dev->hub_endpoint->maxpacket,
+ sizeof (dev->statuschange)),
+ (char *) &dev->statuschange);
+
+ if (err || actual == 0 || changed == 0)
+ return;
+
+ grub_dprintf ("usb", "statuschanged = %02x, err = %d, actual = %d\n",
+ changed, err, actual);
+
/* Iterate over the Hub ports. */
for (i = 1; i <= dev->nports; i++)
{
grub_uint32_t status;
+ if (!(changed & (1 << i)))
+ continue;
+
/* 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;
- if (status & GRUB_USB_HUB_STATUS_C_CONNECTED)
+ /* FIXME: properly handle these conditions. */
+ if (status & GRUB_USB_HUB_STATUS_C_PORT_RESET)
+ 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_PORT_RESET, i, 0, 0);
+
+ if (status & GRUB_USB_HUB_STATUS_C_PORT_ENABLED)
+ 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_PORT_ENABLED, i, 0, 0);
+
+ if (status & GRUB_USB_HUB_STATUS_C_PORT_SUSPEND)
+ 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_PORT_SUSPEND, i, 0, 0);
+
+ if (status & GRUB_USB_HUB_STATUS_C_PORT_OVERCURRENT)
+ 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_PORT_OVERCURRENT, i, 0, 0);
+
+ if (!(status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED))
+ continue;
+
+ 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_PORT_CONNECTED, i, 0, 0);
+
+ if (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED)
{
detach_device (attached_devices[i-1]);
attached_devices[i - 1] = NULL;
}
/* Connected and status of connection changed ? */
- if ((status & GRUB_USB_HUB_STATUS_CONNECTED)
- && (status & GRUB_USB_HUB_STATUS_C_CONNECTED))
+ if ((status & GRUB_USB_HUB_STATUS_PORT_CONNECTED)
+ && (status & GRUB_USB_HUB_STATUS_C_PORT_CONNECTED))
{
grub_usb_speed_t speed;
/* Determine the device speed. */
- if (status & GRUB_USB_HUB_STATUS_LOWSPEED)
+ if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED)
speed = GRUB_USB_SPEED_LOW;
else
{
- if (status & GRUB_USB_HUB_STATUS_HIGHSPEED)
+ if (status & GRUB_USB_HUB_STATUS_PORT_HIGHSPEED)
speed = GRUB_USB_SPEED_HIGH;
else
speed = GRUB_USB_SPEED_FULL;
| GRUB_USB_REQTYPE_CLASS
| GRUB_USB_REQTYPE_TARGET_OTHER),
GRUB_USB_REQ_CLEAR_FEATURE,
- GRUB_USB_HUB_FEATURE_C_CONNECTED,
+ GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED,
i, 0, 0);
/* Just ignore the device if the Hub reports some error */
if (err)
GRUB_USB_REQTYPE_VENDOR_IN = GRUB_USB_REQTYPE_VENDOR | GRUB_USB_REQTYPE_IN
};
-#define GRUB_USB_REQ_GET_STATUS 0x00
-#define GRUB_USB_REQ_CLEAR_FEATURE 0x01
-#define GRUB_USB_REQ_SET_FEATURE 0x03
-#define GRUB_USB_REQ_SET_ADDRESS 0x05
-#define GRUB_USB_REQ_GET_DESCRIPTOR 0x06
-#define GRUB_USB_REQ_SET_DESCRIPTOR 0x07
-#define GRUB_USB_REQ_GET_CONFIGURATION 0x08
-#define GRUB_USB_REQ_SET_CONFIGURATION 0x09
-#define GRUB_USB_REQ_GET_INTERFACE 0x0A
-#define GRUB_USB_REQ_SET_INTERFACE 0x0B
-#define GRUB_USB_REQ_SYNC_FRAME 0x0C
+enum
+ {
+ GRUB_USB_REQ_GET_STATUS = 0x00,
+ GRUB_USB_REQ_CLEAR_FEATURE = 0x01,
+ GRUB_USB_REQ_SET_FEATURE = 0x03,
+ GRUB_USB_REQ_SET_ADDRESS = 0x05,
+ GRUB_USB_REQ_GET_DESCRIPTOR = 0x06,
+ GRUB_USB_REQ_SET_DESCRIPTOR = 0x07,
+ GRUB_USB_REQ_GET_CONFIGURATION = 0x08,
+ GRUB_USB_REQ_SET_CONFIGURATION = 0x09,
+ GRUB_USB_REQ_GET_INTERFACE = 0x0A,
+ GRUB_USB_REQ_SET_INTERFACE = 0x0B,
+ GRUB_USB_REQ_SYNC_FRAME = 0x0C
+ };
#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_FEATURE_PORT_RESET 0x04
-#define GRUB_USB_HUB_FEATURE_PORT_POWER 0x08
-#define GRUB_USB_HUB_FEATURE_C_CONNECTED 0x10
+enum
+ {
+ GRUB_USB_HUB_FEATURE_PORT_RESET = 0x04,
+ GRUB_USB_HUB_FEATURE_PORT_POWER = 0x08,
+ GRUB_USB_HUB_FEATURE_C_PORT_CONNECTED = 0x10,
+ GRUB_USB_HUB_FEATURE_C_PORT_ENABLED = 0x11,
+ GRUB_USB_HUB_FEATURE_C_PORT_SUSPEND = 0x12,
+ GRUB_USB_HUB_FEATURE_C_PORT_OVERCURRENT = 0x13,
+ GRUB_USB_HUB_FEATURE_C_PORT_RESET = 0x14
+ };
-#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)
+enum
+ {
+ GRUB_USB_HUB_STATUS_PORT_CONNECTED = (1 << 0),
+ GRUB_USB_HUB_STATUS_PORT_ENABLED = (1 << 1),
+ GRUB_USB_HUB_STATUS_PORT_SUSPEND = (1 << 2),
+ GRUB_USB_HUB_STATUS_PORT_OVERCURRENT = (1 << 3),
+ GRUB_USB_HUB_STATUS_PORT_LOWSPEED = (1 << 9),
+ GRUB_USB_HUB_STATUS_PORT_HIGHSPEED = (1 << 10),
+ GRUB_USB_HUB_STATUS_C_PORT_CONNECTED = (1 << 16),
+ GRUB_USB_HUB_STATUS_C_PORT_ENABLED = (1 << 17),
+ GRUB_USB_HUB_STATUS_C_PORT_SUSPEND = (1 << 18),
+ GRUB_USB_HUB_STATUS_C_PORT_OVERCURRENT = (1 << 19),
+ GRUB_USB_HUB_STATUS_C_PORT_RESET = (1 << 20)
+ };
struct grub_usb_packet_setup
{