file_storage.c revision 87c4252a35310fdbb2aabb880a39b83f83cadf62
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file_storage.c -- File-backed USB Storage Gadget, for USB development 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2003-2005 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, 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * appearing to the host as a disk drive. In addition to providing an 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * example of a genuinely useful gadget driver for a USB device, it also 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * illustrates a technique of double-buffering for increased throughput. 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Last but not least, it gives an easy way to probe the behavior of the 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 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 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting the optional "ro" module parameter. The gadget will indicate that 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it has removable media if the optional "removable" module parameter is set. 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the optional "transport" module parameter. It also supports the 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the optional "protocol" module parameter. In addition, the default 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Vendor ID, Product ID, and release number can be overridden. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is support for multiple logical units (LUNs), each of which has 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * its own backing file. The number of LUNs can be set using the optional 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "luns" module parameter (anywhere from 1 to 8), and the corresponding 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * files are specified using comma-separated lists for "file" and "ro". 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The default number of LUNs is taken from the number of "file" elements; 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is 1 if "file" is not given. If "removable" is not set then a backing 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file must be specified for each LUN. If it is set, then an unspecified 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or empty backing filename means the LUN's medium is not loaded. 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Requirements are modest; only a bulk-in and a bulk-out endpoint are 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * needed (an interrupt-out endpoint is also needed for CBI). The memory 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requirement amounts to two 16K buffers, size configurable by a parameter. 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Support is included for both full-speed and high-speed operation. 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Module options: 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * file=filename[,filename...] 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Required if "removable" is not set, names of 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the files or block devices used for 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * backing storage 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ro=b[,b...] Default false, booleans for read-only access 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * removable Default false, boolean for removable media 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * luns=N Default N = number of filenames, number of 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LUNs to support 84d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * stall Default determined according to the type of 85d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * USB device controller (usually true), 86d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * boolean to permit the driver to halt 87d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * bulk endpoints 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transport=XXX Default BBB, transport name (CB, CBI, or BBB) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * protocol=YYY Default SCSI, protocol name (RBC, 8020 or 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ATAPI, QIC, UFI, 8070, or SCSI; 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * also 1 - 6) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * release=0xRRRR Override the USB release number (bcdDevice) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buflen=N Default N=16384, buffer size used (will be 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rounded down to a multiple of 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PAGE_CACHE_SIZE) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", 100d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * "removable", "luns", and "stall" options are available; default values 101d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern * are used for everything else. 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The pathnames of the backing files and the ro settings are available in 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the attribute files "file" and "ro" in the lun<n> subdirectory of the 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gadget's sysfs directory. If the "removable" option is set, writing to 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these files will simulate ejecting/loading the medium (writing an empty 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * line means eject) and adjusting a write-enable tab. Changes to the ro 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting are not allowed when the medium is loaded. 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This gadget driver is heavily based on "Gadget Zero" by David Brownell. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver Design 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The FSG driver is fairly straightforward. There is a main kernel 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread that handles most of the work. Interrupt routines field 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * callbacks from the controller driver: bulk- and interrupt-request 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * completion notifications, endpoint-0 events, and disconnect events. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Completion events are passed to the main thread by wakeup calls. Many 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ep0 requests are handled at interrupt time, but SetInterface, 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SetConfiguration, and device reset requests are forwarded to the 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread in the form of "exceptions" using SIGUSR1 signals (since they 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * should interrupt any ongoing file I/O operations). 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The thread's main routine implements the standard command/data/status 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parts of a SCSI interaction. It and its subroutines are full of tests 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for pending signals/exceptions -- all this polling is necessary since 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the kernel has no setjmp/longjmp equivalents. (Maybe this is an 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * indication that the driver really wants to be running in userspace.) 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * An important point is that so long as the thread is alive it keeps an 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * open reference to the backing file. This will prevent unmounting 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the backing file's underlying filesystem and could cause problems 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * during system shutdown, for example. To prevent such problems, the 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread catches INT, TERM, and KILL signals and converts them into 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an EXIT exception. 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In normal operation the main thread is started during the gadget's 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fsg_bind() callback and stopped during fsg_unbind(). But it can also 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exit when it receives a signal, and there's no point leaving the 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gadget running when the thread is dead. So just before the thread 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exits, it deregisters the gadget driver. This makes things a little 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tricky: The driver is deregistered at two places, and the exiting 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread can indirectly call fsg_unbind() which in turn can tell the 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * thread to exit. The first problem is resolved through the use of the 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * REGISTERED atomic bitflag; the driver will only be deregistered once. 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The second problem is resolved by having fsg_unbind() check 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fsg->state; it won't try to stop the thread if the state is already 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FSG_STATE_TERMINATED. 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To provide maximum throughput, the driver uses a circular pipeline of 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer heads (struct fsg_buffhd). In principle the pipeline can be 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arbitrarily long; in practice the benefits don't justify having more 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than 2 stages (i.e., double buffering). But it helps to think of the 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pipeline as being a long one. Each buffer head contains a bulk-in and 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a bulk-out request pointer (since the buffer can be used for both 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * output and input -- directions always are given from the host's 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * point of view) as well as a pointer to the buffer and various state 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * variables. 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use of the pipeline follows a simple protocol. There is a variable 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * At any time that buffer head may still be in use from an earlier 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request, so each buffer head has a state variable indicating whether 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * buffer head to be EMPTY, filling the buffer either by file I/O or by 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB I/O (during which the buffer head is BUSY), and marking the buffer 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * head FULL when the I/O is complete. Then the buffer will be emptied 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (again possibly by USB I/O, during which it is marked BUSY) and 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * finally marked EMPTY again (possibly by a completion routine). 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A module parameter tells the driver to avoid stalling the bulk 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * endpoints wherever the transport specification allows. This is 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * necessary for some UDCs like the SuperH, which cannot reliably clear a 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * halt on a bulk endpoint. However, under certain circumstances the 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bulk-only specification requires a stall. In such cases the driver 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will halt the endpoint and set a flag indicating that it should clear 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the halt in software during the next device reset. Hopefully this 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will permit everything to work correctly. Furthermore, although the 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specification allows the bulk-out endpoint to halt when the host sends 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * too much data, implementing this would cause an unavoidable race. 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The driver will always use the "no-stall" approach for OUT transfers. 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * One subtle point concerns sending status-stage responses for ep0 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requests. Some of these requests, such as device reset, can involve 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupting an ongoing file I/O operation, which might take an 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arbitrarily long time. During that delay the host might give up on 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the original ep0 request and issue a new one. When that happens the 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver should not notify the host about completion of the original 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * request, as the host will no longer be waiting for it. So the driver 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assigns to each ep0 request a unique tag, and it keeps track of the 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tag value of the request associated with a long-running exception 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (device-reset, interface-change, or configuration-change). When the 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exception handler is finished, the status-stage response is submitted 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * only if the current ep0 request tag is equal to the exception request 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tag. Thus only the most recently received ep0 request will get a 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * status-stage response. 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Warning: This driver source file is too long. It ought to be split up 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into a header file plus about 3 separate .c files, to handle the details 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the Gadget, USB Mass Storage, and SCSI protocols. 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef VERBOSE 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DUMP_MSGS 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h> 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/compiler.h> 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/completion.h> 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dcache.h> 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h> 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/file.h> 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 22787c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern#include <linux/kref.h> 22822efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern#include <linux/kthread.h> 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/limits.h> 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pagemap.h> 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rwsem.h> 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h> 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/suspend.h> 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/utsname.h> 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wait.h> 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb_ch9.h> 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/usb_gadget.h> 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "gadget_chips.h" 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_DESC "File-backed Storage Gadget" 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_NAME "g_file_storage" 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VERSION "20 October 2004" 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char longname[] = DRIVER_DESC; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char shortname[] = DRIVER_NAME; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(DRIVER_DESC); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Alan Stern"); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("Dual BSD/GPL"); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Thanks to NetChip Technologies for donating this product ID. 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DO NOT REUSE THESE IDs with any other driver!! Ever!! 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Instead: allocate your own, using normal USB-IF procedures. */ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_VENDOR_ID 0x0525 // NetChip 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRIVER_PRODUCT_ID 0xa4a5 // Linux-USB File-backed Storage Gadget 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver assumes self-powered hardware and has no way for users to 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * trigger remote wakeup. It uses autoconfiguration to select endpoints 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and endpoint addresses. 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define xprintk(f,level,fmt,args...) \ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_printk(level , &(f)->gadget->dev , fmt , ## args) 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define yprintk(l,level,fmt,args...) \ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_printk(level , &(l)->dev , fmt , ## args) 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(fsg,fmt,args...) \ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xprintk(fsg , KERN_DEBUG , fmt , ## args) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LDBG(lun,fmt,args...) \ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds yprintk(lun , KERN_DEBUG , fmt , ## args) 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDBG(fmt,args...) \ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args) 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG(fsg,fmt,args...) \ 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { } while (0) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LDBG(lun,fmt,args...) \ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { } while (0) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MDBG(fmt,args...) \ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { } while (0) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef VERBOSE 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DUMP_MSGS 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* DEBUG */ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef VERBOSE 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VDBG DBG 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VLDBG LDBG 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VDBG(fsg,fmt,args...) \ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { } while (0) 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VLDBG(lun,fmt,args...) \ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { } while (0) 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* VERBOSE */ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ERROR(fsg,fmt,args...) \ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xprintk(fsg , KERN_ERR , fmt , ## args) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LERROR(lun,fmt,args...) \ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds yprintk(lun , KERN_ERR , fmt , ## args) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WARN(fsg,fmt,args...) \ 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xprintk(fsg , KERN_WARNING , fmt , ## args) 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LWARN(lun,fmt,args...) \ 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds yprintk(lun , KERN_WARNING , fmt , ## args) 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INFO(fsg,fmt,args...) \ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xprintk(fsg , KERN_INFO , fmt , ## args) 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINFO(lun,fmt,args...) \ 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds yprintk(lun , KERN_INFO , fmt , ## args) 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MINFO(fmt,args...) \ 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DRIVER_NAME ": " fmt , ## args) 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Encapsulate the module parameter settings */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_LUNS 8 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Arggh! There should be a module_param_array_named macro! */ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *file[MAX_LUNS] = {NULL, }; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ro[MAX_LUNS] = {0, }; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct { 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_filenames; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_ros; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nluns; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 347d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern int removable; 348d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern int can_stall; 349d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *transport_parm; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *protocol_parm; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short vendor; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short product; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short release; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int buflen; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int transport_type; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *transport_name; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int protocol_type; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *protocol_name; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} mod_data = { // Default values 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .transport_parm = "BBB", 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .protocol_parm = "SCSI", 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .removable = 0, 366d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern .can_stall = 1, 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .vendor = DRIVER_VENDOR_ID, 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .product = DRIVER_PRODUCT_ID, 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = 0xffff, // Use controller chip type 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .buflen = 16384, 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(file, charp, &mod_data.num_filenames, S_IRUGO); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(file, "names of backing files or devices"); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_array(ro, bool, &mod_data.num_ros, S_IRUGO); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(ro, "true to force read-only"); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(luns, mod_data.nluns, uint, S_IRUGO); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(luns, "number of LUNs"); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(removable, mod_data.removable, bool, S_IRUGO); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(removable, "true to simulate removable media"); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 386d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Sternmodule_param_named(stall, mod_data.can_stall, bool, S_IRUGO); 387d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan SternMODULE_PARM_DESC(stall, "false to prevent bulk stalls"); 388d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* In the non-TEST version, only the module parameters listed above 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are available. */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "8070, or SCSI)"); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(vendor, "USB Vendor ID"); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(product, mod_data.product, ushort, S_IRUGO); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(product, "USB Product ID"); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(release, mod_data.release, ushort, S_IRUGO); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(release, "USB release number"); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param_named(buflen, mod_data.buflen, uint, S_IRUGO); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(buflen, "I/O buffer size"); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* USB protocol value = the transport method */ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_PR_BULK 0x50 // Bulk-only 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* USB subclass value = the protocol encapsulation */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_SC_RBC 0x01 // Reduced Block Commands (flash) 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_SC_8020 0x02 // SFF-8020i, MMC-2, ATAPI (CD-ROM) 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_SC_QIC 0x03 // QIC-157 (tape) 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_SC_UFI 0x04 // UFI (floppy) 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_SC_8070 0x05 // SFF-8070i (removable) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_SC_SCSI 0x06 // Transparent SCSI 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bulk-only data structures */ 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Command Block Wrapper */ 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct bulk_cb_wrap { 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le32 Signature; // Contains 'USBC' 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 Tag; // Unique per command id 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le32 DataTransferLength; // Size of the data 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 Flags; // Direction in bit 7 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 Lun; // LUN (normally 0) 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 Length; // Of the CDB, <= MAX_COMMAND_SIZE 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 CDB[16]; // Command Data Block 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_BULK_CB_WRAP_LEN 31 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_BULK_CB_SIG 0x43425355 // Spells out USBC 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_BULK_IN_FLAG 0x80 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Command Status Wrapper */ 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct bulk_cs_wrap { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le32 Signature; // Should = 'USBS' 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 Tag; // Same as original command 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __le32 Residue; // Amount not transferred 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 Status; // See below 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_BULK_CS_WRAP_LEN 13 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_BULK_CS_SIG 0x53425355 // Spells out 'USBS' 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_STATUS_PASS 0 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_STATUS_FAIL 1 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_STATUS_PHASE_ERROR 2 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bulk-only class specific requests */ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_BULK_RESET_REQUEST 0xff 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CBI Interrupt data structure */ 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct interrupt_data { 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 bType; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 bValue; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CBI_INTERRUPT_DATA_LEN 2 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CBI Accept Device-Specific Command request */ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define USB_CBI_ADSC_REQUEST 0x00 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_COMMAND_SIZE 16 // Length of a SCSI Command Data Block 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SCSI commands that we recognize */ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_FORMAT_UNIT 0x04 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_INQUIRY 0x12 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_MODE_SELECT_6 0x15 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_MODE_SELECT_10 0x55 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_MODE_SENSE_6 0x1a 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_MODE_SENSE_10 0x5a 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_READ_6 0x08 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_READ_10 0x28 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_READ_12 0xa8 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_READ_CAPACITY 0x25 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_READ_FORMAT_CAPACITIES 0x23 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_RELEASE 0x17 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_REQUEST_SENSE 0x03 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_RESERVE 0x16 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_SEND_DIAGNOSTIC 0x1d 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_START_STOP_UNIT 0x1b 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_SYNCHRONIZE_CACHE 0x35 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_TEST_UNIT_READY 0x00 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_VERIFY 0x2f 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_WRITE_6 0x0a 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_WRITE_10 0x2a 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SC_WRITE_12 0xaa 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_NO_SENSE 0 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_COMMUNICATION_FAILURE 0x040800 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_INVALID_COMMAND 0x052000 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_INVALID_FIELD_IN_CDB 0x052400 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_MEDIUM_NOT_PRESENT 0x023a00 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_RESET_OCCURRED 0x062900 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_UNRECOVERED_READ_ERROR 0x031100 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_WRITE_ERROR 0x030c02 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SS_WRITE_PROTECTED 0x072700 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SK(x) ((u8) ((x) >> 16)) // Sense Key byte, etc. 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASC(x) ((u8) ((x) >> 8)) 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ASCQ(x) ((u8) (x)) 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These definitions will permit the compiler to avoid generating code for 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * parts of the driver that aren't used in the non-TEST version. Even gcc 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can recognize when a test of a constant expression yields a dead code 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * path. 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_bbb() 1 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define transport_is_cbi() 0 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define protocol_is_scsi() 1 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lun { 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file *filp; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t file_length; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t num_sectors; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ro : 1; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int prevent_medium_removal : 1; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int registered : 1; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 sense_data; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 sense_data_info; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 unit_attention_data; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct device dev; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define backing_file_is_open(curlun) ((curlun)->filp != NULL) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct lun *dev_to_lun(struct device *dev) 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return container_of(dev, struct lun, dev); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Big enough to hold our biggest descriptor */ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EP0_BUFSIZE 256 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DELAYED_STATUS (EP0_BUFSIZE + 999) // An impossibly large value 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Number of buffers we will use. 2 is enough for double-buffering */ 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NUM_BUFFERS 2 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum fsg_buffer_state { 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUF_STATE_EMPTY = 0, 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUF_STATE_FULL, 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUF_STATE_BUSY 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct fsg_buffhd { 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *buf; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t dma; 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile enum fsg_buffer_state state; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *next; 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The NetChip 2280 is faster, and handles some protocol faults 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * better, if we don't submit any short bulk-out read requests. 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So we will record the intended request length here. */ 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bulk_out_intended_length; 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *inreq; 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile int inreq_busy; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *outreq; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile int outreq_busy; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum fsg_state { 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_COMMAND_PHASE = -10, // This one isn't used anywhere 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_DATA_PHASE, 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_STATUS_PHASE, 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_IDLE = 0, 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_ABORT_BULK_OUT, 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_RESET, 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_INTERFACE_CHANGE, 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_CONFIG_CHANGE, 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_DISCONNECT, 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_EXIT, 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FSG_STATE_TERMINATED 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum data_direction { 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DATA_DIR_UNKNOWN = 0, 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DATA_DIR_FROM_HOST, 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DATA_DIR_TO_HOST, 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DATA_DIR_NONE 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct fsg_dev { 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_gadget *gadget; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* filesem protects: backing files in use */ 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct rw_semaphore filesem; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63587c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern /* reference counting: wait until all LUNs are released */ 63687c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern struct kref ref; 63787c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *ep0; // Handy copy of gadget->ep0 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *ep0req; // For control responses 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile unsigned int ep0_req_tag; 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *ep0req_name; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *intreq; // For interrupt responses 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile int intreq_busy; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *intr_buffhd; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bulk_out_maxpacket; 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum fsg_state state; // For exception handling 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int exception_req_tag; 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 config, new_config; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int running : 1; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bulk_in_enabled : 1; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bulk_out_enabled : 1; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int intr_in_enabled : 1; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int phase_error : 1; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int short_packet_received : 1; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bad_lun_okay : 1; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long atomic_bitflags; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define REGISTERED 0 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CLEAR_BULK_HALTS 1 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SUSPENDED 2 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *bulk_in; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *bulk_out; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *intr_in; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *next_buffhd_to_fill; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *next_buffhd_to_drain; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd buffhds[NUM_BUFFERS]; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_queue_head_t thread_wqh; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int thread_wakeup_needed; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct completion thread_notifier; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct task_struct *thread_task; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigset_t thread_signal_mask; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cmnd_size; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 cmnd[MAX_COMMAND_SIZE]; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum data_direction data_dir; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 data_size; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 data_size_from_cmnd; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tag; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int lun; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 residue; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 usb_amount_left; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The CB protocol offers no way for a host to know when a command 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has completed. As a result the next command may arrive early, 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and we will still have to handle it. For that reason we need 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a buffer to store new commands when using CB (or CBI, which 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not oblige a host to wait for command completion either). */ 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cbbuf_cmnd_size; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int nluns; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *luns; 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef void (*fsg_routine_t)(struct fsg_dev *); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int inline exception_in_progress(struct fsg_dev *fsg) 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (fsg->state > FSG_STATE_IDLE); 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Make bulk-out requests be divisible by the maxpacket size */ 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void inline set_bulk_out_req_length(struct fsg_dev *fsg, 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh, unsigned int length) 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int rem; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->bulk_out_intended_length = length; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rem = length % fsg->bulk_out_maxpacket; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rem > 0) 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length += fsg->bulk_out_maxpacket - rem; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq->length = length; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fsg_dev *the_fsg; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_gadget_driver fsg_driver; 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void close_backing_file(struct lun *curlun); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void close_all_backing_files(struct fsg_dev *fsg); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DUMP_MSGS 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dump_msg(struct fsg_dev *fsg, const char *label, 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u8 *buf, unsigned int length) 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int start, num, i; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char line[52], *p; 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (length >= 512) 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "%s, length %u:\n", label, length); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = 0; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (length > 0) { 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num = min(length, 16u); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = line; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < num; ++i) { 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == 8) 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p++ = ' '; 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(p, " %02x", buf[i]); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p += 3; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *p = 0; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%6x: %s\n", start, line); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += num; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start += num; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length -= num; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void inline dump_cdb(struct fsg_dev *fsg) 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{} 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void inline dump_msg(struct fsg_dev *fsg, const char *label, 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u8 *buf, unsigned int length) 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{} 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void inline dump_cdb(struct fsg_dev *fsg) 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char cmdbuf[3*MAX_COMMAND_SIZE + 1]; 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->cmnd_size; ++i) 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "SCSI CDB: %s\n", cmdbuf); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* DUMP_MSGS */ 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *name; 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == fsg->bulk_in) 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "bulk-in"; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep == fsg->bulk_out) 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "bulk-out"; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = ep->name; 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "%s set halt\n", name); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return usb_ep_set_halt(ep); 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Routines for unaligned data access */ 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 inline get_be16(u8 *buf) 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((u16) buf[0] << 8) | ((u16) buf[1]); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 inline get_be32(u8 *buf) 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((u32) buf[2] << 8) | ((u32) buf[3]); 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void inline put_be16(u8 *buf, u16 val) 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = val >> 8; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = val; 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void inline put_be32(u8 *buf, u32 val) 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = val >> 24; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = val >> 16; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = val >> 8; 8251bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell buf[3] = val & 0xff; 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DESCRIPTORS ... most are static, but strings and (full) configuration 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * descriptors are built on demand. Also the (static) config and interface 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * descriptors are adjusted during fsg_bind(). 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STRING_MANUFACTURER 1 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STRING_PRODUCT 2 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STRING_SERIAL 3 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STRING_CONFIG 4 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STRING_INTERFACE 5 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* There is only one configuration. */ 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG_VALUE 1 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_device_descriptor 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_desc = { 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof device_desc, 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_DEVICE, 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bcdUSB = __constant_cpu_to_le16(0x0200), 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDeviceClass = USB_CLASS_PER_INTERFACE, 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The next three values can be overridden by module parameters */ 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bcdDevice = __constant_cpu_to_le16(0xffff), 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .iManufacturer = STRING_MANUFACTURER, 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .iProduct = STRING_PRODUCT, 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .iSerialNumber = STRING_SERIAL, 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bNumConfigurations = 1, 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_config_descriptor 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsconfig_desc = { 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof config_desc, 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_CONFIG, 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wTotalLength computed by usb_gadget_config_buf() */ 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bNumInterfaces = 1, 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bConfigurationValue = CONFIG_VALUE, 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .iConfiguration = STRING_CONFIG, 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bMaxPower = 1, // self-powered 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_otg_descriptor 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsotg_desc = { 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof(otg_desc), 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_OTG, 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_OTG_SRP, 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* There is only one interface. */ 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_interface_descriptor 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsintf_desc = { 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof intf_desc, 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_INTERFACE, 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bNumEndpoints = 2, // Adjusted during fsg_bind() 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterfaceClass = USB_CLASS_MASS_STORAGE, 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterfaceSubClass = USB_SC_SCSI, // Adjusted during fsg_bind() 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterfaceProtocol = USB_PR_BULK, // Adjusted during fsg_bind() 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .iInterface = STRING_INTERFACE, 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Three full-speed endpoint descriptors: bulk-in, bulk-out, 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and interrupt-in. */ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_endpoint_descriptor 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfs_bulk_in_desc = { 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = USB_DT_ENDPOINT_SIZE, 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_ENDPOINT, 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bEndpointAddress = USB_DIR_IN, 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_ENDPOINT_XFER_BULK, 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wMaxPacketSize set by autoconfiguration */ 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_endpoint_descriptor 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfs_bulk_out_desc = { 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = USB_DT_ENDPOINT_SIZE, 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_ENDPOINT, 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bEndpointAddress = USB_DIR_OUT, 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_ENDPOINT_XFER_BULK, 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wMaxPacketSize set by autoconfiguration */ 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_endpoint_descriptor 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfs_intr_in_desc = { 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = USB_DT_ENDPOINT_SIZE, 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_ENDPOINT, 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bEndpointAddress = USB_DIR_IN, 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_ENDPOINT_XFER_INT, 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wMaxPacketSize = __constant_cpu_to_le16(2), 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterval = 32, // frames -> 32 ms 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_descriptor_header *fs_function[] = { 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &otg_desc, 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &intf_desc, 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &fs_bulk_in_desc, 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &fs_bulk_out_desc, 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &fs_intr_in_desc, 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL, 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FS_FUNCTION_PRE_EP_ENTRIES 2 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_GADGET_DUALSPEED 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USB 2.0 devices need to expose both high speed and full speed 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * descriptors, unless they only run at full speed. 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * That means alternate endpoint descriptors (bigger packets) 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and a "device qualifier" ... plus more construction options 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for the config descriptor. 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_qualifier_descriptor 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdev_qualifier = { 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = sizeof dev_qualifier, 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_DEVICE_QUALIFIER, 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bcdUSB = __constant_cpu_to_le16(0x0200), 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDeviceClass = USB_CLASS_PER_INTERFACE, 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bNumConfigurations = 1, 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_endpoint_descriptor 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshs_bulk_in_desc = { 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = USB_DT_ENDPOINT_SIZE, 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_ENDPOINT, 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_ENDPOINT_XFER_BULK, 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wMaxPacketSize = __constant_cpu_to_le16(512), 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_endpoint_descriptor 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshs_bulk_out_desc = { 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = USB_DT_ENDPOINT_SIZE, 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_ENDPOINT, 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_ENDPOINT_XFER_BULK, 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wMaxPacketSize = __constant_cpu_to_le16(512), 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterval = 1, // NAK every 1 uframe 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_endpoint_descriptor 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshs_intr_in_desc = { 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = USB_DT_ENDPOINT_SIZE, 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_ENDPOINT, 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bmAttributes = USB_ENDPOINT_XFER_INT, 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .wMaxPacketSize = __constant_cpu_to_le16(2), 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bInterval = 9, // 2**(9-1) = 256 uframes -> 32 ms 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct usb_descriptor_header *hs_function[] = { 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &otg_desc, 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &intf_desc, 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &hs_bulk_in_desc, 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &hs_bulk_out_desc, 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (struct usb_descriptor_header *) &hs_intr_in_desc, 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL, 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HS_FUNCTION_PRE_EP_ENTRIES 2 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Maxpacket and other transfer characteristics vary by speed. */ 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs)) 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If there's no high speed support, always use the full-speed descriptor. */ 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ep_desc(g,fs,hs) fs 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* !CONFIG_USB_GADGET_DUALSPEED */ 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The CBI specification limits the serial string to 12 uppercase hexadecimal 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * characters. */ 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char manufacturer[64]; 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char serial[13]; 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_string strings[] = { 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {STRING_MANUFACTURER, manufacturer}, 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {STRING_PRODUCT, longname}, 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {STRING_SERIAL, serial}, 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {STRING_CONFIG, "Self-powered"}, 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {STRING_INTERFACE, "Mass Storage"}, 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {} 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_gadget_strings stringtab = { 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .language = 0x0409, // en-us 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .strings = strings, 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Config descriptors must agree with the code that sets configurations 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and with code managing interfaces and their altsettings. They must 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * also handle different speeds and other-speed requests. 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int populate_config_buf(struct usb_gadget *gadget, 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf, u8 type, unsigned index) 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_GADGET_DUALSPEED 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum usb_device_speed speed = gadget->speed; 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len; 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_descriptor_header **function; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (index > 0) 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_GADGET_DUALSPEED 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == USB_DT_OTHER_SPEED_CONFIG) 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (speed == USB_SPEED_HIGH) 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function = hs_function; 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function = fs_function; 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* for now, don't advertise srp-only devices */ 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!gadget->is_otg) 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds function++; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((struct usb_config_descriptor *) buf)->bDescriptorType = type; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These routines may be called in process context or in_irq */ 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void wakeup_thread(struct fsg_dev *fsg) 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tell the main thread that something has happened */ 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->thread_wakeup_needed = 1; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_all(&fsg->thread_wqh); 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Do nothing if a higher-priority exception is already in progress. 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a lower-or-equal priority exception is in progress, preempt it 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and notify the main thread by sending it a signal. */ 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&fsg->lock, flags); 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->state <= new_state) { 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->exception_req_tag = fsg->ep0_req_tag; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = new_state; 109822efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern if (fsg->thread_task) 109922efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern send_sig_info(SIGUSR1, SEND_SIG_FORCED, 110022efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern fsg->thread_task); 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&fsg->lock, flags); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The disconnect callback and ep0 routines. These always run in_irq, 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * except that ep0_queue() is called in the main thread to acknowledge 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * completion of various requests: set config, set interface, and 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bulk-only device reset. */ 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsg_disconnect(struct usb_gadget *gadget) 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "disconnect or port reset\n"); 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_DISCONNECT); 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ep0_queue(struct fsg_dev *fsg) 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0 && rc != -ESHUTDOWN) { 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't do much more than wait for a reset */ 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN(fsg, "error in submission: %s --> %d\n", 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0->name, rc); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ep0_complete(struct usb_ep *ep, struct usb_request *req) 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->actual > 0) 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->actual != req->length) 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->status, req->actual, req->length); 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == 0 && req->context) 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((fsg_routine_t) (req->context))(fsg); 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bulk and interrupt endpoint completion handlers. 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These always run in_irq. */ 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->actual != req->length) 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->status, req->actual, req->length); 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hold the lock while we update the request and buffer states */ 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq_busy = 0; 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&fsg->lock); 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "bulk-out", req->buf, req->actual); 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->actual != bh->bulk_out_intended_length) 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->status, req->actual, 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->bulk_out_intended_length); 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hold the lock while we update the request and buffer states */ 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq_busy = 0; 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&fsg->lock); 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void intr_in_complete(struct usb_ep *ep, struct usb_request *req) 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data; 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context; 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->actual != req->length) 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__, 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->status, req->actual, req->length); 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status == -ECONNRESET) // Request was cancelled 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(ep); 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hold the lock while we update the request and buffer states */ 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq_busy = 0; 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&fsg->lock); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void intr_in_complete(struct usb_ep *ep, struct usb_request *req) 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{} 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ep0 class-specific handlers. These always run in_irq. */ 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static u8 cbi_reset_cmnd[6] = { 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Error in command transfer? */ 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status || req->length != req->actual || 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Not all controllers allow a protocol stall after 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * receiving control-out data, but we'll try anyway. */ 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->ep0); 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; // Wait for reset 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is it the special reset command? */ 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->actual >= sizeof cbi_reset_cmnd && 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcmp(req->buf, cbi_reset_cmnd, 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof cbi_reset_cmnd) == 0) { 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to stop the current operation 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and reinitialize our state. */ 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "cbi reset request\n"); 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_RESET); 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "CB[I] accept device-specific command\n"); 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&fsg->lock); 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Save the command for later */ 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cbbuf_cmnd_size) 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN(fsg, "CB[I] overwriting previous command\n"); 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cbbuf_cmnd_size = req->actual; 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&fsg->lock); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wakeup_thread(fsg); 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{} 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int class_setup_req(struct fsg_dev *fsg, 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_ctrlrequest *ctrl) 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = -EOPNOTSUPP; 12821bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_index = le16_to_cpu(ctrl->wIndex); 12831bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_length = le16_to_cpu(ctrl->wLength); 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->config) 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return value; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle Bulk-only class-specific requests */ 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ctrl->bRequest) { 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_BULK_RESET_REQUEST: 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT | 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_TYPE_CLASS | USB_RECIP_INTERFACE)) 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_index != 0) { 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to stop the current operation 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and reinitialize our state. */ 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "bulk reset request\n"); 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_RESET); 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = DELAYED_STATUS; 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_BULK_GET_MAX_LUN_REQUEST: 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_TYPE_CLASS | USB_RECIP_INTERFACE)) 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_index != 0) { 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get max LUN\n"); 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(u8 *) req->buf = fsg->nluns - 1; 131876f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = 1; 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Handle CBI class-specific requests */ 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ctrl->bRequest) { 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_CBI_ADSC_REQUEST: 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT | 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_TYPE_CLASS | USB_RECIP_INTERFACE)) 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_index != 0) { 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_length > MAX_COMMAND_SIZE) { 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EOVERFLOW; 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = w_length; 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->context = received_cbi_adsc; 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == -EOPNOTSUPP) 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "unknown class-specific control req " 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%02x.%02x v%04x i%04x l%u\n", 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl->bRequestType, ctrl->bRequest, 13501bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell le16_to_cpu(ctrl->wValue), w_index, w_length); 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return value; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Ep0 standard request handlers. These always run in_irq. */ 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int standard_setup_req(struct fsg_dev *fsg, 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_ctrlrequest *ctrl) 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int value = -EOPNOTSUPP; 13641bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_index = le16_to_cpu(ctrl->wIndex); 13651bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell u16 w_value = le16_to_cpu(ctrl->wValue); 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Usually this just stores reply data in the pre-allocated ep0 buffer, 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but config change events will also reconfigure hardware. */ 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (ctrl->bRequest) { 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_DESCRIPTOR: 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_DEVICE)) 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (w_value >> 8) { 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_DEVICE: 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get device descriptor\n"); 137976f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = sizeof device_desc; 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(req->buf, &device_desc, value); 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_GADGET_DUALSPEED 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_DEVICE_QUALIFIER: 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get device qualifier\n"); 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->gadget->is_dualspeed) 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 138776f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = sizeof dev_qualifier; 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(req->buf, &dev_qualifier, value); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_OTHER_SPEED_CONFIG: 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get other-speed config descriptor\n"); 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->gadget->is_dualspeed) 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto get_config; 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_CONFIG: 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get configuration descriptor\n"); 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_GADGET_DUALSPEED 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_config: 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = populate_config_buf(fsg->gadget, 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->buf, 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_value >> 8, 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_value & 0xff); 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_DT_STRING: 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get string descriptor\n"); 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wIndex == language code */ 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = usb_gadget_get_string(&stringtab, 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w_value & 0xff, req->buf); 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* One config, two speeds */ 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_CONFIGURATION: 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_DEVICE)) 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "set configuration\n"); 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_value == CONFIG_VALUE || w_value == 0) { 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->new_config = w_value; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to wipe out previous transaction 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state (queued bufs, etc) and set the new config. */ 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = DELAYED_STATUS; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_CONFIGURATION: 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_DEVICE)) 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get configuration\n"); 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(u8 *) req->buf = fsg->config; 143976f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = 1; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_SET_INTERFACE: 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_INTERFACE)) 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->config && w_index == 0) { 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Raise an exception to wipe out previous transaction 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state (queued bufs, etc) and install the new 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interface altsetting. */ 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = DELAYED_STATUS; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_REQ_GET_INTERFACE: 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_RECIP_INTERFACE)) 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->config) 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w_index != 0) { 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = -EDOM; 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "get interface\n"); 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *(u8 *) req->buf = 0; 146776f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern value = 1; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "unknown control req %02x.%02x v%04x i%04x l%u\n", 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl->bRequestType, ctrl->bRequest, 14741bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell w_value, w_index, le16_to_cpu(ctrl->wLength)); 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return value; 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fsg_setup(struct usb_gadget *gadget, 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_ctrlrequest *ctrl) 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 14861bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell int w_length = le16_to_cpu(ctrl->wLength); 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++fsg->ep0_req_tag; // Record arrival of a new request 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->context = NULL; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->length = 0; 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = class_setup_req(fsg, ctrl); 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = standard_setup_req(fsg, ctrl); 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Respond with data/status or defer until later? */ 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc >= 0 && rc != DELAYED_STATUS) { 150076f4af8efc72b6091d230cbe718cedca06d2d79eAlan Stern rc = min(rc, w_length); 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req->length = rc; 15021bbc169621cbe502b9143a27eb12802a0f1d43a0David Brownell fsg->ep0req->zero = rc < w_length; 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ep0-in" : "ep0-out"); 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = ep0_queue(fsg); 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Device either stalls (rc < 0) or reports success */ 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* All the following routines run in process context */ 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Use this for bulk or interrupt transfers, not ep0 */ 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req, volatile int *pbusy, 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile enum fsg_buffer_state *state) 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ep == fsg->bulk_in) 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "bulk-in", req->buf, req->length); 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ep == fsg->intr_in) 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_msg(fsg, "intr-in", req->buf, req->length); 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pbusy = 1; 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *state = BUF_STATE_BUSY; 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = usb_ep_queue(ep, req, GFP_KERNEL); 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0) { 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *pbusy = 0; 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *state = BUF_STATE_EMPTY; 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't do much more than wait for a reset */ 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Note: currently the net2280 driver fails zero-length 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * submissions if DMA is enabled. */ 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->length == 0)) 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN(fsg, "error in submission: %s --> %d\n", 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->name, rc); 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sleep_thread(struct fsg_dev *fsg) 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait until a signal arrives or we are woken up */ 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = wait_event_interruptible(fsg->thread_wqh, 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->thread_wakeup_needed); 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->thread_wakeup_needed = 0; 15563e1d1d28d99dabe63c64f7f40f1ca1d646de1f73Christoph Lameter try_to_freeze(); 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (rc ? -EINTR : 0); 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read(struct fsg_dev *fsg) 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 lba; 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount_left; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t file_offset, file_offset_tmp; 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int amount; 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int partial_page; 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t nread; 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the starting Logical Block Address and check that it's 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not too big */ 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[0] == SC_READ_6) 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lba = get_be32(&fsg->cmnd[2]); 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We allow DPO (Disable Page Out = don't save data in the 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache) and FUA (Force Unit Access = don't read from the 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache), but we don't implement them. */ 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x18) != 0) { 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lba >= curlun->num_sectors) { 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset = ((loff_t) lba) << 9; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Carry out the file reads */ 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left = fsg->data_size_from_cmnd; 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(amount_left == 0)) 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Figure out how much we need to read: 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to read the remaining amount. 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But don't read more than the buffer size. 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And don't try to read past the end of the file. 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally, if we're not at a page boundary, don't read past 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the next page. 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this means reading 0 then we were asked to read past 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the end of file. */ 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((unsigned int) amount_left, mod_data.buflen); 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((loff_t) amount, 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->file_length - file_offset); 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds partial_page = file_offset & (PAGE_CACHE_SIZE - 1); 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (partial_page > 0) 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds partial_page); 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available */ 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we were asked to read past the end of file, 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * end with an empty buffer. */ 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount == 0) { 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = file_offset >> 9; 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = 0; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Perform the read */ 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset_tmp = file_offset; 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = vfs_read(curlun->filp, 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char __user *) bh->buf, 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, &file_offset_tmp); 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) file_offset, 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread < 0) { 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "error in file read: %d\n", 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = 0; 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (nread < amount) { 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "partial file read: %d/%u\n", 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread, amount); 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread -= (nread & 511); // Round down to a block 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset += nread; 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left -= nread; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue -= nread; 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = nread; 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If an error occurred, report it and its position */ 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread < amount) { 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = file_offset >> 9; 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount_left == 0) 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // No more left to read 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Send this buffer and go read some more */ 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 0; 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_write(struct fsg_dev *fsg) 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 lba; 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int get_some_more; 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount_left_to_req, amount_left_to_write; 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t usb_offset, file_offset, file_offset_tmp; 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int amount; 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int partial_page; 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t nwritten; 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->ro) { 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_WRITE_PROTECTED; 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the starting Logical Block Address and check that it's 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not too big */ 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[0] == SC_WRITE_6) 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]); 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lba = get_be32(&fsg->cmnd[2]); 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We allow DPO (Disable Page Out = don't save data in the 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache) and FUA (Force Unit Access = write directly to the 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * medium). We don't implement DPO; we implement FUA by 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * performing synchronous output. */ 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x18) != 0) { 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[1] & 0x08) // FUA 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->filp->f_flags |= O_SYNC; 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lba >= curlun->num_sectors) { 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Carry out the file writes */ 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_some_more = 1; 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset = usb_offset = ((loff_t) lba) << 9; 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (amount_left_to_write > 0) { 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Queue a request for more data from the host */ 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_EMPTY && get_some_more) { 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Figure out how much we want to get: 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to get the remaining amount. 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But don't get more than the buffer size. 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And don't try to go past the end of the file. 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're not at a page boundary, 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * don't go past the next page. 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this means getting 0, then we were asked 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to write past the end of file. 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Finally, round down to a block boundary. */ 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min(amount_left_to_req, mod_data.buflen); 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((loff_t) amount, curlun->file_length - 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_offset); 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (partial_page > 0) 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min(amount, 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) PAGE_CACHE_SIZE - partial_page); 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount == 0) { 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_some_more = 0; 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = usb_offset >> 9; 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount -= (amount & 511); 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount == 0) { 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Why were we were asked to transfer a 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * partial block? */ 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_some_more = 0; 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the next buffer */ 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_offset += amount; 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left -= amount; 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left_to_req -= amount; 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount_left_to_req == 0) 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_some_more = 0; 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* amount is always divisible by 512, hence by 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the bulk-out maxpacket size */ 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq->length = bh->bulk_out_intended_length = 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount; 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_out, bh->outreq, 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->outreq_busy, &bh->state); 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write the received data to the backing file */ 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_drain; 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_EMPTY && !get_some_more) 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // We stopped early 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_FULL) { 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_drain = bh->next; 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Did something go wrong with the transfer? */ 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq->status != 0) { 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_COMMUNICATION_FAILURE; 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = file_offset >> 9; 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = bh->outreq->actual; 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->file_length - file_offset < amount) { 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LERROR(curlun, 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "write %u @ %llu beyond end %llu\n", 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, (unsigned long long) file_offset, 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) curlun->file_length); 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = curlun->file_length - file_offset; 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Perform the write */ 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset_tmp = file_offset; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nwritten = vfs_write(curlun->filp, 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char __user *) bh->buf, 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, &file_offset_tmp); 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) file_offset, 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nwritten); 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; // Interrupted! 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nwritten < 0) { 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "error in file write: %d\n", 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nwritten); 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nwritten = 0; 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (nwritten < amount) { 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "partial file write: %d/%u\n", 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nwritten, amount); 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nwritten -= (nwritten & 511); 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Round down to a block 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset += nwritten; 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left_to_write -= nwritten; 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue -= nwritten; 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If an error occurred, report it and its position */ 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nwritten < amount) { 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_WRITE_ERROR; 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = file_offset >> 9; 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Did the host decide to stop early? */ 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq->actual != bh->outreq->length) { 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->short_packet_received = 1; 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for something to happen */ 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sync the file data, don't bother with the metadata. 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code was copied from fs/buffer.c:sys_fdatasync(). */ 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fsync_sub(struct lun *curlun) 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file *filp = curlun->filp; 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct inode *inode; 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc, err; 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->ro || !filp) 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!filp->f_op->fsync) 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode = filp->f_dentry->d_inode; 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&inode->i_sem); 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->flags |= PF_SYNCWRITE; 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = filemap_fdatawrite(inode->i_mapping); 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = filp->f_op->fsync(filp, filp->f_dentry, 1); 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rc) 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = err; 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = filemap_fdatawait(inode->i_mapping); 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rc) 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = err; 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds current->flags &= ~PF_SYNCWRITE; 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&inode->i_sem); 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "fdatasync -> %d\n", rc); 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsync_all(struct fsg_dev *fsg) 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsync_sub(&fsg->luns[i]); 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_synchronize_cache(struct fsg_dev *fsg) 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We ignore the requested LBA and write out all file's 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dirty data buffers. */ 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = fsync_sub(curlun); 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_WRITE_ERROR; 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void invalidate_sub(struct lun *curlun) 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file *filp = curlun->filp; 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long rc; 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = invalidate_inode_pages(inode->i_mapping); 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_verify(struct fsg_dev *fsg) 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 lba; 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 verification_length; 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t file_offset, file_offset_tmp; 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount_left; 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int amount; 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t nread; 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the starting Logical Block Address and check that it's 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not too big */ 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lba = get_be32(&fsg->cmnd[2]); 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lba >= curlun->num_sectors) { 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We allow DPO (Disable Page Out = don't save data in the 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cache) but we don't implement it. */ 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x10) != 0) { 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds verification_length = get_be16(&fsg->cmnd[7]); 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(verification_length == 0)) 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; // No default reply 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Prepare to carry out the file verify */ 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left = verification_length << 9; 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset = ((loff_t) lba) << 9; 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write out all the dirty buffers before invalidating them */ 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsync_sub(curlun); 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds invalidate_sub(curlun); 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Just try to read the requested blocks */ 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (amount_left > 0) { 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Figure out how much we need to read: 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to read the remaining amount, but not more than 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the buffer size. 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And don't try to read past the end of the file. 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this means reading 0 then we were asked to read 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * past the end of file. */ 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((unsigned int) amount_left, mod_data.buflen); 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min((loff_t) amount, 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->file_length - file_offset); 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (amount == 0) { 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = file_offset >> 9; 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Perform the read */ 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset_tmp = file_offset; 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = vfs_read(curlun->filp, 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char __user *) bh->buf, 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount, &file_offset_tmp); 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long long) file_offset, 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending(current)) 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread < 0) { 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "error in file verify: %d\n", 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread); 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread = 0; 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (nread < amount) { 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "partial file verify: %d/%u\n", 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) nread, amount); 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nread -= (nread & 511); // Round down to a sector 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nread == 0) { 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_UNRECOVERED_READ_ERROR; 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = file_offset >> 9; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds file_offset += nread; 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount_left -= nread; 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static char vendor_id[] = "Linux "; 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static char product_id[] = "File-Stor Gadget"; 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->curlun) { // Unsupported LUNs are okay 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bad_lun_okay = 1; 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, 36); 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x7f; // Unsupported, no device-type 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 36; 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, 8); // Non-removable, direct-access device 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.removable) 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 0x80; 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = 2; // ANSI SCSI level 2 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = 2; // SCSI-2 INQUIRY data format 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 31; // Additional length 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // No special options 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id, 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.release); 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 36; 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 sd, sdinfo; 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * From the SCSI-2 spec., section 7.9 (Unit attention condition): 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a REQUEST SENSE command is received from an initiator 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with a pending unit attention condition (before the target 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generates the contingent allegiance condition), then the 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target shall either: 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a) report any pending sense data and preserve the unit 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * attention condition on the logical unit, or, 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * b) report the unit attention condition, may discard any 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pending sense data, and clear the unit attention 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * condition on the logical unit for that initiator. 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FSG normally uses option a); enable this code to use option b). 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = curlun->unit_attention_data; 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->unit_attention_data = SS_NO_SENSE; 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!curlun) { // Unsupported LUNs are okay 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bad_lun_okay = 1; 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdinfo = 0; 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = curlun->sense_data; 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdinfo = curlun->sense_data_info; 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_NO_SENSE; 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = 0; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, 18); 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x80 | 0x70; // Valid, current error 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = SK(sd); 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be32(&buf[3], sdinfo); // Sense information 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[7] = 18 - 8; // Additional sense length 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[12] = ASC(sd); 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[13] = ASCQ(sd); 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 18; 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 lba = get_be32(&fsg->cmnd[2]); 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pmi = fsg->cmnd[8]; 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the PMI and LBA fields */ 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pmi > 1 || (pmi == 0 && lba != 0)) { 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be32(&buf[0], curlun->num_sectors - 1); // Max logical block 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be32(&buf[4], 512); // Block length 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 8; 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int mscmnd = fsg->cmnd[0]; 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf0 = buf; 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pc, page_code; 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int changeable_values, all_pages; 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int valid_page = 0; 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len, limit; 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = fsg->cmnd[2] >> 6; 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page_code = fsg->cmnd[2] & 0x3f; 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pc == 3) { 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds changeable_values = (pc == 1); 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds all_pages = (page_code == 0x3f); 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write the mode parameter header. Fixed values are: default 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * medium type, no cache control (DPOFUA), and no block descriptors. 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The only variable value is the WriteProtect bit. We will fill in 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the mode data length later. */ 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf, 0, 8); 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mscmnd == SC_MODE_SENSE_6) { 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 4; 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 255; 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // SC_MODE_SENSE_10 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 8; 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limit = 65535; // Should really be mod_data.buflen 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No block descriptors */ 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The mode pages, in numerical order. The only page we support 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is the Caching page. */ 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (page_code == 0x08 || all_pages) { 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds valid_page = 1; 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = 0x08; // Page code 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[1] = 10; // Page length 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf+2, 0, 10); // None of the fields are changeable 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!changeable_values) { 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[2] = 0x04; // Write cache enable, 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Read cache not disabled 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // No cache retention priorities 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be16(&buf[4], 0xffff); // Don't disable prefetch 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Minimum prefetch = 0 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be16(&buf[8], 0xffff); // Maximum prefetch 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 12; 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check that a valid page was requested and the mode data length 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isn't too long. */ 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = buf - buf0; 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!valid_page || len > limit) { 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store the mode data length */ 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mscmnd == SC_MODE_SENSE_6) 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf0[0] = len - 1; 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be16(buf0, len - 2); 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_start_stop(struct fsg_dev *fsg) 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int loej, start; 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mod_data.removable) { 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_COMMAND; 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // int immed = fsg->cmnd[1] & 0x01; 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loej = fsg->cmnd[4] & 0x02; 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = fsg->cmnd[4] & 0x01; 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!start) { 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Are we allowed to unload the media? */ 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->prevent_medium_removal) { 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "unload attempt prevented\n"); 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (loej) { // Simulate an unload/eject 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&fsg->filesem); 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_write(&fsg->filesem); 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_backing_file(curlun); 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_write(&fsg->filesem); 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&fsg->filesem); 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Our emulation doesn't support mounting; the medium is 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * available for use as soon as it is loaded. */ 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!backing_file_is_open(curlun)) { 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_prevent_allow(struct fsg_dev *fsg) 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int prevent; 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mod_data.removable) { 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_COMMAND; 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prevent = fsg->cmnd[4] & 0x01; 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->prevent_medium_removal && !prevent) 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsync_sub(curlun); 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->prevent_medium_removal = prevent; 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read_format_capacities(struct fsg_dev *fsg, 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh) 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf = (u8 *) bh->buf; 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[0] = buf[1] = buf[2] = 0; 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[3] = 8; // Only the Current/Maximum Capacity Descriptor 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf += 4; 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be32(&buf[0], curlun->num_sectors); // Number of blocks 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_be32(&buf[4], 512); // Block length 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[4] = 0x02; // Current capacity 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 12; 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We don't support MODE SELECT */ 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_COMMAND; 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int halt_bulk_in_endpoint(struct fsg_dev *fsg) 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = fsg_set_halt(fsg, fsg->bulk_in); 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc == -EAGAIN) 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "delayed bulk-in endpoint halt\n"); 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (rc != 0) { 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != -EAGAIN) { 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN(fsg, "usb_ep_set_halt -> %d\n", rc); 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for a short time and then try again */ 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (msleep_interruptible(100) != 0) 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = usb_ep_set_halt(fsg->bulk_in); 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pad_with_zeros(struct fsg_dev *fsg) 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 nkeep = bh->inreq->length; 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 nsend; 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; // For the first iteration 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left = nkeep + fsg->residue; 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fsg->usb_amount_left > 0) { 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to be free */ 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nsend = min(fsg->usb_amount_left, (u32) mod_data.buflen); 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(bh->buf + nkeep, 0, nsend - nkeep); 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = nsend; 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 0; 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill = bh->next; 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left -= nsend; 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nkeep = 0; 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int throw_away_data(struct fsg_dev *fsg) 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 amount; 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left > 0) { 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Throw away the data in a filled buffer */ 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_FULL) { 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_drain = bh->next; 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* A short packet or an error ends everything */ 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq->actual != bh->outreq->length || 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq->status != 0) { 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Try to submit another request if we need one */ 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount = min(fsg->usb_amount_left, 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (u32) mod_data.buflen); 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* amount is always divisible by 512, hence by 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the bulk-out maxpacket size */ 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq->length = bh->bulk_out_intended_length = 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds amount; 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_out, bh->outreq, 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->outreq_busy, &bh->state); 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->usb_amount_left -= amount; 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Otherwise wait for something to happen */ 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int finish_reply(struct fsg_dev *fsg) 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (fsg->data_dir) { 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_NONE: 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; // Nothing to send 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we don't know whether the host wants to read or write, 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this must be CB or CBI with an unknown command. We mustn't 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try to send or receive any data. So stall both bulk pipes 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if we can and wait for a reset. */ 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_UNKNOWN: 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.can_stall) { 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->bulk_out); 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = halt_bulk_in_endpoint(fsg); 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All but the last buffer of data must have already been sent */ 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_TO_HOST: 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size == 0) 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Nothing to send 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If there's no residue, simply send the last buffer */ 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (fsg->residue == 0) { 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 0; 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There is a residue. For CB and CBI, simply mark the end 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the data with a short packet. However, if we are 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allowed to stall, there was no data at all (residue == 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data_size), and the command failed (invalid LUN or 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sense data is set), then halt the bulk-in endpoint 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * instead. */ 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (!transport_is_bbb()) { 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.can_stall && 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue == fsg->data_size && 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = halt_bulk_in_endpoint(fsg); 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 1; 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* For Bulk-only, if we're allowed to stall then send the 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * short packet and halt the bulk-in endpoint. If we can't 24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stall, pad out the remaining data with 0's. */ 24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.can_stall) { 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 1; 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = halt_bulk_in_endpoint(fsg); 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = pad_with_zeros(fsg); 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We have processed all we want from the data the host has sent. 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There may still be outstanding bulk-out requests. */ 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case DATA_DIR_FROM_HOST: 24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->residue == 0) 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Nothing to receive 24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Did the host stop sending unexpectedly early? */ 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (fsg->short_packet_received) { 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINTR; 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We haven't processed all the incoming data. Even though 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we may be allowed to stall, doing so would cause a race. 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The controller may already have ACK'ed all the remaining 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bulk-out packets, in which case the host wouldn't see a 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STALL. Not realizing the endpoint was halted, it wouldn't 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clear the halt -- leading to problems later on. */ 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (mod_data.can_stall) { 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->bulk_out); 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINTR; 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't stall. Read in the excess data and throw it 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all away. */ 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = throw_away_data(fsg); 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int send_status(struct fsg_dev *fsg) 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = fsg->curlun; 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 status = USB_STATUS_PASS; 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 sd, sdinfo = 0; 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available */ 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun) { 25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = curlun->sense_data; 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdinfo = curlun->sense_data_info; 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (fsg->bad_lun_okay) 25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_NO_SENSE; 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->phase_error) { 25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "sending phase-error status\n"); 25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = USB_STATUS_PHASE_ERROR; 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sd = SS_INVALID_COMMAND; 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (sd != SS_NO_SENSE) { 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "sending command-failure status\n"); 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = USB_STATUS_FAIL; 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " info x%x\n", 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SK(sd), ASC(sd), ASCQ(sd), sdinfo); 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf; 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store and send the Bulk-only CSW */ 25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG); 25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csw->Tag = fsg->tag; 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csw->Residue = cpu_to_le32(fsg->residue); 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csw->Status = status; 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = USB_BULK_CS_WRAP_LEN; 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->zero = 0; 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_in, bh->inreq, 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->inreq_busy, &bh->state); 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (mod_data.transport_type == USB_PR_CB) { 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Control-Bulk transport has no status phase! */ 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // USB_PR_CBI 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct interrupt_data *buf = (struct interrupt_data *) 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->buf; 25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store and send the Interrupt data. UFI sends the ASC 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and ASCQ bytes. Everything else sends a Type (which 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is always 0) and the status Value. */ 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.protocol_type == USB_SC_UFI) { 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bType = ASC(sd); 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bValue = ASCQ(sd); 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bType = 0; 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->bValue = status; 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; 25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_buffhd = bh; // Point to the right buffhd 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->buf = bh->inreq->buf; 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->dma = bh->inreq->dma; 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->context = bh; 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->intr_in, fsg->intreq, 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &fsg->intreq_busy, &bh->state); 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = bh->next; 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Check whether the command is properly formed and whether its data size 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and direction agree with the values we already have. */ 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_command(struct fsg_dev *fsg, int cmnd_size, 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum data_direction data_dir, unsigned int mask, 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int needs_medium, const char *name) 25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lun = fsg->cmnd[1] >> 5; 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char dirletter[4] = {'u', 'o', 'i', 'n'}; 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char hdlen[20]; 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun; 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Adjust the expected cmnd_size for protocol encapsulation padding. 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transparent SCSI doesn't pad. */ 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (protocol_is_scsi()) 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There's some disagreement as to whether RBC pads commands or not. 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'll play it safe and accept either form. */ 26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (mod_data.protocol_type == USB_SC_RBC) { 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd_size == 12) 26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmnd_size = 12; 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All the other protocols pad to 12 bytes */ 26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmnd_size = 12; 26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdlen[0] = 0; 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_dir != DATA_DIR_UNKNOWN) 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size); 26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name, cmnd_size, dirletter[(int) data_dir], 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can't reply at all until we know the correct data direction 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and size. */ 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size_from_cmnd == 0) 26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_dir = DATA_DIR_NONE; 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = data_dir; 26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size = fsg->data_size_from_cmnd; 26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // Bulk-only 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size < fsg->data_size_from_cmnd) { 26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Host data size < Device data size is a phase error. 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Carry out the command, but only transfer as much 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as we are allowed. */ 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->data_size; 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 1; 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue = fsg->usb_amount_left = fsg->data_size; 26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Conflicting data directions is a phase error */ 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 1; 26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Verify the length of the command itself */ 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmnd_size != fsg->cmnd_size) { 26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Special case workaround: MS-Windows issues REQUEST SENSE 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with cbw->Length == 12 (it should be 6). */ 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[0] == SC_REQUEST_SENSE && fsg->cmnd_size == 12) 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmnd_size = fsg->cmnd_size; 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 1; 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2662d794ac7ae3613c2abfb678617ac7d74c8ff0099cAlan Stern /* Check that the LUN values are consistent */ 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->lun != lun) 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "using LUN %d from CBW, " 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "not LUN %d from CDB\n", 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->lun, lun); 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->lun = lun; // Use LUN from the command 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the LUN */ 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->lun >= 0 && fsg->lun < fsg->nluns) { 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->curlun = curlun = &fsg->luns[fsg->lun]; 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[0] != SC_REQUEST_SENSE) { 26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_NO_SENSE; 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = 0; 26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->curlun = curlun = NULL; 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bad_lun_okay = 0; 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* INQUIRY and REQUEST SENSE commands are explicitly allowed 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to use unsupported LUNs; all others may not. */ 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[0] != SC_INQUIRY && 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd[0] != SC_REQUEST_SENSE) { 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "unsupported LUN %d\n", fsg->lun); 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If a unit attention condition exists, only INQUIRY and 26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * REQUEST SENSE commands are allowed; anything else must fail. */ 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun && curlun->unit_attention_data != SS_NO_SENSE && 26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd[0] != SC_INQUIRY && 26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd[0] != SC_REQUEST_SENSE) { 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = curlun->unit_attention_data; 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->unit_attention_data = SS_NO_SENSE; 26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check that only command bytes listed in the mask are non-zero */ 27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd[1] &= 0x1f; // Mask away the LUN 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < cmnd_size; ++i) { 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->cmnd[i] && !(mask & (1 << i))) { 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun) 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_INVALID_FIELD_IN_CDB; 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the medium isn't mounted and the command needs to access 27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it, return an error. */ 27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun && !backing_file_is_open(curlun) && needs_medium) { 27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = SS_MEDIUM_NOT_PRESENT; 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_scsi_command(struct fsg_dev *fsg) 27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int reply = -EINVAL; 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static char unknown[16]; 27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_cdb(fsg); 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available for data or status */ 27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; 27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->phase_error = 0; 27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->short_packet_received = 0; 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&fsg->filesem); // We're using the backing file 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (fsg->cmnd[0]) { 27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_INQUIRY: 27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<4), 0, 27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "INQUIRY")) == 0) 27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_inquiry(fsg, bh); 27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_MODE_SELECT_6: 27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, 27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<4), 0, 27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SELECT(6)")) == 0) 27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_select(fsg, bh); 27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_MODE_SELECT_10: 27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); 27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, 27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (3<<7), 0, 27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SELECT(10)")) == 0) 27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_select(fsg, bh); 27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_MODE_SENSE_6: 27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, 27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<2) | (1<<4), 0, 27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SENSE(6)")) == 0) 27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_sense(fsg, bh); 27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_MODE_SENSE_10: 27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); 27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<2) | (3<<7), 0, 27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "MODE SENSE(10)")) == 0) 27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_mode_sense(fsg, bh); 27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: 27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_NONE, 27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<4), 0, 27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) 27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_prevent_allow(fsg); 27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_READ_6: 27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = fsg->cmnd[4]; 27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; 27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, 27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (7<<1) | (1<<4), 1, 27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ(6)")) == 0) 27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read(fsg); 27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_READ_10: 28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; 28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (3<<7), 1, 28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ(10)")) == 0) 28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read(fsg); 28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_READ_12: 28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; 28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, 28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (0xf<<6), 1, 28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ(12)")) == 0) 28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read(fsg); 28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_READ_CAPACITY: 28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 8; 28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0xf<<2) | (1<<8), 1, 28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ CAPACITY")) == 0) 28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read_capacity(fsg, bh); 28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_READ_FORMAT_CAPACITIES: 28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]); 28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, 28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (3<<7), 1, 28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "READ FORMAT CAPACITIES")) == 0) 28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_read_format_capacities(fsg, bh); 28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_REQUEST_SENSE: 28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = fsg->cmnd[4]; 28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, 28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<4), 0, 28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "REQUEST SENSE")) == 0) 28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_request_sense(fsg, bh); 28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_START_STOP_UNIT: 28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_NONE, 28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (1<<4), 0, 28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "START-STOP UNIT")) == 0) 28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_start_stop(fsg); 28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_SYNCHRONIZE_CACHE: 28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_NONE, 28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0xf<<2) | (3<<7), 1, 28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SYNCHRONIZE CACHE")) == 0) 28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_synchronize_cache(fsg); 28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_TEST_UNIT_READY: 28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = check_command(fsg, 6, DATA_DIR_NONE, 28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 1, 28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "TEST UNIT READY"); 28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Although optional, this command is used by MS-Windows. We 28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * support a minimal version: BytChk must be 0. */ 28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_VERIFY: 28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_NONE, 28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (3<<7), 1, 28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "VERIFY")) == 0) 28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_verify(fsg); 28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_WRITE_6: 28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = fsg->cmnd[4]; 28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; 28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, 28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (7<<1) | (1<<4), 1, 28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "WRITE(6)")) == 0) 28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_write(fsg); 28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_WRITE_10: 28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9; 28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, 28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (3<<7), 1, 28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "WRITE(10)")) == 0) 28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_write(fsg); 28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_WRITE_12: 28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9; 28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, 28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (1<<1) | (0xf<<2) | (0xf<<6), 1, 28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "WRITE(12)")) == 0) 28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = do_write(fsg); 28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Some mandatory commands that we recognize but don't implement. 29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * They don't mean much in this setting. It's left as an exercise 29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for anyone interested to implement RESERVE and RELEASE in terms 29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of Posix locks. */ 29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_FORMAT_UNIT: 29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_RELEASE: 29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_RESERVE: 29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SC_SEND_DIAGNOSTIC: 29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Fall through 29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size_from_cmnd = 0; 29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); 29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((reply = check_command(fsg, fsg->cmnd_size, 29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DATA_DIR_UNKNOWN, 0xff, 0, unknown)) == 0) { 29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->curlun->sense_data = SS_INVALID_COMMAND; 29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = -EINVAL; 29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&fsg->filesem); 29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reply == -EINTR || signal_pending(current)) 29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINTR; 29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set up the single reply buffer for finish_reply() */ 29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reply == -EINVAL) 29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = 0; // Error reply length 29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { 29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reply = min((u32) reply, fsg->data_size_from_cmnd); 29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->length = reply; 29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_FULL; 29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->residue -= reply; 29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } // Otherwise it's already set 29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) 29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = bh->outreq; 29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf; 29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Was this a real packet? */ 29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->status) 29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is the CBW valid? */ 29501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->actual != USB_BULK_CB_WRAP_LEN || 29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cbw->Signature != __constant_cpu_to_le32( 29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds USB_BULK_CB_SIG)) { 29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "invalid CBW: len %u sig 0x%x\n", 29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->actual, 29551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpu(cbw->Signature)); 29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The Bulk-only spec says we MUST stall the bulk pipes! 29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we want to avoid stalls, set a flag so that we will 29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clear the endpoint halts at the next reset. */ 29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!mod_data.can_stall) 29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(CLEAR_BULK_HALTS, &fsg->atomic_bitflags); 29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->bulk_out); 29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds halt_bulk_in_endpoint(fsg); 29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is the CBW meaningful? */ 29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || 29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) { 29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " 29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cmdlen %u\n", 29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cbw->Lun, cbw->Flags, cbw->Length); 29731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We can do anything we want here, so let's stall the 29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bulk pipes if we are allowed to. */ 29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.can_stall) { 29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->bulk_out); 29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds halt_bulk_in_endpoint(fsg); 29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Save the command for later */ 29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd_size = cbw->Length; 29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); 29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cbw->Flags & USB_BULK_IN_FLAG) 29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_TO_HOST; 29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_FROM_HOST; 29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_size = le32_to_cpu(cbw->DataTransferLength); 29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->data_size == 0) 29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_NONE; 29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->lun = cbw->Lun; 29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->tag = cbw->Tag; 29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_next_command(struct fsg_dev *fsg) 30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 30031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next buffer to become available */ 30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = fsg->next_buffhd_to_fill; 30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_EMPTY) { 30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Queue a request to read a Bulk-only CBW */ 30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); 30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start_transfer(fsg, fsg->bulk_out, bh->outreq, 30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->outreq_busy, &bh->state); 30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We will drain the buffer in software, which means we 30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can reuse it for the next filling. No need to advance 30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * next_buffhd_to_fill. */ 30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the CBW to arrive */ 30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (bh->state != BUF_STATE_FULL) { 30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = received_cbw(fsg, bh); 30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // USB_PR_CB or USB_PR_CBI 30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the next command to arrive */ 30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fsg->cbbuf_cmnd_size == 0) { 30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = sleep_thread(fsg)) != 0) 30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is the previous status interrupt request still busy? 30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The host is allowed to skip reading the status, 30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so we must cancel it. */ 30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intreq_busy) 30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->intr_in, fsg->intreq); 30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy the command and mark the buffer empty */ 30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->data_dir = DATA_DIR_UNKNOWN; 30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cmnd_size = fsg->cbbuf_cmnd_size; 30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); 30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->cbbuf_cmnd_size = 0; 30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, 30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *d) 30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; 30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = usb_ep_enable(ep, d); 30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc) 30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); 30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, 30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request **preq) 30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); 30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*preq) 30751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 30761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "can't allocate request for %s\n", ep->name); 30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset interface setting and re-init endpoint state (toggle etc). 30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Call with altsetting < 0 to disable the interface. The only other 30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * available altsetting is 0, which enables the interface. 30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_set_interface(struct fsg_dev *fsg, int altsetting) 30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct usb_endpoint_descriptor *d; 30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->running) 30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "reset interface\n"); 30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreset: 30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Deallocate the requests */ 30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_BUFFERS; ++i) { 30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = &fsg->buffhds[i]; 30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->inreq) { 31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->bulk_in, bh->inreq); 31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq = NULL; 31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq) { 31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->bulk_out, bh->outreq); 31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq = NULL; 31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intreq) { 31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->intr_in, fsg->intreq); 31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq = NULL; 31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable the endpoints */ 31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_in_enabled) { 31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_disable(fsg->bulk_in); 31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_in_enabled = 0; 31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_out_enabled) { 31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_disable(fsg->bulk_out); 31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_out_enabled = 0; 31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intr_in_enabled) { 31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_disable(fsg->intr_in); 31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_in_enabled = 0; 31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->running = 0; 31281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (altsetting < 0 || rc != 0) 31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "set interface %d\n", altsetting); 31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable the endpoints */ 31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d = ep_desc(fsg->gadget, &fs_bulk_in_desc, &hs_bulk_in_desc); 31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) 31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_in_enabled = 1; 31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d = ep_desc(fsg->gadget, &fs_bulk_out_desc, &hs_bulk_out_desc); 31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) 31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_out_enabled = 1; 31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); 31441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_cbi()) { 31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d = ep_desc(fsg->gadget, &fs_intr_in_desc, &hs_intr_in_desc); 31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) 31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_in_enabled = 1; 31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the requests */ 31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_BUFFERS; ++i) { 31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = &fsg->buffhds[i]; 31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) 31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) 31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->buf = bh->outreq->buf = bh->buf; 31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->dma = bh->outreq->dma = bh->dma; 31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->context = bh->outreq->context = bh; 31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->inreq->complete = bulk_in_complete; 31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->outreq->complete = bulk_out_complete; 31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_cbi()) { 31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) 31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset; 31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intreq->complete = intr_in_complete; 31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->running = 1; 31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) 31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; 31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change our operational configuration. This code must agree with the code 31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that returns config descriptors, and with interface altsetting code. 31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It's also responsible for power management interactions. Some 31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * configurations might not work with our current power sources. 31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now we just assume the gadget is always self-powered. 31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_set_config(struct fsg_dev *fsg, u8 new_config) 31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable the single interface */ 31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->config != 0) { 31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "reset config\n"); 31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->config = 0; 31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = do_set_interface(fsg, -1); 31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable the interface */ 31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (new_config != 0) { 32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->config = new_config; 32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = do_set_interface(fsg, 0)) != 0) 32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->config = 0; // Reset on errors 32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *speed; 32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (fsg->gadget->speed) { 32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_LOW: speed = "low"; break; 32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_FULL: speed = "full"; break; 32091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case USB_SPEED_HIGH: speed = "high"; break; 32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: speed = "?"; break; 32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFO(fsg, "%s speed config #%d\n", speed, fsg->config); 32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handle_exception(struct fsg_dev *fsg) 32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginfo_t info; 32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int sig; 32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int num_active; 32271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh; 32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum fsg_state old_state; 32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 new_config; 32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun; 32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int exception_req_tag; 32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear the existing signals. Anything but SIGUSR1 is converted 32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into a high-priority EXIT exception. */ 32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sig = dequeue_signal_lock(current, &fsg->thread_signal_mask, 32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &info); 32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sig) 32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sig != SIGUSR1) { 32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->state < FSG_STATE_EXIT) 32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "Main thread exiting on signal\n"); 32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_EXIT); 32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Cancel all the pending transfers */ 32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intreq_busy) 32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->intr_in, fsg->intreq); 32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_BUFFERS; ++i) { 32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = &fsg->buffhds[i]; 32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->inreq_busy) 32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->bulk_in, bh->inreq); 32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->outreq_busy) 32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_dequeue(fsg->bulk_out, bh->outreq); 32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait until everything is idle */ 32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_active = fsg->intreq_busy; 32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_BUFFERS; ++i) { 32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = &fsg->buffhds[i]; 32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_active += bh->inreq_busy + bh->outreq_busy; 32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num_active == 0) 32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sleep_thread(fsg)) 32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear out the controller's fifos */ 32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_in_enabled) 32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(fsg->bulk_in); 32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->bulk_out_enabled) 32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(fsg->bulk_out); 32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->intr_in_enabled) 32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_fifo_flush(fsg->intr_in); 32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset the I/O buffer states and pointers, the SCSI 32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state, and the exception. Then invoke the handler. */ 32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_BUFFERS; ++i) { 32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh = &fsg->buffhds[i]; 32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->state = BUF_STATE_EMPTY; 32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = 32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &fsg->buffhds[0]; 32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exception_req_tag = fsg->exception_req_tag; 32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_config = fsg->new_config; 32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_state = fsg->state; 32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_state == FSG_STATE_ABORT_BULK_OUT) 32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_STATUS_PHASE; 32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->prevent_medium_removal = 0; 33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data = curlun->unit_attention_data = 33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_NO_SENSE; 33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->sense_data_info = 0; 33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_IDLE; 33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Carry out any extra actions required for the exception */ 33101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (old_state) { 33111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_ABORT_BULK_OUT: 33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_status(fsg); 33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->state == FSG_STATE_STATUS_PHASE) 33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_IDLE; 33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_RESET: 33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* In case we were forced against our will to halt a 33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bulk endpoint, clear the halt now. (The SuperH UDC 33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requires this.) */ 33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_clear_bit(CLEAR_BULK_HALTS, 33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &fsg->atomic_bitflags)) { 33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_clear_halt(fsg->bulk_in); 33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_clear_halt(fsg->bulk_out); 33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_bbb()) { 33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->ep0_req_tag == exception_req_tag) 33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0_queue(fsg); // Complete the status stage 33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (transport_is_cbi()) 33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_status(fsg); // Status by interrupt pipe 33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Technically this should go here, but it would only be 33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a waste of time. Ditto for the INTERFACE_CHANGE and 33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CONFIG_CHANGE cases. */ 33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // for (i = 0; i < fsg->nluns; ++i) 33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; 33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_INTERFACE_CHANGE: 33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = do_set_interface(fsg, 0); 33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->ep0_req_tag != exception_req_tag) 33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0) // STALL on errors 33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->ep0); 33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else // Complete the status stage 33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0_queue(fsg); 33541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_CONFIG_CHANGE: 33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = do_set_config(fsg, new_config); 33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->ep0_req_tag != exception_req_tag) 33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc != 0) // STALL on errors 33611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_set_halt(fsg, fsg->ep0); 33621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else // Complete the status stage 33631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep0_queue(fsg); 33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_DISCONNECT: 33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsync_all(fsg); 33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_set_config(fsg, 0); // Unconfigured state 33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_EXIT: 33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case FSG_STATE_TERMINATED: 33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_set_config(fsg, 0); // Free resources 33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_TERMINATED; // Stop the thread 33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int fsg_main_thread(void *fsg_) 33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) fsg_; 33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allow the thread to be killed by a signal, but set the signal mask 33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to block everything but INT, TERM, KILL, and USR1. */ 33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) | 33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigmask(SIGTERM) | sigmask(SIGKILL) | 33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigmask(SIGUSR1)); 33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sigprocmask(SIG_SETMASK, &fsg->thread_signal_mask, NULL); 33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Arrange for userspace references to be interpreted as kernel 33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointers. That way we can pass a kernel pointer to a routine 33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that expects a __user pointer and it will work okay. */ 33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_fs(get_ds()); 33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The main loop */ 34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (fsg->state != FSG_STATE_TERMINATED) { 34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (exception_in_progress(fsg) || signal_pending(current)) { 34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handle_exception(fsg); 34041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->running) { 34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sleep_thread(fsg); 34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (get_next_command(fsg)) 34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!exception_in_progress(fsg)) 34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_DATA_PHASE; 34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (do_scsi_command(fsg) || finish_reply(fsg)) 34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!exception_in_progress(fsg)) 34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_STATUS_PHASE; 34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (send_status(fsg)) 34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&fsg->lock); 34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!exception_in_progress(fsg)) 34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_IDLE; 34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&fsg->lock); 34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 343722efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern spin_lock_irq(&fsg->lock); 34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->thread_task = NULL; 343922efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern spin_unlock_irq(&fsg->lock); 34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* In case we are exiting because of a signal, unregister the 34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gadget driver and close the backing file. */ 34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) { 34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_unregister_driver(&fsg_driver); 34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_all_backing_files(fsg); 34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Let the unbind and cleanup routines know the thread has exited */ 34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complete_and_exit(&fsg->thread_notifier, 0); 34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If the next two routines are called while the gadget is registered, 34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the caller must own fsg->filesem for writing. */ 34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int open_backing_file(struct lun *curlun, const char *filename) 34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ro; 34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct file *filp = NULL; 34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = -EINVAL; 34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct inode *inode = NULL; 34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t size; 34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t num_sectors; 34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* R/W if we can, R/O if we must */ 34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ro = curlun->ro; 34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ro) { 34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); 34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (-EROFS == PTR_ERR(filp)) 34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ro = 1; 34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ro) 34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); 34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(filp)) { 34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LINFO(curlun, "unable to open backing file: %s\n", filename); 34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(filp); 34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(filp->f_mode & FMODE_WRITE)) 34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ro = 1; 34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (filp->f_dentry) 34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inode = filp->f_dentry->d_inode; 34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inode && S_ISBLK(inode->i_mode)) { 34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bdev_read_only(inode->i_bdev)) 34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ro = 1; 34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!inode || !S_ISREG(inode->i_mode)) { 34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LINFO(curlun, "invalid file type: %s\n", filename); 34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we can't read the file, it's no good. 34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we can't write the file, use it read-only. */ 34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { 34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LINFO(curlun, "file not readable: %s\n", filename); 34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(filp->f_op->write || filp->f_op->aio_write)) 35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ro = 1; 35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = i_size_read(inode->i_mapping->host); 35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size < 0) { 35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LINFO(curlun, "unable to find file size: %s\n", filename); 35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = (int) size; 35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_sectors = size >> 9; // File size in 512-byte sectors 35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num_sectors == 0) { 35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LINFO(curlun, "file too small: %s\n", filename); 35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ETOOSMALL; 35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_file(filp); 35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->ro = ro; 35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->filp = filp; 35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->file_length = size; 35201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->num_sectors = num_sectors; 35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "open backing file: %s\n", filename); 35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp_close(filp, current->files); 35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void close_backing_file(struct lun *curlun) 35311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->filp) { 35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "close backing file\n"); 35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fput(curlun->filp); 35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->filp = NULL; 35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void close_all_backing_files(struct fsg_dev *fsg) 35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) 35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_backing_file(&fsg->luns[i]); 35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 354810523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoustatic ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *buf) 35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = dev_to_lun(dev); 35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%d\n", curlun->ro); 35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 355510523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoustatic ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) 35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = dev_to_lun(dev); 35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); 35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *p; 35601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t rc; 35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&fsg->filesem); 35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (backing_file_is_open(curlun)) { // Get the complete pathname 35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt, 35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf, PAGE_SIZE - 1); 35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(p)) 35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = PTR_ERR(p); 35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = strlen(p); 35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memmove(buf, p, rc); 35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[rc] = '\n'; // Add a newline 35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf[++rc] = 0; 35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { // No file, return 0 bytes 35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *buf = 0; 35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = 0; 35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&fsg->filesem); 35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 35811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 358310523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoustatic ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t rc = count; 35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = dev_to_lun(dev); 35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); 35881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 35891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sscanf(buf, "%d", &i) != 1) 35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allow the write-enable status to change only while the backing file 35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is closed. */ 35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_read(&fsg->filesem); 35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (backing_file_is_open(curlun)) { 35971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "read-only status change prevented\n"); 35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EBUSY; 35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->ro = !!i; 36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "read-only status set to %d\n", curlun->ro); 36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_read(&fsg->filesem); 36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 360710523b3b82456e416cbaffcc24ea2246980aa746Yani Ioannoustatic ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun = dev_to_lun(dev); 36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); 36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc = 0; 36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) { 36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LDBG(curlun, "eject attempt prevented\n"); 36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; // "Door is locked" 36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remove a trailing newline */ 36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > 0 && buf[count-1] == '\n') 36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((char *) buf)[count-1] = 0; // Ugh! 36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Eject current medium */ 36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down_write(&fsg->filesem); 36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (backing_file_is_open(curlun)) { 36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_backing_file(curlun); 36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; 36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Load new medium */ 36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count > 0 && buf[0]) { 36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = open_backing_file(curlun, buf); 36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rc == 0) 36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->unit_attention_data = 36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SS_NOT_READY_TO_READY_TRANSITION; 36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up_write(&fsg->filesem); 36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (rc < 0 ? rc : count); 36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The write permissions and store_xxx pointers are set in fsg_bind() */ 36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(ro, 0444, show_ro, NULL); 36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(file, 0444, show_file, NULL); 36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 364887c4252a35310fdbb2aabb880a39b83f83cadf62Alan Sternstatic void fsg_release(struct kref *ref) 364987c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern{ 365087c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); 365187c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern 365287c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kfree(fsg->luns); 365387c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kfree(fsg); 365487c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern} 365587c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern 36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lun_release(struct device *dev) 36571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev); 36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 366087c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_put(&fsg->ref, fsg_release); 36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsg_unbind(struct usb_gadget *gadget) 36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun; 36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req = fsg->ep0req; 36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "unbind\n"); 36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(REGISTERED, &fsg->atomic_bitflags); 36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unregister the sysfs attribute files and the LUNs */ 36741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (curlun->registered) { 36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_remove_file(&curlun->dev, &dev_attr_ro); 36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_remove_file(&curlun->dev, &dev_attr_file); 36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_unregister(&curlun->dev); 36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->registered = 0; 36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the thread isn't already dead, tell it to exit now */ 36851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fsg->state != FSG_STATE_TERMINATED) { 36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raise_exception(fsg, FSG_STATE_EXIT); 36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_for_completion(&fsg->thread_notifier); 36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The cleanup routine waits for this completion also */ 36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complete(&fsg->thread_notifier); 36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Free the data buffers */ 36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_BUFFERS; ++i) { 36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = &fsg->buffhds[i]; 36961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bh->buf) 36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma, 36991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.buflen); 37001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Free the request and buffer for endpoint 0 */ 37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req) { 37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req->buf) 37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_buffer(fsg->ep0, req->buf, 37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->dma, EP0_BUFSIZE); 37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_free_request(fsg->ep0, req); 37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_gadget_data(gadget, NULL); 37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init check_parameters(struct fsg_dev *fsg) 37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int prot; 371791e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell int gcnum; 37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Store the default values */ 37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_type = USB_PR_BULK; 37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name = "Bulk-only"; 37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_SCSI; 37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "Transparent SCSI"; 37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gadget_is_sh(fsg->gadget)) 37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.can_stall = 0; 37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.release == 0xffff) { // Parameter wasn't set 37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The sa1100 controller is not supported */ 373091e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell if (gadget_is_sa1100(fsg->gadget)) 373191e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell gcnum = -1; 373291e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell else 373391e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell gcnum = usb_gadget_controller_number(fsg->gadget); 373491e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell if (gcnum >= 0) 373591e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell mod_data.release = 0x0300 + gcnum; 37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WARN(fsg, "controller '%s' not recognized\n", 37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->gadget->name); 37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.release = 0x0399; 37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot = simple_strtol(mod_data.protocol_parm, NULL, 0); 37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_FILE_STORAGE_TEST 37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { 37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Use default setting 37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { 37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_type = USB_PR_CB; 37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name = "Control-Bulk"; 37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { 37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_type = USB_PR_CBI; 37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name = "Control-Bulk-Interrupt"; 37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); 37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || 37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_SCSI) { 37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; // Use default setting 37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || 37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_RBC) { 37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_RBC; 37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "RBC"; 37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || 37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || 37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_8020) { 37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_8020; 37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "8020i (ATAPI)"; 37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || 37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_QIC) { 37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_QIC; 37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "QIC-157"; 37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || 37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_UFI) { 37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_UFI; 37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "UFI"; 37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || 37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds prot == USB_SC_8070) { 37811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_type = USB_SC_8070; 37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name = "8070i"; 37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); 37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.buflen &= PAGE_CACHE_MASK; 37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.buflen <= 0) { 37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid buflen\n"); 37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ETOOSMALL; 37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_USB_FILE_STORAGE_TEST */ 37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init fsg_bind(struct usb_gadget *gadget) 38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = the_fsg; 38021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lun *curlun; 38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_ep *ep; 38061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct usb_request *req; 38071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *pathbuf, *p; 38081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->gadget = gadget; 38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_gadget_data(gadget, fsg); 38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0 = gadget->ep0; 38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0->driver_data = fsg; 38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = check_parameters(fsg)) != 0) 38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mod_data.removable) { // Enable the store_xxx attributes 38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644; 38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_attr_ro.store = store_ro; 38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_attr_file.store = store_file; 38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find out how many LUNs there should be */ 38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = mod_data.nluns; 38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i == 0) 38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = max(mod_data.num_filenames, 1); 38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i > MAX_LUNS) { 38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "invalid number of LUNs: %d\n", i); 38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Create the LUNs, open their backing files, and register the 38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LUN devices in sysfs. */ 3835a922c68732725866c88457026cf06a7620846506Alan Stern fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL); 38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg->luns) { 38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOMEM; 38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->nluns = i; 38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 38431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->ro = ro[i]; 38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->dev.parent = &gadget->dev; 38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->dev.driver = &fsg_driver.driver; 38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_set_drvdata(&curlun->dev, fsg); 38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snprintf(curlun->dev.bus_id, BUS_ID_SIZE, 38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%s-lun%d", gadget->dev.bus_id, i); 38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = device_register(&curlun->dev)) != 0) 38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFO(fsg, "failed to register LUN%d: %d\n", i, rc); 38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->registered = 1; 38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->dev.release = lun_release; 38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file(&curlun->dev, &dev_attr_ro); 38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file(&curlun->dev, &dev_attr_file); 385887c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_get(&fsg->ref); 38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file[i] && *file[i]) { 38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = open_backing_file(curlun, file[i])) != 0) 38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (!mod_data.removable) { 38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "no file given for LUN%d\n", i); 38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -EINVAL; 38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find all the endpoints we will use */ 38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_ep_autoconfig_reset(gadget); 38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc); 38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) 38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto autoconf_fail; 38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; // claim the endpoint 38771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_in = ep; 38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_autoconfig(gadget, &fs_bulk_out_desc); 38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) 38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto autoconf_fail; 38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; // claim the endpoint 38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->bulk_out = ep; 38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (transport_is_cbi()) { 38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep = usb_ep_autoconfig(gadget, &fs_intr_in_desc); 38871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ep) 38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto autoconf_fail; 38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ep->driver_data = fsg; // claim the endpoint 38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->intr_in = ep; 38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fix up the descriptors */ 38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; 38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_desc.idVendor = cpu_to_le16(mod_data.vendor); 38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_desc.idProduct = cpu_to_le16(mod_data.product); 38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_desc.bcdDevice = cpu_to_le16(mod_data.release); 38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (transport_is_cbi() ? 3 : 2); // Number of endpoints 39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intf_desc.bNumEndpoints = i; 39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intf_desc.bInterfaceSubClass = mod_data.protocol_type; 39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intf_desc.bInterfaceProtocol = mod_data.transport_type; 39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL; 39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_GADGET_DUALSPEED 39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL; 39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Assume ep0 uses the same maxpacket value for both speeds */ 39091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; 39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Assume that all endpoint addresses are the same for both speeds */ 39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress; 39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress; 39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress; 39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (gadget->is_otg) { 39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds otg_desc.bmAttributes |= USB_OTG_HNP, 39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOMEM; 39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the request and buffer for endpoint 0 */ 39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); 39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE, 39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &req->dma, GFP_KERNEL); 39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req->buf) 39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->complete = ep0_complete; 39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Allocate the data buffers */ 39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NUM_BUFFERS; ++i) { 39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_buffhd *bh = &fsg->buffhds[i]; 39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen, 39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &bh->dma, GFP_KERNEL); 39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bh->buf) 39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bh->next = bh + 1; 39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->buffhds[NUM_BUFFERS - 1].next = &fsg->buffhds[0]; 39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This should reflect the actual gadget power source */ 39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_set_selfpowered(gadget); 39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", 39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds system_utsname.sysname, system_utsname.release, 39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gadget->name); 39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* On a real device, serial[] would be loaded from permanent 39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * storage. We just encode it from the driver version string. */ 39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < sizeof(serial) - 2; i += 2) { 39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char c = DRIVER_VERSION[i / 2]; 39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!c) 39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(&serial[i], "%02X", c); 39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 396322efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern fsg->thread_task = kthread_create(fsg_main_thread, fsg, 396422efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern "file-storage-gadget"); 396522efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern if (IS_ERR(fsg->thread_task)) { 396622efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern rc = PTR_ERR(fsg->thread_task); 39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 396822efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern } 39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); 39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); 39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); 39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < fsg->nluns; ++i) { 39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun = &fsg->luns[i]; 39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (backing_file_is_open(curlun)) { 39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = NULL; 39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pathbuf) { 39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = d_path(curlun->filp->f_dentry, 39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->filp->f_vfsmnt, 39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pathbuf, PATH_MAX); 39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(p)) 39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds p = NULL; 39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LINFO(curlun, "ro=%d, file: %s\n", 39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds curlun->ro, (p ? p : "(error)")); 39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(pathbuf); 39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "transport=%s (x%02x)\n", 39921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.transport_name, mod_data.transport_type); 39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "protocol=%s (x%02x)\n", 39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.protocol_name, mod_data.protocol_type); 39951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", 39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.vendor, mod_data.product, mod_data.release); 39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "removable=%d, stall=%d, buflen=%u\n", 39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.removable, mod_data.can_stall, 39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_data.buflen); 400022efcf4adec4262e0f49e6225f6cd070e4a85d20Alan Stern DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid); 4001a922c68732725866c88457026cf06a7620846506Alan Stern 4002a922c68732725866c88457026cf06a7620846506Alan Stern set_bit(REGISTERED, &fsg->atomic_bitflags); 4003a922c68732725866c88457026cf06a7620846506Alan Stern 4004a922c68732725866c88457026cf06a7620846506Alan Stern /* Tell the thread to start working */ 4005a922c68732725866c88457026cf06a7620846506Alan Stern wake_up_process(fsg->thread_task); 40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsautoconf_fail: 40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR(fsg, "unable to autoconfigure all endpoints\n"); 40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rc = -ENOTSUPP; 40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg->state = FSG_STATE_TERMINATED; // The thread is dead 40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg_unbind(gadget); 40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_all_backing_files(fsg); 40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 40171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsg_suspend(struct usb_gadget *gadget) 40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "suspend\n"); 40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(SUSPENDED, &fsg->atomic_bitflags); 40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void fsg_resume(struct usb_gadget *gadget) 40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = get_gadget_data(gadget); 40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG(fsg, "resume\n"); 40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(SUSPENDED, &fsg->atomic_bitflags); 40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*-------------------------------------------------------------------------*/ 40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_gadget_driver fsg_driver = { 40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_USB_GADGET_DUALSPEED 40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .speed = USB_SPEED_HIGH, 40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .speed = USB_SPEED_FULL, 40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .function = (char *) longname, 40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bind = fsg_bind, 40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .unbind = fsg_unbind, 40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disconnect = fsg_disconnect, 40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .setup = fsg_setup, 40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .suspend = fsg_suspend, 40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .resume = fsg_resume, 40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .driver = { 40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = (char *) shortname, 4057d0d5049fb02fc1082c17e08deecd6fed8db549b6Ben Dooks .owner = THIS_MODULE, 40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // .release = ... 40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // .suspend = ... 40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // .resume = ... 40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init fsg_alloc(void) 40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg; 40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4069a922c68732725866c88457026cf06a7620846506Alan Stern fsg = kzalloc(sizeof *fsg, GFP_KERNEL); 40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fsg) 40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&fsg->lock); 40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_rwsem(&fsg->filesem); 407487c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_init(&fsg->ref); 40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&fsg->thread_wqh); 40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_completion(&fsg->thread_notifier); 40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the_fsg = fsg; 40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init fsg_init(void) 40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rc; 40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg; 40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rc = fsg_alloc()) != 0) 40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rc; 40901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fsg = the_fsg; 4091a922c68732725866c88457026cf06a7620846506Alan Stern if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) 409287c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_put(&fsg->ref, fsg_release); 4093a922c68732725866c88457026cf06a7620846506Alan Stern return rc; 40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(fsg_init); 40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit fsg_cleanup(void) 40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fsg_dev *fsg = the_fsg; 41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unregister the driver iff the thread hasn't already done so */ 41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) 41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds usb_gadget_unregister_driver(&fsg_driver); 41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Wait for the thread to finish up */ 41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_for_completion(&fsg->thread_notifier); 41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds close_all_backing_files(fsg); 411087c4252a35310fdbb2aabb880a39b83f83cadf62Alan Stern kref_put(&fsg->ref, fsg_release); 41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(fsg_cleanup); 4113