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

📄 alauda.c

📁 LINUX下USB驱动程序的开发
💻 C
📖 第 1 页 / 共 2 页
字号:
error:	kfree(lba_to_pba);	kfree(pba_to_lba);out:	return result;}/* * Checks to see whether we have already mapped a certain zone * If we haven't, the map is generated */static void alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone){	if (MEDIA_INFO(us).lba_to_pba[zone] == NULL		|| MEDIA_INFO(us).pba_to_lba[zone] == NULL)		alauda_read_map(us, zone);}/* * Erases an entire block */static int alauda_erase_block(struct us_data *us, u16 pba){	int rc;	unsigned char command[] = {		ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),		PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, MEDIA_PORT(us)	};	unsigned char buf[2];	US_DEBUGP("alauda_erase_block: Erasing PBA %d\n", pba);	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,		command, 9, NULL);	if (rc != USB_STOR_XFER_GOOD)		return rc;	rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,		buf, 2, NULL);	if (rc != USB_STOR_XFER_GOOD)		return rc;	US_DEBUGP("alauda_erase_block: Erase result: %02X %02X\n",		buf[0], buf[1]);	return rc;}/* * Reads data from a certain offset page inside a PBA, including interleaved * redundancy data. Returns (pagesize+64)*pages bytes in data. */static int alauda_read_block_raw(struct us_data *us, u16 pba,		unsigned int page, unsigned int pages, unsigned char *data){	int rc;	unsigned char command[] = {		ALAUDA_BULK_CMD, ALAUDA_BULK_READ_BLOCK, PBA_HI(pba),		PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us)	};	US_DEBUGP("alauda_read_block: pba %d page %d count %d\n",		pba, page, pages);	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,		command, 9, NULL);	if (rc != USB_STOR_XFER_GOOD)		return rc;	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,		data, (MEDIA_INFO(us).pagesize + 64) * pages, NULL);}/* * Reads data from a certain offset page inside a PBA, excluding redundancy * data. Returns pagesize*pages bytes in data. Note that data must be big enough * to hold (pagesize+64)*pages bytes of data, but you can ignore those 'extra' * trailing bytes outside this function. */static int alauda_read_block(struct us_data *us, u16 pba,		unsigned int page, unsigned int pages, unsigned char *data){	int i, rc;	unsigned int pagesize = MEDIA_INFO(us).pagesize;	rc = alauda_read_block_raw(us, pba, page, pages, data);	if (rc != USB_STOR_XFER_GOOD)		return rc;	/* Cut out the redundancy data */	for (i = 0; i < pages; i++) {		int dest_offset = i * pagesize;		int src_offset = i * (pagesize + 64);		memmove(data + dest_offset, data + src_offset, pagesize);	}	return rc;}/* * Writes an entire block of data and checks status after write. * Redundancy data must be already included in data. Data should be * (pagesize+64)*blocksize bytes in length. */static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data){	int rc;	struct alauda_info *info = (struct alauda_info *) us->extra;	unsigned char command[] = {		ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_BLOCK, PBA_HI(pba),		PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us)	};	US_DEBUGP("alauda_write_block: pba %d\n", pba);	rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,		command, 9, NULL);	if (rc != USB_STOR_XFER_GOOD)		return rc;	rc = usb_stor_bulk_transfer_buf(us, info->wr_ep, data,		(MEDIA_INFO(us).pagesize + 64) * MEDIA_INFO(us).blocksize,		NULL);	if (rc != USB_STOR_XFER_GOOD)		return rc;	return alauda_check_status2(us);}/* * Write some data to a specific LBA. */static int alauda_write_lba(struct us_data *us, u16 lba,		 unsigned int page, unsigned int pages,		 unsigned char *ptr, unsigned char *blockbuffer){	u16 pba, lbap, new_pba;	unsigned char *bptr, *cptr, *xptr;	unsigned char ecc[3];	int i, result;	unsigned int uzonesize = MEDIA_INFO(us).uzonesize;	unsigned int zonesize = MEDIA_INFO(us).zonesize;	unsigned int pagesize = MEDIA_INFO(us).pagesize;	unsigned int blocksize = MEDIA_INFO(us).blocksize;	unsigned int lba_offset = lba % uzonesize;	unsigned int new_pba_offset;	unsigned int zone = lba / uzonesize;	alauda_ensure_map_for_zone(us, zone);	pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];	if (pba == 1) {		/* Maybe it is impossible to write to PBA 1.		   Fake success, but don't do anything. */		printk("alauda_write_lba: avoid writing to pba 1\n");		return USB_STOR_TRANSPORT_GOOD;	}	new_pba = alauda_find_unused_pba(&MEDIA_INFO(us), zone);	if (!new_pba) {		printk("alauda_write_lba: Out of unused blocks\n");		return USB_STOR_TRANSPORT_ERROR;	}	/* read old contents */	if (pba != UNDEF) {		result = alauda_read_block_raw(us, pba, 0,			blocksize, blockbuffer);		if (result != USB_STOR_XFER_GOOD)			return result;	} else {		memset(blockbuffer, 0, blocksize * (pagesize + 64));	}	lbap = (lba_offset << 1) | 0x1000;	if (parity[MSB_of(lbap) ^ LSB_of(lbap)])		lbap ^= 1;	/* check old contents and fill lba */	for (i = 0; i < blocksize; i++) {		bptr = blockbuffer + (i * (pagesize + 64));		cptr = bptr + 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 + (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 * (pagesize + 64));		cptr = bptr + pagesize;		memcpy(bptr, xptr, pagesize);		xptr += pagesize;		nand_compute_ecc(bptr, ecc);		nand_store_ecc(cptr+13, ecc);		nand_compute_ecc(bptr + (pagesize / 2), ecc);		nand_store_ecc(cptr+8, ecc);	}	result = alauda_write_block(us, new_pba, blockbuffer);	if (result != USB_STOR_XFER_GOOD)		return result;	new_pba_offset = new_pba - (zone * zonesize);	MEDIA_INFO(us).pba_to_lba[zone][new_pba_offset] = lba;	MEDIA_INFO(us).lba_to_pba[zone][lba_offset] = new_pba;	US_DEBUGP("alauda_write_lba: Remapped LBA %d to PBA %d\n",		lba, new_pba);	if (pba != UNDEF) {		unsigned int pba_offset = pba - (zone * zonesize);		result = alauda_erase_block(us, pba);		if (result != USB_STOR_XFER_GOOD)			return result;		MEDIA_INFO(us).pba_to_lba[zone][pba_offset] = UNDEF;	}	return USB_STOR_TRANSPORT_GOOD;}/* * Read data from a specific sector address */static int alauda_read_data(struct us_data *us, unsigned long address,		unsigned int sectors){	unsigned char *buffer;	u16 lba, max_lba;	unsigned int page, len, index, offset;	unsigned int blockshift = MEDIA_INFO(us).blockshift;	unsigned int pageshift = MEDIA_INFO(us).pageshift;	unsigned int blocksize = MEDIA_INFO(us).blocksize;	unsigned int pagesize = MEDIA_INFO(us).pagesize;	unsigned int uzonesize = MEDIA_INFO(us).uzonesize;	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.	 * We make this buffer big enough to hold temporary redundancy data,	 * which we use when reading the data blocks.	 */	len = min(sectors, blocksize) * (pagesize + 64);	buffer = kmalloc(len, GFP_NOIO);	if (buffer == NULL) {		printk("alauda_read_data: Out of memory\n");		return USB_STOR_TRANSPORT_ERROR;	}	/* Figure out the initial LBA and page */	lba = address >> blockshift;	page = (address & MEDIA_INFO(us).blockmask);	max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift);	result = USB_STOR_TRANSPORT_GOOD;	index = offset = 0;	while (sectors > 0) {		unsigned int zone = lba / uzonesize; /* integer division */		unsigned int lba_offset = lba - (zone * uzonesize);		unsigned int pages;		u16 pba;		alauda_ensure_map_for_zone(us, zone);		/* Not overflowing capacity? */		if (lba >= max_lba) {			US_DEBUGP("Error: Requested lba %u exceeds "				  "maximum %u\n", lba, max_lba);			result = USB_STOR_TRANSPORT_ERROR;			break;		}		/* Find number of pages we can read in this block */		pages = min(sectors, blocksize - page);		len = pages << pageshift;		/* Find where this lba lives on disk */		pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset];		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);			result = alauda_read_block(us, pba, page, pages, buffer);			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;}/* * Write data to a specific sector address */static int alauda_write_data(struct us_data *us, unsigned long address,		unsigned int sectors){	unsigned char *buffer, *blockbuffer;	unsigned int page, len, index, offset;	unsigned int blockshift = MEDIA_INFO(us).blockshift;	unsigned int pageshift = MEDIA_INFO(us).pageshift;	unsigned int blocksize = MEDIA_INFO(us).blocksize;	unsigned int pagesize = MEDIA_INFO(us).pagesize;	u16 lba, max_lba;	int result;	/*	 * 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, blocksize) * pagesize;	buffer = kmalloc(len, GFP_NOIO);	if (buffer == NULL) {		printk("alauda_write_data: Out of memory\n");		return USB_STOR_TRANSPORT_ERROR;	}	/*	 * We also need a temporary block buffer, where we read in the old data,	 * overwrite parts with the new data, and manipulate the redundancy data	 */	blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO);	if (blockbuffer == NULL) {		printk("alauda_write_data: Out of memory\n");		kfree(buffer);		return USB_STOR_TRANSPORT_ERROR;	}	/* Figure out the initial LBA and page */	lba = address >> blockshift;	page = (address & MEDIA_INFO(us).blockmask);	max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift);	result = USB_STOR_TRANSPORT_GOOD;	index = offset = 0;	while (sectors > 0) {		/* Write as many sectors as possible in this block */		unsigned int pages = min(sectors, blocksize - page);		len = pages << pageshift;		/* Not overflowing capacity? */		if (lba >= max_lba) {			US_DEBUGP("alauda_write_data: Requested lba %u exceeds "				  "maximum %u\n", lba, max_lba);			result = USB_STOR_TRANSPORT_ERROR;			break;		}		/* Get the data from the transfer buffer */		usb_stor_access_xfer_buf(buffer, len, us->srb,				&index, &offset, FROM_XFER_BUF);		result = alauda_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;}/* * Our interface with the rest of the world */static void alauda_info_destructor(void *extra){	struct alauda_info *info = (struct alauda_info *) extra;	int port;	if (!info)		return;	for (port = 0; port < 2; port++) {		struct alauda_media_info *media_info = &info->port[port];		alauda_free_maps(media_info);		kfree(media_info->lba_to_pba);		kfree(media_info->pba_to_lba);	}}/* * Initialize alauda_info struct and find the data-write endpoint */int init_alauda(struct us_data *us){	struct alauda_info *info;	struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting;	nand_init_ecc();	us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO);	if (!us->extra) {		US_DEBUGP("init_alauda: Gah! Can't allocate storage for"			"alauda info struct!\n");		return USB_STOR_TRANSPORT_ERROR;	}	info = (struct alauda_info *) us->extra;	us->extra_destructor = alauda_info_destructor;	info->wr_ep = usb_sndbulkpipe(us->pusb_dev,		altsetting->endpoint[0].desc.bEndpointAddress		& USB_ENDPOINT_NUMBER_MASK);	return USB_STOR_TRANSPORT_GOOD;}int alauda_transport(struct scsi_cmnd *srb, struct us_data *us){	int rc;	struct alauda_info *info = (struct alauda_info *) us->extra;	unsigned char *ptr = us->iobuf;	static unsigned char inquiry_response[36] = {		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00	};	if (srb->cmnd[0] == INQUIRY) {		US_DEBUGP("alauda_transport: INQUIRY. "			"Returning bogus response.\n");		memcpy(ptr, inquiry_response, sizeof(inquiry_response));		fill_inquiry_response(us, ptr, 36);		return USB_STOR_TRANSPORT_GOOD;	}	if (srb->cmnd[0] == TEST_UNIT_READY) {		US_DEBUGP("alauda_transport: TEST_UNIT_READY.\n");		return alauda_check_media(us);	}	if (srb->cmnd[0] == READ_CAPACITY) {		unsigned int num_zones;		unsigned long capacity;		rc = alauda_check_media(us);		if (rc != USB_STOR_TRANSPORT_GOOD)			return rc;		num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift			+ MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift);		capacity = num_zones * MEDIA_INFO(us).uzonesize			* MEDIA_INFO(us).blocksize;		/* Report capacity and page size */		((__be32 *) ptr)[0] = cpu_to_be32(capacity - 1);		((__be32 *) ptr)[1] = cpu_to_be32(512);		usb_stor_set_xfer_buf(ptr, 8, srb);		return USB_STOR_TRANSPORT_GOOD;	}	if (srb->cmnd[0] == READ_10) {		unsigned int page, pages;		rc = alauda_check_media(us);		if (rc != USB_STOR_TRANSPORT_GOOD)			return rc;		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]);		US_DEBUGP("alauda_transport: READ_10: page %d pagect %d\n",			  page, pages);		return alauda_read_data(us, page, pages);	}	if (srb->cmnd[0] == WRITE_10) {		unsigned int page, pages;		rc = alauda_check_media(us);		if (rc != USB_STOR_TRANSPORT_GOOD)			return rc;		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]);		US_DEBUGP("alauda_transport: WRITE_10: page %d pagect %d\n",			  page, pages);		return alauda_write_data(us, page, pages);	}	if (srb->cmnd[0] == REQUEST_SENSE) {		US_DEBUGP("alauda_transport: REQUEST_SENSE.\n");		memset(ptr, 0, 18);		ptr[0] = 0xF0;		ptr[2] = info->sense_key;		ptr[7] = 11;		ptr[12] = info->sense_asc;		ptr[13] = info->sense_ascq;		usb_stor_set_xfer_buf(ptr, 18, srb);		return USB_STOR_TRANSPORT_GOOD;	}	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {		/* sure.  whatever.  not like we can stop the user from popping		   the media out of the device (no locking doors, etc) */		return USB_STOR_TRANSPORT_GOOD;	}	US_DEBUGP("alauda_transport: Gah! Unknown command: %d (0x%x)\n",		srb->cmnd[0], srb->cmnd[0]);	info->sense_key = 0x05;	info->sense_asc = 0x20;	info->sense_ascq = 0x00;	return USB_STOR_TRANSPORT_FAILED;}

⌨️ 快捷键说明

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