2013-06-07 18:03:56 +00:00
|
|
|
|
From 16e60d9443ebe87df0cecac9a22df6e0440b805d Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: =?UTF-8?q?Ale=C5=A1=20Nesrsta?= <starous@volny.cz>
|
2013-05-02 20:54:52 +00:00
|
|
|
|
Date: Fri, 12 Apr 2013 20:42:46 +0200
|
2013-06-07 18:03:56 +00:00
|
|
|
|
Subject: [PATCH 292/471] Fix handling of split transfers.
|
2013-05-02 20:54:52 +00:00
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
ChangeLog | 4 ++++
|
|
|
|
|
grub-core/bus/usb/ehci.c | 25 ++++++++++-------------
|
|
|
|
|
grub-core/bus/usb/usbhub.c | 50 +++++++++++++++++++++++++++++++++++++++-------
|
|
|
|
|
include/grub/usb.h | 4 ++--
|
|
|
|
|
4 files changed, 59 insertions(+), 24 deletions(-)
|
|
|
|
|
|
|
|
|
|
diff --git a/ChangeLog b/ChangeLog
|
|
|
|
|
index 79563b8..e8e4569 100644
|
|
|
|
|
--- a/ChangeLog
|
|
|
|
|
+++ b/ChangeLog
|
|
|
|
|
@@ -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>
|
|
|
|
|
|
|
|
|
|
* grub-core/net/http.c: Fix bad free.
|
|
|
|
|
diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c
|
|
|
|
|
index e902fcd..18b12b2 100644
|
|
|
|
|
--- a/grub-core/bus/usb/ehci.c
|
|
|
|
|
+++ b/grub-core/bus/usb/ehci.c
|
|
|
|
|
@@ -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 */
|
|
|
|
|
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_CMD_AS_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,
|
|
|
|
|
* InterruptScheduleMask - AFAIK it should be zero in async. list */
|
|
|
|
|
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;
|
|
|
|
|
- ep_cap |= (transfer->dev->hubaddr << GRUB_EHCI_HUBADDR_OFF)
|
|
|
|
|
+ ep_cap |= (transfer->dev->split_hubaddr << GRUB_EHCI_HUBADDR_OFF)
|
|
|
|
|
& GRUB_EHCI_HUBADDR_MASK;
|
|
|
|
|
if (transfer->dev->speed == GRUB_USB_SPEED_LOW
|
|
|
|
|
&& 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 */
|
|
|
|
|
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. */
|
|
|
|
|
cdata = grub_malloc (sizeof (*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. */
|
|
|
|
|
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 */
|
|
|
|
|
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 */
|
|
|
|
|
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;
|
|
|
|
|
diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c
|
|
|
|
|
index 6fc9d02..e3b7d40 100644
|
|
|
|
|
--- a/grub-core/bus/usb/usbhub.c
|
|
|
|
|
+++ b/grub-core/bus/usb/usbhub.c
|
|
|
|
|
@@ -49,7 +49,7 @@ static grub_usb_controller_dev_t grub_usb_list;
|
|
|
|
|
static grub_usb_device_t
|
|
|
|
|
grub_usb_hub_add_dev (grub_usb_controller_t controller,
|
|
|
|
|
grub_usb_speed_t speed,
|
|
|
|
|
- int port, int hubaddr)
|
|
|
|
|
+ int split_hubport, int split_hubaddr)
|
|
|
|
|
{
|
|
|
|
|
grub_usb_device_t dev;
|
|
|
|
|
int i;
|
|
|
|
|
@@ -63,8 +63,8 @@ grub_usb_hub_add_dev (grub_usb_controller_t controller,
|
|
|
|
|
|
|
|
|
|
dev->controller = *controller;
|
|
|
|
|
dev->speed = speed;
|
|
|
|
|
- dev->port = port;
|
|
|
|
|
- dev->hubaddr = hubaddr;
|
|
|
|
|
+ dev->split_hubport = split_hubport;
|
|
|
|
|
+ dev->split_hubaddr = split_hubaddr;
|
|
|
|
|
|
|
|
|
|
err = grub_usb_device_initialize (dev);
|
|
|
|
|
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",
|
|
|
|
|
dev, i);
|
|
|
|
|
- grub_dprintf ("usb", "speed=%d, port=%d, hubaddr=%d\n",
|
|
|
|
|
- speed, port, hubaddr);
|
|
|
|
|
+ grub_dprintf ("usb", "speed=%d, split_hubport=%d, split_hubaddr=%d\n",
|
|
|
|
|
+ speed, split_hubport, split_hubaddr);
|
|
|
|
|
|
|
|
|
|
/* Wait "recovery interval", spec. says 2ms */
|
|
|
|
|
grub_millisleep (2);
|
|
|
|
|
@@ -219,7 +219,12 @@ attach_root_port (struct grub_usb_hub *hub, int portno,
|
|
|
|
|
grub_boot_time ("Port enabled");
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
npending--;
|
|
|
|
|
if (! dev)
|
|
|
|
|
@@ -593,6 +598,8 @@ poll_nonroot_hub (grub_usb_device_t dev)
|
|
|
|
|
{
|
|
|
|
|
grub_usb_speed_t speed;
|
|
|
|
|
grub_usb_device_t next_dev;
|
|
|
|
|
+ int split_hubport = 0;
|
|
|
|
|
+ int split_hubaddr = 0;
|
|
|
|
|
|
|
|
|
|
/* Determine the device speed. */
|
|
|
|
|
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 */
|
|
|
|
|
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. */
|
|
|
|
|
- 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)
|
|
|
|
|
{
|
|
|
|
|
dev->controller.dev->pending_reset = 0;
|
|
|
|
|
diff --git a/include/grub/usb.h b/include/grub/usb.h
|
|
|
|
|
index 9e2c221..1cc9942 100644
|
|
|
|
|
--- a/include/grub/usb.h
|
|
|
|
|
+++ b/include/grub/usb.h
|
|
|
|
|
@@ -225,9 +225,9 @@ struct grub_usb_device
|
|
|
|
|
struct grub_usb_desc_endp *hub_endpoint;
|
|
|
|
|
|
|
|
|
|
/* EHCI Split Transfer information */
|
|
|
|
|
- int port;
|
|
|
|
|
+ int split_hubport;
|
|
|
|
|
|
|
|
|
|
- int hubaddr;
|
|
|
|
|
+ int split_hubaddr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--
|
2013-06-07 18:03:56 +00:00
|
|
|
|
1.8.2.1
|
2013-05-02 20:54:52 +00:00
|
|
|
|
|