2009-10-28 16:57:18 +01:00
/*
2009-11-09 14:15:23 +01:00
* f_mass_storage . c - - Mass Storage USB Composite Function
2009-10-28 16:57:18 +01:00
*
* Copyright ( C ) 2003 - 2008 Alan Stern
2009-11-09 14:15:23 +01:00
* Copyright ( C ) 2009 Samsung Electronics
* Author : Michal Nazarewicz < m . nazarewicz @ samsung . com >
2009-10-28 16:57:18 +01:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The names of the above - listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission .
*
* ALTERNATIVELY , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) as published by the Free Software
* Foundation , either version 2 of that License or ( at your option ) any
* later version .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS
* IS " AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
/*
2009-11-09 14:15:23 +01:00
* The Mass Storage Function acts as a USB Mass Storage device ,
* appearing to the host as a disk drive or as a CD - ROM drive . In
* addition to providing an example of a genuinely useful composite
* function for a USB device , it also illustrates a technique of
* double - buffering for increased throughput .
2009-10-28 16:57:18 +01:00
*
2009-11-09 14:15:23 +01:00
* Function supports multiple logical units ( LUNs ) . Backing storage
* for each LUN is provided by a regular file or a block device .
* Access for each LUN can be limited to read - only . Moreover , the
* function can indicate that LUN is removable and / or CD - ROM . ( The
* later implies read - only access . )
*
* MSF is configured by specifying a fsg_config structure . It has the
* following fields :
*
* nluns Number of LUNs function have ( anywhere from 1
* to FSG_MAX_LUNS which is 8 ) .
* luns An array of LUN configuration values . This
* should be filled for each LUN that
* function will include ( ie . for " nluns "
* LUNs ) . Each element of the array has
* the following fields :
* - > filename The path to the backing file for the LUN .
* Required if LUN is not marked as
* removable .
* - > ro Flag specifying access to the LUN shall be
* read - only . This is implied if CD - ROM
* emulation is enabled as well as when
* it was impossible to open " filename "
* in R / W mode .
* - > removable Flag specifying that LUN shall be indicated as
* being removable .
* - > cdrom Flag specifying that LUN shall be reported as
* being a CD - ROM .
2010-08-12 17:43:51 +02:00
* - > nofua Flag specifying that FUA flag in SCSI WRITE ( 10 , 12 )
* commands for this LUN shall be ignored .
2009-11-09 14:15:23 +01:00
*
* lun_name_format A printf - like format for names of the LUN
* devices . This determines how the
* directory in sysfs will be named .
* Unless you are using several MSFs in
* a single gadget ( as opposed to single
* MSF in many configurations ) you may
* leave it as NULL ( in which case
* " lun%d " will be used ) . In the format
* you can use " %d " to index LUNs for
* MSF ' s with more than one LUN . ( Beware
* that there is only one integer given
* as an argument for the format and
* specifying invalid format may cause
* unspecified behaviour . )
* thread_name Name of the kernel thread process used by the
* MSF . You can safely set it to NULL
* ( in which case default " file-storage "
* will be used ) .
*
* vendor_name
* product_name
* release Information used as a reply to INQUIRY
* request . To use default set to NULL ,
* NULL , 0xffff respectively . The first
* field should be 8 and the second 16
* characters or less .
*
* can_stall Set to permit function to halt bulk endpoints .
* Disabled on some USB devices known not
* to work correctly . You should set it
* to true .
*
* If " removable " is not set for a LUN then a backing file must be
* specified . If it is set , then NULL filename means the LUN ' s medium
* is not loaded ( an empty string as " filename " in the fsg_config
* structure causes error ) . The CD - ROM emulation includes a single
* data track and no audio tracks ; hence there need be only one
* backing file per LUN . Note also that the CD - ROM block length is
* set to 512 rather than the more common value 2048.
*
*
* MSF includes support for module parameters . If gadget using it
* decides to use it , the following module parameters will be
* available :
*
* file = filename [ , filename . . . ]
* Names of the files or block devices used for
* backing storage .
* ro = b [ , b . . . ] Default false , boolean for read - only access .
* removable = b [ , b . . . ]
* Default true , boolean for removable media .
* cdrom = b [ , b . . . ] Default false , boolean for whether to emulate
* a CD - ROM drive .
2010-08-12 17:43:51 +02:00
* nofua = b [ , b . . . ] Default false , booleans for ignore FUA flag
* in SCSI WRITE ( 10 , 12 ) commands
2009-11-09 14:15:23 +01:00
* luns = N Default N = number of filenames , number of
* LUNs to support .
* stall Default determined according to the type of
* USB device controller ( usually true ) ,
* boolean to permit the driver to halt
* bulk endpoints .
*
* The module parameters may be prefixed with some string . You need
* to consult gadget ' s documentation or source to verify whether it is
* using those module parameters and if it does what are the prefixes
* ( look for FSG_MODULE_PARAMETERS ( ) macro usage , what ' s inside it is
* the prefix ) .
2009-10-28 16:57:18 +01:00
*
*
* Requirements are modest ; only a bulk - in and a bulk - out endpoint are
2009-11-09 14:15:23 +01:00
* needed . The memory requirement amounts to two 16 K buffers , size
* configurable by a parameter . Support is included for both
* full - speed and high - speed operation .
2009-10-28 16:57:18 +01:00
*
* Note that the driver is slightly non - portable in that it assumes a
* single memory / DMA buffer will be useable for bulk - in , bulk - out , and
* interrupt - in endpoints . With most device controllers this isn ' t an
* issue , but there may be some with hardware restrictions that prevent
* a buffer from being used by more than one endpoint .
*
*
2009-11-09 14:15:23 +01:00
* The pathnames of the backing files and the ro settings are
* available in the attribute files " file " and " ro " in the lun < n > ( or
* to be more precise in a directory which name comes from
* " lun_name_format " option ! ) subdirectory of the gadget ' s sysfs
* directory . If the " removable " option is set , writing to these
* files will simulate ejecting / loading the medium ( writing an empty
* line means eject ) and adjusting a write - enable tab . Changes to the
* ro setting are not allowed when the medium is loaded or if CD - ROM
* emulation is being used .
2009-10-28 16:57:18 +01:00
*
2010-04-26 12:34:54 +02:00
* When a LUN receive an " eject " SCSI request ( Start / Stop Unit ) ,
* if the LUN is removable , the backing file is released to simulate
* ejection .
*
2009-10-28 16:57:18 +01:00
*
2009-11-09 14:15:23 +01:00
* This function is heavily based on " File-backed Storage Gadget " by
* Alan Stern which in turn is heavily based on " Gadget Zero " by David
* Brownell . The driver ' s SCSI command interface was based on the
* " Information technology - Small Computer System Interface - 2 "
* document from X3T9 .2 Project 375 D , Revision 10L , 7 - SEP - 93 ,
* available at < http : //www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>.
* The single exception is opcode 0x23 ( READ FORMAT CAPACITIES ) , which
* was based on the " Universal Serial Bus Mass Storage Class UFI
* Command Specification " document, Revision 1.0, December 14, 1998,
* available at
2009-10-28 16:57:18 +01:00
* < http : //www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>.
*/
/*
* Driver Design
*
2009-11-09 14:15:23 +01:00
* The MSF is fairly straightforward . There is a main kernel
2009-10-28 16:57:18 +01:00
* thread that handles most of the work . Interrupt routines field
* callbacks from the controller driver : bulk - and interrupt - request
* completion notifications , endpoint - 0 events , and disconnect events .
* Completion events are passed to the main thread by wakeup calls . Many
* ep0 requests are handled at interrupt time , but SetInterface ,
* SetConfiguration , and device reset requests are forwarded to the
* thread in the form of " exceptions " using SIGUSR1 signals ( since they
* should interrupt any ongoing file I / O operations ) .
*
* The thread ' s main routine implements the standard command / data / status
* parts of a SCSI interaction . It and its subroutines are full of tests
* for pending signals / exceptions - - all this polling is necessary since
* the kernel has no setjmp / longjmp equivalents . ( Maybe this is an
* indication that the driver really wants to be running in userspace . )
* An important point is that so long as the thread is alive it keeps an
* open reference to the backing file . This will prevent unmounting
* the backing file ' s underlying filesystem and could cause problems
* during system shutdown , for example . To prevent such problems , the
* thread catches INT , TERM , and KILL signals and converts them into
* an EXIT exception .
*
* In normal operation the main thread is started during the gadget ' s
2009-11-09 14:15:23 +01:00
* fsg_bind ( ) callback and stopped during fsg_unbind ( ) . But it can
* also exit when it receives a signal , and there ' s no point leaving
* the gadget running when the thread is dead . At of this moment , MSF
* provides no way to deregister the gadget when thread dies - - maybe
* a callback functions is needed .
2009-10-28 16:57:18 +01:00
*
* To provide maximum throughput , the driver uses a circular pipeline of
* buffer heads ( struct fsg_buffhd ) . In principle the pipeline can be
* arbitrarily long ; in practice the benefits don ' t justify having more
* than 2 stages ( i . e . , double buffering ) . But it helps to think of the
* pipeline as being a long one . Each buffer head contains a bulk - in and
* a bulk - out request pointer ( since the buffer can be used for both
* output and input - - directions always are given from the host ' s
* point of view ) as well as a pointer to the buffer and various state
* variables .
*
* Use of the pipeline follows a simple protocol . There is a variable
* ( fsg - > next_buffhd_to_fill ) that points to the next buffer head to use .
* At any time that buffer head may still be in use from an earlier
* request , so each buffer head has a state variable indicating whether
* it is EMPTY , FULL , or BUSY . Typical use involves waiting for the
* buffer head to be EMPTY , filling the buffer either by file I / O or by
* USB I / O ( during which the buffer head is BUSY ) , and marking the buffer
* head FULL when the I / O is complete . Then the buffer will be emptied
* ( again possibly by USB I / O , during which it is marked BUSY ) and
* finally marked EMPTY again ( possibly by a completion routine ) .
*
* A module parameter tells the driver to avoid stalling the bulk
* endpoints wherever the transport specification allows . This is
* necessary for some UDCs like the SuperH , which cannot reliably clear a
* halt on a bulk endpoint . However , under certain circumstances the
* Bulk - only specification requires a stall . In such cases the driver
* will halt the endpoint and set a flag indicating that it should clear
* the halt in software during the next device reset . Hopefully this
* will permit everything to work correctly . Furthermore , although the
* specification allows the bulk - out endpoint to halt when the host sends
* too much data , implementing this would cause an unavoidable race .
* The driver will always use the " no-stall " approach for OUT transfers .
*
* One subtle point concerns sending status - stage responses for ep0
* requests . Some of these requests , such as device reset , can involve
* interrupting an ongoing file I / O operation , which might take an
* arbitrarily long time . During that delay the host might give up on
* the original ep0 request and issue a new one . When that happens the
* driver should not notify the host about completion of the original
* request , as the host will no longer be waiting for it . So the driver
* assigns to each ep0 request a unique tag , and it keeps track of the
* tag value of the request associated with a long - running exception
* ( device - reset , interface - change , or configuration - change ) . When the
* exception handler is finished , the status - stage response is submitted
* only if the current ep0 request tag is equal to the exception request
* tag . Thus only the most recently received ep0 request will get a
* status - stage response .
*
* Warning : This driver source file is too long . It ought to be split up
* into a header file plus about 3 separate . c files , to handle the details
* of the Gadget , USB Mass Storage , and SCSI protocols .
*/
/* #define VERBOSE_DEBUG */
/* #define DUMP_MSGS */
# include <linux/blkdev.h>
# include <linux/completion.h>
# include <linux/dcache.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/fcntl.h>
# include <linux/file.h>
# include <linux/fs.h>
# include <linux/kref.h>
# include <linux/kthread.h>
# include <linux/limits.h>
# include <linux/rwsem.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/string.h>
# include <linux/freezer.h>
# include <linux/utsname.h>
# include <linux/usb/ch9.h>
# include <linux/usb/gadget.h>
2011-01-29 02:26:51 +01:00
# include <linux/usb/composite.h>
2009-10-28 16:57:18 +01:00
# include "gadget_chips.h"
2009-11-09 14:15:22 +01:00
/*------------------------------------------------------------------------*/
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:20 +01:00
# define FSG_DRIVER_DESC "Mass Storage Function"
2009-11-09 14:15:23 +01:00
# define FSG_DRIVER_VERSION "2009 / 09 / 11"
2009-10-28 16:57:18 +01:00
static const char fsg_string_interface [ ] = " Mass Storage " ;
2009-10-28 16:57:19 +01:00
# define FSG_NO_INTR_EP 1
2009-11-09 14:15:20 +01:00
# define FSG_NO_DEVICE_STRINGS 1
# define FSG_NO_OTG 1
# define FSG_NO_INTR_EP 1
2009-10-28 16:57:19 +01:00
2009-10-28 16:57:18 +01:00
# include "storage_common.c"
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
struct fsg_dev ;
2010-06-21 13:57:09 +02:00
struct fsg_common ;
/* FSF callback functions */
struct fsg_operations {
2010-10-28 17:31:23 +02:00
/*
* Callback function to call when thread exits . If no
2010-06-21 13:57:09 +02:00
* callback is set or it returns value lower then zero MSF
* will force eject all LUNs it operates on ( including those
* marked as non - removable or with prevent_medium_removal flag
2010-10-28 17:31:23 +02:00
* set ) .
*/
2010-06-21 13:57:09 +02:00
int ( * thread_exits ) ( struct fsg_common * common ) ;
2010-10-28 17:31:23 +02:00
/*
* Called prior to ejection . Negative return means error ,
2010-06-21 13:57:09 +02:00
* zero means to continue with ejection , positive means not to
2010-10-28 17:31:23 +02:00
* eject .
*/
2010-06-21 13:57:09 +02:00
int ( * pre_eject ) ( struct fsg_common * common ,
struct fsg_lun * lun , int num ) ;
2010-10-28 17:31:23 +02:00
/*
* Called after ejection . Negative return means error , zero
* or positive is just a success .
*/
2010-06-21 13:57:09 +02:00
int ( * post_eject ) ( struct fsg_common * common ,
struct fsg_lun * lun , int num ) ;
} ;
2009-11-09 14:15:24 +01:00
2009-10-28 16:57:20 +01:00
/* Data shared by all the FSG instances. */
struct fsg_common {
2009-10-28 16:57:22 +01:00
struct usb_gadget * gadget ;
2010-06-25 16:29:28 +02:00
struct fsg_dev * fsg , * new_fsg ;
wait_queue_head_t fsg_wait ;
2009-10-28 16:57:22 +01:00
2009-10-28 16:57:20 +01:00
/* filesem protects: backing files in use */
struct rw_semaphore filesem ;
2009-11-09 14:15:24 +01:00
/* lock protects: state, all the req_busy's */
spinlock_t lock ;
struct usb_ep * ep0 ; /* Copy of gadget->ep0 */
struct usb_request * ep0req ; /* Copy of cdev->req */
unsigned int ep0_req_tag ;
2009-10-28 16:57:20 +01:00
struct fsg_buffhd * next_buffhd_to_fill ;
struct fsg_buffhd * next_buffhd_to_drain ;
struct fsg_buffhd buffhds [ FSG_NUM_BUFFERS ] ;
int cmnd_size ;
u8 cmnd [ MAX_COMMAND_SIZE ] ;
unsigned int nluns ;
unsigned int lun ;
struct fsg_lun * luns ;
struct fsg_lun * curlun ;
2009-10-28 16:57:22 +01:00
2009-11-09 14:15:24 +01:00
unsigned int bulk_out_maxpacket ;
enum fsg_state state ; /* For exception handling */
unsigned int exception_req_tag ;
enum data_direction data_dir ;
u32 data_size ;
u32 data_size_from_cmnd ;
u32 tag ;
u32 residue ;
u32 usb_amount_left ;
2009-11-09 14:15:21 +01:00
unsigned int can_stall : 1 ;
2009-10-28 16:57:22 +01:00
unsigned int free_storage_on_release : 1 ;
2009-11-09 14:15:24 +01:00
unsigned int phase_error : 1 ;
unsigned int short_packet_received : 1 ;
unsigned int bad_lun_okay : 1 ;
unsigned int running : 1 ;
2009-10-28 16:57:22 +01:00
2009-11-09 14:15:24 +01:00
int thread_wakeup_needed ;
struct completion thread_notifier ;
struct task_struct * thread_task ;
2009-11-09 14:15:22 +01:00
2010-06-21 13:57:09 +02:00
/* Callback functions. */
const struct fsg_operations * ops ;
2009-11-09 14:15:26 +01:00
/* Gadget's private data. */
void * private_data ;
2010-10-28 17:31:23 +02:00
/*
* Vendor ( 8 chars ) , product ( 16 chars ) , release ( 4
* hexadecimal digits ) and NUL byte
*/
2009-11-09 14:15:21 +01:00
char inquiry_string [ 8 + 16 + 4 + 1 ] ;
2009-10-28 16:57:22 +01:00
struct kref ref ;
2009-10-28 16:57:20 +01:00
} ;
2009-11-09 14:15:21 +01:00
struct fsg_config {
unsigned nluns ;
struct fsg_lun_config {
const char * filename ;
char ro ;
char removable ;
char cdrom ;
2010-08-12 17:43:51 +02:00
char nofua ;
2009-11-09 14:15:21 +01:00
} luns [ FSG_MAX_LUNS ] ;
2009-11-09 14:15:22 +01:00
const char * lun_name_format ;
const char * thread_name ;
2010-06-21 13:57:09 +02:00
/* Callback functions. */
const struct fsg_operations * ops ;
2009-11-09 14:15:26 +01:00
/* Gadget's private data. */
void * private_data ;
2009-11-09 14:15:21 +01:00
const char * vendor_name ; /* 8 characters or less */
const char * product_name ; /* 16 characters or less */
u16 release ;
char can_stall ;
} ;
2009-10-28 16:57:18 +01:00
struct fsg_dev {
2009-11-09 14:15:20 +01:00
struct usb_function function ;
struct usb_gadget * gadget ; /* Copy of cdev->gadget */
2009-10-28 16:57:20 +01:00
struct fsg_common * common ;
2009-11-09 14:15:20 +01:00
u16 interface_number ;
2009-11-09 14:15:23 +01:00
unsigned int bulk_in_enabled : 1 ;
unsigned int bulk_out_enabled : 1 ;
2009-10-28 16:57:18 +01:00
unsigned long atomic_bitflags ;
2009-11-09 14:15:24 +01:00
# define IGNORE_BULK_OUT 0
2009-10-28 16:57:18 +01:00
struct usb_ep * bulk_in ;
struct usb_ep * bulk_out ;
2009-11-09 14:15:24 +01:00
} ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
static inline int __fsg_is_set ( struct fsg_common * common ,
const char * func , unsigned line )
{
if ( common - > fsg )
return 1 ;
ERROR ( common , " common->fsg is NULL in %s at %u \n " , func , line ) ;
2010-06-21 13:57:09 +02:00
WARN_ON ( 1 ) ;
2009-11-09 14:15:24 +01:00
return 0 ;
}
# define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__))
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:20 +01:00
static inline struct fsg_dev * fsg_from_func ( struct usb_function * f )
{
return container_of ( f , struct fsg_dev , function ) ;
}
2009-10-28 16:57:18 +01:00
typedef void ( * fsg_routine_t ) ( struct fsg_dev * ) ;
2009-11-09 14:15:24 +01:00
static int exception_in_progress ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
return common - > state > FSG_STATE_IDLE ;
2009-10-28 16:57:18 +01:00
}
/*-------------------------------------------------------------------------*/
static int fsg_set_halt ( struct fsg_dev * fsg , struct usb_ep * ep )
{
const char * name ;
if ( ep = = fsg - > bulk_in )
name = " bulk-in " ;
else if ( ep = = fsg - > bulk_out )
name = " bulk-out " ;
else
name = ep - > name ;
DBG ( fsg , " %s set halt \n " , name ) ;
return usb_ep_set_halt ( ep ) ;
}
/*-------------------------------------------------------------------------*/
/* These routines may be called in process context or in_irq */
/* Caller must hold fsg->lock */
2009-11-09 14:15:24 +01:00
static void wakeup_thread ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
/* Tell the main thread that something has happened */
2009-11-09 14:15:24 +01:00
common - > thread_wakeup_needed = 1 ;
if ( common - > thread_task )
wake_up_process ( common - > thread_task ) ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
static void raise_exception ( struct fsg_common * common , enum fsg_state new_state )
2009-10-28 16:57:18 +01:00
{
unsigned long flags ;
2010-10-28 17:31:23 +02:00
/*
* Do nothing if a higher - priority exception is already in progress .
2009-10-28 16:57:18 +01:00
* If a lower - or - equal priority exception is in progress , preempt it
2010-10-28 17:31:23 +02:00
* and notify the main thread by sending it a signal .
*/
2009-11-09 14:15:24 +01:00
spin_lock_irqsave ( & common - > lock , flags ) ;
if ( common - > state < = new_state ) {
common - > exception_req_tag = common - > ep0_req_tag ;
common - > state = new_state ;
if ( common - > thread_task )
2009-10-28 16:57:18 +01:00
send_sig_info ( SIGUSR1 , SEND_SIG_FORCED ,
2009-11-09 14:15:24 +01:00
common - > thread_task ) ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
spin_unlock_irqrestore ( & common - > lock , flags ) ;
2009-10-28 16:57:18 +01:00
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static int ep0_queue ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
int rc ;
2009-11-09 14:15:24 +01:00
rc = usb_ep_queue ( common - > ep0 , common - > ep0req , GFP_ATOMIC ) ;
common - > ep0 - > driver_data = common ;
2009-10-28 16:57:18 +01:00
if ( rc ! = 0 & & rc ! = - ESHUTDOWN ) {
/* We can't do much more than wait for a reset */
2009-11-09 14:15:24 +01:00
WARNING ( common , " error in submission: %s --> %d \n " ,
common - > ep0 - > name , rc ) ;
2009-10-28 16:57:18 +01:00
}
return rc ;
}
2010-10-28 17:31:23 +02:00
2009-10-28 16:57:18 +01:00
/*-------------------------------------------------------------------------*/
2010-10-28 17:31:23 +02:00
/* Completion handlers. These always run in_irq. */
2009-10-28 16:57:18 +01:00
static void bulk_in_complete ( struct usb_ep * ep , struct usb_request * req )
{
2009-11-09 14:15:24 +01:00
struct fsg_common * common = ep - > driver_data ;
2009-10-28 16:57:18 +01:00
struct fsg_buffhd * bh = req - > context ;
if ( req - > status | | req - > actual ! = req - > length )
2009-11-09 14:15:24 +01:00
DBG ( common , " %s --> %d, %u/%u \n " , __func__ ,
2010-10-28 17:31:23 +02:00
req - > status , req - > actual , req - > length ) ;
2009-11-09 14:15:23 +01:00
if ( req - > status = = - ECONNRESET ) /* Request was cancelled */
2009-10-28 16:57:18 +01:00
usb_ep_fifo_flush ( ep ) ;
/* Hold the lock while we update the request and buffer states */
smp_wmb ( ) ;
2009-11-09 14:15:24 +01:00
spin_lock ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
bh - > inreq_busy = 0 ;
bh - > state = BUF_STATE_EMPTY ;
2009-11-09 14:15:24 +01:00
wakeup_thread ( common ) ;
spin_unlock ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
}
static void bulk_out_complete ( struct usb_ep * ep , struct usb_request * req )
{
2009-11-09 14:15:24 +01:00
struct fsg_common * common = ep - > driver_data ;
2009-10-28 16:57:18 +01:00
struct fsg_buffhd * bh = req - > context ;
2009-11-09 14:15:24 +01:00
dump_msg ( common , " bulk-out " , req - > buf , req - > actual ) ;
2011-03-24 12:20:13 +01:00
if ( req - > status | | req - > actual ! = req - > length )
2009-11-09 14:15:24 +01:00
DBG ( common , " %s --> %d, %u/%u \n " , __func__ ,
2011-03-24 12:20:13 +01:00
req - > status , req - > actual , req - > length ) ;
2009-11-09 14:15:23 +01:00
if ( req - > status = = - ECONNRESET ) /* Request was cancelled */
2009-10-28 16:57:18 +01:00
usb_ep_fifo_flush ( ep ) ;
/* Hold the lock while we update the request and buffer states */
smp_wmb ( ) ;
2009-11-09 14:15:24 +01:00
spin_lock ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
bh - > outreq_busy = 0 ;
bh - > state = BUF_STATE_FULL ;
2009-11-09 14:15:24 +01:00
wakeup_thread ( common ) ;
spin_unlock ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:20 +01:00
static int fsg_setup ( struct usb_function * f ,
2010-10-28 17:31:23 +02:00
const struct usb_ctrlrequest * ctrl )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:20 +01:00
struct fsg_dev * fsg = fsg_from_func ( f ) ;
2009-11-09 14:15:24 +01:00
struct usb_request * req = fsg - > common - > ep0req ;
2009-10-28 16:57:18 +01:00
u16 w_index = le16_to_cpu ( ctrl - > wIndex ) ;
2009-10-28 16:57:19 +01:00
u16 w_value = le16_to_cpu ( ctrl - > wValue ) ;
2009-10-28 16:57:18 +01:00
u16 w_length = le16_to_cpu ( ctrl - > wLength ) ;
2010-06-25 16:29:28 +02:00
if ( ! fsg_is_set ( fsg - > common ) )
2009-10-28 16:57:19 +01:00
return - EOPNOTSUPP ;
2009-10-28 16:57:18 +01:00
2011-04-05 18:36:38 +03:00
+ + fsg - > common - > ep0_req_tag ; /* Record arrival of a new request */
req - > context = NULL ;
req - > length = 0 ;
dump_msg ( fsg , " ep0-setup " , ( u8 * ) ctrl , sizeof ( * ctrl ) ) ;
2009-10-28 16:57:19 +01:00
switch ( ctrl - > bRequest ) {
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:19 +01:00
case USB_BULK_RESET_REQUEST :
if ( ctrl - > bRequestType ! =
( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE ) )
2009-10-28 16:57:18 +01:00
break ;
2009-11-09 14:15:20 +01:00
if ( w_index ! = fsg - > interface_number | | w_value ! = 0 )
2009-10-28 16:57:19 +01:00
return - EDOM ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* Raise an exception to stop the current operation
* and reinitialize our state .
*/
2009-10-28 16:57:19 +01:00
DBG ( fsg , " bulk reset request \n " ) ;
2009-11-09 14:15:24 +01:00
raise_exception ( fsg - > common , FSG_STATE_RESET ) ;
2009-10-28 16:57:19 +01:00
return DELAYED_STATUS ;
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:19 +01:00
case USB_BULK_GET_MAX_LUN_REQUEST :
if ( ctrl - > bRequestType ! =
( USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE ) )
2009-10-28 16:57:18 +01:00
break ;
2009-11-09 14:15:20 +01:00
if ( w_index ! = fsg - > interface_number | | w_value ! = 0 )
2009-10-28 16:57:19 +01:00
return - EDOM ;
VDBG ( fsg , " get max LUN \n " ) ;
2010-10-28 17:31:23 +02:00
* ( u8 * ) req - > buf = fsg - > common - > nluns - 1 ;
2010-01-27 11:14:28 +01:00
/* Respond with data/status */
2010-02-03 11:37:17 +01:00
req - > length = min ( ( u16 ) 1 , w_length ) ;
2010-01-27 11:14:28 +01:00
return ep0_queue ( fsg - > common ) ;
2009-10-28 16:57:19 +01:00
}
VDBG ( fsg ,
2010-10-28 17:31:23 +02:00
" unknown class-specific control req %02x.%02x v%04x i%04x l%u \n " ,
2009-10-28 16:57:19 +01:00
ctrl - > bRequestType , ctrl - > bRequest ,
le16_to_cpu ( ctrl - > wValue ) , w_index , w_length ) ;
return - EOPNOTSUPP ;
2009-10-28 16:57:18 +01:00
}
/*-------------------------------------------------------------------------*/
/* All the following routines run in process context */
/* Use this for bulk or interrupt transfers, not ep0 */
static void start_transfer ( struct fsg_dev * fsg , struct usb_ep * ep ,
2010-10-28 17:31:23 +02:00
struct usb_request * req , int * pbusy ,
enum fsg_buffer_state * state )
2009-10-28 16:57:18 +01:00
{
int rc ;
if ( ep = = fsg - > bulk_in )
dump_msg ( fsg , " bulk-in " , req - > buf , req - > length ) ;
2009-11-09 14:15:24 +01:00
spin_lock_irq ( & fsg - > common - > lock ) ;
2009-10-28 16:57:18 +01:00
* pbusy = 1 ;
* state = BUF_STATE_BUSY ;
2009-11-09 14:15:24 +01:00
spin_unlock_irq ( & fsg - > common - > lock ) ;
2009-10-28 16:57:18 +01:00
rc = usb_ep_queue ( ep , req , GFP_KERNEL ) ;
if ( rc ! = 0 ) {
* pbusy = 0 ;
* state = BUF_STATE_EMPTY ;
/* We can't do much more than wait for a reset */
2010-10-28 17:31:23 +02:00
/*
* Note : currently the net2280 driver fails zero - length
* submissions if DMA is enabled .
*/
if ( rc ! = - ESHUTDOWN & &
! ( rc = = - EOPNOTSUPP & & req - > length = = 0 ) )
2009-10-28 16:57:18 +01:00
WARNING ( fsg , " error in submission: %s --> %d \n " ,
2010-10-28 17:31:23 +02:00
ep - > name , rc ) ;
2009-10-28 16:57:18 +01:00
}
}
2010-10-28 17:31:21 +02:00
static bool start_in_transfer ( struct fsg_common * common , struct fsg_buffhd * bh )
{
if ( ! fsg_is_set ( common ) )
return false ;
start_transfer ( common - > fsg , common - > fsg - > bulk_in ,
bh - > inreq , & bh - > inreq_busy , & bh - > state ) ;
return true ;
}
2009-11-09 14:15:24 +01:00
2010-10-28 17:31:21 +02:00
static bool start_out_transfer ( struct fsg_common * common , struct fsg_buffhd * bh )
{
if ( ! fsg_is_set ( common ) )
return false ;
start_transfer ( common - > fsg , common - > fsg - > bulk_out ,
bh - > outreq , & bh - > outreq_busy , & bh - > state ) ;
return true ;
}
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
static int sleep_thread ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
int rc = 0 ;
/* Wait until a signal arrives or we are woken up */
for ( ; ; ) {
try_to_freeze ( ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
if ( signal_pending ( current ) ) {
rc = - EINTR ;
break ;
}
2009-11-09 14:15:24 +01:00
if ( common - > thread_wakeup_needed )
2009-10-28 16:57:18 +01:00
break ;
schedule ( ) ;
}
__set_current_state ( TASK_RUNNING ) ;
2009-11-09 14:15:24 +01:00
common - > thread_wakeup_needed = 0 ;
2009-10-28 16:57:18 +01:00
return rc ;
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static int do_read ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
u32 lba ;
struct fsg_buffhd * bh ;
int rc ;
u32 amount_left ;
loff_t file_offset , file_offset_tmp ;
unsigned int amount ;
unsigned int partial_page ;
ssize_t nread ;
2010-10-28 17:31:23 +02:00
/*
* Get the starting Logical Block Address and check that it ' s
* not too big .
*/
2010-10-07 14:46:15 +02:00
if ( common - > cmnd [ 0 ] = = READ_6 )
2009-11-09 14:15:24 +01:00
lba = get_unaligned_be24 ( & common - > cmnd [ 1 ] ) ;
2009-10-28 16:57:18 +01:00
else {
2009-11-09 14:15:24 +01:00
lba = get_unaligned_be32 ( & common - > cmnd [ 2 ] ) ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* We allow DPO ( Disable Page Out = don ' t save data in the
2009-10-28 16:57:18 +01:00
* cache ) and FUA ( Force Unit Access = don ' t read from the
2010-10-28 17:31:23 +02:00
* cache ) , but we don ' t implement them .
*/
2009-11-09 14:15:24 +01:00
if ( ( common - > cmnd [ 1 ] & ~ 0x18 ) ! = 0 ) {
2009-10-28 16:57:18 +01:00
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
}
if ( lba > = curlun - > num_sectors ) {
curlun - > sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE ;
return - EINVAL ;
}
file_offset = ( ( loff_t ) lba ) < < 9 ;
/* Carry out the file reads */
2009-11-09 14:15:24 +01:00
amount_left = common - > data_size_from_cmnd ;
2009-10-28 16:57:18 +01:00
if ( unlikely ( amount_left = = 0 ) )
2009-11-09 14:15:23 +01:00
return - EIO ; /* No default reply */
2009-10-28 16:57:18 +01:00
for ( ; ; ) {
2010-10-28 17:31:23 +02:00
/*
* Figure out how much we need to read :
2009-10-28 16:57:18 +01:00
* Try to read the remaining amount .
* But don ' t read more than the buffer size .
* And don ' t try to read past the end of the file .
* Finally , if we ' re not at a page boundary , don ' t read past
* the next page .
* If this means reading 0 then we were asked to read past
2010-10-28 17:31:23 +02:00
* the end of file .
*/
2009-10-28 16:57:19 +01:00
amount = min ( amount_left , FSG_BUFLEN ) ;
2010-10-28 17:31:23 +02:00
amount = min ( ( loff_t ) amount ,
curlun - > file_length - file_offset ) ;
2009-10-28 16:57:18 +01:00
partial_page = file_offset & ( PAGE_CACHE_SIZE - 1 ) ;
if ( partial_page > 0 )
2010-10-28 17:31:23 +02:00
amount = min ( amount , ( unsigned int ) PAGE_CACHE_SIZE -
partial_page ) ;
2009-10-28 16:57:18 +01:00
/* Wait for the next buffer to become available */
2009-11-09 14:15:24 +01:00
bh = common - > next_buffhd_to_fill ;
2009-10-28 16:57:18 +01:00
while ( bh - > state ! = BUF_STATE_EMPTY ) {
2009-11-09 14:15:24 +01:00
rc = sleep_thread ( common ) ;
2009-10-28 16:57:18 +01:00
if ( rc )
return rc ;
}
2010-10-28 17:31:23 +02:00
/*
* If we were asked to read past the end of file ,
* end with an empty buffer .
*/
2009-10-28 16:57:18 +01:00
if ( amount = = 0 ) {
curlun - > sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE ;
curlun - > sense_data_info = file_offset > > 9 ;
curlun - > info_valid = 1 ;
bh - > inreq - > length = 0 ;
bh - > state = BUF_STATE_FULL ;
break ;
}
/* Perform the read */
file_offset_tmp = file_offset ;
nread = vfs_read ( curlun - > filp ,
2010-10-28 17:31:23 +02:00
( char __user * ) bh - > buf ,
amount , & file_offset_tmp ) ;
2009-10-28 16:57:18 +01:00
VLDBG ( curlun , " file read %u @ %llu -> %d \n " , amount ,
2010-10-28 17:31:23 +02:00
( unsigned long long ) file_offset , ( int ) nread ) ;
2009-10-28 16:57:18 +01:00
if ( signal_pending ( current ) )
return - EINTR ;
if ( nread < 0 ) {
2010-10-28 17:31:23 +02:00
LDBG ( curlun , " error in file read: %d \n " , ( int ) nread ) ;
2009-10-28 16:57:18 +01:00
nread = 0 ;
} else if ( nread < amount ) {
LDBG ( curlun , " partial file read: %d/%u \n " ,
2010-10-28 17:31:23 +02:00
( int ) nread , amount ) ;
2009-11-09 14:15:23 +01:00
nread - = ( nread & 511 ) ; /* Round down to a block */
2009-10-28 16:57:18 +01:00
}
file_offset + = nread ;
amount_left - = nread ;
2009-11-09 14:15:24 +01:00
common - > residue - = nread ;
2009-10-28 16:57:18 +01:00
bh - > inreq - > length = nread ;
bh - > state = BUF_STATE_FULL ;
/* If an error occurred, report it and its position */
if ( nread < amount ) {
curlun - > sense_data = SS_UNRECOVERED_READ_ERROR ;
curlun - > sense_data_info = file_offset > > 9 ;
curlun - > info_valid = 1 ;
break ;
}
if ( amount_left = = 0 )
2009-11-09 14:15:23 +01:00
break ; /* No more left to read */
2009-10-28 16:57:18 +01:00
/* Send this buffer and go read some more */
bh - > inreq - > zero = 0 ;
2010-10-28 17:31:21 +02:00
if ( ! start_in_transfer ( common , bh ) )
/* Don't know what to do if common->fsg is NULL */
2009-11-09 14:15:24 +01:00
return - EIO ;
common - > next_buffhd_to_fill = bh - > next ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:23 +01:00
return - EIO ; /* No default reply */
2009-10-28 16:57:18 +01:00
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static int do_write ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
u32 lba ;
struct fsg_buffhd * bh ;
int get_some_more ;
u32 amount_left_to_req , amount_left_to_write ;
loff_t usb_offset , file_offset , file_offset_tmp ;
unsigned int amount ;
unsigned int partial_page ;
ssize_t nwritten ;
int rc ;
if ( curlun - > ro ) {
curlun - > sense_data = SS_WRITE_PROTECTED ;
return - EINVAL ;
}
spin_lock ( & curlun - > filp - > f_lock ) ;
2009-11-09 14:15:23 +01:00
curlun - > filp - > f_flags & = ~ O_SYNC ; /* Default is not to wait */
2009-10-28 16:57:18 +01:00
spin_unlock ( & curlun - > filp - > f_lock ) ;
2010-10-28 17:31:23 +02:00
/*
* Get the starting Logical Block Address and check that it ' s
* not too big
*/
2010-10-07 14:46:15 +02:00
if ( common - > cmnd [ 0 ] = = WRITE_6 )
2009-11-09 14:15:24 +01:00
lba = get_unaligned_be24 ( & common - > cmnd [ 1 ] ) ;
2009-10-28 16:57:18 +01:00
else {
2009-11-09 14:15:24 +01:00
lba = get_unaligned_be32 ( & common - > cmnd [ 2 ] ) ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* We allow DPO ( Disable Page Out = don ' t save data in the
2009-10-28 16:57:18 +01:00
* cache ) and FUA ( Force Unit Access = write directly to the
* medium ) . We don ' t implement DPO ; we implement FUA by
2010-10-28 17:31:23 +02:00
* performing synchronous output .
*/
2009-11-09 14:15:24 +01:00
if ( common - > cmnd [ 1 ] & ~ 0x18 ) {
2009-10-28 16:57:18 +01:00
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
2010-08-12 17:43:51 +02:00
if ( ! curlun - > nofua & & ( common - > cmnd [ 1 ] & 0x08 ) ) { /* FUA */
2009-10-28 16:57:18 +01:00
spin_lock ( & curlun - > filp - > f_lock ) ;
curlun - > filp - > f_flags | = O_SYNC ;
spin_unlock ( & curlun - > filp - > f_lock ) ;
}
}
if ( lba > = curlun - > num_sectors ) {
curlun - > sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE ;
return - EINVAL ;
}
/* Carry out the file writes */
get_some_more = 1 ;
file_offset = usb_offset = ( ( loff_t ) lba ) < < 9 ;
2009-11-09 14:15:24 +01:00
amount_left_to_req = common - > data_size_from_cmnd ;
amount_left_to_write = common - > data_size_from_cmnd ;
2009-10-28 16:57:18 +01:00
while ( amount_left_to_write > 0 ) {
/* Queue a request for more data from the host */
2009-11-09 14:15:24 +01:00
bh = common - > next_buffhd_to_fill ;
2009-10-28 16:57:18 +01:00
if ( bh - > state = = BUF_STATE_EMPTY & & get_some_more ) {
2010-10-28 17:31:23 +02:00
/*
* Figure out how much we want to get :
2009-10-28 16:57:18 +01:00
* Try to get the remaining amount .
* But don ' t get more than the buffer size .
* And don ' t try to go past the end of the file .
* If we ' re not at a page boundary ,
* don ' t go past the next page .
* If this means getting 0 , then we were asked
* to write past the end of file .
2010-10-28 17:31:23 +02:00
* Finally , round down to a block boundary .
*/
2009-10-28 16:57:19 +01:00
amount = min ( amount_left_to_req , FSG_BUFLEN ) ;
2010-10-28 17:31:23 +02:00
amount = min ( ( loff_t ) amount ,
curlun - > file_length - usb_offset ) ;
2009-10-28 16:57:18 +01:00
partial_page = usb_offset & ( PAGE_CACHE_SIZE - 1 ) ;
if ( partial_page > 0 )
amount = min ( amount ,
2010-10-28 17:31:23 +02:00
( unsigned int ) PAGE_CACHE_SIZE - partial_page ) ;
2009-10-28 16:57:18 +01:00
if ( amount = = 0 ) {
get_some_more = 0 ;
curlun - > sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE ;
curlun - > sense_data_info = usb_offset > > 9 ;
curlun - > info_valid = 1 ;
continue ;
}
2010-10-28 17:31:23 +02:00
amount - = amount & 511 ;
2009-10-28 16:57:18 +01:00
if ( amount = = 0 ) {
2010-10-28 17:31:23 +02:00
/*
* Why were we were asked to transfer a
* partial block ?
*/
2009-10-28 16:57:18 +01:00
get_some_more = 0 ;
continue ;
}
/* Get the next buffer */
usb_offset + = amount ;
2009-11-09 14:15:24 +01:00
common - > usb_amount_left - = amount ;
2009-10-28 16:57:18 +01:00
amount_left_to_req - = amount ;
if ( amount_left_to_req = = 0 )
get_some_more = 0 ;
2010-10-28 17:31:23 +02:00
/*
* amount is always divisible by 512 , hence by
* the bulk - out maxpacket size
*/
2009-11-09 14:15:23 +01:00
bh - > outreq - > length = amount ;
2009-10-28 16:57:18 +01:00
bh - > outreq - > short_not_ok = 1 ;
2010-10-28 17:31:21 +02:00
if ( ! start_out_transfer ( common , bh ) )
2010-10-28 17:31:23 +02:00
/* Dunno what to do if common->fsg is NULL */
2009-11-09 14:15:24 +01:00
return - EIO ;
common - > next_buffhd_to_fill = bh - > next ;
2009-10-28 16:57:18 +01:00
continue ;
}
/* Write the received data to the backing file */
2009-11-09 14:15:24 +01:00
bh = common - > next_buffhd_to_drain ;
2009-10-28 16:57:18 +01:00
if ( bh - > state = = BUF_STATE_EMPTY & & ! get_some_more )
2009-11-09 14:15:23 +01:00
break ; /* We stopped early */
2009-10-28 16:57:18 +01:00
if ( bh - > state = = BUF_STATE_FULL ) {
smp_rmb ( ) ;
2009-11-09 14:15:24 +01:00
common - > next_buffhd_to_drain = bh - > next ;
2009-10-28 16:57:18 +01:00
bh - > state = BUF_STATE_EMPTY ;
/* Did something go wrong with the transfer? */
if ( bh - > outreq - > status ! = 0 ) {
curlun - > sense_data = SS_COMMUNICATION_FAILURE ;
curlun - > sense_data_info = file_offset > > 9 ;
curlun - > info_valid = 1 ;
break ;
}
amount = bh - > outreq - > actual ;
if ( curlun - > file_length - file_offset < amount ) {
LERROR ( curlun ,
2010-10-28 17:31:23 +02:00
" write %u @ %llu beyond end %llu \n " ,
amount , ( unsigned long long ) file_offset ,
( unsigned long long ) curlun - > file_length ) ;
2009-10-28 16:57:18 +01:00
amount = curlun - > file_length - file_offset ;
}
/* Perform the write */
file_offset_tmp = file_offset ;
nwritten = vfs_write ( curlun - > filp ,
2010-10-28 17:31:23 +02:00
( char __user * ) bh - > buf ,
amount , & file_offset_tmp ) ;
2009-10-28 16:57:18 +01:00
VLDBG ( curlun , " file write %u @ %llu -> %d \n " , amount ,
2010-10-28 17:31:23 +02:00
( unsigned long long ) file_offset , ( int ) nwritten ) ;
2009-10-28 16:57:18 +01:00
if ( signal_pending ( current ) )
2009-11-09 14:15:23 +01:00
return - EINTR ; /* Interrupted! */
2009-10-28 16:57:18 +01:00
if ( nwritten < 0 ) {
LDBG ( curlun , " error in file write: %d \n " ,
2010-10-28 17:31:23 +02:00
( int ) nwritten ) ;
2009-10-28 16:57:18 +01:00
nwritten = 0 ;
} else if ( nwritten < amount ) {
LDBG ( curlun , " partial file write: %d/%u \n " ,
2010-10-28 17:31:23 +02:00
( int ) nwritten , amount ) ;
2009-10-28 16:57:18 +01:00
nwritten - = ( nwritten & 511 ) ;
2009-11-09 14:15:23 +01:00
/* Round down to a block */
2009-10-28 16:57:18 +01:00
}
file_offset + = nwritten ;
amount_left_to_write - = nwritten ;
2009-11-09 14:15:24 +01:00
common - > residue - = nwritten ;
2009-10-28 16:57:18 +01:00
/* If an error occurred, report it and its position */
if ( nwritten < amount ) {
curlun - > sense_data = SS_WRITE_ERROR ;
curlun - > sense_data_info = file_offset > > 9 ;
curlun - > info_valid = 1 ;
break ;
}
/* Did the host decide to stop early? */
if ( bh - > outreq - > actual ! = bh - > outreq - > length ) {
2009-11-09 14:15:24 +01:00
common - > short_packet_received = 1 ;
2009-10-28 16:57:18 +01:00
break ;
}
continue ;
}
/* Wait for something to happen */
2009-11-09 14:15:24 +01:00
rc = sleep_thread ( common ) ;
2009-10-28 16:57:18 +01:00
if ( rc )
return rc ;
}
2009-11-09 14:15:23 +01:00
return - EIO ; /* No default reply */
2009-10-28 16:57:18 +01:00
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static int do_synchronize_cache ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
int rc ;
/* We ignore the requested LBA and write out all file's
* dirty data buffers . */
rc = fsg_lun_fsync_sub ( curlun ) ;
if ( rc )
curlun - > sense_data = SS_WRITE_ERROR ;
return 0 ;
}
/*-------------------------------------------------------------------------*/
static void invalidate_sub ( struct fsg_lun * curlun )
{
struct file * filp = curlun - > filp ;
struct inode * inode = filp - > f_path . dentry - > d_inode ;
unsigned long rc ;
rc = invalidate_mapping_pages ( inode - > i_mapping , 0 , - 1 ) ;
2010-01-26 17:27:20 +01:00
VLDBG ( curlun , " invalidate_mapping_pages -> %ld \n " , rc ) ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
static int do_verify ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
u32 lba ;
u32 verification_length ;
2009-11-09 14:15:24 +01:00
struct fsg_buffhd * bh = common - > next_buffhd_to_fill ;
2009-10-28 16:57:18 +01:00
loff_t file_offset , file_offset_tmp ;
u32 amount_left ;
unsigned int amount ;
ssize_t nread ;
2010-10-28 17:31:23 +02:00
/*
* Get the starting Logical Block Address and check that it ' s
* not too big .
*/
2009-11-09 14:15:24 +01:00
lba = get_unaligned_be32 ( & common - > cmnd [ 2 ] ) ;
2009-10-28 16:57:18 +01:00
if ( lba > = curlun - > num_sectors ) {
curlun - > sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE ;
return - EINVAL ;
}
2010-10-28 17:31:23 +02:00
/*
* We allow DPO ( Disable Page Out = don ' t save data in the
* cache ) but we don ' t implement it .
*/
2009-11-09 14:15:24 +01:00
if ( common - > cmnd [ 1 ] & ~ 0x10 ) {
2009-10-28 16:57:18 +01:00
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
2009-11-09 14:15:24 +01:00
verification_length = get_unaligned_be16 ( & common - > cmnd [ 7 ] ) ;
2009-10-28 16:57:18 +01:00
if ( unlikely ( verification_length = = 0 ) )
2009-11-09 14:15:23 +01:00
return - EIO ; /* No default reply */
2009-10-28 16:57:18 +01:00
/* Prepare to carry out the file verify */
amount_left = verification_length < < 9 ;
file_offset = ( ( loff_t ) lba ) < < 9 ;
/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub ( curlun ) ;
if ( signal_pending ( current ) )
return - EINTR ;
invalidate_sub ( curlun ) ;
if ( signal_pending ( current ) )
return - EINTR ;
/* Just try to read the requested blocks */
while ( amount_left > 0 ) {
2010-10-28 17:31:23 +02:00
/*
* Figure out how much we need to read :
2009-10-28 16:57:18 +01:00
* Try to read the remaining amount , but not more than
* the buffer size .
* And don ' t try to read past the end of the file .
* If this means reading 0 then we were asked to read
2010-10-28 17:31:23 +02:00
* past the end of file .
*/
2009-10-28 16:57:19 +01:00
amount = min ( amount_left , FSG_BUFLEN ) ;
2010-10-28 17:31:23 +02:00
amount = min ( ( loff_t ) amount ,
curlun - > file_length - file_offset ) ;
2009-10-28 16:57:18 +01:00
if ( amount = = 0 ) {
curlun - > sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE ;
curlun - > sense_data_info = file_offset > > 9 ;
curlun - > info_valid = 1 ;
break ;
}
/* Perform the read */
file_offset_tmp = file_offset ;
nread = vfs_read ( curlun - > filp ,
( char __user * ) bh - > buf ,
amount , & file_offset_tmp ) ;
VLDBG ( curlun , " file read %u @ %llu -> %d \n " , amount ,
( unsigned long long ) file_offset ,
( int ) nread ) ;
if ( signal_pending ( current ) )
return - EINTR ;
if ( nread < 0 ) {
2010-10-28 17:31:23 +02:00
LDBG ( curlun , " error in file verify: %d \n " , ( int ) nread ) ;
2009-10-28 16:57:18 +01:00
nread = 0 ;
} else if ( nread < amount ) {
LDBG ( curlun , " partial file verify: %d/%u \n " ,
2010-10-28 17:31:23 +02:00
( int ) nread , amount ) ;
nread - = nread & 511 ; /* Round down to a sector */
2009-10-28 16:57:18 +01:00
}
if ( nread = = 0 ) {
curlun - > sense_data = SS_UNRECOVERED_READ_ERROR ;
curlun - > sense_data_info = file_offset > > 9 ;
curlun - > info_valid = 1 ;
break ;
}
file_offset + = nread ;
amount_left - = nread ;
}
return 0 ;
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static int do_inquiry ( struct fsg_common * common , struct fsg_buffhd * bh )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
u8 * buf = ( u8 * ) bh - > buf ;
2009-11-09 14:15:21 +01:00
if ( ! curlun ) { /* Unsupported LUNs are okay */
2009-11-09 14:15:24 +01:00
common - > bad_lun_okay = 1 ;
2009-10-28 16:57:18 +01:00
memset ( buf , 0 , 36 ) ;
2009-11-09 14:15:23 +01:00
buf [ 0 ] = 0x7f ; /* Unsupported, no device-type */
buf [ 4 ] = 31 ; /* Additional length */
2009-10-28 16:57:18 +01:00
return 36 ;
}
2010-10-07 14:46:15 +02:00
buf [ 0 ] = curlun - > cdrom ? TYPE_ROM : TYPE_DISK ;
2009-11-09 14:15:21 +01:00
buf [ 1 ] = curlun - > removable ? 0x80 : 0 ;
2009-11-09 14:15:23 +01:00
buf [ 2 ] = 2 ; /* ANSI SCSI level 2 */
buf [ 3 ] = 2 ; /* SCSI-2 INQUIRY data format */
buf [ 4 ] = 31 ; /* Additional length */
buf [ 5 ] = 0 ; /* No special options */
2009-11-09 14:15:21 +01:00
buf [ 6 ] = 0 ;
buf [ 7 ] = 0 ;
2009-11-09 14:15:24 +01:00
memcpy ( buf + 8 , common - > inquiry_string , sizeof common - > inquiry_string ) ;
2009-10-28 16:57:18 +01:00
return 36 ;
}
2009-11-09 14:15:24 +01:00
static int do_request_sense ( struct fsg_common * common , struct fsg_buffhd * bh )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
u8 * buf = ( u8 * ) bh - > buf ;
u32 sd , sdinfo ;
int valid ;
/*
* From the SCSI - 2 spec . , section 7.9 ( Unit attention condition ) :
*
* If a REQUEST SENSE command is received from an initiator
* with a pending unit attention condition ( before the target
* generates the contingent allegiance condition ) , then the
* target shall either :
* a ) report any pending sense data and preserve the unit
* attention condition on the logical unit , or ,
* b ) report the unit attention condition , may discard any
* pending sense data , and clear the unit attention
* condition on the logical unit for that initiator .
*
* FSG normally uses option a ) ; enable this code to use option b ) .
*/
#if 0
if ( curlun & & curlun - > unit_attention_data ! = SS_NO_SENSE ) {
curlun - > sense_data = curlun - > unit_attention_data ;
curlun - > unit_attention_data = SS_NO_SENSE ;
}
# endif
2009-11-09 14:15:23 +01:00
if ( ! curlun ) { /* Unsupported LUNs are okay */
2009-11-09 14:15:24 +01:00
common - > bad_lun_okay = 1 ;
2009-10-28 16:57:18 +01:00
sd = SS_LOGICAL_UNIT_NOT_SUPPORTED ;
sdinfo = 0 ;
valid = 0 ;
} else {
sd = curlun - > sense_data ;
sdinfo = curlun - > sense_data_info ;
valid = curlun - > info_valid < < 7 ;
curlun - > sense_data = SS_NO_SENSE ;
curlun - > sense_data_info = 0 ;
curlun - > info_valid = 0 ;
}
memset ( buf , 0 , 18 ) ;
2009-11-09 14:15:23 +01:00
buf [ 0 ] = valid | 0x70 ; /* Valid, current error */
2009-10-28 16:57:18 +01:00
buf [ 2 ] = SK ( sd ) ;
put_unaligned_be32 ( sdinfo , & buf [ 3 ] ) ; /* Sense information */
2009-11-09 14:15:23 +01:00
buf [ 7 ] = 18 - 8 ; /* Additional sense length */
2009-10-28 16:57:18 +01:00
buf [ 12 ] = ASC ( sd ) ;
buf [ 13 ] = ASCQ ( sd ) ;
return 18 ;
}
2009-11-09 14:15:24 +01:00
static int do_read_capacity ( struct fsg_common * common , struct fsg_buffhd * bh )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
u32 lba = get_unaligned_be32 ( & common - > cmnd [ 2 ] ) ;
int pmi = common - > cmnd [ 8 ] ;
2010-10-28 17:31:23 +02:00
u8 * buf = ( u8 * ) bh - > buf ;
2009-10-28 16:57:18 +01:00
/* Check the PMI and LBA fields */
if ( pmi > 1 | | ( pmi = = 0 & & lba ! = 0 ) ) {
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
put_unaligned_be32 ( curlun - > num_sectors - 1 , & buf [ 0 ] ) ;
/* Max logical block */
put_unaligned_be32 ( 512 , & buf [ 4 ] ) ; /* Block length */
return 8 ;
}
2009-11-09 14:15:24 +01:00
static int do_read_header ( struct fsg_common * common , struct fsg_buffhd * bh )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
int msf = common - > cmnd [ 1 ] & 0x02 ;
u32 lba = get_unaligned_be32 ( & common - > cmnd [ 2 ] ) ;
2010-10-28 17:31:23 +02:00
u8 * buf = ( u8 * ) bh - > buf ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
if ( common - > cmnd [ 1 ] & ~ 0x02 ) { /* Mask away MSF */
2009-10-28 16:57:18 +01:00
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
if ( lba > = curlun - > num_sectors ) {
curlun - > sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE ;
return - EINVAL ;
}
memset ( buf , 0 , 8 ) ;
buf [ 0 ] = 0x01 ; /* 2048 bytes of user data, rest is EC */
store_cdrom_address ( & buf [ 4 ] , msf , lba ) ;
return 8 ;
}
2009-11-09 14:15:24 +01:00
static int do_read_toc ( struct fsg_common * common , struct fsg_buffhd * bh )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
int msf = common - > cmnd [ 1 ] & 0x02 ;
int start_track = common - > cmnd [ 6 ] ;
2010-10-28 17:31:23 +02:00
u8 * buf = ( u8 * ) bh - > buf ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
if ( ( common - > cmnd [ 1 ] & ~ 0x02 ) ! = 0 | | /* Mask away MSF */
2009-10-28 16:57:18 +01:00
start_track > 1 ) {
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
memset ( buf , 0 , 20 ) ;
buf [ 1 ] = ( 20 - 2 ) ; /* TOC data length */
buf [ 2 ] = 1 ; /* First track number */
buf [ 3 ] = 1 ; /* Last track number */
buf [ 5 ] = 0x16 ; /* Data track, copying allowed */
buf [ 6 ] = 0x01 ; /* Only track is number 1 */
store_cdrom_address ( & buf [ 8 ] , msf , 0 ) ;
buf [ 13 ] = 0x16 ; /* Lead-out track is data */
buf [ 14 ] = 0xAA ; /* Lead-out track number */
store_cdrom_address ( & buf [ 16 ] , msf , curlun - > num_sectors ) ;
return 20 ;
}
2009-11-09 14:15:24 +01:00
static int do_mode_sense ( struct fsg_common * common , struct fsg_buffhd * bh )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
int mscmnd = common - > cmnd [ 0 ] ;
2009-10-28 16:57:18 +01:00
u8 * buf = ( u8 * ) bh - > buf ;
u8 * buf0 = buf ;
int pc , page_code ;
int changeable_values , all_pages ;
int valid_page = 0 ;
int len , limit ;
2009-11-09 14:15:24 +01:00
if ( ( common - > cmnd [ 1 ] & ~ 0x08 ) ! = 0 ) { /* Mask away DBD */
2009-10-28 16:57:18 +01:00
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
2009-11-09 14:15:24 +01:00
pc = common - > cmnd [ 2 ] > > 6 ;
page_code = common - > cmnd [ 2 ] & 0x3f ;
2009-10-28 16:57:18 +01:00
if ( pc = = 3 ) {
curlun - > sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED ;
return - EINVAL ;
}
changeable_values = ( pc = = 1 ) ;
all_pages = ( page_code = = 0x3f ) ;
2010-10-28 17:31:23 +02:00
/*
* Write the mode parameter header . Fixed values are : default
2009-10-28 16:57:18 +01:00
* medium type , no cache control ( DPOFUA ) , and no block descriptors .
* The only variable value is the WriteProtect bit . We will fill in
2010-10-28 17:31:23 +02:00
* the mode data length later .
*/
2009-10-28 16:57:18 +01:00
memset ( buf , 0 , 8 ) ;
2010-10-07 14:46:15 +02:00
if ( mscmnd = = MODE_SENSE ) {
2009-11-09 14:15:23 +01:00
buf [ 2 ] = ( curlun - > ro ? 0x80 : 0x00 ) ; /* WP, DPOFUA */
2009-10-28 16:57:18 +01:00
buf + = 4 ;
limit = 255 ;
2010-10-07 14:46:15 +02:00
} else { /* MODE_SENSE_10 */
2009-11-09 14:15:23 +01:00
buf [ 3 ] = ( curlun - > ro ? 0x80 : 0x00 ) ; /* WP, DPOFUA */
2009-10-28 16:57:18 +01:00
buf + = 8 ;
2009-11-09 14:15:23 +01:00
limit = 65535 ; /* Should really be FSG_BUFLEN */
2009-10-28 16:57:18 +01:00
}
/* No block descriptors */
2010-10-28 17:31:23 +02:00
/*
* The mode pages , in numerical order . The only page we support
* is the Caching page .
*/
2009-10-28 16:57:18 +01:00
if ( page_code = = 0x08 | | all_pages ) {
valid_page = 1 ;
2009-11-09 14:15:23 +01:00
buf [ 0 ] = 0x08 ; /* Page code */
buf [ 1 ] = 10 ; /* Page length */
memset ( buf + 2 , 0 , 10 ) ; /* None of the fields are changeable */
2009-10-28 16:57:18 +01:00
if ( ! changeable_values ) {
2009-11-09 14:15:23 +01:00
buf [ 2 ] = 0x04 ; /* Write cache enable, */
/* Read cache not disabled */
/* No cache retention priorities */
2009-10-28 16:57:18 +01:00
put_unaligned_be16 ( 0xffff , & buf [ 4 ] ) ;
/* Don't disable prefetch */
/* Minimum prefetch = 0 */
put_unaligned_be16 ( 0xffff , & buf [ 8 ] ) ;
/* Maximum prefetch */
put_unaligned_be16 ( 0xffff , & buf [ 10 ] ) ;
/* Maximum prefetch ceiling */
}
buf + = 12 ;
}
2010-10-28 17:31:23 +02:00
/*
* Check that a valid page was requested and the mode data length
* isn ' t too long .
*/
2009-10-28 16:57:18 +01:00
len = buf - buf0 ;
if ( ! valid_page | | len > limit ) {
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
/* Store the mode data length */
2010-10-07 14:46:15 +02:00
if ( mscmnd = = MODE_SENSE )
2009-10-28 16:57:18 +01:00
buf0 [ 0 ] = len - 1 ;
else
put_unaligned_be16 ( len - 2 , buf0 ) ;
return len ;
}
2009-11-09 14:15:24 +01:00
static int do_start_stop ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2010-04-26 12:34:54 +02:00
struct fsg_lun * curlun = common - > curlun ;
int loej , start ;
if ( ! curlun ) {
2009-11-09 14:15:21 +01:00
return - EINVAL ;
2010-04-26 12:34:54 +02:00
} else if ( ! curlun - > removable ) {
curlun - > sense_data = SS_INVALID_COMMAND ;
2009-10-28 16:57:18 +01:00
return - EINVAL ;
2010-06-21 13:57:09 +02:00
} else if ( ( common - > cmnd [ 1 ] & ~ 0x01 ) ! = 0 | | /* Mask away Immed */
( common - > cmnd [ 4 ] & ~ 0x03 ) ! = 0 ) { /* Mask LoEj, Start */
2010-04-26 12:34:54 +02:00
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
2010-06-21 13:57:09 +02:00
loej = common - > cmnd [ 4 ] & 0x02 ;
start = common - > cmnd [ 4 ] & 0x01 ;
2010-04-26 12:34:54 +02:00
2010-10-28 17:31:23 +02:00
/*
* Our emulation doesn ' t support mounting ; the medium is
* available for use as soon as it is loaded .
*/
2010-06-21 13:57:09 +02:00
if ( start ) {
2010-04-26 12:34:54 +02:00
if ( ! fsg_lun_is_open ( curlun ) ) {
curlun - > sense_data = SS_MEDIUM_NOT_PRESENT ;
return - EINVAL ;
}
2010-06-21 13:57:09 +02:00
return 0 ;
2010-04-26 12:34:54 +02:00
}
2010-06-21 13:57:09 +02:00
/* Are we allowed to unload the media? */
if ( curlun - > prevent_medium_removal ) {
LDBG ( curlun , " unload attempt prevented \n " ) ;
curlun - > sense_data = SS_MEDIUM_REMOVAL_PREVENTED ;
return - EINVAL ;
}
if ( ! loej )
return 0 ;
/* Simulate an unload/eject */
if ( common - > ops & & common - > ops - > pre_eject ) {
int r = common - > ops - > pre_eject ( common , curlun ,
curlun - common - > luns ) ;
if ( unlikely ( r < 0 ) )
return r ;
else if ( r )
return 0 ;
}
up_read ( & common - > filesem ) ;
down_write ( & common - > filesem ) ;
fsg_lun_close ( curlun ) ;
up_write ( & common - > filesem ) ;
down_read ( & common - > filesem ) ;
return common - > ops & & common - > ops - > post_eject
? min ( 0 , common - > ops - > post_eject ( common , curlun ,
curlun - common - > luns ) )
: 0 ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
static int do_prevent_allow ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
int prevent ;
2009-11-09 14:15:24 +01:00
if ( ! common - > curlun ) {
2009-11-09 14:15:21 +01:00
return - EINVAL ;
2009-11-09 14:15:24 +01:00
} else if ( ! common - > curlun - > removable ) {
common - > curlun - > sense_data = SS_INVALID_COMMAND ;
2009-10-28 16:57:18 +01:00
return - EINVAL ;
}
2009-11-09 14:15:24 +01:00
prevent = common - > cmnd [ 4 ] & 0x01 ;
if ( ( common - > cmnd [ 4 ] & ~ 0x01 ) ! = 0 ) { /* Mask away Prevent */
2009-10-28 16:57:18 +01:00
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
if ( curlun - > prevent_medium_removal & & ! prevent )
fsg_lun_fsync_sub ( curlun ) ;
curlun - > prevent_medium_removal = prevent ;
return 0 ;
}
2009-11-09 14:15:24 +01:00
static int do_read_format_capacities ( struct fsg_common * common ,
2009-10-28 16:57:18 +01:00
struct fsg_buffhd * bh )
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
u8 * buf = ( u8 * ) bh - > buf ;
buf [ 0 ] = buf [ 1 ] = buf [ 2 ] = 0 ;
2009-11-09 14:15:23 +01:00
buf [ 3 ] = 8 ; /* Only the Current/Maximum Capacity Descriptor */
2009-10-28 16:57:18 +01:00
buf + = 4 ;
put_unaligned_be32 ( curlun - > num_sectors , & buf [ 0 ] ) ;
/* Number of blocks */
put_unaligned_be32 ( 512 , & buf [ 4 ] ) ; /* Block length */
buf [ 4 ] = 0x02 ; /* Current capacity */
return 12 ;
}
2009-11-09 14:15:24 +01:00
static int do_mode_select ( struct fsg_common * common , struct fsg_buffhd * bh )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
/* We don't support MODE SELECT */
2009-11-09 14:15:24 +01:00
if ( curlun )
curlun - > sense_data = SS_INVALID_COMMAND ;
2009-10-28 16:57:18 +01:00
return - EINVAL ;
}
/*-------------------------------------------------------------------------*/
static int halt_bulk_in_endpoint ( struct fsg_dev * fsg )
{
int rc ;
rc = fsg_set_halt ( fsg , fsg - > bulk_in ) ;
if ( rc = = - EAGAIN )
VDBG ( fsg , " delayed bulk-in endpoint halt \n " ) ;
while ( rc ! = 0 ) {
if ( rc ! = - EAGAIN ) {
WARNING ( fsg , " usb_ep_set_halt -> %d \n " , rc ) ;
rc = 0 ;
break ;
}
/* Wait for a short time and then try again */
if ( msleep_interruptible ( 100 ) ! = 0 )
return - EINTR ;
rc = usb_ep_set_halt ( fsg - > bulk_in ) ;
}
return rc ;
}
static int wedge_bulk_in_endpoint ( struct fsg_dev * fsg )
{
int rc ;
DBG ( fsg , " bulk-in set wedge \n " ) ;
rc = usb_ep_set_wedge ( fsg - > bulk_in ) ;
if ( rc = = - EAGAIN )
VDBG ( fsg , " delayed bulk-in endpoint wedge \n " ) ;
while ( rc ! = 0 ) {
if ( rc ! = - EAGAIN ) {
WARNING ( fsg , " usb_ep_set_wedge -> %d \n " , rc ) ;
rc = 0 ;
break ;
}
/* Wait for a short time and then try again */
if ( msleep_interruptible ( 100 ) ! = 0 )
return - EINTR ;
rc = usb_ep_set_wedge ( fsg - > bulk_in ) ;
}
return rc ;
}
2009-11-09 14:15:24 +01:00
static int throw_away_data ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
struct fsg_buffhd * bh ;
u32 amount ;
int rc ;
2009-11-09 14:15:24 +01:00
for ( bh = common - > next_buffhd_to_drain ;
bh - > state ! = BUF_STATE_EMPTY | | common - > usb_amount_left > 0 ;
bh = common - > next_buffhd_to_drain ) {
2009-10-28 16:57:18 +01:00
/* Throw away the data in a filled buffer */
if ( bh - > state = = BUF_STATE_FULL ) {
smp_rmb ( ) ;
bh - > state = BUF_STATE_EMPTY ;
2009-11-09 14:15:24 +01:00
common - > next_buffhd_to_drain = bh - > next ;
2009-10-28 16:57:18 +01:00
/* A short packet or an error ends everything */
if ( bh - > outreq - > actual ! = bh - > outreq - > length | |
2010-10-28 17:31:23 +02:00
bh - > outreq - > status ! = 0 ) {
2009-11-09 14:15:24 +01:00
raise_exception ( common ,
FSG_STATE_ABORT_BULK_OUT ) ;
2009-10-28 16:57:18 +01:00
return - EINTR ;
}
continue ;
}
/* Try to submit another request if we need one */
2009-11-09 14:15:24 +01:00
bh = common - > next_buffhd_to_fill ;
if ( bh - > state = = BUF_STATE_EMPTY
& & common - > usb_amount_left > 0 ) {
amount = min ( common - > usb_amount_left , FSG_BUFLEN ) ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* amount is always divisible by 512 , hence by
* the bulk - out maxpacket size .
*/
2009-11-09 14:15:23 +01:00
bh - > outreq - > length = amount ;
2009-10-28 16:57:18 +01:00
bh - > outreq - > short_not_ok = 1 ;
2010-10-28 17:31:21 +02:00
if ( ! start_out_transfer ( common , bh ) )
2010-10-28 17:31:23 +02:00
/* Dunno what to do if common->fsg is NULL */
2009-11-09 14:15:24 +01:00
return - EIO ;
common - > next_buffhd_to_fill = bh - > next ;
common - > usb_amount_left - = amount ;
2009-10-28 16:57:18 +01:00
continue ;
}
/* Otherwise wait for something to happen */
2009-11-09 14:15:24 +01:00
rc = sleep_thread ( common ) ;
2009-10-28 16:57:18 +01:00
if ( rc )
return rc ;
}
return 0 ;
}
2009-11-09 14:15:24 +01:00
static int finish_reply ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_buffhd * bh = common - > next_buffhd_to_fill ;
2009-10-28 16:57:18 +01:00
int rc = 0 ;
2009-11-09 14:15:24 +01:00
switch ( common - > data_dir ) {
2009-10-28 16:57:18 +01:00
case DATA_DIR_NONE :
2009-11-09 14:15:23 +01:00
break ; /* Nothing to send */
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* If we don ' t know whether the host wants to read or write ,
2009-10-28 16:57:18 +01:00
* this must be CB or CBI with an unknown command . We mustn ' t
* try to send or receive any data . So stall both bulk pipes
2010-10-28 17:31:23 +02:00
* if we can and wait for a reset .
*/
2009-10-28 16:57:18 +01:00
case DATA_DIR_UNKNOWN :
2009-11-09 14:15:24 +01:00
if ( ! common - > can_stall ) {
/* Nothing */
} else if ( fsg_is_set ( common ) ) {
fsg_set_halt ( common - > fsg , common - > fsg - > bulk_out ) ;
rc = halt_bulk_in_endpoint ( common - > fsg ) ;
} else {
/* Don't know what to do if common->fsg is NULL */
rc = - EIO ;
2009-10-28 16:57:18 +01:00
}
break ;
/* All but the last buffer of data must have already been sent */
case DATA_DIR_TO_HOST :
2009-11-09 14:15:24 +01:00
if ( common - > data_size = = 0 ) {
2009-10-28 16:57:19 +01:00
/* Nothing to send */
2009-10-28 16:57:18 +01:00
2011-03-25 11:46:27 -04:00
/* Don't know what to do if common->fsg is NULL */
} else if ( ! fsg_is_set ( common ) ) {
rc = - EIO ;
2009-10-28 16:57:18 +01:00
/* If there's no residue, simply send the last buffer */
2009-11-09 14:15:24 +01:00
} else if ( common - > residue = = 0 ) {
2009-10-28 16:57:18 +01:00
bh - > inreq - > zero = 0 ;
2010-10-28 17:31:21 +02:00
if ( ! start_in_transfer ( common , bh ) )
2009-11-09 14:15:24 +01:00
return - EIO ;
common - > next_buffhd_to_fill = bh - > next ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
2011-03-25 11:46:27 -04:00
* For Bulk - only , mark the end of the data with a short
* packet . If we are allowed to stall , halt the bulk - in
* endpoint . ( Note : This violates the Bulk - Only Transport
* specification , which requires us to pad the data if we
* don ' t halt the endpoint . Presumably nobody will mind . )
2010-10-28 17:31:23 +02:00
*/
2011-03-25 11:46:27 -04:00
} else {
2009-10-28 16:57:19 +01:00
bh - > inreq - > zero = 1 ;
2010-10-28 17:31:21 +02:00
if ( ! start_in_transfer ( common , bh ) )
2009-11-09 14:15:24 +01:00
rc = - EIO ;
common - > next_buffhd_to_fill = bh - > next ;
2011-03-25 11:46:27 -04:00
if ( common - > can_stall )
2009-11-09 14:15:24 +01:00
rc = halt_bulk_in_endpoint ( common - > fsg ) ;
2009-10-28 16:57:18 +01:00
}
break ;
2010-10-28 17:31:23 +02:00
/*
* We have processed all we want from the data the host has sent .
* There may still be outstanding bulk - out requests .
*/
2009-10-28 16:57:18 +01:00
case DATA_DIR_FROM_HOST :
2009-11-09 14:15:24 +01:00
if ( common - > residue = = 0 ) {
2009-11-09 14:15:23 +01:00
/* Nothing to receive */
2009-10-28 16:57:18 +01:00
/* Did the host stop sending unexpectedly early? */
2009-11-09 14:15:24 +01:00
} else if ( common - > short_packet_received ) {
raise_exception ( common , FSG_STATE_ABORT_BULK_OUT ) ;
2009-10-28 16:57:18 +01:00
rc = - EINTR ;
2010-10-28 17:31:23 +02:00
/*
* We haven ' t processed all the incoming data . Even though
2009-10-28 16:57:18 +01:00
* we may be allowed to stall , doing so would cause a race .
* The controller may already have ACK ' ed all the remaining
* bulk - out packets , in which case the host wouldn ' t see a
* STALL . Not realizing the endpoint was halted , it wouldn ' t
2010-10-28 17:31:23 +02:00
* clear the halt - - leading to problems later on .
*/
2009-10-28 16:57:18 +01:00
#if 0
2009-11-09 14:15:24 +01:00
} else if ( common - > can_stall ) {
if ( fsg_is_set ( common ) )
fsg_set_halt ( common - > fsg ,
common - > fsg - > bulk_out ) ;
raise_exception ( common , FSG_STATE_ABORT_BULK_OUT ) ;
2009-10-28 16:57:18 +01:00
rc = - EINTR ;
# endif
2010-10-28 17:31:23 +02:00
/*
* We can ' t stall . Read in the excess data and throw it
* all away .
*/
2009-11-09 14:15:23 +01:00
} else {
2009-11-09 14:15:24 +01:00
rc = throw_away_data ( common ) ;
2009-11-09 14:15:23 +01:00
}
2009-10-28 16:57:18 +01:00
break ;
}
return rc ;
}
2009-11-09 14:15:24 +01:00
static int send_status ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_lun * curlun = common - > curlun ;
2009-10-28 16:57:18 +01:00
struct fsg_buffhd * bh ;
2009-10-28 16:57:19 +01:00
struct bulk_cs_wrap * csw ;
2009-10-28 16:57:18 +01:00
int rc ;
u8 status = USB_STATUS_PASS ;
u32 sd , sdinfo = 0 ;
/* Wait for the next buffer to become available */
2009-11-09 14:15:24 +01:00
bh = common - > next_buffhd_to_fill ;
2009-10-28 16:57:18 +01:00
while ( bh - > state ! = BUF_STATE_EMPTY ) {
2009-11-09 14:15:24 +01:00
rc = sleep_thread ( common ) ;
2009-10-28 16:57:18 +01:00
if ( rc )
return rc ;
}
if ( curlun ) {
sd = curlun - > sense_data ;
sdinfo = curlun - > sense_data_info ;
2009-11-09 14:15:24 +01:00
} else if ( common - > bad_lun_okay )
2009-10-28 16:57:18 +01:00
sd = SS_NO_SENSE ;
else
sd = SS_LOGICAL_UNIT_NOT_SUPPORTED ;
2009-11-09 14:15:24 +01:00
if ( common - > phase_error ) {
DBG ( common , " sending phase-error status \n " ) ;
2009-10-28 16:57:18 +01:00
status = USB_STATUS_PHASE_ERROR ;
sd = SS_INVALID_COMMAND ;
} else if ( sd ! = SS_NO_SENSE ) {
2009-11-09 14:15:24 +01:00
DBG ( common , " sending command-failure status \n " ) ;
2009-10-28 16:57:18 +01:00
status = USB_STATUS_FAIL ;
2009-11-09 14:15:24 +01:00
VDBG ( common , " sense data: SK x%02x, ASC x%02x, ASCQ x%02x; "
2009-10-28 16:57:18 +01:00
" info x%x \n " ,
SK ( sd ) , ASC ( sd ) , ASCQ ( sd ) , sdinfo ) ;
}
2009-10-28 16:57:19 +01:00
/* Store and send the Bulk-only CSW */
2009-11-09 14:15:23 +01:00
csw = ( void * ) bh - > buf ;
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:19 +01:00
csw - > Signature = cpu_to_le32 ( USB_BULK_CS_SIG ) ;
2009-11-09 14:15:24 +01:00
csw - > Tag = common - > tag ;
csw - > Residue = cpu_to_le32 ( common - > residue ) ;
2009-10-28 16:57:19 +01:00
csw - > Status = status ;
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:19 +01:00
bh - > inreq - > length = USB_BULK_CS_WRAP_LEN ;
bh - > inreq - > zero = 0 ;
2010-10-28 17:31:21 +02:00
if ( ! start_in_transfer ( common , bh ) )
2009-11-09 14:15:24 +01:00
/* Don't know what to do if common->fsg is NULL */
return - EIO ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
common - > next_buffhd_to_fill = bh - > next ;
2009-10-28 16:57:18 +01:00
return 0 ;
}
/*-------------------------------------------------------------------------*/
2010-10-28 17:31:23 +02:00
/*
* Check whether the command is properly formed and whether its data size
* and direction agree with the values we already have .
*/
2009-11-09 14:15:24 +01:00
static int check_command ( struct fsg_common * common , int cmnd_size ,
2010-10-28 17:31:23 +02:00
enum data_direction data_dir , unsigned int mask ,
int needs_medium , const char * name )
2009-10-28 16:57:18 +01:00
{
int i ;
2009-11-09 14:15:24 +01:00
int lun = common - > cmnd [ 1 ] > > 5 ;
2009-10-28 16:57:18 +01:00
static const char dirletter [ 4 ] = { ' u ' , ' o ' , ' i ' , ' n ' } ;
char hdlen [ 20 ] ;
struct fsg_lun * curlun ;
hdlen [ 0 ] = 0 ;
2009-11-09 14:15:24 +01:00
if ( common - > data_dir ! = DATA_DIR_UNKNOWN )
sprintf ( hdlen , " , H%c=%u " , dirletter [ ( int ) common - > data_dir ] ,
2010-10-28 17:31:23 +02:00
common - > data_size ) ;
2009-11-09 14:15:24 +01:00
VDBG ( common , " SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s \n " ,
2009-11-09 14:15:23 +01:00
name , cmnd_size , dirletter [ ( int ) data_dir ] ,
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd , common - > cmnd_size , hdlen ) ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* We can ' t reply at all until we know the correct data direction
* and size .
*/
2009-11-09 14:15:24 +01:00
if ( common - > data_size_from_cmnd = = 0 )
2009-10-28 16:57:18 +01:00
data_dir = DATA_DIR_NONE ;
2009-11-09 14:15:24 +01:00
if ( common - > data_size < common - > data_size_from_cmnd ) {
2010-10-28 17:31:23 +02:00
/*
* Host data size < Device data size is a phase error .
2009-11-09 14:15:24 +01:00
* Carry out the command , but only transfer as much as
2010-10-28 17:31:23 +02:00
* we are allowed .
*/
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = common - > data_size ;
common - > phase_error = 1 ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
common - > residue = common - > data_size ;
common - > usb_amount_left = common - > data_size ;
2009-10-28 16:57:18 +01:00
/* Conflicting data directions is a phase error */
2010-10-28 17:31:23 +02:00
if ( common - > data_dir ! = data_dir & & common - > data_size_from_cmnd > 0 ) {
2009-11-09 14:15:24 +01:00
common - > phase_error = 1 ;
2009-10-28 16:57:18 +01:00
return - EINVAL ;
}
/* Verify the length of the command itself */
2009-11-09 14:15:24 +01:00
if ( cmnd_size ! = common - > cmnd_size ) {
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* Special case workaround : There are plenty of buggy SCSI
2009-10-28 16:57:18 +01:00
* implementations . Many have issues with cbw - > Length
* field passing a wrong command size . For those cases we
* always try to work around the problem by using the length
* sent by the host side provided it is at least as large
* as the correct command length .
* Examples of such cases would be MS - Windows , which issues
* REQUEST SENSE with cbw - > Length = = 12 where it should
* be 6 , and xbox360 issuing INQUIRY , TEST UNIT READY and
* REQUEST SENSE with cbw - > Length = = 10 where it should
* be 6 as well .
*/
2009-11-09 14:15:24 +01:00
if ( cmnd_size < = common - > cmnd_size ) {
DBG ( common , " %s is buggy! Expected length %d "
2009-10-28 16:57:20 +01:00
" but we got %d \n " , name ,
2009-11-09 14:15:24 +01:00
cmnd_size , common - > cmnd_size ) ;
cmnd_size = common - > cmnd_size ;
2009-10-28 16:57:18 +01:00
} else {
2009-11-09 14:15:24 +01:00
common - > phase_error = 1 ;
2009-10-28 16:57:18 +01:00
return - EINVAL ;
}
}
/* Check that the LUN values are consistent */
2009-11-09 14:15:24 +01:00
if ( common - > lun ! = lun )
DBG ( common , " using LUN %d from CBW, not LUN %d from CDB \n " ,
common - > lun , lun ) ;
2009-10-28 16:57:18 +01:00
/* Check the LUN */
2009-11-09 14:15:24 +01:00
if ( common - > lun > = 0 & & common - > lun < common - > nluns ) {
curlun = & common - > luns [ common - > lun ] ;
common - > curlun = curlun ;
2010-10-07 14:46:15 +02:00
if ( common - > cmnd [ 0 ] ! = REQUEST_SENSE ) {
2009-10-28 16:57:18 +01:00
curlun - > sense_data = SS_NO_SENSE ;
curlun - > sense_data_info = 0 ;
curlun - > info_valid = 0 ;
}
} else {
2009-11-09 14:15:24 +01:00
common - > curlun = NULL ;
curlun = NULL ;
common - > bad_lun_okay = 0 ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* INQUIRY and REQUEST SENSE commands are explicitly allowed
* to use unsupported LUNs ; all others may not .
*/
2010-10-07 14:46:15 +02:00
if ( common - > cmnd [ 0 ] ! = INQUIRY & &
common - > cmnd [ 0 ] ! = REQUEST_SENSE ) {
2009-11-09 14:15:24 +01:00
DBG ( common , " unsupported LUN %d \n " , common - > lun ) ;
2009-10-28 16:57:18 +01:00
return - EINVAL ;
}
}
2010-10-28 17:31:23 +02:00
/*
* If a unit attention condition exists , only INQUIRY and
* REQUEST SENSE commands are allowed ; anything else must fail .
*/
2009-10-28 16:57:18 +01:00
if ( curlun & & curlun - > unit_attention_data ! = SS_NO_SENSE & &
2010-10-28 17:31:23 +02:00
common - > cmnd [ 0 ] ! = INQUIRY & &
common - > cmnd [ 0 ] ! = REQUEST_SENSE ) {
2009-10-28 16:57:18 +01:00
curlun - > sense_data = curlun - > unit_attention_data ;
curlun - > unit_attention_data = SS_NO_SENSE ;
return - EINVAL ;
}
/* Check that only command bytes listed in the mask are non-zero */
2009-11-09 14:15:24 +01:00
common - > cmnd [ 1 ] & = 0x1f ; /* Mask away the LUN */
2009-10-28 16:57:18 +01:00
for ( i = 1 ; i < cmnd_size ; + + i ) {
2009-11-09 14:15:24 +01:00
if ( common - > cmnd [ i ] & & ! ( mask & ( 1 < < i ) ) ) {
2009-10-28 16:57:18 +01:00
if ( curlun )
curlun - > sense_data = SS_INVALID_FIELD_IN_CDB ;
return - EINVAL ;
}
}
/* If the medium isn't mounted and the command needs to access
* it , return an error . */
if ( curlun & & ! fsg_lun_is_open ( curlun ) & & needs_medium ) {
curlun - > sense_data = SS_MEDIUM_NOT_PRESENT ;
return - EINVAL ;
}
return 0 ;
}
2009-11-09 14:15:24 +01:00
static int do_scsi_command ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
struct fsg_buffhd * bh ;
int rc ;
int reply = - EINVAL ;
int i ;
static char unknown [ 16 ] ;
2009-11-09 14:15:24 +01:00
dump_cdb ( common ) ;
2009-10-28 16:57:18 +01:00
/* Wait for the next buffer to become available for data or status */
2009-11-09 14:15:24 +01:00
bh = common - > next_buffhd_to_fill ;
common - > next_buffhd_to_drain = bh ;
2009-10-28 16:57:18 +01:00
while ( bh - > state ! = BUF_STATE_EMPTY ) {
2009-11-09 14:15:24 +01:00
rc = sleep_thread ( common ) ;
2009-10-28 16:57:18 +01:00
if ( rc )
return rc ;
}
2009-11-09 14:15:24 +01:00
common - > phase_error = 0 ;
common - > short_packet_received = 0 ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
down_read ( & common - > filesem ) ; /* We're using the backing file */
switch ( common - > cmnd [ 0 ] ) {
2009-10-28 16:57:18 +01:00
2010-10-07 14:46:15 +02:00
case INQUIRY :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = common - > cmnd [ 4 ] ;
reply = check_command ( common , 6 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 4 ) , 0 ,
" INQUIRY " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_inquiry ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case MODE_SELECT :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = common - > cmnd [ 4 ] ;
reply = check_command ( common , 6 , DATA_DIR_FROM_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 1 < < 4 ) , 0 ,
" MODE SELECT(6) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_mode_select ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case MODE_SELECT_10 :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be16 ( & common - > cmnd [ 7 ] ) ;
reply = check_command ( common , 10 , DATA_DIR_FROM_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 3 < < 7 ) , 0 ,
" MODE SELECT(10) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_mode_select ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case MODE_SENSE :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = common - > cmnd [ 4 ] ;
reply = check_command ( common , 6 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 1 < < 2 ) | ( 1 < < 4 ) , 0 ,
" MODE SENSE(6) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_mode_sense ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case MODE_SENSE_10 :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be16 ( & common - > cmnd [ 7 ] ) ;
reply = check_command ( common , 10 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 1 < < 2 ) | ( 3 < < 7 ) , 0 ,
" MODE SENSE(10) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_mode_sense ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case ALLOW_MEDIUM_REMOVAL :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = 0 ;
reply = check_command ( common , 6 , DATA_DIR_NONE ,
2009-11-09 14:15:23 +01:00
( 1 < < 4 ) , 0 ,
" PREVENT-ALLOW MEDIUM REMOVAL " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_prevent_allow ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case READ_6 :
2009-11-09 14:15:24 +01:00
i = common - > cmnd [ 4 ] ;
common - > data_size_from_cmnd = ( i = = 0 ? 256 : i ) < < 9 ;
reply = check_command ( common , 6 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 7 < < 1 ) | ( 1 < < 4 ) , 1 ,
" READ(6) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_read ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case READ_10 :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be16 ( & common - > cmnd [ 7 ] ) < < 9 ;
reply = check_command ( common , 10 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 0xf < < 2 ) | ( 3 < < 7 ) , 1 ,
" READ(10) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_read ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case READ_12 :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be32 ( & common - > cmnd [ 6 ] ) < < 9 ;
reply = check_command ( common , 12 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 0xf < < 2 ) | ( 0xf < < 6 ) , 1 ,
" READ(12) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_read ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case READ_CAPACITY :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = 8 ;
reply = check_command ( common , 10 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 0xf < < 2 ) | ( 1 < < 8 ) , 1 ,
" READ CAPACITY " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_read_capacity ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case READ_HEADER :
2009-11-09 14:15:24 +01:00
if ( ! common - > curlun | | ! common - > curlun - > cdrom )
2009-10-28 16:57:18 +01:00
goto unknown_cmnd ;
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be16 ( & common - > cmnd [ 7 ] ) ;
reply = check_command ( common , 10 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 3 < < 7 ) | ( 0x1f < < 1 ) , 1 ,
" READ HEADER " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_read_header ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case READ_TOC :
2009-11-09 14:15:24 +01:00
if ( ! common - > curlun | | ! common - > curlun - > cdrom )
2009-10-28 16:57:18 +01:00
goto unknown_cmnd ;
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be16 ( & common - > cmnd [ 7 ] ) ;
reply = check_command ( common , 10 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 7 < < 6 ) | ( 1 < < 1 ) , 1 ,
" READ TOC " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_read_toc ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case READ_FORMAT_CAPACITIES :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be16 ( & common - > cmnd [ 7 ] ) ;
reply = check_command ( common , 10 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 3 < < 7 ) , 1 ,
" READ FORMAT CAPACITIES " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_read_format_capacities ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case REQUEST_SENSE :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = common - > cmnd [ 4 ] ;
reply = check_command ( common , 6 , DATA_DIR_TO_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 4 ) , 0 ,
" REQUEST SENSE " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_request_sense ( common , bh ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case START_STOP :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = 0 ;
reply = check_command ( common , 6 , DATA_DIR_NONE ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 1 < < 4 ) , 0 ,
" START-STOP UNIT " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_start_stop ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case SYNCHRONIZE_CACHE :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = 0 ;
reply = check_command ( common , 10 , DATA_DIR_NONE ,
2009-11-09 14:15:23 +01:00
( 0xf < < 2 ) | ( 3 < < 7 ) , 1 ,
" SYNCHRONIZE CACHE " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_synchronize_cache ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case TEST_UNIT_READY :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = 0 ;
reply = check_command ( common , 6 , DATA_DIR_NONE ,
2009-10-28 16:57:18 +01:00
0 , 1 ,
" TEST UNIT READY " ) ;
break ;
2010-10-28 17:31:23 +02:00
/*
* Although optional , this command is used by MS - Windows . We
* support a minimal version : BytChk must be 0.
*/
2010-10-07 14:46:15 +02:00
case VERIFY :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = 0 ;
reply = check_command ( common , 10 , DATA_DIR_NONE ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 0xf < < 2 ) | ( 3 < < 7 ) , 1 ,
" VERIFY " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_verify ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case WRITE_6 :
2009-11-09 14:15:24 +01:00
i = common - > cmnd [ 4 ] ;
common - > data_size_from_cmnd = ( i = = 0 ? 256 : i ) < < 9 ;
reply = check_command ( common , 6 , DATA_DIR_FROM_HOST ,
2009-11-09 14:15:23 +01:00
( 7 < < 1 ) | ( 1 < < 4 ) , 1 ,
" WRITE(6) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_write ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case WRITE_10 :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be16 ( & common - > cmnd [ 7 ] ) < < 9 ;
reply = check_command ( common , 10 , DATA_DIR_FROM_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 0xf < < 2 ) | ( 3 < < 7 ) , 1 ,
" WRITE(10) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_write ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-07 14:46:15 +02:00
case WRITE_12 :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd =
get_unaligned_be32 ( & common - > cmnd [ 6 ] ) < < 9 ;
reply = check_command ( common , 12 , DATA_DIR_FROM_HOST ,
2009-11-09 14:15:23 +01:00
( 1 < < 1 ) | ( 0xf < < 2 ) | ( 0xf < < 6 ) , 1 ,
" WRITE(12) " ) ;
if ( reply = = 0 )
2009-11-09 14:15:24 +01:00
reply = do_write ( common ) ;
2009-10-28 16:57:18 +01:00
break ;
2010-10-28 17:31:23 +02:00
/*
* Some mandatory commands that we recognize but don ' t implement .
2009-10-28 16:57:18 +01:00
* They don ' t mean much in this setting . It ' s left as an exercise
* for anyone interested to implement RESERVE and RELEASE in terms
2010-10-28 17:31:23 +02:00
* of Posix locks .
*/
2010-10-07 14:46:15 +02:00
case FORMAT_UNIT :
case RELEASE :
case RESERVE :
case SEND_DIAGNOSTIC :
2009-11-09 14:15:23 +01:00
/* Fall through */
2009-10-28 16:57:18 +01:00
default :
2009-11-09 14:15:23 +01:00
unknown_cmnd :
2009-11-09 14:15:24 +01:00
common - > data_size_from_cmnd = 0 ;
sprintf ( unknown , " Unknown x%02x " , common - > cmnd [ 0 ] ) ;
reply = check_command ( common , common - > cmnd_size ,
2009-11-09 14:15:23 +01:00
DATA_DIR_UNKNOWN , 0xff , 0 , unknown ) ;
if ( reply = = 0 ) {
2009-11-09 14:15:24 +01:00
common - > curlun - > sense_data = SS_INVALID_COMMAND ;
2009-10-28 16:57:18 +01:00
reply = - EINVAL ;
}
break ;
}
2009-11-09 14:15:24 +01:00
up_read ( & common - > filesem ) ;
2009-10-28 16:57:18 +01:00
if ( reply = = - EINTR | | signal_pending ( current ) )
return - EINTR ;
/* Set up the single reply buffer for finish_reply() */
if ( reply = = - EINVAL )
2009-11-09 14:15:23 +01:00
reply = 0 ; /* Error reply length */
2009-11-09 14:15:24 +01:00
if ( reply > = 0 & & common - > data_dir = = DATA_DIR_TO_HOST ) {
2010-10-28 17:31:23 +02:00
reply = min ( ( u32 ) reply , common - > data_size_from_cmnd ) ;
2009-10-28 16:57:18 +01:00
bh - > inreq - > length = reply ;
bh - > state = BUF_STATE_FULL ;
2009-11-09 14:15:24 +01:00
common - > residue - = reply ;
2009-11-09 14:15:23 +01:00
} /* Otherwise it's already set */
2009-10-28 16:57:18 +01:00
return 0 ;
}
/*-------------------------------------------------------------------------*/
static int received_cbw ( struct fsg_dev * fsg , struct fsg_buffhd * bh )
{
2009-11-09 14:15:24 +01:00
struct usb_request * req = bh - > outreq ;
2009-10-28 16:57:18 +01:00
struct fsg_bulk_cb_wrap * cbw = req - > buf ;
2009-11-09 14:15:24 +01:00
struct fsg_common * common = fsg - > common ;
2009-10-28 16:57:18 +01:00
/* Was this a real packet? Should it be ignored? */
if ( req - > status | | test_bit ( IGNORE_BULK_OUT , & fsg - > atomic_bitflags ) )
return - EINVAL ;
/* Is the CBW valid? */
if ( req - > actual ! = USB_BULK_CB_WRAP_LEN | |
cbw - > Signature ! = cpu_to_le32 (
USB_BULK_CB_SIG ) ) {
DBG ( fsg , " invalid CBW: len %u sig 0x%x \n " ,
req - > actual ,
le32_to_cpu ( cbw - > Signature ) ) ;
2010-10-28 17:31:23 +02:00
/*
* The Bulk - only spec says we MUST stall the IN endpoint
2009-10-28 16:57:18 +01:00
* ( 6.6 .1 ) , so it ' s unavoidable . It also says we must
* retain this state until the next reset , but there ' s
* no way to tell the controller driver it should ignore
* Clear - Feature ( HALT ) requests .
*
* We aren ' t required to halt the OUT endpoint ; instead
* we can simply accept and discard any data received
2010-10-28 17:31:23 +02:00
* until the next reset .
*/
2009-10-28 16:57:18 +01:00
wedge_bulk_in_endpoint ( fsg ) ;
set_bit ( IGNORE_BULK_OUT , & fsg - > atomic_bitflags ) ;
return - EINVAL ;
}
/* Is the CBW meaningful? */
if ( cbw - > Lun > = FSG_MAX_LUNS | | cbw - > Flags & ~ USB_BULK_IN_FLAG | |
cbw - > Length < = 0 | | cbw - > Length > MAX_COMMAND_SIZE ) {
DBG ( fsg , " non-meaningful CBW: lun = %u, flags = 0x%x, "
" cmdlen %u \n " ,
cbw - > Lun , cbw - > Flags , cbw - > Length ) ;
2010-10-28 17:31:23 +02:00
/*
* We can do anything we want here , so let ' s stall the
* bulk pipes if we are allowed to .
*/
2009-11-09 14:15:24 +01:00
if ( common - > can_stall ) {
2009-10-28 16:57:18 +01:00
fsg_set_halt ( fsg , fsg - > bulk_out ) ;
halt_bulk_in_endpoint ( fsg ) ;
}
return - EINVAL ;
}
/* Save the command for later */
2009-11-09 14:15:24 +01:00
common - > cmnd_size = cbw - > Length ;
memcpy ( common - > cmnd , cbw - > CDB , common - > cmnd_size ) ;
2009-10-28 16:57:18 +01:00
if ( cbw - > Flags & USB_BULK_IN_FLAG )
2009-11-09 14:15:24 +01:00
common - > data_dir = DATA_DIR_TO_HOST ;
2009-10-28 16:57:18 +01:00
else
2009-11-09 14:15:24 +01:00
common - > data_dir = DATA_DIR_FROM_HOST ;
common - > data_size = le32_to_cpu ( cbw - > DataTransferLength ) ;
if ( common - > data_size = = 0 )
common - > data_dir = DATA_DIR_NONE ;
common - > lun = cbw - > Lun ;
common - > tag = cbw - > Tag ;
2009-10-28 16:57:18 +01:00
return 0 ;
}
2009-11-09 14:15:24 +01:00
static int get_next_command ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
struct fsg_buffhd * bh ;
int rc = 0 ;
2009-10-28 16:57:19 +01:00
/* Wait for the next buffer to become available */
2009-11-09 14:15:24 +01:00
bh = common - > next_buffhd_to_fill ;
2009-10-28 16:57:19 +01:00
while ( bh - > state ! = BUF_STATE_EMPTY ) {
2009-11-09 14:15:24 +01:00
rc = sleep_thread ( common ) ;
2009-10-28 16:57:19 +01:00
if ( rc )
return rc ;
}
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:19 +01:00
/* Queue a request to read a Bulk-only CBW */
2011-03-24 12:20:13 +01:00
bh - > outreq - > length = USB_BULK_CB_WRAP_LEN ;
bh - > outreq - > short_not_ok = 0 ;
2010-10-28 17:31:21 +02:00
if ( ! start_out_transfer ( common , bh ) )
2009-11-09 14:15:24 +01:00
/* Don't know what to do if common->fsg is NULL */
return - EIO ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* We will drain the buffer in software , which means we
2009-10-28 16:57:19 +01:00
* can reuse it for the next filling . No need to advance
2010-10-28 17:31:23 +02:00
* next_buffhd_to_fill .
*/
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:19 +01:00
/* Wait for the CBW to arrive */
while ( bh - > state ! = BUF_STATE_FULL ) {
2009-11-09 14:15:24 +01:00
rc = sleep_thread ( common ) ;
2009-10-28 16:57:19 +01:00
if ( rc )
return rc ;
2009-10-28 16:57:18 +01:00
}
2009-10-28 16:57:19 +01:00
smp_rmb ( ) ;
2009-11-09 14:15:24 +01:00
rc = fsg_is_set ( common ) ? received_cbw ( common - > fsg , bh ) : - EIO ;
2009-10-28 16:57:19 +01:00
bh - > state = BUF_STATE_EMPTY ;
2009-10-28 16:57:18 +01:00
return rc ;
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static int enable_endpoint ( struct fsg_common * common , struct usb_ep * ep ,
2009-10-28 16:57:18 +01:00
const struct usb_endpoint_descriptor * d )
{
int rc ;
2009-11-09 14:15:24 +01:00
ep - > driver_data = common ;
2009-10-28 16:57:18 +01:00
rc = usb_ep_enable ( ep , d ) ;
if ( rc )
2009-11-09 14:15:24 +01:00
ERROR ( common , " can't enable %s, result %d \n " , ep - > name , rc ) ;
2009-10-28 16:57:18 +01:00
return rc ;
}
2009-11-09 14:15:24 +01:00
static int alloc_request ( struct fsg_common * common , struct usb_ep * ep ,
2009-10-28 16:57:18 +01:00
struct usb_request * * preq )
{
* preq = usb_ep_alloc_request ( ep , GFP_ATOMIC ) ;
if ( * preq )
return 0 ;
2009-11-09 14:15:24 +01:00
ERROR ( common , " can't allocate request for %s \n " , ep - > name ) ;
2009-10-28 16:57:18 +01:00
return - ENOMEM ;
}
2010-06-25 16:29:28 +02:00
/* Reset interface setting and re-init endpoint state (toggle etc). */
static int do_set_interface ( struct fsg_common * common , struct fsg_dev * new_fsg )
2009-10-28 16:57:18 +01:00
{
2010-06-25 16:29:28 +02:00
const struct usb_endpoint_descriptor * d ;
struct fsg_dev * fsg ;
int i , rc = 0 ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
if ( common - > running )
DBG ( common , " reset interface \n " ) ;
2009-10-28 16:57:18 +01:00
reset :
/* Deallocate the requests */
2010-06-25 16:29:28 +02:00
if ( common - > fsg ) {
fsg = common - > fsg ;
2009-11-09 14:15:24 +01:00
for ( i = 0 ; i < FSG_NUM_BUFFERS ; + + i ) {
struct fsg_buffhd * bh = & common - > buffhds [ i ] ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
if ( bh - > inreq ) {
usb_ep_free_request ( fsg - > bulk_in , bh - > inreq ) ;
bh - > inreq = NULL ;
}
if ( bh - > outreq ) {
usb_ep_free_request ( fsg - > bulk_out , bh - > outreq ) ;
bh - > outreq = NULL ;
}
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
/* Disable the endpoints */
if ( fsg - > bulk_in_enabled ) {
usb_ep_disable ( fsg - > bulk_in ) ;
fsg - > bulk_in_enabled = 0 ;
}
if ( fsg - > bulk_out_enabled ) {
usb_ep_disable ( fsg - > bulk_out ) ;
fsg - > bulk_out_enabled = 0 ;
2009-10-28 16:57:18 +01:00
}
2010-06-25 16:29:28 +02:00
common - > fsg = NULL ;
wake_up ( & common - > fsg_wait ) ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
common - > running = 0 ;
2010-06-25 16:29:28 +02:00
if ( ! new_fsg | | rc )
2009-10-28 16:57:18 +01:00
return rc ;
2010-06-25 16:29:28 +02:00
common - > fsg = new_fsg ;
fsg = common - > fsg ;
2009-10-28 16:57:18 +01:00
2010-06-25 16:29:28 +02:00
/* Enable the endpoints */
d = fsg_ep_desc ( common - > gadget ,
& fsg_fs_bulk_in_desc , & fsg_hs_bulk_in_desc ) ;
rc = enable_endpoint ( common , fsg - > bulk_in , d ) ;
if ( rc )
goto reset ;
fsg - > bulk_in_enabled = 1 ;
2009-11-09 14:15:24 +01:00
2010-06-25 16:29:28 +02:00
d = fsg_ep_desc ( common - > gadget ,
& fsg_fs_bulk_out_desc , & fsg_hs_bulk_out_desc ) ;
rc = enable_endpoint ( common , fsg - > bulk_out , d ) ;
if ( rc )
goto reset ;
fsg - > bulk_out_enabled = 1 ;
common - > bulk_out_maxpacket = le16_to_cpu ( d - > wMaxPacketSize ) ;
clear_bit ( IGNORE_BULK_OUT , & fsg - > atomic_bitflags ) ;
/* Allocate the requests */
for ( i = 0 ; i < FSG_NUM_BUFFERS ; + + i ) {
struct fsg_buffhd * bh = & common - > buffhds [ i ] ;
rc = alloc_request ( common , fsg - > bulk_in , & bh - > inreq ) ;
2009-11-09 14:15:24 +01:00
if ( rc )
2009-10-28 16:57:18 +01:00
goto reset ;
2010-06-25 16:29:28 +02:00
rc = alloc_request ( common , fsg - > bulk_out , & bh - > outreq ) ;
2009-11-09 14:15:24 +01:00
if ( rc )
2009-10-28 16:57:18 +01:00
goto reset ;
2010-06-25 16:29:28 +02:00
bh - > inreq - > buf = bh - > outreq - > buf = bh - > buf ;
bh - > inreq - > context = bh - > outreq - > context = bh ;
bh - > inreq - > complete = bulk_in_complete ;
bh - > outreq - > complete = bulk_out_complete ;
2009-11-09 14:15:24 +01:00
}
2009-10-28 16:57:18 +01:00
2010-06-25 16:29:28 +02:00
common - > running = 1 ;
for ( i = 0 ; i < common - > nluns ; + + i )
common - > luns [ i ] . unit_attention_data = SS_RESET_OCCURRED ;
2009-10-28 16:57:18 +01:00
return rc ;
}
2009-11-09 14:15:20 +01:00
/****************************** ALT CONFIGS ******************************/
static int fsg_set_alt ( struct usb_function * f , unsigned intf , unsigned alt )
{
struct fsg_dev * fsg = fsg_from_func ( f ) ;
2010-06-25 16:29:28 +02:00
fsg - > common - > new_fsg = fsg ;
2009-11-09 14:15:24 +01:00
raise_exception ( fsg - > common , FSG_STATE_CONFIG_CHANGE ) ;
2009-11-09 14:15:20 +01:00
return 0 ;
}
static void fsg_disable ( struct usb_function * f )
{
struct fsg_dev * fsg = fsg_from_func ( f ) ;
2010-06-25 16:29:28 +02:00
fsg - > common - > new_fsg = NULL ;
2009-11-09 14:15:24 +01:00
raise_exception ( fsg - > common , FSG_STATE_CONFIG_CHANGE ) ;
2009-11-09 14:15:20 +01:00
}
2009-10-28 16:57:18 +01:00
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static void handle_exception ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
siginfo_t info ;
int i ;
struct fsg_buffhd * bh ;
enum fsg_state old_state ;
struct fsg_lun * curlun ;
unsigned int exception_req_tag ;
2010-10-28 17:31:23 +02:00
/*
* Clear the existing signals . Anything but SIGUSR1 is converted
* into a high - priority EXIT exception .
*/
2009-10-28 16:57:18 +01:00
for ( ; ; ) {
2010-06-25 16:29:28 +02:00
int sig =
dequeue_signal_lock ( current , & current - > blocked , & info ) ;
2009-10-28 16:57:18 +01:00
if ( ! sig )
break ;
if ( sig ! = SIGUSR1 ) {
2009-11-09 14:15:24 +01:00
if ( common - > state < FSG_STATE_EXIT )
DBG ( common , " Main thread exiting on signal \n " ) ;
raise_exception ( common , FSG_STATE_EXIT ) ;
2009-10-28 16:57:18 +01:00
}
}
/* Cancel all the pending transfers */
2010-06-25 16:29:28 +02:00
if ( likely ( common - > fsg ) ) {
2009-10-28 16:57:18 +01:00
for ( i = 0 ; i < FSG_NUM_BUFFERS ; + + i ) {
2009-11-09 14:15:24 +01:00
bh = & common - > buffhds [ i ] ;
if ( bh - > inreq_busy )
usb_ep_dequeue ( common - > fsg - > bulk_in , bh - > inreq ) ;
if ( bh - > outreq_busy )
usb_ep_dequeue ( common - > fsg - > bulk_out ,
bh - > outreq ) ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
/* Wait until everything is idle */
for ( ; ; ) {
int num_active = 0 ;
for ( i = 0 ; i < FSG_NUM_BUFFERS ; + + i ) {
bh = & common - > buffhds [ i ] ;
num_active + = bh - > inreq_busy + bh - > outreq_busy ;
}
if ( num_active = = 0 )
break ;
if ( sleep_thread ( common ) )
return ;
}
/* Clear out the controller's fifos */
if ( common - > fsg - > bulk_in_enabled )
usb_ep_fifo_flush ( common - > fsg - > bulk_in ) ;
if ( common - > fsg - > bulk_out_enabled )
usb_ep_fifo_flush ( common - > fsg - > bulk_out ) ;
}
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* Reset the I / O buffer states and pointers , the SCSI
* state , and the exception . Then invoke the handler .
*/
2009-11-09 14:15:24 +01:00
spin_lock_irq ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
for ( i = 0 ; i < FSG_NUM_BUFFERS ; + + i ) {
2009-11-09 14:15:24 +01:00
bh = & common - > buffhds [ i ] ;
2009-10-28 16:57:18 +01:00
bh - > state = BUF_STATE_EMPTY ;
}
2009-11-09 14:15:24 +01:00
common - > next_buffhd_to_fill = & common - > buffhds [ 0 ] ;
common - > next_buffhd_to_drain = & common - > buffhds [ 0 ] ;
exception_req_tag = common - > exception_req_tag ;
old_state = common - > state ;
2009-10-28 16:57:18 +01:00
if ( old_state = = FSG_STATE_ABORT_BULK_OUT )
2009-11-09 14:15:24 +01:00
common - > state = FSG_STATE_STATUS_PHASE ;
2009-10-28 16:57:18 +01:00
else {
2009-11-09 14:15:24 +01:00
for ( i = 0 ; i < common - > nluns ; + + i ) {
curlun = & common - > luns [ i ] ;
2009-10-28 16:57:18 +01:00
curlun - > prevent_medium_removal = 0 ;
2009-11-09 14:15:23 +01:00
curlun - > sense_data = SS_NO_SENSE ;
curlun - > unit_attention_data = SS_NO_SENSE ;
2009-10-28 16:57:18 +01:00
curlun - > sense_data_info = 0 ;
curlun - > info_valid = 0 ;
}
2009-11-09 14:15:24 +01:00
common - > state = FSG_STATE_IDLE ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:24 +01:00
spin_unlock_irq ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
/* Carry out any extra actions required for the exception */
switch ( old_state ) {
case FSG_STATE_ABORT_BULK_OUT :
2009-11-09 14:15:24 +01:00
send_status ( common ) ;
spin_lock_irq ( & common - > lock ) ;
if ( common - > state = = FSG_STATE_STATUS_PHASE )
common - > state = FSG_STATE_IDLE ;
spin_unlock_irq ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
break ;
case FSG_STATE_RESET :
2010-10-28 17:31:23 +02:00
/*
* In case we were forced against our will to halt a
2009-10-28 16:57:18 +01:00
* bulk endpoint , clear the halt now . ( The SuperH UDC
2010-10-28 17:31:23 +02:00
* requires this . )
*/
2009-11-09 14:15:24 +01:00
if ( ! fsg_is_set ( common ) )
break ;
if ( test_and_clear_bit ( IGNORE_BULK_OUT ,
& common - > fsg - > atomic_bitflags ) )
usb_ep_clear_halt ( common - > fsg - > bulk_in ) ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
if ( common - > ep0_req_tag = = exception_req_tag )
ep0_queue ( common ) ; /* Complete the status stage */
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* Technically this should go here , but it would only be
2009-10-28 16:57:18 +01:00
* a waste of time . Ditto for the INTERFACE_CHANGE and
2010-10-28 17:31:23 +02:00
* CONFIG_CHANGE cases .
*/
2009-11-09 14:15:24 +01:00
/* for (i = 0; i < common->nluns; ++i) */
/* common->luns[i].unit_attention_data = */
2009-11-09 14:15:23 +01:00
/* SS_RESET_OCCURRED; */
2009-10-28 16:57:18 +01:00
break ;
case FSG_STATE_CONFIG_CHANGE :
2010-06-25 16:29:28 +02:00
do_set_interface ( common , common - > new_fsg ) ;
2009-10-28 16:57:18 +01:00
break ;
case FSG_STATE_EXIT :
case FSG_STATE_TERMINATED :
2010-06-25 16:29:28 +02:00
do_set_interface ( common , NULL ) ; /* Free resources */
2009-11-09 14:15:24 +01:00
spin_lock_irq ( & common - > lock ) ;
common - > state = FSG_STATE_TERMINATED ; /* Stop the thread */
spin_unlock_irq ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
break ;
2009-11-09 14:15:20 +01:00
case FSG_STATE_INTERFACE_CHANGE :
case FSG_STATE_DISCONNECT :
case FSG_STATE_COMMAND_PHASE :
case FSG_STATE_DATA_PHASE :
case FSG_STATE_STATUS_PHASE :
case FSG_STATE_IDLE :
break ;
2009-10-28 16:57:18 +01:00
}
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:24 +01:00
static int fsg_main_thread ( void * common_ )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:24 +01:00
struct fsg_common * common = common_ ;
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:23 +02:00
/*
* Allow the thread to be killed by a signal , but set the signal mask
* to block everything but INT , TERM , KILL , and USR1 .
*/
2009-10-28 16:57:18 +01:00
allow_signal ( SIGINT ) ;
allow_signal ( SIGTERM ) ;
allow_signal ( SIGKILL ) ;
allow_signal ( SIGUSR1 ) ;
/* Allow the thread to be frozen */
set_freezable ( ) ;
2010-10-28 17:31:23 +02:00
/*
* Arrange for userspace references to be interpreted as kernel
2009-10-28 16:57:18 +01:00
* pointers . That way we can pass a kernel pointer to a routine
2010-10-28 17:31:23 +02:00
* that expects a __user pointer and it will work okay .
*/
2009-10-28 16:57:18 +01:00
set_fs ( get_ds ( ) ) ;
/* The main loop */
2009-11-09 14:15:24 +01:00
while ( common - > state ! = FSG_STATE_TERMINATED ) {
if ( exception_in_progress ( common ) | | signal_pending ( current ) ) {
handle_exception ( common ) ;
2009-10-28 16:57:18 +01:00
continue ;
}
2009-11-09 14:15:24 +01:00
if ( ! common - > running ) {
sleep_thread ( common ) ;
2009-10-28 16:57:18 +01:00
continue ;
}
2009-11-09 14:15:24 +01:00
if ( get_next_command ( common ) )
2009-10-28 16:57:18 +01:00
continue ;
2009-11-09 14:15:24 +01:00
spin_lock_irq ( & common - > lock ) ;
if ( ! exception_in_progress ( common ) )
common - > state = FSG_STATE_DATA_PHASE ;
spin_unlock_irq ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
if ( do_scsi_command ( common ) | | finish_reply ( common ) )
2009-10-28 16:57:18 +01:00
continue ;
2009-11-09 14:15:24 +01:00
spin_lock_irq ( & common - > lock ) ;
if ( ! exception_in_progress ( common ) )
common - > state = FSG_STATE_STATUS_PHASE ;
spin_unlock_irq ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
if ( send_status ( common ) )
2009-10-28 16:57:18 +01:00
continue ;
2009-11-09 14:15:24 +01:00
spin_lock_irq ( & common - > lock ) ;
if ( ! exception_in_progress ( common ) )
common - > state = FSG_STATE_IDLE ;
spin_unlock_irq ( & common - > lock ) ;
2009-11-09 14:15:20 +01:00
}
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:24 +01:00
spin_lock_irq ( & common - > lock ) ;
common - > thread_task = NULL ;
spin_unlock_irq ( & common - > lock ) ;
2009-10-28 16:57:18 +01:00
2010-06-21 13:57:09 +02:00
if ( ! common - > ops | | ! common - > ops - > thread_exits
| | common - > ops - > thread_exits ( common ) < 0 ) {
2010-01-28 13:05:26 +01:00
struct fsg_lun * curlun = common - > luns ;
unsigned i = common - > nluns ;
down_write ( & common - > filesem ) ;
for ( ; i - - ; + + curlun ) {
if ( ! fsg_lun_is_open ( curlun ) )
continue ;
fsg_lun_close ( curlun ) ;
curlun - > unit_attention_data = SS_MEDIUM_NOT_PRESENT ;
}
up_write ( & common - > filesem ) ;
}
2009-10-28 16:57:18 +01:00
2010-10-28 17:31:22 +02:00
/* Let fsg_unbind() know the thread has exited */
2009-11-09 14:15:24 +01:00
complete_and_exit ( & common - > thread_notifier , 0 ) ;
2009-10-28 16:57:18 +01:00
}
2009-10-28 16:57:22 +01:00
/*************************** DEVICE ATTRIBUTES ***************************/
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:20 +01:00
/* Write permission is checked per LUN in store_*() functions. */
static DEVICE_ATTR ( ro , 0644 , fsg_show_ro , fsg_store_ro ) ;
2010-08-12 17:43:51 +02:00
static DEVICE_ATTR ( nofua , 0644 , fsg_show_nofua , fsg_store_nofua ) ;
2009-11-09 14:15:20 +01:00
static DEVICE_ATTR ( file , 0644 , fsg_show_file , fsg_store_file ) ;
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:22 +01:00
/****************************** FSG COMMON ******************************/
static void fsg_common_release ( struct kref * ref ) ;
2009-10-28 16:57:18 +01:00
2009-10-28 16:57:22 +01:00
static void fsg_lun_release ( struct device * dev )
2009-10-28 16:57:18 +01:00
{
2009-10-28 16:57:22 +01:00
/* Nothing needs to be done */
2009-10-28 16:57:18 +01:00
}
2009-10-28 16:57:22 +01:00
static inline void fsg_common_get ( struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-10-28 16:57:22 +01:00
kref_get ( & common - > ref ) ;
2009-10-28 16:57:18 +01:00
}
2009-10-28 16:57:22 +01:00
static inline void fsg_common_put ( struct fsg_common * common )
{
kref_put ( & common - > ref , fsg_common_release ) ;
}
static struct fsg_common * fsg_common_init ( struct fsg_common * common ,
2009-11-09 14:15:21 +01:00
struct usb_composite_dev * cdev ,
struct fsg_config * cfg )
2009-10-28 16:57:22 +01:00
{
2009-11-09 14:15:20 +01:00
struct usb_gadget * gadget = cdev - > gadget ;
2009-10-28 16:57:22 +01:00
struct fsg_buffhd * bh ;
struct fsg_lun * curlun ;
2009-11-09 14:15:21 +01:00
struct fsg_lun_config * lcfg ;
2009-10-28 16:57:22 +01:00
int nluns , i , rc ;
2009-11-09 14:15:20 +01:00
char * pathbuf ;
2009-10-28 16:57:22 +01:00
/* Find out how many LUNs there should be */
2009-11-09 14:15:21 +01:00
nluns = cfg - > nluns ;
2009-10-28 16:57:22 +01:00
if ( nluns < 1 | | nluns > FSG_MAX_LUNS ) {
dev_err ( & gadget - > dev , " invalid number of LUNs: %u \n " , nluns ) ;
return ERR_PTR ( - EINVAL ) ;
}
/* Allocate? */
if ( ! common ) {
common = kzalloc ( sizeof * common , GFP_KERNEL ) ;
if ( ! common )
return ERR_PTR ( - ENOMEM ) ;
common - > free_storage_on_release = 1 ;
} else {
2011-01-29 02:26:51 +01:00
memset ( common , 0 , sizeof * common ) ;
2009-10-28 16:57:22 +01:00
common - > free_storage_on_release = 0 ;
}
2009-11-09 14:15:24 +01:00
2010-06-21 13:57:09 +02:00
common - > ops = cfg - > ops ;
2009-11-09 14:15:26 +01:00
common - > private_data = cfg - > private_data ;
2009-10-28 16:57:22 +01:00
common - > gadget = gadget ;
2009-11-09 14:15:24 +01:00
common - > ep0 = gadget - > ep0 ;
common - > ep0req = cdev - > req ;
/* Maybe allocate device-global string IDs, and patch descriptors */
if ( fsg_strings [ FSG_STRING_INTERFACE ] . id = = 0 ) {
rc = usb_string_id ( cdev ) ;
2010-05-12 12:51:13 +02:00
if ( unlikely ( rc < 0 ) )
goto error_release ;
2009-11-09 14:15:24 +01:00
fsg_strings [ FSG_STRING_INTERFACE ] . id = rc ;
fsg_intf_desc . iInterface = rc ;
}
2009-10-28 16:57:22 +01:00
2010-10-28 17:31:23 +02:00
/*
* Create the LUNs , open their backing files , and register the
* LUN devices in sysfs .
*/
2009-10-28 16:57:22 +01:00
curlun = kzalloc ( nluns * sizeof * curlun , GFP_KERNEL ) ;
2010-05-12 12:51:13 +02:00
if ( unlikely ( ! curlun ) ) {
rc = - ENOMEM ;
goto error_release ;
2009-10-28 16:57:22 +01:00
}
common - > luns = curlun ;
init_rwsem ( & common - > filesem ) ;
2009-11-09 14:15:21 +01:00
for ( i = 0 , lcfg = cfg - > luns ; i < nluns ; + + i , + + curlun , + + lcfg ) {
curlun - > cdrom = ! ! lcfg - > cdrom ;
curlun - > ro = lcfg - > cdrom | | lcfg - > ro ;
curlun - > removable = lcfg - > removable ;
2009-10-28 16:57:22 +01:00
curlun - > dev . release = fsg_lun_release ;
curlun - > dev . parent = & gadget - > dev ;
2009-11-09 14:15:20 +01:00
/* curlun->dev.driver = &fsg_driver.driver; XXX */
2009-10-28 16:57:22 +01:00
dev_set_drvdata ( & curlun - > dev , & common - > filesem ) ;
2009-11-09 14:15:22 +01:00
dev_set_name ( & curlun - > dev ,
cfg - > lun_name_format
? cfg - > lun_name_format
: " lun%d " ,
i ) ;
2009-10-28 16:57:22 +01:00
rc = device_register ( & curlun - > dev ) ;
if ( rc ) {
INFO ( common , " failed to register LUN%d: %d \n " , i , rc ) ;
common - > nluns = i ;
2010-10-28 17:31:19 +02:00
put_device ( & curlun - > dev ) ;
2009-10-28 16:57:22 +01:00
goto error_release ;
}
rc = device_create_file ( & curlun - > dev , & dev_attr_ro ) ;
if ( rc )
goto error_luns ;
rc = device_create_file ( & curlun - > dev , & dev_attr_file ) ;
2010-08-12 17:43:51 +02:00
if ( rc )
goto error_luns ;
rc = device_create_file ( & curlun - > dev , & dev_attr_nofua ) ;
2009-10-28 16:57:22 +01:00
if ( rc )
goto error_luns ;
2009-11-09 14:15:21 +01:00
if ( lcfg - > filename ) {
rc = fsg_lun_open ( curlun , lcfg - > filename ) ;
2009-10-28 16:57:22 +01:00
if ( rc )
goto error_luns ;
2009-11-09 14:15:21 +01:00
} else if ( ! curlun - > removable ) {
2009-10-28 16:57:22 +01:00
ERROR ( common , " no file given for LUN%d \n " , i ) ;
rc = - EINVAL ;
goto error_luns ;
}
}
common - > nluns = nluns ;
/* Data buffers cyclic list */
bh = common - > buffhds ;
2010-03-15 21:38:31 +01:00
i = FSG_NUM_BUFFERS ;
goto buffhds_first_it ;
2009-10-28 16:57:22 +01:00
do {
bh - > next = bh + 1 ;
2010-03-15 21:38:31 +01:00
+ + bh ;
buffhds_first_it :
bh - > buf = kmalloc ( FSG_BUFLEN , GFP_KERNEL ) ;
if ( unlikely ( ! bh - > buf ) ) {
rc = - ENOMEM ;
goto error_release ;
}
} while ( - - i ) ;
2009-10-28 16:57:22 +01:00
bh - > next = common - > buffhds ;
2009-11-09 14:15:21 +01:00
/* Prepare inquiryString */
if ( cfg - > release ! = 0xffff ) {
i = cfg - > release ;
} else {
2010-02-05 13:24:12 +01:00
i = usb_gadget_controller_number ( gadget ) ;
2009-11-09 14:15:21 +01:00
if ( i > = 0 ) {
i = 0x0300 + i ;
} else {
2009-10-28 16:57:22 +01:00
WARNING ( common , " controller '%s' not recognized \n " ,
gadget - > name ) ;
2009-11-09 14:15:21 +01:00
i = 0x0399 ;
2009-10-28 16:57:22 +01:00
}
}
2009-11-09 14:15:21 +01:00
snprintf ( common - > inquiry_string , sizeof common - > inquiry_string ,
2010-10-28 17:31:20 +02:00
" %-8s%-16s%04x " , cfg - > vendor_name ? : " Linux " ,
2009-11-09 14:15:21 +01:00
/* Assume product name dependent on the first LUN */
2010-10-28 17:31:20 +02:00
cfg - > product_name ? : ( common - > luns - > cdrom
2009-11-09 14:15:21 +01:00
? " File-Stor Gadget "
2010-10-28 17:31:20 +02:00
: " File-CD Gadget " ) ,
2009-11-09 14:15:21 +01:00
i ) ;
2009-10-28 16:57:22 +01:00
2010-10-28 17:31:23 +02:00
/*
* Some peripheral controllers are known not to be able to
2009-10-28 16:57:22 +01:00
* halt bulk endpoints correctly . If one of them is present ,
* disable stalls .
*/
2009-11-09 14:15:21 +01:00
common - > can_stall = cfg - > can_stall & &
2010-02-05 13:24:12 +01:00
! ( gadget_is_at91 ( common - > gadget ) ) ;
2009-10-28 16:57:22 +01:00
2009-11-09 14:15:24 +01:00
spin_lock_init ( & common - > lock ) ;
2009-10-28 16:57:22 +01:00
kref_init ( & common - > ref ) ;
2009-11-09 14:15:24 +01:00
/* Tell the thread to start working */
common - > thread_task =
kthread_create ( fsg_main_thread , common ,
2010-10-28 17:31:20 +02:00
cfg - > thread_name ? : " file-storage " ) ;
2009-11-09 14:15:24 +01:00
if ( IS_ERR ( common - > thread_task ) ) {
rc = PTR_ERR ( common - > thread_task ) ;
goto error_release ;
}
init_completion ( & common - > thread_notifier ) ;
2010-06-25 16:29:28 +02:00
init_waitqueue_head ( & common - > fsg_wait ) ;
2009-11-09 14:15:22 +01:00
2009-11-09 14:15:20 +01:00
/* Information */
INFO ( common , FSG_DRIVER_DESC " , version: " FSG_DRIVER_VERSION " \n " ) ;
INFO ( common , " Number of LUNs=%d \n " , common - > nluns ) ;
pathbuf = kmalloc ( PATH_MAX , GFP_KERNEL ) ;
for ( i = 0 , nluns = common - > nluns , curlun = common - > luns ;
i < nluns ;
+ + curlun , + + i ) {
char * p = " (no medium) " ;
if ( fsg_lun_is_open ( curlun ) ) {
p = " (error) " ;
if ( pathbuf ) {
p = d_path ( & curlun - > filp - > f_path ,
pathbuf , PATH_MAX ) ;
if ( IS_ERR ( p ) )
p = " (error) " ;
}
}
LINFO ( curlun , " LUN: %s%s%sfile: %s \n " ,
curlun - > removable ? " removable " : " " ,
curlun - > ro ? " read only " : " " ,
curlun - > cdrom ? " CD-ROM " : " " ,
p ) ;
}
kfree ( pathbuf ) ;
2009-11-09 14:15:24 +01:00
DBG ( common , " I/O thread pid: %d \n " , task_pid_nr ( common - > thread_task ) ) ;
wake_up_process ( common - > thread_task ) ;
2009-10-28 16:57:22 +01:00
return common ;
error_luns :
common - > nluns = i + 1 ;
error_release :
2009-11-09 14:15:24 +01:00
common - > state = FSG_STATE_TERMINATED ; /* The thread is dead */
2010-10-28 17:31:23 +02:00
/* Call fsg_common_release() directly, ref might be not initialised. */
2009-10-28 16:57:22 +01:00
fsg_common_release ( & common - > ref ) ;
return ERR_PTR ( rc ) ;
}
static void fsg_common_release ( struct kref * ref )
{
2010-05-12 12:51:13 +02:00
struct fsg_common * common = container_of ( ref , struct fsg_common , ref ) ;
2009-10-28 16:57:22 +01:00
2009-11-09 14:15:24 +01:00
/* If the thread isn't already dead, tell it to exit now */
if ( common - > state ! = FSG_STATE_TERMINATED ) {
raise_exception ( common , FSG_STATE_EXIT ) ;
wait_for_completion ( & common - > thread_notifier ) ;
}
2010-05-12 12:51:13 +02:00
if ( likely ( common - > luns ) ) {
struct fsg_lun * lun = common - > luns ;
unsigned i = common - > nluns ;
/* In error recovery common->nluns may be zero. */
for ( ; i ; - - i , + + lun ) {
2010-08-12 17:43:51 +02:00
device_remove_file ( & lun - > dev , & dev_attr_nofua ) ;
2010-05-12 12:51:13 +02:00
device_remove_file ( & lun - > dev , & dev_attr_ro ) ;
device_remove_file ( & lun - > dev , & dev_attr_file ) ;
fsg_lun_close ( lun ) ;
device_unregister ( & lun - > dev ) ;
}
2009-10-28 16:57:22 +01:00
2010-05-12 12:51:13 +02:00
kfree ( common - > luns ) ;
2009-10-28 16:57:22 +01:00
}
2010-05-12 12:51:13 +02:00
{
struct fsg_buffhd * bh = common - > buffhds ;
unsigned i = FSG_NUM_BUFFERS ;
do {
kfree ( bh - > buf ) ;
} while ( + + bh , - - i ) ;
}
2010-03-15 21:38:31 +01:00
2009-10-28 16:57:22 +01:00
if ( common - > free_storage_on_release )
kfree ( common ) ;
}
/*-------------------------------------------------------------------------*/
2009-11-09 14:15:20 +01:00
static void fsg_unbind ( struct usb_configuration * c , struct usb_function * f )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:20 +01:00
struct fsg_dev * fsg = fsg_from_func ( f ) ;
2010-06-25 16:29:28 +02:00
struct fsg_common * common = fsg - > common ;
2009-10-28 16:57:18 +01:00
DBG ( fsg , " unbind \n " ) ;
2010-06-25 16:29:28 +02:00
if ( fsg - > common - > fsg = = fsg ) {
fsg - > common - > new_fsg = NULL ;
raise_exception ( fsg - > common , FSG_STATE_CONFIG_CHANGE ) ;
/* FIXME: make interruptible or killable somehow? */
wait_event ( common - > fsg_wait , common - > fsg ! = fsg ) ;
}
fsg_common_put ( common ) ;
2010-03-29 14:01:32 +02:00
usb_free_descriptors ( fsg - > function . descriptors ) ;
usb_free_descriptors ( fsg - > function . hs_descriptors ) ;
2009-10-28 16:57:22 +01:00
kfree ( fsg ) ;
2009-10-28 16:57:18 +01:00
}
2010-05-05 12:53:13 +02:00
static int fsg_bind ( struct usb_configuration * c , struct usb_function * f )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:20 +01:00
struct fsg_dev * fsg = fsg_from_func ( f ) ;
struct usb_gadget * gadget = c - > cdev - > gadget ;
2009-10-28 16:57:18 +01:00
int i ;
struct usb_ep * ep ;
fsg - > gadget = gadget ;
2009-11-09 14:15:20 +01:00
/* New interface */
i = usb_interface_id ( c , f ) ;
if ( i < 0 )
return i ;
fsg_intf_desc . bInterfaceNumber = i ;
fsg - > interface_number = i ;
2009-10-28 16:57:18 +01:00
/* Find all the endpoints we will use */
ep = usb_ep_autoconfig ( gadget , & fsg_fs_bulk_in_desc ) ;
if ( ! ep )
goto autoconf_fail ;
2009-11-09 14:15:24 +01:00
ep - > driver_data = fsg - > common ; /* claim the endpoint */
2009-10-28 16:57:18 +01:00
fsg - > bulk_in = ep ;
ep = usb_ep_autoconfig ( gadget , & fsg_fs_bulk_out_desc ) ;
if ( ! ep )
goto autoconf_fail ;
2009-11-09 14:15:24 +01:00
ep - > driver_data = fsg - > common ; /* claim the endpoint */
2009-10-28 16:57:18 +01:00
fsg - > bulk_out = ep ;
2010-06-25 16:29:26 +02:00
/* Copy descriptors */
f - > descriptors = usb_copy_descriptors ( fsg_fs_function ) ;
if ( unlikely ( ! f - > descriptors ) )
return - ENOMEM ;
2009-10-28 16:57:18 +01:00
if ( gadget_is_dualspeed ( gadget ) ) {
/* Assume endpoint addresses are the same for both speeds */
fsg_hs_bulk_in_desc . bEndpointAddress =
fsg_fs_bulk_in_desc . bEndpointAddress ;
fsg_hs_bulk_out_desc . bEndpointAddress =
fsg_fs_bulk_out_desc . bEndpointAddress ;
2010-03-29 14:01:32 +02:00
f - > hs_descriptors = usb_copy_descriptors ( fsg_hs_function ) ;
2010-06-25 16:29:26 +02:00
if ( unlikely ( ! f - > hs_descriptors ) ) {
usb_free_descriptors ( f - > descriptors ) ;
2010-03-29 14:01:32 +02:00
return - ENOMEM ;
2010-06-25 16:29:26 +02:00
}
2009-10-28 16:57:18 +01:00
}
return 0 ;
autoconf_fail :
ERROR ( fsg , " unable to autoconfigure all endpoints \n " ) ;
2010-06-25 16:29:26 +02:00
return - ENOTSUPP ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:20 +01:00
/****************************** ADD FUNCTION ******************************/
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:20 +01:00
static struct usb_gadget_strings * fsg_strings_array [ ] = {
& fsg_stringtab ,
NULL ,
2009-10-28 16:57:18 +01:00
} ;
2010-06-16 12:07:57 +02:00
static int fsg_bind_config ( struct usb_composite_dev * cdev ,
struct usb_configuration * c ,
struct fsg_common * common )
2009-10-28 16:57:18 +01:00
{
2009-11-09 14:15:20 +01:00
struct fsg_dev * fsg ;
int rc ;
fsg = kzalloc ( sizeof * fsg , GFP_KERNEL ) ;
if ( unlikely ( ! fsg ) )
return - ENOMEM ;
2009-10-28 16:57:18 +01:00
2009-11-09 14:15:20 +01:00
fsg - > function . name = FSG_DRIVER_DESC ;
fsg - > function . strings = fsg_strings_array ;
fsg - > function . bind = fsg_bind ;
fsg - > function . unbind = fsg_unbind ;
fsg - > function . setup = fsg_setup ;
fsg - > function . set_alt = fsg_set_alt ;
fsg - > function . disable = fsg_disable ;
fsg - > common = common ;
2010-10-28 17:31:23 +02:00
/*
* Our caller holds a reference to common structure so we
2009-11-09 14:15:20 +01:00
* don ' t have to be worry about it being freed until we return
* from this function . So instead of incrementing counter now
* and decrement in error recovery we increment it only when
2010-10-28 17:31:23 +02:00
* call to usb_add_function ( ) was successful .
*/
2009-11-09 14:15:20 +01:00
rc = usb_add_function ( c , & fsg - > function ) ;
2010-03-29 14:01:32 +02:00
if ( unlikely ( rc ) )
2010-06-25 16:29:26 +02:00
kfree ( fsg ) ;
else
fsg_common_get ( fsg - > common ) ;
2009-11-09 14:15:20 +01:00
return rc ;
2009-10-28 16:57:18 +01:00
}
2009-11-09 14:15:21 +01:00
2010-06-16 12:07:57 +02:00
static inline int __deprecated __maybe_unused
2010-10-28 17:31:23 +02:00
fsg_add ( struct usb_composite_dev * cdev , struct usb_configuration * c ,
2010-06-16 12:07:57 +02:00
struct fsg_common * common )
{
return fsg_bind_config ( cdev , c , common ) ;
}
2009-11-09 14:15:21 +01:00
/************************* Module parameters *************************/
struct fsg_module_parameters {
char * file [ FSG_MAX_LUNS ] ;
int ro [ FSG_MAX_LUNS ] ;
int removable [ FSG_MAX_LUNS ] ;
int cdrom [ FSG_MAX_LUNS ] ;
2010-08-12 17:43:51 +02:00
int nofua [ FSG_MAX_LUNS ] ;
2009-11-09 14:15:21 +01:00
unsigned int file_count , ro_count , removable_count , cdrom_count ;
2010-08-12 17:43:51 +02:00
unsigned int nofua_count ;
2009-11-09 14:15:21 +01:00
unsigned int luns ; /* nluns */
int stall ; /* can_stall */
} ;
# define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \
module_param_array_named ( prefix # # name , params . name , type , \
& prefix # # params . name # # _count , \
S_IRUGO ) ; \
MODULE_PARM_DESC ( prefix # # name , desc )
# define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \
module_param_named ( prefix # # name , params . name , type , \
S_IRUGO ) ; \
MODULE_PARM_DESC ( prefix # # name , desc )
# define FSG_MODULE_PARAMETERS(prefix, params) \
_FSG_MODULE_PARAM_ARRAY ( prefix , params , file , charp , \
" names of backing files or devices " ) ; \
_FSG_MODULE_PARAM_ARRAY ( prefix , params , ro , bool , \
" true to force read-only " ) ; \
_FSG_MODULE_PARAM_ARRAY ( prefix , params , removable , bool , \
" true to simulate removable media " ) ; \
_FSG_MODULE_PARAM_ARRAY ( prefix , params , cdrom , bool , \
" true to simulate CD-ROM instead of disk " ) ; \
2010-08-12 17:43:51 +02:00
_FSG_MODULE_PARAM_ARRAY ( prefix , params , nofua , bool , \
" true to ignore SCSI WRITE(10,12) FUA bit " ) ; \
2009-11-09 14:15:21 +01:00
_FSG_MODULE_PARAM ( prefix , params , luns , uint , \
" number of LUNs " ) ; \
_FSG_MODULE_PARAM ( prefix , params , stall , bool , \
" false to prevent bulk stalls " )
static void
fsg_config_from_params ( struct fsg_config * cfg ,
const struct fsg_module_parameters * params )
{
struct fsg_lun_config * lun ;
2009-11-09 14:15:23 +01:00
unsigned i ;
2009-11-09 14:15:21 +01:00
/* Configure LUNs */
2009-11-09 14:15:23 +01:00
cfg - > nluns =
min ( params - > luns ? : ( params - > file_count ? : 1u ) ,
( unsigned ) FSG_MAX_LUNS ) ;
for ( i = 0 , lun = cfg - > luns ; i < cfg - > nluns ; + + i , + + lun ) {
2009-11-09 14:15:21 +01:00
lun - > ro = ! ! params - > ro [ i ] ;
lun - > cdrom = ! ! params - > cdrom [ i ] ;
2009-11-09 14:15:23 +01:00
lun - > removable = /* Removable by default */
2009-11-09 14:15:21 +01:00
params - > removable_count < = i | | params - > removable [ i ] ;
lun - > filename =
params - > file_count > i & & params - > file [ i ] [ 0 ]
? params - > file [ i ]
: 0 ;
}
2009-11-09 14:15:23 +01:00
/* Let MSF use defaults */
2009-11-09 14:15:22 +01:00
cfg - > lun_name_format = 0 ;
cfg - > thread_name = 0 ;
2009-11-09 14:15:21 +01:00
cfg - > vendor_name = 0 ;
cfg - > product_name = 0 ;
cfg - > release = 0xffff ;
2010-06-21 13:57:09 +02:00
cfg - > ops = NULL ;
cfg - > private_data = NULL ;
2009-11-09 14:15:26 +01:00
2009-11-09 14:15:21 +01:00
/* Finalise */
cfg - > can_stall = params - > stall ;
}
static inline struct fsg_common *
fsg_common_from_params ( struct fsg_common * common ,
struct usb_composite_dev * cdev ,
const struct fsg_module_parameters * params )
__attribute__ ( ( unused ) ) ;
static inline struct fsg_common *
fsg_common_from_params ( struct fsg_common * common ,
struct usb_composite_dev * cdev ,
const struct fsg_module_parameters * params )
{
struct fsg_config cfg ;
fsg_config_from_params ( & cfg , params ) ;
return fsg_common_init ( common , cdev , & cfg ) ;
}