📄 sddr09.c
字号:
command[0] = 0xE9; command[1] = LUNBITS; command[2] = MSB_of(Waddress>>16); command[3] = LSB_of(Waddress>>16); command[4] = MSB_of(Waddress & 0xFFFF); command[5] = LSB_of(Waddress & 0xFFFF); command[6] = MSB_of(Eaddress>>16); command[7] = LSB_of(Eaddress>>16); command[8] = MSB_of(Eaddress & 0xFFFF); command[9] = LSB_of(Eaddress & 0xFFFF); command[10] = MSB_of(nr_of_pages); command[11] = LSB_of(nr_of_pages); 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); return result; } result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, 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; } return USB_STOR_TRANSPORT_GOOD;}/* erase address, write same address */static intsddr09_write_inplace(struct us_data *us, unsigned long address, int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); return sddr09_writeX(us, address, address, nr_of_pages, bulklen, buf, use_sg);}#if 0/* * Read Scatter Gather Command: 3+4n bytes. * byte 0: opcode E7 * byte 2: n * bytes 4i-1,4i,4i+1: page address * byte 4i+2: page count * (i=1..n) * * This reads several pages from the card to a single memory buffer. * The last two bits of byte 1 have the same meaning as for E8. */static intsddr09_read_sg_test_only(struct us_data *us) { unsigned char *command = us->iobuf; int result, bulklen, nsg, ct; unsigned char *buf; unsigned long address; nsg = bulklen = 0; command[0] = 0xE7; command[1] = LUNBITS; command[2] = 0; address = 040000; ct = 1; nsg++; bulklen += (ct << 9); command[4*nsg+2] = ct; command[4*nsg+1] = ((address >> 9) & 0xFF); command[4*nsg+0] = ((address >> 17) & 0xFF); command[4*nsg-1] = ((address >> 25) & 0xFF); address = 0340000; ct = 1; nsg++; bulklen += (ct << 9); command[4*nsg+2] = ct; command[4*nsg+1] = ((address >> 9) & 0xFF); command[4*nsg+0] = ((address >> 17) & 0xFF); command[4*nsg-1] = ((address >> 25) & 0xFF); address = 01000000; ct = 2; nsg++; bulklen += (ct << 9); command[4*nsg+2] = ct; command[4*nsg+1] = ((address >> 9) & 0xFF); command[4*nsg+0] = ((address >> 17) & 0xFF); command[4*nsg-1] = ((address >> 25) & 0xFF); command[2] = nsg; 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); return result; } buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO); if (!buf) return USB_STOR_TRANSPORT_ERROR; 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; } return USB_STOR_TRANSPORT_GOOD;}#endif/* * Read Status Command: 12 bytes. * byte 0: opcode: EC * * Returns 64 bytes, all zero except for the first. * bit 0: 1: Error * bit 5: 1: Suspended * bit 6: 1: Ready * bit 7: 1: Not write-protected */static intsddr09_read_status(struct us_data *us, unsigned char *status) { unsigned char *command = us->iobuf; unsigned char *data = us->iobuf; int result; US_DEBUGP("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) 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);}static intsddr09_read_data(struct us_data *us, unsigned long address, unsigned int sectors) { struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; unsigned char *buffer; unsigned int lba, maxlba, pba; unsigned int page, pages; unsigned int len, index, offset; int result; // 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. 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; } // 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; while (sectors > 0) { /* Find number of pages we can read in this block */ 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 = USB_STOR_TRANSPORT_ERROR; break; } /* Find where this lba lives on disk */ pba = info->lba_to_pba[lba]; if (pba == UNDEF) { /* this lba was never written */ US_DEBUGP("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 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); address = ((pba << info->blockshift) + page) << info->pageshift; result = sddr09_read20(us, address>>1, pages, info->pageshift, buffer, 0); if (result != USB_STOR_TRANSPORT_GOOD) break; } // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, &index, &offset, TO_XFER_BUF); page = 0; lba++; sectors -= pages; } kfree(buffer); return result;}static unsigned intsddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) { static unsigned int lastpba = 1; 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 < end; i++) { if (info->pba_to_lba[zonestart+i] == UNDEF) { lastpba = 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;}static intsddr09_write_lba(struct us_data *us, unsigned int lba, unsigned int page, unsigned int pages, unsigned char *ptr, unsigned char *blockbuffer) { struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; unsigned long address; unsigned int pba, lbap; unsigned int pagelen; unsigned char *bptr, *cptr, *xptr; unsigned char ecc[3]; int i, result, isnew; 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, 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) { /* 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; } pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); /* read old contents */ address = (pba << (info->pageshift + info->blockshift)); result = sddr09_read22(us, address>>1, info->blocksize, info->pageshift, blockbuffer, 0); if (result != USB_STOR_TRANSPORT_GOOD) return result; /* 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); if (!nand_compare_ecc(cptr+13, ecc)) { US_DEBUGP("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); 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 */ xptr = ptr; for (i = page; i < page+pages; i++) { bptr = blockbuffer + i*pagelen; cptr = bptr + info->pagesize; memcpy(bptr, xptr, info->pagesize); xptr += info->pagesize; nand_compute_ecc(bptr, ecc); nand_store_ecc(cptr+13, ecc); nand_compute_ecc(bptr+(info->pagesize / 2), ecc); nand_store_ecc(cptr+8, ecc); } US_DEBUGP("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);#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"); else if (status != 0xc0) US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n", status); }#endif#if 0 { int result2 = sddr09_test_unit_ready(us); }#endif return result;}static intsddr09_write_data(struct us_data *us, unsigned long address, unsigned int sectors) { struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; unsigned int lba, page, pages; unsigned int pagelen, blocklen; unsigned char *blockbuffer; unsigned char *buffer; unsigned int len, index, offset; int result; // blockbuffer is used for reading in the old data, overwriting // with the new data, and performing ECC calculations /* TODO: instead of doing kmalloc/kfree for each write, add a bufferpointer to the info structure */ pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); blocklen = (pagelen << info->blockshift); blockbuffer = kmalloc(blocklen, GFP_NOIO); if (!blockbuffer) { printk("sddr09_write_data: Out of memory\n"); return USB_STOR_TRANSPORT_ERROR; } // Since we don't write the user data directly to the device, // 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. 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"); kfree(blockbuffer); return USB_STOR_TRANSPORT_ERROR; } // Figure out the initial LBA and page lba = address >> info->blockshift; page = (address & info->blockmask); result = USB_STOR_TRANSPORT_GOOD; index = offset = 0; while (sectors > 0) { // Write as many sectors as possible in this block pages = min(sectors, info->blocksize - page); len = (pages << info->pageshift); // 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) break; page = 0; lba++; sectors -= pages; } kfree(buffer); kfree(blockbuffer); return result;}static intsddr09_read_control(struct us_data *us, unsigned long address, unsigned int blocks, unsigned char *content, int use_sg) { US_DEBUGP("Read control address %lu, blocks %d\n", address, blocks); return sddr09_read21(us, address, blocks, CONTROL_SHIFT, content, use_sg);}/* * Read Device ID Command: 12 bytes. * byte 0: opcode: ED * * Returns 2 bytes: Manufacturer ID and Device ID. * On more recent cards 3 bytes: the third byte is an option code A5 * signifying that the secret command to read an 128-bit ID is available. * On still more recent cards 4 bytes: the fourth byte C0 means that * a second read ID cmd is available. */static intsddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { unsigned char *command = us->iobuf; unsigned char *content = us->iobuf; int result, i; memset(command, 0, 12); command[0] = 0xED; command[1] = LUNBITS; result = sddr09_send_scsi_command(us, command, 12); if (result != USB_STOR_TRANSPORT_GOOD) return result; result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, content, 64, NULL); for (i = 0; i < 4; i++) deviceID[i] = content[i]; return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);}static intsddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) { int result; unsigned char status; result = sddr09_read_status(us, &status); if (result != USB_STOR_TRANSPORT_GOOD) { US_DEBUGP("sddr09_get_wp: read_status fails\n"); return result; } US_DEBUGP("sddr09_get_wp: status 0x%02X", status); if ((status & 0x80) == 0) { info->flags |= SDDR09_WP; /* write protected */ US_DEBUGP(" WP"); } if (status & 0x40) US_DEBUGP(" Ready"); if (status & LUNBITS) US_DEBUGP(" Suspended"); if (status & 0x1) US_DEBUGP(" Error"); US_DEBUGP("\n"); return USB_STOR_TRANSPORT_GOOD;}#if 0/* * Reset Command: 12 bytes. * byte 0: opcode: EB */static intsddr09_reset(struct us_data *us) { unsigned char *command = us->iobuf; memset(command, 0, 12); command[0] = 0xEB; command[1] = LUNBITS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -