📄 file_storage.c
字号:
/* * file_storage.c -- File-backed USB Storage Gadget, for USB development * * Copyright (C) 2003, 2004 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 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. For testing purposes the * gadget will indicate that it has removable media if the optional * "removable" module parameter is set. 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 * luns=N Default N = number of filenames, number of * LUNs to support * 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) * removable Default false, boolean for removable media * 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) * stall Default determined according to the type of * USB device controller (usually true), * boolean to permit the driver to halt * bulk endpoints * * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file" and "ro" * options are available; default values are used for everything else. * * 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. * * 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/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/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/uts.h>#include <linux/version.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 "05 June 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 fakedev_printk(level, dev, format, args...) \ printk(level "%s %s: " format , DRIVER_NAME , (dev)->name , ## args)#define xprintk(f,level,fmt,args...) \ fakedev_printk(level , (f)->gadget , fmt , ## args)#define yprintk(l,level,fmt,args...) \ fakedev_printk(level , &(l)->dev , fmt , ## args)#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 */#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 8static char *file[MAX_LUNS] = {NULL, };static int ro[MAX_LUNS] = {0, };static unsigned int luns = 0; // Default valuesstatic char *transport = "BBB";static char *protocol = "SCSI";static int removable = 0;static unsigned short vendor = DRIVER_VENDOR_ID;static unsigned short product = DRIVER_PRODUCT_ID;static unsigned short release = 0xffff; // Use controller chip typestatic unsigned int buflen = 16384;static int stall = 1;static struct { unsigned int nluns; char *transport_parm; char *protocol_parm; int removable; unsigned short vendor; unsigned short product; unsigned short release; unsigned int buflen; int can_stall; int transport_type; char *transport_name; int protocol_type; char *protocol_name;} mod_data;MODULE_PARM(file, "1-8s");MODULE_PARM_DESC(file, "names of backing files or devices");MODULE_PARM(ro, "1-8b");MODULE_PARM_DESC(ro, "true to force read-only");/* In the non-TEST version, only the file and ro module parameters * are available. */#ifdef CONFIG_USB_FILE_STORAGE_TESTMODULE_PARM(luns, "i");MODULE_PARM_DESC(luns, "number of LUNs");MODULE_PARM(transport, "s");MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)");MODULE_PARM(protocol, "s");MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " "8070, or SCSI)");MODULE_PARM(removable, "b");MODULE_PARM_DESC(removable, "true to simulate removable media");MODULE_PARM(vendor, "h");MODULE_PARM_DESC(vendor, "USB Vendor ID");MODULE_PARM(product, "h");MODULE_PARM_DESC(product, "USB Product ID");MODULE_PARM(release, "h");MODULE_PARM_DESC(release, "USB release number");MODULE_PARM(buflen, "i");MODULE_PARM_DESC(buflen, "I/O buffer size");MODULE_PARM(stall, "i");MODULE_PARM_DESC(stall, "false to prevent bulk stalls");#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/* Bulk-only data structures *//* Command Block Wrapper */struct bulk_cb_wrap { u32 Signature; // Contains 'USBC' u32 Tag; // Unique per command id u32 DataTransferLength; // Size of the data u8 Flags; // Direction in bit 7 u8 Lun; // LUN (normally 0) u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE u8 CDB[16]; // Command Data Block};#define USB_BULK_CB_WRAP_LEN 31#define USB_BULK_CB_SIG 0x43425355 // Spells out USBC#define USB_BULK_IN_FLAG 0x80/* Command Status Wrapper */struct bulk_cs_wrap { u32 Signature; // Should = 'USBS' u32 Tag; // Same as original command u32 Residue; // Amount not transferred u8 Status; // See below};#define USB_BULK_CS_WRAP_LEN 13#define USB_BULK_CS_SIG 0x53425355 // Spells out 'USBS'#define USB_STATUS_PASS 0#define USB_STATUS_FAIL 1#define USB_STATUS_PHASE_ERROR 2/* Bulk-only class specific requests */#define USB_BULK_RESET_REQUEST 0xff#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -