2009-10-28 18:57:14 +03:00
/*
* storage_common . c - - Common definitions for mass storage functionality
*
* Copyright ( C ) 2003 - 2008 Alan Stern
* Copyeight ( C ) 2009 Samsung Electronics
* Author : Michal Nazarewicz ( m . nazarewicz @ samsung . com )
2009-10-28 18:57:15 +03:00
*
* 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 of the License , 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/*
* This file requires the following identifiers used in USB strings to
* be defined ( each of type pointer to char ) :
* - fsg_string_manufacturer - - name of the manufacturer
* - fsg_string_product - - name of the product
* - fsg_string_config - - name of the configuration
* - fsg_string_interface - - name of the interface
* The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
* macro is defined prior to including this file .
2009-10-28 18:57:14 +03:00
*/
2009-10-28 18:57:19 +03:00
/*
* When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
* fsg_hs_intr_in_desc objects as well as
* FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
* macros are not defined .
*
* When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER ,
* FSG_STRING_PRODUCT , FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
* defined ( as well as corresponding entries in string tables are
* missing ) and FSG_STRING_INTERFACE has value of zero .
*
* When FSG_NO_OTG is defined fsg_otg_desc won ' t be defined .
*/
2009-10-28 18:57:21 +03:00
/*
* When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
* the fsg_buffhd structure ' s buf field will be an array of FSG_BUFLEN
* characters rather then a pointer to void .
*/
2009-10-28 18:57:14 +03:00
2010-10-07 15:05:24 +04:00
# include <linux/usb/storage.h>
2010-10-07 16:46:15 +04:00
# include <scsi/scsi.h>
# include <asm/unaligned.h>
2009-10-28 18:57:15 +03:00
2009-10-28 18:57:14 +03:00
2010-07-05 18:38:04 +04:00
/*
* Thanks to NetChip Technologies for donating this product ID .
2009-10-28 18:57:17 +03:00
*
* DO NOT REUSE THESE IDs with any other driver ! ! Ever ! !
2010-07-05 18:38:04 +04:00
* Instead : allocate your own , using normal USB - IF procedures .
*/
2009-11-09 16:15:23 +03:00
# define FSG_VENDOR_ID 0x0525 /* NetChip */
# define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
2009-10-28 18:57:17 +03:00
2009-10-28 18:57:14 +03:00
/*-------------------------------------------------------------------------*/
# ifndef DEBUG
# undef VERBOSE_DEBUG
# undef DUMP_MSGS
# endif /* !DEBUG */
# ifdef VERBOSE_DEBUG
# define VLDBG LDBG
# else
# define VLDBG(lun, fmt, args...) do { } while (0)
# endif /* VERBOSE_DEBUG */
# define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args)
# define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
# define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
# define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
2010-07-05 18:38:04 +04:00
/*
* Keep those macros in sync with those in
* include / linux / usb / composite . h or else GCC will complain . If they
2009-11-09 16:15:20 +03:00
* are identical ( the same names of arguments , white spaces in the
* same places ) GCC will allow redefinition otherwise ( even if some
2010-07-05 18:38:04 +04:00
* white space is removed or added ) warning will be issued .
*
* Those macros are needed here because File Storage Gadget does not
* include the composite . h header . For composite gadgets those macros
* are redundant since composite . h is included any way .
*
* One could check whether those macros are already defined ( which
* would indicate composite . h had been included ) or not ( which would
* indicate we were in FSG ) but this is not done because a warning is
* desired if definitions here differ from the ones in composite . h .
*
* We want the definitions to match and be the same in File Storage
* Gadget as well as Mass Storage Function ( and so composite gadgets
* using MSF ) . If someone changes them in composite . h it will produce
* a warning in this file when building MSF .
*/
2009-11-09 16:15:20 +03:00
# define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
# define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args)
# define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args)
# define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
# define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args)
2009-10-28 18:57:14 +03:00
# ifdef DUMP_MSGS
# define dump_msg(fsg, /* const char * */ label, \
2009-11-09 16:15:23 +03:00
/* const u8 * */ buf , /* unsigned */ length ) do { \
2009-10-28 18:57:14 +03:00
if ( length < 512 ) { \
DBG ( fsg , " %s, length %u: \n " , label , length ) ; \
print_hex_dump ( KERN_DEBUG , " " , DUMP_PREFIX_OFFSET , \
16 , 1 , buf , length , 0 ) ; \
} \
} while ( 0 )
# define dump_cdb(fsg) do { } while (0)
# else
# define dump_msg(fsg, /* const char * */ label, \
2009-11-09 16:15:23 +03:00
/* const u8 * */ buf , /* unsigned */ length ) do { } while ( 0 )
2009-10-28 18:57:14 +03:00
# ifdef VERBOSE_DEBUG
2009-11-09 16:15:23 +03:00
# define dump_cdb(fsg) \
2009-10-28 18:57:14 +03:00
print_hex_dump ( KERN_DEBUG , " SCSI CDB: " , DUMP_PREFIX_NONE , \
16 , 1 , ( fsg ) - > cmnd , ( fsg ) - > cmnd_size , 0 ) \
# else
# define dump_cdb(fsg) do { } while (0)
# endif /* VERBOSE_DEBUG */
# endif /* DUMP_MSGS */
/*-------------------------------------------------------------------------*/
/* Bulk-only data structures */
/* Command Block Wrapper */
2009-10-28 18:57:15 +03:00
struct fsg_bulk_cb_wrap {
2009-11-09 16:15:23 +03:00
__le32 Signature ; /* Contains 'USBC' */
u32 Tag ; /* Unique per command id */
__le32 DataTransferLength ; /* Size of the data */
u8 Flags ; /* Direction in bit 7 */
u8 Lun ; /* LUN (normally 0) */
u8 Length ; /* Of the CDB, <= MAX_COMMAND_SIZE */
u8 CDB [ 16 ] ; /* Command Data Block */
2009-10-28 18:57:14 +03:00
} ;
# define USB_BULK_CB_WRAP_LEN 31
2009-11-09 16:15:23 +03:00
# define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */
2009-10-28 18:57:14 +03:00
# define USB_BULK_IN_FLAG 0x80
/* Command Status Wrapper */
struct bulk_cs_wrap {
2009-11-09 16:15:23 +03:00
__le32 Signature ; /* Should = 'USBS' */
u32 Tag ; /* Same as original command */
__le32 Residue ; /* Amount not transferred */
u8 Status ; /* See below */
2009-10-28 18:57:14 +03:00
} ;
# define USB_BULK_CS_WRAP_LEN 13
2009-11-09 16:15:23 +03:00
# define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */
2009-10-28 18:57:14 +03:00
# define USB_STATUS_PASS 0
# define USB_STATUS_FAIL 1
# define USB_STATUS_PHASE_ERROR 2
/* Bulk-only class specific requests */
# define USB_BULK_RESET_REQUEST 0xff
# define USB_BULK_GET_MAX_LUN_REQUEST 0xfe
/* CBI Interrupt data structure */
struct interrupt_data {
u8 bType ;
u8 bValue ;
} ;
# define CBI_INTERRUPT_DATA_LEN 2
/* CBI Accept Device-Specific Command request */
# define USB_CBI_ADSC_REQUEST 0x00
2009-11-09 16:15:23 +03:00
/* Length of a SCSI Command Data Block */
# define MAX_COMMAND_SIZE 16
2009-10-28 18:57:14 +03:00
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
# define SS_NO_SENSE 0
# define SS_COMMUNICATION_FAILURE 0x040800
# define SS_INVALID_COMMAND 0x052000
# define SS_INVALID_FIELD_IN_CDB 0x052400
# define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100
# define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500
# define SS_MEDIUM_NOT_PRESENT 0x023a00
# define SS_MEDIUM_REMOVAL_PREVENTED 0x055302
# define SS_NOT_READY_TO_READY_TRANSITION 0x062800
# define SS_RESET_OCCURRED 0x062900
# define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900
# define SS_UNRECOVERED_READ_ERROR 0x031100
# define SS_WRITE_ERROR 0x030c02
# define SS_WRITE_PROTECTED 0x072700
2009-11-09 16:15:23 +03:00
# define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
2009-10-28 18:57:14 +03:00
# define ASC(x) ((u8) ((x) >> 8))
# define ASCQ(x) ((u8) (x))
/*-------------------------------------------------------------------------*/
2009-10-28 18:57:15 +03:00
struct fsg_lun {
2009-10-28 18:57:14 +03:00
struct file * filp ;
loff_t file_length ;
loff_t num_sectors ;
2009-11-09 16:15:23 +03:00
unsigned int initially_ro : 1 ;
unsigned int ro : 1 ;
unsigned int removable : 1 ;
unsigned int cdrom : 1 ;
unsigned int prevent_medium_removal : 1 ;
unsigned int registered : 1 ;
unsigned int info_valid : 1 ;
2010-07-22 18:53:56 +04:00
unsigned int nofua : 1 ;
2009-10-28 18:57:14 +03:00
u32 sense_data ;
u32 sense_data_info ;
u32 unit_attention_data ;
struct device dev ;
} ;
2009-10-28 18:57:15 +03:00
# define fsg_lun_is_open(curlun) ((curlun)->filp != NULL)
2009-10-28 18:57:14 +03:00
2009-10-28 18:57:15 +03:00
static struct fsg_lun * fsg_lun_from_dev ( struct device * dev )
2009-10-28 18:57:14 +03:00
{
2009-10-28 18:57:15 +03:00
return container_of ( dev , struct fsg_lun , dev ) ;
2009-10-28 18:57:14 +03:00
}
/* Big enough to hold our biggest descriptor */
# define EP0_BUFSIZE 256
2009-11-09 16:15:23 +03:00
# define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */
2009-10-28 18:57:14 +03:00
/* Number of buffers we will use. 2 is enough for double-buffering */
2009-10-28 18:57:15 +03:00
# define FSG_NUM_BUFFERS 2
2009-10-28 18:57:14 +03:00
2009-10-28 18:57:17 +03:00
/* Default size of buffer length. */
# define FSG_BUFLEN ((u32)16384)
/* Maximal number of LUNs supported in mass storage function */
# define FSG_MAX_LUNS 8
2009-10-28 18:57:14 +03:00
enum fsg_buffer_state {
BUF_STATE_EMPTY = 0 ,
BUF_STATE_FULL ,
BUF_STATE_BUSY
} ;
struct fsg_buffhd {
2009-10-28 18:57:21 +03:00
# ifdef FSG_BUFFHD_STATIC_BUFFER
char buf [ FSG_BUFLEN ] ;
# else
2009-10-28 18:57:14 +03:00
void * buf ;
2009-10-28 18:57:21 +03:00
# endif
2009-10-28 18:57:14 +03:00
enum fsg_buffer_state state ;
struct fsg_buffhd * next ;
2011-04-15 00:42:46 +04:00
/*
* The NetChip 2280 is faster , and handles some protocol faults
* better , if we don ' t submit any short bulk - out read requests .
* So we will record the intended request length here .
*/
unsigned int bulk_out_intended_length ;
2009-10-28 18:57:14 +03:00
struct usb_request * inreq ;
int inreq_busy ;
struct usb_request * outreq ;
int outreq_busy ;
} ;
enum fsg_state {
2009-11-09 16:15:23 +03:00
/* This one isn't used anywhere */
FSG_STATE_COMMAND_PHASE = - 10 ,
2009-10-28 18:57:14 +03:00
FSG_STATE_DATA_PHASE ,
FSG_STATE_STATUS_PHASE ,
FSG_STATE_IDLE = 0 ,
FSG_STATE_ABORT_BULK_OUT ,
FSG_STATE_RESET ,
FSG_STATE_INTERFACE_CHANGE ,
FSG_STATE_CONFIG_CHANGE ,
FSG_STATE_DISCONNECT ,
FSG_STATE_EXIT ,
FSG_STATE_TERMINATED
} ;
enum data_direction {
DATA_DIR_UNKNOWN = 0 ,
DATA_DIR_FROM_HOST ,
DATA_DIR_TO_HOST ,
DATA_DIR_NONE
} ;
/*-------------------------------------------------------------------------*/
static inline u32 get_unaligned_be24 ( u8 * buf )
{
return 0xffffff & ( u32 ) get_unaligned_be32 ( buf - 1 ) ;
}
/*-------------------------------------------------------------------------*/
2009-10-28 18:57:15 +03:00
enum {
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_DEVICE_STRINGS
2009-10-28 18:57:15 +03:00
FSG_STRING_MANUFACTURER = 1 ,
FSG_STRING_PRODUCT ,
FSG_STRING_SERIAL ,
FSG_STRING_CONFIG ,
2009-10-28 18:57:19 +03:00
# endif
2009-10-28 18:57:15 +03:00
FSG_STRING_INTERFACE
} ;
2009-10-28 18:57:14 +03:00
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_OTG
2009-10-28 18:57:14 +03:00
static struct usb_otg_descriptor
2009-10-28 18:57:15 +03:00
fsg_otg_desc = {
. bLength = sizeof fsg_otg_desc ,
2009-10-28 18:57:14 +03:00
. bDescriptorType = USB_DT_OTG ,
. bmAttributes = USB_OTG_SRP ,
} ;
2009-10-28 18:57:19 +03:00
# endif
2009-10-28 18:57:14 +03:00
/* There is only one interface. */
static struct usb_interface_descriptor
2009-10-28 18:57:15 +03:00
fsg_intf_desc = {
. bLength = sizeof fsg_intf_desc ,
2009-10-28 18:57:14 +03:00
. bDescriptorType = USB_DT_INTERFACE ,
2009-11-09 16:15:23 +03:00
. bNumEndpoints = 2 , /* Adjusted during fsg_bind() */
2009-10-28 18:57:14 +03:00
. bInterfaceClass = USB_CLASS_MASS_STORAGE ,
2009-11-09 16:15:23 +03:00
. bInterfaceSubClass = USB_SC_SCSI , /* Adjusted during fsg_bind() */
. bInterfaceProtocol = USB_PR_BULK , /* Adjusted during fsg_bind() */
2009-10-28 18:57:15 +03:00
. iInterface = FSG_STRING_INTERFACE ,
2009-10-28 18:57:14 +03:00
} ;
2010-07-05 18:38:04 +04:00
/*
* Three full - speed endpoint descriptors : bulk - in , bulk - out , and
* interrupt - in .
*/
2009-10-28 18:57:14 +03:00
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_fs_bulk_in_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
. bEndpointAddress = USB_DIR_IN ,
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
/* wMaxPacketSize set by autoconfiguration */
} ;
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_fs_bulk_out_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
. bEndpointAddress = USB_DIR_OUT ,
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
/* wMaxPacketSize set by autoconfiguration */
} ;
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_INTR_EP
2009-10-28 18:57:14 +03:00
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_fs_intr_in_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
. bEndpointAddress = USB_DIR_IN ,
. bmAttributes = USB_ENDPOINT_XFER_INT ,
. wMaxPacketSize = cpu_to_le16 ( 2 ) ,
2009-11-09 16:15:23 +03:00
. bInterval = 32 , /* frames -> 32 ms */
2009-10-28 18:57:14 +03:00
} ;
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_OTG
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2
# else
# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1
# endif
# endif
2009-11-09 16:15:20 +03:00
static struct usb_descriptor_header * fsg_fs_function [ ] = {
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_OTG
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_otg_desc ,
2009-10-28 18:57:19 +03:00
# endif
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_intf_desc ,
( struct usb_descriptor_header * ) & fsg_fs_bulk_in_desc ,
( struct usb_descriptor_header * ) & fsg_fs_bulk_out_desc ,
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_INTR_EP
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_fs_intr_in_desc ,
2009-10-28 18:57:19 +03:00
# endif
2009-10-28 18:57:14 +03:00
NULL ,
} ;
/*
* USB 2.0 devices need to expose both high speed and full speed
* descriptors , unless they only run at full speed .
*
* That means alternate endpoint descriptors ( bigger packets )
* and a " device qualifier " . . . plus more construction options
2010-07-05 18:38:04 +04:00
* for the configuration descriptor .
2009-10-28 18:57:14 +03:00
*/
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_hs_bulk_in_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
. wMaxPacketSize = cpu_to_le16 ( 512 ) ,
} ;
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_hs_bulk_out_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
. bmAttributes = USB_ENDPOINT_XFER_BULK ,
. wMaxPacketSize = cpu_to_le16 ( 512 ) ,
2009-11-09 16:15:23 +03:00
. bInterval = 1 , /* NAK every 1 uframe */
2009-10-28 18:57:14 +03:00
} ;
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_INTR_EP
2009-10-28 18:57:14 +03:00
static struct usb_endpoint_descriptor
2009-10-28 18:57:15 +03:00
fsg_hs_intr_in_desc = {
2009-10-28 18:57:14 +03:00
. bLength = USB_DT_ENDPOINT_SIZE ,
. bDescriptorType = USB_DT_ENDPOINT ,
/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
. bmAttributes = USB_ENDPOINT_XFER_INT ,
. wMaxPacketSize = cpu_to_le16 ( 2 ) ,
2009-11-09 16:15:23 +03:00
. bInterval = 9 , /* 2**(9-1) = 256 uframes -> 32 ms */
2009-10-28 18:57:14 +03:00
} ;
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_OTG
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2
# else
# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1
# endif
# endif
2009-11-09 16:15:20 +03:00
static struct usb_descriptor_header * fsg_hs_function [ ] = {
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_OTG
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_otg_desc ,
2009-10-28 18:57:19 +03:00
# endif
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_intf_desc ,
( struct usb_descriptor_header * ) & fsg_hs_bulk_in_desc ,
( struct usb_descriptor_header * ) & fsg_hs_bulk_out_desc ,
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_INTR_EP
2009-10-28 18:57:15 +03:00
( struct usb_descriptor_header * ) & fsg_hs_intr_in_desc ,
2009-10-28 18:57:19 +03:00
# endif
2009-10-28 18:57:14 +03:00
NULL ,
} ;
/* Maxpacket and other transfer characteristics vary by speed. */
2011-06-30 09:44:42 +04:00
static __maybe_unused struct usb_endpoint_descriptor *
2009-10-28 18:57:15 +03:00
fsg_ep_desc ( struct usb_gadget * g , struct usb_endpoint_descriptor * fs ,
2009-10-28 18:57:14 +03:00
struct usb_endpoint_descriptor * hs )
{
if ( gadget_is_dualspeed ( g ) & & g - > speed = = USB_SPEED_HIGH )
return hs ;
return fs ;
}
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
2009-10-28 18:57:15 +03:00
static struct usb_string fsg_strings [ ] = {
2009-10-28 18:57:19 +03:00
# ifndef FSG_NO_DEVICE_STRINGS
2009-10-28 18:57:15 +03:00
{ FSG_STRING_MANUFACTURER , fsg_string_manufacturer } ,
{ FSG_STRING_PRODUCT , fsg_string_product } ,
2010-09-03 19:15:41 +04:00
{ FSG_STRING_SERIAL , " " } ,
2009-10-28 18:57:15 +03:00
{ FSG_STRING_CONFIG , fsg_string_config } ,
2009-10-28 18:57:19 +03:00
# endif
2009-10-28 18:57:15 +03:00
{ FSG_STRING_INTERFACE , fsg_string_interface } ,
2009-10-28 18:57:14 +03:00
{ }
} ;
2009-10-28 18:57:15 +03:00
static struct usb_gadget_strings fsg_stringtab = {
2009-11-09 16:15:23 +03:00
. language = 0x0409 , /* en-us */
2009-10-28 18:57:15 +03:00
. strings = fsg_strings ,
2009-10-28 18:57:14 +03:00
} ;
/*-------------------------------------------------------------------------*/
2010-07-05 18:38:04 +04:00
/*
* If the next two routines are called while the gadget is registered ,
* the caller must own fsg - > filesem for writing .
*/
2009-10-28 18:57:14 +03:00
2009-10-28 18:57:15 +03:00
static int fsg_lun_open ( struct fsg_lun * curlun , const char * filename )
2009-10-28 18:57:14 +03:00
{
int ro ;
struct file * filp = NULL ;
int rc = - EINVAL ;
struct inode * inode = NULL ;
loff_t size ;
loff_t num_sectors ;
loff_t min_sectors ;
/* R/W if we can, R/O if we must */
2009-10-28 18:57:16 +03:00
ro = curlun - > initially_ro ;
2009-10-28 18:57:14 +03:00
if ( ! ro ) {
filp = filp_open ( filename , O_RDWR | O_LARGEFILE , 0 ) ;
2010-11-13 13:55:17 +03:00
if ( PTR_ERR ( filp ) = = - EROFS | | PTR_ERR ( filp ) = = - EACCES )
2009-10-28 18:57:14 +03:00
ro = 1 ;
}
if ( ro )
filp = filp_open ( filename , O_RDONLY | O_LARGEFILE , 0 ) ;
if ( IS_ERR ( filp ) ) {
LINFO ( curlun , " unable to open backing file: %s \n " , filename ) ;
return PTR_ERR ( filp ) ;
}
if ( ! ( filp - > f_mode & FMODE_WRITE ) )
ro = 1 ;
if ( filp - > f_path . dentry )
inode = filp - > f_path . dentry - > d_inode ;
2010-11-13 13:55:17 +03:00
if ( ! inode | | ( ! S_ISREG ( inode - > i_mode ) & & ! S_ISBLK ( inode - > i_mode ) ) ) {
2009-10-28 18:57:14 +03:00
LINFO ( curlun , " invalid file type: %s \n " , filename ) ;
goto out ;
}
2010-07-05 18:38:04 +04:00
/*
* If we can ' t read the file , it ' s no good .
* If we can ' t write the file , use it read - only .
*/
2009-10-28 18:57:14 +03:00
if ( ! filp - > f_op | | ! ( filp - > f_op - > read | | filp - > f_op - > aio_read ) ) {
LINFO ( curlun , " file not readable: %s \n " , filename ) ;
goto out ;
}
if ( ! ( filp - > f_op - > write | | filp - > f_op - > aio_write ) )
ro = 1 ;
size = i_size_read ( inode - > i_mapping - > host ) ;
if ( size < 0 ) {
LINFO ( curlun , " unable to find file size: %s \n " , filename ) ;
rc = ( int ) size ;
goto out ;
}
2009-11-09 16:15:23 +03:00
num_sectors = size > > 9 ; /* File size in 512-byte blocks */
2009-10-28 18:57:14 +03:00
min_sectors = 1 ;
2009-10-28 18:57:16 +03:00
if ( curlun - > cdrom ) {
2009-11-09 16:15:23 +03:00
num_sectors & = ~ 3 ; /* Reduce to a multiple of 2048 */
min_sectors = 300 * 4 ; /* Smallest track is 300 frames */
2009-10-28 18:57:14 +03:00
if ( num_sectors > = 256 * 60 * 75 * 4 ) {
num_sectors = ( 256 * 60 * 75 - 1 ) * 4 ;
LINFO ( curlun , " file too big: %s \n " , filename ) ;
LINFO ( curlun , " using only first %d blocks \n " ,
( int ) num_sectors ) ;
}
}
if ( num_sectors < min_sectors ) {
LINFO ( curlun , " file too small: %s \n " , filename ) ;
rc = - ETOOSMALL ;
goto out ;
}
get_file ( filp ) ;
curlun - > ro = ro ;
curlun - > filp = filp ;
curlun - > file_length = size ;
curlun - > num_sectors = num_sectors ;
LDBG ( curlun , " open backing file: %s \n " , filename ) ;
rc = 0 ;
out :
filp_close ( filp , current - > files ) ;
return rc ;
}
2009-10-28 18:57:15 +03:00
static void fsg_lun_close ( struct fsg_lun * curlun )
2009-10-28 18:57:14 +03:00
{
if ( curlun - > filp ) {
LDBG ( curlun , " close backing file \n " ) ;
fput ( curlun - > filp ) ;
curlun - > filp = NULL ;
}
}
/*-------------------------------------------------------------------------*/
2010-07-05 18:38:04 +04:00
/*
* Sync the file data , don ' t bother with the metadata .
* This code was copied from fs / buffer . c : sys_fdatasync ( ) .
*/
2009-10-28 18:57:15 +03:00
static int fsg_lun_fsync_sub ( struct fsg_lun * curlun )
2009-10-28 18:57:14 +03:00
{
struct file * filp = curlun - > filp ;
if ( curlun - > ro | | ! filp )
return 0 ;
2010-03-22 19:32:25 +03:00
return vfs_fsync ( filp , 1 ) ;
2009-10-28 18:57:14 +03:00
}
static void store_cdrom_address ( u8 * dest , int msf , u32 addr )
{
if ( msf ) {
/* Convert to Minutes-Seconds-Frames */
addr > > = 2 ; /* Convert to 2048-byte frames */
addr + = 2 * 75 ; /* Lead-in occupies 2 seconds */
dest [ 3 ] = addr % 75 ; /* Frames */
addr / = 75 ;
dest [ 2 ] = addr % 60 ; /* Seconds */
addr / = 60 ;
dest [ 1 ] = addr ; /* Minutes */
dest [ 0 ] = 0 ; /* Reserved */
} else {
/* Absolute sector */
put_unaligned_be32 ( addr , dest ) ;
}
}
2009-10-28 18:57:17 +03:00
/*-------------------------------------------------------------------------*/
static ssize_t fsg_show_ro ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
return sprintf ( buf , " %d \n " , fsg_lun_is_open ( curlun )
? curlun - > ro
: curlun - > initially_ro ) ;
}
2010-07-22 18:53:56 +04:00
static ssize_t fsg_show_nofua ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
return sprintf ( buf , " %u \n " , curlun - > nofua ) ;
}
2009-10-28 18:57:17 +03:00
static ssize_t fsg_show_file ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
struct rw_semaphore * filesem = dev_get_drvdata ( dev ) ;
char * p ;
ssize_t rc ;
down_read ( filesem ) ;
2009-11-09 16:15:23 +03:00
if ( fsg_lun_is_open ( curlun ) ) { /* Get the complete pathname */
2009-10-28 18:57:17 +03:00
p = d_path ( & curlun - > filp - > f_path , buf , PAGE_SIZE - 1 ) ;
if ( IS_ERR ( p ) )
rc = PTR_ERR ( p ) ;
else {
rc = strlen ( p ) ;
memmove ( buf , p , rc ) ;
2009-11-09 16:15:23 +03:00
buf [ rc ] = ' \n ' ; /* Add a newline */
2009-10-28 18:57:17 +03:00
buf [ + + rc ] = 0 ;
}
2009-11-09 16:15:23 +03:00
} else { /* No file, return 0 bytes */
2009-10-28 18:57:17 +03:00
* buf = 0 ;
rc = 0 ;
}
up_read ( filesem ) ;
return rc ;
}
static ssize_t fsg_store_ro ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
2011-04-14 13:55:43 +04:00
ssize_t rc ;
2009-10-28 18:57:17 +03:00
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
struct rw_semaphore * filesem = dev_get_drvdata ( dev ) ;
2011-04-14 02:37:00 +04:00
unsigned ro ;
2009-10-28 18:57:17 +03:00
2011-04-14 02:37:00 +04:00
rc = kstrtouint ( buf , 2 , & ro ) ;
if ( rc )
return rc ;
2009-10-28 18:57:17 +03:00
2010-07-05 18:38:04 +04:00
/*
* Allow the write - enable status to change only while the
* backing file is closed .
*/
2009-10-28 18:57:17 +03:00
down_read ( filesem ) ;
if ( fsg_lun_is_open ( curlun ) ) {
LDBG ( curlun , " read-only status change prevented \n " ) ;
rc = - EBUSY ;
} else {
2010-07-22 12:58:47 +04:00
curlun - > ro = ro ;
curlun - > initially_ro = ro ;
2009-10-28 18:57:17 +03:00
LDBG ( curlun , " read-only status set to %d \n " , curlun - > ro ) ;
2011-04-14 13:55:43 +04:00
rc = count ;
2009-10-28 18:57:17 +03:00
}
up_read ( filesem ) ;
return rc ;
}
2010-07-22 18:53:56 +04:00
static ssize_t fsg_store_nofua ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
2011-04-14 02:37:00 +04:00
unsigned nofua ;
int ret ;
2010-07-22 18:53:56 +04:00
2011-04-14 02:37:00 +04:00
ret = kstrtouint ( buf , 2 , & nofua ) ;
if ( ret )
return ret ;
2010-07-22 18:53:56 +04:00
/* Sync data when switching from async mode to sync */
if ( ! nofua & & curlun - > nofua )
fsg_lun_fsync_sub ( curlun ) ;
curlun - > nofua = nofua ;
return count ;
}
2009-10-28 18:57:17 +03:00
static ssize_t fsg_store_file ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct fsg_lun * curlun = fsg_lun_from_dev ( dev ) ;
struct rw_semaphore * filesem = dev_get_drvdata ( dev ) ;
int rc = 0 ;
if ( curlun - > prevent_medium_removal & & fsg_lun_is_open ( curlun ) ) {
LDBG ( curlun , " eject attempt prevented \n " ) ;
2009-11-09 16:15:23 +03:00
return - EBUSY ; /* "Door is locked" */
2009-10-28 18:57:17 +03:00
}
/* Remove a trailing newline */
if ( count > 0 & & buf [ count - 1 ] = = ' \n ' )
2009-11-09 16:15:23 +03:00
( ( char * ) buf ) [ count - 1 ] = 0 ; /* Ugh! */
2009-10-28 18:57:17 +03:00
/* Eject current medium */
down_write ( filesem ) ;
if ( fsg_lun_is_open ( curlun ) ) {
fsg_lun_close ( curlun ) ;
curlun - > unit_attention_data = SS_MEDIUM_NOT_PRESENT ;
}
/* Load new medium */
if ( count > 0 & & buf [ 0 ] ) {
rc = fsg_lun_open ( curlun , buf ) ;
if ( rc = = 0 )
curlun - > unit_attention_data =
SS_NOT_READY_TO_READY_TRANSITION ;
}
up_write ( filesem ) ;
return ( rc < 0 ? rc : count ) ;
}