11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file_storage.c -- File-backed USB Storage Gadget, for USB development 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * Copyright (C) 2003-2008 Alan Stern 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All rights reserved. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Redistribution and use in source and binary forms, with or without 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modification, are permitted provided that the following conditions 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are met: 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1. Redistributions of source code must retain the above copyright 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * notice, this list of conditions, and the following disclaimer, 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without modification. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * notice, this list of conditions and the following disclaimer in the 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * documentation and/or other materials provided with the distribution. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3. The names of the above-listed copyright holders may not be used 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to endorse or promote products derived from this software without 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specific prior written permission. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ALTERNATIVELY, this software may be distributed under the terms of the 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License ("GPL") as published by the Free Software 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, either version 2 of that License or (at your option) any 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * later version. 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The File-backed Storage Gadget acts as a USB Mass Storage device, 4112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * appearing to the host as a disk drive or as a CD-ROM drive. In addition 4212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * to providing an example of a genuinely useful gadget driver for a USB 4312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * device, it also illustrates a technique of double-buffering for increased 4412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * throughput. Last but not least, it gives an easy way to probe the 4512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * behavior of the Mass Storage drivers in a USB host. 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Backing storage is provided by a regular file or a block device, specified 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the "file" module parameter. Access can be limited to read-only by 4912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * setting the optional "ro" module parameter. (For CD-ROM emulation, 5012aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * access is always read-only.) The gadget will indicate that it has 5112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * removable media if the optional "removable" module parameter is set. 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the optional "transport" module parameter. It also supports the 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the optional "protocol" module parameter. In addition, the default 5987eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin * Vendor ID, Product ID, release number and serial number can be overridden. 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is support for multiple logical units (LUNs), each of which has 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its own backing file. The number of LUNs can be set using the optional 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "luns" module parameter (anywhere from 1 to 8), and the corresponding 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * files are specified using comma-separated lists for "file" and "ro". 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The default number of LUNs is taken from the number of "file" elements; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is 1 if "file" is not given. If "removable" is not set then a backing 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file must be specified for each LUN. If it is set, then an unspecified 6812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * or empty backing filename means the LUN's medium is not loaded. Ideally 6912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * each LUN would be settable independently as a disk drive or a CD-ROM 7012aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * drive, but currently all LUNs have to be the same type. The CD-ROM 7112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * emulation includes a single data track and no audio tracks; hence there 723f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li * need be only one backing file per LUN. 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Requirements are modest; only a bulk-in and a bulk-out endpoint are 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * needed (an interrupt-out endpoint is also needed for CBI). The memory 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requirement amounts to two 16K buffers, size configurable by a parameter. 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Support is included for both full-speed and high-speed operation. 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7914cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * Note that the driver is slightly non-portable in that it assumes a 8014cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * single memory/DMA buffer will be useable for bulk-in, bulk-out, and 8114cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * interrupt-in endpoints. With most device controllers this isn't an 8214cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * issue, but there may be some with hardware restrictions that prevent 8314cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * a buffer from being used by more than one endpoint. 8414cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Module options: 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file=filename[,filename...] 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Required if "removable" is not set, names of 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the files or block devices used for 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * backing storage 91d8087427ccefc0b3364735b96274375246fd452cAlan Stern * serial=HHHH... Required serial number (string of hex chars) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ro=b[,b...] Default false, booleans for read-only access 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * removable Default false, boolean for removable media 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * luns=N Default N = number of filenames, number of 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LUNs to support 96a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko * nofua=b[,b...] Default false, booleans for ignore FUA flag 97a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko * in SCSI WRITE(10,12) commands 98d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * stall Default determined according to the type of 99d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * USB device controller (usually true), 100d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * boolean to permit the driver to halt 101d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * bulk endpoints 10212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * cdrom Default false, boolean for whether to emulate 10312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * a CD-ROM drive 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transport=XXX Default BBB, transport name (CB, CBI, or BBB) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * protocol=YYY Default SCSI, protocol name (RBC, 8020 or 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ATAPI, QIC, UFI, 8070, or SCSI; 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * also 1 - 6) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * release=0xRRRR Override the USB release number (bcdDevice) 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buflen=N Default N=16384, buffer size used (will be 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rounded down to a multiple of 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PAGE_CACHE_SIZE) 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 115d8087427ccefc0b3364735b96274375246fd452cAlan Stern * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro", 116a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko * "removable", "luns", "nofua", "stall", and "cdrom" options are available; 117a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko * default values are used for everything else. 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The pathnames of the backing files and the ro settings are available in 120a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of 121a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko * the gadget's sysfs directory. If the "removable" option is set, writing to 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these files will simulate ejecting/loading the medium (writing an empty 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * line means eject) and adjusting a write-enable tab. Changes to the ro 12412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * setting are not allowed when the medium is loaded or if CD-ROM emulation 12512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern * is being used. 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This gadget driver is heavily based on "Gadget Zero" by David Brownell. 128aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * The driver's SCSI command interface was based on the "Information 129aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * technology - Small Computer System Interface - 2" document from 130aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at 131aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception 132aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the 133aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * "Universal Serial Bus Mass Storage Class UFI Command Specification" 134aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * document, Revision 1.0, December 14, 1998, available at 135aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver Design 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The FSG driver is fairly straightforward. There is a main kernel 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread that handles most of the work. Interrupt routines field 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * callbacks from the controller driver: bulk- and interrupt-request 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * completion notifications, endpoint-0 events, and disconnect events. 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Completion events are passed to the main thread by wakeup calls. Many 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ep0 requests are handled at interrupt time, but SetInterface, 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SetConfiguration, and device reset requests are forwarded to the 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread in the form of "exceptions" using SIGUSR1 signals (since they 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * should interrupt any ongoing file I/O operations). 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The thread's main routine implements the standard command/data/status 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parts of a SCSI interaction. It and its subroutines are full of tests 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for pending signals/exceptions -- all this polling is necessary since 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the kernel has no setjmp/longjmp equivalents. (Maybe this is an 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * indication that the driver really wants to be running in userspace.) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * An important point is that so long as the thread is alive it keeps an 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * open reference to the backing file. This will prevent unmounting 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the backing file's underlying filesystem and could cause problems 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * during system shutdown, for example. To prevent such problems, the 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread catches INT, TERM, and KILL signals and converts them into 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an EXIT exception. 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In normal operation the main thread is started during the gadget's 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fsg_bind() callback and stopped during fsg_unbind(). But it can also 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exit when it receives a signal, and there's no point leaving the 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gadget running when the thread is dead. So just before the thread 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exits, it deregisters the gadget driver. This makes things a little 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tricky: The driver is deregistered at two places, and the exiting 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread can indirectly call fsg_unbind() which in turn can tell the 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread to exit. The first problem is resolved through the use of the 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * REGISTERED atomic bitflag; the driver will only be deregistered once. 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The second problem is resolved by having fsg_unbind() check 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fsg->state; it won't try to stop the thread if the state is already 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FSG_STATE_TERMINATED. 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To provide maximum throughput, the driver uses a circular pipeline of 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer heads (struct fsg_buffhd). In principle the pipeline can be 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arbitrarily long; in practice the benefits don't justify having more 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than 2 stages (i.e., double buffering). But it helps to think of the 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pipeline as being a long one. Each buffer head contains a bulk-in and 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a bulk-out request pointer (since the buffer can be used for both 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * output and input -- directions always are given from the host's 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * point of view) as well as a pointer to the buffer and various state 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * variables. 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use of the pipeline follows a simple protocol. There is a variable 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * At any time that buffer head may still be in use from an earlier 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request, so each buffer head has a state variable indicating whether 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer head to be EMPTY, filling the buffer either by file I/O or by 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB I/O (during which the buffer head is BUSY), and marking the buffer 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * head FULL when the I/O is complete. Then the buffer will be emptied 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (again possibly by USB I/O, during which it is marked BUSY) and 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * finally marked EMPTY again (possibly by a completion routine). 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A module parameter tells the driver to avoid stalling the bulk 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * endpoints wherever the transport specification allows. This is 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * necessary for some UDCs like the SuperH, which cannot reliably clear a 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * halt on a bulk endpoint. However, under certain circumstances the 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bulk-only specification requires a stall. In such cases the driver 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will halt the endpoint and set a flag indicating that it should clear 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the halt in software during the next device reset. Hopefully this 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will permit everything to work correctly. Furthermore, although the 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specification allows the bulk-out endpoint to halt when the host sends 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * too much data, implementing this would cause an unavoidable race. 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The driver will always use the "no-stall" approach for OUT transfers. 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * One subtle point concerns sending status-stage responses for ep0 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requests. Some of these requests, such as device reset, can involve 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupting an ongoing file I/O operation, which might take an 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arbitrarily long time. During that delay the host might give up on 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the original ep0 request and issue a new one. When that happens the 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver should not notify the host about completion of the original 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request, as the host will no longer be waiting for it. So the driver 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assigns to each ep0 request a unique tag, and it keeps track of the 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tag value of the request associated with a long-running exception 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (device-reset, interface-change, or configuration-change). When the 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exception handler is finished, the status-stage response is submitted 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only if the current ep0 request tag is equal to the exception request 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tag. Thus only the most recently received ep0 request will get a 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * status-stage response. 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Warning: This driver source file is too long. It ought to be split up 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into a header file plus about 3 separate .c files, to handle the details 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the Gadget, USB Mass Storage, and SCSI protocols. 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2312e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell/* #define VERBOSE_DEBUG */ 23279a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern/* #define DUMP_MSGS */ 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/completion.h> 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dcache.h> 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h> 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/file.h> 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 24387c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern#include <linux/kref.h> 24422efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern#include <linux/kthread.h> 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/limits.h> 2466eb0de827084060e6607c8f8542d9e9566214538Paul Gortmaker#include <linux/module.h> 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rwsem.h> 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 2517dfb71030f7636a0d65200158113c37764552f93Nigel Cunningham#include <linux/freezer.h> 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/utsname.h> 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2545f848137744106ee737f559454ce5adfceb38347David Brownell#include <linux/usb/ch9.h> 2559454a57ab5922e5cd25321cae9d1a8cbeb3e2e85David Brownell#include <linux/usb/gadget.h> 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "gadget_chips.h" 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 260352e2b961c885b98065c402e2ad85057d0a334b2David Brownell 261352e2b961c885b98065c402e2ad85057d0a334b2David Brownell/* 262352e2b961c885b98065c402e2ad85057d0a334b2David Brownell * Kbuild is not very cooperative with respect to linking separately 263352e2b961c885b98065c402e2ad85057d0a334b2David Brownell * compiled library objects into one module. So for now we won't use 264352e2b961c885b98065c402e2ad85057d0a334b2David Brownell * separate compilation ... ensuring init/exit sections work to shrink 265352e2b961c885b98065c402e2ad85057d0a334b2David Brownell * the runtime footprint, and giving us at least some parts of what 266352e2b961c885b98065c402e2ad85057d0a334b2David Brownell * a "gcc --combine ... part1.c part2.c part3.c ... " build would. 267352e2b961c885b98065c402e2ad85057d0a334b2David Brownell */ 268352e2b961c885b98065c402e2ad85057d0a334b2David Brownell#include "usbstring.c" 269352e2b961c885b98065c402e2ad85057d0a334b2David Brownell#include "config.c" 270352e2b961c885b98065c402e2ad85057d0a334b2David Brownell#include "epautoconf.c" 271352e2b961c885b98065c402e2ad85057d0a334b2David Brownell 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "File-backed Storage Gadget" 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "g_file_storage" 276d8087427ccefc0b3364735b96274375246fd452cAlan Stern#define DRIVER_VERSION "1 September 2010" 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 278d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewiczstatic char fsg_string_manufacturer[64]; 279d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewiczstatic const char fsg_string_product[] = DRIVER_DESC; 280d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewiczstatic const char fsg_string_config[] = "Self-powered"; 281d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewiczstatic const char fsg_string_interface[] = "Mass Storage"; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28393f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz 28493f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz#include "storage_common.c" 28593f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz 28693f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Alan Stern"); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("Dual BSD/GPL"); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver assumes self-powered hardware and has no way for users to 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * trigger remote wakeup. It uses autoconfiguration to select endpoints 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and endpoint addresses. 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Encapsulate the module parameter settings */ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct { 304d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz char *file[FSG_MAX_LUNS]; 305d8087427ccefc0b3364735b96274375246fd452cAlan Stern char *serial; 30690ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russell bool ro[FSG_MAX_LUNS]; 30790ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russell bool nofua[FSG_MAX_LUNS]; 3082e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell unsigned int num_filenames; 3092e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell unsigned int num_ros; 310a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko unsigned int num_nofuas; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nluns; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31390ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russell bool removable; 31490ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russell bool can_stall; 31590ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russell bool cdrom; 316d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *transport_parm; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *protocol_parm; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short vendor; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short product; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short release; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int buflen; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int transport_type; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *transport_name; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int protocol_type; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *protocol_name; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} mod_data = { // Default values 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .transport_parm = "BBB", 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .protocol_parm = "SCSI", 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .removable = 0, 333d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern .can_stall = 1, 33412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern .cdrom = 0, 335d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .vendor = FSG_VENDOR_ID, 336d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .product = FSG_PRODUCT_ID, 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = 0xffff, // Use controller chip type 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .buflen = 16384, 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 342aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Sternmodule_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, 343aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern S_IRUGO); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(file, "names of backing files or devices"); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 346d8087427ccefc0b3364735b96274375246fd452cAlan Sternmodule_param_named(serial, mod_data.serial, charp, S_IRUGO); 347d8087427ccefc0b3364735b96274375246fd452cAlan SternMODULE_PARM_DESC(serial, "USB serial number"); 348d8087427ccefc0b3364735b96274375246fd452cAlan Stern 349aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Sternmodule_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(ro, "true to force read-only"); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 352a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenkomodule_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, 353a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko S_IRUGO); 354a93917d39fc388c4761d2530af82513e2d3bf9f6Andy ShevchenkoMODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); 355a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(luns, mod_data.nluns, uint, S_IRUGO); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(luns, "number of LUNs"); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(removable, mod_data.removable, bool, S_IRUGO); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(removable, "true to simulate removable media"); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 362d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Sternmodule_param_named(stall, mod_data.can_stall, bool, S_IRUGO); 363d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan SternMODULE_PARM_DESC(stall, "false to prevent bulk stalls"); 364d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern 36512aae68a203e97a58d3f8237fc389201a4d9282dAlan Sternmodule_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); 36612aae68a203e97a58d3f8237fc389201a4d9282dAlan SternMODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); 36712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* In the non-TEST version, only the module parameters listed above 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are available. */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "8070, or SCSI)"); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(vendor, "USB Vendor ID"); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(product, mod_data.product, ushort, S_IRUGO); 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(product, "USB Product ID"); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(release, mod_data.release, ushort, S_IRUGO); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(release, "USB release number"); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(buflen, mod_data.buflen, uint, S_IRUGO); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(buflen, "I/O buffer size"); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These definitions will permit the compiler to avoid generating code for 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parts of the driver that aren't used in the non-TEST version. Even gcc 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can recognize when a test of a constant expression yields a dead code 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * path. 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_bbb() 1 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_cbi() 0 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define protocol_is_scsi() 1 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 416b6058d0fefc0b5ff777dfbff990a0a50a4ac144bMichal Nazarewicz/*-------------------------------------------------------------------------*/ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct fsg_dev { 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget *gadget; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* filesem protects: backing files in use */ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rw_semaphore filesem; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42787c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern /* reference counting: wait until all LUNs are released */ 42887c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern struct kref ref; 42987c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *ep0; // Handy copy of gadget->ep0 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *ep0req; // For control responses 432a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern unsigned int ep0_req_tag; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *ep0req_name; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *intreq; // For interrupt responses 436a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern int intreq_busy; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *intr_buffhd; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 439d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz unsigned int bulk_out_maxpacket; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum fsg_state state; // For exception handling 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int exception_req_tag; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 config, new_config; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int running : 1; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bulk_in_enabled : 1; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bulk_out_enabled : 1; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int intr_in_enabled : 1; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int phase_error : 1; 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int short_packet_received : 1; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bad_lun_okay : 1; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long atomic_bitflags; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REGISTERED 0 455b950bdbc67041412cb042e404938667204c7902cAlan Stern#define IGNORE_BULK_OUT 1 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SUSPENDED 2 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *bulk_in; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *bulk_out; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *intr_in; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *next_buffhd_to_fill; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *next_buffhd_to_drain; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int thread_wakeup_needed; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct completion thread_notifier; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct task_struct *thread_task; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmnd_size; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 cmnd[MAX_COMMAND_SIZE]; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum data_direction data_dir; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 data_size; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 data_size_from_cmnd; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tag; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int lun; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 residue; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 usb_amount_left; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The CB protocol offers no way for a host to know when a command 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has completed. As a result the next command may arrive early, 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and we will still have to handle it. For that reason we need 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a buffer to store new commands when using CB (or CBI, which 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not oblige a host to wait for command completion either). */ 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cbbuf_cmnd_size; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nluns; 488d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *luns; 489d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun; 4906532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin /* Must be the last entry */ 4916532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin struct fsg_buffhd buffhds[]; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef void (*fsg_routine_t)(struct fsg_dev *); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49679a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Sternstatic int exception_in_progress(struct fsg_dev *fsg) 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (fsg->state > FSG_STATE_IDLE); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50198346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman/* Make bulk-out requests be divisible by the maxpacket size */ 50298346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartmanstatic void set_bulk_out_req_length(struct fsg_dev *fsg, 50398346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman struct fsg_buffhd *bh, unsigned int length) 50498346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman{ 50598346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman unsigned int rem; 50698346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman 50798346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman bh->bulk_out_intended_length = length; 50898346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman rem = length % fsg->bulk_out_maxpacket; 50998346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman if (rem > 0) 51098346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman length += fsg->bulk_out_maxpacket - rem; 51198346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman bh->outreq->length = length; 51298346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman} 51398346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fsg_dev *the_fsg; 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_gadget_driver fsg_driver; 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *name; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == fsg->bulk_in) 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "bulk-in"; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep == fsg->bulk_out) 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "bulk-out"; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = ep->name; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "%s set halt\n", name); 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return usb_ep_set_halt(ep); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DESCRIPTORS ... most are static, but strings and (full) configuration 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * descriptors are built on demand. Also the (static) config and interface 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * descriptors are adjusted during fsg_bind(). 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* There is only one configuration. */ 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG_VALUE 1 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_descriptor 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_desc = { 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof device_desc, 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_DEVICE, 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551551509d267905705f6d723e51ec706916f06b859Harvey Harrison .bcdUSB = cpu_to_le16(0x0200), 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDeviceClass = USB_CLASS_PER_INTERFACE, 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The next three values can be overridden by module parameters */ 555d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .idVendor = cpu_to_le16(FSG_VENDOR_ID), 556d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .idProduct = cpu_to_le16(FSG_PRODUCT_ID), 557551509d267905705f6d723e51ec706916f06b859Harvey Harrison .bcdDevice = cpu_to_le16(0xffff), 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 559d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .iManufacturer = FSG_STRING_MANUFACTURER, 560d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .iProduct = FSG_STRING_PRODUCT, 561d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .iSerialNumber = FSG_STRING_SERIAL, 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bNumConfigurations = 1, 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_config_descriptor 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsconfig_desc = { 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof config_desc, 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_CONFIG, 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wTotalLength computed by usb_gadget_config_buf() */ 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bNumInterfaces = 1, 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bConfigurationValue = CONFIG_VALUE, 573d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .iConfiguration = FSG_STRING_CONFIG, 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 57536e893d25aa2abcae0f11ef263de0e8322641386David Brownell .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_qualifier_descriptor 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdev_qualifier = { 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof dev_qualifier, 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_DEVICE_QUALIFIER, 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 584551509d267905705f6d723e51ec706916f06b859Harvey Harrison .bcdUSB = cpu_to_le16(0x0200), 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDeviceClass = USB_CLASS_PER_INTERFACE, 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bNumConfigurations = 1, 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5904bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbistatic int populate_bos(struct fsg_dev *fsg, u8 *buf) 5914bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi{ 5924bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE); 5934bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi buf += USB_DT_BOS_SIZE; 5944bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 5954bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE); 5964bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi buf += USB_DT_USB_EXT_CAP_SIZE; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5984bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE); 5994bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 6004bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE 6014bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi + USB_DT_USB_EXT_CAP_SIZE; 6024bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi} 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Config descriptors must agree with the code that sets configurations 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and with code managing interfaces and their altsettings. They must 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * also handle different speeds and other-speed requests. 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int populate_config_buf(struct usb_gadget *gadget, 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf, u8 type, unsigned index) 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum usb_device_speed speed = gadget->speed; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_descriptor_header **function; 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (index > 0) 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6192e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; 621d23b0f08d18fc42f26f6a0776c6d827eb35143a9Michal Nazarewicz function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH 622d23b0f08d18fc42f26f6a0776c6d827eb35143a9Michal Nazarewicz ? (const struct usb_descriptor_header **)fsg_hs_function 623d23b0f08d18fc42f26f6a0776c6d827eb35143a9Michal Nazarewicz : (const struct usb_descriptor_header **)fsg_fs_function; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* for now, don't advertise srp-only devices */ 6262e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell if (!gadget_is_otg(gadget)) 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function++; 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((struct usb_config_descriptor *) buf)->bDescriptorType = type; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These routines may be called in process context or in_irq */ 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 639a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern/* Caller must hold fsg->lock */ 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void wakeup_thread(struct fsg_dev *fsg) 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tell the main thread that something has happened */ 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->thread_wakeup_needed = 1; 644a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern if (fsg->thread_task) 645a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern wake_up_process(fsg->thread_task); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Do nothing if a higher-priority exception is already in progress. 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a lower-or-equal priority exception is in progress, preempt it 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and notify the main thread by sending it a signal. */ 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&fsg->lock, flags); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->state <= new_state) { 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->exception_req_tag = fsg->ep0_req_tag; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = new_state; 66022efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern if (fsg->thread_task) 66122efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern send_sig_info(SIGUSR1, SEND_SIG_FORCED, 66222efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern fsg->thread_task); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&fsg->lock, flags); 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The disconnect callback and ep0 routines. These always run in_irq, 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * except that ep0_queue() is called in the main thread to acknowledge 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * completion of various requests: set config, set interface, and 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bulk-only device reset. */ 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsg_disconnect(struct usb_gadget *gadget) 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "disconnect or port reset\n"); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_DISCONNECT); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ep0_queue(struct fsg_dev *fsg) 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0 && rc != -ESHUTDOWN) { 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't do much more than wait for a reset */ 692b6c63937001889af6fe431aaba97e59d04e028e7Arjan van de Ven WARNING(fsg, "error in submission: %s --> %d\n", 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0->name, rc); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ep0_complete(struct usb_ep *ep, struct usb_request *req) 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7007ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_dev *fsg = ep->driver_data; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->actual > 0) 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->actual != req->length) 705441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison DBG(fsg, "%s --> %d, %u/%u\n", __func__, 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->status, req->actual, req->length); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == 0 && req->context) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((fsg_routine_t) (req->context))(fsg); 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bulk and interrupt endpoint completion handlers. 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These always run in_irq. */ 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7227ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_dev *fsg = ep->driver_data; 7237ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_buffhd *bh = req->context; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->actual != req->length) 726441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison DBG(fsg, "%s --> %d, %u/%u\n", __func__, 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->status, req->actual, req->length); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hold the lock while we update the request and buffer states */ 732a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern smp_wmb(); 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq_busy = 0; 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 737a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern spin_unlock(&fsg->lock); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7427ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_dev *fsg = ep->driver_data; 7437ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_buffhd *bh = req->context; 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "bulk-out", req->buf, req->actual); 74698346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman if (req->status || req->actual != bh->bulk_out_intended_length) 747441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison DBG(fsg, "%s --> %d, %u/%u\n", __func__, 74898346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman req->status, req->actual, 74998346f7db014614a4814eb60639f651f8bbc591dGreg Kroah-Hartman bh->bulk_out_intended_length); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hold the lock while we update the request and buffer states */ 754a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern smp_wmb(); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq_busy = 0; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 759a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern spin_unlock(&fsg->lock); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void intr_in_complete(struct usb_ep *ep, struct usb_request *req) 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7667ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_dev *fsg = ep->driver_data; 7677ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_buffhd *bh = req->context; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->actual != req->length) 770441b62c1edb986827154768d89bbac0ba779984fHarvey Harrison DBG(fsg, "%s --> %d, %u/%u\n", __func__, 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->status, req->actual, req->length); 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hold the lock while we update the request and buffer states */ 776a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern smp_wmb(); 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq_busy = 0; 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 781a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern spin_unlock(&fsg->lock); 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void intr_in_complete(struct usb_ep *ep, struct usb_request *req) 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{} 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ep0 class-specific handlers. These always run in_irq. */ 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static u8 cbi_reset_cmnd[6] = { 7990a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Error in command transfer? */ 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->length != req->actual || 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not all controllers allow a protocol stall after 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * receiving control-out data, but we'll try anyway. */ 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->ep0); 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; // Wait for reset 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is it the special reset command? */ 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->actual >= sizeof cbi_reset_cmnd && 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcmp(req->buf, cbi_reset_cmnd, 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof cbi_reset_cmnd) == 0) { 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to stop the current operation 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and reinitialize our state. */ 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "cbi reset request\n"); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_RESET); 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "CB[I] accept device-specific command\n"); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Save the command for later */ 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cbbuf_cmnd_size) 828b6c63937001889af6fe431aaba97e59d04e028e7Arjan van de Ven WARNING(fsg, "CB[I] overwriting previous command\n"); 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cbbuf_cmnd_size = req->actual; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 833a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern spin_unlock(&fsg->lock); 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{} 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int class_setup_req(struct fsg_dev *fsg, 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_ctrlrequest *ctrl) 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = -EOPNOTSUPP; 8471bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_index = le16_to_cpu(ctrl->wIndex); 84888e45dbbababd29cd6c80a3e0b60a828676b3ba9Luis Lloret u16 w_value = le16_to_cpu(ctrl->wValue); 8491bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_length = le16_to_cpu(ctrl->wLength); 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->config) 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return value; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle Bulk-only class-specific requests */ 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ctrl->bRequest) { 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 858775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior case US_BULK_RESET_REQUEST: 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT | 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_TYPE_CLASS | USB_RECIP_INTERFACE)) 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 862ce7b6121851c72d661134d113a78161095e0ae73Paul Zimmerman if (w_index != 0 || w_value != 0 || w_length != 0) { 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to stop the current operation 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and reinitialize our state. */ 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "bulk reset request\n"); 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_RESET); 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = DELAYED_STATUS; 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 874775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior case US_BULK_GET_MAX_LUN: 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_TYPE_CLASS | USB_RECIP_INTERFACE)) 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 878db332bc9b26bbd79a37241721cccc9919489d5a9Paul Zimmerman if (w_index != 0 || w_value != 0 || w_length != 1) { 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get max LUN\n"); 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(u8 *) req->buf = fsg->nluns - 1; 88476f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = 1; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle CBI class-specific requests */ 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ctrl->bRequest) { 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_CBI_ADSC_REQUEST: 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT | 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_TYPE_CLASS | USB_RECIP_INTERFACE)) 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 89788e45dbbababd29cd6c80a3e0b60a828676b3ba9Luis Lloret if (w_index != 0 || w_value != 0) { 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_length > MAX_COMMAND_SIZE) { 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOVERFLOW; 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = w_length; 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->context = received_cbi_adsc; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == -EOPNOTSUPP) 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "unknown class-specific control req " 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%02x.%02x v%04x i%04x l%u\n", 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl->bRequestType, ctrl->bRequest, 9161bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell le16_to_cpu(ctrl->wValue), w_index, w_length); 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return value; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ep0 standard request handlers. These always run in_irq. */ 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int standard_setup_req(struct fsg_dev *fsg, 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_ctrlrequest *ctrl) 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = -EOPNOTSUPP; 9301bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_index = le16_to_cpu(ctrl->wIndex); 9311bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_value = le16_to_cpu(ctrl->wValue); 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Usually this just stores reply data in the pre-allocated ep0 buffer, 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but config change events will also reconfigure hardware. */ 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ctrl->bRequest) { 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_DESCRIPTOR: 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_DEVICE)) 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (w_value >> 8) { 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_DEVICE: 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get device descriptor\n"); 945765f5b830e547229bb752e7b232ee83e2b3d49d5Sebastian Andrzej Siewior device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; 94676f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = sizeof device_desc; 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(req->buf, &device_desc, value); 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_DEVICE_QUALIFIER: 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get device qualifier\n"); 9514bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi if (!gadget_is_dualspeed(fsg->gadget) || 9524bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg->gadget->speed == USB_SPEED_SUPER) 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 954765f5b830e547229bb752e7b232ee83e2b3d49d5Sebastian Andrzej Siewior /* 955765f5b830e547229bb752e7b232ee83e2b3d49d5Sebastian Andrzej Siewior * Assume ep0 uses the same maxpacket value for both 956765f5b830e547229bb752e7b232ee83e2b3d49d5Sebastian Andrzej Siewior * speeds 957765f5b830e547229bb752e7b232ee83e2b3d49d5Sebastian Andrzej Siewior */ 958765f5b830e547229bb752e7b232ee83e2b3d49d5Sebastian Andrzej Siewior dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; 95976f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = sizeof dev_qualifier; 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(req->buf, &dev_qualifier, value); 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_OTHER_SPEED_CONFIG: 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get other-speed config descriptor\n"); 9654bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi if (!gadget_is_dualspeed(fsg->gadget) || 9664bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg->gadget->speed == USB_SPEED_SUPER) 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto get_config; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_CONFIG: 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get configuration descriptor\n"); 9712e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownellget_config: 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = populate_config_buf(fsg->gadget, 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->buf, 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_value >> 8, 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_value & 0xff); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_STRING: 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get string descriptor\n"); 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wIndex == language code */ 982d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz value = usb_gadget_get_string(&fsg_stringtab, 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_value & 0xff, req->buf); 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9854bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 9864bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi case USB_DT_BOS: 9874bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi VDBG(fsg, "get bos descriptor\n"); 9884bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 9894bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi if (gadget_is_superspeed(fsg->gadget)) 9904bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi value = populate_bos(fsg, req->buf); 9914bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi break; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9934bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* One config, two speeds */ 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_CONFIGURATION: 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_DEVICE)) 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "set configuration\n"); 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_value == CONFIG_VALUE || w_value == 0) { 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->new_config = w_value; 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to wipe out previous transaction 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state (queued bufs, etc) and set the new config. */ 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = DELAYED_STATUS; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_CONFIGURATION: 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_DEVICE)) 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get configuration\n"); 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(u8 *) req->buf = fsg->config; 101776f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = 1; 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_INTERFACE: 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_INTERFACE)) 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->config && w_index == 0) { 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to wipe out previous transaction 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state (queued bufs, etc) and install the new 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interface altsetting. */ 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = DELAYED_STATUS; 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_INTERFACE: 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_INTERFACE)) 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->config) 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_index != 0) { 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get interface\n"); 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(u8 *) req->buf = 0; 104576f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = 1; 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "unknown control req %02x.%02x v%04x i%04x l%u\n", 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl->bRequestType, ctrl->bRequest, 10521bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell w_value, w_index, le16_to_cpu(ctrl->wLength)); 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return value; 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fsg_setup(struct usb_gadget *gadget, 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_ctrlrequest *ctrl) 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 10641bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell int w_length = le16_to_cpu(ctrl->wLength); 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++fsg->ep0_req_tag; // Record arrival of a new request 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->context = NULL; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->length = 0; 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = class_setup_req(fsg, ctrl); 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = standard_setup_req(fsg, ctrl); 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Respond with data/status or defer until later? */ 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc >= 0 && rc != DELAYED_STATUS) { 107876f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern rc = min(rc, w_length); 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->length = rc; 10801bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell fsg->ep0req->zero = rc < w_length; 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep0-in" : "ep0-out"); 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ep0_queue(fsg); 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Device either stalls (rc < 0) or reports success */ 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* All the following routines run in process context */ 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Use this for bulk or interrupt transfers, not ep0 */ 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, 1098a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern struct usb_request *req, int *pbusy, 1099a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern enum fsg_buffer_state *state) 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == fsg->bulk_in) 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "bulk-in", req->buf, req->length); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep == fsg->intr_in) 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "intr-in", req->buf, req->length); 1107a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern 1108a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern spin_lock_irq(&fsg->lock); 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pbusy = 1; 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *state = BUF_STATE_BUSY; 1111a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern spin_unlock_irq(&fsg->lock); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = usb_ep_queue(ep, req, GFP_KERNEL); 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0) { 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pbusy = 0; 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *state = BUF_STATE_EMPTY; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't do much more than wait for a reset */ 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Note: currently the net2280 driver fails zero-length 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * submissions if DMA is enabled. */ 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->length == 0)) 1123b6c63937001889af6fe431aaba97e59d04e028e7Arjan van de Ven WARNING(fsg, "error in submission: %s --> %d\n", 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->name, rc); 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sleep_thread(struct fsg_dev *fsg) 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1131a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern int rc = 0; 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait until a signal arrives or we are woken up */ 1134a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern for (;;) { 1135a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern try_to_freeze(); 1136a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern set_current_state(TASK_INTERRUPTIBLE); 1137a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern if (signal_pending(current)) { 1138a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern rc = -EINTR; 1139a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern break; 1140a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern } 1141a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern if (fsg->thread_wakeup_needed) 1142a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern break; 1143a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern schedule(); 1144a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern } 1145a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern __set_current_state(TASK_RUNNING); 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->thread_wakeup_needed = 0; 1147a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern return rc; 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read(struct fsg_dev *fsg) 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1155d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 lba; 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount_left; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t file_offset, file_offset_tmp; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int amount; 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t nread; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the starting Logical Block Address and check that it's 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not too big */ 11660a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz if (fsg->cmnd[0] == READ_6) 1167604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern lba = get_unaligned_be24(&fsg->cmnd[1]); 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 1169604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern lba = get_unaligned_be32(&fsg->cmnd[2]); 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We allow DPO (Disable Page Out = don't save data in the 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache) and FUA (Force Unit Access = don't read from the 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache), but we don't implement them. */ 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x18) != 0) { 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lba >= curlun->num_sectors) { 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11833f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li file_offset = ((loff_t) lba) << curlun->blkbits; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Carry out the file reads */ 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left = fsg->data_size_from_cmnd; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(amount_left == 0)) 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Figure out how much we need to read: 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to read the remaining amount. 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But don't read more than the buffer size. 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And don't try to read past the end of the file. 119604eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern */ 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((unsigned int) amount_left, mod_data.buflen); 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((loff_t) amount, 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->file_length - file_offset); 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available */ 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 120479a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 120579a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we were asked to read past the end of file, 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * end with an empty buffer. */ 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount == 0) { 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 12143f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li curlun->sense_data_info = file_offset >> curlun->blkbits; 12156174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 1; 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = 0; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Perform the read */ 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset_tmp = file_offset; 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = vfs_read(curlun->filp, 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char __user *) bh->buf, 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, &file_offset_tmp); 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) file_offset, 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread < 0) { 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "error in file read: %d\n", 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = 0; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (nread < amount) { 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "partial file read: %d/%u\n", 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread, amount); 12393f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li nread = round_down(nread, curlun->blksize); 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset += nread; 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left -= nread; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue -= nread; 124404eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern 124504eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern /* Except at the end of the transfer, nread will be 124604eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * equal to the buffer size, which is divisible by the 124704eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * bulk-in maxpacket size. 124804eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern */ 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = nread; 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If an error occurred, report it and its position */ 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread < amount) { 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 12553f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li curlun->sense_data_info = file_offset >> curlun->blkbits; 12566174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 1; 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount_left == 0) 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // No more left to read 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Send this buffer and go read some more */ 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 0; 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_write(struct fsg_dev *fsg) 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1278d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 lba; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int get_some_more; 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount_left_to_req, amount_left_to_write; 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t usb_offset, file_offset, file_offset_tmp; 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int amount; 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t nwritten; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->ro) { 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_WRITE_PROTECTED; 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1292db1dd4d376134eba0e08af523b61cc566a4ea1cdJonathan Corbet spin_lock(&curlun->filp->f_lock); 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait 1294db1dd4d376134eba0e08af523b61cc566a4ea1cdJonathan Corbet spin_unlock(&curlun->filp->f_lock); 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the starting Logical Block Address and check that it's 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not too big */ 12980a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz if (fsg->cmnd[0] == WRITE_6) 1299604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern lba = get_unaligned_be24(&fsg->cmnd[1]); 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 1301604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern lba = get_unaligned_be32(&fsg->cmnd[2]); 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We allow DPO (Disable Page Out = don't save data in the 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache) and FUA (Force Unit Access = write directly to the 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * medium). We don't implement DPO; we implement FUA by 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * performing synchronous output. */ 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x18) != 0) { 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1311a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko /* FUA */ 1312a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { 1313db1dd4d376134eba0e08af523b61cc566a4ea1cdJonathan Corbet spin_lock(&curlun->filp->f_lock); 13146b2f3d1f769be5779b479c37800229d9a4809fc3Christoph Hellwig curlun->filp->f_flags |= O_DSYNC; 1315db1dd4d376134eba0e08af523b61cc566a4ea1cdJonathan Corbet spin_unlock(&curlun->filp->f_lock); 1316db1dd4d376134eba0e08af523b61cc566a4ea1cdJonathan Corbet } 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lba >= curlun->num_sectors) { 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Carry out the file writes */ 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_some_more = 1; 13253f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (amount_left_to_write > 0) { 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Queue a request for more data from the host */ 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_EMPTY && get_some_more) { 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Figure out how much we want to get: 133504eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * Try to get the remaining amount, 133604eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * but not more than the buffer size. 133704eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern */ 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min(amount_left_to_req, mod_data.buflen); 133904eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern 134004eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern /* Beyond the end of the backing file? */ 134104eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern if (usb_offset >= curlun->file_length) { 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_some_more = 0; 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 13453f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li curlun->sense_data_info = usb_offset >> curlun->blkbits; 13466174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 1; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the next buffer */ 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_offset += amount; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left -= amount; 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left_to_req -= amount; 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount_left_to_req == 0) 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_some_more = 0; 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 135704eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern /* Except at the end of the transfer, amount will be 135804eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * equal to the buffer size, which is divisible by 135904eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * the bulk-out maxpacket size. 136004eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern */ 1361fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman set_bulk_out_req_length(fsg, bh, amount); 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_out, bh->outreq, 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->outreq_busy, &bh->state); 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write the received data to the backing file */ 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_drain; 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_EMPTY && !get_some_more) 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // We stopped early 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_FULL) { 1373a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern smp_rmb(); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_drain = bh->next; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Did something go wrong with the transfer? */ 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq->status != 0) { 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_COMMUNICATION_FAILURE; 13803f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li curlun->sense_data_info = file_offset >> curlun->blkbits; 13816174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 1; 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = bh->outreq->actual; 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->file_length - file_offset < amount) { 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LERROR(curlun, 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "write %u @ %llu beyond end %llu\n", 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, (unsigned long long) file_offset, 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) curlun->file_length); 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = curlun->file_length - file_offset; 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1394fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman /* Don't accept excess data. The spec doesn't say 1395fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman * what to do in this case. We'll ignore the error. 1396fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman */ 1397fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman amount = min(amount, bh->bulk_out_intended_length); 1398fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman 139904eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern /* Don't write a partial block */ 140004eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern amount = round_down(amount, curlun->blksize); 140104eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern if (amount == 0) 140204eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern goto empty_write; 140304eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Perform the write */ 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset_tmp = file_offset; 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nwritten = vfs_write(curlun->filp, 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char __user *) bh->buf, 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, &file_offset_tmp); 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) file_offset, 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nwritten); 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; // Interrupted! 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nwritten < 0) { 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "error in file write: %d\n", 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nwritten); 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nwritten = 0; 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (nwritten < amount) { 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "partial file write: %d/%u\n", 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nwritten, amount); 14223f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li nwritten = round_down(nwritten, curlun->blksize); 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset += nwritten; 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left_to_write -= nwritten; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue -= nwritten; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If an error occurred, report it and its position */ 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nwritten < amount) { 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_WRITE_ERROR; 14313f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li curlun->sense_data_info = file_offset >> curlun->blkbits; 14326174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 1; 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143604eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern empty_write: 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Did the host decide to stop early? */ 1438fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman if (bh->outreq->actual < bh->bulk_out_intended_length) { 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->short_packet_received = 1; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for something to happen */ 144679a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 144779a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_synchronize_cache(struct fsg_dev *fsg) 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1459d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We ignore the requested LBA and write out all file's 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dirty data buffers. */ 1464d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz rc = fsg_lun_fsync_sub(curlun); 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_WRITE_ERROR; 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1473d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewiczstatic void invalidate_sub(struct fsg_lun *curlun) 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file *filp = curlun->filp; 147633cb89940082c54f348062db2f8bab6cf8fed816Josef Sipek struct inode *inode = filp->f_path.dentry->d_inode; 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long rc; 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1479fc0ecff698165ae8e178efa086e0dd1f385206b1Andrew Morton rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); 14802ecdc82ef0b03e67ce5ecee79d0d108177a704dfChristoph Hellwig VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_verify(struct fsg_dev *fsg) 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1485d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 lba; 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 verification_length; 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t file_offset, file_offset_tmp; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount_left; 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int amount; 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t nread; 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the starting Logical Block Address and check that it's 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not too big */ 1496604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern lba = get_unaligned_be32(&fsg->cmnd[2]); 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lba >= curlun->num_sectors) { 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We allow DPO (Disable Page Out = don't save data in the 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache) but we don't implement it. */ 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x10) != 0) { 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1509604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern verification_length = get_unaligned_be16(&fsg->cmnd[7]); 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(verification_length == 0)) 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Prepare to carry out the file verify */ 15143f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li amount_left = verification_length << curlun->blkbits; 15153f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li file_offset = ((loff_t) lba) << curlun->blkbits; 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write out all the dirty buffers before invalidating them */ 1518d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_lun_fsync_sub(curlun); 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds invalidate_sub(curlun); 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Just try to read the requested blocks */ 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (amount_left > 0) { 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Figure out how much we need to read: 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to read the remaining amount, but not more than 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the buffer size. 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And don't try to read past the end of the file. 153304eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern */ 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((unsigned int) amount_left, mod_data.buflen); 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((loff_t) amount, 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->file_length - file_offset); 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount == 0) { 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 15403f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li curlun->sense_data_info = file_offset >> curlun->blkbits; 15416174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 1; 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Perform the read */ 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset_tmp = file_offset; 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = vfs_read(curlun->filp, 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char __user *) bh->buf, 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, &file_offset_tmp); 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) file_offset, 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread < 0) { 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "error in file verify: %d\n", 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = 0; 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (nread < amount) { 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "partial file verify: %d/%u\n", 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread, amount); 15633f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li nread = round_down(nread, curlun->blksize); 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread == 0) { 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 15673f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li curlun->sense_data_info = file_offset >> curlun->blkbits; 15686174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 1; 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset += nread; 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left -= nread; 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static char vendor_id[] = "Linux "; 158512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern static char product_disk_id[] = "File-Stor Gadget"; 158612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern static char product_cdrom_id[] = "File-CD Gadget "; 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->curlun) { // Unsupported LUNs are okay 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bad_lun_okay = 1; 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, 36); 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x7f; // Unsupported, no device-type 159212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[4] = 31; // Additional length 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 36; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 159612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern memset(buf, 0, 8); 15970a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK); 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.removable) 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 0x80; 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = 2; // ANSI SCSI level 2 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = 2; // SCSI-2 INQUIRY data format 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 31; // Additional length 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // No special options 160412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, 160512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern (mod_data.cdrom ? product_cdrom_id : 160612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern product_disk_id), 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.release); 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 36; 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1614d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 sd, sdinfo; 16176174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern int valid; 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * From the SCSI-2 spec., section 7.9 (Unit attention condition): 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a REQUEST SENSE command is received from an initiator 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a pending unit attention condition (before the target 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generates the contingent allegiance condition), then the 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target shall either: 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a) report any pending sense data and preserve the unit 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attention condition on the logical unit, or, 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * b) report the unit attention condition, may discard any 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pending sense data, and clear the unit attention 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * condition on the logical unit for that initiator. 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FSG normally uses option a); enable this code to use option b). 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = curlun->unit_attention_data; 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->unit_attention_data = SS_NO_SENSE; 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!curlun) { // Unsupported LUNs are okay 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bad_lun_okay = 1; 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdinfo = 0; 16456174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern valid = 0; 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = curlun->sense_data; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdinfo = curlun->sense_data_info; 16496174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern valid = curlun->info_valid << 7; 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_NO_SENSE; 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = 0; 16526174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 0; 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, 18); 16566174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern buf[0] = valid | 0x70; // Valid, current error 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = SK(sd); 1658604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[7] = 18 - 8; // Additional sense length 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[12] = ASC(sd); 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[13] = ASCQ(sd); 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 18; 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1668d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 1669604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern u32 lba = get_unaligned_be32(&fsg->cmnd[2]); 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pmi = fsg->cmnd[8]; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the PMI and LBA fields */ 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pmi > 1 || (pmi == 0 && lba != 0)) { 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1679604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); 1680604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern /* Max logical block */ 16813f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 8; 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 168612aae68a203e97a58d3f8237fc389201a4d9282dAlan Sternstatic int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) 168712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern{ 1688d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 168912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern int msf = fsg->cmnd[1] & 0x02; 1690604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern u32 lba = get_unaligned_be32(&fsg->cmnd[2]); 169112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern u8 *buf = (u8 *) bh->buf; 169212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 169312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ 169412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 169512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern return -EINVAL; 169612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern } 169712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if (lba >= curlun->num_sectors) { 169812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 169912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern return -EINVAL; 170012aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern } 170112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 170212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern memset(buf, 0, 8); 170312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ 170412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern store_cdrom_address(&buf[4], msf, lba); 170512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern return 8; 170612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern} 170712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 170812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 170912aae68a203e97a58d3f8237fc389201a4d9282dAlan Sternstatic int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) 171012aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern{ 1711d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 171212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern int msf = fsg->cmnd[1] & 0x02; 171312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern int start_track = fsg->cmnd[6]; 171412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern u8 *buf = (u8 *) bh->buf; 171512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 171612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ 171712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern start_track > 1) { 171812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 171912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern return -EINVAL; 172012aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern } 172112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 172212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern memset(buf, 0, 20); 172312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[1] = (20-2); /* TOC data length */ 172412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[2] = 1; /* First track number */ 172512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[3] = 1; /* Last track number */ 172612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[5] = 0x16; /* Data track, copying allowed */ 172712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[6] = 0x01; /* Only track is number 1 */ 172812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern store_cdrom_address(&buf[8], msf, 0); 172912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 173012aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[13] = 0x16; /* Lead-out track is data */ 173112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern buf[14] = 0xAA; /* Lead-out track number */ 173212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern store_cdrom_address(&buf[16], msf, curlun->num_sectors); 173312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern return 20; 173412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern} 173512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 173612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1739d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mscmnd = fsg->cmnd[0]; 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf0 = buf; 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pc, page_code; 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int changeable_values, all_pages; 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int valid_page = 0; 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len, limit; 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = fsg->cmnd[2] >> 6; 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_code = fsg->cmnd[2] & 0x3f; 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pc == 3) { 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds changeable_values = (pc == 1); 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds all_pages = (page_code == 0x3f); 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write the mode parameter header. Fixed values are: default 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * medium type, no cache control (DPOFUA), and no block descriptors. 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The only variable value is the WriteProtect bit. We will fill in 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the mode data length later. */ 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, 8); 17660a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz if (mscmnd == MODE_SENSE) { 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 4; 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 255; 17700a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz } else { // MODE_SENSE_10 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 8; 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 65535; // Should really be mod_data.buflen 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No block descriptors */ 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The mode pages, in numerical order. The only page we support 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is the Caching page. */ 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (page_code == 0x08 || all_pages) { 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds valid_page = 1; 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x08; // Page code 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 10; // Page length 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf+2, 0, 10); // None of the fields are changeable 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!changeable_values) { 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = 0x04; // Write cache enable, 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Read cache not disabled 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // No cache retention priorities 1790604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern put_unaligned_be16(0xffff, &buf[4]); 1791604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern /* Don't disable prefetch */ 1792604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern /* Minimum prefetch = 0 */ 1793604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern put_unaligned_be16(0xffff, &buf[8]); 1794604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern /* Maximum prefetch */ 1795604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern put_unaligned_be16(0xffff, &buf[10]); 1796604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern /* Maximum prefetch ceiling */ 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 12; 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check that a valid page was requested and the mode data length 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isn't too long. */ 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = buf - buf0; 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!valid_page || len > limit) { 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store the mode data length */ 18100a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz if (mscmnd == MODE_SENSE) 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf0[0] = len - 1; 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 1813604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern put_unaligned_be16(len - 2, buf0); 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_start_stop(struct fsg_dev *fsg) 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1820d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int loej, start; 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mod_data.removable) { 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_COMMAND; 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // int immed = fsg->cmnd[1] & 0x01; 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loej = fsg->cmnd[4] & 0x02; 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = fsg->cmnd[4] & 0x01; 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!start) { 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Are we allowed to unload the media? */ 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->prevent_medium_removal) { 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "unload attempt prevented\n"); 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (loej) { // Simulate an unload/eject 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&fsg->filesem); 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_write(&fsg->filesem); 1850d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_lun_close(curlun); 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_write(&fsg->filesem); 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&fsg->filesem); 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Our emulation doesn't support mounting; the medium is 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * available for use as soon as it is loaded. */ 1858d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz if (!fsg_lun_is_open(curlun)) { 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_prevent_allow(struct fsg_dev *fsg) 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1870d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int prevent; 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mod_data.removable) { 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_COMMAND; 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevent = fsg->cmnd[4] & 0x01; 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->prevent_medium_removal && !prevent) 1885d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_lun_fsync_sub(curlun); 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->prevent_medium_removal = prevent; 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read_format_capacities(struct fsg_dev *fsg, 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh) 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1894d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = buf[1] = buf[2] = 0; 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = 8; // Only the Current/Maximum Capacity Descriptor 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 4; 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern put_unaligned_be32(curlun->num_sectors, &buf[0]); 1902604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern /* Number of blocks */ 19033f565a363cee14d2ed281823196d455bfc7c4170Peiyu Li put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ 1904604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern buf[4] = 0x02; /* Current capacity */ 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 12; 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1911d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We don't support MODE SELECT */ 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_COMMAND; 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int halt_bulk_in_endpoint(struct fsg_dev *fsg) 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = fsg_set_halt(fsg, fsg->bulk_in); 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc == -EAGAIN) 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "delayed bulk-in endpoint halt\n"); 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (rc != 0) { 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != -EAGAIN) { 1930b6c63937001889af6fe431aaba97e59d04e028e7Arjan van de Ven WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for a short time and then try again */ 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msleep_interruptible(100) != 0) 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = usb_ep_set_halt(fsg->bulk_in); 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 194362fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopostatic int wedge_bulk_in_endpoint(struct fsg_dev *fsg) 194462fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo{ 194562fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo int rc; 194662fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo 194762fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo DBG(fsg, "bulk-in set wedge\n"); 194862fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo rc = usb_ep_set_wedge(fsg->bulk_in); 194962fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo if (rc == -EAGAIN) 195062fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo VDBG(fsg, "delayed bulk-in endpoint wedge\n"); 195162fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo while (rc != 0) { 195262fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo if (rc != -EAGAIN) { 1953b6c63937001889af6fe431aaba97e59d04e028e7Arjan van de Ven WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); 195462fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo rc = 0; 195562fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo break; 195662fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo } 195762fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo 195862fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo /* Wait for a short time and then try again */ 195962fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo if (msleep_interruptible(100) != 0) 196062fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo return -EINTR; 196162fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo rc = usb_ep_set_wedge(fsg->bulk_in); 196262fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo } 196362fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo return rc; 196462fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo} 196562fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int throw_away_data(struct fsg_dev *fsg) 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount; 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left > 0) { 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Throw away the data in a filled buffer */ 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_FULL) { 1977a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern smp_rmb(); 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_drain = bh->next; 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* A short packet or an error ends everything */ 1982fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman if (bh->outreq->actual < bh->bulk_out_intended_length || 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq->status != 0) { 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Try to submit another request if we need one */ 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min(fsg->usb_amount_left, 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (u32) mod_data.buflen); 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 199604eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern /* Except at the end of the transfer, amount will be 199704eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * equal to the buffer size, which is divisible by 199804eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern * the bulk-out maxpacket size. 199904eee25b1d754a837360504b7af426d1f86ffeb7Alan Stern */ 2000fe69676530f182bbb1fe0edd027e18751a1a2595Paul Zimmerman set_bulk_out_req_length(fsg, bh, amount); 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_out, bh->outreq, 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->outreq_busy, &bh->state); 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left -= amount; 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Otherwise wait for something to happen */ 200979a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 201079a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int finish_reply(struct fsg_dev *fsg) 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (fsg->data_dir) { 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_NONE: 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // Nothing to send 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we don't know whether the host wants to read or write, 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this must be CB or CBI with an unknown command. We mustn't 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try to send or receive any data. So stall both bulk pipes 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if we can and wait for a reset. */ 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_UNKNOWN: 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.can_stall) { 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->bulk_out); 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = halt_bulk_in_endpoint(fsg); 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All but the last buffer of data must have already been sent */ 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_TO_HOST: 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size == 0) 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Nothing to send 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If there's no residue, simply send the last buffer */ 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (fsg->residue == 0) { 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 0; 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There is a residue. For CB and CBI, simply mark the end 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the data with a short packet. However, if we are 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allowed to stall, there was no data at all (residue == 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data_size), and the command failed (invalid LUN or 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sense data is set), then halt the bulk-in endpoint 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instead. */ 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (!transport_is_bbb()) { 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.can_stall && 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue == fsg->data_size && 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = halt_bulk_in_endpoint(fsg); 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 1; 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2070ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern /* 2071ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern * For Bulk-only, mark the end of the data with a short 2072ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern * packet. If we are allowed to stall, halt the bulk-in 2073ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern * endpoint. (Note: This violates the Bulk-Only Transport 2074ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern * specification, which requires us to pad the data if we 2075ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern * don't halt the endpoint. Presumably nobody will mind.) 2076ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern */ 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 2078ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern bh->inreq->zero = 1; 2079ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern start_transfer(fsg, fsg->bulk_in, bh->inreq, 2080ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern &bh->inreq_busy, &bh->state); 2081ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern fsg->next_buffhd_to_fill = bh->next; 2082ee81b3e086c907a3347b15ef219a24fc8bf900f6Alan Stern if (mod_data.can_stall) 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = halt_bulk_in_endpoint(fsg); 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We have processed all we want from the data the host has sent. 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There may still be outstanding bulk-out requests. */ 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_FROM_HOST: 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->residue == 0) 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Nothing to receive 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Did the host stop sending unexpectedly early? */ 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (fsg->short_packet_received) { 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINTR; 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We haven't processed all the incoming data. Even though 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we may be allowed to stall, doing so would cause a race. 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The controller may already have ACK'ed all the remaining 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bulk-out packets, in which case the host wouldn't see a 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STALL. Not realizing the endpoint was halted, it wouldn't 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clear the halt -- leading to problems later on. */ 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (mod_data.can_stall) { 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->bulk_out); 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINTR; 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't stall. Read in the excess data and throw it 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all away. */ 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = throw_away_data(fsg); 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int send_status(struct fsg_dev *fsg) 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2125d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun = fsg->curlun; 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 2128775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior u8 status = US_BULK_STAT_OK; 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 sd, sdinfo = 0; 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available */ 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 213479a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 213579a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun) { 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = curlun->sense_data; 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdinfo = curlun->sense_data_info; 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (fsg->bad_lun_okay) 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_NO_SENSE; 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->phase_error) { 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "sending phase-error status\n"); 2149775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior status = US_BULK_STAT_PHASE; 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_INVALID_COMMAND; 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (sd != SS_NO_SENSE) { 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "sending command-failure status\n"); 2153775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior status = US_BULK_STAT_FAIL; 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " info x%x\n", 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SK(sd), ASC(sd), ASCQ(sd), sdinfo); 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 21607ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct bulk_cs_wrap *csw = bh->buf; 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store and send the Bulk-only CSW */ 2163775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csw->Tag = fsg->tag; 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csw->Residue = cpu_to_le32(fsg->residue); 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csw->Status = status; 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2168775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior bh->inreq->length = US_BULK_CS_WRAP_LEN; 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 0; 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (mod_data.transport_type == USB_PR_CB) { 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Control-Bulk transport has no status phase! */ 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // USB_PR_CBI 21797ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct interrupt_data *buf = bh->buf; 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store and send the Interrupt data. UFI sends the ASC 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and ASCQ bytes. Everything else sends a Type (which 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is always 0) and the status Value. */ 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.protocol_type == USB_SC_UFI) { 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bType = ASC(sd); 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bValue = ASCQ(sd); 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bType = 0; 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bValue = status; 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_buffhd = bh; // Point to the right buffhd 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->buf = bh->inreq->buf; 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->context = bh; 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->intr_in, fsg->intreq, 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &fsg->intreq_busy, &bh->state); 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Check whether the command is properly formed and whether its data size 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and direction agree with the values we already have. */ 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_command(struct fsg_dev *fsg, int cmnd_size, 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum data_direction data_dir, unsigned int mask, 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int needs_medium, const char *name) 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun = fsg->cmnd[1] >> 5; 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char dirletter[4] = {'u', 'o', 'i', 'n'}; 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char hdlen[20]; 2217d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun; 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Adjust the expected cmnd_size for protocol encapsulation padding. 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transparent SCSI doesn't pad. */ 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (protocol_is_scsi()) 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There's some disagreement as to whether RBC pads commands or not. 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'll play it safe and accept either form. */ 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (mod_data.protocol_type == USB_SC_RBC) { 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd_size == 12) 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmnd_size = 12; 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All the other protocols pad to 12 bytes */ 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmnd_size = 12; 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlen[0] = 0; 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_dir != DATA_DIR_UNKNOWN) 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size); 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name, cmnd_size, dirletter[(int) data_dir], 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't reply at all until we know the correct data direction 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and size. */ 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size_from_cmnd == 0) 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_dir = DATA_DIR_NONE; 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = data_dir; 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size = fsg->data_size_from_cmnd; 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // Bulk-only 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size < fsg->data_size_from_cmnd) { 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Host data size < Device data size is a phase error. 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Carry out the command, but only transfer as much 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as we are allowed. */ 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->data_size; 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 1; 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue = fsg->usb_amount_left = fsg->data_size; 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Conflicting data directions is a phase error */ 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 1; 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Verify the length of the command itself */ 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmnd_size != fsg->cmnd_size) { 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi /* Special case workaround: There are plenty of buggy SCSI 2272549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * implementations. Many have issues with cbw->Length 2273549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * field passing a wrong command size. For those cases we 2274549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * always try to work around the problem by using the length 2275549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * sent by the host side provided it is at least as large 2276549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * as the correct command length. 2277549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * Examples of such cases would be MS-Windows, which issues 2278549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * REQUEST SENSE with cbw->Length == 12 where it should 2279549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and 2280549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * REQUEST SENSE with cbw->Length == 10 where it should 2281549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi * be 6 as well. 2282549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi */ 2283549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi if (cmnd_size <= fsg->cmnd_size) { 2284549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi DBG(fsg, "%s is buggy! Expected length %d " 2285549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi "but we got %d\n", name, 2286549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi cmnd_size, fsg->cmnd_size); 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmnd_size = fsg->cmnd_size; 2288549c41e0ac0a3eb68cfdaeb43c1a314e2a6c289aFelipe Balbi } else { 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 1; 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2294d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern /* Check that the LUN values are consistent */ 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->lun != lun) 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "using LUN %d from CBW, " 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "not LUN %d from CDB\n", 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->lun, lun); 2300144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo } 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the LUN */ 2303144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo curlun = fsg->curlun; 2304144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if (curlun) { 23050a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz if (fsg->cmnd[0] != REQUEST_SENSE) { 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_NO_SENSE; 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = 0; 23086174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 0; 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bad_lun_okay = 0; 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* INQUIRY and REQUEST SENSE commands are explicitly allowed 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to use unsupported LUNs; all others may not. */ 23150a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz if (fsg->cmnd[0] != INQUIRY && 23160a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz fsg->cmnd[0] != REQUEST_SENSE) { 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "unsupported LUN %d\n", fsg->lun); 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If a unit attention condition exists, only INQUIRY and 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * REQUEST SENSE commands are allowed; anything else must fail. */ 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun && curlun->unit_attention_data != SS_NO_SENSE && 23250a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz fsg->cmnd[0] != INQUIRY && 23260a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz fsg->cmnd[0] != REQUEST_SENSE) { 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = curlun->unit_attention_data; 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->unit_attention_data = SS_NO_SENSE; 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check that only command bytes listed in the mask are non-zero */ 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd[1] &= 0x1f; // Mask away the LUN 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < cmnd_size; ++i) { 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[i] && !(mask & (1 << i))) { 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun) 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the medium isn't mounted and the command needs to access 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it, return an error. */ 2344d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2352144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo/* wrapper of check_command for data size in blocks handling */ 2353144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luostatic int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, 2354144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo enum data_direction data_dir, unsigned int mask, 2355144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo int needs_medium, const char *name) 2356144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo{ 2357144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if (fsg->curlun) 2358144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; 2359144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo return check_command(fsg, cmnd_size, data_dir, 2360144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo mask, needs_medium, name); 2361144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo} 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_scsi_command(struct fsg_dev *fsg) 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reply = -EINVAL; 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static char unknown[16]; 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_cdb(fsg); 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available for data or status */ 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 237679a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 237779a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 237979a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern } 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 0; 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->short_packet_received = 0; 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&fsg->filesem); // We're using the backing file 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (fsg->cmnd[0]) { 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23860a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case INQUIRY: 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<4), 0, 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "INQUIRY")) == 0) 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_inquiry(fsg, bh); 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23940a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case MODE_SELECT: 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<4), 0, 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SELECT(6)")) == 0) 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_select(fsg, bh); 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24020a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case MODE_SELECT_10: 2403604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (3<<7), 0, 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SELECT(10)")) == 0) 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_select(fsg, bh); 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24100a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case MODE_SENSE: 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<2) | (1<<4), 0, 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SENSE(6)")) == 0) 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_sense(fsg, bh); 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24180a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case MODE_SENSE_10: 2419604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<2) | (3<<7), 0, 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SENSE(10)")) == 0) 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_sense(fsg, bh); 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24260a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case ALLOW_MEDIUM_REMOVAL: 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_NONE, 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<4), 0, 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_prevent_allow(fsg); 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24340a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case READ_6: 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = fsg->cmnd[4]; 2436144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->data_size_from_cmnd = (i == 0) ? 256 : i; 2437144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if ((reply = check_command_size_in_blocks(fsg, 6, 2438144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo DATA_DIR_TO_HOST, 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (7<<1) | (1<<4), 1, 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ(6)")) == 0) 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read(fsg); 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24440a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case READ_10: 2445144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); 2446144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if ((reply = check_command_size_in_blocks(fsg, 10, 2447144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo DATA_DIR_TO_HOST, 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (3<<7), 1, 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ(10)")) == 0) 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read(fsg); 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24530a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case READ_12: 2454144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); 2455144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if ((reply = check_command_size_in_blocks(fsg, 12, 2456144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo DATA_DIR_TO_HOST, 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (0xf<<6), 1, 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ(12)")) == 0) 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read(fsg); 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24620a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case READ_CAPACITY: 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 8; 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0xf<<2) | (1<<8), 1, 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ CAPACITY")) == 0) 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read_capacity(fsg, bh); 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24700a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case READ_HEADER: 247112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if (!mod_data.cdrom) 247212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern goto unknown_cmnd; 2473604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); 247412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 247512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern (3<<7) | (0x1f<<1), 1, 247612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern "READ HEADER")) == 0) 247712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern reply = do_read_header(fsg, bh); 247812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern break; 247912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 24800a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case READ_TOC: 248112aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if (!mod_data.cdrom) 248212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern goto unknown_cmnd; 2483604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); 248412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 248512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern (7<<6) | (1<<1), 1, 248612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern "READ TOC")) == 0) 248712aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern reply = do_read_toc(fsg, bh); 248812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern break; 248912aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern 24900a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case READ_FORMAT_CAPACITIES: 2491604eb89ffed9fba268582dc44d5b462ea94cc0caAlan Stern fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (3<<7), 1, 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ FORMAT CAPACITIES")) == 0) 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read_format_capacities(fsg, bh); 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24980a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case REQUEST_SENSE: 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, 25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<4), 0, 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "REQUEST SENSE")) == 0) 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_request_sense(fsg, bh); 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25060a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case START_STOP: 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_NONE, 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<4), 0, 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "START-STOP UNIT")) == 0) 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_start_stop(fsg); 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25140a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case SYNCHRONIZE_CACHE: 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_NONE, 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0xf<<2) | (3<<7), 1, 25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SYNCHRONIZE CACHE")) == 0) 25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_synchronize_cache(fsg); 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25220a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case TEST_UNIT_READY: 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = check_command(fsg, 6, DATA_DIR_NONE, 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 1, 25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "TEST UNIT READY"); 25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Although optional, this command is used by MS-Windows. We 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * support a minimal version: BytChk must be 0. */ 25310a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case VERIFY: 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_NONE, 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (3<<7), 1, 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "VERIFY")) == 0) 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_verify(fsg); 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25390a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case WRITE_6: 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = fsg->cmnd[4]; 2541144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->data_size_from_cmnd = (i == 0) ? 256 : i; 2542144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if ((reply = check_command_size_in_blocks(fsg, 6, 2543144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo DATA_DIR_FROM_HOST, 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (7<<1) | (1<<4), 1, 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "WRITE(6)")) == 0) 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_write(fsg); 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25490a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case WRITE_10: 2550144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); 2551144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if ((reply = check_command_size_in_blocks(fsg, 10, 2552144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo DATA_DIR_FROM_HOST, 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (3<<7), 1, 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "WRITE(10)")) == 0) 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_write(fsg); 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25580a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case WRITE_12: 2559144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); 2560144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if ((reply = check_command_size_in_blocks(fsg, 12, 2561144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo DATA_DIR_FROM_HOST, 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (0xf<<6), 1, 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "WRITE(12)")) == 0) 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_write(fsg); 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Some mandatory commands that we recognize but don't implement. 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * They don't mean much in this setting. It's left as an exercise 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for anyone interested to implement RESERVE and RELEASE in terms 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of Posix locks. */ 25710a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case FORMAT_UNIT: 25720a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case RELEASE: 25730a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case RESERVE: 25740a6a717ceff67f887b16783ce891f5dcf846f1fcMichal Nazarewicz case SEND_DIAGNOSTIC: 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Fall through 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 257812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern unknown_cmnd: 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, fsg->cmnd_size, 2582c85dcdac5852295cf6822f5c4331a6ddab72581fAlan Stern DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) { 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->curlun->sense_data = SS_INVALID_COMMAND; 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = -EINVAL; 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&fsg->filesem); 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reply == -EINTR || signal_pending(current)) 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set up the single reply buffer for finish_reply() */ 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reply == -EINVAL) 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = 0; // Error reply length 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = min((u32) reply, fsg->data_size_from_cmnd); 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = reply; 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue -= reply; 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } // Otherwise it's already set 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2611d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct usb_request *req = bh->outreq; 26127ac4704c099125214a4f0a4bd54ce94d15be2ffbSebastian Andrzej Siewior struct bulk_cb_wrap *cbw = req->buf; 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2614b950bdbc67041412cb042e404938667204c7902cAlan Stern /* Was this a real packet? Should it be ignored? */ 2615b950bdbc67041412cb042e404938667204c7902cAlan Stern if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is the CBW valid? */ 2619775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior if (req->actual != US_BULK_CB_WRAP_LEN || 2620551509d267905705f6d723e51ec706916f06b859Harvey Harrison cbw->Signature != cpu_to_le32( 2621775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior US_BULK_CB_SIGN)) { 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "invalid CBW: len %u sig 0x%x\n", 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->actual, 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(cbw->Signature)); 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2626b950bdbc67041412cb042e404938667204c7902cAlan Stern /* The Bulk-only spec says we MUST stall the IN endpoint 2627b950bdbc67041412cb042e404938667204c7902cAlan Stern * (6.6.1), so it's unavoidable. It also says we must 2628b950bdbc67041412cb042e404938667204c7902cAlan Stern * retain this state until the next reset, but there's 2629b950bdbc67041412cb042e404938667204c7902cAlan Stern * no way to tell the controller driver it should ignore 2630b950bdbc67041412cb042e404938667204c7902cAlan Stern * Clear-Feature(HALT) requests. 2631b950bdbc67041412cb042e404938667204c7902cAlan Stern * 2632b950bdbc67041412cb042e404938667204c7902cAlan Stern * We aren't required to halt the OUT endpoint; instead 2633b950bdbc67041412cb042e404938667204c7902cAlan Stern * we can simply accept and discard any data received 2634b950bdbc67041412cb042e404938667204c7902cAlan Stern * until the next reset. */ 263562fd2cac5bf5cf9e6fcb2fc40b32e7271e605c53David Lopo wedge_bulk_in_endpoint(fsg); 2636b950bdbc67041412cb042e404938667204c7902cAlan Stern set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is the CBW meaningful? */ 2641775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || 264212943f097e5a4a0550f52f98ab8f476435e2ce15Alan Stern cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cmdlen %u\n", 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cbw->Lun, cbw->Flags, cbw->Length); 26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can do anything we want here, so let's stall the 26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bulk pipes if we are allowed to. */ 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.can_stall) { 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->bulk_out); 26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds halt_bulk_in_endpoint(fsg); 26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Save the command for later */ 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd_size = cbw->Length; 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); 2659775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior if (cbw->Flags & US_BULK_FLAG_IN) 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_TO_HOST; 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_FROM_HOST; 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size = le32_to_cpu(cbw->DataTransferLength); 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size == 0) 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_NONE; 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->lun = cbw->Lun; 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->tag = cbw->Tag; 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_next_command(struct fsg_dev *fsg) 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available */ 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 268279a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 268379a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 268579a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern } 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Queue a request to read a Bulk-only CBW */ 2688775dafdcd330d021cee984459fbdacfc01d29f69Sebastian Andrzej Siewior set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN); 26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_out, bh->outreq, 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->outreq_busy, &bh->state); 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We will drain the buffer in software, which means we 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can reuse it for the next filling. No need to advance 26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * next_buffhd_to_fill. */ 26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the CBW to arrive */ 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_FULL) { 269879a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 269979a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 270179a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern } 2702a21d4fed4b00eaf7e7c3b2e2b25de24f540bfa66Alan Stern smp_rmb(); 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = received_cbw(fsg, bh); 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // USB_PR_CB or USB_PR_CBI 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next command to arrive */ 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fsg->cbbuf_cmnd_size == 0) { 271079a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern rc = sleep_thread(fsg); 271179a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern if (rc) 27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 271379a7d9ee1a2e8b8dc44dd217f07496911850ec0eAlan Stern } 27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is the previous status interrupt request still busy? 27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The host is allowed to skip reading the status, 27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we must cancel it. */ 27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intreq_busy) 27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->intr_in, fsg->intreq); 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy the command and mark the buffer empty */ 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_UNKNOWN; 27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd_size = fsg->cbbuf_cmnd_size; 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); 27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cbbuf_cmnd_size = 0; 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 2728144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo 2729144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo /* Use LUN from the command */ 2730144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->lun = fsg->cmnd[1] >> 5; 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2732144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo 2733144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo /* Update current lun */ 2734144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo if (fsg->lun >= 0 && fsg->lun < fsg->nluns) 2735144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->curlun = &fsg->luns[fsg->lun]; 2736144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo else 2737144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo fsg->curlun = NULL; 2738144974e7f9e32b53b02f6c8632be45d8f43d6ab5Yuping Luo 27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *d) 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; 275172c973dd2b01b212a159faa330a2bc641a3ed809Tatyana Brokhman ep->desc = d; 275272c973dd2b01b212a159faa330a2bc641a3ed809Tatyana Brokhman rc = usb_ep_enable(ep); 27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); 27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, 27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request **preq) 27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); 27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*preq) 27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "can't allocate request for %s\n", ep->name); 27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset interface setting and re-init endpoint state (toggle etc). 27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Call with altsetting < 0 to disable the interface. The only other 27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * available altsetting is 0, which enables the interface. 27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_set_interface(struct fsg_dev *fsg, int altsetting) 27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *d; 27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->running) 27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "reset interface\n"); 27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreset: 27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Deallocate the requests */ 27846532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin for (i = 0; i < fsg_num_buffers; ++i) { 27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = &fsg->buffhds[i]; 27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->inreq) { 27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->bulk_in, bh->inreq); 27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq = NULL; 27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq) { 27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->bulk_out, bh->outreq); 27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq = NULL; 27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intreq) { 27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->intr_in, fsg->intreq); 27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq = NULL; 27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable the endpoints */ 28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_in_enabled) { 28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_disable(fsg->bulk_in); 28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_in_enabled = 0; 28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_out_enabled) { 28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_disable(fsg->bulk_out); 28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_out_enabled = 0; 28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intr_in_enabled) { 28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_disable(fsg->intr_in); 28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_in_enabled = 0; 28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->running = 0; 28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (altsetting < 0 || rc != 0) 28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "set interface %d\n", altsetting); 28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable the endpoints */ 2822d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz d = fsg_ep_desc(fsg->gadget, 28234bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc, 28244bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi &fsg_ss_bulk_in_desc); 28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) 28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_in_enabled = 1; 28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2829d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz d = fsg_ep_desc(fsg->gadget, 28304bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc, 28314bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi &fsg_ss_bulk_out_desc); 28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) 28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_out_enabled = 1; 283529cc88979a8818cd8c5019426e945aed118b400eKuninori Morimoto fsg->bulk_out_maxpacket = usb_endpoint_maxp(d); 2836b950bdbc67041412cb042e404938667204c7902cAlan Stern clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); 28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_cbi()) { 2839d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz d = fsg_ep_desc(fsg->gadget, 28404bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc, 28414bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi &fsg_ss_intr_in_desc); 28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) 28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_in_enabled = 1; 28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the requests */ 28486532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin for (i = 0; i < fsg_num_buffers; ++i) { 28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = &fsg->buffhds[i]; 28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) 28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) 28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->buf = bh->outreq->buf = bh->buf; 28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->context = bh->outreq->context = bh; 28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->complete = bulk_in_complete; 28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq->complete = bulk_out_complete; 28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_cbi()) { 28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) 28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->complete = intr_in_complete; 28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->running = 1; 28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) 28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; 28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change our operational configuration. This code must agree with the code 28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that returns config descriptors, and with interface altsetting code. 28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It's also responsible for power management interactions. Some 28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations might not work with our current power sources. 28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now we just assume the gadget is always self-powered. 28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_set_config(struct fsg_dev *fsg, u8 new_config) 28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable the single interface */ 28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->config != 0) { 28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "reset config\n"); 28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->config = 0; 28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = do_set_interface(fsg, -1); 28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable the interface */ 28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_config != 0) { 28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->config = new_config; 28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = do_set_interface(fsg, 0)) != 0) 28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->config = 0; // Reset on errors 2897e538dfdae85244fd2c4231725d82cc1f1bc4942cMichal Nazarewicz else 2898e538dfdae85244fd2c4231725d82cc1f1bc4942cMichal Nazarewicz INFO(fsg, "%s config #%d\n", 2899e538dfdae85244fd2c4231725d82cc1f1bc4942cMichal Nazarewicz usb_speed_string(fsg->gadget->speed), 2900e538dfdae85244fd2c4231725d82cc1f1bc4942cMichal Nazarewicz fsg->config); 29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_exception(struct fsg_dev *fsg) 29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int sig; 29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_active; 29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum fsg_state old_state; 29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 new_config; 2917d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun; 29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int exception_req_tag; 29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear the existing signals. Anything but SIGUSR1 is converted 29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into a high-priority EXIT exception. */ 29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 29248cfbe7e60d9618d8f80a3cd218c45dd64cb9e5cfOleg Nesterov sig = dequeue_signal_lock(current, ¤t->blocked, &info); 29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sig) 29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sig != SIGUSR1) { 29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->state < FSG_STATE_EXIT) 29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "Main thread exiting on signal\n"); 29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_EXIT); 29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Cancel all the pending transfers */ 29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intreq_busy) 29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->intr_in, fsg->intreq); 29376532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin for (i = 0; i < fsg_num_buffers; ++i) { 29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = &fsg->buffhds[i]; 29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->inreq_busy) 29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->bulk_in, bh->inreq); 29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq_busy) 29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->bulk_out, bh->outreq); 29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait until everything is idle */ 29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_active = fsg->intreq_busy; 29486532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin for (i = 0; i < fsg_num_buffers; ++i) { 29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = &fsg->buffhds[i]; 29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_active += bh->inreq_busy + bh->outreq_busy; 29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num_active == 0) 29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sleep_thread(fsg)) 29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear out the controller's fifos */ 29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_in_enabled) 29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(fsg->bulk_in); 29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_out_enabled) 29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(fsg->bulk_out); 29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intr_in_enabled) 29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(fsg->intr_in); 29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset the I/O buffer states and pointers, the SCSI 29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state, and the exception. Then invoke the handler. */ 29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29706532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin for (i = 0; i < fsg_num_buffers; ++i) { 29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = &fsg->buffhds[i]; 29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = 29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &fsg->buffhds[0]; 29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exception_req_tag = fsg->exception_req_tag; 29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_config = fsg->new_config; 29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_state = fsg->state; 29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_state == FSG_STATE_ABORT_BULK_OUT) 29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_STATUS_PHASE; 29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->prevent_medium_removal = 0; 29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = curlun->unit_attention_data = 29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_NO_SENSE; 29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = 0; 29906174d0fd35f486f59b743630bdf088a9f9792d4dAlan Stern curlun->info_valid = 0; 29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_IDLE; 29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Carry out any extra actions required for the exception */ 29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (old_state) { 29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_ABORT_BULK_OUT: 30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_status(fsg); 30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->state == FSG_STATE_STATUS_PHASE) 30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_IDLE; 30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_RESET: 30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* In case we were forced against our will to halt a 30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bulk endpoint, clear the halt now. (The SuperH UDC 30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requires this.) */ 3013b950bdbc67041412cb042e404938667204c7902cAlan Stern if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) 30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_clear_halt(fsg->bulk_in); 30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->ep0_req_tag == exception_req_tag) 30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0_queue(fsg); // Complete the status stage 30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (transport_is_cbi()) 30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_status(fsg); // Status by interrupt pipe 30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Technically this should go here, but it would only be 30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a waste of time. Ditto for the INTERFACE_CHANGE and 30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CONFIG_CHANGE cases. */ 30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // for (i = 0; i < fsg->nluns; ++i) 30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; 30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_INTERFACE_CHANGE: 30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = do_set_interface(fsg, 0); 30321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->ep0_req_tag != exception_req_tag) 30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0) // STALL on errors 30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->ep0); 30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else // Complete the status stage 30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0_queue(fsg); 30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_CONFIG_CHANGE: 30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = do_set_config(fsg, new_config); 30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->ep0_req_tag != exception_req_tag) 30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0) // STALL on errors 30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->ep0); 30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else // Complete the status stage 30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0_queue(fsg); 30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_DISCONNECT: 3051b6058d0fefc0b5ff777dfbff990a0a50a4ac144bMichal Nazarewicz for (i = 0; i < fsg->nluns; ++i) 3052d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_lun_fsync_sub(fsg->luns + i); 30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_set_config(fsg, 0); // Unconfigured state 30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_EXIT: 30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_TERMINATED: 30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_set_config(fsg, 0); // Free resources 30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_TERMINATED; // Stop the thread 30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fsg_main_thread(void *fsg_) 30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30717ca46b862f0e30fe0dcc4a4aef5b32f6b6a3fda5John Daiker struct fsg_dev *fsg = fsg_; 30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allow the thread to be killed by a signal, but set the signal mask 30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to block everything but INT, TERM, KILL, and USR1. */ 30758cfbe7e60d9618d8f80a3cd218c45dd64cb9e5cfOleg Nesterov allow_signal(SIGINT); 30768cfbe7e60d9618d8f80a3cd218c45dd64cb9e5cfOleg Nesterov allow_signal(SIGTERM); 30778cfbe7e60d9618d8f80a3cd218c45dd64cb9e5cfOleg Nesterov allow_signal(SIGKILL); 30788cfbe7e60d9618d8f80a3cd218c45dd64cb9e5cfOleg Nesterov allow_signal(SIGUSR1); 30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3080831441862956fffa17b9801db37e6ea1650b0f69Rafael J. Wysocki /* Allow the thread to be frozen */ 3081831441862956fffa17b9801db37e6ea1650b0f69Rafael J. Wysocki set_freezable(); 3082831441862956fffa17b9801db37e6ea1650b0f69Rafael J. Wysocki 30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Arrange for userspace references to be interpreted as kernel 30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointers. That way we can pass a kernel pointer to a routine 30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that expects a __user pointer and it will work okay. */ 30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_fs(get_ds()); 30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The main loop */ 30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fsg->state != FSG_STATE_TERMINATED) { 30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (exception_in_progress(fsg) || signal_pending(current)) { 30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_exception(fsg); 30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->running) { 30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sleep_thread(fsg); 30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_next_command(fsg)) 31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!exception_in_progress(fsg)) 31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_DATA_PHASE; 31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (do_scsi_command(fsg) || finish_reply(fsg)) 31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!exception_in_progress(fsg)) 31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_STATUS_PHASE; 31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (send_status(fsg)) 31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!exception_in_progress(fsg)) 31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_IDLE; 31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 312522efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern spin_lock_irq(&fsg->lock); 31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->thread_task = NULL; 312722efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern spin_unlock_irq(&fsg->lock); 31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 312982a10a81c853be3859b3d222db0f372ee8d2eaa2Alan Stern /* If we are exiting because of a signal, unregister the 313082a10a81c853be3859b3d222db0f372ee8d2eaa2Alan Stern * gadget driver. */ 313182a10a81c853be3859b3d222db0f372ee8d2eaa2Alan Stern if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) 31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_unregister_driver(&fsg_driver); 31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Let the unbind and cleanup routines know the thread has exited */ 31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complete_and_exit(&fsg->thread_notifier, 0); 31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The write permissions and store_xxx pointers are set in fsg_bind() */ 314393f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewiczstatic DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); 3144a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenkostatic DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); 314593f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewiczstatic DEVICE_ATTR(file, 0444, fsg_show_file, NULL); 31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 315087c4252a35310fdbb2aabb880a39b83f83cadf62Alan Sternstatic void fsg_release(struct kref *ref) 315187c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern{ 315287c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); 315387c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern 315487c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kfree(fsg->luns); 315587c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kfree(fsg); 315687c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern} 315787c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern 31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lun_release(struct device *dev) 31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 316093f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz struct rw_semaphore *filesem = dev_get_drvdata(dev); 316193f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz struct fsg_dev *fsg = 316293f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz container_of(filesem, struct fsg_dev, filesem); 31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 316487c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_put(&fsg->ref, fsg_release); 31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3167a353678d3136306c1d00f0d2319de1dac8a6b1dbDavid Brownellstatic void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) 31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3171d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun; 31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "unbind\n"); 31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(REGISTERED, &fsg->atomic_bitflags); 31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 317791960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta /* If the thread isn't already dead, tell it to exit now */ 317891960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta if (fsg->state != FSG_STATE_TERMINATED) { 317991960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta raise_exception(fsg, FSG_STATE_EXIT); 318091960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta wait_for_completion(&fsg->thread_notifier); 318191960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta 318291960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta /* The cleanup routine waits for this completion also */ 318391960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta complete(&fsg->thread_notifier); 318491960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta } 318591960c2ef095c4b0744349e80a933921cbdcfd6eYauheni Kaliuta 31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unregister the sysfs attribute files and the LUNs */ 31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->registered) { 3190452ee0eb10bd3581cf667a1db18cb684889ce446Michal Nazarewicz device_remove_file(&curlun->dev, &dev_attr_nofua); 31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_remove_file(&curlun->dev, &dev_attr_ro); 31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_remove_file(&curlun->dev, &dev_attr_file); 3193d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_lun_close(curlun); 31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_unregister(&curlun->dev); 31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->registered = 0; 31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Free the data buffers */ 32006532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin for (i = 0; i < fsg_num_buffers; ++i) 32019d8bab58b758cd5a96d368a8cc64111c9ab50407David Brownell kfree(fsg->buffhds[i].buf); 32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Free the request and buffer for endpoint 0 */ 32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req) { 32059d8bab58b758cd5a96d368a8cc64111c9ab50407David Brownell kfree(req->buf); 32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->ep0, req); 32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_gadget_data(gadget, NULL); 32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init check_parameters(struct fsg_dev *fsg) 32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int prot; 321691e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell int gcnum; 32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store the default values */ 32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_type = USB_PR_BULK; 32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name = "Bulk-only"; 32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_SCSI; 32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "Transparent SCSI"; 32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3224ce459ec1d278b19be8e0719dbfd47dd1d6687bfbAlan Stern /* Some peripheral controllers are known not to be able to 3225ce459ec1d278b19be8e0719dbfd47dd1d6687bfbAlan Stern * halt bulk endpoints correctly. If one of them is present, 3226ce459ec1d278b19be8e0719dbfd47dd1d6687bfbAlan Stern * disable stalls. 3227ce459ec1d278b19be8e0719dbfd47dd1d6687bfbAlan Stern */ 322890f7976880bbbf9968629500972f8e2f80401217Christoph Egger if (gadget_is_at91(fsg->gadget)) 32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.can_stall = 0; 32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.release == 0xffff) { // Parameter wasn't set 323290f7976880bbbf9968629500972f8e2f80401217Christoph Egger gcnum = usb_gadget_controller_number(fsg->gadget); 323391e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell if (gcnum >= 0) 323491e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell mod_data.release = 0x0300 + gcnum; 32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 3236b6c63937001889af6fe431aaba97e59d04e028e7Arjan van de Ven WARNING(fsg, "controller '%s' not recognized\n", 32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->gadget->name); 32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.release = 0x0399; 32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot = simple_strtol(mod_data.protocol_parm, NULL, 0); 32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { 32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Use default setting 32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { 32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_type = USB_PR_CB; 32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name = "Control-Bulk"; 32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { 32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_type = USB_PR_CBI; 32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name = "Control-Bulk-Interrupt"; 32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); 32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || 32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_SCSI) { 32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Use default setting 32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || 32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_RBC) { 32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_RBC; 32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "RBC"; 32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || 32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || 32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_8020) { 32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_8020; 32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "8020i (ATAPI)"; 32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || 32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_QIC) { 32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_QIC; 32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "QIC-157"; 32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || 32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_UFI) { 32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_UFI; 32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "UFI"; 32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || 32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_8070) { 32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_8070; 32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "8070i"; 32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); 32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.buflen &= PAGE_CACHE_MASK; 32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.buflen <= 0) { 32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid buflen\n"); 32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ETOOSMALL; 32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 329287eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin 3293567064916e4fe32af81b89e473a1e4f40c64b27bMichal Nazarewicz#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 3294567064916e4fe32af81b89e473a1e4f40c64b27bMichal Nazarewicz 329587eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin /* Serial string handling. 329687eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin * On a real device, the serial string would be loaded 329787eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin * from permanent storage. */ 3298567064916e4fe32af81b89e473a1e4f40c64b27bMichal Nazarewicz if (mod_data.serial) { 329987eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin const char *ch; 330087eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin unsigned len = 0; 330187eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin 330287eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin /* Sanity check : 330387eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin * The CB[I] specification limits the serial string to 330487eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin * 12 uppercase hexadecimal characters. 330587eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin * BBB need at least 12 uppercase hexadecimal characters, 330687eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin * with a maximum of 126. */ 3307567064916e4fe32af81b89e473a1e4f40c64b27bMichal Nazarewicz for (ch = mod_data.serial; *ch; ++ch) { 330887eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin ++len; 330987eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin if ((*ch < '0' || *ch > '9') && 331087eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ 331187eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin WARNING(fsg, 3312d8087427ccefc0b3364735b96274375246fd452cAlan Stern "Invalid serial string character: %c\n", 331387eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin *ch); 3314d8087427ccefc0b3364735b96274375246fd452cAlan Stern goto no_serial; 331587eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin } 331687eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin } 331787eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin if (len > 126 || 331887eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin (mod_data.transport_type == USB_PR_BULK && len < 12) || 331987eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin (mod_data.transport_type != USB_PR_BULK && len > 12)) { 3320d8087427ccefc0b3364735b96274375246fd452cAlan Stern WARNING(fsg, "Invalid serial string length!\n"); 3321d8087427ccefc0b3364735b96274375246fd452cAlan Stern goto no_serial; 332287eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin } 3323567064916e4fe32af81b89e473a1e4f40c64b27bMichal Nazarewicz fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; 332487eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin } else { 3325d8087427ccefc0b3364735b96274375246fd452cAlan Stern WARNING(fsg, "No serial-number string provided!\n"); 3326d8087427ccefc0b3364735b96274375246fd452cAlan Stern no_serial: 3327d8087427ccefc0b3364735b96274375246fd452cAlan Stern device_desc.iSerialNumber = 0; 332887eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin } 332987eb1bead832b9880126fdbea74cc8ecb22b50c0Yann Cantin 33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3334e12995ec8f8d99f2a339541fc28998af2d60af0fMichal Nazarewiczstatic int __init fsg_bind(struct usb_gadget *gadget) 33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = the_fsg; 33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3339d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz struct fsg_lun *curlun; 33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *ep; 33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req; 33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *pathbuf, *p; 33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->gadget = gadget; 33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_gadget_data(gadget, fsg); 33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0 = gadget->ep0; 33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0->driver_data = fsg; 33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = check_parameters(fsg)) != 0) 33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.removable) { // Enable the store_xxx attributes 335312aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern dev_attr_file.attr.mode = 0644; 335493f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz dev_attr_file.store = fsg_store_file; 335512aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern if (!mod_data.cdrom) { 335612aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern dev_attr_ro.attr.mode = 0644; 335793f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz dev_attr_ro.store = fsg_store_ro; 335812aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern } 33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko /* Only for removable media? */ 3362a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko dev_attr_nofua.attr.mode = 0644; 3363a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko dev_attr_nofua.store = fsg_store_nofua; 3364a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko 33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find out how many LUNs there should be */ 33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = mod_data.nluns; 33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == 0) 33682e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell i = max(mod_data.num_filenames, 1u); 3369d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz if (i > FSG_MAX_LUNS) { 33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid number of LUNs: %d\n", i); 33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Create the LUNs, open their backing files, and register the 33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LUN devices in sysfs. */ 3377d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); 33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->luns) { 33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOMEM; 33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->nluns = i; 33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 3386e909ef5def59236b91fa9ee83446084eb6f48d1aMichal Nazarewicz curlun->cdrom = !!mod_data.cdrom; 3387e909ef5def59236b91fa9ee83446084eb6f48d1aMichal Nazarewicz curlun->ro = mod_data.cdrom || mod_data.ro[i]; 3388e909ef5def59236b91fa9ee83446084eb6f48d1aMichal Nazarewicz curlun->initially_ro = curlun->ro; 3389e909ef5def59236b91fa9ee83446084eb6f48d1aMichal Nazarewicz curlun->removable = mod_data.removable; 3390a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko curlun->nofua = mod_data.nofua[i]; 33912de9eaefa7330b8e3d3fc5f31288cb1e826173a8Alan Stern curlun->dev.release = lun_release; 33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->dev.parent = &gadget->dev; 33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->dev.driver = &fsg_driver.driver; 339493f937405bd5280ced9bf845f620d1de19b9bf7dMichal Nazarewicz dev_set_drvdata(&curlun->dev, &fsg->filesem); 33950031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers dev_set_name(&curlun->dev,"%s-lun%d", 33960031a06e2f07ab0d1bc98c31dbb6801f95f4bf01Kay Sievers dev_name(&gadget->dev), i); 33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3398d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz kref_get(&fsg->ref); 3399d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz rc = device_register(&curlun->dev); 3400d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz if (rc) { 34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFO(fsg, "failed to register LUN%d: %d\n", i, rc); 3402d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz put_device(&curlun->dev); 34032de9eaefa7330b8e3d3fc5f31288cb1e826173a8Alan Stern goto out; 34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34052de9eaefa7330b8e3d3fc5f31288cb1e826173a8Alan Stern curlun->registered = 1; 3406d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz 3407d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz rc = device_create_file(&curlun->dev, &dev_attr_ro); 3408d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz if (rc) 3409d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz goto out; 3410d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz rc = device_create_file(&curlun->dev, &dev_attr_nofua); 3411d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz if (rc) 3412d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz goto out; 3413d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz rc = device_create_file(&curlun->dev, &dev_attr_file); 3414d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz if (rc) 3415d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz goto out; 34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3417aafe5bd6ec341edfaf3233d272febbb8862a7251Alan Stern if (mod_data.file[i] && *mod_data.file[i]) { 3418d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz rc = fsg_lun_open(curlun, mod_data.file[i]); 3419d9385b6352da7fed50981f375c2ccb60354039a6Michal Nazarewicz if (rc) 34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!mod_data.removable) { 34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "no file given for LUN%d\n", i); 34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find all the endpoints we will use */ 34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_autoconfig_reset(gadget); 3430d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); 34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) 34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto autoconf_fail; 34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; // claim the endpoint 34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_in = ep; 34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3436d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); 34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) 34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto autoconf_fail; 34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; // claim the endpoint 34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_out = ep; 34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_cbi()) { 3443d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); 34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) 34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto autoconf_fail; 34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; // claim the endpoint 34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_in = ep; 34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fix up the descriptors */ 34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_desc.idVendor = cpu_to_le16(mod_data.vendor); 34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_desc.idProduct = cpu_to_le16(mod_data.product); 34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_desc.bcdDevice = cpu_to_le16(mod_data.release); 34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (transport_is_cbi() ? 3 : 2); // Number of endpoints 3456d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_intf_desc.bNumEndpoints = i; 3457d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; 3458d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; 3459d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; 34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34612e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell if (gadget_is_dualspeed(gadget)) { 3462d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; 34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34642e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell /* Assume endpoint addresses are the same for both speeds */ 3465d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_hs_bulk_in_desc.bEndpointAddress = 3466d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_fs_bulk_in_desc.bEndpointAddress; 3467d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_hs_bulk_out_desc.bEndpointAddress = 3468d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_fs_bulk_out_desc.bEndpointAddress; 3469d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_hs_intr_in_desc.bEndpointAddress = 3470d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_fs_intr_in_desc.bEndpointAddress; 34712e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell } 34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34734bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi if (gadget_is_superspeed(gadget)) { 34744bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi unsigned max_burst; 34754bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 34764bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL; 34774bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 34784bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi /* Calculate bMaxBurst, we know packet size is 1024 */ 34794bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi max_burst = min_t(unsigned, mod_data.buflen / 1024, 15); 34804bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 34814bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi /* Assume endpoint addresses are the same for both speeds */ 34824bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg_ss_bulk_in_desc.bEndpointAddress = 34834bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg_fs_bulk_in_desc.bEndpointAddress; 34844bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; 34854bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 34864bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg_ss_bulk_out_desc.bEndpointAddress = 34874bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg_fs_bulk_out_desc.bEndpointAddress; 34884bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; 34894bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi } 34904bb99b7c82bac1488a0228d2363db1f68d90f6f3Felipe Balbi 34912e806f67cc570d25395469a0ded0df8ffbd4d82fDavid Brownell if (gadget_is_otg(gadget)) 3492d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz fsg_otg_desc.bmAttributes |= USB_OTG_HNP; 34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOMEM; 34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the request and buffer for endpoint 0 */ 34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); 34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 35009d8bab58b758cd5a96d368a8cc64111c9ab50407David Brownell req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); 35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req->buf) 35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->complete = ep0_complete; 35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the data buffers */ 35066532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin for (i = 0; i < fsg_num_buffers; ++i) { 35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = &fsg->buffhds[i]; 35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 350914cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern /* Allocate for the bulk-in endpoint. We assume that 351014cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * the buffer will also work with the bulk-out (and 351114cd5f8e85e90c9dead2393377b9a2c23131e0ceAlan Stern * interrupt-in) endpoint. */ 35129d8bab58b758cd5a96d368a8cc64111c9ab50407David Brownell bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); 35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh->buf) 35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->next = bh + 1; 35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35176532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; 35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This should reflect the actual gadget power source */ 35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_set_selfpowered(gadget); 35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3522d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer, 3523d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz "%s %s with %s", 352496b644bdec977b97a45133e5b4466ba47a7a5e65Serge E. Hallyn init_utsname()->sysname, init_utsname()->release, 35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gadget->name); 35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 352722efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern fsg->thread_task = kthread_create(fsg_main_thread, fsg, 352822efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern "file-storage-gadget"); 352922efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern if (IS_ERR(fsg->thread_task)) { 353022efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern rc = PTR_ERR(fsg->thread_task); 35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 353222efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern } 35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); 3535664a51a81f6ba39db30cd7b7de61577ca0b2d20dAlan Stern INFO(fsg, "NOTE: This driver is deprecated. " 3536664a51a81f6ba39db30cd7b7de61577ca0b2d20dAlan Stern "Consider using g_mass_storage instead.\n"); 35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); 35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); 35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 3542d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz if (fsg_lun_is_open(curlun)) { 35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = NULL; 35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pathbuf) { 3545cf28b4863f9ee8f122e8ff3ac0d403e07ba9c6d9Jan Blunck p = d_path(&curlun->filp->f_path, 3546cf28b4863f9ee8f122e8ff3ac0d403e07ba9c6d9Jan Blunck pathbuf, PATH_MAX); 35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(p)) 35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = NULL; 35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3550a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", 3551a93917d39fc388c4761d2530af82513e2d3bf9f6Andy Shevchenko curlun->ro, curlun->nofua, (p ? p : "(error)")); 35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pathbuf); 35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "transport=%s (x%02x)\n", 35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name, mod_data.transport_type); 35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "protocol=%s (x%02x)\n", 35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name, mod_data.protocol_type); 35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", 35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.vendor, mod_data.product, mod_data.release); 356212aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", 35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.removable, mod_data.can_stall, 356412aae68a203e97a58d3f8237fc389201a4d9282dAlan Stern mod_data.cdrom, mod_data.buflen); 3565ba25f9dcc4ea6e30839fcab5a5516f2176d5bfedPavel Emelyanov DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); 3566a922c68732725866c88457026cf06a7620846506Alan Stern 3567a922c68732725866c88457026cf06a7620846506Alan Stern set_bit(REGISTERED, &fsg->atomic_bitflags); 3568a922c68732725866c88457026cf06a7620846506Alan Stern 3569a922c68732725866c88457026cf06a7620846506Alan Stern /* Tell the thread to start working */ 3570a922c68732725866c88457026cf06a7620846506Alan Stern wake_up_process(fsg->thread_task); 35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsautoconf_fail: 35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "unable to autoconfigure all endpoints\n"); 35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOTSUPP; 35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_TERMINATED; // The thread is dead 35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_unbind(gadget); 3580889394b1eb95f040525d06dd4f2f1222b94023e2Felipe Balbi complete(&fsg->thread_notifier); 35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsg_suspend(struct usb_gadget *gadget) 35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "suspend\n"); 35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(SUSPENDED, &fsg->atomic_bitflags); 35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsg_resume(struct usb_gadget *gadget) 35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "resume\n"); 36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(SUSPENDED, &fsg->atomic_bitflags); 36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_gadget_driver fsg_driver = { 36077177aed44f515d949f587170e0e177ce17e74793Michal Nazarewicz .max_speed = USB_SPEED_SUPER, 3608d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .function = (char *) fsg_string_product, 36096bea476cf628eb7bb18a036ac6a8fed1ad319951David Brownell .unbind = fsg_unbind, 36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = fsg_disconnect, 36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .setup = fsg_setup, 36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .suspend = fsg_suspend, 36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .resume = fsg_resume, 36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 3616d6181702f510302dce5666a50344b5acb196ab4eMichal Nazarewicz .name = DRIVER_NAME, 3617d0d5049fb02fc1082c17e08deecd6fed8db549b6Ben Dooks .owner = THIS_MODULE, 36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // .release = ... 36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // .suspend = ... 36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // .resume = ... 36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init fsg_alloc(void) 36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg; 36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36296532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin fsg = kzalloc(sizeof *fsg + 36306532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); 36316532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin 36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg) 36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&fsg->lock); 36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_rwsem(&fsg->filesem); 363687c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_init(&fsg->ref); 36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_completion(&fsg->thread_notifier); 36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_fsg = fsg; 36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init fsg_init(void) 36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg; 36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36496532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin rc = fsg_num_buffers_validate(); 36506532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin if (rc != 0) 36516532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin return rc; 36526532c7fdb2c3a2ec1b949ecd2ff5375069c1639aPer Forlin 36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = fsg_alloc()) != 0) 36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg = the_fsg; 3656b0fca50f5a94a268ed02cfddf44448051ed9343fUwe Kleine-König if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0) 365787c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_put(&fsg->ref, fsg_release); 3658a922c68732725866c88457026cf06a7620846506Alan Stern return rc; 36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(fsg_init); 36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit fsg_cleanup(void) 36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = the_fsg; 36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unregister the driver iff the thread hasn't already done so */ 36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) 36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_unregister_driver(&fsg_driver); 36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the thread to finish up */ 36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_for_completion(&fsg->thread_notifier); 36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 367487c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_put(&fsg->ref, fsg_release); 36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(fsg_cleanup); 3677