Fix handling of split transfers.
This commit is contained in:
parent
92c8f58d97
commit
51a4c3e3b0
4 changed files with 59 additions and 24 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
2013-04-12 Aleš Nesrsta <starous@volny.cz>
|
||||||
|
|
||||||
|
Fix handling of split transfers.
|
||||||
|
|
||||||
2013-04-12 Vladimir Serbinenko <phcoder@gmail.com>
|
2013-04-12 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* grub-core/net/http.c: Fix bad free.
|
* grub-core/net/http.c: Fix bad free.
|
||||||
|
|
|
@ -798,7 +798,7 @@ grub_ehci_pci_iter (grub_pci_device_t dev, grub_pci_id_t pciid,
|
||||||
/* Set ownership of root hub ports to EHCI */
|
/* Set ownership of root hub ports to EHCI */
|
||||||
grub_ehci_oper_write32 (e, GRUB_EHCI_CONFIG_FLAG, GRUB_EHCI_CF_EHCI_OWNER);
|
grub_ehci_oper_write32 (e, GRUB_EHCI_CONFIG_FLAG, GRUB_EHCI_CF_EHCI_OWNER);
|
||||||
|
|
||||||
/* Enable asynchronous list */
|
/* Enable both lists */
|
||||||
grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
|
grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
|
||||||
GRUB_EHCI_CMD_AS_ENABL
|
GRUB_EHCI_CMD_AS_ENABL
|
||||||
| GRUB_EHCI_CMD_PS_ENABL
|
| GRUB_EHCI_CMD_PS_ENABL
|
||||||
|
@ -942,9 +942,9 @@ grub_ehci_setup_qh (grub_ehci_qh_t qh, grub_usb_transfer_t transfer)
|
||||||
* SplitCompletionMask - AFAIK it is ignored in asynchronous list,
|
* SplitCompletionMask - AFAIK it is ignored in asynchronous list,
|
||||||
* InterruptScheduleMask - AFAIK it should be zero in async. list */
|
* InterruptScheduleMask - AFAIK it should be zero in async. list */
|
||||||
ep_cap |= GRUB_EHCI_MULT_THREE;
|
ep_cap |= GRUB_EHCI_MULT_THREE;
|
||||||
ep_cap |= (transfer->dev->port << GRUB_EHCI_DEVPORT_OFF)
|
ep_cap |= (transfer->dev->split_hubport << GRUB_EHCI_DEVPORT_OFF)
|
||||||
& GRUB_EHCI_DEVPORT_MASK;
|
& GRUB_EHCI_DEVPORT_MASK;
|
||||||
ep_cap |= (transfer->dev->hubaddr << GRUB_EHCI_HUBADDR_OFF)
|
ep_cap |= (transfer->dev->split_hubaddr << GRUB_EHCI_HUBADDR_OFF)
|
||||||
& GRUB_EHCI_HUBADDR_MASK;
|
& GRUB_EHCI_HUBADDR_MASK;
|
||||||
if (transfer->dev->speed == GRUB_USB_SPEED_LOW
|
if (transfer->dev->speed == GRUB_USB_SPEED_LOW
|
||||||
&& transfer->type != GRUB_USB_TRANSACTION_TYPE_CONTROL)
|
&& transfer->type != GRUB_USB_TRANSACTION_TYPE_CONTROL)
|
||||||
|
@ -1261,16 +1261,6 @@ grub_ehci_setup_transfer (grub_usb_controller_t dev,
|
||||||
/* XXX: Fix it: Currently we don't do anything to restart EHCI */
|
/* XXX: Fix it: Currently we don't do anything to restart EHCI */
|
||||||
return GRUB_USB_ERR_INTERNAL;
|
return GRUB_USB_ERR_INTERNAL;
|
||||||
|
|
||||||
/* Check if transfer is not high speed and connected to root hub.
|
|
||||||
* It should not happened but... */
|
|
||||||
if ((transfer->dev->speed != GRUB_USB_SPEED_HIGH)
|
|
||||||
&& !transfer->dev->hubaddr)
|
|
||||||
{
|
|
||||||
grub_error (GRUB_USB_ERR_BADDEVICE,
|
|
||||||
"FULL/LOW speed device on EHCI port!?!");
|
|
||||||
return GRUB_USB_ERR_BADDEVICE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate memory for controller transfer data. */
|
/* Allocate memory for controller transfer data. */
|
||||||
cdata = grub_malloc (sizeof (*cdata));
|
cdata = grub_malloc (sizeof (*cdata));
|
||||||
if (!cdata)
|
if (!cdata)
|
||||||
|
@ -1887,13 +1877,18 @@ grub_ehci_fini_hw (int noreturn __attribute__ ((unused)))
|
||||||
/* We should disable all EHCI HW to prevent any DMA access etc. */
|
/* We should disable all EHCI HW to prevent any DMA access etc. */
|
||||||
for (e = ehci; e; e = e->next)
|
for (e = ehci; e; e = e->next)
|
||||||
{
|
{
|
||||||
|
/* Disable both lists */
|
||||||
|
grub_ehci_oper_write32 (e, GRUB_EHCI_COMMAND,
|
||||||
|
~(GRUB_EHCI_CMD_AS_ENABL | GRUB_EHCI_CMD_PS_ENABL)
|
||||||
|
& grub_ehci_oper_read32 (e, GRUB_EHCI_COMMAND));
|
||||||
|
|
||||||
/* Check if EHCI is halted and halt it if not */
|
/* Check if EHCI is halted and halt it if not */
|
||||||
if (grub_ehci_halt (e) != GRUB_USB_ERR_NONE)
|
if (grub_ehci_halt (e) != GRUB_USB_ERR_NONE)
|
||||||
grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI halt timeout");
|
grub_error (GRUB_ERR_TIMEOUT, "fini_hw: EHCI halt timeout");
|
||||||
|
|
||||||
/* Reset EHCI */
|
/* Reset EHCI */
|
||||||
if (grub_ehci_reset (e) != GRUB_USB_ERR_NONE)
|
if (grub_ehci_reset (e) != GRUB_USB_ERR_NONE)
|
||||||
grub_error (GRUB_ERR_TIMEOUT, "restore_hw: EHCI reset timeout");
|
grub_error (GRUB_ERR_TIMEOUT, "fini_hw: EHCI reset timeout");
|
||||||
}
|
}
|
||||||
|
|
||||||
return GRUB_USB_ERR_NONE;
|
return GRUB_USB_ERR_NONE;
|
||||||
|
|
|
@ -49,7 +49,7 @@ static grub_usb_controller_dev_t grub_usb_list;
|
||||||
static grub_usb_device_t
|
static grub_usb_device_t
|
||||||
grub_usb_hub_add_dev (grub_usb_controller_t controller,
|
grub_usb_hub_add_dev (grub_usb_controller_t controller,
|
||||||
grub_usb_speed_t speed,
|
grub_usb_speed_t speed,
|
||||||
int port, int hubaddr)
|
int split_hubport, int split_hubaddr)
|
||||||
{
|
{
|
||||||
grub_usb_device_t dev;
|
grub_usb_device_t dev;
|
||||||
int i;
|
int i;
|
||||||
|
@ -63,8 +63,8 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller,
|
||||||
|
|
||||||
dev->controller = *controller;
|
dev->controller = *controller;
|
||||||
dev->speed = speed;
|
dev->speed = speed;
|
||||||
dev->port = port;
|
dev->split_hubport = split_hubport;
|
||||||
dev->hubaddr = hubaddr;
|
dev->split_hubaddr = split_hubaddr;
|
||||||
|
|
||||||
err = grub_usb_device_initialize (dev);
|
err = grub_usb_device_initialize (dev);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -108,8 +108,8 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller,
|
||||||
|
|
||||||
grub_dprintf ("usb", "Added new usb device: %p, addr=%d\n",
|
grub_dprintf ("usb", "Added new usb device: %p, addr=%d\n",
|
||||||
dev, i);
|
dev, i);
|
||||||
grub_dprintf ("usb", "speed=%d, port=%d, hubaddr=%d\n",
|
grub_dprintf ("usb", "speed=%d, split_hubport=%d, split_hubaddr=%d\n",
|
||||||
speed, port, hubaddr);
|
speed, split_hubport, split_hubaddr);
|
||||||
|
|
||||||
/* Wait "recovery interval", spec. says 2ms */
|
/* Wait "recovery interval", spec. says 2ms */
|
||||||
grub_millisleep (2);
|
grub_millisleep (2);
|
||||||
|
@ -219,7 +219,12 @@ attach_root_port (struct grub_usb_hub *hub, int portno,
|
||||||
grub_boot_time ("Port enabled");
|
grub_boot_time ("Port enabled");
|
||||||
|
|
||||||
/* Enable the port and create a device. */
|
/* Enable the port and create a device. */
|
||||||
dev = grub_usb_hub_add_dev (hub->controller, speed, portno, 0);
|
/* High speed device needs not transaction translation
|
||||||
|
and full/low speed device cannot be connected to EHCI root hub
|
||||||
|
and full/low speed device connected to OHCI/UHCI needs not
|
||||||
|
transaction translation - e.g. hubport and hubaddr should be
|
||||||
|
always none (zero) for any device connected to any root hub. */
|
||||||
|
dev = grub_usb_hub_add_dev (hub->controller, speed, 0, 0);
|
||||||
hub->controller->dev->pending_reset = 0;
|
hub->controller->dev->pending_reset = 0;
|
||||||
npending--;
|
npending--;
|
||||||
if (! dev)
|
if (! dev)
|
||||||
|
@ -593,6 +598,8 @@ poll_nonroot_hub (grub_usb_device_t dev)
|
||||||
{
|
{
|
||||||
grub_usb_speed_t speed;
|
grub_usb_speed_t speed;
|
||||||
grub_usb_device_t next_dev;
|
grub_usb_device_t next_dev;
|
||||||
|
int split_hubport = 0;
|
||||||
|
int split_hubaddr = 0;
|
||||||
|
|
||||||
/* Determine the device speed. */
|
/* Determine the device speed. */
|
||||||
if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED)
|
if (status & GRUB_USB_HUB_STATUS_PORT_LOWSPEED)
|
||||||
|
@ -608,8 +615,37 @@ poll_nonroot_hub (grub_usb_device_t dev)
|
||||||
/* Wait a recovery time after reset, spec. says 10ms */
|
/* Wait a recovery time after reset, spec. says 10ms */
|
||||||
grub_millisleep (10);
|
grub_millisleep (10);
|
||||||
|
|
||||||
|
/* Find correct values for SPLIT hubport and hubaddr */
|
||||||
|
if (speed == GRUB_USB_SPEED_HIGH)
|
||||||
|
{
|
||||||
|
/* HIGH speed device needs not transaction translation */
|
||||||
|
split_hubport = 0;
|
||||||
|
split_hubaddr = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* FULL/LOW device needs hub port and hub address
|
||||||
|
for transaction translation (if connected to EHCI) */
|
||||||
|
if (dev->speed == GRUB_USB_SPEED_HIGH)
|
||||||
|
{
|
||||||
|
/* This port is the first FULL/LOW speed port
|
||||||
|
in the chain from root hub. Attached device
|
||||||
|
should use its port number and hub address */
|
||||||
|
split_hubport = i;
|
||||||
|
split_hubaddr = dev->addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This port is NOT the first FULL/LOW speed port
|
||||||
|
in the chain from root hub. Attached device
|
||||||
|
should use values inherited from some parent
|
||||||
|
HIGH speed hub - if any. */
|
||||||
|
split_hubport = dev->split_hubport;
|
||||||
|
split_hubaddr = dev->split_hubaddr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add the device and assign a device address to it. */
|
/* Add the device and assign a device address to it. */
|
||||||
next_dev = grub_usb_hub_add_dev (&dev->controller, speed, i, dev->addr);
|
next_dev = grub_usb_hub_add_dev (&dev->controller, speed,
|
||||||
|
split_hubport, split_hubaddr);
|
||||||
if (dev->controller.dev->pending_reset)
|
if (dev->controller.dev->pending_reset)
|
||||||
{
|
{
|
||||||
dev->controller.dev->pending_reset = 0;
|
dev->controller.dev->pending_reset = 0;
|
||||||
|
|
|
@ -225,9 +225,9 @@ struct grub_usb_device
|
||||||
struct grub_usb_desc_endp *hub_endpoint;
|
struct grub_usb_desc_endp *hub_endpoint;
|
||||||
|
|
||||||
/* EHCI Split Transfer information */
|
/* EHCI Split Transfer information */
|
||||||
int port;
|
int split_hubport;
|
||||||
|
|
||||||
int hubaddr;
|
int split_hubaddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue