diff options
author | Stefan Reinauer <stepan@coresystems.de> | 2010-03-25 22:17:36 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2010-03-25 22:17:36 +0000 |
commit | b56f2d0ad4bfc81e7ef5ffd406c652f2c3bd954a (patch) | |
tree | ec2bbc0918ee3e1f2ee66491c7b87da204e607da /payloads/libpayload/drivers/usb/usbmsc.c | |
parent | e5d30b78b7720ba3e511819b7fc51c11d642153b (diff) |
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
Diffstat (limited to 'payloads/libpayload/drivers/usb/usbmsc.c')
-rw-r--r-- | payloads/libpayload/drivers/usb/usbmsc.c | 124 |
1 files changed, 88 insertions, 36 deletions
diff --git a/payloads/libpayload/drivers/usb/usbmsc.c b/payloads/libpayload/drivers/usb/usbmsc.c index f24bd6d857..5af3330b2f 100644 --- a/payloads/libpayload/drivers/usb/usbmsc.c +++ b/payloads/libpayload/drivers/usb/usbmsc.c @@ -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; - - 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) +} __attribute__ ((packed)) cbw_t; + +typedef struct { + unsigned int dCSWSignature; + unsigned int dCSWTag; + unsigned int dCSWDataResidue; + unsigned char bCSWStatus; +} __attribute__ ((packed)) csw_t; + +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"); |