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

📄 transport.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	up(&(us->current_urb_sem));	wait_for_completion(&urb_done);	down(&(us->current_urb_sem));	/* return the actual length of the data transferred if no error*/	status = us->current_urb->status;	if (status >= 0)		status = us->current_urb->actual_length;	/* release the lock and return status */	up(&(us->current_urb_sem));	kfree(dr);  	return status;}/* This is our function to emulate usb_bulk_msg() but give us enough * access to make aborts/resets work */int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,		      unsigned int len, unsigned int *act_len){	struct completion urb_done;	int status;	/* set up data structures for the wakeup system */	init_completion(&urb_done);	/* lock the URB */	down(&(us->current_urb_sem));	/* fill the URB */	FILL_BULK_URB(us->current_urb, us->pusb_dev, pipe, data, len,		      usb_stor_blocking_completion, &urb_done);	us->current_urb->actual_length = 0;	us->current_urb->error_count = 0;	us->current_urb->transfer_flags = USB_ASYNC_UNLINK;	/* submit the URB */	status = usb_submit_urb(us->current_urb);	if (status) {		/* something went wrong */		up(&(us->current_urb_sem));		return status;	}	/* wait for the completion of the URB */	up(&(us->current_urb_sem));	wait_for_completion(&urb_done);	down(&(us->current_urb_sem));	/* return the actual length of the data transferred */	*act_len = us->current_urb->actual_length;	/* release the lock and return status */	up(&(us->current_urb_sem));	return us->current_urb->status;}/* * Transfer one SCSI scatter-gather buffer via bulk transfer * * Note that this function is necessary because we want the ability to * use scatter-gather memory.  Good performance is achieved by a combination * of scatter-gather and clustering (which makes each chunk bigger). * * Note that the lower layer will always retry when a NAK occurs, up to the * timeout limit.  Thus we don't have to worry about it for individual * packets. */int usb_stor_transfer_partial(struct us_data *us, char *buf, int length){	int result;	int partial;	int pipe;	/* calculate the appropriate pipe information */	if (us->srb->sc_data_direction == SCSI_DATA_READ)		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);	else		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);	/* transfer the data */	US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length);	result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);	US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",		  result, partial, length);	/* 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_stor_clear_halt(us->pusb_dev, pipe);	}	/* did we send all the data? */	if (partial == length) {		US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n");		return US_BULK_TRANSFER_GOOD;	}	/* uh oh... we have an error code, so something went wrong. */	if (result) {		/* NAK - that means we've retried a few times already */		if (result == -ETIMEDOUT) {			US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");			return US_BULK_TRANSFER_FAILED;		}		/* -ENOENT -- we canceled this transfer */		if (result == -ENOENT) {			US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");			return US_BULK_TRANSFER_ABORTED;		}		/* the catch-all case */		US_DEBUGP("usb_stor_transfer_partial(): unknown error\n");		return US_BULK_TRANSFER_FAILED;	}	/* no error code, so we must have transferred some data, 	 * just not all of it */	return US_BULK_TRANSFER_SHORT;}/* * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately.  For now, it also re-interprets the error codes. */void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us){	int i;	int result = -1;	struct scatterlist *sg;	unsigned int total_transferred = 0;	unsigned int transfer_amount;	/* calculate how much we want to transfer */	transfer_amount = usb_stor_transfer_length(srb);	/* was someone foolish enough to request more data than available	 * buffer space? */	if (transfer_amount > srb->request_bufflen)		transfer_amount = srb->request_bufflen;	/* are we scatter-gathering? */	if (srb->use_sg) {		/* loop over all the scatter gather structures and 		 * make the appropriate requests for each, until done		 */		sg = (struct scatterlist *) srb->request_buffer;		for (i = 0; i < srb->use_sg; i++) {			/* transfer the lesser of the next buffer or the			 * remaining data */			if (transfer_amount - total_transferred >= 					sg[i].length) {				result = usb_stor_transfer_partial(us,						sg[i].address, sg[i].length);				total_transferred += sg[i].length;			} else				result = usb_stor_transfer_partial(us,						sg[i].address,						transfer_amount - total_transferred);			/* if we get an error, end the loop here */			if (result)				break;		}	}	else		/* no scatter-gather, just make the request */		result = usb_stor_transfer_partial(us, srb->request_buffer, 					     transfer_amount);	/* return the result in the data structure itself */	srb->result = result;}/*********************************************************************** * Transport routines ***********************************************************************//* Invoke the transport and basic error-handling/recovery methods * * This is used by the protocol layers to actually send the message to * the device and recieve the response. */void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us){	int need_auto_sense;	int result;	/* send the command to the transport layer */	result = us->transport(srb, us);	/* if the command gets aborted by the higher layers, we need to	 * short-circuit all other processing	 */	if (result == USB_STOR_TRANSPORT_ABORTED) {		US_DEBUGP("-- transport indicates command was aborted\n");		srb->result = DID_ABORT << 16;		return;	}	/* Determine if we need to auto-sense	 *	 * I normally don't use a flag like this, but it's almost impossible	 * to understand what's going on here if I don't.	 */	need_auto_sense = 0;	/*	 * If we're running the CB transport, which is incapable	 * of determining status on it's own, we need to auto-sense almost	 * every time.	 */	if (us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) {		US_DEBUGP("-- CB transport device requiring auto-sense\n");		need_auto_sense = 1;		/* There are some exceptions to this.  Notably, if this is		 * a UFI device and the command is REQUEST_SENSE or INQUIRY,		 * then it is impossible to truly determine status.		 */		if (us->subclass == US_SC_UFI &&		    ((srb->cmnd[0] == REQUEST_SENSE) ||		     (srb->cmnd[0] == INQUIRY))) {			US_DEBUGP("** no auto-sense for a special command\n");			need_auto_sense = 0;		}	}	/*	 * If we have an error, we're going to do a REQUEST_SENSE 	 * automatically.  Note that we differentiate between a command	 * "failure" and an "error" in the transport mechanism.	 */	if (result == USB_STOR_TRANSPORT_FAILED) {		US_DEBUGP("-- transport indicates command failure\n");		need_auto_sense = 1;	}	if (result == USB_STOR_TRANSPORT_ERROR) {		us->transport_reset(us);		US_DEBUGP("-- transport indicates transport failure\n");		need_auto_sense = 0;		srb->result = DID_ERROR << 16;		return;	}	/*	 * Also, if we have a short transfer on a command that can't have	 * a short transfer, we're going to do this.	 */	if ((srb->result == US_BULK_TRANSFER_SHORT) &&	    !((srb->cmnd[0] == REQUEST_SENSE) ||	      (srb->cmnd[0] == INQUIRY) ||	      (srb->cmnd[0] == MODE_SENSE) ||	      (srb->cmnd[0] == LOG_SENSE) ||	      (srb->cmnd[0] == MODE_SENSE_10))) {		US_DEBUGP("-- unexpectedly short transfer\n");		need_auto_sense = 1;	}	/* Now, if we need to do the auto-sense, let's do it */	if (need_auto_sense) {		int temp_result;		void* old_request_buffer;		unsigned short old_sg;		unsigned old_request_bufflen;		unsigned char old_sc_data_direction;		unsigned char old_cmnd[MAX_COMMAND_SIZE];		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");		/* save the old command */		memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);		/* set the command and the LUN */		srb->cmnd[0] = REQUEST_SENSE;		srb->cmnd[1] = old_cmnd[1] & 0xE0;		srb->cmnd[2] = 0;		srb->cmnd[3] = 0;		srb->cmnd[4] = 18;		srb->cmnd[5] = 0;		/* set the transfer direction */		old_sc_data_direction = srb->sc_data_direction;		srb->sc_data_direction = SCSI_DATA_READ;		/* use the new buffer we have */		old_request_buffer = srb->request_buffer;		srb->request_buffer = srb->sense_buffer;		/* set the buffer length for transfer */		old_request_bufflen = srb->request_bufflen;		srb->request_bufflen = 18;		/* set up for no scatter-gather use */		old_sg = srb->use_sg;		srb->use_sg = 0;		/* issue the auto-sense command */		temp_result = us->transport(us->srb, us);		if (temp_result != USB_STOR_TRANSPORT_GOOD) {			US_DEBUGP("-- auto-sense failure\n");			/* we skip the reset if this happens to be a			 * multi-target device, since failure of an			 * auto-sense is perfectly valid			 */			if (!(us->flags & US_FL_SCM_MULT_TARG)) {				us->transport_reset(us);			}			srb->result = DID_ERROR << 16;			return;		}		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);		US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",			  srb->sense_buffer[0],			  srb->sense_buffer[2] & 0xf,			  srb->sense_buffer[12], 			  srb->sense_buffer[13]);#ifdef CONFIG_USB_STORAGE_DEBUG		usb_stor_show_sense(			  srb->sense_buffer[2] & 0xf,			  srb->sense_buffer[12], 			  srb->sense_buffer[13]);#endif		/* set the result so the higher layers expect this data */		srb->result = CHECK_CONDITION << 1;		/* we're done here, let's clean up */		srb->request_buffer = old_request_buffer;		srb->request_bufflen = old_request_bufflen;		srb->use_sg = old_sg;		srb->sc_data_direction = old_sc_data_direction;		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);		/* If things are really okay, then let's show that */		if ((srb->sense_buffer[2] & 0xf) == 0x0)			srb->result = GOOD << 1;	} else /* if (need_auto_sense) */		srb->result = GOOD << 1;	/* Regardless of auto-sense, if we _know_ we have an error	 * condition, show that in the result code	 */	if (result == USB_STOR_TRANSPORT_FAILED)		srb->result = CHECK_CONDITION << 1;	/* If we think we're good, then make sure the sense data shows it.	 * This is necessary because the auto-sense for some devices always	 * sets byte 0 == 0x70, even if there is no error	 */	if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) && 	    (result == USB_STOR_TRANSPORT_GOOD) &&	    ((srb->sense_buffer[2] & 0xf) == 0x0))		srb->sense_buffer[0] = 0x0;}/* * Control/Bulk/Interrupt transport *//* The interrupt handler for CBI devices */void usb_stor_CBI_irq(struct urb *urb){	struct us_data *us = (struct us_data *)urb->context;	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);	US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);	US_DEBUGP("-- IRQ state is %d\n", urb->status);	US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",			us->irqbuf[0], us->irqbuf[1]);	/* reject improper IRQs */	if (urb->actual_length != 2) {		US_DEBUGP("-- IRQ too short\n");		return;	}	/* is the device removed? */	if (urb->status == -ENOENT) {		US_DEBUGP("-- device has been removed\n");		return;	}	/* was this a command-completion interrupt? */	if (us->irqbuf[0] && (us->subclass != US_SC_UFI)) {		US_DEBUGP("-- not a command-completion IRQ\n");		return;	}	/* was this a wanted interrupt? */	if (!atomic_read(us->ip_wanted)) {		US_DEBUGP("ERROR: Unwanted interrupt received!\n");		return;	}	/* adjust the flag */	atomic_set(us->ip_wanted, 0);			/* copy the valid data */	us->irqdata[0] = us->irqbuf[0];	us->irqdata[1] = us->irqbuf[1];	/* wake up the command thread */	US_DEBUGP("-- Current value of ip_waitq is: %d\n",			atomic_read(&us->ip_waitq.count));	up(&(us->ip_waitq));}int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us){	int result;	/* Set up for status notification */	atomic_set(us->ip_wanted, 1);

⌨️ 快捷键说明

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