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);
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. */
grub_uhci_writereg16 (u, reg, enable << 9);
grub_uhci_writereg16 (u, reg, 1 << 9);
/* Wait for the reset to complete. XXX: How long exactly? */
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);
/* Enable the port. */
grub_uhci_writereg16 (u, reg, enable << 2);
grub_uhci_writereg16 (u, reg, 1 << 2);
grub_millisleep (10);
grub_dprintf ("uhci", "waiting for the port to be enabled\n");

View file

@ -166,7 +166,7 @@ grub_usb_device_initialize (grub_usb_device_t dev)
* max. size of packet */
dev->descdev.maxsize0 = 0; /* invalidating, for safety only, can be removed if it is sure it is zero here */
err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE,
0, 8, (char *) &dev->descdev);
0, 8, (char *) &dev->descdev);
if (err)
return err;

View file

@ -87,14 +87,47 @@ grub_usb_add_hub (grub_usb_device_t dev)
struct grub_usb_usb_hubdesc hubdesc;
grub_err_t err;
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
| 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);
/* 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. */
for (i = 1; i <= hubdesc.portcnt; i++)
{
@ -104,14 +137,14 @@ grub_usb_add_hub (grub_usb_device_t dev)
err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
| GRUB_USB_REQTYPE_CLASS
| GRUB_USB_REQTYPE_TARGET_OTHER),
GRUB_USB_REQ_HUB_GET_PORT_STATUS,
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;
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)
{
@ -128,21 +161,46 @@ grub_usb_add_hub (grub_usb_device_t dev)
speed = GRUB_USB_SPEED_FULL;
}
/* A device is actually connected to this port, not enable
the port. XXX: Why 0x03? According to some docs it
should be 0x0. Check the specification! */
/* A device is actually connected to this port.
* Now do reset of port. */
grub_dprintf ("usb", "Reset hub port - port %d\n", i);
err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
| GRUB_USB_REQTYPE_CLASS
| 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
the port. */
if (err)
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. */
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_err_t err;
/* Enable the port. */
/* Disable the port. XXX: Why? */
err = controller->dev->portstatus (controller, portno, 0);
if (err)
return;

View file

@ -81,7 +81,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
else
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;
@ -146,6 +146,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
transfer->transactions[datablocks + 1].toggle = 1;
err = dev->controller.dev->transfer (&dev->controller, transfer);
grub_dprintf ("usb", "control: err=%d\n", err);
grub_free (transfer->transactions);
@ -174,6 +175,8 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
struct grub_pci_dma_chunk *data_chunk;
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. */
data_chunk = grub_memalign_dma32 (128, size);
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;
else
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;
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 errCSW = GRUB_USB_ERR_NONE;
int retrycnt = 3 + 1;
grub_size_t i;
retry:
retrycnt--;
@ -293,30 +292,27 @@ grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
goto CheckCSW;
}
/* Debug print of received data. */
grub_dprintf ("usb", "buf:\n");
if (size <= 64)
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");
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",
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]);
}
else if (size)
{
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", "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 == GRUB_USB_ERR_STALL)
grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
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. */

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_SYNC_FRAME 0x0C
#define GRUB_USB_REQ_HUB_GET_PORT_STATUS 0x00
#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_STATUS_CONNECTED (1 << 0)
#define GRUB_USB_HUB_STATUS_LOWSPEED (1 << 9)
#define GRUB_USB_HUB_STATUS_HIGHSPEED (1 << 10)
#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_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
{