USB updates from our internal tree

- support MMC2 devices
- make usb stack more solid
- drop some unused functions
- fix lowspeed/speed naming
- add support for "quirks"
- improve usbhid driver

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Joseph Smith <joe@settoplinux.org>


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5299 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Stefan Reinauer
2010-03-25 22:17:36 +00:00
committed by Stefan Reinauer
parent e5d30b78b7
commit b56f2d0ad4
12 changed files with 780 additions and 268 deletions

View File

@ -40,6 +40,7 @@ enum {
msc_subclass_sff8070i = 0x5,
msc_subclass_scsitrans = 0x6
};
static const char *msc_subclass_strings[7] = {
"(none)",
"RBC",
@ -96,19 +97,20 @@ typedef struct {
unsigned long bCBWCBLength:5;
unsigned long:3;
unsigned char CBWCB[31 - 15];
} __attribute__ ((packed))
cbw_t;
} __attribute__ ((packed)) cbw_t;
typedef struct {
unsigned int dCSWSignature;
unsigned int dCSWTag;
unsigned int dCSWDataResidue;
unsigned char bCSWStatus;
} __attribute__ ((packed))
csw_t;
typedef struct {
unsigned int dCSWSignature;
unsigned int dCSWTag;
unsigned int dCSWDataResidue;
unsigned char bCSWStatus;
} __attribute__ ((packed)) csw_t;
static void
reset_transport (usbdev_t *dev)
static int
request_sense (usbdev_t *dev);
static void
reset_transport (usbdev_t *dev)
{
dev_req_t dr;
memset (&dr, 0, sizeof (dr));
@ -171,7 +173,8 @@ wrap_cbw (cbw_t *cbw, int datalen, cbw_direction dir, const u8 *cmd,
static void
get_csw (endpoint_t *ep, csw_t *csw)
{
ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1);
if (ep->dev->controller->bulk (ep, sizeof (csw_t), (u8 *) csw, 1))
clear_stall (ep);
}
static int
@ -188,21 +191,23 @@ execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
wrap_cbw (&cbw, buflen, dir, cb, cblen);
if (dev->controller->
bulk (MSC_INST (dev)->bulk_out, sizeof (cbw), (u8 *) &cbw, 0)) {
clear_stall (MSC_INST (dev)->bulk_out);
reset_transport (dev);
return 1;
}
mdelay (10);
if (dir == cbw_direction_data_in) {
if (dev->controller->
bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
clear_stall (MSC_INST (dev)->bulk_in);
return 1;
}
} else {
if (dev->controller->
bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
clear_stall (MSC_INST (dev)->bulk_out);
return 1;
if (buflen > 0) {
if (dir == cbw_direction_data_in) {
if (dev->controller->
bulk (MSC_INST (dev)->bulk_in, buflen, buf, 0)) {
clear_stall (MSC_INST (dev)->bulk_in);
return 1;
}
} else {
if (dev->controller->
bulk (MSC_INST (dev)->bulk_out, buflen, buf, 0)) {
clear_stall (MSC_INST (dev)->bulk_out);
return 1;
}
}
}
get_csw (MSC_INST (dev)->bulk_in, &csw);
@ -220,6 +225,7 @@ execute_command (usbdev_t *dev, cbw_direction dir, const u8 *cb, int cblen,
return 0;
}
// error "check condition" or reserved error
request_sense (dev);
return 1;
}
@ -241,6 +247,27 @@ typedef struct {
unsigned char res4; //5
} __attribute__ ((packed)) cmdblock6_t;
/**
* Like readwrite_blocks, but for soft-sectors of 512b size. Converts the
* start and count from 512b units.
* Start and count must be aligned so that they match the native
* sector size.
*
* @param dev device to access
* @param start first sector to access
* @param n number of sectors to access
* @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
* @param buf buffer to read into or write from. Must be at least n*512 bytes
* @return 0 on success, 1 on failure
*/
int
readwrite_blocks_512 (usbdev_t *dev, int start, int n,
cbw_direction dir, u8 *buf)
{
int blocksize_divider = MSC_INST(dev)->blocksize / 512;
return readwrite_blocks (dev, start / blocksize_divider,
n / blocksize_divider, dir, buf);
}
/**
* Reads or writes a number of sequential blocks on a USB storage device.
@ -251,7 +278,7 @@ typedef struct {
* @param start first sector to access
* @param n number of sectors to access
* @param dir direction of access: cbw_direction_data_in == read, cbw_direction_data_out == write
* @param buf buffer to read into or write from. Must be at least n*512 bytes
* @param buf buffer to read into or write from. Must be at least n*sectorsize bytes
* @return 0 on success, 1 on failure
*/
int
@ -266,10 +293,26 @@ readwrite_blocks (usbdev_t *dev, int start, int n, cbw_direction dir, u8 *buf)
// write
cb.command = 0x2a;
}
cb.block = ntohl (start);
cb.numblocks = ntohw (n);
cb.block = htonl (start);
cb.numblocks = htonw (n);
return execute_command (dev, dir, (u8 *) &cb, sizeof (cb), buf,
n * 512);
n * MSC_INST(dev)->blocksize);
}
/* Only request it, we don't interpret it.
On certain errors, that's necessary to get devices out of
a special state called "Contingent Allegiance Condition" */
static int
request_sense (usbdev_t *dev)
{
u8 buf[19];
cmdblock6_t cb;
memset (&cb, 0, sizeof (cb));
cb.command = 0x3;
return execute_command (dev, cbw_direction_data_in, (u8 *) &cb,
sizeof (cb), buf, 19);
}
static int
@ -338,17 +381,25 @@ usb_msc_init (usbdev_t *dev)
printf (" it uses %s protocol\n",
msc_protocol_strings[interface->bInterfaceProtocol]);
if ((interface->bInterfaceProtocol != 0x50)
|| (interface->bInterfaceSubClass != 6)) {
if (interface->bInterfaceProtocol != 0x50) {
printf (" Protocol not supported.\n");
return;
}
if ((interface->bInterfaceSubClass != 2) && // ATAPI 8020
(interface->bInterfaceSubClass != 5) && // ATAPI 8070
(interface->bInterfaceSubClass != 6)) { // SCSI
/* Other protocols, such as ATAPI don't seem to be very popular. looks like ATAPI would be really easy to add, if necessary. */
printf (" Only SCSI over Bulk is supported.\n");
printf (" Interface SubClass not supported.\n");
return;
}
dev->data = malloc (sizeof (usbmsc_inst_t));
if (!dev->data)
usb_fatal("Not enough memory for USB MSC device.\n");
usb_fatal ("Not enough memory for USB MSC device.\n");
MSC_INST (dev)->protocol = interface->bInterfaceSubClass;
MSC_INST (dev)->bulk_in = 0;
MSC_INST (dev)->bulk_out = 0;
@ -376,10 +427,11 @@ usb_msc_init (usbdev_t *dev)
printf (" has %d luns\n", get_max_luns (dev) + 1);
printf (" Waiting for device to become ready... ");
timeout = 10;
timeout = 30 * 10; /* SCSI/ATA specs say we have to wait up to 30s. Ugh */
while (test_unit_ready (dev) && --timeout) {
mdelay (100);
printf (".");
if (!(timeout % 10))
printf (".");
}
if (test_unit_ready (dev)) {
printf ("timeout. Device not ready. Still trying...\n");