Faster OHCI, USB hub support, UHCI portstatus corr.
This commit is contained in:
parent
7a4c893eb0
commit
12cd7239d9
7 changed files with 778 additions and 338 deletions
920
bus/usb/ohci.c
920
bus/usb/ohci.c
File diff suppressed because it is too large
Load diff
|
@ -612,8 +612,23 @@ grub_uhci_portstatus (grub_usb_controller_t dev,
|
||||||
status = grub_uhci_readreg16 (u, reg);
|
status = grub_uhci_readreg16 (u, reg);
|
||||||
grub_dprintf ("uhci", "detect=0x%02x\n", status);
|
grub_dprintf ("uhci", "detect=0x%02x\n", status);
|
||||||
|
|
||||||
|
if (!enable) /* We don't need reset port */
|
||||||
|
{
|
||||||
|
/* Disable the port. */
|
||||||
|
grub_uhci_writereg16 (u, reg, 0 << 2);
|
||||||
|
grub_dprintf ("uhci", "waiting for the port to be disabled\n");
|
||||||
|
endtime = grub_get_time_ms () + 1000;
|
||||||
|
while ((grub_uhci_readreg16 (u, reg) & (1 << 2)))
|
||||||
|
if (grub_get_time_ms () > endtime)
|
||||||
|
return grub_error (GRUB_ERR_IO, "UHCI Timed out");
|
||||||
|
|
||||||
|
status = grub_uhci_readreg16 (u, reg);
|
||||||
|
grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Reset the port. */
|
/* Reset the port. */
|
||||||
grub_uhci_writereg16 (u, reg, enable << 9);
|
grub_uhci_writereg16 (u, reg, 1 << 9);
|
||||||
|
|
||||||
/* Wait for the reset to complete. XXX: How long exactly? */
|
/* Wait for the reset to complete. XXX: How long exactly? */
|
||||||
grub_millisleep (50); /* For root hub should be nominaly 50ms */
|
grub_millisleep (50); /* For root hub should be nominaly 50ms */
|
||||||
|
@ -623,7 +638,7 @@ grub_uhci_portstatus (grub_usb_controller_t dev,
|
||||||
grub_millisleep (10);
|
grub_millisleep (10);
|
||||||
|
|
||||||
/* Enable the port. */
|
/* Enable the port. */
|
||||||
grub_uhci_writereg16 (u, reg, enable << 2);
|
grub_uhci_writereg16 (u, reg, 1 << 2);
|
||||||
grub_millisleep (10);
|
grub_millisleep (10);
|
||||||
|
|
||||||
grub_dprintf ("uhci", "waiting for the port to be enabled\n");
|
grub_dprintf ("uhci", "waiting for the port to be enabled\n");
|
||||||
|
|
|
@ -87,13 +87,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++)
|
||||||
|
@ -104,13 +137,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)
|
||||||
|
@ -128,21 +161,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +214,7 @@ attach_root_port (grub_usb_controller_t controller, int portno,
|
||||||
grub_usb_device_t dev;
|
grub_usb_device_t dev;
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
|
|
||||||
/* Enable the port. */
|
/* Disable the port. XXX: Why? */
|
||||||
err = controller->dev->portstatus (controller, portno, 0);
|
err = controller->dev->portstatus (controller, portno, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -81,7 +81,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
||||||
else
|
else
|
||||||
max = 64;
|
max = 64;
|
||||||
|
|
||||||
grub_dprintf ("usb", "transfer = %p, dev = %p\n", transfer, dev);
|
grub_dprintf ("usb", "control: transfer = %p, dev = %p\n", transfer, dev);
|
||||||
|
|
||||||
datablocks = (size + max - 1) / max;
|
datablocks = (size + max - 1) / max;
|
||||||
|
|
||||||
|
@ -146,6 +146,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
|
||||||
transfer->transactions[datablocks + 1].toggle = 1;
|
transfer->transactions[datablocks + 1].toggle = 1;
|
||||||
|
|
||||||
err = dev->controller.dev->transfer (&dev->controller, transfer);
|
err = dev->controller.dev->transfer (&dev->controller, transfer);
|
||||||
|
grub_dprintf ("usb", "control: err=%d\n", err);
|
||||||
|
|
||||||
grub_free (transfer->transactions);
|
grub_free (transfer->transactions);
|
||||||
|
|
||||||
|
@ -174,6 +175,8 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
|
||||||
struct grub_pci_dma_chunk *data_chunk;
|
struct grub_pci_dma_chunk *data_chunk;
|
||||||
grub_size_t size = size0;
|
grub_size_t size = size0;
|
||||||
|
|
||||||
|
grub_dprintf ("usb", "bulk: size=0x%02x type=%d\n", size, type);
|
||||||
|
|
||||||
/* FIXME: avoid allocation any kind of buffer in a first place. */
|
/* FIXME: avoid allocation any kind of buffer in a first place. */
|
||||||
data_chunk = grub_memalign_dma32 (128, size);
|
data_chunk = grub_memalign_dma32 (128, size);
|
||||||
if (!data_chunk)
|
if (!data_chunk)
|
||||||
|
@ -248,7 +251,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
|
||||||
toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1;
|
toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1;
|
||||||
else
|
else
|
||||||
toggle = dev->toggle[endpoint]; /* Nothing done, take original */
|
toggle = dev->toggle[endpoint]; /* Nothing done, take original */
|
||||||
grub_dprintf ("usb", "toggle=%d\n", toggle);
|
grub_dprintf ("usb", "bulk: err=%d, toggle=%d\n", err, toggle);
|
||||||
dev->toggle[endpoint] = toggle;
|
dev->toggle[endpoint] = toggle;
|
||||||
|
|
||||||
grub_free (transfer->transactions);
|
grub_free (transfer->transactions);
|
||||||
|
|
24
disk/usbms.c
24
disk/usbms.c
|
@ -239,7 +239,6 @@ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
|
||||||
grub_usb_err_t err = GRUB_USB_ERR_NONE;
|
grub_usb_err_t err = GRUB_USB_ERR_NONE;
|
||||||
grub_usb_err_t errCSW = GRUB_USB_ERR_NONE;
|
grub_usb_err_t errCSW = GRUB_USB_ERR_NONE;
|
||||||
int retrycnt = 3 + 1;
|
int retrycnt = 3 + 1;
|
||||||
grub_size_t i;
|
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
retrycnt--;
|
retrycnt--;
|
||||||
|
@ -293,30 +292,27 @@ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
|
||||||
goto CheckCSW;
|
goto CheckCSW;
|
||||||
}
|
}
|
||||||
/* Debug print of received data. */
|
/* Debug print of received data. */
|
||||||
grub_dprintf ("usb", "buf:\n");
|
grub_dprintf ("usb", "First 16 bytes of received data:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||||
if (size <= 64)
|
buf[ 0], buf[ 1], buf[ 2], buf[ 3],
|
||||||
for (i=0; i<size; i++)
|
buf[ 4], buf[ 5], buf[ 6], buf[ 7],
|
||||||
grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
|
buf[ 8], buf[ 9], buf[10], buf[11],
|
||||||
else
|
buf[12], buf[13], buf[14], buf[15]);
|
||||||
grub_dprintf ("usb", "Too much data for debug print...\n");
|
|
||||||
}
|
}
|
||||||
else if (size)
|
else if (size)
|
||||||
{
|
{
|
||||||
err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr, size, buf);
|
err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr, size, buf);
|
||||||
grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL);
|
grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL);
|
||||||
grub_dprintf ("usb", "buf:\n");
|
grub_dprintf ("usb", "First 16 bytes of sent data:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||||
|
buf[ 0], buf[ 1], buf[ 2], buf[ 3],
|
||||||
|
buf[ 4], buf[ 5], buf[ 6], buf[ 7],
|
||||||
|
buf[ 8], buf[ 9], buf[10], buf[11],
|
||||||
|
buf[12], buf[13], buf[14], buf[15]);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (err == GRUB_USB_ERR_STALL)
|
if (err == GRUB_USB_ERR_STALL)
|
||||||
grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
|
grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
|
||||||
goto CheckCSW;
|
goto CheckCSW;
|
||||||
}
|
}
|
||||||
/* Debug print of sent data. */
|
|
||||||
if (size <= 256)
|
|
||||||
for (i=0; i<size; i++)
|
|
||||||
grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
|
|
||||||
else
|
|
||||||
grub_dprintf ("usb", "Too much data for debug print...\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the status - (maybe) according to specification. */
|
/* Read the status - (maybe) according to specification. */
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue