📄 sddr09.c
字号:
unsigned char deviceID; int result; US_DEBUGP("Reading capacity...\n"); result = sddr09_read_deviceID(us, &manufacturerID, &deviceID); US_DEBUGP("Result of read_deviceID is %d\n", result); if (result != USB_STOR_TRANSPORT_GOOD) return 0; US_DEBUGP("Device ID = %02X\n", deviceID); US_DEBUGP("Manuf ID = %02X\n", manufacturerID); *pagesize = 512; *blocksize = 16; switch (deviceID) { case 0x6e: // 1MB case 0xe8: case 0xec: *pagesize = 256; return 0x00100000; case 0xea: // 2MB case 0x5d: // 5d is a ROM card with pagesize 512. case 0x64: if (deviceID!=0x5D) *pagesize = 256; return 0x00200000; case 0xe3: // 4MB case 0xe5: case 0x6b: case 0xd5: return 0x00400000; case 0xe6: // 8MB case 0xd6: return 0x00800000; case 0x73: // 16MB *blocksize = 32; return 0x01000000; case 0x75: // 32MB *blocksize = 32; return 0x02000000; case 0x76: // 64MB *blocksize = 32; return 0x04000000; case 0x79: // 128MB *blocksize = 32; return 0x08000000; default: // unknown return 0; }}int sddr09_read_map(struct us_data *us) { struct scatterlist *sg; struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra); int numblocks; int i; unsigned char *ptr; unsigned short lba; unsigned char parity; unsigned char fast_parity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; int result; int alloc_len; int alloc_blocks; if (!info->capacity) return -1; // read 64 (1<<6) bytes for every block // ( 1 << ( blockshift + pageshift ) bytes) // of capacity: // (1<<6)*capacity/(1<<(b+p)) = // ((1<<6)*capacity)>>(b+p) = // capacity>>(b+p-6) alloc_len = info->capacity >> (info->blockshift + info->pageshift - 6); // Allocate a number of scatterlist structures according to // the number of 128k blocks in the alloc_len. Adding 128k-1 // and then dividing by 128k gives the correct number of blocks. // 128k = 1<<17 alloc_blocks = (alloc_len + (1<<17) - 1) >> 17; sg = kmalloc(alloc_blocks*sizeof(struct scatterlist), GFP_NOIO); if (sg == NULL) return 0; for (i=0; i<alloc_blocks; i++) { if (i<alloc_blocks-1) { sg[i].address = kmalloc( (1<<17), GFP_NOIO ); sg[i].page = NULL; sg[i].length = (1<<17); } else { sg[i].address = kmalloc(alloc_len, GFP_NOIO); sg[i].page = NULL; sg[i].length = alloc_len; } alloc_len -= sg[i].length; } for (i=0; i<alloc_blocks; i++) if (sg[i].address == NULL) { for (i=0; i<alloc_blocks; i++) if (sg[i].address != NULL) kfree(sg[i].address); kfree(sg); return 0; } numblocks = info->capacity >> (info->blockshift + info->pageshift); if ( (result = sddr09_read_control(us, 0, numblocks, (unsigned char *)sg, alloc_blocks)) != USB_STOR_TRANSPORT_GOOD) { for (i=0; i<alloc_blocks; i++) kfree(sg[i].address); kfree(sg); return -1; } if (info->lba_to_pba) kfree(info->lba_to_pba); if (info->pba_to_lba) kfree(info->pba_to_lba); info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { if (info->lba_to_pba != NULL) kfree(info->lba_to_pba); if (info->pba_to_lba != NULL) kfree(info->pba_to_lba); info->lba_to_pba = NULL; info->pba_to_lba = NULL; for (i=0; i<alloc_blocks; i++) kfree(sg[i].address); kfree(sg); return 0; } memset(info->lba_to_pba, 0, numblocks*sizeof(int)); memset(info->pba_to_lba, 0, numblocks*sizeof(int)); // Each block is 64 bytes of control data, so block i is located in // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) for (i=0; i<numblocks; i++) { ptr = sg[i>>11].address+((i&0x7ff)<<6); if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF || ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF) { US_DEBUGP("PBA %04X 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], ptr[4], ptr[5]); continue; } if ((ptr[6]>>4)!=0x01) { US_DEBUGP("PBA %04X has invalid address field %02X%02X/%02X%02X\n", i, ptr[6], ptr[7], ptr[11], ptr[12]); continue; } /* ensure even parity */ lba = short_pack(ptr[7], ptr[6]); parity = 1; // the parity of 0x1000 parity ^= fast_parity[lba & 0x000F]; parity ^= fast_parity[(lba>>4) & 0x000F]; parity ^= fast_parity[(lba>>8) & 0x000F]; if (parity) { /* bad parity bit */ US_DEBUGP("Bad parity in LBA for block %04X\n", i); continue; } lba = (lba&0x07FF)>>1; /* Every 1024 physical blocks ("zone"), the LBA numbers * go back to zero, but are within a higher * block of LBA's. Also, there is a maximum of * 1000 LBA's per zone. In other words, in PBA * 1024-2047 you will find LBA 0-999 which are * really LBA 1000-1999. Yes, this wastes 24 * physical blocks per zone. Go figure. */ lba += 1000*(i/0x400); if (lba>=numblocks) { US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i); continue; } if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF)) US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i); info->pba_to_lba[i] = lba; info->lba_to_pba[lba] = i; } for (i=0; i<alloc_blocks; i++) kfree(sg[i].address); kfree(sg); return 0;}/*static int init_sddr09(struct us_data *us) { int result; unsigned char data[14]; unsigned char command[8] = { 0xc1, 0x01, 0, 0, 0, 0, 0, 0 }; unsigned char command2[8] = { 0x41, 0, 0, 0, 0, 0, 0, 0 }; unsigned char tur[12] = { 0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0 }; // What the hey is all this for? Doesn't seem to // affect the device, so we won't do device inits. if ( (result = sddr09_send_control(us, command, data, 2)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]); command[1] = 0x08; if ( (result = sddr09_send_control(us, command, data, 2)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]); if ( (result = sddr09_send_control(us, command2, tur, 12)) != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("SDDR09: request sense failed\n"); return result; } if ( (result = sddr09_raw_bulk( us, SCSI_DATA_READ, data, 14)) != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("SDDR09: request sense bulk in failed\n"); return result; } US_DEBUGP("SDDR09: request sense worked\n"); return result;}*/void sddr09_card_info_destructor(void *extra) { struct sddr09_card_info *info = (struct sddr09_card_info *)extra; if (!extra) return; if (info->lba_to_pba) kfree(info->lba_to_pba); if (info->pba_to_lba) kfree(info->pba_to_lba);}/* * Transport for the Sandisk SDDR-09 */int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us){ int result; int i; char string[64]; unsigned char inquiry_response[36] = { 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00 }; unsigned char mode_page_01[16] = { // write-protected for now 0x03, 0x00, 0x80, 0x00, 0x01, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char *ptr; unsigned long capacity; unsigned int lba; unsigned int pba; unsigned int page; unsigned short pages; struct sddr09_card_info *info = (struct sddr09_card_info *)(us->extra); if (!us->extra) { us->extra = kmalloc( sizeof(struct sddr09_card_info), GFP_NOIO); if (!us->extra) return USB_STOR_TRANSPORT_ERROR; memset(us->extra, 0, sizeof(struct sddr09_card_info)); us->extra_destructor = sddr09_card_info_destructor; } ptr = (unsigned char *)srb->request_buffer; /* Dummy up a response for INQUIRY since SDDR09 doesn't respond to INQUIRY commands */ if (srb->cmnd[0] == INQUIRY) { memset(inquiry_response+8, 0, 28); fill_inquiry_response(us, inquiry_response, 36); return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == READ_CAPACITY) { capacity = sddr09_get_capacity(us, &info->pagesize, &info->blocksize); if (!capacity) return USB_STOR_TRANSPORT_FAILED; info->capacity = capacity; for (info->pageshift=1; (info->pagesize>>info->pageshift); info->pageshift++); info->pageshift--; for (info->blockshift=1; (info->blocksize>>info->blockshift); info->blockshift++); info->blockshift--; info->blockmask = (1<<info->blockshift)-1; // Last page in the card capacity /= info->pagesize; capacity--; ptr[0] = MSB_of(capacity>>16); ptr[1] = LSB_of(capacity>>16); ptr[2] = MSB_of(capacity&0xFFFF); ptr[3] = LSB_of(capacity&0xFFFF); // The page size ptr[4] = MSB_of(info->pagesize>>16); ptr[5] = LSB_of(info->pagesize>>16); ptr[6] = MSB_of(info->pagesize&0xFFFF); ptr[7] = LSB_of(info->pagesize&0xFFFF); sddr09_read_map(us); return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == MODE_SENSE) { // Read-write error recovery page: there needs to // be a check for write-protect here if ( (srb->cmnd[2] & 0x3F) == 0x01 ) { US_DEBUGP( "SDDR09: Dummy up request for mode page 1\n"); if (ptr==NULL || srb->request_bufflen<sizeof(mode_page_01)) return USB_STOR_TRANSPORT_ERROR; memcpy(ptr, mode_page_01, sizeof(mode_page_01)); return USB_STOR_TRANSPORT_GOOD; } else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) { US_DEBUGP( "SDDR09: Dummy up request for all mode pages\n"); if (ptr==NULL || srb->request_bufflen<sizeof(mode_page_01)) return USB_STOR_TRANSPORT_ERROR; memcpy(ptr, mode_page_01, sizeof(mode_page_01)); return USB_STOR_TRANSPORT_GOOD; } // FIXME: sense buffer? 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"); return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == READ_10) { page = short_pack(srb->cmnd[3], srb->cmnd[2]); page <<= 16; page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); // convert page to block and page-within-block lba = page >> info->blockshift; page = page & info->blockmask; // locate physical block corresponding to logical block if (lba >= (info->capacity >> (info->pageshift + info->blockshift) ) ) { US_DEBUGP("Error: Requested LBA %04X exceeds maximum " "block %04lX\n", lba, (info->capacity >> (info->pageshift + info->blockshift))-1); // FIXME: sense buffer? return USB_STOR_TRANSPORT_ERROR; } pba = info->lba_to_pba[lba]; // if pba is 0, either it's really 0, in which case // the pba-to-lba map for pba 0 will be the lba, // or that lba doesn't exist. if (pba==0 && info->pba_to_lba[0] != lba) { // FIXME: sense buffer? US_DEBUGP("Error: Requested LBA %04X has no physical block " "mapping.\n", lba); return USB_STOR_TRANSPORT_ERROR; } US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X" " pages %d\n", pba, lba, page, pages); return sddr09_read_data(us, ( (pba << info->blockshift) + page) << info->pageshift, pages, ptr, srb->use_sg); } // Pass TEST_UNIT_READY and REQUEST_SENSE through if (srb->cmnd[0] != TEST_UNIT_READY && srb->cmnd[0] != REQUEST_SENSE) return USB_STOR_TRANSPORT_ERROR; // FIXME: sense buffer? for (; srb->cmd_len<12; srb->cmd_len++) srb->cmnd[srb->cmd_len] = 0; srb->cmnd[1] = 0x20; string[0] = 0; for (i=0; i<12; i++) sprintf(string+strlen(string), "%02X ", srb->cmnd[i]); US_DEBUGP("SDDR09: Send control for command %s\n", string); if ( (result = sddr09_send_control(us, usb_sndctrlpipe(us->pusb_dev,0), 0, 0x41, 0, 0, srb->cmnd, 12)) != USB_STOR_TRANSPORT_GOOD) return result; US_DEBUGP("SDDR09: Control for command OK\n"); 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) { US_DEBUGP("SDDR09: %s %d bytes\n", srb->sc_data_direction==SCSI_DATA_WRITE ? "sending" : "receiving", srb->request_bufflen); result = sddr09_bulk_transport(us, srb->sc_data_direction, srb->request_buffer, srb->request_bufflen, srb->use_sg); return result; } return USB_STOR_TRANSPORT_GOOD;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -