⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sddr09.c

📁 LINUX下USB驱动程序的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
 * the output stream by 64 bytes. * * count counts control groups of size (1 << controlshift). * For me, controlshift = 6. Is this constant? * * After getting one control group, jump to the next page * (fromaddress += 256). */static intsddr09_read23(struct us_data *us, unsigned long fromaddress,	      int count, int controlshift, unsigned char *buf, int use_sg) {	int bulklen = (count << controlshift);	return sddr09_readX(us, 3, fromaddress, count, bulklen,			    buf, use_sg);}#endif#if 0/* * Erase Command: 12 bytes. * byte 0: opcode: EA * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). *  * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored. * The byte address being erased is 2*Eaddress. */static intsddr09_erase(struct us_data *us, unsigned long Eaddress) {	unsigned char command[12] = {		0xea, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	int result;	command[6] = MSB_of(Eaddress>>16);	command[7] = LSB_of(Eaddress>>16);	command[8] = MSB_of(Eaddress & 0xFFFF);	command[9] = LSB_of(Eaddress & 0xFFFF);	result = sddr09_send_scsi_command(us, command, sizeof(command));	if (result != USB_STOR_TRANSPORT_GOOD)		US_DEBUGP("Result for send_control in sddr09_erase %d\n",			  result);	return result;}#endif/* * Write Command: 12 bytes. * byte 0: opcode: E9 * bytes 2-5: write address (big-endian, counting shorts, sector aligned). * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). * bytes 10-11: sector count (big-endian, in 512-byte sectors). * * If write address equals erase address, the erase is done first, * otherwise the write is done first. When erase address equals zero * no erase is done? */static intsddr09_writeX(struct us_data *us,	      unsigned long Waddress, unsigned long Eaddress,	      int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) {	unsigned char command[12] = {		0xe9, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	int result;	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, sizeof(command));	if (result != USB_STOR_TRANSPORT_GOOD) {		US_DEBUGP("Result for send_control in sddr09_writeX %d\n",			  result);		return result;	}	result = sddr09_bulk_transport(us, SCSI_DATA_WRITE,				       buf, bulklen, use_sg);	if (result != USB_STOR_TRANSPORT_GOOD)		US_DEBUGP("Result for bulk_transport in sddr09_writeX %d\n",			  result);	return result;}/* 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. */static intsddr09_read_sg_test_only(struct us_data *us) {	unsigned char command[15] = {		0xe7, 0x20, 0	};	int result, bulklen, nsg, ct;	unsigned char *buf;	unsigned long address;	nsg = bulklen = 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 = sddr09_bulk_transport(us, SCSI_DATA_READ,				       buf, bulklen, 0);	if (result != USB_STOR_TRANSPORT_GOOD)		US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n",			  result);	kfree(buf);	return result;}#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[12] = {		0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	unsigned char data[64];	int result;	US_DEBUGP("Reading status...\n");	result = sddr09_send_scsi_command(us, command, sizeof(command));	if (result != USB_STOR_TRANSPORT_GOOD)		return result;	result = sddr09_bulk_transport(us, SCSI_DATA_READ,				       data, sizeof(data), 0);	*status = data[0];	return result;}static intsddr09_read_data(struct us_data *us,		 unsigned long address,		 unsigned int sectors,		 unsigned char *content,		 int use_sg) {	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;	unsigned int lba, maxlba, pba;	unsigned int page, pages;	unsigned char *buffer = NULL;	unsigned char *ptr;	struct scatterlist *sg = NULL;	int result, i, len;	// If we're using scatter-gather, we have to create a new	// buffer to read all of the data in first, since a	// scatter-gather buffer could in theory start in the middle	// of a page, which would be bad. A developer who wants a	// challenge might want to write a limited-buffer	// version of this code.	len = sectors*info->pagesize;	if (use_sg) {		sg = (struct scatterlist *)content;		buffer = kmalloc(len, GFP_NOIO);		if (buffer == NULL)			return USB_STOR_TRANSPORT_ERROR;		ptr = buffer;	} else		ptr = content;	// 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;	while (sectors > 0) {		/* Find number of pages we can read in this block */		pages = info->blocksize - page;		if (pages > sectors)			pages = sectors;		/* 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(ptr, 0, pages << info->pageshift);		} 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, ptr, 0);			if (result != USB_STOR_TRANSPORT_GOOD)				break;		}		page = 0;		lba++;		sectors -= pages;		ptr += (pages << info->pageshift);	}	if (use_sg && result == USB_STOR_TRANSPORT_GOOD) {		int transferred = 0;		for (i=0; i<use_sg && transferred<len; i++) {			unsigned char *buf = sg[i].address;			unsigned int length;			length = len-transferred;			if (length > sg[i].length)				length = sg[i].length;			memcpy(buf, buffer+transferred, length);			transferred += sg[i].length;		}	}	if (use_sg)		kfree(buffer);	return result;}/* we never free blocks, so lastpba can only increase */static unsigned intsddr09_find_unused_pba(struct sddr09_card_info *info) {	static unsigned int lastpba = 1;	int numblocks = info->capacity >> (info->blockshift + info->pageshift);	int i;	for (i = lastpba+1; i < numblocks; i++) {		if (info->pba_to_lba[i] == UNDEF) {			lastpba = i;			return i;		}	}	return 0;}static intsddr09_write_lba(struct us_data *us, unsigned int lba,		 unsigned int page, unsigned int pages,		 unsigned char *ptr) {	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;	unsigned long address;	unsigned int pba, lbap;	unsigned int pagelen, blocklen;	unsigned char *blockbuffer, *bptr, *cptr, *xptr;	unsigned char ecc[3];	int i, result;	lbap = ((lba & 0x3ff) << 1) | 0x1000;	if (parity[MSB_of(lbap) ^ LSB_of(lbap)])		lbap ^= 1;	pba = info->lba_to_pba[lba];	if (pba == UNDEF) {		pba = sddr09_find_unused_pba(info);		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;	}	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);	blocklen = (pagelen << info->blockshift);	blockbuffer = kmalloc(blocklen, GFP_NOIO);	if (!blockbuffer) {		printk("sddr09_write_lba: Out of memory\n");		return USB_STOR_TRANSPORT_ERROR;	}	/* 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)		goto err;	/* check old contents */	for (i = 0; i < info->blockshift; 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);		}	}	/* 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);		cptr[6] = cptr[11] = MSB_of(lbap);		cptr[7] = cptr[12] = LSB_of(lbap);	}	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 err:	kfree(blockbuffer);	/* TODO: instead of doing kmalloc/kfree for each block,	   add a bufferpointer to the info structure */	return result;}static intsddr09_write_data(struct us_data *us,		  unsigned long address,		  unsigned int sectors,		  unsigned char *content,		  int use_sg) {	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;	unsigned int lba, page, pages;	unsigned char *buffer = NULL;	unsigned char *ptr;	struct scatterlist *sg = NULL;	int result, i, len;	// If we're using scatter-gather, we have to create a new	// buffer to write all of the data in first, since a	// scatter-gather buffer could in theory start in the middle	// of a page, which would be bad. A developer who wants a	// challenge might want to write a limited-buffer	// version of this code.	len = sectors*info->pagesize;	if (use_sg) {		int transferred = 0;		sg = (struct scatterlist *)content;		buffer = kmalloc(len, GFP_NOIO);		if (buffer == NULL)			return USB_STOR_TRANSPORT_ERROR;		for (i=0; i<use_sg && transferred<len; i++) {			memcpy(buffer+transferred,			       sg[i].address,			       len-transferred > sg[i].length ?			        sg[i].length : len-transferred);			transferred += sg[i].length;		}		ptr = buffer;	} else		ptr = content;	// Figure out the initial LBA and page	lba = address >> info->blockshift;	page = (address & info->blockmask);	// This could be made much more efficient by checking for	// contiguous LBA's. Another exercise left to the student.	result = USB_STOR_TRANSPORT_GOOD;	while (sectors > 0) {		// Write as many sectors as possible in this block		pages = info->blocksize - page;		if (pages > sectors)			pages = sectors;		result = sddr09_write_lba(us, lba, page, pages, ptr);		if (result != USB_STOR_TRANSPORT_GOOD)			break;		page = 0;		lba++;		sectors -= pages;		ptr += (pages << info->pageshift);	}	if (use_sg)		kfree(buffer);	return result;}int sddr09_read_control(struct us_data *us,		unsigned long address,		unsigned int blocks,		unsigned char *content,		int use_sg) {	US_DEBUGP("Read control address %08lX blocks %04X\n",		address, blocks);	return sddr09_read21(us, address, blocks, CONTROL_SHIFT, content, use_sg);}static intsddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {/* * 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. */	unsigned char command[12] = {		0xed, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	};	unsigned char content[64];	int result, i;	result = sddr09_send_scsi_command(us, command, sizeof(command));	if (result != USB_STOR_TRANSPORT_GOOD)		return result;	result = sddr09_bulk_transport(us, SCSI_DATA_READ, content, 64, 0);	for (i = 0; i < 4; i++)		deviceID[i] = content[i];	return result;}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 %02X", status);	if ((status & 0x80) == 0) {		info->flags |= SDDR09_WP;	/* write protected */		US_DEBUGP(" WP");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -