Faster OHCI, USB hub support, UHCI portstatus corr.

This commit is contained in:
starous 2010-06-21 21:12:20 +02:00
parent 7a4c893eb0
commit 12cd7239d9
7 changed files with 778 additions and 338 deletions

File diff suppressed because it is too large Load diff

View file

@ -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");

View file

@ -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;

View file

@ -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);

View file

@ -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. */

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
{ {