diff options
Diffstat (limited to 'drivers/usb/storage/sddr09.c')
| -rw-r--r-- | drivers/usb/storage/sddr09.c | 549 |
1 files changed, 362 insertions, 187 deletions
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 0ea2f5ab66b..073a2c32ccc 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -1,6 +1,5 @@ /* Driver for SanDisk SDDR-09 SmartMedia reader * - * $Id: sddr09.c,v 1.24 2002/04/22 03:39:43 mdharm Exp $ * (c) 2000, 2001 Robert Baruch (autophile@starband.net) * (c) 2002 Andries Brouwer (aeb@cwi.nl) * Developed with the assistance of: @@ -41,26 +40,71 @@ * EF: compute checksum (?) */ -#include <linux/sched.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/slab.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> #include "usb.h" #include "transport.h" #include "protocol.h" #include "debug.h" -#include "sddr09.h" + +MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader"); +MODULE_AUTHOR("Andries Brouwer <aeb@cwi.nl>, Robert Baruch <autophile@starband.net>"); +MODULE_LICENSE("GPL"); + +static int usb_stor_sddr09_dpcm_init(struct us_data *us); +static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); +static int usb_stor_sddr09_init(struct us_data *us); + + +/* + * The table of devices + */ +#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ + vendorName, productName, useProtocol, useTransport, \ + initFunction, flags) \ +{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ + .driver_info = (flags) } + +static struct usb_device_id sddr09_usb_ids[] = { +# include "unusual_sddr09.h" + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, sddr09_usb_ids); + +#undef UNUSUAL_DEV + +/* + * The flags table + */ +#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ + vendor_name, product_name, use_protocol, use_transport, \ + init_function, Flags) \ +{ \ + .vendorName = vendor_name, \ + .productName = product_name, \ + .useProtocol = use_protocol, \ + .useTransport = use_transport, \ + .initFunction = init_function, \ +} + +static struct us_unusual_dev sddr09_unusual_dev_list[] = { +# include "unusual_sddr09.h" + { } /* Terminating entry */ +}; + +#undef UNUSUAL_DEV #define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) -/* #define US_DEBUGP printk */ - /* * First some stuff that does not belong here: * data on SmartMedia and other cards, completely @@ -133,13 +177,11 @@ static struct nand_flash_dev nand_flash_ids[] = { { 0,} }; -#define SIZE(a) (sizeof(a)/sizeof((a)[0])) - static struct nand_flash_dev * nand_find_id(unsigned char id) { int i; - for (i = 0; i < SIZE(nand_flash_ids); i++) + for (i = 0; i < ARRAY_SIZE(nand_flash_ids); i++) if (nand_flash_ids[i].model_id == id) return &(nand_flash_ids[i]); return NULL; @@ -177,11 +219,7 @@ static void nand_init_ecc(void) { /* compute 3-byte ecc on 256 bytes */ static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) { int i, j, a; - unsigned char par, bit, bits[8]; - - par = 0; - for (j = 0; j < 8; j++) - bits[j] = 0; + unsigned char par = 0, bit, bits[8] = {0}; /* collect 16 checksum bits */ for (i = 0; i < 256; i++) { @@ -214,6 +252,20 @@ static void nand_store_ecc(unsigned char *data, unsigned char *ecc) { * The actual driver starts here. */ +struct sddr09_card_info { + unsigned long capacity; /* Size of card in bytes */ + int pagesize; /* Size of page in bytes */ + int pageshift; /* log2 of pagesize */ + int blocksize; /* Size of block in pages */ + int blockshift; /* log2 of blocksize */ + int blockmask; /* 2^blockshift - 1 */ + int *lba_to_pba; /* logical to physical map */ + int *pba_to_lba; /* physical to logical map */ + int lbact; /* number of available pages */ + int flags; +#define SDDR09_WP 1 /* write protected */ +}; + /* * On my 16MB card, control blocks have size 64 (16 real control bytes, * and 48 junk bytes). In reality of course the card uses 16 control bytes, @@ -237,7 +289,7 @@ static void nand_store_ecc(unsigned char *data, unsigned char *ecc) { #define SPARE 0xfffffffe #define UNUSABLE 0xfffffffd -static int erase_bad_lba_entries = 0; +static const int erase_bad_lba_entries = 0; /* send vendor interface command (0x41) */ /* called for requests 0, 1, 8 */ @@ -260,8 +312,11 @@ sddr09_send_command(struct us_data *us, rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype, 0, 0, xfer_data, xfer_len); - return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : - USB_STOR_TRANSPORT_ERROR); + switch (rc) { + case USB_STOR_XFER_GOOD: return 0; + case USB_STOR_XFER_STALLED: return -EPIPE; + default: return -EIO; + } } static int @@ -286,7 +341,7 @@ sddr09_test_unit_ready(struct us_data *us) { result = sddr09_send_scsi_command(us, command, 6); - US_DEBUGP("sddr09_test_unit_ready returns %d\n", result); + usb_stor_dbg(us, "sddr09_test_unit_ready returns %d\n", result); return result; } @@ -308,20 +363,12 @@ sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { command[4] = buflen; result = sddr09_send_scsi_command(us, command, 12); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("request sense failed\n"); + if (result) return result; - } result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, sensebuf, buflen, NULL); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("request sense bulk in failed\n"); - return USB_STOR_TRANSPORT_ERROR; - } else { - US_DEBUGP("request sense worked\n"); - return USB_STOR_TRANSPORT_GOOD; - } + return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); } /* @@ -369,9 +416,9 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress, result = sddr09_send_scsi_command(us, command, 12); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("Result for send_control in sddr09_read2%d %d\n", - x, result); + if (result) { + usb_stor_dbg(us, "Result for send_control in sddr09_read2%d %d\n", + x, result); return result; } @@ -379,11 +426,11 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress, buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n", - x, result); - return USB_STOR_TRANSPORT_ERROR; + usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read2%d %d\n", + x, result); + return -EIO; } - return USB_STOR_TRANSPORT_GOOD; + return 0; } /* @@ -441,8 +488,7 @@ sddr09_read22(struct us_data *us, unsigned long fromaddress, int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); - US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n", - nr_of_pages, bulklen); + usb_stor_dbg(us, "reading %d pages, %d bytes\n", nr_of_pages, bulklen); return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen, buf, use_sg); } @@ -485,7 +531,7 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) { unsigned char *command = us->iobuf; int result; - US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress); + usb_stor_dbg(us, "erase address %lu\n", Eaddress); memset(command, 0, 12); command[0] = 0xEA; @@ -497,9 +543,9 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) { result = sddr09_send_scsi_command(us, command, 12); - if (result != USB_STOR_TRANSPORT_GOOD) - US_DEBUGP("Result for send_control in sddr09_erase %d\n", - result); + if (result) + usb_stor_dbg(us, "Result for send_control in sddr09_erase %d\n", + result); return result; } @@ -555,9 +601,9 @@ sddr09_writeX(struct us_data *us, result = sddr09_send_scsi_command(us, command, 12); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("Result for send_control in sddr09_writeX %d\n", - result); + if (result) { + usb_stor_dbg(us, "Result for send_control in sddr09_writeX %d\n", + result); return result; } @@ -565,11 +611,11 @@ sddr09_writeX(struct us_data *us, buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n", - result); - return USB_STOR_TRANSPORT_ERROR; + usb_stor_dbg(us, "Result for bulk_transfer in sddr09_writeX %d\n", + result); + return -EIO; } - return USB_STOR_TRANSPORT_GOOD; + return 0; } /* erase address, write same address */ @@ -633,26 +679,26 @@ sddr09_read_sg_test_only(struct us_data *us) { result = sddr09_send_scsi_command(us, command, 4*nsg+3); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("Result for send_control in sddr09_read_sg %d\n", - result); + if (result) { + usb_stor_dbg(us, "Result for send_control in sddr09_read_sg %d\n", + result); return result; } - buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO); + buf = kmalloc(bulklen, GFP_NOIO); if (!buf) - return USB_STOR_TRANSPORT_ERROR; + return -ENOMEM; result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, buf, bulklen, NULL); kfree(buf); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n", - result); - return USB_STOR_TRANSPORT_ERROR; + usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read_sg %d\n", + result); + return -EIO; } - return USB_STOR_TRANSPORT_GOOD; + return 0; } #endif @@ -674,21 +720,20 @@ sddr09_read_status(struct us_data *us, unsigned char *status) { unsigned char *data = us->iobuf; int result; - US_DEBUGP("Reading status...\n"); + usb_stor_dbg(us, "Reading status...\n"); memset(command, 0, 12); command[0] = 0xEC; command[1] = LUNBITS; result = sddr09_send_scsi_command(us, command, 12); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result) return result; result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, 64, NULL); *status = data[0]; - return (result == USB_STOR_XFER_GOOD ? - USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); + return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); } static int @@ -700,9 +745,17 @@ sddr09_read_data(struct us_data *us, unsigned char *buffer; unsigned int lba, maxlba, pba; unsigned int page, pages; - unsigned int len, index, offset; + unsigned int len, offset; + struct scatterlist *sg; int result; + // Figure out the initial LBA and page + lba = address >> info->blockshift; + page = (address & info->blockmask); + maxlba = info->capacity >> (info->pageshift + info->blockshift); + if (lba >= maxlba) + return -EIO; + // Since we only read in one block at a time, we have to create // a bounce buffer and move the data a piece at a time between the // bounce buffer and the actual transfer buffer. @@ -710,20 +763,16 @@ sddr09_read_data(struct us_data *us, len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) { - printk("sddr09_read_data: Out of memory\n"); - return USB_STOR_TRANSPORT_ERROR; + printk(KERN_WARNING "sddr09_read_data: Out of memory\n"); + return -ENOMEM; } - // Figure out the initial LBA and page - lba = address >> info->blockshift; - page = (address & info->blockmask); - maxlba = info->capacity >> (info->pageshift + info->blockshift); - // This could be made much more efficient by checking for // contiguous LBA's. Another exercise left to the student. - result = USB_STOR_TRANSPORT_GOOD; - index = offset = 0; + result = 0; + offset = 0; + sg = NULL; while (sectors > 0) { @@ -733,9 +782,9 @@ sddr09_read_data(struct us_data *us, /* Not overflowing capacity? */ if (lba >= maxlba) { - US_DEBUGP("Error: Requested lba %u exceeds " - "maximum %u\n", lba, maxlba); - result = USB_STOR_TRANSPORT_ERROR; + usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", + lba, maxlba); + result = -EIO; break; } @@ -744,33 +793,32 @@ sddr09_read_data(struct us_data *us, if (pba == UNDEF) { /* this lba was never written */ - US_DEBUGP("Read %d zero pages (LBA %d) page %d\n", - pages, lba, page); + usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n", + pages, lba, page); /* This is not really an error. It just means that the block has never been written. - Instead of returning USB_STOR_TRANSPORT_ERROR + Instead of returning an error it is better to return all zero data. */ memset(buffer, 0, len); } else { - US_DEBUGP("Read %d pages, from PBA %d" - " (LBA %d) page %d\n", - pages, pba, lba, page); + usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n", + pages, pba, lba, page); address = ((pba << info->blockshift) + page) << info->pageshift; result = sddr09_read20(us, address>>1, pages, info->pageshift, buffer, 0); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result) break; } // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, TO_XFER_BUF); + &sg, &offset, TO_XFER_BUF); page = 0; lba++; @@ -829,8 +877,9 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, if (pba == UNDEF) { pba = sddr09_find_unused_pba(info, lba); if (!pba) { - printk("sddr09_write_lba: Out of unused blocks\n"); - return USB_STOR_TRANSPORT_ERROR; + printk(KERN_WARNING + "sddr09_write_lba: Out of unused blocks\n"); + return -ENOSPC; } info->pba_to_lba[pba] = lba; info->lba_to_pba[lba] = pba; @@ -840,8 +889,8 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, if (pba == 1) { /* Maybe it is impossible to write to PBA 1. Fake success, but don't do anything. */ - printk("sddr09: avoid writing to pba 1\n"); - return USB_STOR_TRANSPORT_GOOD; + printk(KERN_WARNING "sddr09: avoid writing to pba 1\n"); + return 0; } pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); @@ -850,7 +899,7 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, address = (pba << (info->pageshift + info->blockshift)); result = sddr09_read22(us, address>>1, info->blocksize, info->pageshift, blockbuffer, 0); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result) return result; /* check old contents and fill lba */ @@ -859,14 +908,14 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, cptr = bptr + info->pagesize; nand_compute_ecc(bptr, ecc); if (!nand_compare_ecc(cptr+13, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n", - i, pba); + usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n", + i, pba); nand_store_ecc(cptr+13, ecc); } nand_compute_ecc(bptr+(info->pagesize / 2), ecc); if (!nand_compare_ecc(cptr+8, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n", - i, pba); + usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n", + i, pba); nand_store_ecc(cptr+8, ecc); } cptr[6] = cptr[11] = MSB_of(lbap); @@ -886,22 +935,21 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, nand_store_ecc(cptr+8, ecc); } - US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba); + usb_stor_dbg(us, "Rewrite PBA %d (LBA %d)\n", pba, lba); result = sddr09_write_inplace(us, address>>1, info->blocksize, info->pageshift, blockbuffer, 0); - US_DEBUGP("sddr09_write_inplace returns %d\n", result); + usb_stor_dbg(us, "sddr09_write_inplace returns %d\n", result); #if 0 { unsigned char status = 0; int result2 = sddr09_read_status(us, &status); - if (result2 != USB_STOR_TRANSPORT_GOOD) - US_DEBUGP("sddr09_write_inplace: cannot read status\n"); + if (result2) + usb_stor_dbg(us, "cannot read status\n"); else if (status != 0xc0) - US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n", - status); + usb_stor_dbg(us, "status after write: 0x%x\n", status); } #endif @@ -920,13 +968,21 @@ sddr09_write_data(struct us_data *us, unsigned int sectors) { struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; - unsigned int lba, page, pages; + unsigned int lba, maxlba, page, pages; unsigned int pagelen, blocklen; unsigned char *blockbuffer; unsigned char *buffer; - unsigned int len, index, offset; + unsigned int len, offset; + struct scatterlist *sg; int result; + // Figure out the initial LBA and page + lba = address >> info->blockshift; + page = (address & info->blockmask); + maxlba = info->capacity >> (info->pageshift + info->blockshift); + if (lba >= maxlba) + return -EIO; + // blockbuffer is used for reading in the old data, overwriting // with the new data, and performing ECC calculations @@ -937,8 +993,8 @@ sddr09_write_data(struct us_data *us, blocklen = (pagelen << info->blockshift); blockbuffer = kmalloc(blocklen, GFP_NOIO); if (!blockbuffer) { - printk("sddr09_write_data: Out of memory\n"); - return USB_STOR_TRANSPORT_ERROR; + printk(KERN_WARNING "sddr09_write_data: Out of memory\n"); + return -ENOMEM; } // Since we don't write the user data directly to the device, @@ -948,17 +1004,14 @@ sddr09_write_data(struct us_data *us, len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) { - printk("sddr09_write_data: Out of memory\n"); + printk(KERN_WARNING "sddr09_write_data: Out of memory\n"); kfree(blockbuffer); - return USB_STOR_TRANSPORT_ERROR; + return -ENOMEM; } - // Figure out the initial LBA and page - lba = address >> info->blockshift; - page = (address & info->blockmask); - - result = USB_STOR_TRANSPORT_GOOD; - index = offset = 0; + result = 0; + offset = 0; + sg = NULL; while (sectors > 0) { @@ -967,13 +1020,21 @@ sddr09_write_data(struct us_data *us, pages = min(sectors, info->blocksize - page); len = (pages << info->pageshift); + /* Not overflowing capacity? */ + if (lba >= maxlba) { + usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", + lba, maxlba); + result = -EIO; + break; + } + // Get the data from the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, - &index, &offset, FROM_XFER_BUF); + &sg, &offset, FROM_XFER_BUF); result = sddr09_write_lba(us, lba, page, pages, buffer, blockbuffer); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result) break; page = 0; @@ -994,8 +1055,8 @@ sddr09_read_control(struct us_data *us, unsigned char *content, int use_sg) { - US_DEBUGP("Read control address %lu, blocks %d\n", - address, blocks); + usb_stor_dbg(us, "Read control address %lu, blocks %d\n", + address, blocks); return sddr09_read21(us, address, blocks, CONTROL_SHIFT, content, use_sg); @@ -1022,7 +1083,7 @@ sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { command[1] = LUNBITS; result = sddr09_send_scsi_command(us, command, 12); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result) return result; result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, @@ -1031,8 +1092,7 @@ sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { for (i = 0; i < 4; i++) deviceID[i] = content[i]; - return (result == USB_STOR_XFER_GOOD ? - USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); + return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); } static int @@ -1041,23 +1101,23 @@ sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) { unsigned char status; result = sddr09_read_status(us, &status); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("sddr09_get_wp: read_status fails\n"); + if (result) { + usb_stor_dbg(us, "read_status fails\n"); return result; } - US_DEBUGP("sddr09_get_wp: status 0x%02X", status); + usb_stor_dbg(us, "status 0x%02X", status); if ((status & 0x80) == 0) { info->flags |= SDDR09_WP; /* write protected */ - US_DEBUGP(" WP"); + US_DEBUGPX(" WP"); } if (status & 0x40) - US_DEBUGP(" Ready"); + US_DEBUGPX(" Ready"); if (status & LUNBITS) - US_DEBUGP(" Suspended"); + US_DEBUGPX(" Suspended"); if (status & 0x1) - US_DEBUGP(" Error"); - US_DEBUGP("\n"); - return USB_STOR_TRANSPORT_GOOD; + US_DEBUGPX(" Error"); + US_DEBUGPX("\n"); + return 0; } #if 0 @@ -1085,13 +1145,13 @@ sddr09_get_cardinfo(struct us_data *us, unsigned char flags) { char blurbtxt[256]; int result; - US_DEBUGP("Reading capacity...\n"); + usb_stor_dbg(us, "Reading capacity...\n"); result = sddr09_read_deviceID(us, deviceID); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("Result of read_deviceID is %d\n", result); - printk("sddr09: could not read card info\n"); + if (result) { + usb_stor_dbg(us, "Result of read_deviceID is %d\n", result); + printk(KERN_WARNING "sddr09: could not read card info\n"); return NULL; } @@ -1132,7 +1192,7 @@ sddr09_get_cardinfo(struct us_data *us, unsigned char flags) { sprintf(blurbtxt + strlen(blurbtxt), ", WP"); - printk("%s\n", blurbtxt); + printk(KERN_WARNING "%s\n", blurbtxt); return cardinfo; } @@ -1163,7 +1223,7 @@ sddr09_read_map(struct us_data *us) { alloc_len = (alloc_blocks << CONTROL_SHIFT); buffer = kmalloc(alloc_len, GFP_NOIO); if (buffer == NULL) { - printk("sddr09_read_map: out of memory\n"); + printk(KERN_WARNING "sddr09_read_map: out of memory\n"); result = -1; goto done; } @@ -1177,7 +1237,7 @@ sddr09_read_map(struct us_data *us) { info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { - printk("sddr09_read_map: out of memory\n"); + printk(KERN_WARNING "sddr09_read_map: out of memory\n"); result = -1; goto done; } @@ -1200,7 +1260,7 @@ sddr09_read_map(struct us_data *us) { us, address>>1, min(alloc_blocks, numblocks - i), buffer, 0); - if (result != USB_STOR_TRANSPORT_GOOD) { + if (result) { result = -1; goto done; } @@ -1217,7 +1277,8 @@ sddr09_read_map(struct us_data *us) { if (ptr[j] != 0) goto nonz; info->pba_to_lba[i] = UNUSABLE; - printk("sddr09: PBA %d has no logical mapping\n", i); + printk(KERN_WARNING "sddr09: PBA %d has no logical mapping\n", + i); continue; nonz: @@ -1230,7 +1291,8 @@ sddr09_read_map(struct us_data *us) { nonff: /* normal PBAs start with six FFs */ if (j < 6) { - printk("sddr09: PBA %d has no logical mapping: " + printk(KERN_WARNING + "sddr09: PBA %d has no logical mapping: " "reserved area = %02X%02X%02X%02X " "data status %02X block status %02X\n", i, ptr[0], ptr[1], ptr[2], ptr[3], @@ -1240,7 +1302,8 @@ sddr09_read_map(struct us_data *us) { } if ((ptr[6] >> 4) != 0x01) { - printk("sddr09: PBA %d has invalid address field " + printk(KERN_WARNING + "sddr09: PBA %d has invalid address field " "%02X%02X/%02X%02X\n", i, ptr[6], ptr[7], ptr[11], ptr[12]); info->pba_to_lba[i] = UNUSABLE; @@ -1249,7 +1312,8 @@ sddr09_read_map(struct us_data *us) { /* check even parity */ if (parity[ptr[6] ^ ptr[7]]) { - printk("sddr09: Bad parity in LBA for block %d" + printk(KERN_WARNING + "sddr09: Bad parity in LBA for block %d" " (%02X %02X)\n", i, ptr[6], ptr[7]); info->pba_to_lba[i] = UNUSABLE; continue; @@ -1268,7 +1332,8 @@ sddr09_read_map(struct us_data *us) { */ if (lba >= 1000) { - printk("sddr09: Bad low LBA %d for block %d\n", + printk(KERN_WARNING + "sddr09: Bad low LBA %d for block %d\n", lba, i); goto possibly_erase; } @@ -1276,7 +1341,8 @@ sddr09_read_map(struct us_data *us) { lba += 1000*(i/0x400); if (info->lba_to_pba[lba] != UNDEF) { - printk("sddr09: LBA %d seen for PBA %d and %d\n", + printk(KERN_WARNING + "sddr09: LBA %d seen for PBA %d and %d\n", lba, info->lba_to_pba[lba], i); goto possibly_erase; } @@ -1317,7 +1383,7 @@ sddr09_read_map(struct us_data *us) { lbact += ct; } info->lbact = lbact; - US_DEBUGP("Found %d LBA's\n", lbact); + usb_stor_dbg(us, "Found %d LBA's\n", lbact); result = 0; done: @@ -1342,47 +1408,71 @@ sddr09_card_info_destructor(void *extra) { kfree(info->pba_to_lba); } -static void -sddr09_init_card_info(struct us_data *us) { - if (!us->extra) { - us->extra = kmalloc(sizeof(struct sddr09_card_info), GFP_NOIO); - if (us->extra) { - memset(us->extra, 0, sizeof(struct sddr09_card_info)); - us->extra_destructor = sddr09_card_info_destructor; - } +static int +sddr09_common_init(struct us_data *us) { + int result; + + /* set the configuration -- STALL is an acceptable response here */ + if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) { + usb_stor_dbg(us, "active config #%d != 1 ??\n", + us->pusb_dev->actconfig->desc.bConfigurationValue); + return -EINVAL; } + + result = usb_reset_configuration(us->pusb_dev); + usb_stor_dbg(us, "Result of usb_reset_configuration is %d\n", result); + if (result == -EPIPE) { + usb_stor_dbg(us, "-- stall on control interface\n"); + } else if (result != 0) { + /* it's not a stall, but another error -- time to bail */ + usb_stor_dbg(us, "-- Unknown error. Rejecting device\n"); + return -EINVAL; + } + + us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO); + if (!us->extra) + return -ENOMEM; + us->extra_destructor = sddr09_card_info_destructor; + + nand_init_ecc(); + return 0; } + /* * This is needed at a very early stage. If this is not listed in the * unusual devices list but called from here then LUN 0 of the combo reader * is not recognized. But I do not know what precisely these calls do. */ -int -sddr09_init(struct us_data *us) { +static int +usb_stor_sddr09_dpcm_init(struct us_data *us) { int result; unsigned char *data = us->iobuf; + result = sddr09_common_init(us); + if (result) + return result; + result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("sddr09_init: send_command fails\n"); + if (result) { + usb_stor_dbg(us, "send_command fails\n"); return result; } - US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); + usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]); // get 07 02 result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("sddr09_init: 2nd send_command fails\n"); + if (result) { + usb_stor_dbg(us, "2nd send_command fails\n"); return result; } - US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); + usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]); // get 07 00 result = sddr09_request_sense(us, data, 18); - if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) { + if (result == 0 && data[2] != 0) { int j; for (j=0; j<18; j++) printk(" %02X", data[j]); @@ -1398,13 +1488,54 @@ sddr09_init(struct us_data *us) { // test unit ready - return USB_STOR_TRANSPORT_GOOD; /* not result */ + return 0; /* not result */ } /* + * Transport for the Microtech DPCM-USB + */ +static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) +{ + int ret; + + usb_stor_dbg(us, "LUN=%d\n", srb->device->lun); + + switch (srb->device->lun) { + case 0: + + /* + * LUN 0 corresponds to the CompactFlash card reader. + */ + ret = usb_stor_CB_transport(srb, us); + break; + + case 1: + + /* + * LUN 1 corresponds to the SmartMedia card reader. + */ + + /* + * Set the LUN to 0 (just in case). + */ + srb->device->lun = 0; + ret = sddr09_transport(srb, us); + srb->device->lun = 1; + break; + + default: + usb_stor_dbg(us, "Invalid LUN %d\n", srb->device->lun); + ret = USB_STOR_TRANSPORT_ERROR; + break; + } + return ret; +} + + +/* * Transport for the Sandisk SDDR-09 */ -int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) +static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) { static unsigned char sensekey = 0, sensecode = 0; static unsigned char havefakesense = 0; @@ -1427,13 +1558,6 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) }; info = (struct sddr09_card_info *)us->extra; - if (!info) { - nand_init_ecc(); - sddr09_init_card_info(us); - info = (struct sddr09_card_info *)us->extra; - if (!info) - return USB_STOR_TRANSPORT_ERROR; - } if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) { /* for a faked command, we have to follow with a faked sense */ @@ -1506,8 +1630,8 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) or for all pages. */ /* %% We should check DBD %% */ if (modepage == 0x01 || modepage == 0x3F) { - US_DEBUGP("SDDR09: Dummy up request for " - "mode page 0x%x\n", modepage); + usb_stor_dbg(us, "Dummy up request for mode page 0x%x\n", + modepage); memcpy(ptr, mode_page_01, sizeof(mode_page_01)); ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); @@ -1533,10 +1657,12 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - US_DEBUGP("READ_10: read page %d pagect %d\n", - page, pages); + usb_stor_dbg(us, "READ_10: read page %d pagect %d\n", + page, pages); - return sddr09_read_data(us, page, pages); + result = sddr09_read_data(us, page, pages); + return (result == 0 ? USB_STOR_TRANSPORT_GOOD : + USB_STOR_TRANSPORT_ERROR); } if (srb->cmnd[0] == WRITE_10) { @@ -1546,10 +1672,12 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - US_DEBUGP("WRITE_10: write page %d pagect %d\n", - page, pages); + usb_stor_dbg(us, "WRITE_10: write page %d pagect %d\n", + page, pages); - return sddr09_write_data(us, page, pages); + result = sddr09_write_data(us, page, pages); + return (result == 0 ? USB_STOR_TRANSPORT_GOOD : + USB_STOR_TRANSPORT_ERROR); } /* catch-all for all other commands, except @@ -1572,16 +1700,16 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) for (i=0; i<12; i++) sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]); - US_DEBUGP("SDDR09: Send control for command %s\n", ptr); + usb_stor_dbg(us, "Send control for command %s\n", ptr); result = sddr09_send_scsi_command(us, srb->cmnd, 12); - if (result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("sddr09_transport: sddr09_send_scsi_command " - "returns %d\n", result); - return result; + if (result) { + usb_stor_dbg(us, "sddr09_send_scsi_command returns %d\n", + result); + return USB_STOR_TRANSPORT_ERROR; } - if (srb->request_bufflen == 0) + if (scsi_bufflen(srb) == 0) return USB_STOR_TRANSPORT_GOOD; if (srb->sc_data_direction == DMA_TO_DEVICE || @@ -1589,15 +1717,12 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) ? us->send_bulk_pipe : us->recv_bulk_pipe; - US_DEBUGP("SDDR09: %s %d bytes\n", - (srb->sc_data_direction == DMA_TO_DEVICE) ? - "sending" : "receiving", - srb->request_bufflen); + usb_stor_dbg(us, "%s %d bytes\n", + (srb->sc_data_direction == DMA_TO_DEVICE) ? + "sending" : "receiving", + scsi_bufflen(srb)); - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, - srb->request_bufflen, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -1606,3 +1731,53 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_GOOD; } +/* + * Initialization routine for the sddr09 subdriver + */ +static int +usb_stor_sddr09_init(struct us_data *us) { + return sddr09_common_init(us); +} + +static int sddr09_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct us_data *us; + int result; + + result = usb_stor_probe1(&us, intf, id, + (id - sddr09_usb_ids) + sddr09_unusual_dev_list); + if (result) + return result; + + if (us->protocol == USB_PR_DPCM_USB) { + us->transport_name = "Control/Bulk-EUSB/SDDR09"; + us->transport = dpcm_transport; + us->transport_reset = usb_stor_CB_reset; + us->max_lun = 1; + } else { + us->transport_name = "EUSB/SDDR09"; + us->transport = sddr09_transport; + us->transport_reset = usb_stor_CB_reset; + us->max_lun = 0; + } + + result = usb_stor_probe2(us); + return result; +} + +static struct usb_driver sddr09_driver = { + .name = "ums-sddr09", + .probe = sddr09_probe, + .disconnect = usb_stor_disconnect, + .suspend = usb_stor_suspend, + .resume = usb_stor_resume, + .reset_resume = usb_stor_reset_resume, + .pre_reset = usb_stor_pre_reset, + .post_reset = usb_stor_post_reset, + .id_table = sddr09_usb_ids, + .soft_unbind = 1, + .no_dynamic_id = 1, +}; + +module_usb_driver(sddr09_driver); |
