Fix a bunch of problems with USB.

This commit is contained in:
Aleš Nesrsta 2010-05-31 14:11:41 +02:00 committed by Vladimir 'phcoder' Serbinenko
parent 7fd08f56ae
commit 778ff32476
10 changed files with 637 additions and 167 deletions

View file

@ -27,6 +27,7 @@
#include <grub/cpu/io.h>
#include <grub/time.h>
#include <grub/cs5536.h>
#include <grub/loader.h>
struct grub_ohci_hcca
{
@ -96,7 +97,11 @@ typedef enum
GRUB_OHCI_REG_FRAME_INTERVAL,
GRUB_OHCI_REG_PERIODIC_START = 16,
GRUB_OHCI_REG_RHUBA = 18,
GRUB_OHCI_REG_RHUBPORT = 21
GRUB_OHCI_REG_RHUBPORT = 21,
GRUB_OHCI_REG_LEGACY_CONTROL = 0x100,
GRUB_OHCI_REG_LEGACY_INPUT = 0x104,
GRUB_OHCI_REG_LEGACY_OUTPUT = 0x108,
GRUB_OHCI_REG_LEGACY_STATUS = 0x10c
} grub_ohci_reg_t;
#define GRUB_OHCI_RHUB_PORT_POWER_MASK 0x300
@ -195,7 +200,7 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
if (! o)
return 1;
o->iobase = grub_pci_device_map_range (dev, base, 0x100);
o->iobase = grub_pci_device_map_range (dev, base, 0x800);
grub_dprintf ("ohci", "base=%p\n", o->iobase);
@ -212,10 +217,48 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
if ((revision & 0xFF) != 0x10)
goto fail;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBA,
(grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA)
& ~GRUB_OHCI_RHUB_PORT_POWER_MASK)
| GRUB_OHCI_RHUB_PORT_ALL_POWERED);
{
grub_uint32_t control;
/* Check SMM/BIOS ownership of OHCI (SMM = USB Legacy Support driver for BIOS) */
control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
if ((control & 0x100) != 0)
{
unsigned i;
grub_dprintf("ohci", "OHCI is owned by SMM\n");
/* Do change of ownership */
/* Ownership change request */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, (1<<3)); /* XXX: Magic. */
/* Waiting for SMM deactivation */
for (i=0; i < 10; i++)
{
if ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) & 0x100) == 0)
{
grub_dprintf("ohci", "Ownership changed normally.\n");
break;
}
grub_millisleep (100);
}
if (i >= 10)
{
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL,
grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) & ~0x100);
grub_dprintf("ohci", "Ownership changing timeout, change forced !\n");
}
}
else if (((control & 0x100) == 0) &&
((control & 0xc0) != 0)) /* Not owned by SMM nor reset */
{
grub_dprintf("ohci", "OHCI is owned by BIOS\n");
/* Do change of ownership - not implemented yet... */
/* In fact we probably need to do nothing ...? */
}
else
{
grub_dprintf("ohci", "OHCI is not owned by SMM nor BIOS\n");
/* We can setup OHCI. */
}
}
/* Suspend the OHCI by issuing a reset. */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, 1); /* XXX: Magic. */
@ -232,15 +275,58 @@ grub_ohci_pci_iter (grub_pci_device_t dev,
GRUB_OHCI_PERIODIC_START);
/* Setup the HCCA. */
o->hcca->donehead = 0;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_HCCA, o->hcca_addr);
grub_dprintf ("ohci", "OHCI HCCA\n");
/* Misc. pre-sets. */
o->hcca->donehead = 0;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears WDH */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, 0);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0);
/* Check OHCI Legacy Support */
if ((revision & 0x100) != 0)
{
grub_dprintf ("ohci", "Legacy Support registers detected\n");
grub_dprintf ("ohci", "Current state of legacy control reg.: 0x%04x\n",
grub_ohci_readreg32 (o, GRUB_OHCI_REG_LEGACY_CONTROL));
grub_ohci_writereg32 (o, GRUB_OHCI_REG_LEGACY_CONTROL,
(grub_ohci_readreg32 (o, GRUB_OHCI_REG_LEGACY_CONTROL)) & ~1);
grub_dprintf ("ohci", "OHCI Legacy Support disabled.\n");
}
/* Enable the OHCI. */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL,
(2 << 6));
grub_dprintf ("ohci", "OHCI enable: 0x%02x\n",
(grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) >> 6) & 3);
/* Power on all ports */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBA,
(grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBA)
& ~GRUB_OHCI_RHUB_PORT_POWER_MASK)
| GRUB_OHCI_RHUB_PORT_ALL_POWERED);
/* Wait for stable power (100ms) and stable attachment (100ms) */
/* I.e. minimum wait time should be probably 200ms. */
/* We assume that device is attached when ohci is loaded. */
/* Some devices take long time to power-on or indicate attach. */
/* Here is some experimental value which should probably mostly work. */
/* Cameras with manual USB mode selection and maybe some other similar
* devices will not work in some cases - they are repowered during
* ownership change and then they are starting slowly and mostly they
* are wanting select proper mode again...
* The same situation can be on computers where BIOS not set-up OHCI
* to be at least powered USB bus (maybe it is Yeelong case...?)
* Possible workaround could be for example some prompt
* for user with confirmation of proper USB device connection.
* Another workaround - "rmmod usbms", "rmmod ohci", proper start
* and configuration of USB device and then "insmod ohci"
* and "insmod usbms". */
grub_millisleep (500);
/* Link to ohci now that initialisation is successful. */
o->next = ohci;
ohci = o;
@ -317,13 +403,29 @@ grub_ohci_transaction (grub_ohci_td_t td,
token |= toggle << 24;
token |= 1 << 25;
/* Set "Not accessed" error code */
token |= 15 << 28;
buffer = data;
buffer_end = buffer + size - 1;
/* Set correct buffer values in TD if zero transfer occurs */
if (size)
{
buffer = (grub_uint32_t) data;
buffer_end = buffer + size - 1;
td->buffer = grub_cpu_to_le32 (buffer);
td->buffer_end = grub_cpu_to_le32 (buffer_end);
}
else
{
td->buffer = 0;
td->buffer_end = 0;
}
/* Set the rest of TD */
td->token = grub_cpu_to_le32 (token);
td->buffer = grub_cpu_to_le32 (buffer);
td->next_td = 0;
td->buffer_end = grub_cpu_to_le32 (buffer_end);
}
static grub_usb_err_t
@ -342,7 +444,9 @@ grub_ohci_transfer (grub_usb_controller_t dev,
grub_uint32_t status;
grub_uint32_t control;
grub_usb_err_t err;
int i;
int i, j;
grub_uint64_t maxtime;
int err_timeout = 0;
/* Allocate an Endpoint Descriptor. */
ed_chunk = grub_memalign_dma32 (256, sizeof (*ed));
@ -375,13 +479,25 @@ grub_ohci_transfer (grub_usb_controller_t dev,
+ (i + 1) * sizeof (td_list[0]));
}
/* The last-1 TD token we should change to enable interrupt when TD finishes.
* As OHCI interrupts are disabled, it does only setting of WDH bit in
* HcInterruptStatus register - and that is what we want to safely detect
* normal end of all transactions. */
td_list[transfer->transcnt - 1].token &= ~(7 << 21);
td_list[transfer->transcnt].token = 0;
td_list[transfer->transcnt].buffer = 0;
td_list[transfer->transcnt].buffer_end = 0;
td_list[transfer->transcnt].next_td =
(grub_uint32_t) &td_list[transfer->transcnt];
/* Setup the Endpoint Descriptor. */
/* Set the device address. */
target = transfer->devaddr;
/* Set the endpoint. */
target |= transfer->endpoint << 7;
/* Set the endpoint. It should be masked, we need 4 bits only. */
target |= (transfer->endpoint & 15) << 7;
/* Set the device speed. */
target |= (transfer->dev->speed == GRUB_USB_SPEED_LOW) << 13;
@ -400,6 +516,30 @@ grub_ohci_transfer (grub_usb_controller_t dev,
grub_dprintf ("ohci", "program OHCI\n");
/* Disable the Control and Bulk lists. */
control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
control &= ~(3 << 4);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
/* Clear BulkListFilled and ControlListFilled. */
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
status &= ~(3 << 1);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
/* Now we should wait for start of next frame. Because we are not using
* interrupt, we reset SF bit and wait when it goes to 1. */
/* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2));
/* Wait for new SOF */
while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) == 0);
/* Now it should be safe to change CONTROL and BULK lists. */
/* This we do for safety's sake - it should be done in previous call
* of grub_ohci_transfer and nobody should change it in meantime...
* It should be done before start of control or bulk OHCI list. */
o->hcca->donehead = 0;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears WDH */
/* Program the OHCI to actually transfer. */
switch (transfer->type)
{
@ -407,24 +547,17 @@ grub_ohci_transfer (grub_usb_controller_t dev,
{
grub_dprintf ("ohci", "add to bulk list\n");
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
/* Disable the Control and Bulk lists. */
control &= ~(3 << 4);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
/* Clear BulkListFilled. */
status &= ~(1 << 2);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
/* Set BulkList Head and Current */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, ed_addr);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0);
/* Enable the Bulk list. */
control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
control |= 1 << 5;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
/* Set BulkListFilled. */
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
status |= 1 << 2;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
@ -433,21 +566,9 @@ grub_ohci_transfer (grub_usb_controller_t dev,
case GRUB_USB_TRANSACTION_TYPE_CONTROL:
{
grub_dprintf ("ohci", "add to control list\n");
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
control = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL);
/* Disable the Control and Bulk lists. */
control &= ~(3 << 4);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL, control);
/* Clear ControlListFilled. */
status &= ~(1 << 1);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
/* Set ControlList Head and Current */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, ed_addr);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD+1,
ed_addr);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0);
/* Enable the Control list. */
control |= 1 << 4;
@ -465,36 +586,77 @@ grub_ohci_transfer (grub_usb_controller_t dev,
grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL),
grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS));
/* Safety measure to avoid a hang. */
maxtime = grub_get_time_ms () + 1000;
/* Wait until the transfer is completed or STALLs. */
while ((ed->td_head & ~0xf) != (ed->td_tail & ~0xf))
do
{
grub_cpu_idle ();
grub_dprintf ("ohci", "head=0x%02x tail=0x%02x\n", ed->td_head, ed->td_tail);
/* Detected a HALT. */
if (grub_le_to_cpu32 (ed->td_head) & 1)
break;
if ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x2) != 0)
{
if ((grub_le_to_cpu32 (o->hcca->donehead) & ~0xf)
== td_list_addr + (transfer->transcnt - 1) * sizeof (td_list[0]))
break;
/* Detected a STALL. */
if (ed->td_head & 1)
/* Done Head can be updated on some another place if ED is halted. */
if (grub_le_to_cpu32 (ed->td_head) & 1)
break;
/* If there is not HALT in ED, it is not correct, so debug it, reset
* donehead and WDH and continue waiting. */
grub_dprintf ("ohci", "Incorrect HccaDoneHead=0x%08x\n",
o->hcca->donehead);
o->hcca->donehead = 0;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1));
continue;
}
/* Timeout ? */
if (grub_get_time_ms () > maxtime)
{
/* Disable the Control and Bulk lists. */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROL,
grub_ohci_readreg32 (o, GRUB_OHCI_REG_CONTROL) & ~(3 << 4));
err_timeout = 1;
break;
}
if ((ed->td_head & ~0xf) == (ed->td_tail & ~0xf))
break;
}
while (1);
grub_dprintf ("ohci", "complete\n");
/* if (ed->td_head & 1) */
/* err = GRUB_USB_ERR_STALL; */
/* else if (ed->td */
if (ed->td_head & 1)
if (err_timeout)
{
err = GRUB_ERR_TIMEOUT;
grub_dprintf("ohci", "Timeout, target=%08x, head=%08x\n\t\ttail=%08x, next=%08x\n",
grub_le_to_cpu32(ed->target),
grub_le_to_cpu32(ed->td_head),
grub_le_to_cpu32(ed->td_tail),
grub_le_to_cpu32(ed->next_ed));
}
else if (grub_le_to_cpu32 (ed->td_head) & 1)
{
grub_uint8_t errcode;
grub_ohci_td_t tderr;
grub_uint32_t td_err_addr;
grub_uint8_t errcode;
grub_ohci_td_t tderr = NULL;
td_err_addr = grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD);
td_err_addr = (grub_ohci_readreg32 (o, GRUB_OHCI_REG_DONEHEAD) & ~0xf);
if (td_err_addr == 0)
/* If DONEHEAD==0 it means that correct address is in HCCA.
* It should be always now! */
td_err_addr = (grub_le_to_cpu32 (o->hcca->donehead) & ~0xf);
tderr = (grub_ohci_td_t) ((char *) td_list
+ (td_err_addr - td_list_addr));
errcode = tderr->token >> 28;
errcode = grub_le_to_cpu32 (tderr->token) >> 28;
grub_dprintf ("ohci", "OHCI errcode=0x%02x\n", errcode);
switch (errcode)
{
@ -540,11 +702,17 @@ grub_ohci_transfer (grub_usb_controller_t dev,
case 8:
/* XXX: Data overrun error. */
err = GRUB_USB_ERR_DATA;
j = ((grub_uint32_t)tderr - (grub_uint32_t)td_list) / sizeof (*td_list);
grub_dprintf ("ohci", "Overrun, failed TD address: %p, index: %d\n", tderr, j);
break;
case 9:
/* XXX: Data underrun error. */
err = GRUB_USB_ERR_DATA;
grub_dprintf ("ohci", "Underrun, number of not transferred bytes: %d\n",
1 + grub_le_to_cpu32 (tderr->buffer_end) - grub_le_to_cpu32 (tderr->buffer));
j = ((grub_uint32_t)tderr - (grub_uint32_t)td_list) / sizeof (*td_list);
grub_dprintf ("ohci", "Underrun, failed TD address: %p, index: %d\n", tderr, j);
break;
case 10:
@ -582,43 +750,73 @@ grub_ohci_transfer (grub_usb_controller_t dev,
/* Clear BulkListFilled and ControlListFilled. */
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_CMDSTATUS);
status &= ~((1 << 2) | (1 << 3));
status &= ~(3 << 1);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CMDSTATUS, status);
/* XXX */
/* Set ED to be skipped - for safety */
ed->target |= grub_cpu_to_le32 (1 << 14);
/* Now we should wait for start of next frame.
* It is necessary because we will invalidate pointer to ED and it
* can be on OHCI active till SOF!
* Because we are not using interrupt, we reset SF bit and wait when
* it goes to 1. */
/* SF bit reset. (SF bit indicates Start Of Frame (SOF) packet) */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1<<2));
/* Wait for new SOF */
while ((grub_ohci_readreg32 (o, GRUB_OHCI_REG_INTSTATUS) & 0x4) == 0);
/* Now it should be safe to change CONTROL and BULK lists. */
/* Important cleaning. */
o->hcca->donehead = 0;
grub_ohci_writereg32 (o, GRUB_OHCI_REG_INTSTATUS, (1 << 1)); /* Clears WDH */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLHEAD, 0);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_CONTROLCURR, 0);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKHEAD, 0);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_BULKCURR, 0);
grub_dprintf ("ohci", "OHCI finished, freeing, err=0x%02x\n", err);
grub_dma_free (td_list_chunk);
grub_dma_free (ed_chunk);
return err;
}
#define GRUB_OHCI_SET_PORT_ENABLE (1 << 1)
#define GRUB_OHCI_CLEAR_PORT_ENABLE (1 << 0)
#define GRUB_OHCI_SET_PORT_RESET (1 << 4)
#define GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE (1 << 20)
static grub_err_t
grub_ohci_portstatus (grub_usb_controller_t dev,
unsigned int port, unsigned int enable)
{
struct grub_ohci *o = (struct grub_ohci *) dev->data;
grub_uint32_t status;
/* Reset the port. */
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
status |= (1 << 4); /* XXX: Magic. */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status);
grub_millisleep (100);
grub_dprintf ("ohci", "begin of portstatus=0x%02x\n",
grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port));
/* End the reset signaling. */
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
status |= (1 << 20); /* XXX: Magic. */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status);
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
GRUB_OHCI_SET_PORT_RESET);
grub_millisleep (50); /* For root hub should be nominaly 50ms */
/* End the reset signaling. */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
GRUB_OHCI_SET_PORT_RESET_STATUS_CHANGE);
grub_millisleep (10);
/* Enable the port. */
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
status |= (enable << 1); /* XXX: Magic. */
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port, status);
status = grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port);
grub_dprintf ("ohci", "portstatus=0x%02x\n", status);
if (enable)
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
GRUB_OHCI_SET_PORT_ENABLE);
else
grub_ohci_writereg32 (o, GRUB_OHCI_REG_RHUBPORT + port,
GRUB_OHCI_CLEAR_PORT_ENABLE);
grub_millisleep (10);
grub_dprintf ("ohci", "end of portstatus=0x%02x\n",
grub_ohci_readreg32 (o, GRUB_OHCI_REG_RHUBPORT + port));
return GRUB_ERR_NONE;
}

View file

@ -174,14 +174,15 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
return 1;
u->iobase = base & GRUB_UHCI_IOMASK;
grub_dprintf ("uhci", "class=0x%02x 0x%02x interface 0x%02x base=0x%x\n",
class, subclass, interf, u->iobase);
/* Reserve a page for the frame list. */
u->framelist = grub_memalign (4096, 4096);
if (! u->framelist)
goto fail;
grub_dprintf ("uhci", "class=0x%02x 0x%02x interface 0x%02x base=0x%x framelist=%p\n",
class, subclass, interf, u->iobase, u->framelist);
/* The framelist pointer of UHCI is only 32 bits, make sure this
code works on on 64 bits architectures. */
#if GRUB_CPU_SIZEOF_VOID_P == 8
@ -221,6 +222,9 @@ grub_uhci_pci_iter (grub_pci_device_t dev,
}
#endif
grub_dprintf ("uhci", "QH=%p, TD=%p\n",
u->qh, u->td);
/* Link all Transfer Descriptors in a list of available Transfer
Descriptors. */
for (i = 0; i < 256; i++)
@ -441,6 +445,8 @@ grub_uhci_transfer (grub_usb_controller_t dev,
if (! qh)
return grub_errno;
grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
for (i = 0; i < transfer->transcnt; i++)
{
grub_usb_transaction_t tr = &transfer->transactions[i];
@ -548,7 +554,8 @@ grub_uhci_transfer (grub_usb_controller_t dev,
fail:
grub_dprintf ("uhci", "transaction failed\n");
if (err != GRUB_USB_ERR_NONE)
grub_dprintf ("uhci", "transaction failed\n");
/* Place the QH back in the free list and deallocate the associated
TDs. */
@ -583,6 +590,8 @@ grub_uhci_portstatus (grub_usb_controller_t dev,
unsigned int status;
grub_uint64_t endtime;
grub_dprintf ("uhci", "portstatus, iobase:%08x\n", u->iobase);
grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port);
if (port == 0)
@ -631,6 +640,8 @@ grub_uhci_detect_dev (grub_usb_controller_t dev, int port)
int reg;
unsigned int status;
grub_dprintf ("uhci", "detect_dev, iobase:%08x\n", u->iobase);
if (port == 0)
reg = GRUB_UHCI_REG_PORTSC1;
else if (port == 1)

View file

@ -107,7 +107,7 @@ grub_usb_set_configuration (grub_usb_device_t dev, int configuration)
{
int i;
for (i = 0; i < 16; i++)
for (i = 0; i < 256; i++)
dev->toggle[i] = 0;
return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
@ -163,6 +163,16 @@ grub_usb_device_initialize (grub_usb_device_t dev)
grub_usb_err_t err;
int i;
/* First we have to read first 8 bytes only and determine
* 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);
if (err)
return err;
/* Now we have valid value in dev->descdev.maxsize0,
* so we can read whole device descriptor */
err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE,
0, sizeof (struct grub_usb_desc_device),
(char *) &dev->descdev);

View file

@ -138,7 +138,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
/* End with an empty OUT transaction. */
transfer->transactions[datablocks + 1].size = 0;
transfer->transactions[datablocks + 1].data = 0;
if (reqtype & 128)
if ((reqtype & 128) && datablocks)
transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_OUT;
else
transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_IN;
@ -148,6 +148,7 @@ grub_usb_control_msg (grub_usb_device_t dev,
err = dev->controller.dev->transfer (&dev->controller, transfer);
grub_free (transfer->transactions);
grub_free (transfer);
grub_dma_free (data_chunk);
grub_dma_free (setupdata_chunk);
@ -207,7 +208,7 @@ grub_usb_bulk_readwrite (grub_usb_device_t dev,
datablocks = ((size + max - 1) / max);
transfer->transcnt = datablocks;
transfer->size = size - 1;
transfer->endpoint = endpoint;
transfer->endpoint = endpoint & 15;
transfer->devaddr = dev->addr;
transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK;
transfer->max = max;