This patch adds support for 64MB SmartMedia cards, thanks to Andries Brouwer.
Greg, please apply.
Matt
----- Forwarded message from Alan Stern <[EMAIL PROTECTED]> -----
Date: Fri, 21 Nov 2003 13:17:31 -0500 (EST)
From: Alan Stern <[EMAIL PROTECTED]>
Subject: PATCH: (as137) Enhance sddr09 to work with 64 MB SmartMedia cards
To: Matthew Dharm <[EMAIL PROTECTED]>
cc: [EMAIL PROTECTED], USB Storage List <[EMAIL PROTECTED]>
Return-Path: <[EMAIL PROTECTED]>
X-Spam-Status: No, hits=-4.0 required=5.0 tests=UNIFIED_PATCH,RCVD_IN_ORBZ version=2.11
Matt:
This patch was written by Andries Brouwer. It adds to sddr09 the ability
to use 64 MB SmartMedia cards. I have added a few minor alterations to
make it fit in with my sequence of other patches.
Alan Stern
--- a/drivers/usb/storage/sddr09.c Fri Nov 21 10:51:19 2003
+++ b/drivers/usb/storage/sddr09.c Fri Nov 21 11:15:55 2003
@@ -66,7 +66,7 @@
* NAND Flash Manufacturer ID Codes
*/
#define NAND_MFR_AMD 0x01
-#define NAND_MFR_NS 0x8f
+#define NAND_MFR_NATSEMI 0x8f
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
@@ -74,8 +74,8 @@
switch(manuf_id) {
case NAND_MFR_AMD:
return "AMD";
- case NAND_MFR_NS:
- return "NS";
+ case NAND_MFR_NATSEMI:
+ return "NATSEMI";
case NAND_MFR_TOSHIBA:
return "Toshiba";
case NAND_MFR_SAMSUNG:
@@ -302,8 +302,7 @@
if (result != USB_STOR_XFER_GOOD) {
US_DEBUGP("request sense bulk in failed\n");
return USB_STOR_TRANSPORT_ERROR;
- }
- else {
+ } else {
US_DEBUGP("request sense worked\n");
return USB_STOR_TRANSPORT_GOOD;
}
@@ -469,6 +468,8 @@
unsigned char *command = us->iobuf;
int result;
+ US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress);
+
memset(command, 0, 12);
command[0] = 0xEA;
command[1] = LUNBITS;
@@ -757,17 +758,27 @@
return result;
}
-/* we never free blocks, so lastpba can only increase */
static unsigned int
-sddr09_find_unused_pba(struct sddr09_card_info *info) {
+sddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) {
static unsigned int lastpba = 1;
- int numblocks = info->capacity >> (info->blockshift + info->pageshift);
- int i;
+ int zonestart, end, i;
+
+ zonestart = (lba/1000) << 10;
+ end = info->capacity >> (info->blockshift + info->pageshift);
+ end -= zonestart;
+ if (end > 1024)
+ end = 1024;
- for (i = lastpba+1; i < numblocks; i++) {
- if (info->pba_to_lba[i] == UNDEF) {
+ for (i = lastpba+1; i < end; i++) {
+ if (info->pba_to_lba[zonestart+i] == UNDEF) {
lastpba = i;
- return i;
+ return zonestart+i;
+ }
+ }
+ for (i = 0; i <= lastpba; i++) {
+ if (info->pba_to_lba[zonestart+i] == UNDEF) {
+ lastpba = i;
+ return zonestart+i;
}
}
return 0;
@@ -784,21 +795,23 @@
unsigned int pagelen, blocklen;
unsigned char *blockbuffer, *bptr, *cptr, *xptr;
unsigned char ecc[3];
- int i, result;
+ int i, result, isnew;
- lbap = ((lba & 0x3ff) << 1) | 0x1000;
+ lbap = ((lba % 1000) << 1) | 0x1000;
if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
lbap ^= 1;
pba = info->lba_to_pba[lba];
+ isnew = 0;
if (pba == UNDEF) {
- pba = sddr09_find_unused_pba(info);
+ pba = sddr09_find_unused_pba(info, lba);
if (!pba) {
printk("sddr09_write_lba: Out of unused blocks\n");
return USB_STOR_TRANSPORT_ERROR;
}
info->pba_to_lba[pba] = lba;
info->lba_to_pba[lba] = pba;
+ isnew = 1;
}
if (pba == 1) {
@@ -823,8 +836,8 @@
if (result != USB_STOR_TRANSPORT_GOOD)
goto err;
- /* check old contents */
- for (i = 0; i < info->blockshift; i++) {
+ /* check old contents and fill lba */
+ for (i = 0; i < info->blocksize; i++) {
bptr = blockbuffer + i*pagelen;
cptr = bptr + info->pagesize;
nand_compute_ecc(bptr, ecc);
@@ -839,6 +852,8 @@
i, pba);
nand_store_ecc(cptr+8, ecc);
}
+ cptr[6] = cptr[11] = MSB_of(lbap);
+ cptr[7] = cptr[12] = LSB_of(lbap);
}
/* copy in new stuff and compute ECC */
@@ -852,8 +867,6 @@
nand_store_ecc(cptr+13, ecc);
nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
nand_store_ecc(cptr+8, ecc);
- cptr[6] = cptr[11] = MSB_of(lbap);
- cptr[7] = cptr[12] = LSB_of(lbap);
}
US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba);
@@ -947,10 +960,11 @@
unsigned char *content,
int use_sg) {
- US_DEBUGP("Read control address %08lX blocks %04X\n",
+ US_DEBUGP("Read control address %lu, blocks %d\n",
address, blocks);
- return sddr09_read21(us, address, blocks, CONTROL_SHIFT, content, use_sg);
+ return sddr09_read21(us, address, blocks,
+ CONTROL_SHIFT, content, use_sg);
}
/*
@@ -997,7 +1011,7 @@
US_DEBUGP("sddr09_get_wp: read_status fails\n");
return result;
}
- US_DEBUGP("sddr09_get_wp: status %02X", status);
+ US_DEBUGP("sddr09_get_wp: status 0x%02X", status);
if ((status & 0x80) == 0) {
info->flags |= SDDR09_WP; /* write protected */
US_DEBUGP(" WP");
@@ -1114,8 +1128,11 @@
alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT);
alloc_len = (alloc_blocks << CONTROL_SHIFT);
buffer = kmalloc(alloc_len, GFP_NOIO);
- if (buffer == NULL)
- return 0;
+ if (buffer == NULL) {
+ printk("sddr09_read_map: out of memory\n");
+ result = -1;
+ goto done;
+ }
buffer_end = buffer + alloc_len;
#undef SDDR09_READ_MAP_BUFSZ
@@ -1141,15 +1158,18 @@
for (i = 0; i < numblocks; i++) {
ptr += (1 << CONTROL_SHIFT);
if (ptr >= buffer_end) {
- ptr = buffer;
+ unsigned long address;
+
+ address = i << (info->pageshift + info->blockshift);
result = sddr09_read_control(
- us, i << (info->blockshift + 8),
+ us, address>>1,
min(alloc_blocks, numblocks - i),
buffer, 0);
if (result != USB_STOR_TRANSPORT_GOOD) {
result = -1;
goto done;
}
+ ptr = buffer;
}
if (i == 0 || i == 1) {
@@ -1162,7 +1182,7 @@
if (ptr[j] != 0)
goto nonz;
info->pba_to_lba[i] = UNUSABLE;
- printk("sddr09: PBA %04X has no logical mapping\n", i);
+ printk("sddr09: PBA %d has no logical mapping\n", i);
continue;
nonz:
@@ -1175,7 +1195,7 @@
nonff:
/* normal PBAs start with six FFs */
if (j < 6) {
- printk("sddr09: PBA %04X has no logical mapping: "
+ printk("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],
@@ -1185,7 +1205,7 @@
}
if ((ptr[6] >> 4) != 0x01) {
- printk("sddr09: PBA %04X has invalid address field "
+ printk("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;
@@ -1194,7 +1214,7 @@
/* check even parity */
if (parity[ptr[6] ^ ptr[7]]) {
- printk("sddr09: Bad parity in LBA for block %04X"
+ printk("sddr09: Bad parity in LBA for block %d"
" (%02X %02X)\n", i, ptr[6], ptr[7]);
info->pba_to_lba[i] = UNUSABLE;
continue;
@@ -1213,27 +1233,32 @@
*/
if (lba >= 1000) {
- unsigned long address;
-
- printk("sddr09: Bad LBA %04X for block %04X\n",
+ printk("sddr09: Bad low LBA %d for block %d\n",
lba, i);
- info->pba_to_lba[i] = UNDEF /* UNUSABLE */;
- if (erase_bad_lba_entries) {
- /* some cameras cannot erase a card if it has
- bad entries, so we supply this function */
- address = (i << (info->pageshift + info->blockshift));
- sddr09_erase(us, address>>1);
- }
- continue;
+ goto possibly_erase;
}
lba += 1000*(i/0x400);
- if (lba<0x10 || (lba >= 0x3E0 && lba < 0x3EF))
- US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
+ if (info->lba_to_pba[lba] != UNDEF) {
+ printk("sddr09: LBA %d seen for PBA %d and %d\n",
+ lba, info->lba_to_pba[lba], i);
+ goto possibly_erase;
+ }
info->pba_to_lba[i] = lba;
info->lba_to_pba[lba] = i;
+ continue;
+
+ possibly_erase:
+ if (erase_bad_lba_entries) {
+ unsigned long address;
+
+ address = (i << (info->pageshift + info->blockshift));
+ sddr09_erase(us, address>>1);
+ info->pba_to_lba[i] = UNDEF;
+ } else
+ info->pba_to_lba[i] = UNUSABLE;
}
/*
@@ -1410,6 +1435,7 @@
cardinfo = sddr09_get_cardinfo(us, info->flags);
if (!cardinfo) {
/* probably no media */
+ init_error:
sensekey = 0x02; /* not ready */
sensecode = 0x3a; /* medium not present */
return USB_STOR_TRANSPORT_FAILED;
@@ -1423,7 +1449,10 @@
info->blockmask = info->blocksize - 1;
// map initialization, must follow get_cardinfo()
- sddr09_read_map(us);
+ if (sddr09_read_map(us)) {
+ /* probably out of memory */
+ goto init_error;
+ }
// Report capacity
@@ -1444,12 +1473,13 @@
return USB_STOR_TRANSPORT_GOOD;
}
- if (srb->cmnd[0] == MODE_SENSE) {
+ if (srb->cmnd[0] == MODE_SENSE || srb->cmnd[0] == MODE_SENSE_10) {
int modepage = (srb->cmnd[2] & 0x3F);
int len;
/* They ask for the Read/Write error recovery page,
or for all pages. Give as much as they have room for. */
+ /* %% We should check DBD %% */
if (modepage == 0x01 || modepage == 0x3F) {
US_DEBUGP("SDDR09: Dummy up request for "
@@ -1471,17 +1501,9 @@
return USB_STOR_TRANSPORT_ERROR;
}
- if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
-
- US_DEBUGP(
- "SDDR09: %s medium removal. Not that I can do"
- " anything about it...\n",
- (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
-
+ if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL)
return USB_STOR_TRANSPORT_GOOD;
- }
-
havefakesense = 0;
if (srb->cmnd[0] == READ_10) {
@@ -1527,8 +1549,7 @@
for (i=0; i<12; i++)
sprintf(string+strlen(string), "%02X ", srb->cmnd[i]);
- US_DEBUGP("SDDR09: Send control for command %s\n",
- string);
+ US_DEBUGP("SDDR09: Send control for command %s\n", string);
result = sddr09_send_scsi_command(us, srb->cmnd, 12);
if (result != USB_STOR_TRANSPORT_GOOD) {
----- End forwarded message -----
--
Matthew Dharm Home: [EMAIL PROTECTED]
Maintainer, Linux USB Mass Storage Driver
It was a new hope.
-- Dust Puppy
User Friendly, 12/25/1998
pgp00000.pgp
Description: PGP signature
