diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-08-28 22:00:09 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-08-28 22:00:09 +0000 |
commit | 1a1d77dd589de5a567fa95e36aa6999c704ceca4 (patch) | |
tree | 141e31f89f18b9fe0831f31852e0435ceaccafc5 /drivers/usb/storage | |
parent | fb9c690a18b3d66925a65b17441c37fa14d4370b (diff) |
Merge with 2.4.0-test7.
Diffstat (limited to 'drivers/usb/storage')
-rw-r--r-- | drivers/usb/storage/Makefile | 6 | ||||
-rw-r--r-- | drivers/usb/storage/dpcm.c | 83 | ||||
-rw-r--r-- | drivers/usb/storage/dpcm.h | 34 | ||||
-rw-r--r-- | drivers/usb/storage/scsiglue.c | 8 | ||||
-rw-r--r-- | drivers/usb/storage/shuttle_usbat.c | 2 | ||||
-rw-r--r-- | drivers/usb/storage/shuttle_usbat.h | 2 | ||||
-rw-r--r-- | drivers/usb/storage/transport.c | 435 | ||||
-rw-r--r-- | drivers/usb/storage/transport.h | 5 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 285 | ||||
-rw-r--r-- | drivers/usb/storage/usb.h | 20 |
10 files changed, 752 insertions, 128 deletions
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile index 7da59f78e..e7761863e 100644 --- a/drivers/usb/storage/Makefile +++ b/drivers/usb/storage/Makefile @@ -5,6 +5,7 @@ O_TARGET := usb-storage.o M_OBJS := usb-storage.o O_OBJS := scsiglue.o protocol.o transport.o usb.o +MOD_LIST_NAME := USB_STORAGE_MODULES CFLAGS_scsiglue.o:= -I../../scsi/ CFLAGS_protocol.o:= -I../../scsi/ @@ -13,6 +14,7 @@ CFLAGS_debug.o:= -I../../scsi/ CFLAGS_usb.o:= -I../../scsi/ CFLAGS_shuttle_usbat.o:= -I../../scsi/ CFLAGS_sddr09.o:= -I../../scsi/ +CFLAGS_dpcm.o:= -I../../scsi/ ifeq ($(CONFIG_USB_STORAGE_DEBUG),y) O_OBJS += debug.o @@ -37,5 +39,9 @@ endif ifeq ($(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH),y) O_OBJS += shuttle_cf.o endif + +ifeq ($(CONFIG_USB_STORAGE_DPCM),y) + O_OBJS += dpcm.o +endif include $(TOPDIR)/Rules.make diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c new file mode 100644 index 000000000..8b7195bfc --- /dev/null +++ b/drivers/usb/storage/dpcm.c @@ -0,0 +1,83 @@ +/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader + * + * $Id: dpcm.c,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * + * DPCM driver v0.1: + * + * First release + * + * Current development and maintainance by: + * (c) 2000 Brian Webb (webbb@earthlink.net) + * + * This device contains both a CompactFlash card reader, which + * usest the Control/Bulk w/o Interrupt protocol and + * a SmartMedia card reader that uses the same protocol + * as the SDDR09. + * + * 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 "dpcm.h" +#include "sddr09.h" + + +/* + * Transport for the Microtech DPCM-USB + * + */ +int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us) +{ + int ret; + + if(srb == NULL) + return USB_STOR_TRANSPORT_ERROR; + + US_DEBUGP("dpcm_transport: LUN=%d\n", srb->lun); + + switch(srb->lun) { + case 0: + + /* + * LUN 0 corresponds to the CompactFlash card reader. + */ + return usb_stor_CB_transport(srb, us); + +#ifdef CONFIG_USB_STORAGE_SDDR09 + case 1: + + /* + * LUN 1 corresponds to the SmartMedia card reader. + */ + + /* + * Set the LUN to 0 (just in case). + */ + srb->lun = 0; us->srb->lun = 0; + ret = sddr09_transport(srb, us); + srb->lun = 1; us->srb->lun = 1; + + return ret; +#endif + + default: + US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->lun); + return USB_STOR_TRANSPORT_ERROR; + } +} diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h new file mode 100644 index 000000000..d6e5f86ad --- /dev/null +++ b/drivers/usb/storage/dpcm.h @@ -0,0 +1,34 @@ +/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader + * + * $Id: dpcm.h,v 1.1 2000/08/08 01:26:12 webbb Exp $ + * + * DPCM driver v0.1: + * + * First release + * + * Current development and maintainance by: + * (c) 2000 Brian Webb (webbb@earthlink.net) + * + * See dpcm.c for more explanation + * + * 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. + */ + +#ifndef _MICROTECH_DPCM_USB_H +#define _MICROTECH_DPCM_USB_H + +extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); + +#endif diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 7517d63bc..c823aaed1 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.7 2000/07/28 20:33:18 gowdy Exp $ + * $Id: scsiglue.c,v 1.8 2000/08/11 23:15:05 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -189,6 +189,12 @@ static int command_abort( Scsi_Cmnd *srb ) return SUCCESS; } + /* This is a sanity check that we should never hit */ + if (in_interrupt()) { + printk(KERN_ERR "usb-storage: command_abort() called from an interrupt!!! BAD!!! BAD!! BAD!!\n"); + return FAILED; + } + /* if we have an urb pending, let's wake the control thread up */ if (us->current_urb->status == -EINPROGRESS) { /* cancel the URB */ diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index f68595c47..492bc7259 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -1,5 +1,7 @@ /* Driver for SCM Microsystems USB-ATAPI cable * + * $Id: shuttle_usbat.c,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * * SCM driver v0.2: * * Removed any reference to maxlen for bulk transfers. diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h index eede2651f..ff5c07541 100644 --- a/drivers/usb/storage/shuttle_usbat.h +++ b/drivers/usb/storage/shuttle_usbat.h @@ -1,6 +1,8 @@ /* Driver for SCM Microsystems USB-ATAPI cable * Header File * + * $Id: shuttle_usbat.h,v 1.2 2000/08/03 00:03:39 groovyjava Exp $ + * * Current development and maintainance by: * (c) 2000 Robert Baruch (autophile@dol.net) * diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index a0fb2407c..dd3c489f1 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1,12 +1,13 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.5 2000/07/28 22:40:20 mdharm Exp $ + * $Id: transport.c,v 1.12 2000/08/08 15:22:38 gowdy Exp $ * * Current development and maintainance 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) @@ -52,6 +53,353 @@ #include <linux/malloc.h> /*********************************************************************** + * Helper routines + ***********************************************************************/ + +/* Calculate the length of the data transfer (not the command) for any + * given SCSI command + */ +static unsigned int us_transfer_length(Scsi_Cmnd *srb, struct us_data *us) +{ + int i; + unsigned int total = 0; + struct scatterlist *sg; + + /* support those devices which need the length calculated + * differently + */ + if (srb->cmnd[0] == INQUIRY) { + srb->cmnd[4] = 36; + } + + if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) + return srb->cmnd[4]; + + if (srb->cmnd[0] == TEST_UNIT_READY) + return 0; + + /* Are we going to scatter gather? */ + if (srb->use_sg) { + /* Add up the sizes of all the scatter-gather segments */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) + total += sg[i].length; + + return total; + } + else + /* Just return the length of the buffer */ + return srb->request_bufflen; +} + +/* Calculate the length of the data transfer (not the command) for any + * given SCSI command + */ +static unsigned int us_transfer_length_new(Scsi_Cmnd *srb, struct us_data *us) +{ + 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" "XHH00HXX0TH0H0XX" /* 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_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 + */ + + /* Not sure this is right as an INQUIRY can contain nonstandard info */ + if (srb->cmnd[0] == INQUIRY) + srb->cmnd[4] = 36; + + 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 + */ +static int 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 ***********************************************************************/ @@ -217,7 +565,7 @@ static int us_transfer_partial(struct us_data *us, char *buf, int 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_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } /* did we send all the data? */ @@ -287,44 +635,6 @@ static void us_transfer(Scsi_Cmnd *srb, struct us_data* us) srb->result = 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, struct us_data *us) -{ - int i; - unsigned int total = 0; - struct scatterlist *sg; - - /* support those devices which need the length calculated - * differently - */ - if (us->flags & US_FL_ALT_LENGTH) { - if (srb->cmnd[0] == INQUIRY) { - srb->cmnd[4] = 36; - } - - if ((srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE)) - return srb->cmnd[4]; - - if (srb->cmnd[0] == TEST_UNIT_READY) - return 0; - } - - /* Are we going to scatter gather? */ - if (srb->use_sg) { - /* Add up the sizes of all the scatter-gather segments */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) - total += sg[i].length; - - return total; - } - else - /* Just return the length of the buffer */ - return srb->request_bufflen; -} - /*********************************************************************** * Transport routines ***********************************************************************/ @@ -363,7 +673,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * of determining status on it's own, we need to auto-sense almost * every time. */ - if (us->protocol == US_PR_CB) { + 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; @@ -490,7 +800,7 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) * 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) && + 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; @@ -548,10 +858,10 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) /* STALL must be cleared when they are detected */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = clear_halt(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, + 0)); + US_DEBUGP("-- clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -652,10 +962,10 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) /* a stall is a fatal condition from the device */ if (result == -EPIPE) { US_DEBUGP("-- Stall on control pipe. Clearing\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, - 0)); - US_DEBUGP("-- usb_clear_halt() returns %d\n", result); + result = clear_halt(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, + 0)); + US_DEBUGP("-- clear_halt() returns %d\n", result); return USB_STOR_TRANSPORT_FAILED; } @@ -710,7 +1020,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us) /* if we get a STALL, clear the stall */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); } /* return the default -- no LUNs */ @@ -757,7 +1067,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* 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); + clear_halt(us->pusb_dev, pipe); } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; @@ -796,7 +1106,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); @@ -810,7 +1120,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); + clear_halt(us->pusb_dev, pipe); return USB_STOR_TRANSPORT_ERROR; } } @@ -877,10 +1187,10 @@ int usb_stor_CB_reset(struct us_data *us) schedule_timeout(HZ*6); US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); return 0; @@ -904,14 +1214,13 @@ int usb_stor_Bulk_reset(struct us_data *us) if (result < 0) US_DEBUGP("Bulk hard reset failed %d\n", result); - usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + clear_halt(us->pusb_dev, + usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + clear_halt(us->pusb_dev, + usb_sndbulkpipe(us->pusb_dev, us->ep_out)); /* long wait for reset */ schedule_timeout(HZ*6); return result; } - diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 9d0993c1e..4615569f3 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.6 2000/07/27 14:42:43 groovyjava Exp $ + * $Id: transport.h,v 1.8 2000/08/08 01:23:55 webbb Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -58,6 +58,7 @@ #define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for SDDR-09 */ #endif +#define US_PR_DPCM_USB 0xf0 /* Combination CB/SDDR09 */ /* * Bulk only data structures @@ -133,4 +134,6 @@ extern int usb_stor_Bulk_reset(struct us_data*); void usb_stor_invoke_transport(Scsi_Cmnd *, struct us_data *); +extern int dpcm_transport(Scsi_Cmnd *srb, struct us_data *us); + #endif diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index fc70bc72a..50ebddd6f 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.16 2000/08/01 22:01:19 mdharm Exp $ + * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -44,7 +44,6 @@ */ #include <linux/config.h> - #include "usb.h" #include "scsiglue.h" #include "transport.h" @@ -56,6 +55,9 @@ #ifdef CONFIG_USB_STORAGE_SDDR09 #include "sddr09.h" #endif +#ifdef CONFIG_USB_STORAGE_DPCM +#include "dpcm.h" +#endif #include <linux/module.h> #include <linux/sched.h> @@ -63,6 +65,10 @@ #include <linux/init.h> #include <linux/malloc.h> +/* Some informational data */ +MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); +MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); + /* * Per device data */ @@ -91,6 +97,58 @@ static struct usb_driver storage_driver = { disconnect: storage_disconnect, }; +/* + * fill_inquiry_response takes an unsigned char array (which must + * be at least 36 characters) and populates the vendor name, + * product name, and revision fields. Then the array is copied + * into the SCSI command's response buffer (oddly enough + * called request_buffer). data_len contains the length of the + * data array, which again must be at least 36. + */ + +void fill_inquiry_response(struct us_data *us, unsigned char *data, + unsigned int data_len) { + + int i; + struct scatterlist *sg; + int len = + us->srb->request_bufflen > data_len ? data_len : + us->srb->request_bufflen; + int transferred; + int amt; + + if (data_len<36) // You lose. + return; + + memcpy(data+8, us->unusual_dev->vendorName, + strlen(us->unusual_dev->vendorName) > 8 ? 8 : + strlen(us->unusual_dev->vendorName)); + memcpy(data+16, us->unusual_dev->productName, + strlen(us->unusual_dev->productName) > 16 ? 16 : + strlen(us->unusual_dev->productName)); + data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F); + data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F); + data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F); + data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F); + + if (us->srb->use_sg) { + sg = (struct scatterlist *)us->srb->request_buffer; + for (i=0; i<us->srb->use_sg; i++) + memset(sg[i].address, 0, sg[i].length); + for (i=0, transferred=0; + i<us->srb->use_sg && transferred < len; + i++) { + amt = sg[i].length > len-transferred ? + len-transferred : sg[i].length; + memcpy(sg[i].address, data+transferred, amt); + transferred -= amt; + } + } else { + memset(us->srb->request_buffer, 0, us->srb->request_bufflen); + memcpy(us->srb->request_buffer, data, len); + } +} + static int usb_stor_control_thread(void * __us) { wait_queue_t wait; @@ -176,7 +234,7 @@ static int usb_stor_control_thread(void * __us) us->srb = NULL; break; } - + /* lock the device pointers */ down(&(us->dev_semaphore)); @@ -246,50 +304,140 @@ static int usb_stor_control_thread(void * __us) } /* This is the list of devices we recognize, along with their flag data */ + +/* The vendor name should be kept at eight characters or less, and + * the product name should be kept at 16 characters or less. If a device + * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names + * normally generated by a device thorugh the INQUIRY response will be + * taken from this list, and this is the reason for the above size + * restriction. However, if the flag is not present, then you + * are free to use as many characters as you like. + */ + static struct us_unusual_dev us_unusual_dev_list[] = { - { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus", - US_SC_8070, US_PR_CB, 0}, + + { 0x03f0, 0x0107, 0x0200, 0x0200, + "HP", + "CD-Writer+", + US_SC_8070, US_PR_CB, NULL, + 0}, + #ifdef CONFIG_USB_STORAGE_HP8200e - { 0x03f0, 0x0207, 0x0001, 0x0001, "HP USB CD-Writer Plus 8200e", - US_SC_8070, US_PR_SCM_ATAPI, - US_FL_ALT_LENGTH | US_FL_NEED_INIT | US_FL_SINGLE_LUN}, + { 0x03f0, 0x0207, 0x0001, 0x0001, + "HP", + "CD-Writer+ 8200e", + US_SC_8070, US_PR_SCM_ATAPI, init_8200e, + US_FL_SINGLE_LUN}, #endif - { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120", - US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30/S70", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | - US_FL_MODE_XLATE | US_FL_ALT_LENGTH | US_FL_ALT_LENGTH}, - { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP | - US_FL_MODE_XLATE | US_FL_ALT_LENGTH}, - { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U", - US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN}, - { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U", - US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN}, - { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-05a)", - US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP}, -#ifdef CONFIG_USB_STORAGE_SDDR09 - { 0x0781, 0x0200, 0x0100, 0x0100, "Sandisk ImageMate (SDDR-09)", - US_SC_SCSI, US_PR_EUSB_SDDR09, + + { 0x04e6, 0x0001, 0x0200, 0x0200, + "Matshita", + "LS-120", + US_SC_8020, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x04e6, 0x0002, 0x0100, 0x0100, + "Shuttle", + "eUSCSI Bridge", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x04e6, 0x0006, 0x0100, 0x0100, + "Shuttle", + "eUSB MMC Adapter", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x054c, 0x0010, 0x0210, 0x0210, + "Sony", + "DSC-S30/S70", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, + + { 0x054c, 0x002d, 0x0100, 0x0100, + "Sony", + "Memorystick MSAC-US1", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, + + { 0x057b, 0x0000, 0x0000, 0x0299, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + + { 0x057b, 0x0000, 0x0300, 0x9999, + "Y-E Data", + "Flashbuster-U", + US_SC_UFI, US_PR_CBI, NULL, + US_FL_SINGLE_LUN}, + + { 0x0693, 0x0002, 0x0100, 0x0100, + "Hagiwara", + "FlashGate SmartMedia", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x0781, 0x0001, 0x0200, 0x0200, + "Sandisk", + "ImageMate SDDR05a", + US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP}, + +#ifdef CONFIG_USB_STORAGE_SDDR09 + { 0x0781, 0x0200, 0x0100, 0x0100, + "Sandisk", + "ImageMate SDDR09", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP }, +#endif + + { 0x0781, 0x0002, 0x0009, 0x0009, + "Sandisk", + "ImageMate SDDR31", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_IGNORE_SER}, + + { 0x07af, 0x0004, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-DB25", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x059f, 0xa601, 0x0200, 0x0200, + "LaCie", + "USB Hard Disk", + US_SC_RBC, US_PR_CB, NULL, + 0 }, + +#ifdef CONFIG_USB_STORAGE_DPCM + { 0x07af, 0x0006, 0x0100, 0x0100, + "Microtech", + "CameraMate (DPCM_USB)", + US_SC_SCSI, US_PR_DPCM_USB, NULL, + US_FL_START_STOP }, #endif - { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)", - US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER}, - { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech USB-SCSI-DB25", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge", - US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate", - US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH}, - { 0 }}; + + { 0x07af, 0x0005, 0x0100, 0x0100, + "Microtech", + "USB-SCSI-HD50", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0x05ab, 0x0031, 0x0100, 0x0100, + "In-System", + "USB/IDE Bridge", + US_SC_8070, US_PR_BULK, NULL, + 0 }, + + { 0x0693, 0x0005, 0x0100, 0x0100, + "Hagiwara", + "Flashgate", + US_SC_SCSI, US_PR_BULK, NULL, + 0 }, + + { 0 } +}; /* Search our ususual device list, based on vendor/product combinations * to see if we can support this device. Returns a pointer to a structure @@ -319,7 +467,8 @@ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct, } /* otherwise, we found one! */ - US_DEBUGP("-- found matching device: %s\n", ptr->name); + US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName, + ptr->productName); return ptr; } @@ -546,15 +695,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) USB_ENDPOINT_NUMBER_MASK; ss->ep_int = ep_int; - /* Reset the device's NEED_INIT flag if it needs to be - initialized with a magic sequence */ - - if (flags & US_FL_NEED_INIT) - ss->flags |= US_FL_NEED_INIT; - /* allocate an IRQ callback if one is needed */ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) return NULL; + + /* Re-Initialize the device if it needs it */ + + if (unusual_dev && unusual_dev->initFunction) + (*unusual_dev->initFunction)(ss); + } else { /* New device -- allocate memory and initialize */ US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); @@ -586,6 +735,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) ss->subclass = subclass; ss->protocol = protocol; ss->flags = flags; + ss->unusual_dev = unusual_dev; /* copy over the endpoint data */ if (ep_in) @@ -604,10 +754,22 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) strncpy(ss->vendor, mf, USB_STOR_STRING_LEN); strncpy(ss->product, prod, USB_STOR_STRING_LEN); strncpy(ss->serial, serial, USB_STOR_STRING_LEN); - if (strlen(ss->vendor) == 0) - strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN); - if (strlen(ss->product) == 0) - strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN); + if (strlen(ss->vendor) == 0) { + if (unusual_dev) + strncpy(ss->vendor, unusual_dev->vendorName, + USB_STOR_STRING_LEN); + else + strncpy(ss->vendor, "Unknown", + USB_STOR_STRING_LEN); + } + if (strlen(ss->product) == 0) { + if (unusual_dev) + strncpy(ss->product, unusual_dev->productName, + USB_STOR_STRING_LEN); + else + strncpy(ss->product, "Unknown", + USB_STOR_STRING_LEN); + } if (strlen(ss->serial) == 0) strncpy(ss->serial, "None", USB_STOR_STRING_LEN); @@ -657,6 +819,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) ss->max_lun = 1; break; #endif + +#ifdef CONFIG_USB_STORAGE_DPCM + case US_PR_DPCM_USB: + ss->transport_name = "Control/Bulk-EUSB/SDDR09"; + ss->transport = dpcm_transport; + ss->transport_reset = usb_stor_CB_reset; + ss->max_lun = 1; + break; +#endif default: ss->transport_name = "Unknown"; @@ -734,6 +905,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum) * we to do it? */ (struct us_data *)ss->htmplt.proc_dir = ss; + + /* Just before we start our control thread, initialize + * the device if it needs initialization */ + if (unusual_dev && unusual_dev->initFunction) + (*unusual_dev->initFunction)(ss); /* start up our control thread */ ss->pid = kernel_thread(usb_stor_control_thread, ss, @@ -878,6 +1054,3 @@ void __exit usb_stor_exit(void) module_init(usb_stor_init) ; module_exit(usb_stor_exit) ; - -MODULE_AUTHOR("Michael Gee <michael@linuxspecific.com>, David L. Brown, Jr. <usb-storage@davidb.org>, Matthew Dharm <mdharm-usb@one-eyed-alien.net>"); -MODULE_DESCRIPTION("USB Mass Storage driver"); diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index b376d39ee..435ad9777 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Main Header File * - * $Id: usb.h,v 1.4 2000/07/28 20:14:49 groovyjava Exp $ + * $Id: usb.h,v 1.7 2000/08/15 00:06:38 mdharm Exp $ * * Current development and maintainance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -77,6 +77,8 @@ static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *seri } } +struct us_data; + /* * Unusual device list definitions */ @@ -89,9 +91,11 @@ struct us_unusual_dev { __u16 bcdDeviceMax; /* the list specifies these parameters */ - const char* name; + const char* vendorName; + const char* productName; __u8 useProtocol; __u8 useTransport; + int (*initFunction)(struct us_data *); unsigned int flags; }; @@ -100,15 +104,11 @@ struct us_unusual_dev { #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 comands for Win/MacOS compatibility */ #define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ -#define US_FL_ALT_LENGTH 0x00000008 /* use the alternate algorithm for - us_transfer_length() */ #define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ -#define US_FL_NEED_INIT 0x00000020 /* Device needs initialization */ +#define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define USB_STOR_STRING_LEN 32 -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*); @@ -176,6 +176,7 @@ struct us_data { /* mutual exclusion structures */ struct semaphore notify; /* thread begin/end */ struct semaphore queue_exclusion; /* to protect data structs */ + struct us_unusual_dev *unusual_dev; /* If unusual device */ void *extra; /* Any extra data */ void (*extra_destructor)(void *); /* extra data destructor */ }; @@ -184,4 +185,9 @@ struct us_data { extern struct us_data *us_list; extern struct semaphore us_list_semaphore; +/* Function to fill an inquiry response. See usb.c for details */ + +extern void fill_inquiry_response(struct us_data *us, + unsigned char *data, unsigned int data_len); + #endif |