Linux Audio

Check our new training course

Loading...
v4.6
 
  1/*
  2 * storage_common.c -- Common definitions for mass storage functionality
  3 *
  4 * Copyright (C) 2003-2008 Alan Stern
  5 * Copyeight (C) 2009 Samsung Electronics
  6 * Author: Michal Nazarewicz (mina86@mina86.com)
  7 *
  8 * This program is free software; you can redistribute it and/or modify
  9 * it under the terms of the GNU General Public License as published by
 10 * the Free Software Foundation; either version 2 of the License, or
 11 * (at your option) any later version.
 12 */
 13
 14/*
 15 * This file requires the following identifiers used in USB strings to
 16 * be defined (each of type pointer to char):
 17 *  - fsg_string_interface    -- name of the interface
 18 */
 19
 20/*
 21 * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
 22 * sets the number of pipeline buffers (length of the fsg_buffhd array).
 23 * The valid range of num_buffers is: num >= 2 && num <= 4.
 24 */
 25
 26#include <linux/module.h>
 27#include <linux/blkdev.h>
 28#include <linux/file.h>
 29#include <linux/fs.h>
 30#include <linux/usb/composite.h>
 31
 32#include "storage_common.h"
 33
 34/* There is only one interface. */
 35
 36struct usb_interface_descriptor fsg_intf_desc = {
 37	.bLength =		sizeof fsg_intf_desc,
 38	.bDescriptorType =	USB_DT_INTERFACE,
 39
 40	.bNumEndpoints =	2,		/* Adjusted during fsg_bind() */
 41	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
 42	.bInterfaceSubClass =	USB_SC_SCSI,	/* Adjusted during fsg_bind() */
 43	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */
 44	.iInterface =		FSG_STRING_INTERFACE,
 45};
 46EXPORT_SYMBOL_GPL(fsg_intf_desc);
 47
 48/*
 49 * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
 50 * interrupt-in.
 51 */
 52
 53struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {
 54	.bLength =		USB_DT_ENDPOINT_SIZE,
 55	.bDescriptorType =	USB_DT_ENDPOINT,
 56
 57	.bEndpointAddress =	USB_DIR_IN,
 58	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 59	/* wMaxPacketSize set by autoconfiguration */
 60};
 61EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc);
 62
 63struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {
 64	.bLength =		USB_DT_ENDPOINT_SIZE,
 65	.bDescriptorType =	USB_DT_ENDPOINT,
 66
 67	.bEndpointAddress =	USB_DIR_OUT,
 68	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 69	/* wMaxPacketSize set by autoconfiguration */
 70};
 71EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc);
 72
 73struct usb_descriptor_header *fsg_fs_function[] = {
 74	(struct usb_descriptor_header *) &fsg_intf_desc,
 75	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
 76	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
 77	NULL,
 78};
 79EXPORT_SYMBOL_GPL(fsg_fs_function);
 80
 81
 82/*
 83 * USB 2.0 devices need to expose both high speed and full speed
 84 * descriptors, unless they only run at full speed.
 85 *
 86 * That means alternate endpoint descriptors (bigger packets)
 87 * and a "device qualifier" ... plus more construction options
 88 * for the configuration descriptor.
 89 */
 90struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {
 91	.bLength =		USB_DT_ENDPOINT_SIZE,
 92	.bDescriptorType =	USB_DT_ENDPOINT,
 93
 94	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
 95	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 96	.wMaxPacketSize =	cpu_to_le16(512),
 97};
 98EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc);
 99
100struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {
101	.bLength =		USB_DT_ENDPOINT_SIZE,
102	.bDescriptorType =	USB_DT_ENDPOINT,
103
104	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
105	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
106	.wMaxPacketSize =	cpu_to_le16(512),
107	.bInterval =		1,	/* NAK every 1 uframe */
108};
109EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc);
110
111
112struct usb_descriptor_header *fsg_hs_function[] = {
113	(struct usb_descriptor_header *) &fsg_intf_desc,
114	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
115	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
116	NULL,
117};
118EXPORT_SYMBOL_GPL(fsg_hs_function);
119
120struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {
121	.bLength =		USB_DT_ENDPOINT_SIZE,
122	.bDescriptorType =	USB_DT_ENDPOINT,
123
124	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
125	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
126	.wMaxPacketSize =	cpu_to_le16(1024),
127};
128EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc);
129
130struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
131	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
132	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
133
134	/*.bMaxBurst =		DYNAMIC, */
135};
136EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc);
137
138struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = {
139	.bLength =		USB_DT_ENDPOINT_SIZE,
140	.bDescriptorType =	USB_DT_ENDPOINT,
141
142	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
143	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
144	.wMaxPacketSize =	cpu_to_le16(1024),
145};
146EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc);
147
148struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
149	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
150	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
151
152	/*.bMaxBurst =		DYNAMIC, */
153};
154EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc);
155
156struct usb_descriptor_header *fsg_ss_function[] = {
157	(struct usb_descriptor_header *) &fsg_intf_desc,
158	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
159	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
160	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
161	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
162	NULL,
163};
164EXPORT_SYMBOL_GPL(fsg_ss_function);
165
166
167 /*-------------------------------------------------------------------------*/
168
169/*
170 * If the next two routines are called while the gadget is registered,
171 * the caller must own fsg->filesem for writing.
172 */
173
174void fsg_lun_close(struct fsg_lun *curlun)
175{
176	if (curlun->filp) {
177		LDBG(curlun, "close backing file\n");
178		fput(curlun->filp);
179		curlun->filp = NULL;
180	}
181}
182EXPORT_SYMBOL_GPL(fsg_lun_close);
183
184int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
185{
186	int				ro;
187	struct file			*filp = NULL;
188	int				rc = -EINVAL;
189	struct inode			*inode = NULL;
190	loff_t				size;
191	loff_t				num_sectors;
192	loff_t				min_sectors;
193	unsigned int			blkbits;
194	unsigned int			blksize;
195
196	/* R/W if we can, R/O if we must */
197	ro = curlun->initially_ro;
198	if (!ro) {
199		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
200		if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
201			ro = 1;
202	}
203	if (ro)
204		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
205	if (IS_ERR(filp)) {
206		LINFO(curlun, "unable to open backing file: %s\n", filename);
207		return PTR_ERR(filp);
208	}
209
210	if (!(filp->f_mode & FMODE_WRITE))
211		ro = 1;
212
213	inode = file_inode(filp);
214	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
215		LINFO(curlun, "invalid file type: %s\n", filename);
216		goto out;
217	}
218
219	/*
220	 * If we can't read the file, it's no good.
221	 * If we can't write the file, use it read-only.
222	 */
223	if (!(filp->f_mode & FMODE_CAN_READ)) {
224		LINFO(curlun, "file not readable: %s\n", filename);
225		goto out;
226	}
227	if (!(filp->f_mode & FMODE_CAN_WRITE))
228		ro = 1;
229
230	size = i_size_read(inode->i_mapping->host);
231	if (size < 0) {
232		LINFO(curlun, "unable to find file size: %s\n", filename);
233		rc = (int) size;
234		goto out;
235	}
236
237	if (curlun->cdrom) {
238		blksize = 2048;
239		blkbits = 11;
240	} else if (inode->i_bdev) {
241		blksize = bdev_logical_block_size(inode->i_bdev);
242		blkbits = blksize_bits(blksize);
243	} else {
244		blksize = 512;
245		blkbits = 9;
246	}
247
248	num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
249	min_sectors = 1;
250	if (curlun->cdrom) {
251		min_sectors = 300;	/* Smallest track is 300 frames */
252		if (num_sectors >= 256*60*75) {
253			num_sectors = 256*60*75 - 1;
254			LINFO(curlun, "file too big: %s\n", filename);
255			LINFO(curlun, "using only first %d blocks\n",
256					(int) num_sectors);
257		}
258	}
259	if (num_sectors < min_sectors) {
260		LINFO(curlun, "file too small: %s\n", filename);
261		rc = -ETOOSMALL;
262		goto out;
263	}
264
265	if (fsg_lun_is_open(curlun))
266		fsg_lun_close(curlun);
267
268	curlun->blksize = blksize;
269	curlun->blkbits = blkbits;
270	curlun->ro = ro;
271	curlun->filp = filp;
272	curlun->file_length = size;
273	curlun->num_sectors = num_sectors;
274	LDBG(curlun, "open backing file: %s\n", filename);
275	return 0;
276
277out:
278	fput(filp);
279	return rc;
280}
281EXPORT_SYMBOL_GPL(fsg_lun_open);
282
283
284/*-------------------------------------------------------------------------*/
285
286/*
287 * Sync the file data, don't bother with the metadata.
288 * This code was copied from fs/buffer.c:sys_fdatasync().
289 */
290int fsg_lun_fsync_sub(struct fsg_lun *curlun)
291{
292	struct file	*filp = curlun->filp;
293
294	if (curlun->ro || !filp)
295		return 0;
296	return vfs_fsync(filp, 1);
297}
298EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub);
299
300void store_cdrom_address(u8 *dest, int msf, u32 addr)
301{
302	if (msf) {
303		/* Convert to Minutes-Seconds-Frames */
304		addr >>= 2;		/* Convert to 2048-byte frames */
305		addr += 2*75;		/* Lead-in occupies 2 seconds */
306		dest[3] = addr % 75;	/* Frames */
307		addr /= 75;
308		dest[2] = addr % 60;	/* Seconds */
309		addr /= 60;
310		dest[1] = addr;		/* Minutes */
311		dest[0] = 0;		/* Reserved */
312	} else {
313		/* Absolute sector */
314		put_unaligned_be32(addr, dest);
315	}
316}
317EXPORT_SYMBOL_GPL(store_cdrom_address);
318
319/*-------------------------------------------------------------------------*/
320
321
322ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)
323{
324	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
325				  ? curlun->ro
326				  : curlun->initially_ro);
327}
328EXPORT_SYMBOL_GPL(fsg_show_ro);
329
330ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)
331{
332	return sprintf(buf, "%u\n", curlun->nofua);
333}
334EXPORT_SYMBOL_GPL(fsg_show_nofua);
335
336ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
337		      char *buf)
338{
339	char		*p;
340	ssize_t		rc;
341
342	down_read(filesem);
343	if (fsg_lun_is_open(curlun)) {	/* Get the complete pathname */
344		p = file_path(curlun->filp, buf, PAGE_SIZE - 1);
345		if (IS_ERR(p))
346			rc = PTR_ERR(p);
347		else {
348			rc = strlen(p);
349			memmove(buf, p, rc);
350			buf[rc] = '\n';		/* Add a newline */
351			buf[++rc] = 0;
352		}
353	} else {				/* No file, return 0 bytes */
354		*buf = 0;
355		rc = 0;
356	}
357	up_read(filesem);
358	return rc;
359}
360EXPORT_SYMBOL_GPL(fsg_show_file);
361
362ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf)
363{
364	return sprintf(buf, "%u\n", curlun->cdrom);
365}
366EXPORT_SYMBOL_GPL(fsg_show_cdrom);
367
368ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf)
369{
370	return sprintf(buf, "%u\n", curlun->removable);
371}
372EXPORT_SYMBOL_GPL(fsg_show_removable);
373
 
 
 
 
 
 
374/*
375 * The caller must hold fsg->filesem for reading when calling this function.
376 */
377static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro)
378{
379	if (fsg_lun_is_open(curlun)) {
380		LDBG(curlun, "read-only status change prevented\n");
381		return -EBUSY;
382	}
383
384	curlun->ro = ro;
385	curlun->initially_ro = ro;
386	LDBG(curlun, "read-only status set to %d\n", curlun->ro);
387
388	return 0;
389}
390
391ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
392		     const char *buf, size_t count)
393{
394	ssize_t		rc;
395	bool		ro;
396
397	rc = strtobool(buf, &ro);
398	if (rc)
399		return rc;
400
401	/*
402	 * Allow the write-enable status to change only while the
403	 * backing file is closed.
404	 */
405	down_read(filesem);
406	rc = _fsg_store_ro(curlun, ro);
407	if (!rc)
408		rc = count;
409	up_read(filesem);
410
411	return rc;
412}
413EXPORT_SYMBOL_GPL(fsg_store_ro);
414
415ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
416{
417	bool		nofua;
418	int		ret;
419
420	ret = strtobool(buf, &nofua);
421	if (ret)
422		return ret;
423
424	/* Sync data when switching from async mode to sync */
425	if (!nofua && curlun->nofua)
426		fsg_lun_fsync_sub(curlun);
427
428	curlun->nofua = nofua;
429
430	return count;
431}
432EXPORT_SYMBOL_GPL(fsg_store_nofua);
433
434ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
435		       const char *buf, size_t count)
436{
437	int		rc = 0;
438
439	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
440		LDBG(curlun, "eject attempt prevented\n");
441		return -EBUSY;				/* "Door is locked" */
442	}
443
444	/* Remove a trailing newline */
445	if (count > 0 && buf[count-1] == '\n')
446		((char *) buf)[count-1] = 0;		/* Ugh! */
447
448	/* Load new medium */
449	down_write(filesem);
450	if (count > 0 && buf[0]) {
451		/* fsg_lun_open() will close existing file if any. */
452		rc = fsg_lun_open(curlun, buf);
453		if (rc == 0)
454			curlun->unit_attention_data =
455					SS_NOT_READY_TO_READY_TRANSITION;
456	} else if (fsg_lun_is_open(curlun)) {
457		fsg_lun_close(curlun);
458		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
459	}
460	up_write(filesem);
461	return (rc < 0 ? rc : count);
462}
463EXPORT_SYMBOL_GPL(fsg_store_file);
464
465ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
466			const char *buf, size_t count)
467{
468	bool		cdrom;
469	int		ret;
470
471	ret = strtobool(buf, &cdrom);
472	if (ret)
473		return ret;
474
475	down_read(filesem);
476	ret = cdrom ? _fsg_store_ro(curlun, true) : 0;
477
478	if (!ret) {
479		curlun->cdrom = cdrom;
480		ret = count;
481	}
482	up_read(filesem);
483
484	return ret;
485}
486EXPORT_SYMBOL_GPL(fsg_store_cdrom);
487
488ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
489			    size_t count)
490{
491	bool		removable;
492	int		ret;
493
494	ret = strtobool(buf, &removable);
495	if (ret)
496		return ret;
497
498	curlun->removable = removable;
499
500	return count;
501}
502EXPORT_SYMBOL_GPL(fsg_store_removable);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
504MODULE_LICENSE("GPL");
v4.17
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * storage_common.c -- Common definitions for mass storage functionality
  4 *
  5 * Copyright (C) 2003-2008 Alan Stern
  6 * Copyeight (C) 2009 Samsung Electronics
  7 * Author: Michal Nazarewicz (mina86@mina86.com)
 
 
 
 
 
  8 */
  9
 10/*
 11 * This file requires the following identifiers used in USB strings to
 12 * be defined (each of type pointer to char):
 13 *  - fsg_string_interface    -- name of the interface
 14 */
 15
 16/*
 17 * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers
 18 * sets the number of pipeline buffers (length of the fsg_buffhd array).
 19 * The valid range of num_buffers is: num >= 2 && num <= 4.
 20 */
 21
 22#include <linux/module.h>
 23#include <linux/blkdev.h>
 24#include <linux/file.h>
 25#include <linux/fs.h>
 26#include <linux/usb/composite.h>
 27
 28#include "storage_common.h"
 29
 30/* There is only one interface. */
 31
 32struct usb_interface_descriptor fsg_intf_desc = {
 33	.bLength =		sizeof fsg_intf_desc,
 34	.bDescriptorType =	USB_DT_INTERFACE,
 35
 36	.bNumEndpoints =	2,		/* Adjusted during fsg_bind() */
 37	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
 38	.bInterfaceSubClass =	USB_SC_SCSI,	/* Adjusted during fsg_bind() */
 39	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */
 40	.iInterface =		FSG_STRING_INTERFACE,
 41};
 42EXPORT_SYMBOL_GPL(fsg_intf_desc);
 43
 44/*
 45 * Three full-speed endpoint descriptors: bulk-in, bulk-out, and
 46 * interrupt-in.
 47 */
 48
 49struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {
 50	.bLength =		USB_DT_ENDPOINT_SIZE,
 51	.bDescriptorType =	USB_DT_ENDPOINT,
 52
 53	.bEndpointAddress =	USB_DIR_IN,
 54	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 55	/* wMaxPacketSize set by autoconfiguration */
 56};
 57EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc);
 58
 59struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {
 60	.bLength =		USB_DT_ENDPOINT_SIZE,
 61	.bDescriptorType =	USB_DT_ENDPOINT,
 62
 63	.bEndpointAddress =	USB_DIR_OUT,
 64	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 65	/* wMaxPacketSize set by autoconfiguration */
 66};
 67EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc);
 68
 69struct usb_descriptor_header *fsg_fs_function[] = {
 70	(struct usb_descriptor_header *) &fsg_intf_desc,
 71	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
 72	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
 73	NULL,
 74};
 75EXPORT_SYMBOL_GPL(fsg_fs_function);
 76
 77
 78/*
 79 * USB 2.0 devices need to expose both high speed and full speed
 80 * descriptors, unless they only run at full speed.
 81 *
 82 * That means alternate endpoint descriptors (bigger packets).
 
 
 83 */
 84struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {
 85	.bLength =		USB_DT_ENDPOINT_SIZE,
 86	.bDescriptorType =	USB_DT_ENDPOINT,
 87
 88	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
 89	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 90	.wMaxPacketSize =	cpu_to_le16(512),
 91};
 92EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc);
 93
 94struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {
 95	.bLength =		USB_DT_ENDPOINT_SIZE,
 96	.bDescriptorType =	USB_DT_ENDPOINT,
 97
 98	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
 99	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
100	.wMaxPacketSize =	cpu_to_le16(512),
101	.bInterval =		1,	/* NAK every 1 uframe */
102};
103EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc);
104
105
106struct usb_descriptor_header *fsg_hs_function[] = {
107	(struct usb_descriptor_header *) &fsg_intf_desc,
108	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
109	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
110	NULL,
111};
112EXPORT_SYMBOL_GPL(fsg_hs_function);
113
114struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {
115	.bLength =		USB_DT_ENDPOINT_SIZE,
116	.bDescriptorType =	USB_DT_ENDPOINT,
117
118	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
119	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
120	.wMaxPacketSize =	cpu_to_le16(1024),
121};
122EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc);
123
124struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
125	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
126	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
127
128	/*.bMaxBurst =		DYNAMIC, */
129};
130EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc);
131
132struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = {
133	.bLength =		USB_DT_ENDPOINT_SIZE,
134	.bDescriptorType =	USB_DT_ENDPOINT,
135
136	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
137	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
138	.wMaxPacketSize =	cpu_to_le16(1024),
139};
140EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc);
141
142struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
143	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),
144	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
145
146	/*.bMaxBurst =		DYNAMIC, */
147};
148EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc);
149
150struct usb_descriptor_header *fsg_ss_function[] = {
151	(struct usb_descriptor_header *) &fsg_intf_desc,
152	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
153	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
154	(struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
155	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
156	NULL,
157};
158EXPORT_SYMBOL_GPL(fsg_ss_function);
159
160
161 /*-------------------------------------------------------------------------*/
162
163/*
164 * If the next two routines are called while the gadget is registered,
165 * the caller must own fsg->filesem for writing.
166 */
167
168void fsg_lun_close(struct fsg_lun *curlun)
169{
170	if (curlun->filp) {
171		LDBG(curlun, "close backing file\n");
172		fput(curlun->filp);
173		curlun->filp = NULL;
174	}
175}
176EXPORT_SYMBOL_GPL(fsg_lun_close);
177
178int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
179{
180	int				ro;
181	struct file			*filp = NULL;
182	int				rc = -EINVAL;
183	struct inode			*inode = NULL;
184	loff_t				size;
185	loff_t				num_sectors;
186	loff_t				min_sectors;
187	unsigned int			blkbits;
188	unsigned int			blksize;
189
190	/* R/W if we can, R/O if we must */
191	ro = curlun->initially_ro;
192	if (!ro) {
193		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
194		if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES)
195			ro = 1;
196	}
197	if (ro)
198		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
199	if (IS_ERR(filp)) {
200		LINFO(curlun, "unable to open backing file: %s\n", filename);
201		return PTR_ERR(filp);
202	}
203
204	if (!(filp->f_mode & FMODE_WRITE))
205		ro = 1;
206
207	inode = file_inode(filp);
208	if ((!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) {
209		LINFO(curlun, "invalid file type: %s\n", filename);
210		goto out;
211	}
212
213	/*
214	 * If we can't read the file, it's no good.
215	 * If we can't write the file, use it read-only.
216	 */
217	if (!(filp->f_mode & FMODE_CAN_READ)) {
218		LINFO(curlun, "file not readable: %s\n", filename);
219		goto out;
220	}
221	if (!(filp->f_mode & FMODE_CAN_WRITE))
222		ro = 1;
223
224	size = i_size_read(inode->i_mapping->host);
225	if (size < 0) {
226		LINFO(curlun, "unable to find file size: %s\n", filename);
227		rc = (int) size;
228		goto out;
229	}
230
231	if (curlun->cdrom) {
232		blksize = 2048;
233		blkbits = 11;
234	} else if (inode->i_bdev) {
235		blksize = bdev_logical_block_size(inode->i_bdev);
236		blkbits = blksize_bits(blksize);
237	} else {
238		blksize = 512;
239		blkbits = 9;
240	}
241
242	num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
243	min_sectors = 1;
244	if (curlun->cdrom) {
245		min_sectors = 300;	/* Smallest track is 300 frames */
246		if (num_sectors >= 256*60*75) {
247			num_sectors = 256*60*75 - 1;
248			LINFO(curlun, "file too big: %s\n", filename);
249			LINFO(curlun, "using only first %d blocks\n",
250					(int) num_sectors);
251		}
252	}
253	if (num_sectors < min_sectors) {
254		LINFO(curlun, "file too small: %s\n", filename);
255		rc = -ETOOSMALL;
256		goto out;
257	}
258
259	if (fsg_lun_is_open(curlun))
260		fsg_lun_close(curlun);
261
262	curlun->blksize = blksize;
263	curlun->blkbits = blkbits;
264	curlun->ro = ro;
265	curlun->filp = filp;
266	curlun->file_length = size;
267	curlun->num_sectors = num_sectors;
268	LDBG(curlun, "open backing file: %s\n", filename);
269	return 0;
270
271out:
272	fput(filp);
273	return rc;
274}
275EXPORT_SYMBOL_GPL(fsg_lun_open);
276
277
278/*-------------------------------------------------------------------------*/
279
280/*
281 * Sync the file data, don't bother with the metadata.
282 * This code was copied from fs/buffer.c:sys_fdatasync().
283 */
284int fsg_lun_fsync_sub(struct fsg_lun *curlun)
285{
286	struct file	*filp = curlun->filp;
287
288	if (curlun->ro || !filp)
289		return 0;
290	return vfs_fsync(filp, 1);
291}
292EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub);
293
294void store_cdrom_address(u8 *dest, int msf, u32 addr)
295{
296	if (msf) {
297		/* Convert to Minutes-Seconds-Frames */
298		addr >>= 2;		/* Convert to 2048-byte frames */
299		addr += 2*75;		/* Lead-in occupies 2 seconds */
300		dest[3] = addr % 75;	/* Frames */
301		addr /= 75;
302		dest[2] = addr % 60;	/* Seconds */
303		addr /= 60;
304		dest[1] = addr;		/* Minutes */
305		dest[0] = 0;		/* Reserved */
306	} else {
307		/* Absolute sector */
308		put_unaligned_be32(addr, dest);
309	}
310}
311EXPORT_SYMBOL_GPL(store_cdrom_address);
312
313/*-------------------------------------------------------------------------*/
314
315
316ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)
317{
318	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
319				  ? curlun->ro
320				  : curlun->initially_ro);
321}
322EXPORT_SYMBOL_GPL(fsg_show_ro);
323
324ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)
325{
326	return sprintf(buf, "%u\n", curlun->nofua);
327}
328EXPORT_SYMBOL_GPL(fsg_show_nofua);
329
330ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
331		      char *buf)
332{
333	char		*p;
334	ssize_t		rc;
335
336	down_read(filesem);
337	if (fsg_lun_is_open(curlun)) {	/* Get the complete pathname */
338		p = file_path(curlun->filp, buf, PAGE_SIZE - 1);
339		if (IS_ERR(p))
340			rc = PTR_ERR(p);
341		else {
342			rc = strlen(p);
343			memmove(buf, p, rc);
344			buf[rc] = '\n';		/* Add a newline */
345			buf[++rc] = 0;
346		}
347	} else {				/* No file, return 0 bytes */
348		*buf = 0;
349		rc = 0;
350	}
351	up_read(filesem);
352	return rc;
353}
354EXPORT_SYMBOL_GPL(fsg_show_file);
355
356ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf)
357{
358	return sprintf(buf, "%u\n", curlun->cdrom);
359}
360EXPORT_SYMBOL_GPL(fsg_show_cdrom);
361
362ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf)
363{
364	return sprintf(buf, "%u\n", curlun->removable);
365}
366EXPORT_SYMBOL_GPL(fsg_show_removable);
367
368ssize_t fsg_show_inquiry_string(struct fsg_lun *curlun, char *buf)
369{
370	return sprintf(buf, "%s\n", curlun->inquiry_string);
371}
372EXPORT_SYMBOL_GPL(fsg_show_inquiry_string);
373
374/*
375 * The caller must hold fsg->filesem for reading when calling this function.
376 */
377static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro)
378{
379	if (fsg_lun_is_open(curlun)) {
380		LDBG(curlun, "read-only status change prevented\n");
381		return -EBUSY;
382	}
383
384	curlun->ro = ro;
385	curlun->initially_ro = ro;
386	LDBG(curlun, "read-only status set to %d\n", curlun->ro);
387
388	return 0;
389}
390
391ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem,
392		     const char *buf, size_t count)
393{
394	ssize_t		rc;
395	bool		ro;
396
397	rc = strtobool(buf, &ro);
398	if (rc)
399		return rc;
400
401	/*
402	 * Allow the write-enable status to change only while the
403	 * backing file is closed.
404	 */
405	down_read(filesem);
406	rc = _fsg_store_ro(curlun, ro);
407	if (!rc)
408		rc = count;
409	up_read(filesem);
410
411	return rc;
412}
413EXPORT_SYMBOL_GPL(fsg_store_ro);
414
415ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)
416{
417	bool		nofua;
418	int		ret;
419
420	ret = strtobool(buf, &nofua);
421	if (ret)
422		return ret;
423
424	/* Sync data when switching from async mode to sync */
425	if (!nofua && curlun->nofua)
426		fsg_lun_fsync_sub(curlun);
427
428	curlun->nofua = nofua;
429
430	return count;
431}
432EXPORT_SYMBOL_GPL(fsg_store_nofua);
433
434ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem,
435		       const char *buf, size_t count)
436{
437	int		rc = 0;
438
439	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
440		LDBG(curlun, "eject attempt prevented\n");
441		return -EBUSY;				/* "Door is locked" */
442	}
443
444	/* Remove a trailing newline */
445	if (count > 0 && buf[count-1] == '\n')
446		((char *) buf)[count-1] = 0;		/* Ugh! */
447
448	/* Load new medium */
449	down_write(filesem);
450	if (count > 0 && buf[0]) {
451		/* fsg_lun_open() will close existing file if any. */
452		rc = fsg_lun_open(curlun, buf);
453		if (rc == 0)
454			curlun->unit_attention_data =
455					SS_NOT_READY_TO_READY_TRANSITION;
456	} else if (fsg_lun_is_open(curlun)) {
457		fsg_lun_close(curlun);
458		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
459	}
460	up_write(filesem);
461	return (rc < 0 ? rc : count);
462}
463EXPORT_SYMBOL_GPL(fsg_store_file);
464
465ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem,
466			const char *buf, size_t count)
467{
468	bool		cdrom;
469	int		ret;
470
471	ret = strtobool(buf, &cdrom);
472	if (ret)
473		return ret;
474
475	down_read(filesem);
476	ret = cdrom ? _fsg_store_ro(curlun, true) : 0;
477
478	if (!ret) {
479		curlun->cdrom = cdrom;
480		ret = count;
481	}
482	up_read(filesem);
483
484	return ret;
485}
486EXPORT_SYMBOL_GPL(fsg_store_cdrom);
487
488ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf,
489			    size_t count)
490{
491	bool		removable;
492	int		ret;
493
494	ret = strtobool(buf, &removable);
495	if (ret)
496		return ret;
497
498	curlun->removable = removable;
499
500	return count;
501}
502EXPORT_SYMBOL_GPL(fsg_store_removable);
503
504ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf,
505				 size_t count)
506{
507	const size_t len = min(count, sizeof(curlun->inquiry_string));
508
509	if (len == 0 || buf[0] == '\n') {
510		curlun->inquiry_string[0] = 0;
511	} else {
512		snprintf(curlun->inquiry_string,
513			 sizeof(curlun->inquiry_string), "%-28s", buf);
514		if (curlun->inquiry_string[len-1] == '\n')
515			curlun->inquiry_string[len-1] = ' ';
516	}
517
518	return count;
519}
520EXPORT_SYMBOL_GPL(fsg_store_inquiry_string);
521
522MODULE_LICENSE("GPL");