📄 transport.c
字号:
/* Driver for USB Mass Storage compliant devices * * $Id: transport.c,v 1.42 2001/12/08 23:32:48 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * * Developed with the assistance of: * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) * * Initial work by: * (c) 1999 Michael Gee (michael@linuxspecific.com) * * 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 and ATAPI commands in * mind when they created this document. The commands are all very * similar to commands in the SCSI-II and ATAPI specifications. * * 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. * * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more * information about this driver. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/config.h>#include "transport.h"#include "protocol.h"#include "usb.h"#include "debug.h"#include <linux/sched.h>#include <linux/errno.h>#include <linux/slab.h>/*********************************************************************** * Helper routines ***********************************************************************//* Calculate the length of the data transfer (not the command) for any * given SCSI command */unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb){ int i; int doDefault = 0; unsigned int len = 0; unsigned int total = 0; struct scatterlist *sg; /* This table tells us: X = command not supported L = return length in cmnd[4] (8 bits). M = return length in cmnd[8] (8 bits). G = return length in cmnd[3] and cmnd[4] (16 bits) H = return length in cmnd[7] and cmnd[8] (16 bits) I = return length in cmnd[8] and cmnd[9] (16 bits) C = return length in cmnd[2] to cmnd[5] (32 bits) D = return length in cmnd[6] to cmnd[9] (32 bits) B = return length in blocksize so we use buff_len R = return length in cmnd[2] to cmnd[4] (24 bits) S = return length in cmnd[3] to cmnd[5] (24 bits) T = return length in cmnd[6] to cmnd[8] (24 bits) U = return length in cmnd[7] to cmnd[9] (24 bits) 0-9 = fixed return length V = 20 bytes W = 24 bytes Z = return length is mode dependant or not in command, use buff_len */ static char *lengths = /* 0123456789ABCDEF 0123456789ABCDEF */ "00XLZ6XZBXBBXXXB" "00LBBLG0R0L0GG0X" /* 00-1F */ "XXXXT8XXB4B0BBBB" "ZZZ0B00HCSSZTBHH" /* 20-3F */ "M0HHB0X000H0HH0X" "XHH0HHXX0TH0H0XX" /* 40-5F */ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */ "X0XXX00XB0BXBXBB" "ZZZ0XUIDU000XHBX" /* A0-BF */ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */ "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */ /* Commands checked in table: CHANGE_DEFINITION 40 COMPARE 39 COPY 18 COPY_AND_VERIFY 3a ERASE 19 ERASE_10 2c ERASE_12 ac EXCHANGE_MEDIUM a6 FORMAT_UNIT 04 GET_DATA_BUFFER_STATUS 34 GET_MESSAGE_10 28 GET_MESSAGE_12 a8 GET_WINDOW 25 !!! Has more data than READ_CAPACITY, need to fix table INITIALIZE_ELEMENT_STATUS 07 !!! REASSIGN_BLOCKS luckily uses buff_len INQUIRY 12 LOAD_UNLOAD 1b LOCATE 2b LOCK_UNLOCK_CACHE 36 LOG_SELECT 4c LOG_SENSE 4d MEDIUM_SCAN 38 !!! This was M MODE_SELECT6 15 MODE_SELECT_10 55 MODE_SENSE_6 1a MODE_SENSE_10 5a MOVE_MEDIUM a5 OBJECT_POSITION 31 !!! Same as SEARCH_DATA_EQUAL PAUSE_RESUME 4b PLAY_AUDIO_10 45 PLAY_AUDIO_12 a5 PLAY_AUDIO_MSF 47 PLAY_AUDIO_TRACK_INDEX 48 PLAY_AUDIO_TRACK_RELATIVE_10 49 PLAY_AUDIO_TRACK_RELATIVE_12 a9 POSITION_TO_ELEMENT 2b PRE-FETCH 34 PREVENT_ALLOW_MEDIUM_REMOVAL 1e PRINT 0a !!! Same as WRITE_6 but is always in bytes READ_6 08 READ_10 28 READ_12 a8 READ_BLOCK_LIMITS 05 READ_BUFFER 3c READ_CAPACITY 25 READ_CDROM_CAPACITY 25 READ_DEFECT_DATA 37 READ_DEFECT_DATA_12 b7 READ_ELEMENT_STATUS b8 !!! Think this is in bytes READ_GENERATION 29 !!! Could also be M? READ_HEADER 44 !!! This was L READ_LONG 3e READ_POSITION 34 !!! This should be V but conflicts with PRE-FETCH READ_REVERSE 0f READ_SUB-CHANNEL 42 !!! Is this in bytes? READ_TOC 43 !!! Is this in bytes? READ_UPDATED_BLOCK 2d REASSIGN_BLOCKS 07 RECEIVE 08 !!! Same as READ_6 probably in bytes though RECEIVE_DIAGNOSTIC_RESULTS 1c RECOVER_BUFFERED_DATA 14 !!! For PRINTERs this is bytes RELEASE_UNIT 17 REQUEST_SENSE 03 REQUEST_VOLUME_ELEMENT_ADDRESS b5 !!! Think this is in bytes RESERVE_UNIT 16 REWIND 01 REZERO_UNIT 01 SCAN 1b !!! Conflicts with various commands, should be L SEARCH_DATA_EQUAL 31 SEARCH_DATA_EQUAL_12 b1 SEARCH_DATA_LOW 30 SEARCH_DATA_LOW_12 b0 SEARCH_DATA_HIGH 32 SEARCH_DATA_HIGH_12 b2 SEEK_6 0b !!! Conflicts with SLEW_AND_PRINT SEEK_10 2b SEND 0a !!! Same as WRITE_6, probably in bytes though SEND 2a !!! Similar to WRITE_10 but for scanners SEND_DIAGNOSTIC 1d SEND_MESSAGE_6 0a !!! Same as WRITE_6 - is in bytes SEND_MESSAGE_10 2a !!! Same as WRITE_10 - is in bytes SEND_MESSAGE_12 aa !!! Same as WRITE_12 - is in bytes SEND_OPC 54 SEND_VOLUME_TAG b6 !!! Think this is in bytes SET_LIMITS 33 SET_LIMITS_12 b3 SET_WINDOW 24 SLEW_AND_PRINT 0b !!! Conflicts with SEEK_6 SPACE 11 START_STOP_UNIT 1b STOP_PRINT 1b SYNCHRONIZE_BUFFER 10 SYNCHRONIZE_CACHE 35 TEST_UNIT_READY 00 UPDATE_BLOCK 3d VERIFY 13 VERIFY 2f VERIFY_12 af WRITE_6 0a WRITE_10 2a WRITE_12 aa WRITE_AND_VERIFY 2e WRITE_AND_VERIFY_12 ae WRITE_BUFFER 3b WRITE_FILEMARKS 10 WRITE_LONG 3f WRITE_SAME 41 */ if (srb->sc_data_direction == SCSI_DATA_WRITE) { doDefault = 1; } else switch (lengths[srb->cmnd[0]]) { case 'L': len = srb->cmnd[4]; break; case 'M': len = srb->cmnd[8]; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': len = lengths[srb->cmnd[0]]-'0'; break; case 'G': len = (((unsigned int)srb->cmnd[3])<<8) | srb->cmnd[4]; break; case 'H': len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8]; break; case 'I': len = (((unsigned int)srb->cmnd[8])<<8) | srb->cmnd[9]; break; case 'R': len = (((unsigned int)srb->cmnd[2])<<16) | (((unsigned int)srb->cmnd[3])<<8) | srb->cmnd[4]; break; case 'S': len = (((unsigned int)srb->cmnd[3])<<16) | (((unsigned int)srb->cmnd[4])<<8) | srb->cmnd[5]; break; case 'T': len = (((unsigned int)srb->cmnd[6])<<16) | (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8]; break; case 'U': len = (((unsigned int)srb->cmnd[7])<<16) | (((unsigned int)srb->cmnd[8])<<8) | srb->cmnd[9]; break; case 'C': len = (((unsigned int)srb->cmnd[2])<<24) | (((unsigned int)srb->cmnd[3])<<16) | (((unsigned int)srb->cmnd[4])<<8) | srb->cmnd[5]; break; case 'D': len = (((unsigned int)srb->cmnd[6])<<24) | (((unsigned int)srb->cmnd[7])<<16) | (((unsigned int)srb->cmnd[8])<<8) | srb->cmnd[9]; break; case 'V': len = 20; break; case 'W': len = 24; break; case 'B': /* Use buffer size due to different block sizes */ doDefault = 1; break; case 'X': US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n", srb->cmnd[0]); doDefault = 1; break; case 'Z': /* Use buffer size due to mode dependence */ doDefault = 1; break; default: US_DEBUGP("Error: COMMAND %02X out of range or table inconsistent (%c).\n", srb->cmnd[0], lengths[srb->cmnd[0]] ); doDefault = 1; } if ( doDefault == 1 ) { /* Are we going to scatter gather? */ if (srb->use_sg) { /* Add up the sizes of all the sg segments */ sg = (struct scatterlist *) srb->request_buffer; for (i = 0; i < srb->use_sg; i++) total += sg[i].length; len = total; } else /* Just return the length of the buffer */ len = srb->request_bufflen; }return len;}/* This is a version of usb_clear_halt() that doesn't read the status from * the device -- this is because some devices crash their internal firmware * when the status is requested after a halt */int usb_stor_clear_halt(struct usb_device *dev, int pipe){ int result; int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0, HZ * 3); /* this is a failure case */ if (result < 0) return result; /* reset the toggles and endpoint flags */ usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); return 0;}/*********************************************************************** * Data transfer routines ***********************************************************************//* This is the completion handler which will wake us up when an URB * completes. */static void usb_stor_blocking_completion(urb_t *urb){ struct completion *urb_done_ptr = (struct completion *)urb->context; complete(urb_done_ptr);}/* This is our function to emulate usb_control_msg() but give us enough * access to make aborts/resets work */int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size){ struct completion urb_done; int status; devrequest *dr; /* allocate the device request structure */ dr = kmalloc(sizeof(devrequest), GFP_NOIO); if (!dr) return -ENOMEM; /* fill in the structure */ dr->requesttype = requesttype; dr->request = request; dr->value = cpu_to_le16(value); dr->index = cpu_to_le16(index); dr->length = cpu_to_le16(size); /* set up data structures for the wakeup system */ init_completion(&urb_done); /* lock the URB */ down(&(us->current_urb_sem)); /* fill the URB */ FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, (unsigned char*) dr, data, size, 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)); kfree(dr); return status; } /* wait for the completion of the URB */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -