diff options
Diffstat (limited to 'drivers/usb/gadget/storage_common.c')
| -rw-r--r-- | drivers/usb/gadget/storage_common.c | 708 | 
1 files changed, 211 insertions, 497 deletions
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 3b513bafaf2..648f9e489b3 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -3,363 +3,37 @@   *   * Copyright (C) 2003-2008 Alan Stern   * Copyeight (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) + * Author: Michal Nazarewicz (mina86@mina86.com)   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by   * the Free Software Foundation; either version 2 of the License, or   * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   */ -  /*   * This file requires the following identifiers used in USB strings to   * be defined (each of type pointer to char): - *  - fsg_string_manufacturer -- name of the manufacturer - *  - fsg_string_product      -- name of the product - *  - fsg_string_config       -- name of the configuration   *  - fsg_string_interface    -- name of the interface - * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS - * macro is defined prior to including this file. - */ - -/* - * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and - * fsg_hs_intr_in_desc objects as well as - * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES - * macros are not defined. - * - * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, - * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not - * defined (as well as corresponding entries in string tables are - * missing) and FSG_STRING_INTERFACE has value of zero. - * - * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. - */ - -/* - * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included - * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN - * characters rather then a pointer to void. - */ - - -#include <linux/usb/storage.h> -#include <scsi/scsi.h> -#include <asm/unaligned.h> - - -/* - * 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 FSG_VENDOR_ID	0x0525	/* NetChip */ -#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */ - - -/*-------------------------------------------------------------------------*/ - - -#ifndef DEBUG -#undef VERBOSE_DEBUG -#undef DUMP_MSGS -#endif /* !DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VLDBG	LDBG -#else -#define VLDBG(lun, fmt, args...) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args) -#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) -#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args) -#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args)  /* - * Keep those macros in sync with those in - * include/linux/usb/composite.h or else GCC will complain.  If they - * are identical (the same names of arguments, white spaces in the - * same places) GCC will allow redefinition otherwise (even if some - * white space is removed or added) warning will be issued. - * - * Those macros are needed here because File Storage Gadget does not - * include the composite.h header.  For composite gadgets those macros - * are redundant since composite.h is included any way. - * - * One could check whether those macros are already defined (which - * would indicate composite.h had been included) or not (which would - * indicate we were in FSG) but this is not done because a warning is - * desired if definitions here differ from the ones in composite.h. - * - * We want the definitions to match and be the same in File Storage - * Gadget as well as Mass Storage Function (and so composite gadgets - * using MSF).  If someone changes them in composite.h it will produce - * a warning in this file when building MSF. + * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers + * sets the number of pipeline buffers (length of the fsg_buffhd array). + * The valid range of num_buffers is: num >= 2 && num <= 4.   */ -#define DBG(d, fmt, args...)     dev_dbg(&(d)->gadget->dev , fmt , ## args) -#define VDBG(d, fmt, args...)    dev_vdbg(&(d)->gadget->dev , fmt , ## args) -#define ERROR(d, fmt, args...)   dev_err(&(d)->gadget->dev , fmt , ## args) -#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args) -#define INFO(d, fmt, args...)    dev_info(&(d)->gadget->dev , fmt , ## args) +#include <linux/module.h> +#include <linux/blkdev.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/usb/composite.h> - -#ifdef DUMP_MSGS - -#  define dump_msg(fsg, /* const char * */ label,			\ -		   /* const u8 * */ buf, /* unsigned */ length) do {	\ -	if (length < 512) {						\ -		DBG(fsg, "%s, length %u:\n", label, length);		\ -		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,	\ -			       16, 1, buf, length, 0);			\ -	}								\ -} while (0) - -#  define dump_cdb(fsg) do { } while (0) - -#else - -#  define dump_msg(fsg, /* const char * */ label, \ -		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0) - -#  ifdef VERBOSE_DEBUG - -#    define dump_cdb(fsg)						\ -	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,	\ -		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\ - -#  else - -#    define dump_cdb(fsg) do { } while (0) - -#  endif /* VERBOSE_DEBUG */ - -#endif /* DUMP_MSGS */ - - - - - -/*-------------------------------------------------------------------------*/ - -/* Bulk-only data structures */ - -/* Command Block Wrapper */ -struct fsg_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 - -/* Command Status Wrapper */ -struct bulk_cs_wrap { -	__le32	Signature;		/* Should = 'USBS' */ -	u32	Tag;			/* Same as original command */ -	__le32	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 - - -/* CBI Interrupt data structure */ -struct interrupt_data { -	u8	bType; -	u8	bValue; -}; - -#define CBI_INTERRUPT_DATA_LEN		2 - -/* CBI Accept Device-Specific Command request */ -#define USB_CBI_ADSC_REQUEST		0x00 - - -/* Length of a SCSI Command Data Block */ -#define MAX_COMMAND_SIZE	16 - -/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ -#define SS_NO_SENSE				0 -#define SS_COMMUNICATION_FAILURE		0x040800 -#define SS_INVALID_COMMAND			0x052000 -#define SS_INVALID_FIELD_IN_CDB			0x052400 -#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100 -#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500 -#define SS_MEDIUM_NOT_PRESENT			0x023a00 -#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302 -#define SS_NOT_READY_TO_READY_TRANSITION	0x062800 -#define SS_RESET_OCCURRED			0x062900 -#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900 -#define SS_UNRECOVERED_READ_ERROR		0x031100 -#define SS_WRITE_ERROR				0x030c02 -#define SS_WRITE_PROTECTED			0x072700 - -#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */ -#define ASC(x)		((u8) ((x) >> 8)) -#define ASCQ(x)		((u8) (x)) - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_lun { -	struct file	*filp; -	loff_t		file_length; -	loff_t		num_sectors; - -	unsigned int	initially_ro:1; -	unsigned int	ro:1; -	unsigned int	removable:1; -	unsigned int	cdrom:1; -	unsigned int	prevent_medium_removal:1; -	unsigned int	registered:1; -	unsigned int	info_valid:1; -	unsigned int	nofua:1; - -	u32		sense_data; -	u32		sense_data_info; -	u32		unit_attention_data; - -	struct device	dev; -}; - -#define fsg_lun_is_open(curlun)	((curlun)->filp != NULL) - -static struct fsg_lun *fsg_lun_from_dev(struct device *dev) -{ -	return container_of(dev, struct fsg_lun, dev); -} - - -/* Big enough to hold our biggest descriptor */ -#define EP0_BUFSIZE	256 -#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */ - -/* Number of buffers we will use.  2 is enough for double-buffering */ -#define FSG_NUM_BUFFERS	2 - -/* Default size of buffer length. */ -#define FSG_BUFLEN	((u32)16384) - -/* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS	8 - -enum fsg_buffer_state { -	BUF_STATE_EMPTY = 0, -	BUF_STATE_FULL, -	BUF_STATE_BUSY -}; - -struct fsg_buffhd { -#ifdef FSG_BUFFHD_STATIC_BUFFER -	char				buf[FSG_BUFLEN]; -#else -	void				*buf; -#endif -	enum fsg_buffer_state		state; -	struct fsg_buffhd		*next; - -	/* -	 * The NetChip 2280 is faster, and handles some protocol faults -	 * better, if we don't submit any short bulk-out read requests. -	 * So we will record the intended request length here. -	 */ -	unsigned int			bulk_out_intended_length; - -	struct usb_request		*inreq; -	int				inreq_busy; -	struct usb_request		*outreq; -	int				outreq_busy; -}; - -enum fsg_state { -	/* This one isn't used anywhere */ -	FSG_STATE_COMMAND_PHASE = -10, -	FSG_STATE_DATA_PHASE, -	FSG_STATE_STATUS_PHASE, - -	FSG_STATE_IDLE = 0, -	FSG_STATE_ABORT_BULK_OUT, -	FSG_STATE_RESET, -	FSG_STATE_INTERFACE_CHANGE, -	FSG_STATE_CONFIG_CHANGE, -	FSG_STATE_DISCONNECT, -	FSG_STATE_EXIT, -	FSG_STATE_TERMINATED -}; - -enum data_direction { -	DATA_DIR_UNKNOWN = 0, -	DATA_DIR_FROM_HOST, -	DATA_DIR_TO_HOST, -	DATA_DIR_NONE -}; - - -/*-------------------------------------------------------------------------*/ - - -static inline u32 get_unaligned_be24(u8 *buf) -{ -	return 0xffffff & (u32) get_unaligned_be32(buf - 1); -} - - -/*-------------------------------------------------------------------------*/ - - -enum { -#ifndef FSG_NO_DEVICE_STRINGS -	FSG_STRING_MANUFACTURER	= 1, -	FSG_STRING_PRODUCT, -	FSG_STRING_SERIAL, -	FSG_STRING_CONFIG, -#endif -	FSG_STRING_INTERFACE -}; - - -#ifndef FSG_NO_OTG -static struct usb_otg_descriptor -fsg_otg_desc = { -	.bLength =		sizeof fsg_otg_desc, -	.bDescriptorType =	USB_DT_OTG, - -	.bmAttributes =		USB_OTG_SRP, -}; -#endif +#include "storage_common.h"  /* There is only one interface. */ -static struct usb_interface_descriptor -fsg_intf_desc = { +struct usb_interface_descriptor fsg_intf_desc = {  	.bLength =		sizeof fsg_intf_desc,  	.bDescriptorType =	USB_DT_INTERFACE, @@ -369,14 +43,14 @@ fsg_intf_desc = {  	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */  	.iInterface =		FSG_STRING_INTERFACE,  }; +EXPORT_SYMBOL_GPL(fsg_intf_desc);  /*   * Three full-speed endpoint descriptors: bulk-in, bulk-out, and   * interrupt-in.   */ -static struct usb_endpoint_descriptor -fsg_fs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -384,9 +58,9 @@ fsg_fs_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	/* wMaxPacketSize set by autoconfiguration */  }; +EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_fs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -394,40 +68,15 @@ fsg_fs_bulk_out_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	/* wMaxPacketSize set by autoconfiguration */  }; +EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc); -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_fs_intr_in_desc = { -	.bLength =		USB_DT_ENDPOINT_SIZE, -	.bDescriptorType =	USB_DT_ENDPOINT, - -	.bEndpointAddress =	USB_DIR_IN, -	.bmAttributes =		USB_ENDPOINT_XFER_INT, -	.wMaxPacketSize =	cpu_to_le16(2), -	.bInterval =		32,	/* frames -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	2 -#else -#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	1 -#endif - -#endif - -static struct usb_descriptor_header *fsg_fs_function[] = { -#ifndef FSG_NO_OTG -	(struct usb_descriptor_header *) &fsg_otg_desc, -#endif +struct usb_descriptor_header *fsg_fs_function[] = {  	(struct usb_descriptor_header *) &fsg_intf_desc,  	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,  	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP -	(struct usb_descriptor_header *) &fsg_fs_intr_in_desc, -#endif  	NULL,  }; +EXPORT_SYMBOL_GPL(fsg_fs_function);  /* @@ -438,8 +87,7 @@ static struct usb_descriptor_header *fsg_fs_function[] = {   * and a "device qualifier" ... plus more construction options   * for the configuration descriptor.   */ -static struct usb_endpoint_descriptor -fsg_hs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -447,9 +95,9 @@ fsg_hs_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	.wMaxPacketSize =	cpu_to_le16(512),  }; +EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_hs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -458,68 +106,62 @@ fsg_hs_bulk_out_desc = {  	.wMaxPacketSize =	cpu_to_le16(512),  	.bInterval =		1,	/* NAK every 1 uframe */  }; +EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc); + -#ifndef FSG_NO_INTR_EP +struct usb_descriptor_header *fsg_hs_function[] = { +	(struct usb_descriptor_header *) &fsg_intf_desc, +	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, +	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, +	NULL, +}; +EXPORT_SYMBOL_GPL(fsg_hs_function); -static struct usb_endpoint_descriptor -fsg_hs_intr_in_desc = { +struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, -	/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ -	.bmAttributes =		USB_ENDPOINT_XFER_INT, -	.wMaxPacketSize =	cpu_to_le16(2), -	.bInterval =		9,	/* 2**(9-1) = 256 uframes -> 32 ms */ +	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024),  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc); -#ifndef FSG_NO_OTG -#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	2 -#else -#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	1 -#endif +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { +	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc), +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, -#endif - -static struct usb_descriptor_header *fsg_hs_function[] = { -#ifndef FSG_NO_OTG -	(struct usb_descriptor_header *) &fsg_otg_desc, -#endif -	(struct usb_descriptor_header *) &fsg_intf_desc, -	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, -	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP -	(struct usb_descriptor_header *) &fsg_hs_intr_in_desc, -#endif -	NULL, +	/*.bMaxBurst =		DYNAMIC, */  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc); -/* Maxpacket and other transfer characteristics vary by speed. */ -static struct usb_endpoint_descriptor * -fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, -		struct usb_endpoint_descriptor *hs) -{ -	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) -		return hs; -	return fs; -} +struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc); +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { +	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc), +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, -/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ -static struct usb_string		fsg_strings[] = { -#ifndef FSG_NO_DEVICE_STRINGS -	{FSG_STRING_MANUFACTURER,	fsg_string_manufacturer}, -	{FSG_STRING_PRODUCT,		fsg_string_product}, -	{FSG_STRING_SERIAL,		""}, -	{FSG_STRING_CONFIG,		fsg_string_config}, -#endif -	{FSG_STRING_INTERFACE,		fsg_string_interface}, -	{} +	/*.bMaxBurst =		DYNAMIC, */  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc); -static struct usb_gadget_strings	fsg_stringtab = { -	.language	= 0x0409,		/* en-us */ -	.strings	= fsg_strings, +struct usb_descriptor_header *fsg_ss_function[] = { +	(struct usb_descriptor_header *) &fsg_intf_desc, +	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, +	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, +	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc, +	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, +	NULL,  }; +EXPORT_SYMBOL_GPL(fsg_ss_function);   /*-------------------------------------------------------------------------*/ @@ -529,7 +171,17 @@ static struct usb_gadget_strings	fsg_stringtab = {   * the caller must own fsg->filesem for writing.   */ -static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) +void fsg_lun_close(struct fsg_lun *curlun) +{ +	if (curlun->filp) { +		LDBG(curlun, "close backing file\n"); +		fput(curlun->filp); +		curlun->filp = NULL; +	} +} +EXPORT_SYMBOL_GPL(fsg_lun_close); + +int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  {  	int				ro;  	struct file			*filp = NULL; @@ -538,12 +190,14 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  	loff_t				size;  	loff_t				num_sectors;  	loff_t				min_sectors; +	unsigned int			blkbits; +	unsigned int			blksize;  	/* R/W if we can, R/O if we must */  	ro = curlun->initially_ro;  	if (!ro) {  		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); -		if (-EROFS == PTR_ERR(filp)) +		if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)  			ro = 1;  	}  	if (ro) @@ -556,12 +210,8 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  	if (!(filp->f_mode & FMODE_WRITE))  		ro = 1; -	if (filp->f_path.dentry) -		inode = filp->f_path.dentry->d_inode; -	if (inode && S_ISBLK(inode->i_mode)) { -		if (bdev_read_only(inode->i_bdev)) -			ro = 1; -	} else if (!inode || !S_ISREG(inode->i_mode)) { +	inode = file_inode(filp); +	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {  		LINFO(curlun, "invalid file type: %s\n", filename);  		goto out;  	} @@ -570,11 +220,11 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  	 * If we can't read the file, it's no good.  	 * If we can't write the file, use it read-only.  	 */ -	if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { +	if (!(filp->f_mode & FMODE_CAN_READ)) {  		LINFO(curlun, "file not readable: %s\n", filename);  		goto out;  	} -	if (!(filp->f_op->write || filp->f_op->aio_write)) +	if (!(filp->f_mode & FMODE_CAN_WRITE))  		ro = 1;  	size = i_size_read(inode->i_mapping->host); @@ -583,13 +233,24 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  		rc = (int) size;  		goto out;  	} -	num_sectors = size >> 9;	/* File size in 512-byte blocks */ + +	if (curlun->cdrom) { +		blksize = 2048; +		blkbits = 11; +	} else if (inode->i_bdev) { +		blksize = bdev_logical_block_size(inode->i_bdev); +		blkbits = blksize_bits(blksize); +	} else { +		blksize = 512; +		blkbits = 9; +	} + +	num_sectors = size >> blkbits; /* File size in logic-block-size blocks */  	min_sectors = 1;  	if (curlun->cdrom) { -		num_sectors &= ~3;	/* Reduce to a multiple of 2048 */ -		min_sectors = 300*4;	/* Smallest track is 300 frames */ -		if (num_sectors >= 256*60*75*4) { -			num_sectors = (256*60*75 - 1) * 4; +		min_sectors = 300;	/* Smallest track is 300 frames */ +		if (num_sectors >= 256*60*75) { +			num_sectors = 256*60*75 - 1;  			LINFO(curlun, "file too big: %s\n", filename);  			LINFO(curlun, "using only first %d blocks\n",  					(int) num_sectors); @@ -601,28 +262,23 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  		goto out;  	} -	get_file(filp); +	if (fsg_lun_is_open(curlun)) +		fsg_lun_close(curlun); + +	curlun->blksize = blksize; +	curlun->blkbits = blkbits;  	curlun->ro = ro;  	curlun->filp = filp;  	curlun->file_length = size;  	curlun->num_sectors = num_sectors;  	LDBG(curlun, "open backing file: %s\n", filename); -	rc = 0; +	return 0;  out: -	filp_close(filp, current->files); +	fput(filp);  	return rc;  } - - -static void fsg_lun_close(struct fsg_lun *curlun) -{ -	if (curlun->filp) { -		LDBG(curlun, "close backing file\n"); -		fput(curlun->filp); -		curlun->filp = NULL; -	} -} +EXPORT_SYMBOL_GPL(fsg_lun_open);  /*-------------------------------------------------------------------------*/ @@ -631,7 +287,7 @@ static void fsg_lun_close(struct fsg_lun *curlun)   * Sync the file data, don't bother with the metadata.   * This code was copied from fs/buffer.c:sys_fdatasync().   */ -static int fsg_lun_fsync_sub(struct fsg_lun *curlun) +int fsg_lun_fsync_sub(struct fsg_lun *curlun)  {  	struct file	*filp = curlun->filp; @@ -639,8 +295,9 @@ static int fsg_lun_fsync_sub(struct fsg_lun *curlun)  		return 0;  	return vfs_fsync(filp, 1);  } +EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); -static void store_cdrom_address(u8 *dest, int msf, u32 addr) +void store_cdrom_address(u8 *dest, int msf, u32 addr)  {  	if (msf) {  		/* Convert to Minutes-Seconds-Frames */ @@ -657,34 +314,28 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)  		put_unaligned_be32(addr, dest);  	}  } - +EXPORT_SYMBOL_GPL(store_cdrom_address);  /*-------------------------------------------------------------------------*/ -static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, -			   char *buf) +ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -  	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)  				  ? curlun->ro  				  : curlun->initially_ro);  } +EXPORT_SYMBOL_GPL(fsg_show_ro); -static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, -			      char *buf) +ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -  	return sprintf(buf, "%u\n", curlun->nofua);  } +EXPORT_SYMBOL_GPL(fsg_show_nofua); -static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, -			     char *buf) +ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		      char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev);  	char		*p;  	ssize_t		rc; @@ -706,45 +357,69 @@ static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,  	up_read(filesem);  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_show_file); +ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) +{ +	return sprintf(buf, "%u\n", curlun->cdrom); +} +EXPORT_SYMBOL_GPL(fsg_show_cdrom); -static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, -			    const char *buf, size_t count) +ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf)  { -	ssize_t		rc = count; -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev); -	unsigned long	ro; +	return sprintf(buf, "%u\n", curlun->removable); +} +EXPORT_SYMBOL_GPL(fsg_show_removable); -	if (strict_strtoul(buf, 2, &ro)) -		return -EINVAL; +/* + * The caller must hold fsg->filesem for reading when calling this function. + */ +static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro) +{ +	if (fsg_lun_is_open(curlun)) { +		LDBG(curlun, "read-only status change prevented\n"); +		return -EBUSY; +	} + +	curlun->ro = ro; +	curlun->initially_ro = ro; +	LDBG(curlun, "read-only status set to %d\n", curlun->ro); + +	return 0; +} + +ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		     const char *buf, size_t count) +{ +	ssize_t		rc; +	bool		ro; + +	rc = strtobool(buf, &ro); +	if (rc) +		return rc;  	/*  	 * Allow the write-enable status to change only while the  	 * backing file is closed.  	 */  	down_read(filesem); -	if (fsg_lun_is_open(curlun)) { -		LDBG(curlun, "read-only status change prevented\n"); -		rc = -EBUSY; -	} else { -		curlun->ro = ro; -		curlun->initially_ro = ro; -		LDBG(curlun, "read-only status set to %d\n", curlun->ro); -	} +	rc = _fsg_store_ro(curlun, ro); +	if (!rc) +		rc = count;  	up_read(filesem); +  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_store_ro); -static ssize_t fsg_store_nofua(struct device *dev, -			       struct device_attribute *attr, -			       const char *buf, size_t count) +ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	unsigned long	nofua; +	bool		nofua; +	int		ret; -	if (strict_strtoul(buf, 2, &nofua)) -		return -EINVAL; +	ret = strtobool(buf, &nofua); +	if (ret) +		return ret;  	/* Sync data when switching from async mode to sync */  	if (!nofua && curlun->nofua) @@ -754,12 +429,11 @@ static ssize_t fsg_store_nofua(struct device *dev,  	return count;  } +EXPORT_SYMBOL_GPL(fsg_store_nofua); -static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, -			      const char *buf, size_t count) +ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		       const char *buf, size_t count)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev);  	int		rc = 0;  	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { @@ -771,20 +445,60 @@ static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,  	if (count > 0 && buf[count-1] == '\n')  		((char *) buf)[count-1] = 0;		/* Ugh! */ -	/* Eject current medium */ -	down_write(filesem); -	if (fsg_lun_is_open(curlun)) { -		fsg_lun_close(curlun); -		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; -	} -  	/* Load new medium */ +	down_write(filesem);  	if (count > 0 && buf[0]) { +		/* fsg_lun_open() will close existing file if any. */  		rc = fsg_lun_open(curlun, buf);  		if (rc == 0)  			curlun->unit_attention_data =  					SS_NOT_READY_TO_READY_TRANSITION; +	} else if (fsg_lun_is_open(curlun)) { +		fsg_lun_close(curlun); +		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;  	}  	up_write(filesem);  	return (rc < 0 ? rc : count);  } +EXPORT_SYMBOL_GPL(fsg_store_file); + +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, +			const char *buf, size_t count) +{ +	bool		cdrom; +	int		ret; + +	ret = strtobool(buf, &cdrom); +	if (ret) +		return ret; + +	down_read(filesem); +	ret = cdrom ? _fsg_store_ro(curlun, true) : 0; + +	if (!ret) { +		curlun->cdrom = cdrom; +		ret = count; +	} +	up_read(filesem); + +	return ret; +} +EXPORT_SYMBOL_GPL(fsg_store_cdrom); + +ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, +			    size_t count) +{ +	bool		removable; +	int		ret; + +	ret = strtobool(buf, &removable); +	if (ret) +		return ret; + +	curlun->removable = removable; + +	return count; +} +EXPORT_SYMBOL_GPL(fsg_store_removable); + +MODULE_LICENSE("GPL");  | 
