📄 file_storage.c
字号:
/*
* file_storage.c -- File-backed USB Storage Gadget, for USB development
*
* Copyright (C) 2003-2005 Alan Stern
* 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.
*/
/*
* The File-backed Storage Gadget acts as a USB Mass Storage device,
* appearing to the host as a disk drive. In addition to providing an
* example of a genuinely useful gadget driver for a USB device, it also
* illustrates a technique of double-buffering for increased throughput.
* Last but not least, it gives an easy way to probe the behavior of the
* Mass Storage drivers in a USB host.
*
* Backing storage is provided by a regular file or a block device, specified
* by the "file" module parameter. Access can be limited to read-only by
* setting the optional "ro" module parameter. The gadget will indicate that
* it has removable media if the optional "removable" module parameter is set.
*
* The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
* and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
* by the optional "transport" module parameter. It also supports the
* following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
* UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
* the optional "protocol" module parameter. In addition, the default
* Vendor ID, Product ID, and release number can be overridden.
*
* There is support for multiple logical units (LUNs), each of which has
* its own backing file. The number of LUNs can be set using the optional
* "luns" module parameter (anywhere from 1 to 8), and the corresponding
* files are specified using comma-separated lists for "file" and "ro".
* The default number of LUNs is taken from the number of "file" elements;
* it is 1 if "file" is not given. If "removable" is not set then a backing
* file must be specified for each LUN. If it is set, then an unspecified
* or empty backing filename means the LUN's medium is not loaded.
*
* Requirements are modest; only a bulk-in and a bulk-out endpoint are
* needed (an interrupt-out endpoint is also needed for CBI). The memory
* requirement amounts to two 16K buffers, size configurable by a parameter.
* Support is included for both full-speed and high-speed operation.
*
* Module options:
*
* file=filename[,filename...]
* Required if "removable" is not set, names of
* the files or block devices used for
* backing storage
* ro=b[,b...] Default false, booleans for read-only access
* removable Default false, boolean for removable media
* 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
* transport=XXX Default BBB, transport name (CB, CBI, or BBB)
* protocol=YYY Default SCSI, protocol name (RBC, 8020 or
* ATAPI, QIC, UFI, 8070, or SCSI;
* also 1 - 6)
* vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
* product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
* release=0xRRRR Override the USB release number (bcdDevice)
* buflen=N Default N=16384, buffer size used (will be
* rounded down to a multiple of
* PAGE_CACHE_SIZE)
*
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
* "removable", "luns", and "stall" options are available; default values
* are used for everything else.
*
* The pathnames of the backing files and the ro settings are available in
* the attribute files "file" and "ro" in the lun<n> 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.
*
* This gadget driver is heavily based on "Gadget Zero" by David Brownell.
*/
/*
* Driver Design
*
* The FSG driver is fairly straightforward. There is a main kernel
* 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
* 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. So just before the thread
* exits, it deregisters the gadget driver. This makes things a little
* tricky: The driver is deregistered at two places, and the exiting
* thread can indirectly call fsg_unbind() which in turn can tell the
* thread to exit. The first problem is resolved through the use of the
* REGISTERED atomic bitflag; the driver will only be deregistered once.
* The second problem is resolved by having fsg_unbind() check
* fsg->state; it won't try to stop the thread if the state is already
* FSG_STATE_TERMINATED.
*
* 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.
*/
#undef DEBUG
#undef VERBOSE
#undef DUMP_MSGS
#include <linux/config.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/bitops.h>
#include <linux/blkdev.h>
#include <linux/compiler.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/init.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pagemap.h>
#include <linux/rwsem.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/suspend.h>
#include <linux/utsname.h>
#include <linux/wait.h>
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
/*-------------------------------------------------------------------------*/
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
#define DRIVER_VERSION "20 October 2004"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Alan Stern");
MODULE_LICENSE("Dual BSD/GPL");
/* Thanks to NetChip Technologies for donating this product ID.
*
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures. */
#define DRIVER_VENDOR_ID 0x0525 // NetChip
#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget
/*
* This driver assumes self-powered hardware and has no way for users to
* trigger remote wakeup. It uses autoconfiguration to select endpoints
* and endpoint addresses.
*/
/*-------------------------------------------------------------------------*/
#define xprintk(f,level,fmt,args...) \
dev_printk(level , &(f)->gadget->dev , fmt , ## args)
#define yprintk(l,level,fmt,args...) \
dev_printk(level , &(l)->dev , fmt , ## args)
//#define DEBUG
#ifdef DEBUG
#define DBG(fsg,fmt,args...) \
xprintk(fsg , KERN_DEBUG , fmt , ## args)
#define LDBG(lun,fmt,args...) \
yprintk(lun , KERN_DEBUG , fmt , ## args)
#define MDBG(fmt,args...) \
printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
#else
#define DBG(fsg,fmt,args...) \
do { } while (0)
#define LDBG(lun,fmt,args...) \
do { } while (0)
#define MDBG(fmt,args...) \
do { } while (0)
#undef VERBOSE
#undef DUMP_MSGS
#endif /* DEBUG */
//#define VERBOSE
#ifdef VERBOSE
#define VDBG DBG
#define VLDBG LDBG
#else
#define VDBG(fsg,fmt,args...) \
do { } while (0)
#define VLDBG(lun,fmt,args...) \
do { } while (0)
#endif /* VERBOSE */
#define ERROR(fsg,fmt,args...) \
xprintk(fsg , KERN_ERR , fmt , ## args)
#define LERROR(lun,fmt,args...) \
yprintk(lun , KERN_ERR , fmt , ## args)
#define WARN(fsg,fmt,args...) \
xprintk(fsg , KERN_WARNING , fmt , ## args)
#define LWARN(lun,fmt,args...) \
yprintk(lun , KERN_WARNING , fmt , ## args)
#define INFO(fsg,fmt,args...) \
xprintk(fsg , KERN_INFO , fmt , ## args)
#define LINFO(lun,fmt,args...) \
yprintk(lun , KERN_INFO , fmt , ## args)
#define MINFO(fmt,args...) \
printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
/*-------------------------------------------------------------------------*/
/* Encapsulate the module parameter settings */
#define MAX_LUNS 8
/* Arggh! There should be a module_param_array_named macro! */
static char *file[MAX_LUNS] = {NULL, };
static int ro[MAX_LUNS] = {0, };
static struct {
int num_filenames;
int num_ros;
unsigned int nluns;
int removable;
int can_stall;
char *transport_parm;
char *protocol_parm;
unsigned short vendor;
unsigned short product;
unsigned short release;
unsigned int buflen;
int transport_type;
char *transport_name;
int protocol_type;
char *protocol_name;
} mod_data = { // Default values
.transport_parm = "BBB",
.protocol_parm = "SCSI",
.removable = 0,
.can_stall = 1,
.vendor = DRIVER_VENDOR_ID,
.product = DRIVER_PRODUCT_ID,
.release = 0xffff, // Use controller chip type
.buflen = 16384,
};
module_param_array(file, charp, &mod_data.num_filenames, S_IRUGO);
MODULE_PARM_DESC(file, "names of backing files or devices");
module_param_array(ro, bool, &mod_data.num_ros, S_IRUGO);
MODULE_PARM_DESC(ro, "true to force read-only");
module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
MODULE_PARM_DESC(luns, "number of LUNs");
module_param_named(removable, mod_data.removable, bool, S_IRUGO);
MODULE_PARM_DESC(removable, "true to simulate removable media");
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
/* In the non-TEST version, only the module parameters listed above
* are available. */
#ifdef CONFIG_USB_FILE_STORAGE_TEST
module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO);
MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");
module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO);
MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, "
"8070, or SCSI)");
module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO);
MODULE_PARM_DESC(vendor, "USB Vendor ID");
module_param_named(product, mod_data.product, ushort, S_IRUGO);
MODULE_PARM_DESC(product, "USB Product ID");
module_param_named(release, mod_data.release, ushort, S_IRUGO);
MODULE_PARM_DESC(release, "USB release number");
module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
MODULE_PARM_DESC(buflen, "I/O buffer size");
#endif /* CONFIG_USB_FILE_STORAGE_TEST */
/*-------------------------------------------------------------------------*/
/* USB protocol value = the transport method */
#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt
#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt
#define USB_PR_BULK 0x50 // Bulk-only
/* USB subclass value = the protocol encapsulation */
#define USB_SC_RBC 0x01 // Reduced Block Commands (flash)
#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM)
#define USB_SC_QIC 0x03 // QIC-157 (tape)
#define USB_SC_UFI 0x04 // UFI (floppy)
#define USB_SC_8070 0x05 // SFF-8070i (removable)
#define USB_SC_SCSI 0x06 // Transparent SCSI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -