⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 file_storage.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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/kthread.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)#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	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_TESTmodule_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/* Bulk-only data structures *//* Command Block Wrapper */struct bulk_cb_wrap {	__le32	Signature;		// Contains 'USBC'	u32	Tag;			// Unique per command id	__le32	DataTransferLength;	// Size of the data	u8	Flags;			// Direction in bit 7	u8	Lun;			// LUN (normally 0)	u8	Length;			// Of the CDB, <= MAX_COMMAND_SIZE	u8	CDB[16];		// Command Data Block};#define USB_BULK_CB_WRAP_LEN	31#define USB_BULK_CB_SIG		0x43425355	// Spells out USBC#define USB_BULK_IN_FLAG	0x80

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -