2005-04-17 02:20:36 +04:00
/* Driver for USB Mass Storage compliant devices
*
* $ Id : usb . c , v 1.75 2002 / 04 / 22 03 : 39 : 43 mdharm Exp $
*
* Current development and maintenance by :
* ( c ) 1999 - 2003 Matthew Dharm ( mdharm - usb @ one - eyed - alien . net )
*
* Developed with the assistance of :
* ( c ) 2000 David L . Brown , Jr . ( usb - storage @ davidb . org )
* ( c ) 2003 Alan Stern ( stern @ rowland . harvard . edu )
*
* Initial work by :
* ( c ) 1999 Michael Gee ( michael @ linuxspecific . com )
*
* usb_device_id support by Adam J . Richter ( adam @ yggdrasil . com ) :
* ( c ) 2000 Yggdrasil Computing , Inc .
*
* 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 0213 9 , USA .
*/
# include <linux/sched.h>
# include <linux/errno.h>
2006-12-07 07:34:23 +03:00
# include <linux/freezer.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
2005-10-24 06:43:36 +04:00
# include <linux/kthread.h>
2006-01-11 17:55:29 +03:00
# include <linux/mutex.h>
2007-03-05 11:30:55 +03:00
# include <linux/utsname.h>
2005-04-17 02:20:36 +04:00
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_device.h>
# include "usb.h"
# include "scsiglue.h"
# include "transport.h"
# include "protocol.h"
# include "debug.h"
# include "initializers.h"
# ifdef CONFIG_USB_STORAGE_USBAT
# include "shuttle_usbat.h"
# endif
# ifdef CONFIG_USB_STORAGE_SDDR09
# include "sddr09.h"
# endif
# ifdef CONFIG_USB_STORAGE_SDDR55
# include "sddr55.h"
# endif
# ifdef CONFIG_USB_STORAGE_DPCM
# include "dpcm.h"
# endif
# ifdef CONFIG_USB_STORAGE_FREECOM
# include "freecom.h"
# endif
# ifdef CONFIG_USB_STORAGE_ISD200
# include "isd200.h"
# endif
# ifdef CONFIG_USB_STORAGE_DATAFAB
# include "datafab.h"
# endif
# ifdef CONFIG_USB_STORAGE_JUMPSHOT
# include "jumpshot.h"
# endif
2005-07-29 01:49:01 +04:00
# ifdef CONFIG_USB_STORAGE_ONETOUCH
# include "onetouch.h"
# endif
2005-12-05 09:02:44 +03:00
# ifdef CONFIG_USB_STORAGE_ALAUDA
# include "alauda.h"
# endif
2006-08-14 04:30:14 +04:00
# ifdef CONFIG_USB_STORAGE_KARMA
# include "karma.h"
# endif
2008-03-19 21:40:52 +03:00
# ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
# include "cypress_atacb.h"
# endif
2005-04-17 02:20:36 +04:00
/* Some informational data */
MODULE_AUTHOR ( " Matthew Dharm <mdharm-usb@one-eyed-alien.net> " ) ;
MODULE_DESCRIPTION ( " USB Mass Storage driver for Linux " ) ;
MODULE_LICENSE ( " GPL " ) ;
static unsigned int delay_use = 5 ;
module_param ( delay_use , uint , S_IRUGO | S_IWUSR ) ;
MODULE_PARM_DESC ( delay_use , " seconds to delay before using a new device " ) ;
2005-10-23 07:15:09 +04:00
/*
* The entries in this table correspond , line for line ,
* with the entries of us_unusual_dev_list [ ] .
2005-04-17 02:20:36 +04:00
*/
2005-10-23 07:15:09 +04:00
# ifndef CONFIG_USB_LIBUSUAL
2005-04-17 02:20:36 +04:00
# define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName , productName , useProtocol , useTransport , \
initFunction , flags ) \
2005-10-23 07:15:09 +04:00
{ USB_DEVICE_VER ( id_vendor , id_product , bcdDeviceMin , bcdDeviceMax ) , \
. driver_info = ( flags ) | ( USB_US_TYPE_STOR < < 24 ) }
# define USUAL_DEV(useProto, useTrans, useType) \
{ USB_INTERFACE_INFO ( USB_CLASS_MASS_STORAGE , useProto , useTrans ) , \
. driver_info = ( USB_US_TYPE_STOR < < 24 ) }
2005-04-17 02:20:36 +04:00
static struct usb_device_id storage_usb_ids [ ] = {
# include "unusual_devs.h"
# undef UNUSUAL_DEV
2005-10-23 07:15:09 +04:00
# undef USUAL_DEV
2005-04-17 02:20:36 +04:00
/* Terminating entry */
{ }
} ;
MODULE_DEVICE_TABLE ( usb , storage_usb_ids ) ;
2005-10-23 07:15:09 +04:00
# endif /* CONFIG_USB_LIBUSUAL */
2005-04-17 02:20:36 +04:00
/* 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_FIX_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 .
*/
# define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name , product_name , use_protocol , use_transport , \
init_function , Flags ) \
{ \
. vendorName = vendor_name , \
. productName = product_name , \
. useProtocol = use_protocol , \
. useTransport = use_transport , \
. initFunction = init_function , \
2005-10-23 07:15:09 +04:00
}
# define USUAL_DEV(use_protocol, use_transport, use_type) \
{ \
. useProtocol = use_protocol , \
. useTransport = use_transport , \
2005-04-17 02:20:36 +04:00
}
static struct us_unusual_dev us_unusual_dev_list [ ] = {
# include "unusual_devs.h"
# undef UNUSUAL_DEV
2005-10-23 07:15:09 +04:00
# undef USUAL_DEV
2005-04-17 02:20:36 +04:00
/* Terminating entry */
{ NULL }
} ;
2005-10-24 06:41:39 +04:00
# ifdef CONFIG_PM /* Minimal support for suspend and resume */
static int storage_suspend ( struct usb_interface * iface , pm_message_t message )
{
struct us_data * us = usb_get_intfdata ( iface ) ;
/* Wait until no command is running */
2006-01-11 17:55:29 +03:00
mutex_lock ( & us - > dev_mutex ) ;
2005-10-24 06:41:39 +04:00
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " %s \n " , __func__ ) ;
2005-12-05 08:56:51 +03:00
if ( us - > suspend_resume_hook )
( us - > suspend_resume_hook ) ( us , US_SUSPEND ) ;
2005-10-24 06:41:39 +04:00
2007-09-13 17:01:24 +04:00
/* When runtime PM is working, we'll set a flag to indicate
* whether we should autoresume when a SCSI request arrives . */
2006-01-11 17:55:29 +03:00
mutex_unlock ( & us - > dev_mutex ) ;
2005-10-24 06:41:39 +04:00
return 0 ;
}
static int storage_resume ( struct usb_interface * iface )
{
struct us_data * us = usb_get_intfdata ( iface ) ;
2007-09-13 17:01:24 +04:00
mutex_lock ( & us - > dev_mutex ) ;
2007-07-06 22:24:27 +04:00
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " %s \n " , __func__ ) ;
2005-12-05 08:56:51 +03:00
if ( us - > suspend_resume_hook )
( us - > suspend_resume_hook ) ( us , US_RESUME ) ;
2005-10-24 06:41:39 +04:00
2007-09-13 17:01:24 +04:00
mutex_unlock ( & us - > dev_mutex ) ;
2005-10-24 06:41:39 +04:00
return 0 ;
}
2007-05-30 23:38:16 +04:00
static int storage_reset_resume ( struct usb_interface * iface )
{
struct us_data * us = usb_get_intfdata ( iface ) ;
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " %s \n " , __func__ ) ;
2007-05-30 23:38:16 +04:00
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset ( us ) ;
/* FIXME: Notify the subdrivers that they need to reinitialize
* the device */
return 0 ;
}
2005-10-24 06:41:39 +04:00
# endif /* CONFIG_PM */
2005-04-17 02:20:36 +04:00
2006-06-01 21:52:56 +04:00
/*
* The next two routines get called just before and just after
* a USB port reset , whether from this driver or a different one .
*/
2007-05-30 23:38:16 +04:00
static int storage_pre_reset ( struct usb_interface * iface )
2006-06-01 21:52:56 +04:00
{
struct us_data * us = usb_get_intfdata ( iface ) ;
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " %s \n " , __func__ ) ;
2006-06-01 21:52:56 +04:00
/* Make sure no command runs during the reset */
mutex_lock ( & us - > dev_mutex ) ;
2007-05-30 23:38:16 +04:00
return 0 ;
2006-06-01 21:52:56 +04:00
}
2007-05-30 23:38:16 +04:00
static int storage_post_reset ( struct usb_interface * iface )
2006-06-01 21:52:56 +04:00
{
struct us_data * us = usb_get_intfdata ( iface ) ;
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " %s \n " , __func__ ) ;
2006-06-01 21:52:56 +04:00
/* Report the reset to the SCSI core */
usb_stor_report_bus_reset ( us ) ;
/* FIXME: Notify the subdrivers that they need to reinitialize
* the device */
2007-05-04 19:52:20 +04:00
2007-05-30 23:38:16 +04:00
mutex_unlock ( & us - > dev_mutex ) ;
return 0 ;
2006-06-01 21:52:56 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* 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 )
{
if ( data_len < 36 ) // You lose.
return ;
if ( data [ 0 ] & 0x20 ) { /* USB device currently not connected. Return
peripheral qualifier 001 b ( " ...however, the
physical device is not currently connected
to this logical unit " ) and leave vendor and
product identification empty . ( " If the target
does store some of the INQUIRY data on the
device , it may return zeros or ASCII spaces
( 20 h ) in those fields until the data is
available from the device . " ). */
memset ( data + 8 , 0 , 28 ) ;
} else {
u16 bcdDevice = le16_to_cpu ( us - > pusb_dev - > descriptor . bcdDevice ) ;
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 + ( ( bcdDevice > > 12 ) & 0x0F ) ;
data [ 33 ] = 0x30 + ( ( bcdDevice > > 8 ) & 0x0F ) ;
data [ 34 ] = 0x30 + ( ( bcdDevice > > 4 ) & 0x0F ) ;
data [ 35 ] = 0x30 + ( ( bcdDevice ) & 0x0F ) ;
}
usb_stor_set_xfer_buf ( data , data_len , us - > srb ) ;
}
static int usb_stor_control_thread ( void * __us )
{
struct us_data * us = ( struct us_data * ) __us ;
struct Scsi_Host * host = us_to_host ( us ) ;
for ( ; ; ) {
US_DEBUGP ( " *** thread sleeping. \n " ) ;
if ( down_interruptible ( & us - > sema ) )
break ;
US_DEBUGP ( " *** thread awakened. \n " ) ;
/* lock the device pointers */
2006-01-11 17:55:29 +03:00
mutex_lock ( & ( us - > dev_mutex ) ) ;
2005-04-17 02:20:36 +04:00
/* if the device has disconnected, we are free to exit */
if ( test_bit ( US_FLIDX_DISCONNECTING , & us - > flags ) ) {
US_DEBUGP ( " -- exiting \n " ) ;
2006-01-11 17:55:29 +03:00
mutex_unlock ( & us - > dev_mutex ) ;
2005-04-17 02:20:36 +04:00
break ;
}
/* lock access to the state */
scsi_lock ( host ) ;
/* has the command timed out *already* ? */
if ( test_bit ( US_FLIDX_TIMED_OUT , & us - > flags ) ) {
us - > srb - > result = DID_ABORT < < 16 ;
goto SkipForAbort ;
}
scsi_unlock ( host ) ;
/* reject the command if the direction indicator
* is UNKNOWN
*/
if ( us - > srb - > sc_data_direction = = DMA_BIDIRECTIONAL ) {
US_DEBUGP ( " UNKNOWN data direction \n " ) ;
us - > srb - > result = DID_ERROR < < 16 ;
}
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
else if ( us - > srb - > device - > id & &
! ( us - > flags & US_FL_SCM_MULT_TARG ) ) {
US_DEBUGP ( " Bad target number (%d:%d) \n " ,
us - > srb - > device - > id , us - > srb - > device - > lun ) ;
us - > srb - > result = DID_BAD_TARGET < < 16 ;
}
else if ( us - > srb - > device - > lun > us - > max_lun ) {
US_DEBUGP ( " Bad LUN (%d:%d) \n " ,
us - > srb - > device - > id , us - > srb - > device - > lun ) ;
us - > srb - > result = DID_BAD_TARGET < < 16 ;
}
/* Handle those devices which need us to fake
* their inquiry data */
else if ( ( us - > srb - > cmnd [ 0 ] = = INQUIRY ) & &
( us - > flags & US_FL_FIX_INQUIRY ) ) {
unsigned char data_ptr [ 36 ] = {
0x00 , 0x80 , 0x02 , 0x02 ,
0x1F , 0x00 , 0x00 , 0x00 } ;
US_DEBUGP ( " Faking INQUIRY command \n " ) ;
fill_inquiry_response ( us , data_ptr , 36 ) ;
us - > srb - > result = SAM_STAT_GOOD ;
}
/* we've got a command, let's do it! */
else {
US_DEBUG ( usb_stor_show_command ( us - > srb ) ) ;
us - > proto_handler ( us - > srb , us ) ;
}
/* lock access to the state */
scsi_lock ( host ) ;
2006-06-19 22:50:15 +04:00
/* did the command already complete because of a disconnect? */
if ( ! us - > srb )
; /* nothing to do */
2005-04-17 02:20:36 +04:00
/* indicate that the command is done */
2006-06-19 22:50:15 +04:00
else if ( us - > srb - > result ! = DID_ABORT < < 16 ) {
2005-04-17 02:20:36 +04:00
US_DEBUGP ( " scsi cmd done, result=0x%x \n " ,
us - > srb - > result ) ;
us - > srb - > scsi_done ( us - > srb ) ;
} else {
SkipForAbort :
US_DEBUGP ( " scsi command aborted \n " ) ;
}
/* If an abort request was received we need to signal that
* the abort has finished . The proper test for this is
* the TIMED_OUT flag , not srb - > result = = DID_ABORT , because
2005-08-26 07:03:50 +04:00
* the timeout might have occurred after the command had
* already completed with a different result code . */
if ( test_bit ( US_FLIDX_TIMED_OUT , & us - > flags ) ) {
2005-04-17 02:20:36 +04:00
complete ( & ( us - > notify ) ) ;
2005-08-26 07:03:50 +04:00
/* Allow USB transfers to resume */
clear_bit ( US_FLIDX_ABORTING , & us - > flags ) ;
clear_bit ( US_FLIDX_TIMED_OUT , & us - > flags ) ;
}
2005-04-17 02:20:36 +04:00
/* finished working on this command */
us - > srb = NULL ;
scsi_unlock ( host ) ;
/* unlock the device pointers */
2006-01-11 17:55:29 +03:00
mutex_unlock ( & us - > dev_mutex ) ;
2005-04-17 02:20:36 +04:00
} /* for (;;) */
2007-06-08 01:12:25 +04:00
/* Wait until we are told to stop */
for ( ; ; ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
if ( kthread_should_stop ( ) )
break ;
schedule ( ) ;
}
__set_current_state ( TASK_RUNNING ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
/***********************************************************************
* Device probing and disconnecting
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Associate our private data with the USB device */
static int associate_dev ( struct us_data * us , struct usb_interface * intf )
{
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " -- %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Fill in the device-related fields */
us - > pusb_dev = interface_to_usbdev ( intf ) ;
us - > pusb_intf = intf ;
us - > ifnum = intf - > cur_altsetting - > desc . bInterfaceNumber ;
US_DEBUGP ( " Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x \n " ,
le16_to_cpu ( us - > pusb_dev - > descriptor . idVendor ) ,
le16_to_cpu ( us - > pusb_dev - > descriptor . idProduct ) ,
le16_to_cpu ( us - > pusb_dev - > descriptor . bcdDevice ) ) ;
US_DEBUGP ( " Interface Subclass: 0x%02x, Protocol: 0x%02x \n " ,
intf - > cur_altsetting - > desc . bInterfaceSubClass ,
intf - > cur_altsetting - > desc . bInterfaceProtocol ) ;
/* Store our private data in the interface */
usb_set_intfdata ( intf , us ) ;
/* Allocate the device-related DMA-mapped buffers */
us - > cr = usb_buffer_alloc ( us - > pusb_dev , sizeof ( * us - > cr ) ,
GFP_KERNEL , & us - > cr_dma ) ;
if ( ! us - > cr ) {
US_DEBUGP ( " usb_ctrlrequest allocation failed \n " ) ;
return - ENOMEM ;
}
us - > iobuf = usb_buffer_alloc ( us - > pusb_dev , US_IOBUF_SIZE ,
GFP_KERNEL , & us - > iobuf_dma ) ;
if ( ! us - > iobuf ) {
US_DEBUGP ( " I/O buffer allocation failed \n " ) ;
return - ENOMEM ;
}
2005-10-24 06:40:22 +04:00
us - > sensebuf = kmalloc ( US_SENSE_SIZE , GFP_KERNEL ) ;
if ( ! us - > sensebuf ) {
US_DEBUGP ( " Sense buffer allocation failed \n " ) ;
return - ENOMEM ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-10-23 07:15:09 +04:00
/* Find an unusual_dev descriptor (always succeeds in the current code) */
static struct us_unusual_dev * find_unusual ( const struct usb_device_id * id )
{
const int id_index = id - storage_usb_ids ;
return & us_unusual_dev_list [ id_index ] ;
}
2005-04-17 02:20:36 +04:00
/* Get the unusual_devs entries and the string descriptors */
2006-07-26 16:59:23 +04:00
static int get_device_info ( struct us_data * us , const struct usb_device_id * id )
2005-04-17 02:20:36 +04:00
{
struct usb_device * dev = us - > pusb_dev ;
struct usb_interface_descriptor * idesc =
& us - > pusb_intf - > cur_altsetting - > desc ;
2005-10-23 07:15:09 +04:00
struct us_unusual_dev * unusual_dev = find_unusual ( id ) ;
2005-04-17 02:20:36 +04:00
/* Store the entries */
us - > unusual_dev = unusual_dev ;
us - > subclass = ( unusual_dev - > useProtocol = = US_SC_DEVICE ) ?
idesc - > bInterfaceSubClass :
unusual_dev - > useProtocol ;
us - > protocol = ( unusual_dev - > useTransport = = US_PR_DEVICE ) ?
idesc - > bInterfaceProtocol :
unusual_dev - > useTransport ;
2005-10-23 07:15:09 +04:00
us - > flags = USB_US_ORIG_FLAGS ( id - > driver_info ) ;
2005-04-17 02:20:36 +04:00
2006-07-26 16:59:23 +04:00
if ( us - > flags & US_FL_IGNORE_DEVICE ) {
printk ( KERN_INFO USB_STORAGE " device ignored \n " ) ;
return - ENODEV ;
}
2005-04-17 02:20:36 +04:00
/*
* This flag is only needed when we ' re in high - speed , so let ' s
* disable it if we ' re in full - speed
*/
if ( dev - > speed ! = USB_SPEED_HIGH )
us - > flags & = ~ US_FL_GO_SLOW ;
/* Log a message if a non-generic unusual_dev entry contains an
* unnecessary subclass or protocol override . This may stimulate
* reports from users that will help us remove unneeded entries
* from the unusual_devs . h table .
*/
if ( id - > idVendor | | id - > idProduct ) {
2005-11-29 11:43:42 +03:00
static const char * msgs [ 3 ] = {
2005-04-17 02:20:36 +04:00
" an unneeded SubClass entry " ,
" an unneeded Protocol entry " ,
" unneeded SubClass and Protocol entries " } ;
struct usb_device_descriptor * ddesc = & dev - > descriptor ;
int msg = - 1 ;
if ( unusual_dev - > useProtocol ! = US_SC_DEVICE & &
us - > subclass = = idesc - > bInterfaceSubClass )
msg + = 1 ;
if ( unusual_dev - > useTransport ! = US_PR_DEVICE & &
us - > protocol = = idesc - > bInterfaceProtocol )
msg + = 2 ;
2005-10-23 07:15:09 +04:00
if ( msg > = 0 & & ! ( us - > flags & US_FL_NEED_OVERRIDE ) )
2005-04-17 02:20:36 +04:00
printk ( KERN_NOTICE USB_STORAGE " This device "
" (%04x,%04x,%04x S %02x P %02x) "
2006-06-25 04:27:54 +04:00
" has %s in unusual_devs.h (kernel "
" %s) \n "
2005-04-17 02:20:36 +04:00
" Please send a copy of this message to "
" <linux-usb-devel@lists.sourceforge.net> \n " ,
le16_to_cpu ( ddesc - > idVendor ) ,
le16_to_cpu ( ddesc - > idProduct ) ,
le16_to_cpu ( ddesc - > bcdDevice ) ,
idesc - > bInterfaceSubClass ,
idesc - > bInterfaceProtocol ,
2006-06-25 04:27:54 +04:00
msgs [ msg ] ,
2007-03-05 11:30:55 +03:00
utsname ( ) - > release ) ;
2005-04-17 02:20:36 +04:00
}
2006-07-26 16:59:23 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/* Get the transport settings */
static int get_transport ( struct us_data * us )
{
switch ( us - > protocol ) {
case US_PR_CB :
us - > transport_name = " Control/Bulk " ;
us - > transport = usb_stor_CB_transport ;
us - > transport_reset = usb_stor_CB_reset ;
us - > max_lun = 7 ;
break ;
case US_PR_CBI :
us - > transport_name = " Control/Bulk/Interrupt " ;
us - > transport = usb_stor_CBI_transport ;
us - > transport_reset = usb_stor_CB_reset ;
us - > max_lun = 7 ;
break ;
case US_PR_BULK :
us - > transport_name = " Bulk " ;
us - > transport = usb_stor_Bulk_transport ;
us - > transport_reset = usb_stor_Bulk_reset ;
break ;
# ifdef CONFIG_USB_STORAGE_USBAT
2005-09-30 15:49:36 +04:00
case US_PR_USBAT :
us - > transport_name = " Shuttle USBAT " ;
2005-04-17 02:20:36 +04:00
us - > transport = usbat_transport ;
us - > transport_reset = usb_stor_CB_reset ;
us - > max_lun = 1 ;
break ;
# endif
# ifdef CONFIG_USB_STORAGE_SDDR09
case US_PR_EUSB_SDDR09 :
us - > transport_name = " EUSB/SDDR09 " ;
us - > transport = sddr09_transport ;
us - > transport_reset = usb_stor_CB_reset ;
us - > max_lun = 0 ;
break ;
# endif
# ifdef CONFIG_USB_STORAGE_SDDR55
case US_PR_SDDR55 :
us - > transport_name = " SDDR55 " ;
us - > transport = sddr55_transport ;
us - > transport_reset = sddr55_reset ;
us - > max_lun = 0 ;
break ;
# endif
# ifdef CONFIG_USB_STORAGE_DPCM
case US_PR_DPCM_USB :
us - > transport_name = " Control/Bulk-EUSB/SDDR09 " ;
us - > transport = dpcm_transport ;
us - > transport_reset = usb_stor_CB_reset ;
us - > max_lun = 1 ;
break ;
# endif
# ifdef CONFIG_USB_STORAGE_FREECOM
case US_PR_FREECOM :
us - > transport_name = " Freecom " ;
us - > transport = freecom_transport ;
us - > transport_reset = usb_stor_freecom_reset ;
us - > max_lun = 0 ;
break ;
# endif
# ifdef CONFIG_USB_STORAGE_DATAFAB
case US_PR_DATAFAB :
us - > transport_name = " Datafab Bulk-Only " ;
us - > transport = datafab_transport ;
us - > transport_reset = usb_stor_Bulk_reset ;
us - > max_lun = 1 ;
break ;
# endif
# ifdef CONFIG_USB_STORAGE_JUMPSHOT
case US_PR_JUMPSHOT :
us - > transport_name = " Lexar Jumpshot Control/Bulk " ;
us - > transport = jumpshot_transport ;
us - > transport_reset = usb_stor_Bulk_reset ;
us - > max_lun = 1 ;
break ;
# endif
2006-05-09 04:45:27 +04:00
# ifdef CONFIG_USB_STORAGE_ALAUDA
case US_PR_ALAUDA :
us - > transport_name = " Alauda Control/Bulk " ;
us - > transport = alauda_transport ;
us - > transport_reset = usb_stor_Bulk_reset ;
us - > max_lun = 1 ;
break ;
# endif
2006-08-14 04:30:14 +04:00
# ifdef CONFIG_USB_STORAGE_KARMA
case US_PR_KARMA :
us - > transport_name = " Rio Karma/Bulk " ;
us - > transport = rio_karma_transport ;
us - > transport_reset = usb_stor_Bulk_reset ;
break ;
# endif
2005-04-17 02:20:36 +04:00
default :
return - EIO ;
}
US_DEBUGP ( " Transport: %s \n " , us - > transport_name ) ;
/* fix for single-lun devices */
if ( us - > flags & US_FL_SINGLE_LUN )
us - > max_lun = 0 ;
return 0 ;
}
/* Get the protocol settings */
static int get_protocol ( struct us_data * us )
{
switch ( us - > subclass ) {
case US_SC_RBC :
us - > protocol_name = " Reduced Block Commands (RBC) " ;
us - > proto_handler = usb_stor_transparent_scsi_command ;
break ;
case US_SC_8020 :
us - > protocol_name = " 8020i " ;
us - > proto_handler = usb_stor_ATAPI_command ;
us - > max_lun = 0 ;
break ;
case US_SC_QIC :
us - > protocol_name = " QIC-157 " ;
us - > proto_handler = usb_stor_qic157_command ;
us - > max_lun = 0 ;
break ;
case US_SC_8070 :
us - > protocol_name = " 8070i " ;
us - > proto_handler = usb_stor_ATAPI_command ;
us - > max_lun = 0 ;
break ;
case US_SC_SCSI :
us - > protocol_name = " Transparent SCSI " ;
us - > proto_handler = usb_stor_transparent_scsi_command ;
break ;
case US_SC_UFI :
us - > protocol_name = " Uniform Floppy Interface (UFI) " ;
us - > proto_handler = usb_stor_ufi_command ;
break ;
# ifdef CONFIG_USB_STORAGE_ISD200
case US_SC_ISD200 :
us - > protocol_name = " ISD200 ATA/ATAPI " ;
us - > proto_handler = isd200_ata_command ;
break ;
# endif
2008-03-19 21:40:52 +03:00
# ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
case US_SC_CYP_ATACB :
us - > protocol_name = " Transparent SCSI with Cypress ATACB " ;
us - > proto_handler = cypress_atacb_passthrough ;
break ;
# endif
2005-04-17 02:20:36 +04:00
default :
return - EIO ;
}
US_DEBUGP ( " Protocol: %s \n " , us - > protocol_name ) ;
return 0 ;
}
/* Get the pipe settings */
static int get_pipes ( struct us_data * us )
{
struct usb_host_interface * altsetting =
us - > pusb_intf - > cur_altsetting ;
int i ;
struct usb_endpoint_descriptor * ep ;
struct usb_endpoint_descriptor * ep_in = NULL ;
struct usb_endpoint_descriptor * ep_out = NULL ;
struct usb_endpoint_descriptor * ep_int = NULL ;
/*
2007-01-22 19:58:34 +03:00
* Find the first endpoint of each type we need .
2005-04-17 02:20:36 +04:00
* We are expecting a minimum of 2 endpoints - in and out ( bulk ) .
2007-01-22 19:58:34 +03:00
* An optional interrupt - in is OK ( necessary for CBI protocol ) .
2005-04-17 02:20:36 +04:00
* We will ignore any others .
*/
for ( i = 0 ; i < altsetting - > desc . bNumEndpoints ; i + + ) {
ep = & altsetting - > endpoint [ i ] . desc ;
2006-10-26 20:03:03 +04:00
if ( usb_endpoint_xfer_bulk ( ep ) ) {
2007-01-22 19:58:34 +03:00
if ( usb_endpoint_dir_in ( ep ) ) {
if ( ! ep_in )
ep_in = ep ;
} else {
if ( ! ep_out )
ep_out = ep ;
}
2005-04-17 02:20:36 +04:00
}
2007-01-22 19:58:34 +03:00
else if ( usb_endpoint_is_int_in ( ep ) ) {
if ( ! ep_int )
ep_int = ep ;
2005-04-17 02:20:36 +04:00
}
}
if ( ! ep_in | | ! ep_out | | ( us - > protocol = = US_PR_CBI & & ! ep_int ) ) {
US_DEBUGP ( " Endpoint sanity check failed! Rejecting dev. \n " ) ;
return - EIO ;
}
/* Calculate and store the pipe values */
us - > send_ctrl_pipe = usb_sndctrlpipe ( us - > pusb_dev , 0 ) ;
us - > recv_ctrl_pipe = usb_rcvctrlpipe ( us - > pusb_dev , 0 ) ;
us - > send_bulk_pipe = usb_sndbulkpipe ( us - > pusb_dev ,
ep_out - > bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ) ;
us - > recv_bulk_pipe = usb_rcvbulkpipe ( us - > pusb_dev ,
ep_in - > bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ) ;
if ( ep_int ) {
us - > recv_intr_pipe = usb_rcvintpipe ( us - > pusb_dev ,
ep_int - > bEndpointAddress & USB_ENDPOINT_NUMBER_MASK ) ;
us - > ep_bInterval = ep_int - > bInterval ;
}
return 0 ;
}
/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources ( struct us_data * us )
{
int p ;
2005-10-24 06:43:36 +04:00
struct task_struct * th ;
2005-04-17 02:20:36 +04:00
us - > current_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
if ( ! us - > current_urb ) {
US_DEBUGP ( " URB allocation failed \n " ) ;
return - ENOMEM ;
}
/* Just before we start our control thread, initialize
* the device if it needs initialization */
2005-10-24 06:38:56 +04:00
if ( us - > unusual_dev - > initFunction ) {
p = us - > unusual_dev - > initFunction ( us ) ;
if ( p )
return p ;
}
2005-04-17 02:20:36 +04:00
/* Start up our control thread */
2007-06-08 01:12:25 +04:00
th = kthread_run ( usb_stor_control_thread , us , " usb-storage " ) ;
2005-10-24 06:43:36 +04:00
if ( IS_ERR ( th ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING USB_STORAGE
" Unable to start control thread \n " ) ;
2005-10-24 06:43:36 +04:00
return PTR_ERR ( th ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-08 01:12:25 +04:00
us - > ctl_thread = th ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Release all our dynamic resources */
static void usb_stor_release_resources ( struct us_data * us )
{
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " -- %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
/* Tell the control thread to exit. The SCSI host must
* already have been removed so it won ' t try to queue
* any more commands .
*/
US_DEBUGP ( " -- sending exit command to thread \n " ) ;
2005-07-29 01:44:29 +04:00
set_bit ( US_FLIDX_DISCONNECTING , & us - > flags ) ;
2005-04-17 02:20:36 +04:00
up ( & us - > sema ) ;
2007-06-08 01:12:25 +04:00
if ( us - > ctl_thread )
kthread_stop ( us - > ctl_thread ) ;
2005-04-17 02:20:36 +04:00
/* Call the destructor routine, if it exists */
if ( us - > extra_destructor ) {
US_DEBUGP ( " -- calling extra_destructor() \n " ) ;
us - > extra_destructor ( us - > extra ) ;
}
/* Free the extra data and the URB */
kfree ( us - > extra ) ;
usb_free_urb ( us - > current_urb ) ;
}
/* Dissociate from the USB device */
static void dissociate_dev ( struct us_data * us )
{
2008-03-04 03:08:34 +03:00
US_DEBUGP ( " -- %s \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
2005-10-24 06:40:22 +04:00
kfree ( us - > sensebuf ) ;
2005-04-17 02:20:36 +04:00
/* Free the device-related DMA-mapped buffers */
if ( us - > cr )
usb_buffer_free ( us - > pusb_dev , sizeof ( * us - > cr ) , us - > cr ,
us - > cr_dma ) ;
if ( us - > iobuf )
usb_buffer_free ( us - > pusb_dev , US_IOBUF_SIZE , us - > iobuf ,
us - > iobuf_dma ) ;
/* Remove our private data from the interface */
usb_set_intfdata ( us - > pusb_intf , NULL ) ;
}
2005-07-29 01:44:29 +04:00
/* First stage of disconnect processing: stop all commands and remove
* the host */
static void quiesce_and_remove_host ( struct us_data * us )
{
2006-06-19 22:50:15 +04:00
struct Scsi_Host * host = us_to_host ( us ) ;
2005-07-29 01:44:29 +04:00
/* Prevent new USB transfers, stop the current command, and
* interrupt a SCSI - scan or device - reset delay */
2006-06-19 22:50:15 +04:00
scsi_lock ( host ) ;
2005-07-29 01:44:29 +04:00
set_bit ( US_FLIDX_DISCONNECTING , & us - > flags ) ;
2006-06-19 22:50:15 +04:00
scsi_unlock ( host ) ;
2005-07-29 01:44:29 +04:00
usb_stor_stop_transport ( us ) ;
wake_up ( & us - > delay_wait ) ;
2005-07-29 01:45:50 +04:00
/* queuecommand won't accept any new commands and the control
* thread won ' t execute a previously - queued command . If there
* is such a command pending , complete it with an error . */
2006-06-19 22:50:15 +04:00
mutex_lock ( & us - > dev_mutex ) ;
2005-07-29 01:45:50 +04:00
if ( us - > srb ) {
us - > srb - > result = DID_NO_CONNECT < < 16 ;
2006-06-19 22:50:15 +04:00
scsi_lock ( host ) ;
2005-07-29 01:45:50 +04:00
us - > srb - > scsi_done ( us - > srb ) ;
us - > srb = NULL ;
2007-08-17 00:16:00 +04:00
complete ( & us - > notify ) ; /* in case of an abort */
2006-06-19 22:50:15 +04:00
scsi_unlock ( host ) ;
2005-07-29 01:45:50 +04:00
}
2006-06-19 22:50:15 +04:00
mutex_unlock ( & us - > dev_mutex ) ;
2005-07-29 01:45:50 +04:00
/* Now we own no commands so it's safe to remove the SCSI host */
2006-06-19 22:50:15 +04:00
scsi_remove_host ( host ) ;
2007-08-17 00:16:00 +04:00
/* Wait for the SCSI-scanning thread to stop */
wait_for_completion ( & us - > scanning_done ) ;
2005-07-29 01:44:29 +04:00
}
/* Second stage of disconnect processing: deallocate all resources */
static void release_everything ( struct us_data * us )
{
usb_stor_release_resources ( us ) ;
dissociate_dev ( us ) ;
/* Drop our reference to the host; the SCSI core will free it
* ( and " us " along with it ) when the refcount becomes 0. */
scsi_host_put ( us_to_host ( us ) ) ;
}
2005-04-17 02:20:36 +04:00
/* Thread to carry out delayed SCSI-device scanning */
static int usb_stor_scan_thread ( void * __us )
{
struct us_data * us = ( struct us_data * ) __us ;
printk ( KERN_DEBUG
" usb-storage: device found at %d \n " , us - > pusb_dev - > devnum ) ;
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2005-04-17 02:20:36 +04:00
/* Wait for the timeout to expire or for a disconnect */
if ( delay_use > 0 ) {
printk ( KERN_DEBUG " usb-storage: waiting for device "
" to settle before scanning \n " ) ;
2007-10-18 14:04:45 +04:00
wait_event_freezable_timeout ( us - > delay_wait ,
2005-04-17 02:20:36 +04:00
test_bit ( US_FLIDX_DISCONNECTING , & us - > flags ) ,
delay_use * HZ ) ;
}
/* If the device is still connected, perform the scanning */
if ( ! test_bit ( US_FLIDX_DISCONNECTING , & us - > flags ) ) {
2005-10-24 06:38:56 +04:00
/* For bulk-only devices, determine the max LUN value */
if ( us - > protocol = = US_PR_BULK & &
! ( us - > flags & US_FL_SINGLE_LUN ) ) {
2006-01-11 17:55:29 +03:00
mutex_lock ( & us - > dev_mutex ) ;
2005-10-24 06:38:56 +04:00
us - > max_lun = usb_stor_Bulk_max_lun ( us ) ;
2006-01-11 17:55:29 +03:00
mutex_unlock ( & us - > dev_mutex ) ;
2005-10-24 06:38:56 +04:00
}
2005-04-17 02:20:36 +04:00
scsi_scan_host ( us_to_host ( us ) ) ;
printk ( KERN_DEBUG " usb-storage: device scan complete \n " ) ;
/* Should we unbind if no devices were detected? */
}
2007-08-17 00:16:00 +04:00
complete_and_exit ( & us - > scanning_done , 0 ) ;
2005-04-17 02:20:36 +04:00
}
/* Probe to see if we can drive a newly-connected USB device */
static int storage_probe ( struct usb_interface * intf ,
const struct usb_device_id * id )
{
struct Scsi_Host * host ;
struct us_data * us ;
int result ;
2005-10-24 06:43:36 +04:00
struct task_struct * th ;
2005-04-17 02:20:36 +04:00
2005-10-23 07:15:09 +04:00
if ( usb_usual_check_type ( id , USB_US_TYPE_STOR ) )
return - ENXIO ;
2005-04-17 02:20:36 +04:00
US_DEBUGP ( " USB Mass Storage device detected \n " ) ;
/*
* Ask the SCSI layer to allocate a host structure , with extra
* space at the end for our private us_data structure .
*/
host = scsi_host_alloc ( & usb_stor_host_template , sizeof ( * us ) ) ;
if ( ! host ) {
printk ( KERN_WARNING USB_STORAGE
" Unable to allocate the scsi host \n " ) ;
return - ENOMEM ;
}
2007-10-10 21:56:28 +04:00
/*
* Allow 16 - byte CDBs and thus > 2 TB
*/
host - > max_cmd_len = 16 ;
2005-04-17 02:20:36 +04:00
us = host_to_us ( host ) ;
memset ( us , 0 , sizeof ( struct us_data ) ) ;
2006-01-11 17:55:29 +03:00
mutex_init ( & ( us - > dev_mutex ) ) ;
2005-04-17 02:20:36 +04:00
init_MUTEX_LOCKED ( & ( us - > sema ) ) ;
init_completion ( & ( us - > notify ) ) ;
init_waitqueue_head ( & us - > delay_wait ) ;
2007-08-17 00:16:00 +04:00
init_completion ( & us - > scanning_done ) ;
2005-04-17 02:20:36 +04:00
/* Associate the us_data structure with the USB device */
result = associate_dev ( us , intf ) ;
if ( result )
goto BadDevice ;
/*
* Get the unusual_devs entries and the descriptors
*
* id_index is calculated in the declaration to be the index number
* of the match from the usb_device_id table , so we can find the
* corresponding entry in the private table .
*/
2006-07-26 16:59:23 +04:00
result = get_device_info ( us , id ) ;
if ( result )
goto BadDevice ;
2005-04-17 02:20:36 +04:00
/* Get the transport, protocol, and pipe settings */
result = get_transport ( us ) ;
if ( result )
goto BadDevice ;
result = get_protocol ( us ) ;
if ( result )
goto BadDevice ;
result = get_pipes ( us ) ;
if ( result )
goto BadDevice ;
/* Acquire all the other resources and add the host */
result = usb_stor_acquire_resources ( us ) ;
if ( result )
goto BadDevice ;
result = scsi_add_host ( host , & intf - > dev ) ;
if ( result ) {
printk ( KERN_WARNING USB_STORAGE
" Unable to add the scsi host \n " ) ;
goto BadDevice ;
}
/* Start up the thread for delayed SCSI-device scanning */
2005-10-24 06:43:36 +04:00
th = kthread_create ( usb_stor_scan_thread , us , " usb-stor-scan " ) ;
if ( IS_ERR ( th ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING USB_STORAGE
" Unable to start the device-scanning thread \n " ) ;
2005-07-29 01:44:29 +04:00
quiesce_and_remove_host ( us ) ;
2005-10-24 06:43:36 +04:00
result = PTR_ERR ( th ) ;
2005-04-17 02:20:36 +04:00
goto BadDevice ;
}
2005-10-24 06:43:36 +04:00
wake_up_process ( th ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
/* We come here if there are any problems */
BadDevice :
US_DEBUGP ( " storage_probe() failed \n " ) ;
2005-07-29 01:44:29 +04:00
release_everything ( us ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
/* Handle a disconnect event from the USB core */
static void storage_disconnect ( struct usb_interface * intf )
{
struct us_data * us = usb_get_intfdata ( intf ) ;
US_DEBUGP ( " storage_disconnect() called \n " ) ;
2005-07-29 01:44:29 +04:00
quiesce_and_remove_host ( us ) ;
release_everything ( us ) ;
2005-04-17 02:20:36 +04:00
}
/***********************************************************************
* Initialization and registration
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-24 06:41:39 +04:00
static struct usb_driver usb_storage_driver = {
. name = " usb-storage " ,
. probe = storage_probe ,
. disconnect = storage_disconnect ,
# ifdef CONFIG_PM
. suspend = storage_suspend ,
. resume = storage_resume ,
2007-05-30 23:38:16 +04:00
. reset_resume = storage_reset_resume ,
2005-10-24 06:41:39 +04:00
# endif
2006-06-01 21:52:56 +04:00
. pre_reset = storage_pre_reset ,
. post_reset = storage_post_reset ,
2005-10-24 06:41:39 +04:00
. id_table = storage_usb_ids ,
} ;
2005-04-17 02:20:36 +04:00
static int __init usb_stor_init ( void )
{
int retval ;
printk ( KERN_INFO " Initializing USB Mass Storage driver... \n " ) ;
/* register the driver, return usb_register return code if error */
retval = usb_register ( & usb_storage_driver ) ;
2005-10-23 07:15:09 +04:00
if ( retval = = 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " USB Mass Storage support registered. \n " ) ;
2005-10-23 07:15:09 +04:00
usb_usual_set_present ( USB_US_TYPE_STOR ) ;
}
2005-04-17 02:20:36 +04:00
return retval ;
}
static void __exit usb_stor_exit ( void )
{
US_DEBUGP ( " usb_stor_exit() called \n " ) ;
/* Deregister the driver
* This will cause disconnect ( ) to be called for each
* attached unit
*/
US_DEBUGP ( " -- calling usb_deregister() \n " ) ;
usb_deregister ( & usb_storage_driver ) ;
2005-10-23 07:15:09 +04:00
usb_usual_clear_present ( USB_US_TYPE_STOR ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( usb_stor_init ) ;
module_exit ( usb_stor_exit ) ;