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

📄 usb-storage.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Driver for USB Mass Storage compliant devices * * (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Further reference: *	This driver is based on the 'USB Mass Storage Class' document. This *	describes in detail the protocol used to communicate with such *      devices.  Clearly, the designers had SCSI commands in mind when they *      created this document.  The commands are all similar to commands *      in the SCSI-II specification. * *	It is important to note that in a number of cases this class exhibits *	class-specific exemptions from the USB specification. Notably the *	usage of NAK, STALL and ACK differs from the norm, in that they are *	used to communicate wait, failed and OK on commands. *	Also, for certain devices, the interrupt endpoint is used to convey *	status of a command. * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/random.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/malloc.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/usb.h>#include <linux/blk.h>#include "../scsi/scsi.h"#include "../scsi/hosts.h"#include "../scsi/sd.h"#include "usb-storage.h"#include "usb-storage-debug.h"/* * This is the size of the structure Scsi_Host_Template.  We create * an instance of this structure in this file and this is a check * to see if this structure may have changed within the SCSI module. * This is by no means foolproof, but it does help us some. */#define SCSI_HOST_TEMPLATE_SIZE			(104)/* direction table -- this indicates the direction of the data * transfer for each command code -- a 1 indicates input */unsigned char us_direction[256/8] = {	0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, 	0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 	0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};/* * Per device data */static int my_host_number;int usb_stor_debug = 1;struct us_data;typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*);typedef int (*trans_reset)(struct us_data*);typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);struct us_data {	struct us_data	*next;		         /* next device */	struct usb_device	*pusb_dev;       /* this usb_device */	unsigned int		flags;		 /* from filter initially */	__u8			ifnum;		 /* interface number */	__u8			ep_in;		 /* in endpoint */	__u8			ep_out;		 /* out ....... */	__u8			ep_int;		 /* interrupt . */	__u8			subclass;	 /* as in overview */	__u8			protocol;	 /* .............. */	__u8			attention_done;  /* force attn on first cmd */	trans_cmnd              transport;	 /* protocol specific do cmd */	trans_reset             transport_reset; /* .......... device reset */	proto_cmnd              proto_handler;   /* protocol handler */	GUID(guid);				 /* unique dev id */	struct Scsi_Host	*host;		 /* our dummy host data */	Scsi_Host_Template	*htmplt;	 /* own host template */	int			host_number;	 /* to find us */	int			host_no;	 /* allocated by scsi */	Scsi_Cmnd		*srb;		 /* current srb */	int			action;		 /* what to do */	wait_queue_head_t	waitq;		 /* thread waits */	wait_queue_head_t	ip_waitq;	 /* for CBI interrupts */	__u16			ip_data;	 /* interrupt data */	int			ip_wanted;	 /* needed */	int			pid;		 /* control thread */	struct semaphore	*notify;	 /* wait for thread to begin */	void			*irq_handle;	 /* for USB int requests */	unsigned int		irqpipe;	 /* pipe for release_irq */};/* * kernel thread actions */#define US_ACT_COMMAND		1#define US_ACT_ABORT		2#define US_ACT_DEVICE_RESET	3#define US_ACT_BUS_RESET	4#define US_ACT_HOST_RESET	5static struct us_data *us_list;static void * storage_probe(struct usb_device *dev, unsigned int ifnum);static void storage_disconnect(struct usb_device *dev, void *ptr);static struct usb_driver storage_driver = {	"usb-storage",	storage_probe,	storage_disconnect,	{ NULL, NULL }};/*********************************************************************** * Data transfer routines ***********************************************************************//* Transfer one buffer (breaking into packets if necessary) * Note that this function is necessary because if the device NAKs, we * need to know that information directly * * FIXME: is the above true?  Or will the URB status show ETIMEDOUT after * retrying several times allready?  Perhaps this is the way we should * be going anyway? */static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length){	int max_size;	int this_xfer;	int result;	int partial;	int maxtry;	/* determine the maximum packet size for these transfers */	max_size = usb_maxpacket(us->pusb_dev, 				 pipe, usb_pipeout(pipe)) * 16;	/* while we have data left to transfer */	while (length) {		/* calculate how long this will be -- maximum or a remainder */		this_xfer = length > max_size ? max_size : length;		length -= this_xfer;		/* FIXME: this number is totally outrageous.  We need to pick		 * a better (smaller) number).		 */		/* setup the retry counter */		maxtry = 100;		/* set up the transfer loop */		do {			/* transfer the data */			US_DEBUGP("Bulk xfer 0x%x(%d) try #%d\n", 				  (unsigned int)buf, this_xfer, 101 - maxtry);			result = usb_bulk_msg(us->pusb_dev, pipe, buf,					      this_xfer, &partial, HZ*5);			US_DEBUGP("bulk_msg returned %d xferred %d/%d\n",				  result, partial, this_xfer);			/* if we stall, we need to clear it before we go on */			if (result == -EPIPE) {				US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);				usb_clear_halt(us->pusb_dev, pipe);			}			/* update to show what data was transferred */			this_xfer -= partial;			buf += partial;			/* NAK - we retry a few times */			if (result == -ETIMEDOUT) {				US_DEBUGP("us_one_transfer: device NAKed\n");				/* if our try counter reaches 0, bail out */				if (!maxtry--)					return -ETIMEDOUT;				/* just continue the while loop */				continue;			}      			/* other errors (besides NAK) -- we just bail out*/			if (result != 0) {				US_DEBUGP("us_one_transfer: device returned error %d\n", result);				return result;			}			/* continue until this transfer is done */		} while ( this_xfer );	}	/* if we get here, we're done and successful */	return 0;}static unsigned int us_transfer_length(Scsi_Cmnd *srb);/* transfer one SCSI command, using scatter-gather if requested *//* FIXME: what do the return codes here mean? */static int us_transfer(Scsi_Cmnd *srb, int dir_in){	struct us_data *us = (struct us_data *)srb->host_scribble;	int i;	int result = -1;	unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :		usb_sndbulkpipe(us->pusb_dev, us->ep_out);	/* FIXME: stop transferring data at us_transfer_length(), not 	 * bufflen */	if (srb->use_sg) {		struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;		for (i = 0; i < srb->use_sg; i++) {			result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);			if (result)				break;		}	}	else		result = us_one_transfer(us, pipe, srb->request_buffer, 					 us_transfer_length(srb));	if (result < 0)		US_DEBUGP("us_transfer returning error %d\n", result);	return result;}/* calculate the length of the data transfer (not the command) for any * given SCSI command */static unsigned int us_transfer_length(Scsi_Cmnd *srb){	int i;	unsigned int total = 0;	/* always zero for some commands */	switch (srb->cmnd[0]) {	case SEEK_6:	case SEEK_10:	case REZERO_UNIT:	case ALLOW_MEDIUM_REMOVAL:	case START_STOP:	case TEST_UNIT_READY:		return 0;	case REQUEST_SENSE:	case INQUIRY:	case MODE_SENSE:		return srb->cmnd[4];	case LOG_SENSE:	case MODE_SENSE_10:		return (srb->cmnd[7] << 8) + srb->cmnd[8];	default:		break;	}	if (srb->use_sg) {		struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;		for (i = 0; i < srb->use_sg; i++) {			total += sg[i].length;		}		return total;	}	else		return srb->request_bufflen;}/*********************************************************************** * Protocol routines ***********************************************************************/static int CB_transport(Scsi_Cmnd *srb, struct us_data *us);static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us);static void ufi_command(Scsi_Cmnd *srb, struct us_data *us){	int old_cmnd = 0;  	/* fix some commands -- this is a form of mode translation	 * UFI devices only accept 12 byte long commands 	 *	 * NOTE: This only works because a Scsi_Cmnd struct field contains	 * a unsigned char cmnd[12], so we know we have storage available	 */	/* set command length to 12 bytes (this affects the transport layer) */	srb->cmd_len = 12;	/* determine the correct (or minimum) data length for these commands */	switch (us->srb->cmnd[0]) {		/* for INQUIRY, UFI devices only ever return 36 bytes */	case INQUIRY:		us->srb->cmnd[4] = 36;		break;		/* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */	case MODE_SENSE:	case MODE_SELECT:		/* save the command so we can tell what it was */		old_cmnd = srb->cmnd[0];		srb->cmnd[11] = 0;		srb->cmnd[10] = 0;		srb->cmnd[9] = 0;		/* if we're sending data, we send all.  If getting data, 		 * get the minimum */		if (srb->cmnd[0] == MODE_SELECT)			srb->cmnd[8] = srb->cmnd[4];		else			srb->cmnd[8] = 8;		srb->cmnd[7] = 0;		srb->cmnd[6] = 0;		srb->cmnd[5] = 0;		srb->cmnd[4] = 0;		srb->cmnd[3] = 0;		srb->cmnd[2] = srb->cmnd[2];		srb->cmnd[1] = srb->cmnd[1];		srb->cmnd[0] = srb->cmnd[0] | 0x40;		break;		/* again, for MODE_SENSE_10, we get the minimum (8) */	case MODE_SENSE_10:		us->srb->cmnd[7] = 0;		us->srb->cmnd[8] = 8;		break; 		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */	case REQUEST_SENSE:		us->srb->cmnd[4] = 18;		break;		/* change READ_6/WRITE_6 to READ_10/WRITE_10, which 		 * are UFI commands */	case WRITE_6:	case READ_6:		srb->cmnd[11] = 0;		srb->cmnd[10] = 0;		srb->cmnd[9] = 0;		srb->cmnd[8] = srb->cmnd[4];		srb->cmnd[7] = 0;		srb->cmnd[6] = 0;		srb->cmnd[5] = srb->cmnd[3];		srb->cmnd[4] = srb->cmnd[2];		srb->cmnd[3] = srb->cmnd[1] & 0x1F;		srb->cmnd[2] = 0;		srb->cmnd[1] = srb->cmnd[1] & 0xE0;		srb->cmnd[0] = srb->cmnd[0] | 0x20;		break;	} /* end switch on cmnd[0] */  	/* send the command to the transport layer */	us->srb->result = us->transport(srb, us);	/* if we have an error, we're going to do a 	 * REQUEST_SENSE automatically */	/* FIXME: we should only do this for device 	 * errors, not system errors */	if (us->srb->result) {		int temp_result;		int count;		void* old_request_buffer;		US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n");		/* set the result so the higher layers expect this data */		us->srb->result = CHECK_CONDITION;		us->srb->cmnd[0] = REQUEST_SENSE;		us->srb->cmnd[1] = 0;		us->srb->cmnd[2] = 0;		us->srb->cmnd[3] = 0;		us->srb->cmnd[4] = 18;		us->srb->cmnd[5] = 0;    		/* set the buffer length for transfer */		old_request_buffer = us->srb->request_buffer;		us->srb->request_bufflen = 18;		us->srb->request_buffer = kmalloc(18, GFP_KERNEL);		/* FIXME: what if this command fails? */		temp_result = us->transport(us->srb, us);		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);		/* copy the data from the request buffer to the sense buffer */		for(count = 0; count < 18; count++)			us->srb->sense_buffer[count] = 				((unsigned char *)(us->srb->request_buffer))[count];		US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",			  us->srb->sense_buffer[2] & 0xf,			  us->srb->sense_buffer[12], us->srb->sense_buffer[13]);		/* we're done here */		kfree(us->srb->request_buffer);		us->srb->request_buffer = old_request_buffer;		return;	}  	/* FIXME: if we need to send more data, or recieve data, we should	 * do it here.  Then, we can do status handling here also.	 *	 * This includes MODE_SENSE from above	 */	if (old_cmnd == MODE_SENSE) {		unsigned char *dta = (unsigned char *)us->srb->request_buffer;		/* calculate the new length */		int length = (dta[0] << 8) + dta[1] + 2;		/* copy the available data length into the structure */		us->srb->cmnd[7] = length >> 8;		us->srb->cmnd[8] = length & 0xFF;		/* send the command to the transport layer */		us->srb->result = us->transport(srb, us);		/* FIXME: this assumes that the 2nd attempt is always		 * successful convert MODE_SENSE_10 return data format 		 * to MODE_SENSE_6 format */		dta[0] = dta[1];	/* data len */		dta[1] = dta[2];	/* med type */		dta[2] = dta[3];	/* dev-spec prm */		dta[3] = dta[7];	/* block desc len */		printk (KERN_DEBUG USB_STORAGE			"new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n",			dta[0], dta[1], dta[2], dta[3]);	}	/* FIXME: if this was a TEST_UNIT_READY, and we get a NOT READY/	 * LOGICAL DRIVE NOT READY then we do a START_STOP, and retry 	 */	/* FIXME: here is where we need to fix-up the return data from 	 * an INQUIRY command to show ANSI SCSI rev 2	 */	/* FIXME: The rest of this is bogus.  usb_control_msg() will only	 * return an error if we've really honked things up.  If it just	 * needs a START_STOP, then we'll get some data back via 

⌨️ 快捷键说明

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