* EF: compute checksum (?)
*/
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
#include "transport.h"
#include "protocol.h"
-#include "usb.h"
#include "debug.h"
#include "sddr09.h"
-#include <linux/version.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
#define LSB_of(s) ((s)&0xFF)
{ 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;
* 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,
#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 */
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
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);
}
/*
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
US_DEBUGP("Result for send_control in sddr09_read2%d %d\n",
x, result);
return result;
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;
+ return -EIO;
}
- return USB_STOR_TRANSPORT_GOOD;
+ return 0;
}
/*
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
US_DEBUGP("Result for send_control in sddr09_erase %d\n",
result);
result = sddr09_send_scsi_command(us, command, 12);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
US_DEBUGP("Result for send_control in sddr09_writeX %d\n",
result);
return result;
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n",
result);
- return USB_STOR_TRANSPORT_ERROR;
+ return -EIO;
}
- return USB_STOR_TRANSPORT_GOOD;
+ return 0;
}
/* erase address, write same address */
result = sddr09_send_scsi_command(us, command, 4*nsg+3);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
US_DEBUGP("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);
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n",
result);
- return USB_STOR_TRANSPORT_ERROR;
+ return -EIO;
}
- return USB_STOR_TRANSPORT_GOOD;
+ return 0;
}
#endif
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
unsigned int len, index, offset;
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.
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL) {
printk("sddr09_read_data: Out of memory\n");
- return USB_STOR_TRANSPORT_ERROR;
+ 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;
+ result = 0;
index = offset = 0;
while (sectors > 0) {
if (lba >= maxlba) {
US_DEBUGP("Error: Requested lba %u exceeds "
"maximum %u\n", lba, maxlba);
- result = USB_STOR_TRANSPORT_ERROR;
+ result = -EIO;
break;
}
/* 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);
result = sddr09_read20(us, address>>1,
pages, info->pageshift, buffer, 0);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
break;
}
pba = sddr09_find_unused_pba(info, lba);
if (!pba) {
printk("sddr09_write_lba: Out of unused blocks\n");
- return USB_STOR_TRANSPORT_ERROR;
+ return -ENOSPC;
}
info->pba_to_lba[pba] = lba;
info->lba_to_pba[lba] = pba;
/* 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;
+ return 0;
}
pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
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 */
{
unsigned char status = 0;
int result2 = sddr09_read_status(us, &status);
- if (result2 != USB_STOR_TRANSPORT_GOOD)
+ if (result2)
US_DEBUGP("sddr09_write_inplace: cannot read status\n");
else if (status != 0xc0)
US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
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;
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
blockbuffer = kmalloc(blocklen, GFP_NOIO);
if (!blockbuffer) {
printk("sddr09_write_data: Out of memory\n");
- return USB_STOR_TRANSPORT_ERROR;
+ return -ENOMEM;
}
// Since we don't write the user data directly to the device,
if (buffer == NULL) {
printk("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;
+ result = 0;
index = offset = 0;
while (sectors > 0) {
pages = min(sectors, info->blocksize - page);
len = (pages << info->pageshift);
+ /* Not overflowing capacity? */
+ if (lba >= maxlba) {
+ US_DEBUGP("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);
result = sddr09_write_lba(us, lba, page, pages,
buffer, blockbuffer);
- if (result != USB_STOR_TRANSPORT_GOOD)
+ if (result)
break;
page = 0;
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,
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
unsigned char status;
result = sddr09_read_status(us, &status);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
US_DEBUGP("sddr09_get_wp: read_status fails\n");
return result;
}
if (status & 0x1)
US_DEBUGP(" Error");
US_DEBUGP("\n");
- return USB_STOR_TRANSPORT_GOOD;
+ return 0;
}
#if 0
result = sddr09_read_deviceID(us, deviceID);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
US_DEBUGP("Result of read_deviceID is %d\n", result);
printk("sddr09: could not read card info\n");
return NULL;
us, address>>1,
min(alloc_blocks, numblocks - i),
buffer, 0);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
result = -1;
goto done;
}
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) {
+ US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
+ ->actconfig->desc.bConfigurationValue);
+ return -EINVAL;
}
+
+ result = usb_reset_configuration(us->pusb_dev);
+ US_DEBUGP("Result of usb_reset_configuration is %d\n", result);
+ if (result == -EPIPE) {
+ US_DEBUGP("-- stall on control interface\n");
+ } else if (result != 0) {
+ /* it's not a stall, but another error -- time to bail */
+ US_DEBUGP("-- 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) {
+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) {
+ if (result) {
US_DEBUGP("sddr09_init: send_command fails\n");
return result;
}
// get 07 02
result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
US_DEBUGP("sddr09_init: 2nd send_command fails\n");
return result;
}
// 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]);
// test unit ready
- return USB_STOR_TRANSPORT_GOOD; /* not result */
+ return 0; /* not result */
}
/*
* Transport for the Sandisk SDDR-09
*/
-int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
+int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
{
static unsigned char sensekey = 0, sensecode = 0;
static unsigned char havefakesense = 0;
};
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 */
capacity = (info->lbact << info->blockshift) - 1;
- ((u32 *) ptr)[0] = cpu_to_be32(capacity);
+ ((__be32 *) ptr)[0] = cpu_to_be32(capacity);
// Report page size
- ((u32 *) ptr)[1] = cpu_to_be32(info->pagesize);
+ ((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize);
usb_stor_set_xfer_buf(ptr, 8, srb);
return USB_STOR_TRANSPORT_GOOD;
"mode page 0x%x\n", modepage);
memcpy(ptr, mode_page_01, sizeof(mode_page_01));
- ((u16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
+ ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0;
usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
return USB_STOR_TRANSPORT_GOOD;
US_DEBUGP("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) {
US_DEBUGP("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
US_DEBUGP("SDDR09: Send control for command %s\n", ptr);
result = sddr09_send_scsi_command(us, srb->cmnd, 12);
- if (result != USB_STOR_TRANSPORT_GOOD) {
+ if (result) {
US_DEBUGP("sddr09_transport: sddr09_send_scsi_command "
"returns %d\n", result);
- return result;
+ return USB_STOR_TRANSPORT_ERROR;
}
if (srb->request_bufflen == 0)
return USB_STOR_TRANSPORT_GOOD;
- if (srb->sc_data_direction == SCSI_DATA_WRITE ||
- srb->sc_data_direction == SCSI_DATA_READ) {
- unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE)
+ if (srb->sc_data_direction == DMA_TO_DEVICE ||
+ srb->sc_data_direction == DMA_FROM_DEVICE) {
+ 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 == SCSI_DATA_WRITE) ?
+ (srb->sc_data_direction == DMA_TO_DEVICE) ?
"sending" : "receiving",
srb->request_bufflen);
return USB_STOR_TRANSPORT_GOOD;
}
+/*
+ * Initialization routine for the sddr09 subdriver
+ */
+int
+usb_stor_sddr09_init(struct us_data *us) {
+ return sddr09_common_init(us);
+}