usb: gadget: Gadget directory cleanup - group legacy gadgets
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Tue, 15 Jul 2014 11:09:44 +0000 (13:09 +0200)
committerFelipe Balbi <balbi@ti.com>
Wed, 16 Jul 2014 17:14:05 +0000 (12:14 -0500)
The drivers/usb/gadget directory contains many files.
Files which are related can be distributed into separate directories.
This patch moves the legacy gadgets (i.e. those not using configfs)
into a separate directory.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
42 files changed:
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/acm_ms.c [deleted file]
drivers/usb/gadget/audio.c [deleted file]
drivers/usb/gadget/cdc2.c [deleted file]
drivers/usb/gadget/dbgp.c [deleted file]
drivers/usb/gadget/ether.c [deleted file]
drivers/usb/gadget/g_ffs.c [deleted file]
drivers/usb/gadget/gmidi.c [deleted file]
drivers/usb/gadget/hid.c [deleted file]
drivers/usb/gadget/inode.c [deleted file]
drivers/usb/gadget/legacy/Kconfig [new file with mode: 0644]
drivers/usb/gadget/legacy/Makefile [new file with mode: 0644]
drivers/usb/gadget/legacy/acm_ms.c [new file with mode: 0644]
drivers/usb/gadget/legacy/audio.c [new file with mode: 0644]
drivers/usb/gadget/legacy/cdc2.c [new file with mode: 0644]
drivers/usb/gadget/legacy/dbgp.c [new file with mode: 0644]
drivers/usb/gadget/legacy/ether.c [new file with mode: 0644]
drivers/usb/gadget/legacy/g_ffs.c [new file with mode: 0644]
drivers/usb/gadget/legacy/gmidi.c [new file with mode: 0644]
drivers/usb/gadget/legacy/hid.c [new file with mode: 0644]
drivers/usb/gadget/legacy/inode.c [new file with mode: 0644]
drivers/usb/gadget/legacy/mass_storage.c [new file with mode: 0644]
drivers/usb/gadget/legacy/multi.c [new file with mode: 0644]
drivers/usb/gadget/legacy/ncm.c [new file with mode: 0644]
drivers/usb/gadget/legacy/nokia.c [new file with mode: 0644]
drivers/usb/gadget/legacy/printer.c [new file with mode: 0644]
drivers/usb/gadget/legacy/serial.c [new file with mode: 0644]
drivers/usb/gadget/legacy/tcm_usb_gadget.c [new file with mode: 0644]
drivers/usb/gadget/legacy/tcm_usb_gadget.h [new file with mode: 0644]
drivers/usb/gadget/legacy/webcam.c [new file with mode: 0644]
drivers/usb/gadget/legacy/zero.c [new file with mode: 0644]
drivers/usb/gadget/mass_storage.c [deleted file]
drivers/usb/gadget/multi.c [deleted file]
drivers/usb/gadget/ncm.c [deleted file]
drivers/usb/gadget/nokia.c [deleted file]
drivers/usb/gadget/printer.c [deleted file]
drivers/usb/gadget/serial.c [deleted file]
drivers/usb/gadget/tcm_usb_gadget.c [deleted file]
drivers/usb/gadget/tcm_usb_gadget.h [deleted file]
drivers/usb/gadget/webcam.c [deleted file]
drivers/usb/gadget/zero.c [deleted file]

index 49e434ec527d52f81c341f9a12bf0f2dc08c1815..2986a4369df4a25800d4600e3d204e3ab66b1b4a 100644 (file)
@@ -722,466 +722,7 @@ config USB_CONFIGFS_F_FS
          implemented in kernel space (for instance Ethernet, serial or
          mass storage) and other are implemented in user space.
 
-config USB_ZERO
-       tristate "Gadget Zero (DEVELOPMENT)"
-       select USB_LIBCOMPOSITE
-       select USB_F_SS_LB
-       help
-         Gadget Zero is a two-configuration device.  It either sinks and
-         sources bulk data; or it loops back a configurable number of
-         transfers.  It also implements control requests, for "chapter 9"
-         conformance.  The driver needs only two bulk-capable endpoints, so
-         it can work on top of most device-side usb controllers.  It's
-         useful for testing, and is also a working example showing how
-         USB "gadget drivers" can be written.
-
-         Make this be the first driver you try using on top of any new
-         USB peripheral controller driver.  Then you can use host-side
-         test software, like the "usbtest" driver, to put your hardware
-         and its driver through a basic set of functional tests.
-
-         Gadget Zero also works with the host-side "usb-skeleton" driver,
-         and with many kinds of host-side test software.  You may need
-         to tweak product and vendor IDs before host software knows about
-         this device, and arrange to select an appropriate configuration.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_zero".
-
-config USB_ZERO_HNPTEST
-       boolean "HNP Test Device"
-       depends on USB_ZERO && USB_OTG
-       help
-         You can configure this device to enumerate using the device
-         identifiers of the USB-OTG test device.  That means that when
-         this gadget connects to another OTG device, with this one using
-         the "B-Peripheral" role, that device will use HNP to let this
-         one serve as the USB host instead (in the "B-Host" role).
-
-config USB_AUDIO
-       tristate "Audio Gadget"
-       depends on SND
-       select USB_LIBCOMPOSITE
-       select SND_PCM
-       help
-         This Gadget Audio driver is compatible with USB Audio Class
-         specification 2.0. It implements 1 AudioControl interface,
-         1 AudioStreaming Interface each for USB-OUT and USB-IN.
-         Number of channels, sample rate and sample size can be
-         specified as module parameters.
-         This driver doesn't expect any real Audio codec to be present
-         on the device - the audio streams are simply sinked to and
-         sourced from a virtual ALSA sound card created. The user-space
-         application may choose to do whatever it wants with the data
-         received from the USB Host and choose to provide whatever it
-         wants as audio data to the USB Host.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_audio".
-
-config GADGET_UAC1
-       bool "UAC 1.0 (Legacy)"
-       depends on USB_AUDIO
-       help
-         If you instead want older UAC Spec-1.0 driver that also has audio
-         paths hardwired to the Audio codec chip on-board and doesn't work
-         without one.
-
-config USB_ETH
-       tristate "Ethernet Gadget (with CDC Ethernet support)"
-       depends on NET
-       select USB_LIBCOMPOSITE
-       select USB_U_ETHER
-       select USB_F_ECM
-       select USB_F_SUBSET
-       select CRC32
-       help
-         This driver implements Ethernet style communication, in one of
-         several ways:
-         
-          - The "Communication Device Class" (CDC) Ethernet Control Model.
-            That protocol is often avoided with pure Ethernet adapters, in
-            favor of simpler vendor-specific hardware, but is widely
-            supported by firmware for smart network devices.
-
-          - On hardware can't implement that protocol, a simple CDC subset
-            is used, placing fewer demands on USB.
-
-          - CDC Ethernet Emulation Model (EEM) is a newer standard that has
-            a simpler interface that can be used by more USB hardware.
-
-         RNDIS support is an additional option, more demanding than than
-         subset.
-
-         Within the USB device, this gadget driver exposes a network device
-         "usbX", where X depends on what other networking devices you have.
-         Treat it like a two-node Ethernet link:  host, and gadget.
-
-         The Linux-USB host-side "usbnet" driver interoperates with this
-         driver, so that deep I/O queues can be supported.  On 2.4 kernels,
-         use "CDCEther" instead, if you're using the CDC option. That CDC
-         mode should also interoperate with standard CDC Ethernet class
-         drivers on other host operating systems.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_ether".
-
-config USB_ETH_RNDIS
-       bool "RNDIS support"
-       depends on USB_ETH
-       select USB_LIBCOMPOSITE
-       select USB_F_RNDIS
-       default y
-       help
-          Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
-          and Microsoft provides redistributable binary RNDIS drivers for
-          older versions of Windows.
-
-          If you say "y" here, the Ethernet gadget driver will try to provide
-          a second device configuration, supporting RNDIS to talk to such
-          Microsoft USB hosts.
-          
-          To make MS-Windows work with this, use Documentation/usb/linux.inf
-          as the "driver info file".  For versions of MS-Windows older than
-          XP, you'll need to download drivers from Microsoft's website; a URL
-          is given in comments found in that info file.
-
-config USB_ETH_EEM
-       bool "Ethernet Emulation Model (EEM) support"
-       depends on USB_ETH
-       select USB_LIBCOMPOSITE
-       select USB_F_EEM
-       default n
-       help
-         CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
-         and therefore can be supported by more hardware.  Technically ECM and
-         EEM are designed for different applications.  The ECM model extends
-         the network interface to the target (e.g. a USB cable modem), and the
-         EEM model is for mobile devices to communicate with hosts using
-         ethernet over USB.  For Linux gadgets, however, the interface with
-         the host is the same (a usbX device), so the differences are minimal.
-
-         If you say "y" here, the Ethernet gadget driver will use the EEM
-         protocol rather than ECM.  If unsure, say "n".
-
-config USB_G_NCM
-       tristate "Network Control Model (NCM) support"
-       depends on NET
-       select USB_LIBCOMPOSITE
-       select USB_U_ETHER
-       select USB_F_NCM
-       select CRC32
-       help
-         This driver implements USB CDC NCM subclass standard. NCM is
-         an advanced protocol for Ethernet encapsulation, allows grouping
-         of several ethernet frames into one USB transfer and different
-         alignment possibilities.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_ncm".
-
-config USB_GADGETFS
-       tristate "Gadget Filesystem"
-       help
-         This driver provides a filesystem based API that lets user mode
-         programs implement a single-configuration USB device, including
-         endpoint I/O and control requests that don't relate to enumeration.
-         All endpoints, transfer speeds, and transfer types supported by
-         the hardware are available, through read() and write() calls.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "gadgetfs".
-
-config USB_FUNCTIONFS
-       tristate "Function Filesystem"
-       select USB_LIBCOMPOSITE
-       select USB_F_FS
-       select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
-       help
-         The Function Filesystem (FunctionFS) lets one create USB
-         composite functions in user space in the same way GadgetFS
-         lets one create USB gadgets in user space.  This allows creation
-         of composite gadgets such that some of the functions are
-         implemented in kernel space (for instance Ethernet, serial or
-         mass storage) and other are implemented in user space.
-
-         If you say "y" or "m" here you will be able what kind of
-         configurations the gadget will provide.
-
-         Say "y" to link the driver statically, or "m" to build
-         a dynamically linked module called "g_ffs".
-
-config USB_FUNCTIONFS_ETH
-       bool "Include configuration with CDC ECM (Ethernet)"
-       depends on USB_FUNCTIONFS && NET
-       select USB_U_ETHER
-       select USB_F_ECM
-       select USB_F_SUBSET
-       help
-         Include a configuration with CDC ECM function (Ethernet) and the
-         Function Filesystem.
-
-config USB_FUNCTIONFS_RNDIS
-       bool "Include configuration with RNDIS (Ethernet)"
-       depends on USB_FUNCTIONFS && NET
-       select USB_U_ETHER
-       select USB_F_RNDIS
-       help
-         Include a configuration with RNDIS function (Ethernet) and the Filesystem.
-
-config USB_FUNCTIONFS_GENERIC
-       bool "Include 'pure' configuration"
-       depends on USB_FUNCTIONFS
-       help
-         Include a configuration with the Function Filesystem alone with
-         no Ethernet interface.
-
-config USB_MASS_STORAGE
-       tristate "Mass Storage Gadget"
-       depends on BLOCK
-       select USB_LIBCOMPOSITE
-       select USB_F_MASS_STORAGE
-       help
-         The Mass Storage Gadget acts as a USB Mass Storage disk drive.
-         As its storage repository it can use a regular file or a block
-         device (in much the same way as the "loop" device driver),
-         specified as a module parameter or sysfs option.
-
-         This driver is a replacement for now removed File-backed
-         Storage Gadget (g_file_storage).
-
-         Say "y" to link the driver statically, or "m" to build
-         a dynamically linked module called "g_mass_storage".
-
-config USB_GADGET_TARGET
-       tristate "USB Gadget Target Fabric Module"
-       depends on TARGET_CORE
-       select USB_LIBCOMPOSITE
-       help
-         This fabric is an USB gadget. Two USB protocols are supported that is
-         BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
-         advertised on alternative interface 0 (primary) and UAS is on
-         alternative interface 1. Both protocols can work on USB2.0 and USB3.0.
-         UAS utilizes the USB 3.0 feature called streams support.
-
-config USB_G_SERIAL
-       tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
-       depends on TTY
-       select USB_U_SERIAL
-       select USB_F_ACM
-       select USB_F_SERIAL
-       select USB_F_OBEX
-       select USB_LIBCOMPOSITE
-       help
-         The Serial Gadget talks to the Linux-USB generic serial driver.
-         This driver supports a CDC-ACM module option, which can be used
-         to interoperate with MS-Windows hosts or with the Linux-USB
-         "cdc-acm" driver.
-
-         This driver also supports a CDC-OBEX option.  You will need a
-         user space OBEX server talking to /dev/ttyGS*, since the kernel
-         itself doesn't implement the OBEX protocol.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_serial".
-
-         For more information, see Documentation/usb/gadget_serial.txt
-         which includes instructions and a "driver info file" needed to
-         make MS-Windows work with CDC ACM.
-
-config USB_MIDI_GADGET
-       tristate "MIDI Gadget"
-       depends on SND
-       select USB_LIBCOMPOSITE
-       select SND_RAWMIDI
-       help
-         The MIDI Gadget acts as a USB Audio device, with one MIDI
-         input and one MIDI output. These MIDI jacks appear as
-         a sound "card" in the ALSA sound system. Other MIDI
-         connections can then be made on the gadget system, using
-         ALSA's aconnect utility etc.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_midi".
-
-config USB_G_PRINTER
-       tristate "Printer Gadget"
-       select USB_LIBCOMPOSITE
-       help
-         The Printer Gadget channels data between the USB host and a
-         userspace program driving the print engine. The user space
-         program reads and writes the device file /dev/g_printer to
-         receive or send printer data. It can use ioctl calls to
-         the device file to get or set printer status.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_printer".
-
-         For more information, see Documentation/usb/gadget_printer.txt
-         which includes sample code for accessing the device file.
-
-if TTY
-
-config USB_CDC_COMPOSITE
-       tristate "CDC Composite Device (Ethernet and ACM)"
-       depends on NET
-       select USB_LIBCOMPOSITE
-       select USB_U_SERIAL
-       select USB_U_ETHER
-       select USB_F_ACM
-       select USB_F_ECM
-       help
-         This driver provides two functions in one configuration:
-         a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
-
-         This driver requires four bulk and two interrupt endpoints,
-         plus the ability to handle altsettings.  Not all peripheral
-         controllers are that capable.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module.
-
-config USB_G_NOKIA
-       tristate "Nokia composite gadget"
-       depends on PHONET
-       select USB_LIBCOMPOSITE
-       select USB_U_SERIAL
-       select USB_U_ETHER
-       select USB_F_ACM
-       select USB_F_OBEX
-       select USB_F_PHONET
-       select USB_F_ECM
-       help
-         The Nokia composite gadget provides support for acm, obex
-         and phonet in only one composite gadget driver.
-
-         It's only really useful for N900 hardware. If you're building
-         a kernel for N900, say Y or M here. If unsure, say N.
-
-config USB_G_ACM_MS
-       tristate "CDC Composite Device (ACM and mass storage)"
-       depends on BLOCK
-       select USB_LIBCOMPOSITE
-       select USB_U_SERIAL
-       select USB_F_ACM
-       select USB_F_MASS_STORAGE
-       help
-         This driver provides two functions in one configuration:
-         a mass storage, and a CDC ACM (serial port) link.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_acm_ms".
-
-config USB_G_MULTI
-       tristate "Multifunction Composite Gadget"
-       depends on BLOCK && NET
-       select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
-       select USB_LIBCOMPOSITE
-       select USB_U_SERIAL
-       select USB_U_ETHER
-       select USB_F_ACM
-       select USB_F_MASS_STORAGE
-       help
-         The Multifunction Composite Gadget provides Ethernet (RNDIS
-         and/or CDC Ethernet), mass storage and ACM serial link
-         interfaces.
-
-         You will be asked to choose which of the two configurations is
-         to be available in the gadget.  At least one configuration must
-         be chosen to make the gadget usable.  Selecting more than one
-         configuration will prevent Windows from automatically detecting
-         the gadget as a composite gadget, so an INF file will be needed to
-         use the gadget.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_multi".
-
-config USB_G_MULTI_RNDIS
-       bool "RNDIS + CDC Serial + Storage configuration"
-       depends on USB_G_MULTI
-       select USB_F_RNDIS
-       default y
-       help
-         This option enables a configuration with RNDIS, CDC Serial and
-         Mass Storage functions available in the Multifunction Composite
-         Gadget.  This is the configuration dedicated for Windows since RNDIS
-         is Microsoft's protocol.
-
-         If unsure, say "y".
-
-config USB_G_MULTI_CDC
-       bool "CDC Ethernet + CDC Serial + Storage configuration"
-       depends on USB_G_MULTI
-       default n
-       select USB_F_ECM
-       help
-         This option enables a configuration with CDC Ethernet (ECM), CDC
-         Serial and Mass Storage functions available in the Multifunction
-         Composite Gadget.
-
-         If unsure, say "y".
-
-endif # TTY
-
-config USB_G_HID
-       tristate "HID Gadget"
-       select USB_LIBCOMPOSITE
-       help
-         The HID gadget driver provides generic emulation of USB
-         Human Interface Devices (HID).
-
-         For more information, see Documentation/usb/gadget_hid.txt which
-         includes sample code for accessing the device files.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_hid".
-
-# Standalone / single function gadgets
-config USB_G_DBGP
-       tristate "EHCI Debug Device Gadget"
-       depends on TTY
-       select USB_LIBCOMPOSITE
-       help
-         This gadget emulates an EHCI Debug device. This is useful when you want
-         to interact with an EHCI Debug Port.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_dbgp".
-
-if USB_G_DBGP
-choice
-       prompt "EHCI Debug Device mode"
-       default USB_G_DBGP_SERIAL
-
-config USB_G_DBGP_PRINTK
-       depends on USB_G_DBGP
-       bool "printk"
-       help
-         Directly printk() received data. No interaction.
-
-config USB_G_DBGP_SERIAL
-       depends on USB_G_DBGP
-       select USB_U_SERIAL
-       bool "serial"
-       help
-         Userland can interact using /dev/ttyGSxxx.
-endchoice
-endif
-
-# put drivers that need isochronous transfer support (for audio
-# or video class gadget drivers), or specific hardware, here.
-config USB_G_WEBCAM
-       tristate "USB Webcam Gadget"
-       depends on VIDEO_DEV
-       select USB_LIBCOMPOSITE
-       select VIDEOBUF2_VMALLOC
-       help
-         The Webcam Gadget acts as a composite USB Audio and Video Class
-         device. It provides a userspace API to process UVC control requests
-         and stream video data to the host.
-
-         Say "y" to link the driver statically, or "m" to build a
-         dynamically linked module called "g_webcam".
+source "drivers/usb/gadget/legacy/Kconfig"
 
 endchoice
 
index 49514ea60a98a7b740c734bd6904cd76bcdff128..61d2503ef561f232984d94d86f8b073e7149d869 100644 (file)
@@ -1,8 +1,8 @@
 #
 # USB peripheral controller drivers
 #
-ccflags-$(CONFIG_USB_GADGET_DEBUG)     := -DDEBUG
-ccflags-$(CONFIG_USB_GADGET_VERBOSE)   += -DVERBOSE_DEBUG
+subdir-ccflags-$(CONFIG_USB_GADGET_DEBUG)      := -DDEBUG
+subdir-ccflags-$(CONFIG_USB_GADGET_VERBOSE)    += -DVERBOSE_DEBUG
 
 obj-$(CONFIG_USB_GADGET)       += udc-core.o
 obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
@@ -64,42 +64,4 @@ obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o
 usb_f_fs-y                     := f_fs.o
 obj-$(CONFIG_USB_F_FS)         += usb_f_fs.o
 
-#
-# USB gadget drivers
-#
-g_zero-y                       := zero.o
-g_audio-y                      := audio.o
-g_ether-y                      := ether.o
-g_serial-y                     := serial.o
-g_midi-y                       := gmidi.o
-gadgetfs-y                     := inode.o
-g_mass_storage-y               := mass_storage.o
-g_printer-y                    := printer.o
-g_cdc-y                                := cdc2.o
-g_multi-y                      := multi.o
-g_hid-y                                := hid.o
-g_dbgp-y                       := dbgp.o
-g_nokia-y                      := nokia.o
-g_webcam-y                     := webcam.o
-g_ncm-y                                := ncm.o
-g_acm_ms-y                     := acm_ms.o
-g_tcm_usb_gadget-y             := tcm_usb_gadget.o
-
-obj-$(CONFIG_USB_ZERO)         += g_zero.o
-obj-$(CONFIG_USB_AUDIO)                += g_audio.o
-obj-$(CONFIG_USB_ETH)          += g_ether.o
-obj-$(CONFIG_USB_GADGETFS)     += gadgetfs.o
-obj-$(CONFIG_USB_FUNCTIONFS)   += g_ffs.o
-obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
-obj-$(CONFIG_USB_G_SERIAL)     += g_serial.o
-obj-$(CONFIG_USB_G_PRINTER)    += g_printer.o
-obj-$(CONFIG_USB_MIDI_GADGET)  += g_midi.o
-obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
-obj-$(CONFIG_USB_G_HID)                += g_hid.o
-obj-$(CONFIG_USB_G_DBGP)       += g_dbgp.o
-obj-$(CONFIG_USB_G_MULTI)      += g_multi.o
-obj-$(CONFIG_USB_G_NOKIA)      += g_nokia.o
-obj-$(CONFIG_USB_G_WEBCAM)     += g_webcam.o
-obj-$(CONFIG_USB_G_NCM)                += g_ncm.o
-obj-$(CONFIG_USB_G_ACM_MS)     += g_acm_ms.o
-obj-$(CONFIG_USB_GADGET_TARGET)        += tcm_usb_gadget.o
+obj-$(CONFIG_USB_GADGET)       += legacy/
diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c
deleted file mode 100644 (file)
index c30b7b5..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * acm_ms.c -- Composite driver, with ACM and mass storage support
- *
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 Nokia Corporation
- * Author: David Brownell
- * Modified: Klaus Schwarzkopf <schwarzkopf@sensortherm.de>
- *
- * Heavily based on multi.c and cdc2.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "u_serial.h"
-
-#define DRIVER_DESC            "Composite Gadget (ACM + MS)"
-#define DRIVER_VERSION         "2011/10/10"
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-#define ACM_MS_VENDOR_NUM      0x1d6b  /* Linux Foundation */
-#define ACM_MS_PRODUCT_NUM     0x0106  /* Composite Gadget: ACM + MS*/
-
-#include "f_mass_storage.h"
-
-/*-------------------------------------------------------------------------*/
-USB_GADGET_COMPOSITE_OPTIONS();
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16(0x0200),
-
-       .bDeviceClass =         USB_CLASS_MISC /* 0xEF */,
-       .bDeviceSubClass =      2,
-       .bDeviceProtocol =      1,
-
-       /* .bMaxPacketSize0 = f(hardware) */
-
-       /* Vendor and product id can be overridden by module parameters.  */
-       .idVendor =             cpu_to_le16(ACM_MS_VENDOR_NUM),
-       .idProduct =            cpu_to_le16(ACM_MS_PRODUCT_NUM),
-       /* .bcdDevice = f(hardware) */
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       /* NO SERIAL NUMBER */
-       /*.bNumConfigurations = DYNAMIC*/
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /*
-        * REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-/* string IDs are assigned dynamically */
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-/****************************** Configurations ******************************/
-
-static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
-
-#else
-
-/*
- * Number of buffers we will use.
- * 2 is usually enough for good buffering pipeline
- */
-#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
-
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-
-FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
-
-/*-------------------------------------------------------------------------*/
-static struct usb_function *f_acm;
-static struct usb_function_instance *f_acm_inst;
-
-static struct usb_function_instance *fi_msg;
-static struct usb_function *f_msg;
-
-/*
- * We _always_ have both ACM and mass storage functions.
- */
-static int __init acm_ms_do_config(struct usb_configuration *c)
-{
-       struct fsg_opts *opts;
-       int     status;
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       opts = fsg_opts_from_func_inst(fi_msg);
-
-       f_acm = usb_get_function(f_acm_inst);
-       if (IS_ERR(f_acm))
-               return PTR_ERR(f_acm);
-
-       f_msg = usb_get_function(fi_msg);
-       if (IS_ERR(f_msg)) {
-               status = PTR_ERR(f_msg);
-               goto put_acm;
-       }
-
-       status = usb_add_function(c, f_acm);
-       if (status < 0)
-               goto put_msg;
-
-       status = fsg_common_run_thread(opts->common);
-       if (status)
-               goto remove_acm;
-
-       status = usb_add_function(c, f_msg);
-       if (status)
-               goto remove_acm;
-
-       return 0;
-remove_acm:
-       usb_remove_function(c, f_acm);
-put_msg:
-       usb_put_function(f_msg);
-put_acm:
-       usb_put_function(f_acm);
-       return status;
-}
-
-static struct usb_configuration acm_ms_config_driver = {
-       .label                  = DRIVER_DESC,
-       .bConfigurationValue    = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init acm_ms_bind(struct usb_composite_dev *cdev)
-{
-       struct usb_gadget       *gadget = cdev->gadget;
-       struct fsg_opts         *opts;
-       struct fsg_config       config;
-       int                     status;
-
-       f_acm_inst = usb_get_function_instance("acm");
-       if (IS_ERR(f_acm_inst))
-               return PTR_ERR(f_acm_inst);
-
-       fi_msg = usb_get_function_instance("mass_storage");
-       if (IS_ERR(fi_msg)) {
-               status = PTR_ERR(fi_msg);
-               goto fail_get_msg;
-       }
-
-       /* set up mass storage function */
-       fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
-       opts = fsg_opts_from_func_inst(fi_msg);
-
-       opts->no_configfs = true;
-       status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
-       if (status)
-               goto fail;
-
-       status = fsg_common_set_nluns(opts->common, config.nluns);
-       if (status)
-               goto fail_set_nluns;
-
-       status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
-       if (status)
-               goto fail_set_cdev;
-
-       fsg_common_set_sysfs(opts->common, true);
-       status = fsg_common_create_luns(opts->common, &config);
-       if (status)
-               goto fail_set_cdev;
-
-       fsg_common_set_inquiry_string(opts->common, config.vendor_name,
-                                     config.product_name);
-       /*
-        * Allocate string descriptor numbers ... note that string
-        * contents can be overridden by the composite_dev glue.
-        */
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto fail_string_ids;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       /* register our configuration */
-       status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
-       if (status < 0)
-               goto fail_string_ids;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
-                       DRIVER_DESC);
-       return 0;
-
-       /* error recovery */
-fail_string_ids:
-       fsg_common_remove_luns(opts->common);
-fail_set_cdev:
-       fsg_common_free_luns(opts->common);
-fail_set_nluns:
-       fsg_common_free_buffers(opts->common);
-fail:
-       usb_put_function_instance(fi_msg);
-fail_get_msg:
-       usb_put_function_instance(f_acm_inst);
-       return status;
-}
-
-static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
-{
-       usb_put_function(f_msg);
-       usb_put_function_instance(fi_msg);
-       usb_put_function(f_acm);
-       usb_put_function_instance(f_acm_inst);
-       return 0;
-}
-
-static __refdata struct usb_composite_driver acm_ms_driver = {
-       .name           = "g_acm_ms",
-       .dev            = &device_desc,
-       .max_speed      = USB_SPEED_SUPER,
-       .strings        = dev_strings,
-       .bind           = acm_ms_bind,
-       .unbind         = __exit_p(acm_ms_unbind),
-};
-
-module_usb_composite_driver(acm_ms_driver);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
deleted file mode 100644 (file)
index 6eb695e..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * audio.c -- Audio gadget driver
- *
- * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
- * Copyright (C) 2008 Analog Devices, Inc
- *
- * Enter bugs at http://blackfin.uclinux.org/
- *
- * Licensed under the GPL-2 or later.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/usb/composite.h>
-
-#include "gadget_chips.h"
-#define DRIVER_DESC            "Linux USB Audio Gadget"
-#define DRIVER_VERSION         "Feb 2, 2012"
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-/* string IDs are assigned dynamically */
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language = 0x0409,     /* en-us */
-       .strings = strings_dev,
-};
-
-static struct usb_gadget_strings *audio_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-#ifdef CONFIG_GADGET_UAC1
-#include "u_uac1.h"
-#include "u_uac1.c"
-#include "f_uac1.c"
-#else
-#include "f_uac2.c"
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-
-/* Thanks to Linux Foundation for donating this product ID. */
-#define AUDIO_VENDOR_NUM               0x1d6b  /* Linux Foundation */
-#define AUDIO_PRODUCT_NUM              0x0101  /* Linux-USB Audio Gadget */
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               __constant_cpu_to_le16(0x200),
-
-#ifdef CONFIG_GADGET_UAC1
-       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
-       .bDeviceSubClass =      0,
-       .bDeviceProtocol =      0,
-#else
-       .bDeviceClass =         USB_CLASS_MISC,
-       .bDeviceSubClass =      0x02,
-       .bDeviceProtocol =      0x01,
-#endif
-       /* .bMaxPacketSize0 = f(hardware) */
-
-       /* Vendor and product id defaults change according to what configs
-        * we support.  (As does bNumConfigurations.)  These values can
-        * also be overridden by module parameters.
-        */
-       .idVendor =             __constant_cpu_to_le16(AUDIO_VENDOR_NUM),
-       .idProduct =            __constant_cpu_to_le16(AUDIO_PRODUCT_NUM),
-       /* .bcdDevice = f(hardware) */
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       /* NO SERIAL NUMBER */
-       .bNumConfigurations =   1,
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init audio_do_config(struct usb_configuration *c)
-{
-       /* FIXME alloc iConfiguration string, set it in c->strings */
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       audio_bind_config(c);
-
-       return 0;
-}
-
-static struct usb_configuration audio_config_driver = {
-       .label                  = DRIVER_DESC,
-       .bConfigurationValue    = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-#ifndef CONFIG_GADGET_UAC1
-       .unbind                 = uac2_unbind_config,
-#endif
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init audio_bind(struct usb_composite_dev *cdev)
-{
-       int                     status;
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto fail;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
-       if (status < 0)
-               goto fail;
-       usb_composite_overwrite_options(cdev, &coverwrite);
-
-       INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
-       return 0;
-
-fail:
-       return status;
-}
-
-static int __exit audio_unbind(struct usb_composite_dev *cdev)
-{
-#ifdef CONFIG_GADGET_UAC1
-       gaudio_cleanup();
-#endif
-       return 0;
-}
-
-static __refdata struct usb_composite_driver audio_driver = {
-       .name           = "g_audio",
-       .dev            = &device_desc,
-       .strings        = audio_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = audio_bind,
-       .unbind         = __exit_p(audio_unbind),
-};
-
-module_usb_composite_driver(audio_driver);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Bryan Wu <cooloney@kernel.org>");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
deleted file mode 100644 (file)
index 2e85d94..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * cdc2.c -- CDC Composite driver, with ECM and ACM support
- *
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "u_ether.h"
-#include "u_serial.h"
-#include "u_ecm.h"
-
-
-#define DRIVER_DESC            "CDC Composite Gadget"
-#define DRIVER_VERSION         "King Kamehameha Day 2008"
-
-/*-------------------------------------------------------------------------*/
-
-/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-
-/* Thanks to NetChip Technologies for donating this product ID.
- * It's for devices with only this composite CDC configuration.
- */
-#define CDC_VENDOR_NUM         0x0525  /* NetChip */
-#define CDC_PRODUCT_NUM                0xa4aa  /* CDC Composite: ECM + ACM */
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-USB_ETHERNET_MODULE_PARAMETERS();
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16(0x0200),
-
-       .bDeviceClass =         USB_CLASS_COMM,
-       .bDeviceSubClass =      0,
-       .bDeviceProtocol =      0,
-       /* .bMaxPacketSize0 = f(hardware) */
-
-       /* Vendor and product id can be overridden by module parameters.  */
-       .idVendor =             cpu_to_le16(CDC_VENDOR_NUM),
-       .idProduct =            cpu_to_le16(CDC_PRODUCT_NUM),
-       /* .bcdDevice = f(hardware) */
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       /* NO SERIAL NUMBER */
-       .bNumConfigurations =   1,
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-
-/* string IDs are assigned dynamically */
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-/*-------------------------------------------------------------------------*/
-static struct usb_function *f_acm;
-static struct usb_function_instance *fi_serial;
-
-static struct usb_function *f_ecm;
-static struct usb_function_instance *fi_ecm;
-
-/*
- * We _always_ have both CDC ECM and CDC ACM functions.
- */
-static int __init cdc_do_config(struct usb_configuration *c)
-{
-       int     status;
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       f_ecm = usb_get_function(fi_ecm);
-       if (IS_ERR(f_ecm)) {
-               status = PTR_ERR(f_ecm);
-               goto err_get_ecm;
-       }
-
-       status = usb_add_function(c, f_ecm);
-       if (status)
-               goto err_add_ecm;
-
-       f_acm = usb_get_function(fi_serial);
-       if (IS_ERR(f_acm)) {
-               status = PTR_ERR(f_acm);
-               goto err_get_acm;
-       }
-
-       status = usb_add_function(c, f_acm);
-       if (status)
-               goto err_add_acm;
-       return 0;
-
-err_add_acm:
-       usb_put_function(f_acm);
-err_get_acm:
-       usb_remove_function(c, f_ecm);
-err_add_ecm:
-       usb_put_function(f_ecm);
-err_get_ecm:
-       return status;
-}
-
-static struct usb_configuration cdc_config_driver = {
-       .label                  = "CDC Composite (ECM + ACM)",
-       .bConfigurationValue    = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init cdc_bind(struct usb_composite_dev *cdev)
-{
-       struct usb_gadget       *gadget = cdev->gadget;
-       struct f_ecm_opts       *ecm_opts;
-       int                     status;
-
-       if (!can_support_ecm(cdev->gadget)) {
-               dev_err(&gadget->dev, "controller '%s' not usable\n",
-                               gadget->name);
-               return -EINVAL;
-       }
-
-       fi_ecm = usb_get_function_instance("ecm");
-       if (IS_ERR(fi_ecm))
-               return PTR_ERR(fi_ecm);
-
-       ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
-
-       gether_set_qmult(ecm_opts->net, qmult);
-       if (!gether_set_host_addr(ecm_opts->net, host_addr))
-               pr_info("using host ethernet address: %s", host_addr);
-       if (!gether_set_dev_addr(ecm_opts->net, dev_addr))
-               pr_info("using self ethernet address: %s", dev_addr);
-
-       fi_serial = usb_get_function_instance("acm");
-       if (IS_ERR(fi_serial)) {
-               status = PTR_ERR(fi_serial);
-               goto fail;
-       }
-
-       /* Allocate string descriptor numbers ... note that string
-        * contents can be overridden by the composite_dev glue.
-        */
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto fail1;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       /* register our configuration */
-       status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config);
-       if (status < 0)
-               goto fail1;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
-                       DRIVER_DESC);
-
-       return 0;
-
-fail1:
-       usb_put_function_instance(fi_serial);
-fail:
-       usb_put_function_instance(fi_ecm);
-       return status;
-}
-
-static int __exit cdc_unbind(struct usb_composite_dev *cdev)
-{
-       usb_put_function(f_acm);
-       usb_put_function_instance(fi_serial);
-       if (!IS_ERR_OR_NULL(f_ecm))
-               usb_put_function(f_ecm);
-       if (!IS_ERR_OR_NULL(fi_ecm))
-               usb_put_function_instance(fi_ecm);
-       return 0;
-}
-
-static __refdata struct usb_composite_driver cdc_driver = {
-       .name           = "g_cdc",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = cdc_bind,
-       .unbind         = __exit_p(cdc_unbind),
-};
-
-module_usb_composite_driver(cdc_driver);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("David Brownell");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
deleted file mode 100644 (file)
index 986fc51..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * dbgp.c -- EHCI Debug Port device gadget
- *
- * Copyright (C) 2010 Stephane Duverger
- *
- * Released under the GPLv2.
- */
-
-/* verbose messages */
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-
-#include "u_serial.h"
-
-#define DRIVER_VENDOR_ID       0x0525 /* NetChip */
-#define DRIVER_PRODUCT_ID      0xc0de /* undefined */
-
-#define USB_DEBUG_MAX_PACKET_SIZE     8
-#define DBGP_REQ_EP0_LEN              128
-#define DBGP_REQ_LEN                  512
-
-static struct dbgp {
-       struct usb_gadget  *gadget;
-       struct usb_request *req;
-       struct usb_ep      *i_ep;
-       struct usb_ep      *o_ep;
-#ifdef CONFIG_USB_G_DBGP_SERIAL
-       struct gserial     *serial;
-#endif
-} dbgp;
-
-static struct usb_device_descriptor device_desc = {
-       .bLength = sizeof device_desc,
-       .bDescriptorType = USB_DT_DEVICE,
-       .bcdUSB = __constant_cpu_to_le16(0x0200),
-       .bDeviceClass = USB_CLASS_VENDOR_SPEC,
-       .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),
-       .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),
-       .bNumConfigurations = 1,
-};
-
-static struct usb_debug_descriptor dbg_desc = {
-       .bLength = sizeof dbg_desc,
-       .bDescriptorType = USB_DT_DEBUG,
-};
-
-static struct usb_endpoint_descriptor i_desc = {
-       .bLength = USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType = USB_DT_ENDPOINT,
-       .bmAttributes = USB_ENDPOINT_XFER_BULK,
-       .bEndpointAddress = USB_DIR_IN,
-};
-
-static struct usb_endpoint_descriptor o_desc = {
-       .bLength = USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType = USB_DT_ENDPOINT,
-       .bmAttributes = USB_ENDPOINT_XFER_BULK,
-       .bEndpointAddress = USB_DIR_OUT,
-};
-
-#ifdef CONFIG_USB_G_DBGP_PRINTK
-static int dbgp_consume(char *buf, unsigned len)
-{
-       char c;
-
-       if (!len)
-               return 0;
-
-       c = buf[len-1];
-       if (c != 0)
-               buf[len-1] = 0;
-
-       printk(KERN_NOTICE "%s%c", buf, c);
-       return 0;
-}
-
-static void __disable_ep(struct usb_ep *ep)
-{
-       if (ep && ep->driver_data == dbgp.gadget) {
-               usb_ep_disable(ep);
-               ep->driver_data = NULL;
-       }
-}
-
-static void dbgp_disable_ep(void)
-{
-       __disable_ep(dbgp.i_ep);
-       __disable_ep(dbgp.o_ep);
-}
-
-static void dbgp_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       int stp;
-       int err = 0;
-       int status = req->status;
-
-       if (ep == dbgp.i_ep) {
-               stp = 1;
-               goto fail;
-       }
-
-       if (status != 0) {
-               stp = 2;
-               goto release_req;
-       }
-
-       dbgp_consume(req->buf, req->actual);
-
-       req->length = DBGP_REQ_LEN;
-       err = usb_ep_queue(ep, req, GFP_ATOMIC);
-       if (err < 0) {
-               stp = 3;
-               goto release_req;
-       }
-
-       return;
-
-release_req:
-       kfree(req->buf);
-       usb_ep_free_request(dbgp.o_ep, req);
-       dbgp_disable_ep();
-fail:
-       dev_dbg(&dbgp.gadget->dev,
-               "complete: failure (%d:%d) ==> %d\n", stp, err, status);
-}
-
-static int dbgp_enable_ep_req(struct usb_ep *ep)
-{
-       int err, stp;
-       struct usb_request *req;
-
-       req = usb_ep_alloc_request(ep, GFP_KERNEL);
-       if (!req) {
-               err = -ENOMEM;
-               stp = 1;
-               goto fail_1;
-       }
-
-       req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
-       if (!req->buf) {
-               err = -ENOMEM;
-               stp = 2;
-               goto fail_2;
-       }
-
-       req->complete = dbgp_complete;
-       req->length = DBGP_REQ_LEN;
-       err = usb_ep_queue(ep, req, GFP_ATOMIC);
-       if (err < 0) {
-               stp = 3;
-               goto fail_3;
-       }
-
-       return 0;
-
-fail_3:
-       kfree(req->buf);
-fail_2:
-       usb_ep_free_request(dbgp.o_ep, req);
-fail_1:
-       dev_dbg(&dbgp.gadget->dev,
-               "enable ep req: failure (%d:%d)\n", stp, err);
-       return err;
-}
-
-static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
-{
-       int err;
-       ep->desc = desc;
-       err = usb_ep_enable(ep);
-       ep->driver_data = dbgp.gadget;
-       return err;
-}
-
-static int dbgp_enable_ep(void)
-{
-       int err, stp;
-
-       err = __enable_ep(dbgp.i_ep, &i_desc);
-       if (err < 0) {
-               stp = 1;
-               goto fail_1;
-       }
-
-       err = __enable_ep(dbgp.o_ep, &o_desc);
-       if (err < 0) {
-               stp = 2;
-               goto fail_2;
-       }
-
-       err = dbgp_enable_ep_req(dbgp.o_ep);
-       if (err < 0) {
-               stp = 3;
-               goto fail_3;
-       }
-
-       return 0;
-
-fail_3:
-       __disable_ep(dbgp.o_ep);
-fail_2:
-       __disable_ep(dbgp.i_ep);
-fail_1:
-       dev_dbg(&dbgp.gadget->dev, "enable ep: failure (%d:%d)\n", stp, err);
-       return err;
-}
-#endif
-
-static void dbgp_disconnect(struct usb_gadget *gadget)
-{
-#ifdef CONFIG_USB_G_DBGP_PRINTK
-       dbgp_disable_ep();
-#else
-       gserial_disconnect(dbgp.serial);
-#endif
-}
-
-static void dbgp_unbind(struct usb_gadget *gadget)
-{
-#ifdef CONFIG_USB_G_DBGP_SERIAL
-       kfree(dbgp.serial);
-#endif
-       if (dbgp.req) {
-               kfree(dbgp.req->buf);
-               usb_ep_free_request(gadget->ep0, dbgp.req);
-       }
-
-       gadget->ep0->driver_data = NULL;
-}
-
-#ifdef CONFIG_USB_G_DBGP_SERIAL
-static unsigned char tty_line;
-#endif
-
-static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
-{
-       int stp;
-
-       usb_ep_autoconfig_reset(gadget);
-
-       dbgp.i_ep = usb_ep_autoconfig(gadget, &i_desc);
-       if (!dbgp.i_ep) {
-               stp = 1;
-               goto fail_1;
-       }
-
-       dbgp.i_ep->driver_data = gadget;
-       i_desc.wMaxPacketSize =
-               __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
-
-       dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
-       if (!dbgp.o_ep) {
-               dbgp.i_ep->driver_data = NULL;
-               stp = 2;
-               goto fail_2;
-       }
-
-       dbgp.o_ep->driver_data = gadget;
-       o_desc.wMaxPacketSize =
-               __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
-
-       dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress;
-       dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress;
-
-#ifdef CONFIG_USB_G_DBGP_SERIAL
-       dbgp.serial->in = dbgp.i_ep;
-       dbgp.serial->out = dbgp.o_ep;
-
-       dbgp.serial->in->desc = &i_desc;
-       dbgp.serial->out->desc = &o_desc;
-
-       if (gserial_alloc_line(&tty_line)) {
-               stp = 3;
-               goto fail_3;
-       }
-
-       return 0;
-
-fail_3:
-       dbgp.o_ep->driver_data = NULL;
-#else
-       return 0;
-#endif
-fail_2:
-       dbgp.i_ep->driver_data = NULL;
-fail_1:
-       dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp);
-       return -ENODEV;
-}
-
-static int __init dbgp_bind(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver)
-{
-       int err, stp;
-
-       dbgp.gadget = gadget;
-
-       dbgp.req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
-       if (!dbgp.req) {
-               err = -ENOMEM;
-               stp = 1;
-               goto fail;
-       }
-
-       dbgp.req->buf = kmalloc(DBGP_REQ_EP0_LEN, GFP_KERNEL);
-       if (!dbgp.req->buf) {
-               err = -ENOMEM;
-               stp = 2;
-               goto fail;
-       }
-
-       dbgp.req->length = DBGP_REQ_EP0_LEN;
-       gadget->ep0->driver_data = gadget;
-
-#ifdef CONFIG_USB_G_DBGP_SERIAL
-       dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
-       if (!dbgp.serial) {
-               stp = 3;
-               err = -ENOMEM;
-               goto fail;
-       }
-#endif
-       err = dbgp_configure_endpoints(gadget);
-       if (err < 0) {
-               stp = 4;
-               goto fail;
-       }
-
-       dev_dbg(&dbgp.gadget->dev, "bind: success\n");
-       return 0;
-
-fail:
-       dev_dbg(&gadget->dev, "bind: failure (%d:%d)\n", stp, err);
-       dbgp_unbind(gadget);
-       return err;
-}
-
-static void dbgp_setup_complete(struct usb_ep *ep,
-                               struct usb_request *req)
-{
-       dev_dbg(&dbgp.gadget->dev, "setup complete: %d, %d/%d\n",
-               req->status, req->actual, req->length);
-}
-
-static int dbgp_setup(struct usb_gadget *gadget,
-                     const struct usb_ctrlrequest *ctrl)
-{
-       struct usb_request *req = dbgp.req;
-       u8 request = ctrl->bRequest;
-       u16 value = le16_to_cpu(ctrl->wValue);
-       u16 length = le16_to_cpu(ctrl->wLength);
-       int err = -EOPNOTSUPP;
-       void *data = NULL;
-       u16 len = 0;
-
-       gadget->ep0->driver_data = gadget;
-
-       if (request == USB_REQ_GET_DESCRIPTOR) {
-               switch (value>>8) {
-               case USB_DT_DEVICE:
-                       dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
-                       len = sizeof device_desc;
-                       data = &device_desc;
-                       device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-                       break;
-               case USB_DT_DEBUG:
-                       dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
-                       len = sizeof dbg_desc;
-                       data = &dbg_desc;
-                       break;
-               default:
-                       goto fail;
-               }
-               err = 0;
-       } else if (request == USB_REQ_SET_FEATURE &&
-                  value == USB_DEVICE_DEBUG_MODE) {
-               dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n");
-#ifdef CONFIG_USB_G_DBGP_PRINTK
-               err = dbgp_enable_ep();
-#else
-               err = gserial_connect(dbgp.serial, tty_line);
-#endif
-               if (err < 0)
-                       goto fail;
-       } else
-               goto fail;
-
-       req->length = min(length, len);
-       req->zero = len < req->length;
-       if (data && req->length)
-               memcpy(req->buf, data, req->length);
-
-       req->complete = dbgp_setup_complete;
-       return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
-
-fail:
-       dev_dbg(&dbgp.gadget->dev,
-               "setup: failure req %x v %x\n", request, value);
-       return err;
-}
-
-static __refdata struct usb_gadget_driver dbgp_driver = {
-       .function = "dbgp",
-       .max_speed = USB_SPEED_HIGH,
-       .bind = dbgp_bind,
-       .unbind = dbgp_unbind,
-       .setup = dbgp_setup,
-       .disconnect = dbgp_disconnect,
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = "dbgp"
-       },
-};
-
-static int __init dbgp_init(void)
-{
-       return usb_gadget_probe_driver(&dbgp_driver);
-}
-
-static void __exit dbgp_exit(void)
-{
-       usb_gadget_unregister_driver(&dbgp_driver);
-#ifdef CONFIG_USB_G_DBGP_SERIAL
-       gserial_free_line(tty_line);
-#endif
-}
-
-MODULE_AUTHOR("Stephane Duverger");
-MODULE_LICENSE("GPL");
-module_init(dbgp_init);
-module_exit(dbgp_exit);
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
deleted file mode 100644 (file)
index c5fdc61..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * ether.c -- Ethernet gadget driver, with CDC and non-CDC options
- *
- * Copyright (C) 2003-2005,2008 David Brownell
- * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-
-#if defined USB_ETH_RNDIS
-#  undef USB_ETH_RNDIS
-#endif
-#ifdef CONFIG_USB_ETH_RNDIS
-#  define USB_ETH_RNDIS y
-#endif
-
-#include "u_ether.h"
-
-
-/*
- * Ethernet gadget driver -- with CDC and non-CDC options
- * Builds on hardware support for a full duplex link.
- *
- * CDC Ethernet is the standard USB solution for sending Ethernet frames
- * using USB.  Real hardware tends to use the same framing protocol but look
- * different for control features.  This driver strongly prefers to use
- * this USB-IF standard as its open-systems interoperability solution;
- * most host side USB stacks (except from Microsoft) support it.
- *
- * This is sometimes called "CDC ECM" (Ethernet Control Model) to support
- * TLA-soup.  "CDC ACM" (Abstract Control Model) is for modems, and a new
- * "CDC EEM" (Ethernet Emulation Model) is starting to spread.
- *
- * There's some hardware that can't talk CDC ECM.  We make that hardware
- * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
- * link-level setup only requires activating the configuration.  Only the
- * endpoint descriptors, and product/vendor IDs, are relevant; no control
- * operations are available.  Linux supports it, but other host operating
- * systems may not.  (This is a subset of CDC Ethernet.)
- *
- * It turns out that if you add a few descriptors to that "CDC Subset",
- * (Windows) host side drivers from MCCI can treat it as one submode of
- * a proprietary scheme called "SAFE" ... without needing to know about
- * specific product/vendor IDs.  So we do that, making it easier to use
- * those MS-Windows drivers.  Those added descriptors make it resemble a
- * CDC MDLM device, but they don't change device behavior at all.  (See
- * MCCI Engineering report 950198 "SAFE Networking Functions".)
- *
- * A third option is also in use.  Rather than CDC Ethernet, or something
- * simpler, Microsoft pushes their own approach: RNDIS.  The published
- * RNDIS specs are ambiguous and appear to be incomplete, and are also
- * needlessly complex.  They borrow more from CDC ACM than CDC ECM.
- */
-
-#define DRIVER_DESC            "Ethernet Gadget"
-#define DRIVER_VERSION         "Memorial Day 2008"
-
-#ifdef USB_ETH_RNDIS
-#define PREFIX                 "RNDIS/"
-#else
-#define PREFIX                 ""
-#endif
-
-/*
- * This driver aims for interoperability by using CDC ECM unless
- *
- *             can_support_ecm()
- *
- * returns false, in which case it supports the CDC Subset.  By default,
- * that returns true; most hardware has no problems with CDC ECM, that's
- * a good default.  Previous versions of this driver had no default; this
- * version changes that, removing overhead for new controller support.
- *
- *     IF YOUR HARDWARE CAN'T SUPPORT CDC ECM, UPDATE THAT ROUTINE!
- */
-
-static inline bool has_rndis(void)
-{
-#ifdef USB_ETH_RNDIS
-       return true;
-#else
-       return false;
-#endif
-}
-
-#include <linux/module.h>
-
-#include "u_ecm.h"
-#include "u_gether.h"
-#ifdef USB_ETH_RNDIS
-#include "u_rndis.h"
-#include "rndis.h"
-#else
-#define rndis_borrow_net(...) do {} while (0)
-#endif
-#include "u_eem.h"
-
-/*-------------------------------------------------------------------------*/
-USB_GADGET_COMPOSITE_OPTIONS();
-
-USB_ETHERNET_MODULE_PARAMETERS();
-
-/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-
-/* Thanks to NetChip Technologies for donating this product ID.
- * It's for devices with only CDC Ethernet configurations.
- */
-#define CDC_VENDOR_NUM         0x0525  /* NetChip */
-#define CDC_PRODUCT_NUM                0xa4a1  /* Linux-USB Ethernet Gadget */
-
-/* For hardware that can't talk CDC, we use the same vendor ID that
- * ARM Linux has used for ethernet-over-usb, both with sa1100 and
- * with pxa250.  We're protocol-compatible, if the host-side drivers
- * use the endpoint descriptors.  bcdDevice (version) is nonzero, so
- * drivers that need to hard-wire endpoint numbers have a hook.
- *
- * The protocol is a minimal subset of CDC Ether, which works on any bulk
- * hardware that's not deeply broken ... even on hardware that can't talk
- * RNDIS (like SA-1100, with no interrupt endpoint, or anything that
- * doesn't handle control-OUT).
- */
-#define        SIMPLE_VENDOR_NUM       0x049f
-#define        SIMPLE_PRODUCT_NUM      0x505a
-
-/* For hardware that can talk RNDIS and either of the above protocols,
- * use this ID ... the windows INF files will know it.  Unless it's
- * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose
- * the non-RNDIS configuration.
- */
-#define RNDIS_VENDOR_NUM       0x0525  /* NetChip */
-#define RNDIS_PRODUCT_NUM      0xa4a2  /* Ethernet/RNDIS Gadget */
-
-/* For EEM gadgets */
-#define EEM_VENDOR_NUM         0x1d6b  /* Linux Foundation */
-#define EEM_PRODUCT_NUM                0x0102  /* EEM Gadget */
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16 (0x0200),
-
-       .bDeviceClass =         USB_CLASS_COMM,
-       .bDeviceSubClass =      0,
-       .bDeviceProtocol =      0,
-       /* .bMaxPacketSize0 = f(hardware) */
-
-       /* Vendor and product id defaults change according to what configs
-        * we support.  (As does bNumConfigurations.)  These values can
-        * also be overridden by module parameters.
-        */
-       .idVendor =             cpu_to_le16 (CDC_VENDOR_NUM),
-       .idProduct =            cpu_to_le16 (CDC_PRODUCT_NUM),
-       /* .bcdDevice = f(hardware) */
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       /* NO SERIAL NUMBER */
-       .bNumConfigurations =   1,
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = PREFIX DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-static struct usb_function_instance *fi_ecm;
-static struct usb_function *f_ecm;
-
-static struct usb_function_instance *fi_eem;
-static struct usb_function *f_eem;
-
-static struct usb_function_instance *fi_geth;
-static struct usb_function *f_geth;
-
-static struct usb_function_instance *fi_rndis;
-static struct usb_function *f_rndis;
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * We may not have an RNDIS configuration, but if we do it needs to be
- * the first one present.  That's to make Microsoft's drivers happy,
- * and to follow DOCSIS 1.0 (cable modem standard).
- */
-static int __init rndis_do_config(struct usb_configuration *c)
-{
-       int status;
-
-       /* FIXME alloc iConfiguration string, set it in c->strings */
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       f_rndis = usb_get_function(fi_rndis);
-       if (IS_ERR(f_rndis))
-               return PTR_ERR(f_rndis);
-
-       status = usb_add_function(c, f_rndis);
-       if (status < 0)
-               usb_put_function(f_rndis);
-
-       return status;
-}
-
-static struct usb_configuration rndis_config_driver = {
-       .label                  = "RNDIS",
-       .bConfigurationValue    = 2,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef CONFIG_USB_ETH_EEM
-static bool use_eem = 1;
-#else
-static bool use_eem;
-#endif
-module_param(use_eem, bool, 0);
-MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
-
-/*
- * We _always_ have an ECM, CDC Subset, or EEM configuration.
- */
-static int __init eth_do_config(struct usb_configuration *c)
-{
-       int status = 0;
-
-       /* FIXME alloc iConfiguration string, set it in c->strings */
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       if (use_eem) {
-               f_eem = usb_get_function(fi_eem);
-               if (IS_ERR(f_eem))
-                       return PTR_ERR(f_eem);
-
-               status = usb_add_function(c, f_eem);
-               if (status < 0)
-                       usb_put_function(f_eem);
-
-               return status;
-       } else if (can_support_ecm(c->cdev->gadget)) {
-               f_ecm = usb_get_function(fi_ecm);
-               if (IS_ERR(f_ecm))
-                       return PTR_ERR(f_ecm);
-
-               status = usb_add_function(c, f_ecm);
-               if (status < 0)
-                       usb_put_function(f_ecm);
-
-               return status;
-       } else {
-               f_geth = usb_get_function(fi_geth);
-               if (IS_ERR(f_geth))
-                       return PTR_ERR(f_geth);
-
-               status = usb_add_function(c, f_geth);
-               if (status < 0)
-                       usb_put_function(f_geth);
-
-               return status;
-       }
-
-}
-
-static struct usb_configuration eth_config_driver = {
-       /* .label = f(hardware) */
-       .bConfigurationValue    = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init eth_bind(struct usb_composite_dev *cdev)
-{
-       struct usb_gadget       *gadget = cdev->gadget;
-       struct f_eem_opts       *eem_opts = NULL;
-       struct f_ecm_opts       *ecm_opts = NULL;
-       struct f_gether_opts    *geth_opts = NULL;
-       struct net_device       *net;
-       int                     status;
-
-       /* set up main config label and device descriptor */
-       if (use_eem) {
-               /* EEM */
-               fi_eem = usb_get_function_instance("eem");
-               if (IS_ERR(fi_eem))
-                       return PTR_ERR(fi_eem);
-
-               eem_opts = container_of(fi_eem, struct f_eem_opts, func_inst);
-
-               net = eem_opts->net;
-
-               eth_config_driver.label = "CDC Ethernet (EEM)";
-               device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM);
-               device_desc.idProduct = cpu_to_le16(EEM_PRODUCT_NUM);
-       } else if (can_support_ecm(gadget)) {
-               /* ECM */
-
-               fi_ecm = usb_get_function_instance("ecm");
-               if (IS_ERR(fi_ecm))
-                       return PTR_ERR(fi_ecm);
-
-               ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
-
-               net = ecm_opts->net;
-
-               eth_config_driver.label = "CDC Ethernet (ECM)";
-       } else {
-               /* CDC Subset */
-
-               fi_geth = usb_get_function_instance("geth");
-               if (IS_ERR(fi_geth))
-                       return PTR_ERR(fi_geth);
-
-               geth_opts = container_of(fi_geth, struct f_gether_opts,
-                                        func_inst);
-
-               net = geth_opts->net;
-
-               eth_config_driver.label = "CDC Subset/SAFE";
-
-               device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM);
-               device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM);
-               if (!has_rndis())
-                       device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
-       }
-
-       gether_set_qmult(net, qmult);
-       if (!gether_set_host_addr(net, host_addr))
-               pr_info("using host ethernet address: %s", host_addr);
-       if (!gether_set_dev_addr(net, dev_addr))
-               pr_info("using self ethernet address: %s", dev_addr);
-
-       if (has_rndis()) {
-               /* RNDIS plus ECM-or-Subset */
-               gether_set_gadget(net, cdev->gadget);
-               status = gether_register_netdev(net);
-               if (status)
-                       goto fail;
-
-               if (use_eem)
-                       eem_opts->bound = true;
-               else if (can_support_ecm(gadget))
-                       ecm_opts->bound = true;
-               else
-                       geth_opts->bound = true;
-
-               fi_rndis = usb_get_function_instance("rndis");
-               if (IS_ERR(fi_rndis)) {
-                       status = PTR_ERR(fi_rndis);
-                       goto fail;
-               }
-
-               rndis_borrow_net(fi_rndis, net);
-
-               device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM);
-               device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM);
-               device_desc.bNumConfigurations = 2;
-       }
-
-       /* Allocate string descriptor numbers ... note that string
-        * contents can be overridden by the composite_dev glue.
-        */
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto fail1;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       /* register our configuration(s); RNDIS first, if it's used */
-       if (has_rndis()) {
-               status = usb_add_config(cdev, &rndis_config_driver,
-                               rndis_do_config);
-               if (status < 0)
-                       goto fail1;
-       }
-
-       status = usb_add_config(cdev, &eth_config_driver, eth_do_config);
-       if (status < 0)
-               goto fail1;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
-                       DRIVER_DESC);
-
-       return 0;
-
-fail1:
-       if (has_rndis())
-               usb_put_function_instance(fi_rndis);
-fail:
-       if (use_eem)
-               usb_put_function_instance(fi_eem);
-       else if (can_support_ecm(gadget))
-               usb_put_function_instance(fi_ecm);
-       else
-               usb_put_function_instance(fi_geth);
-       return status;
-}
-
-static int __exit eth_unbind(struct usb_composite_dev *cdev)
-{
-       if (has_rndis()) {
-               usb_put_function(f_rndis);
-               usb_put_function_instance(fi_rndis);
-       }
-       if (use_eem) {
-               usb_put_function(f_eem);
-               usb_put_function_instance(fi_eem);
-       } else if (can_support_ecm(cdev->gadget)) {
-               usb_put_function(f_ecm);
-               usb_put_function_instance(fi_ecm);
-       } else {
-               usb_put_function(f_geth);
-               usb_put_function_instance(fi_geth);
-       }
-       return 0;
-}
-
-static __refdata struct usb_composite_driver eth_driver = {
-       .name           = "g_ether",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_SUPER,
-       .bind           = eth_bind,
-       .unbind         = __exit_p(eth_unbind),
-};
-
-module_usb_composite_driver(eth_driver);
-
-MODULE_DESCRIPTION(PREFIX DRIVER_DESC);
-MODULE_AUTHOR("David Brownell, Benedikt Spanger");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
deleted file mode 100644 (file)
index 06acfa5..0000000
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * g_ffs.c -- user mode file system API for USB composite function controllers
- *
- * Copyright (C) 2010 Samsung Electronics
- * Author: Michal Nazarewicz <mina86@mina86.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#define pr_fmt(fmt) "g_ffs: " fmt
-
-#include <linux/module.h>
-
-#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
-#include <linux/netdevice.h>
-
-#  if defined USB_ETH_RNDIS
-#    undef USB_ETH_RNDIS
-#  endif
-#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-#    define USB_ETH_RNDIS y
-#  endif
-
-#  include "u_ecm.h"
-#  include "u_gether.h"
-#  ifdef USB_ETH_RNDIS
-#    include "u_rndis.h"
-#    include "rndis.h"
-#  endif
-#  include "u_ether.h"
-
-USB_ETHERNET_MODULE_PARAMETERS();
-
-#  ifdef CONFIG_USB_FUNCTIONFS_ETH
-static int eth_bind_config(struct usb_configuration *c);
-static struct usb_function_instance *fi_ecm;
-static struct usb_function *f_ecm;
-static struct usb_function_instance *fi_geth;
-static struct usb_function *f_geth;
-#  endif
-#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-static int bind_rndis_config(struct usb_configuration *c);
-static struct usb_function_instance *fi_rndis;
-static struct usb_function *f_rndis;
-#  endif
-#endif
-
-#include "u_fs.h"
-
-#define DRIVER_NAME    "g_ffs"
-#define DRIVER_DESC    "USB Function Filesystem"
-#define DRIVER_VERSION "24 Aug 2004"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Michal Nazarewicz");
-MODULE_LICENSE("GPL");
-
-#define GFS_VENDOR_ID  0x1d6b  /* Linux Foundation */
-#define GFS_PRODUCT_ID 0x0105  /* FunctionFS Gadget */
-
-#define GFS_MAX_DEVS   10
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-static struct usb_device_descriptor gfs_dev_desc = {
-       .bLength                = sizeof gfs_dev_desc,
-       .bDescriptorType        = USB_DT_DEVICE,
-
-       .bcdUSB                 = cpu_to_le16(0x0200),
-       .bDeviceClass           = USB_CLASS_PER_INTERFACE,
-
-       .idVendor               = cpu_to_le16(GFS_VENDOR_ID),
-       .idProduct              = cpu_to_le16(GFS_PRODUCT_ID),
-};
-
-static char *func_names[GFS_MAX_DEVS];
-static unsigned int func_num;
-
-module_param_named(bDeviceClass,    gfs_dev_desc.bDeviceClass,    byte,   0644);
-MODULE_PARM_DESC(bDeviceClass, "USB Device class");
-module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte,   0644);
-MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
-module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte,   0644);
-MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
-module_param_array_named(functions, func_names, charp, &func_num, 0);
-MODULE_PARM_DESC(functions, "USB Functions list");
-
-static const struct usb_descriptor_header *gfs_otg_desc[] = {
-       (const struct usb_descriptor_header *)
-       &(const struct usb_otg_descriptor) {
-               .bLength                = sizeof(struct usb_otg_descriptor),
-               .bDescriptorType        = USB_DT_OTG,
-
-               /*
-                * REVISIT SRP-only hardware is possible, although
-                * it would not be called "OTG" ...
-                */
-               .bmAttributes           = USB_OTG_SRP | USB_OTG_HNP,
-       },
-
-       NULL
-};
-
-/* String IDs are assigned dynamically */
-static struct usb_string gfs_strings[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-       { .s = "FunctionFS + RNDIS" },
-#endif
-#ifdef CONFIG_USB_FUNCTIONFS_ETH
-       { .s = "FunctionFS + ECM" },
-#endif
-#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
-       { .s = "FunctionFS" },
-#endif
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings *gfs_dev_strings[] = {
-       &(struct usb_gadget_strings) {
-               .language       = 0x0409,       /* en-us */
-               .strings        = gfs_strings,
-       },
-       NULL,
-};
-
-struct gfs_configuration {
-       struct usb_configuration c;
-       int (*eth)(struct usb_configuration *c);
-       int num;
-} gfs_configurations[] = {
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-       {
-               .eth            = bind_rndis_config,
-       },
-#endif
-
-#ifdef CONFIG_USB_FUNCTIONFS_ETH
-       {
-               .eth            = eth_bind_config,
-       },
-#endif
-
-#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
-       {
-       },
-#endif
-};
-
-static void *functionfs_acquire_dev(struct ffs_dev *dev);
-static void functionfs_release_dev(struct ffs_dev *dev);
-static int functionfs_ready_callback(struct ffs_data *ffs);
-static void functionfs_closed_callback(struct ffs_data *ffs);
-static int gfs_bind(struct usb_composite_dev *cdev);
-static int gfs_unbind(struct usb_composite_dev *cdev);
-static int gfs_do_config(struct usb_configuration *c);
-
-
-static __refdata struct usb_composite_driver gfs_driver = {
-       .name           = DRIVER_NAME,
-       .dev            = &gfs_dev_desc,
-       .strings        = gfs_dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = gfs_bind,
-       .unbind         = gfs_unbind,
-};
-
-static unsigned int missing_funcs;
-static bool gfs_registered;
-static bool gfs_single_func;
-static struct usb_function_instance **fi_ffs;
-static struct usb_function **f_ffs[] = {
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-       NULL,
-#endif
-
-#ifdef CONFIG_USB_FUNCTIONFS_ETH
-       NULL,
-#endif
-
-#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
-       NULL,
-#endif
-};
-
-#define N_CONF ARRAY_SIZE(f_ffs)
-
-static int __init gfs_init(void)
-{
-       struct f_fs_opts *opts;
-       int i;
-       int ret = 0;
-
-       ENTER();
-
-       if (func_num < 2) {
-               gfs_single_func = true;
-               func_num = 1;
-       }
-
-       /*
-        * Allocate in one chunk for easier maintenance
-        */
-       f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL);
-       if (!f_ffs[0]) {
-               ret = -ENOMEM;
-               goto no_func;
-       }
-       for (i = 1; i < N_CONF; ++i)
-               f_ffs[i] = f_ffs[0] + i * func_num;
-
-       fi_ffs = kcalloc(func_num, sizeof(*fi_ffs), GFP_KERNEL);
-       if (!fi_ffs) {
-               ret = -ENOMEM;
-               goto no_func;
-       }
-
-       for (i = 0; i < func_num; i++) {
-               fi_ffs[i] = usb_get_function_instance("ffs");
-               if (IS_ERR(fi_ffs[i])) {
-                       ret = PTR_ERR(fi_ffs[i]);
-                       --i;
-                       goto no_dev;
-               }
-               opts = to_f_fs_opts(fi_ffs[i]);
-               if (gfs_single_func)
-                       ret = ffs_single_dev(opts->dev);
-               else
-                       ret = ffs_name_dev(opts->dev, func_names[i]);
-               if (ret)
-                       goto no_dev;
-               opts->dev->ffs_ready_callback = functionfs_ready_callback;
-               opts->dev->ffs_closed_callback = functionfs_closed_callback;
-               opts->dev->ffs_acquire_dev_callback = functionfs_acquire_dev;
-               opts->dev->ffs_release_dev_callback = functionfs_release_dev;
-               opts->no_configfs = true;
-       }
-
-       missing_funcs = func_num;
-
-       return 0;
-no_dev:
-       while (i >= 0)
-               usb_put_function_instance(fi_ffs[i--]);
-       kfree(fi_ffs);
-no_func:
-       kfree(f_ffs[0]);
-       return ret;
-}
-module_init(gfs_init);
-
-static void __exit gfs_exit(void)
-{
-       int i;
-
-       ENTER();
-
-       if (gfs_registered)
-               usb_composite_unregister(&gfs_driver);
-       gfs_registered = false;
-
-       kfree(f_ffs[0]);
-
-       for (i = 0; i < func_num; i++)
-               usb_put_function_instance(fi_ffs[i]);
-
-       kfree(fi_ffs);
-}
-module_exit(gfs_exit);
-
-static void *functionfs_acquire_dev(struct ffs_dev *dev)
-{
-       if (!try_module_get(THIS_MODULE))
-               return ERR_PTR(-ENOENT);
-       
-       return 0;
-}
-
-static void functionfs_release_dev(struct ffs_dev *dev)
-{
-       module_put(THIS_MODULE);
-}
-
-/*
- * The caller of this function takes ffs_lock 
- */
-static int functionfs_ready_callback(struct ffs_data *ffs)
-{
-       int ret = 0;
-
-       if (--missing_funcs)
-               return 0;
-
-       if (gfs_registered)
-               return -EBUSY;
-
-       gfs_registered = true;
-
-       ret = usb_composite_probe(&gfs_driver);
-       if (unlikely(ret < 0))
-               gfs_registered = false;
-       
-       return ret;
-}
-
-/*
- * The caller of this function takes ffs_lock 
- */
-static void functionfs_closed_callback(struct ffs_data *ffs)
-{
-       missing_funcs++;
-
-       if (gfs_registered)
-               usb_composite_unregister(&gfs_driver);
-       gfs_registered = false;
-}
-
-/*
- * It is assumed that gfs_bind is called from a context where ffs_lock is held
- */
-static int gfs_bind(struct usb_composite_dev *cdev)
-{
-#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
-       struct net_device *net;
-#endif
-       int ret, i;
-
-       ENTER();
-
-       if (missing_funcs)
-               return -ENODEV;
-#if defined CONFIG_USB_FUNCTIONFS_ETH
-       if (can_support_ecm(cdev->gadget)) {
-               struct f_ecm_opts *ecm_opts;
-
-               fi_ecm = usb_get_function_instance("ecm");
-               if (IS_ERR(fi_ecm))
-                       return PTR_ERR(fi_ecm);
-               ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
-               net = ecm_opts->net;
-       } else {
-               struct f_gether_opts *geth_opts;
-
-               fi_geth = usb_get_function_instance("geth");
-               if (IS_ERR(fi_geth))
-                       return PTR_ERR(fi_geth);
-               geth_opts = container_of(fi_geth, struct f_gether_opts,
-                                        func_inst);
-               net = geth_opts->net;
-       }
-#endif
-
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-       {
-               struct f_rndis_opts *rndis_opts;
-
-               fi_rndis = usb_get_function_instance("rndis");
-               if (IS_ERR(fi_rndis)) {
-                       ret = PTR_ERR(fi_rndis);
-                       goto error;
-               }
-               rndis_opts = container_of(fi_rndis, struct f_rndis_opts,
-                                         func_inst);
-#ifndef CONFIG_USB_FUNCTIONFS_ETH
-               net = rndis_opts->net;
-#endif
-       }
-#endif
-
-#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
-       gether_set_qmult(net, qmult);
-       if (!gether_set_host_addr(net, host_addr))
-               pr_info("using host ethernet address: %s", host_addr);
-       if (!gether_set_dev_addr(net, dev_addr))
-               pr_info("using self ethernet address: %s", dev_addr);
-#endif
-
-#if defined CONFIG_USB_FUNCTIONFS_RNDIS && defined CONFIG_USB_FUNCTIONFS_ETH
-       gether_set_gadget(net, cdev->gadget);
-       ret = gether_register_netdev(net);
-       if (ret)
-               goto error_rndis;
-
-       if (can_support_ecm(cdev->gadget)) {
-               struct f_ecm_opts *ecm_opts;
-
-               ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
-               ecm_opts->bound = true;
-       } else {
-               struct f_gether_opts *geth_opts;
-
-               geth_opts = container_of(fi_geth, struct f_gether_opts,
-                                        func_inst);
-               geth_opts->bound = true;
-       }
-
-       rndis_borrow_net(fi_rndis, net);
-#endif
-
-       /* TODO: gstrings_attach? */
-       ret = usb_string_ids_tab(cdev, gfs_strings);
-       if (unlikely(ret < 0))
-               goto error_rndis;
-       gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
-
-       for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
-               struct gfs_configuration *c = gfs_configurations + i;
-               int sid = USB_GADGET_FIRST_AVAIL_IDX + i;
-
-               c->c.label                      = gfs_strings[sid].s;
-               c->c.iConfiguration             = gfs_strings[sid].id;
-               c->c.bConfigurationValue        = 1 + i;
-               c->c.bmAttributes               = USB_CONFIG_ATT_SELFPOWER;
-
-               c->num = i;
-
-               ret = usb_add_config(cdev, &c->c, gfs_do_config);
-               if (unlikely(ret < 0))
-                       goto error_unbind;
-       }
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       return 0;
-
-/* TODO */
-error_unbind:
-error_rndis:
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-       usb_put_function_instance(fi_rndis);
-error:
-#endif
-#if defined CONFIG_USB_FUNCTIONFS_ETH
-       if (can_support_ecm(cdev->gadget))
-               usb_put_function_instance(fi_ecm);
-       else
-               usb_put_function_instance(fi_geth);
-#endif
-       return ret;
-}
-
-/*
- * It is assumed that gfs_unbind is called from a context where ffs_lock is held
- */
-static int gfs_unbind(struct usb_composite_dev *cdev)
-{
-       int i;
-
-       ENTER();
-
-
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-       usb_put_function(f_rndis);
-       usb_put_function_instance(fi_rndis);
-#endif
-
-#if defined CONFIG_USB_FUNCTIONFS_ETH
-       if (can_support_ecm(cdev->gadget)) {
-               usb_put_function(f_ecm);
-               usb_put_function_instance(fi_ecm);
-       } else {
-               usb_put_function(f_geth);
-               usb_put_function_instance(fi_geth);
-       }
-#endif
-       for (i = 0; i < N_CONF * func_num; ++i)
-               usb_put_function(*(f_ffs[0] + i));
-
-       return 0;
-}
-
-/*
- * It is assumed that gfs_do_config is called from a context where
- * ffs_lock is held
- */
-static int gfs_do_config(struct usb_configuration *c)
-{
-       struct gfs_configuration *gc =
-               container_of(c, struct gfs_configuration, c);
-       int i;
-       int ret;
-
-       if (missing_funcs)
-               return -ENODEV;
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = gfs_otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       if (gc->eth) {
-               ret = gc->eth(c);
-               if (unlikely(ret < 0))
-                       return ret;
-       }
-
-       for (i = 0; i < func_num; i++) {
-               f_ffs[gc->num][i] = usb_get_function(fi_ffs[i]);
-               if (IS_ERR(f_ffs[gc->num][i])) {
-                       ret = PTR_ERR(f_ffs[gc->num][i]);
-                       goto error;
-               }
-               ret = usb_add_function(c, f_ffs[gc->num][i]);
-               if (ret < 0) {
-                       usb_put_function(f_ffs[gc->num][i]);
-                       goto error;
-               }
-       }
-
-       /*
-        * After previous do_configs there may be some invalid
-        * pointers in c->interface array.  This happens every time
-        * a user space function with fewer interfaces than a user
-        * space function that was run before the new one is run.  The
-        * compasit's set_config() assumes that if there is no more
-        * then MAX_CONFIG_INTERFACES interfaces in a configuration
-        * then there is a NULL pointer after the last interface in
-        * c->interface array.  We need to make sure this is true.
-        */
-       if (c->next_interface_id < ARRAY_SIZE(c->interface))
-               c->interface[c->next_interface_id] = NULL;
-
-       return 0;
-error:
-       while (--i >= 0) {
-               if (!IS_ERR(f_ffs[gc->num][i]))
-                       usb_remove_function(c, f_ffs[gc->num][i]);
-               usb_put_function(f_ffs[gc->num][i]);
-       }
-       return ret;
-}
-
-#ifdef CONFIG_USB_FUNCTIONFS_ETH
-
-static int eth_bind_config(struct usb_configuration *c)
-{
-       int status = 0;
-
-       if (can_support_ecm(c->cdev->gadget)) {
-               f_ecm = usb_get_function(fi_ecm);
-               if (IS_ERR(f_ecm))
-                       return PTR_ERR(f_ecm);
-
-               status = usb_add_function(c, f_ecm);
-               if (status < 0)
-                       usb_put_function(f_ecm);
-
-       } else {
-               f_geth = usb_get_function(fi_geth);
-               if (IS_ERR(f_geth))
-                       return PTR_ERR(f_geth);
-
-               status = usb_add_function(c, f_geth);
-               if (status < 0)
-                       usb_put_function(f_geth);
-       }
-       return status;
-}
-
-#endif
-
-#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
-
-static int bind_rndis_config(struct usb_configuration *c)
-{
-       int status = 0;
-
-       f_rndis = usb_get_function(fi_rndis);
-       if (IS_ERR(f_rndis))
-               return PTR_ERR(f_rndis);
-
-       status = usb_add_function(c, f_rndis);
-       if (status < 0)
-               usb_put_function(f_rndis);
-
-       return status;
-}
-
-#endif
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
deleted file mode 100644 (file)
index 3d696b8..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * gmidi.c -- USB MIDI Gadget Driver
- *
- * Copyright (C) 2006 Thumtronics Pty Ltd.
- * Developed for Thumtronics by Grey Innovation
- * Ben Williamson <ben.williamson@greyinnovation.com>
- *
- * This software is distributed under the terms of the GNU General Public
- * License ("GPL") version 2, as published by the Free Software Foundation.
- *
- * This code is based in part on:
- *
- * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell.
- * USB Audio driver, Copyright (C) 2002 by Takashi Iwai.
- * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch.
- *
- * Refer to the USB Device Class Definition for MIDI Devices:
- * http://www.usb.org/developers/devclass_docs/midi10.pdf
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/rawmidi.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/composite.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/audio.h>
-#include <linux/usb/midi.h>
-
-#include "gadget_chips.h"
-
-#include "f_midi.c"
-
-/*-------------------------------------------------------------------------*/
-
-MODULE_AUTHOR("Ben Williamson");
-MODULE_LICENSE("GPL v2");
-
-static const char shortname[] = "g_midi";
-static const char longname[] = "MIDI Gadget";
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-static int index = SNDRV_DEFAULT_IDX1;
-module_param(index, int, S_IRUGO);
-MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
-
-static char *id = SNDRV_DEFAULT_STR1;
-module_param(id, charp, S_IRUGO);
-MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
-
-static unsigned int buflen = 256;
-module_param(buflen, uint, S_IRUGO);
-MODULE_PARM_DESC(buflen, "MIDI buffer length");
-
-static unsigned int qlen = 32;
-module_param(qlen, uint, S_IRUGO);
-MODULE_PARM_DESC(qlen, "USB read request queue length");
-
-static unsigned int in_ports = 1;
-module_param(in_ports, uint, S_IRUGO);
-MODULE_PARM_DESC(in_ports, "Number of MIDI input ports");
-
-static unsigned int out_ports = 1;
-module_param(out_ports, uint, S_IRUGO);
-MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
-
-/* Thanks to Grey Innovation for donating this product ID.
- *
- * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-#define DRIVER_VENDOR_NUM      0x17b3          /* Grey Innovation */
-#define DRIVER_PRODUCT_NUM     0x0004          /* Linux-USB "MIDI Gadget" */
-
-/* string IDs are assigned dynamically */
-
-#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              USB_DT_DEVICE_SIZE,
-       .bDescriptorType =      USB_DT_DEVICE,
-       .bcdUSB =               __constant_cpu_to_le16(0x0200),
-       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
-       .idVendor =             __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
-       .idProduct =            __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
-       /* .iManufacturer =     DYNAMIC */
-       /* .iProduct =          DYNAMIC */
-       .bNumConfigurations =   1,
-};
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "Grey Innovation",
-       [USB_GADGET_PRODUCT_IDX].s      = "MIDI Gadget",
-       [USB_GADGET_SERIAL_IDX].s       = "",
-       [STRING_DESCRIPTION_IDX].s      = "MIDI",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-static int __exit midi_unbind(struct usb_composite_dev *dev)
-{
-       return 0;
-}
-
-static struct usb_configuration midi_config = {
-       .label          = "MIDI Gadget",
-       .bConfigurationValue = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes   = USB_CONFIG_ATT_ONE,
-       .MaxPower       = CONFIG_USB_GADGET_VBUS_DRAW,
-};
-
-static int __init midi_bind_config(struct usb_configuration *c)
-{
-       return f_midi_bind_config(c, index, id,
-                                 in_ports, out_ports,
-                                 buflen, qlen);
-}
-
-static int __init midi_bind(struct usb_composite_dev *cdev)
-{
-       int status;
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               return status;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-       midi_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id;
-
-       status = usb_add_config(cdev, &midi_config, midi_bind_config);
-       if (status < 0)
-               return status;
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       pr_info("%s\n", longname);
-       return 0;
-}
-
-static __refdata struct usb_composite_driver midi_driver = {
-       .name           = (char *) longname,
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = midi_bind,
-       .unbind         = __exit_p(midi_unbind),
-};
-
-module_usb_composite_driver(midi_driver);
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
deleted file mode 100644 (file)
index 778613e..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * hid.c -- HID Composite driver
- *
- * Based on multi.c
- *
- * Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/usb/composite.h>
-
-#include "gadget_chips.h"
-#define DRIVER_DESC            "HID Gadget"
-#define DRIVER_VERSION         "2010/03/16"
-
-/*-------------------------------------------------------------------------*/
-
-#define HIDG_VENDOR_NUM                0x0525  /* XXX NetChip */
-#define HIDG_PRODUCT_NUM       0xa4ac  /* Linux-USB HID gadget */
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "f_hid.c"
-
-
-struct hidg_func_node {
-       struct list_head node;
-       struct hidg_func_descriptor *func;
-};
-
-static LIST_HEAD(hidg_func_list);
-
-/*-------------------------------------------------------------------------*/
-USB_GADGET_COMPOSITE_OPTIONS();
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16(0x0200),
-
-       /* .bDeviceClass =              USB_CLASS_COMM, */
-       /* .bDeviceSubClass =   0, */
-       /* .bDeviceProtocol =   0, */
-       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
-       .bDeviceSubClass =      0,
-       .bDeviceProtocol =      0,
-       /* .bMaxPacketSize0 = f(hardware) */
-
-       /* Vendor and product id can be overridden by module parameters.  */
-       .idVendor =             cpu_to_le16(HIDG_VENDOR_NUM),
-       .idProduct =            cpu_to_le16(HIDG_PRODUCT_NUM),
-       /* .bcdDevice = f(hardware) */
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       /* NO SERIAL NUMBER */
-       .bNumConfigurations =   1,
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-
-/* string IDs are assigned dynamically */
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-
-
-/****************************** Configurations ******************************/
-
-static int __init do_config(struct usb_configuration *c)
-{
-       struct hidg_func_node *e;
-       int func = 0, status = 0;
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       list_for_each_entry(e, &hidg_func_list, node) {
-               status = hidg_bind_config(c, e->func, func++);
-               if (status)
-                       break;
-       }
-
-       return status;
-}
-
-static struct usb_configuration config_driver = {
-       .label                  = "HID Gadget",
-       .bConfigurationValue    = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-/****************************** Gadget Bind ******************************/
-
-static int __init hid_bind(struct usb_composite_dev *cdev)
-{
-       struct usb_gadget *gadget = cdev->gadget;
-       struct list_head *tmp;
-       int status, funcs = 0;
-
-       list_for_each(tmp, &hidg_func_list)
-               funcs++;
-
-       if (!funcs)
-               return -ENODEV;
-
-       /* set up HID */
-       status = ghid_setup(cdev->gadget, funcs);
-       if (status < 0)
-               return status;
-
-       /* Allocate string descriptor numbers ... note that string
-        * contents can be overridden by the composite_dev glue.
-        */
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               return status;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       /* register our configuration */
-       status = usb_add_config(cdev, &config_driver, do_config);
-       if (status < 0)
-               return status;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
-
-       return 0;
-}
-
-static int __exit hid_unbind(struct usb_composite_dev *cdev)
-{
-       ghid_cleanup();
-       return 0;
-}
-
-static int __init hidg_plat_driver_probe(struct platform_device *pdev)
-{
-       struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
-       struct hidg_func_node *entry;
-
-       if (!func) {
-               dev_err(&pdev->dev, "Platform data missing\n");
-               return -ENODEV;
-       }
-
-       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
-       if (!entry)
-               return -ENOMEM;
-
-       entry->func = func;
-       list_add_tail(&entry->node, &hidg_func_list);
-
-       return 0;
-}
-
-static int hidg_plat_driver_remove(struct platform_device *pdev)
-{
-       struct hidg_func_node *e, *n;
-
-       list_for_each_entry_safe(e, n, &hidg_func_list, node) {
-               list_del(&e->node);
-               kfree(e);
-       }
-
-       return 0;
-}
-
-
-/****************************** Some noise ******************************/
-
-
-static __refdata struct usb_composite_driver hidg_driver = {
-       .name           = "g_hid",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = hid_bind,
-       .unbind         = __exit_p(hid_unbind),
-};
-
-static struct platform_driver hidg_plat_driver = {
-       .remove         = hidg_plat_driver_remove,
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "hidg",
-       },
-};
-
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
-MODULE_LICENSE("GPL");
-
-static int __init hidg_init(void)
-{
-       int status;
-
-       status = platform_driver_probe(&hidg_plat_driver,
-                               hidg_plat_driver_probe);
-       if (status < 0)
-               return status;
-
-       status = usb_composite_probe(&hidg_driver);
-       if (status < 0)
-               platform_driver_unregister(&hidg_plat_driver);
-
-       return status;
-}
-module_init(hidg_init);
-
-static void __exit hidg_cleanup(void)
-{
-       platform_driver_unregister(&hidg_plat_driver);
-       usb_composite_unregister(&hidg_driver);
-}
-module_exit(hidg_cleanup);
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
deleted file mode 100644 (file)
index ee6c164..0000000
+++ /dev/null
@@ -1,2142 +0,0 @@
-/*
- * inode.c -- user mode filesystem api for usb gadget controllers
- *
- * Copyright (C) 2003-2004 David Brownell
- * Copyright (C) 2003 Agilent Technologies
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/pagemap.h>
-#include <linux/uts.h>
-#include <linux/wait.h>
-#include <linux/compiler.h>
-#include <asm/uaccess.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/mmu_context.h>
-#include <linux/aio.h>
-
-#include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <linux/usb/gadgetfs.h>
-#include <linux/usb/gadget.h>
-
-
-/*
- * The gadgetfs API maps each endpoint to a file descriptor so that you
- * can use standard synchronous read/write calls for I/O.  There's some
- * O_NONBLOCK and O_ASYNC/FASYNC style i/o support.  Example usermode
- * drivers show how this works in practice.  You can also use AIO to
- * eliminate I/O gaps between requests, to help when streaming data.
- *
- * Key parts that must be USB-specific are protocols defining how the
- * read/write operations relate to the hardware state machines.  There
- * are two types of files.  One type is for the device, implementing ep0.
- * The other type is for each IN or OUT endpoint.  In both cases, the
- * user mode driver must configure the hardware before using it.
- *
- * - First, dev_config() is called when /dev/gadget/$CHIP is configured
- *   (by writing configuration and device descriptors).  Afterwards it
- *   may serve as a source of device events, used to handle all control
- *   requests other than basic enumeration.
- *
- * - Then, after a SET_CONFIGURATION control request, ep_config() is
- *   called when each /dev/gadget/ep* file is configured (by writing
- *   endpoint descriptors).  Afterwards these files are used to write()
- *   IN data or to read() OUT data.  To halt the endpoint, a "wrong
- *   direction" request is issued (like reading an IN endpoint).
- *
- * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
- * not possible on all hardware.  For example, precise fault handling with
- * respect to data left in endpoint fifos after aborted operations; or
- * selective clearing of endpoint halts, to implement SET_INTERFACE.
- */
-
-#define        DRIVER_DESC     "USB Gadget filesystem"
-#define        DRIVER_VERSION  "24 Aug 2004"
-
-static const char driver_desc [] = DRIVER_DESC;
-static const char shortname [] = "gadgetfs";
-
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("GPL");
-
-
-/*----------------------------------------------------------------------*/
-
-#define GADGETFS_MAGIC         0xaee71ee7
-
-/* /dev/gadget/$CHIP represents ep0 and the whole device */
-enum ep0_state {
-       /* DISBLED is the initial state.
-        */
-       STATE_DEV_DISABLED = 0,
-
-       /* Only one open() of /dev/gadget/$CHIP; only one file tracks
-        * ep0/device i/o modes and binding to the controller.  Driver
-        * must always write descriptors to initialize the device, then
-        * the device becomes UNCONNECTED until enumeration.
-        */
-       STATE_DEV_OPENED,
-
-       /* From then on, ep0 fd is in either of two basic modes:
-        * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
-        * - SETUP: read/write will transfer control data and succeed;
-        *   or if "wrong direction", performs protocol stall
-        */
-       STATE_DEV_UNCONNECTED,
-       STATE_DEV_CONNECTED,
-       STATE_DEV_SETUP,
-
-       /* UNBOUND means the driver closed ep0, so the device won't be
-        * accessible again (DEV_DISABLED) until all fds are closed.
-        */
-       STATE_DEV_UNBOUND,
-};
-
-/* enough for the whole queue: most events invalidate others */
-#define        N_EVENT                 5
-
-struct dev_data {
-       spinlock_t                      lock;
-       atomic_t                        count;
-       enum ep0_state                  state;          /* P: lock */
-       struct usb_gadgetfs_event       event [N_EVENT];
-       unsigned                        ev_next;
-       struct fasync_struct            *fasync;
-       u8                              current_config;
-
-       /* drivers reading ep0 MUST handle control requests (SETUP)
-        * reported that way; else the host will time out.
-        */
-       unsigned                        usermode_setup : 1,
-                                       setup_in : 1,
-                                       setup_can_stall : 1,
-                                       setup_out_ready : 1,
-                                       setup_out_error : 1,
-                                       setup_abort : 1;
-       unsigned                        setup_wLength;
-
-       /* the rest is basically write-once */
-       struct usb_config_descriptor    *config, *hs_config;
-       struct usb_device_descriptor    *dev;
-       struct usb_request              *req;
-       struct usb_gadget               *gadget;
-       struct list_head                epfiles;
-       void                            *buf;
-       wait_queue_head_t               wait;
-       struct super_block              *sb;
-       struct dentry                   *dentry;
-
-       /* except this scratch i/o buffer for ep0 */
-       u8                              rbuf [256];
-};
-
-static inline void get_dev (struct dev_data *data)
-{
-       atomic_inc (&data->count);
-}
-
-static void put_dev (struct dev_data *data)
-{
-       if (likely (!atomic_dec_and_test (&data->count)))
-               return;
-       /* needs no more cleanup */
-       BUG_ON (waitqueue_active (&data->wait));
-       kfree (data);
-}
-
-static struct dev_data *dev_new (void)
-{
-       struct dev_data         *dev;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return NULL;
-       dev->state = STATE_DEV_DISABLED;
-       atomic_set (&dev->count, 1);
-       spin_lock_init (&dev->lock);
-       INIT_LIST_HEAD (&dev->epfiles);
-       init_waitqueue_head (&dev->wait);
-       return dev;
-}
-
-/*----------------------------------------------------------------------*/
-
-/* other /dev/gadget/$ENDPOINT files represent endpoints */
-enum ep_state {
-       STATE_EP_DISABLED = 0,
-       STATE_EP_READY,
-       STATE_EP_ENABLED,
-       STATE_EP_UNBOUND,
-};
-
-struct ep_data {
-       struct mutex                    lock;
-       enum ep_state                   state;
-       atomic_t                        count;
-       struct dev_data                 *dev;
-       /* must hold dev->lock before accessing ep or req */
-       struct usb_ep                   *ep;
-       struct usb_request              *req;
-       ssize_t                         status;
-       char                            name [16];
-       struct usb_endpoint_descriptor  desc, hs_desc;
-       struct list_head                epfiles;
-       wait_queue_head_t               wait;
-       struct dentry                   *dentry;
-       struct inode                    *inode;
-};
-
-static inline void get_ep (struct ep_data *data)
-{
-       atomic_inc (&data->count);
-}
-
-static void put_ep (struct ep_data *data)
-{
-       if (likely (!atomic_dec_and_test (&data->count)))
-               return;
-       put_dev (data->dev);
-       /* needs no more cleanup */
-       BUG_ON (!list_empty (&data->epfiles));
-       BUG_ON (waitqueue_active (&data->wait));
-       kfree (data);
-}
-
-/*----------------------------------------------------------------------*/
-
-/* most "how to use the hardware" policy choices are in userspace:
- * mapping endpoint roles (which the driver needs) to the capabilities
- * which the usb controller has.  most of those capabilities are exposed
- * implicitly, starting with the driver name and then endpoint names.
- */
-
-static const char *CHIP;
-
-/*----------------------------------------------------------------------*/
-
-/* NOTE:  don't use dev_printk calls before binding to the gadget
- * at the end of ep0 configuration, or after unbind.
- */
-
-/* too wordy: dev_printk(level , &(d)->gadget->dev , fmt , ## args) */
-#define xprintk(d,level,fmt,args...) \
-       printk(level "%s: " fmt , shortname , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-       xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE_DEBUG
-#define VDEBUG DBG
-#else
-#define VDEBUG(dev,fmt,args...) \
-       do { } while (0)
-#endif /* DEBUG */
-
-#define ERROR(dev,fmt,args...) \
-       xprintk(dev , KERN_ERR , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-       xprintk(dev , KERN_INFO , fmt , ## args)
-
-
-/*----------------------------------------------------------------------*/
-
-/* SYNCHRONOUS ENDPOINT OPERATIONS (bulk/intr/iso)
- *
- * After opening, configure non-control endpoints.  Then use normal
- * stream read() and write() requests; and maybe ioctl() to get more
- * precise FIFO status when recovering from cancellation.
- */
-
-static void epio_complete (struct usb_ep *ep, struct usb_request *req)
-{
-       struct ep_data  *epdata = ep->driver_data;
-
-       if (!req->context)
-               return;
-       if (req->status)
-               epdata->status = req->status;
-       else
-               epdata->status = req->actual;
-       complete ((struct completion *)req->context);
-}
-
-/* tasklock endpoint, returning when it's connected.
- * still need dev->lock to use epdata->ep.
- */
-static int
-get_ready_ep (unsigned f_flags, struct ep_data *epdata)
-{
-       int     val;
-
-       if (f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&epdata->lock))
-                       goto nonblock;
-               if (epdata->state != STATE_EP_ENABLED) {
-                       mutex_unlock(&epdata->lock);
-nonblock:
-                       val = -EAGAIN;
-               } else
-                       val = 0;
-               return val;
-       }
-
-       val = mutex_lock_interruptible(&epdata->lock);
-       if (val < 0)
-               return val;
-
-       switch (epdata->state) {
-       case STATE_EP_ENABLED:
-               break;
-       // case STATE_EP_DISABLED:              /* "can't happen" */
-       // case STATE_EP_READY:                 /* "can't happen" */
-       default:                                /* error! */
-               pr_debug ("%s: ep %p not available, state %d\n",
-                               shortname, epdata, epdata->state);
-               // FALLTHROUGH
-       case STATE_EP_UNBOUND:                  /* clean disconnect */
-               val = -ENODEV;
-               mutex_unlock(&epdata->lock);
-       }
-       return val;
-}
-
-static ssize_t
-ep_io (struct ep_data *epdata, void *buf, unsigned len)
-{
-       DECLARE_COMPLETION_ONSTACK (done);
-       int value;
-
-       spin_lock_irq (&epdata->dev->lock);
-       if (likely (epdata->ep != NULL)) {
-               struct usb_request      *req = epdata->req;
-
-               req->context = &done;
-               req->complete = epio_complete;
-               req->buf = buf;
-               req->length = len;
-               value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC);
-       } else
-               value = -ENODEV;
-       spin_unlock_irq (&epdata->dev->lock);
-
-       if (likely (value == 0)) {
-               value = wait_event_interruptible (done.wait, done.done);
-               if (value != 0) {
-                       spin_lock_irq (&epdata->dev->lock);
-                       if (likely (epdata->ep != NULL)) {
-                               DBG (epdata->dev, "%s i/o interrupted\n",
-                                               epdata->name);
-                               usb_ep_dequeue (epdata->ep, epdata->req);
-                               spin_unlock_irq (&epdata->dev->lock);
-
-                               wait_event (done.wait, done.done);
-                               if (epdata->status == -ECONNRESET)
-                                       epdata->status = -EINTR;
-                       } else {
-                               spin_unlock_irq (&epdata->dev->lock);
-
-                               DBG (epdata->dev, "endpoint gone\n");
-                               epdata->status = -ENODEV;
-                       }
-               }
-               return epdata->status;
-       }
-       return value;
-}
-
-
-/* handle a synchronous OUT bulk/intr/iso transfer */
-static ssize_t
-ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
-
-       value = -ENOMEM;
-       kbuf = kmalloc (len, GFP_KERNEL);
-       if (unlikely (!kbuf))
-               goto free1;
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
-               data->name, len, (int) value);
-       if (value >= 0 && copy_to_user (buf, kbuf, value))
-               value = -EFAULT;
-
-free1:
-       mutex_unlock(&data->lock);
-       kfree (kbuf);
-       return value;
-}
-
-/* handle a synchronous IN bulk/intr/iso transfer */
-static ssize_t
-ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       void                    *kbuf;
-       ssize_t                 value;
-
-       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
-               return value;
-
-       /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (!usb_endpoint_dir_in(&data->desc)) {
-               if (usb_endpoint_xfer_isoc(&data->desc)) {
-                       mutex_unlock(&data->lock);
-                       return -EINVAL;
-               }
-               DBG (data->dev, "%s halt\n", data->name);
-               spin_lock_irq (&data->dev->lock);
-               if (likely (data->ep != NULL))
-                       usb_ep_set_halt (data->ep);
-               spin_unlock_irq (&data->dev->lock);
-               mutex_unlock(&data->lock);
-               return -EBADMSG;
-       }
-
-       /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
-
-       value = -ENOMEM;
-       kbuf = memdup_user(buf, len);
-       if (!kbuf) {
-               value = PTR_ERR(kbuf);
-               goto free1;
-       }
-
-       value = ep_io (data, kbuf, len);
-       VDEBUG (data->dev, "%s write %zu IN, status %d\n",
-               data->name, len, (int) value);
-free1:
-       mutex_unlock(&data->lock);
-       return value;
-}
-
-static int
-ep_release (struct inode *inode, struct file *fd)
-{
-       struct ep_data          *data = fd->private_data;
-       int value;
-
-       value = mutex_lock_interruptible(&data->lock);
-       if (value < 0)
-               return value;
-
-       /* clean up if this can be reopened */
-       if (data->state != STATE_EP_UNBOUND) {
-               data->state = STATE_EP_DISABLED;
-               data->desc.bDescriptorType = 0;
-               data->hs_desc.bDescriptorType = 0;
-               usb_ep_disable(data->ep);
-       }
-       mutex_unlock(&data->lock);
-       put_ep (data);
-       return 0;
-}
-
-static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
-{
-       struct ep_data          *data = fd->private_data;
-       int                     status;
-
-       if ((status = get_ready_ep (fd->f_flags, data)) < 0)
-               return status;
-
-       spin_lock_irq (&data->dev->lock);
-       if (likely (data->ep != NULL)) {
-               switch (code) {
-               case GADGETFS_FIFO_STATUS:
-                       status = usb_ep_fifo_status (data->ep);
-                       break;
-               case GADGETFS_FIFO_FLUSH:
-                       usb_ep_fifo_flush (data->ep);
-                       break;
-               case GADGETFS_CLEAR_HALT:
-                       status = usb_ep_clear_halt (data->ep);
-                       break;
-               default:
-                       status = -ENOTTY;
-               }
-       } else
-               status = -ENODEV;
-       spin_unlock_irq (&data->dev->lock);
-       mutex_unlock(&data->lock);
-       return status;
-}
-
-/*----------------------------------------------------------------------*/
-
-/* ASYNCHRONOUS ENDPOINT I/O OPERATIONS (bulk/intr/iso) */
-
-struct kiocb_priv {
-       struct usb_request      *req;
-       struct ep_data          *epdata;
-       struct kiocb            *iocb;
-       struct mm_struct        *mm;
-       struct work_struct      work;
-       void                    *buf;
-       const struct iovec      *iv;
-       unsigned long           nr_segs;
-       unsigned                actual;
-};
-
-static int ep_aio_cancel(struct kiocb *iocb)
-{
-       struct kiocb_priv       *priv = iocb->private;
-       struct ep_data          *epdata;
-       int                     value;
-
-       local_irq_disable();
-       epdata = priv->epdata;
-       // spin_lock(&epdata->dev->lock);
-       if (likely(epdata && epdata->ep && priv->req))
-               value = usb_ep_dequeue (epdata->ep, priv->req);
-       else
-               value = -EINVAL;
-       // spin_unlock(&epdata->dev->lock);
-       local_irq_enable();
-
-       return value;
-}
-
-static ssize_t ep_copy_to_user(struct kiocb_priv *priv)
-{
-       ssize_t                 len, total;
-       void                    *to_copy;
-       int                     i;
-
-       /* copy stuff into user buffers */
-       total = priv->actual;
-       len = 0;
-       to_copy = priv->buf;
-       for (i=0; i < priv->nr_segs; i++) {
-               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
-               if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
-                       if (len == 0)
-                               len = -EFAULT;
-                       break;
-               }
-
-               total -= this;
-               len += this;
-               to_copy += this;
-               if (total == 0)
-                       break;
-       }
-
-       return len;
-}
-
-static void ep_user_copy_worker(struct work_struct *work)
-{
-       struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work);
-       struct mm_struct *mm = priv->mm;
-       struct kiocb *iocb = priv->iocb;
-       size_t ret;
-
-       use_mm(mm);
-       ret = ep_copy_to_user(priv);
-       unuse_mm(mm);
-
-       /* completing the iocb can drop the ctx and mm, don't touch mm after */
-       aio_complete(iocb, ret, ret);
-
-       kfree(priv->buf);
-       kfree(priv);
-}
-
-static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       struct kiocb            *iocb = req->context;
-       struct kiocb_priv       *priv = iocb->private;
-       struct ep_data          *epdata = priv->epdata;
-
-       /* lock against disconnect (and ideally, cancel) */
-       spin_lock(&epdata->dev->lock);
-       priv->req = NULL;
-       priv->epdata = NULL;
-
-       /* if this was a write or a read returning no data then we
-        * don't need to copy anything to userspace, so we can
-        * complete the aio request immediately.
-        */
-       if (priv->iv == NULL || unlikely(req->actual == 0)) {
-               kfree(req->buf);
-               kfree(priv);
-               iocb->private = NULL;
-               /* aio_complete() reports bytes-transferred _and_ faults */
-               aio_complete(iocb, req->actual ? req->actual : req->status,
-                               req->status);
-       } else {
-               /* ep_copy_to_user() won't report both; we hide some faults */
-               if (unlikely(0 != req->status))
-                       DBG(epdata->dev, "%s fault %d len %d\n",
-                               ep->name, req->status, req->actual);
-
-               priv->buf = req->buf;
-               priv->actual = req->actual;
-               schedule_work(&priv->work);
-       }
-       spin_unlock(&epdata->dev->lock);
-
-       usb_ep_free_request(ep, req);
-       put_ep(epdata);
-}
-
-static ssize_t
-ep_aio_rwtail(
-       struct kiocb    *iocb,
-       char            *buf,
-       size_t          len,
-       struct ep_data  *epdata,
-       const struct iovec *iv,
-       unsigned long   nr_segs
-)
-{
-       struct kiocb_priv       *priv;
-       struct usb_request      *req;
-       ssize_t                 value;
-
-       priv = kmalloc(sizeof *priv, GFP_KERNEL);
-       if (!priv) {
-               value = -ENOMEM;
-fail:
-               kfree(buf);
-               return value;
-       }
-       iocb->private = priv;
-       priv->iocb = iocb;
-       priv->iv = iv;
-       priv->nr_segs = nr_segs;
-       INIT_WORK(&priv->work, ep_user_copy_worker);
-
-       value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
-       if (unlikely(value < 0)) {
-               kfree(priv);
-               goto fail;
-       }
-
-       kiocb_set_cancel_fn(iocb, ep_aio_cancel);
-       get_ep(epdata);
-       priv->epdata = epdata;
-       priv->actual = 0;
-       priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */
-
-       /* each kiocb is coupled to one usb_request, but we can't
-        * allocate or submit those if the host disconnected.
-        */
-       spin_lock_irq(&epdata->dev->lock);
-       if (likely(epdata->ep)) {
-               req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
-               if (likely(req)) {
-                       priv->req = req;
-                       req->buf = buf;
-                       req->length = len;
-                       req->complete = ep_aio_complete;
-                       req->context = iocb;
-                       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
-                       if (unlikely(0 != value))
-                               usb_ep_free_request(epdata->ep, req);
-               } else
-                       value = -EAGAIN;
-       } else
-               value = -ENODEV;
-       spin_unlock_irq(&epdata->dev->lock);
-
-       mutex_unlock(&epdata->lock);
-
-       if (unlikely(value)) {
-               kfree(priv);
-               put_ep(epdata);
-       } else
-               value = -EIOCBQUEUED;
-       return value;
-}
-
-static ssize_t
-ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
-{
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
-
-       if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
-
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
-               return -ENOMEM;
-
-       return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs);
-}
-
-static ssize_t
-ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
-               unsigned long nr_segs, loff_t o)
-{
-       struct ep_data          *epdata = iocb->ki_filp->private_data;
-       char                    *buf;
-       size_t                  len = 0;
-       int                     i = 0;
-
-       if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
-               return -EINVAL;
-
-       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
-       if (unlikely(!buf))
-               return -ENOMEM;
-
-       for (i=0; i < nr_segs; i++) {
-               if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
-                               iov[i].iov_len) != 0)) {
-                       kfree(buf);
-                       return -EFAULT;
-               }
-               len += iov[i].iov_len;
-       }
-       return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
-}
-
-/*----------------------------------------------------------------------*/
-
-/* used after endpoint configuration */
-static const struct file_operations ep_io_operations = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-
-       .read =         ep_read,
-       .write =        ep_write,
-       .unlocked_ioctl = ep_ioctl,
-       .release =      ep_release,
-
-       .aio_read =     ep_aio_read,
-       .aio_write =    ep_aio_write,
-};
-
-/* ENDPOINT INITIALIZATION
- *
- *     fd = open ("/dev/gadget/$ENDPOINT", O_RDWR)
- *     status = write (fd, descriptors, sizeof descriptors)
- *
- * That write establishes the endpoint configuration, configuring
- * the controller to process bulk, interrupt, or isochronous transfers
- * at the right maxpacket size, and so on.
- *
- * The descriptors are message type 1, identified by a host order u32
- * at the beginning of what's written.  Descriptor order is: full/low
- * speed descriptor, then optional high speed descriptor.
- */
-static ssize_t
-ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct ep_data          *data = fd->private_data;
-       struct usb_ep           *ep;
-       u32                     tag;
-       int                     value, length = len;
-
-       value = mutex_lock_interruptible(&data->lock);
-       if (value < 0)
-               return value;
-
-       if (data->state != STATE_EP_READY) {
-               value = -EL2HLT;
-               goto fail;
-       }
-
-       value = len;
-       if (len < USB_DT_ENDPOINT_SIZE + 4)
-               goto fail0;
-
-       /* we might need to change message format someday */
-       if (copy_from_user (&tag, buf, 4)) {
-               goto fail1;
-       }
-       if (tag != 1) {
-               DBG(data->dev, "config %s, bad tag %d\n", data->name, tag);
-               goto fail0;
-       }
-       buf += 4;
-       len -= 4;
-
-       /* NOTE:  audio endpoint extensions not accepted here;
-        * just don't include the extra bytes.
-        */
-
-       /* full/low speed descriptor, then high speed */
-       if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) {
-               goto fail1;
-       }
-       if (data->desc.bLength != USB_DT_ENDPOINT_SIZE
-                       || data->desc.bDescriptorType != USB_DT_ENDPOINT)
-               goto fail0;
-       if (len != USB_DT_ENDPOINT_SIZE) {
-               if (len != 2 * USB_DT_ENDPOINT_SIZE)
-                       goto fail0;
-               if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
-                                       USB_DT_ENDPOINT_SIZE)) {
-                       goto fail1;
-               }
-               if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE
-                               || data->hs_desc.bDescriptorType
-                                       != USB_DT_ENDPOINT) {
-                       DBG(data->dev, "config %s, bad hs length or type\n",
-                                       data->name);
-                       goto fail0;
-               }
-       }
-
-       spin_lock_irq (&data->dev->lock);
-       if (data->dev->state == STATE_DEV_UNBOUND) {
-               value = -ENOENT;
-               goto gone;
-       } else if ((ep = data->ep) == NULL) {
-               value = -ENODEV;
-               goto gone;
-       }
-       switch (data->dev->gadget->speed) {
-       case USB_SPEED_LOW:
-       case USB_SPEED_FULL:
-               ep->desc = &data->desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
-               break;
-       case USB_SPEED_HIGH:
-               /* fails if caller didn't provide that descriptor... */
-               ep->desc = &data->hs_desc;
-               value = usb_ep_enable(ep);
-               if (value == 0)
-                       data->state = STATE_EP_ENABLED;
-               break;
-       default:
-               DBG(data->dev, "unconnected, %s init abandoned\n",
-                               data->name);
-               value = -EINVAL;
-       }
-       if (value == 0) {
-               fd->f_op = &ep_io_operations;
-               value = length;
-       }
-gone:
-       spin_unlock_irq (&data->dev->lock);
-       if (value < 0) {
-fail:
-               data->desc.bDescriptorType = 0;
-               data->hs_desc.bDescriptorType = 0;
-       }
-       mutex_unlock(&data->lock);
-       return value;
-fail0:
-       value = -EINVAL;
-       goto fail;
-fail1:
-       value = -EFAULT;
-       goto fail;
-}
-
-static int
-ep_open (struct inode *inode, struct file *fd)
-{
-       struct ep_data          *data = inode->i_private;
-       int                     value = -EBUSY;
-
-       if (mutex_lock_interruptible(&data->lock) != 0)
-               return -EINTR;
-       spin_lock_irq (&data->dev->lock);
-       if (data->dev->state == STATE_DEV_UNBOUND)
-               value = -ENOENT;
-       else if (data->state == STATE_EP_DISABLED) {
-               value = 0;
-               data->state = STATE_EP_READY;
-               get_ep (data);
-               fd->private_data = data;
-               VDEBUG (data->dev, "%s ready\n", data->name);
-       } else
-               DBG (data->dev, "%s state %d\n",
-                       data->name, data->state);
-       spin_unlock_irq (&data->dev->lock);
-       mutex_unlock(&data->lock);
-       return value;
-}
-
-/* used before endpoint configuration */
-static const struct file_operations ep_config_operations = {
-       .llseek =       no_llseek,
-
-       .open =         ep_open,
-       .write =        ep_config,
-       .release =      ep_release,
-};
-
-/*----------------------------------------------------------------------*/
-
-/* EP0 IMPLEMENTATION can be partly in userspace.
- *
- * Drivers that use this facility receive various events, including
- * control requests the kernel doesn't handle.  Drivers that don't
- * use this facility may be too simple-minded for real applications.
- */
-
-static inline void ep0_readable (struct dev_data *dev)
-{
-       wake_up (&dev->wait);
-       kill_fasync (&dev->fasync, SIGIO, POLL_IN);
-}
-
-static void clean_req (struct usb_ep *ep, struct usb_request *req)
-{
-       struct dev_data         *dev = ep->driver_data;
-
-       if (req->buf != dev->rbuf) {
-               kfree(req->buf);
-               req->buf = dev->rbuf;
-       }
-       req->complete = epio_complete;
-       dev->setup_out_ready = 0;
-}
-
-static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
-{
-       struct dev_data         *dev = ep->driver_data;
-       unsigned long           flags;
-       int                     free = 1;
-
-       /* for control OUT, data must still get to userspace */
-       spin_lock_irqsave(&dev->lock, flags);
-       if (!dev->setup_in) {
-               dev->setup_out_error = (req->status != 0);
-               if (!dev->setup_out_error)
-                       free = 0;
-               dev->setup_out_ready = 1;
-               ep0_readable (dev);
-       }
-
-       /* clean up as appropriate */
-       if (free && req->buf != &dev->rbuf)
-               clean_req (ep, req);
-       req->complete = epio_complete;
-       spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
-{
-       struct dev_data *dev = ep->driver_data;
-
-       if (dev->setup_out_ready) {
-               DBG (dev, "ep0 request busy!\n");
-               return -EBUSY;
-       }
-       if (len > sizeof (dev->rbuf))
-               req->buf = kmalloc(len, GFP_ATOMIC);
-       if (req->buf == NULL) {
-               req->buf = dev->rbuf;
-               return -ENOMEM;
-       }
-       req->complete = ep0_complete;
-       req->length = len;
-       req->zero = 0;
-       return 0;
-}
-
-static ssize_t
-ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct dev_data                 *dev = fd->private_data;
-       ssize_t                         retval;
-       enum ep0_state                  state;
-
-       spin_lock_irq (&dev->lock);
-
-       /* report fd mode change before acting on it */
-       if (dev->setup_abort) {
-               dev->setup_abort = 0;
-               retval = -EIDRM;
-               goto done;
-       }
-
-       /* control DATA stage */
-       if ((state = dev->state) == STATE_DEV_SETUP) {
-
-               if (dev->setup_in) {            /* stall IN */
-                       VDEBUG(dev, "ep0in stall\n");
-                       (void) usb_ep_set_halt (dev->gadget->ep0);
-                       retval = -EL2HLT;
-                       dev->state = STATE_DEV_CONNECTED;
-
-               } else if (len == 0) {          /* ack SET_CONFIGURATION etc */
-                       struct usb_ep           *ep = dev->gadget->ep0;
-                       struct usb_request      *req = dev->req;
-
-                       if ((retval = setup_req (ep, req, 0)) == 0)
-                               retval = usb_ep_queue (ep, req, GFP_ATOMIC);
-                       dev->state = STATE_DEV_CONNECTED;
-
-                       /* assume that was SET_CONFIGURATION */
-                       if (dev->current_config) {
-                               unsigned power;
-
-                               if (gadget_is_dualspeed(dev->gadget)
-                                               && (dev->gadget->speed
-                                                       == USB_SPEED_HIGH))
-                                       power = dev->hs_config->bMaxPower;
-                               else
-                                       power = dev->config->bMaxPower;
-                               usb_gadget_vbus_draw(dev->gadget, 2 * power);
-                       }
-
-               } else {                        /* collect OUT data */
-                       if ((fd->f_flags & O_NONBLOCK) != 0
-                                       && !dev->setup_out_ready) {
-                               retval = -EAGAIN;
-                               goto done;
-                       }
-                       spin_unlock_irq (&dev->lock);
-                       retval = wait_event_interruptible (dev->wait,
-                                       dev->setup_out_ready != 0);
-
-                       /* FIXME state could change from under us */
-                       spin_lock_irq (&dev->lock);
-                       if (retval)
-                               goto done;
-
-                       if (dev->state != STATE_DEV_SETUP) {
-                               retval = -ECANCELED;
-                               goto done;
-                       }
-                       dev->state = STATE_DEV_CONNECTED;
-
-                       if (dev->setup_out_error)
-                               retval = -EIO;
-                       else {
-                               len = min (len, (size_t)dev->req->actual);
-// FIXME don't call this with the spinlock held ...
-                               if (copy_to_user (buf, dev->req->buf, len))
-                                       retval = -EFAULT;
-                               else
-                                       retval = len;
-                               clean_req (dev->gadget->ep0, dev->req);
-                               /* NOTE userspace can't yet choose to stall */
-                       }
-               }
-               goto done;
-       }
-
-       /* else normal: return event data */
-       if (len < sizeof dev->event [0]) {
-               retval = -EINVAL;
-               goto done;
-       }
-       len -= len % sizeof (struct usb_gadgetfs_event);
-       dev->usermode_setup = 1;
-
-scan:
-       /* return queued events right away */
-       if (dev->ev_next != 0) {
-               unsigned                i, n;
-
-               n = len / sizeof (struct usb_gadgetfs_event);
-               if (dev->ev_next < n)
-                       n = dev->ev_next;
-
-               /* ep0 i/o has special semantics during STATE_DEV_SETUP */
-               for (i = 0; i < n; i++) {
-                       if (dev->event [i].type == GADGETFS_SETUP) {
-                               dev->state = STATE_DEV_SETUP;
-                               n = i + 1;
-                               break;
-                       }
-               }
-               spin_unlock_irq (&dev->lock);
-               len = n * sizeof (struct usb_gadgetfs_event);
-               if (copy_to_user (buf, &dev->event, len))
-                       retval = -EFAULT;
-               else
-                       retval = len;
-               if (len > 0) {
-                       /* NOTE this doesn't guard against broken drivers;
-                        * concurrent ep0 readers may lose events.
-                        */
-                       spin_lock_irq (&dev->lock);
-                       if (dev->ev_next > n) {
-                               memmove(&dev->event[0], &dev->event[n],
-                                       sizeof (struct usb_gadgetfs_event)
-                                               * (dev->ev_next - n));
-                       }
-                       dev->ev_next -= n;
-                       spin_unlock_irq (&dev->lock);
-               }
-               return retval;
-       }
-       if (fd->f_flags & O_NONBLOCK) {
-               retval = -EAGAIN;
-               goto done;
-       }
-
-       switch (state) {
-       default:
-               DBG (dev, "fail %s, state %d\n", __func__, state);
-               retval = -ESRCH;
-               break;
-       case STATE_DEV_UNCONNECTED:
-       case STATE_DEV_CONNECTED:
-               spin_unlock_irq (&dev->lock);
-               DBG (dev, "%s wait\n", __func__);
-
-               /* wait for events */
-               retval = wait_event_interruptible (dev->wait,
-                               dev->ev_next != 0);
-               if (retval < 0)
-                       return retval;
-               spin_lock_irq (&dev->lock);
-               goto scan;
-       }
-
-done:
-       spin_unlock_irq (&dev->lock);
-       return retval;
-}
-
-static struct usb_gadgetfs_event *
-next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
-{
-       struct usb_gadgetfs_event       *event;
-       unsigned                        i;
-
-       switch (type) {
-       /* these events purge the queue */
-       case GADGETFS_DISCONNECT:
-               if (dev->state == STATE_DEV_SETUP)
-                       dev->setup_abort = 1;
-               // FALL THROUGH
-       case GADGETFS_CONNECT:
-               dev->ev_next = 0;
-               break;
-       case GADGETFS_SETUP:            /* previous request timed out */
-       case GADGETFS_SUSPEND:          /* same effect */
-               /* these events can't be repeated */
-               for (i = 0; i != dev->ev_next; i++) {
-                       if (dev->event [i].type != type)
-                               continue;
-                       DBG(dev, "discard old event[%d] %d\n", i, type);
-                       dev->ev_next--;
-                       if (i == dev->ev_next)
-                               break;
-                       /* indices start at zero, for simplicity */
-                       memmove (&dev->event [i], &dev->event [i + 1],
-                               sizeof (struct usb_gadgetfs_event)
-                                       * (dev->ev_next - i));
-               }
-               break;
-       default:
-               BUG ();
-       }
-       VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
-       event = &dev->event [dev->ev_next++];
-       BUG_ON (dev->ev_next > N_EVENT);
-       memset (event, 0, sizeof *event);
-       event->type = type;
-       return event;
-}
-
-static ssize_t
-ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct dev_data         *dev = fd->private_data;
-       ssize_t                 retval = -ESRCH;
-
-       spin_lock_irq (&dev->lock);
-
-       /* report fd mode change before acting on it */
-       if (dev->setup_abort) {
-               dev->setup_abort = 0;
-               retval = -EIDRM;
-
-       /* data and/or status stage for control request */
-       } else if (dev->state == STATE_DEV_SETUP) {
-
-               /* IN DATA+STATUS caller makes len <= wLength */
-               if (dev->setup_in) {
-                       retval = setup_req (dev->gadget->ep0, dev->req, len);
-                       if (retval == 0) {
-                               dev->state = STATE_DEV_CONNECTED;
-                               spin_unlock_irq (&dev->lock);
-                               if (copy_from_user (dev->req->buf, buf, len))
-                                       retval = -EFAULT;
-                               else {
-                                       if (len < dev->setup_wLength)
-                                               dev->req->zero = 1;
-                                       retval = usb_ep_queue (
-                                               dev->gadget->ep0, dev->req,
-                                               GFP_KERNEL);
-                               }
-                               if (retval < 0) {
-                                       spin_lock_irq (&dev->lock);
-                                       clean_req (dev->gadget->ep0, dev->req);
-                                       spin_unlock_irq (&dev->lock);
-                               } else
-                                       retval = len;
-
-                               return retval;
-                       }
-
-               /* can stall some OUT transfers */
-               } else if (dev->setup_can_stall) {
-                       VDEBUG(dev, "ep0out stall\n");
-                       (void) usb_ep_set_halt (dev->gadget->ep0);
-                       retval = -EL2HLT;
-                       dev->state = STATE_DEV_CONNECTED;
-               } else {
-                       DBG(dev, "bogus ep0out stall!\n");
-               }
-       } else
-               DBG (dev, "fail %s, state %d\n", __func__, dev->state);
-
-       spin_unlock_irq (&dev->lock);
-       return retval;
-}
-
-static int
-ep0_fasync (int f, struct file *fd, int on)
-{
-       struct dev_data         *dev = fd->private_data;
-       // caller must F_SETOWN before signal delivery happens
-       VDEBUG (dev, "%s %s\n", __func__, on ? "on" : "off");
-       return fasync_helper (f, fd, on, &dev->fasync);
-}
-
-static struct usb_gadget_driver gadgetfs_driver;
-
-static int
-dev_release (struct inode *inode, struct file *fd)
-{
-       struct dev_data         *dev = fd->private_data;
-
-       /* closing ep0 === shutdown all */
-
-       usb_gadget_unregister_driver (&gadgetfs_driver);
-
-       /* at this point "good" hardware has disconnected the
-        * device from USB; the host won't see it any more.
-        * alternatively, all host requests will time out.
-        */
-
-       kfree (dev->buf);
-       dev->buf = NULL;
-       put_dev (dev);
-
-       return 0;
-}
-
-static unsigned int
-ep0_poll (struct file *fd, poll_table *wait)
-{
-       struct dev_data         *dev = fd->private_data;
-       int                     mask = 0;
-
-       poll_wait(fd, &dev->wait, wait);
-
-       spin_lock_irq (&dev->lock);
-
-       /* report fd mode change before acting on it */
-       if (dev->setup_abort) {
-               dev->setup_abort = 0;
-               mask = POLLHUP;
-               goto out;
-       }
-
-       if (dev->state == STATE_DEV_SETUP) {
-               if (dev->setup_in || dev->setup_can_stall)
-                       mask = POLLOUT;
-       } else {
-               if (dev->ev_next != 0)
-                       mask = POLLIN;
-       }
-out:
-       spin_unlock_irq(&dev->lock);
-       return mask;
-}
-
-static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
-{
-       struct dev_data         *dev = fd->private_data;
-       struct usb_gadget       *gadget = dev->gadget;
-       long ret = -ENOTTY;
-
-       if (gadget->ops->ioctl)
-               ret = gadget->ops->ioctl (gadget, code, value);
-
-       return ret;
-}
-
-/* used after device configuration */
-static const struct file_operations ep0_io_operations = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-
-       .read =         ep0_read,
-       .write =        ep0_write,
-       .fasync =       ep0_fasync,
-       .poll =         ep0_poll,
-       .unlocked_ioctl =       dev_ioctl,
-       .release =      dev_release,
-};
-
-/*----------------------------------------------------------------------*/
-
-/* The in-kernel gadget driver handles most ep0 issues, in particular
- * enumerating the single configuration (as provided from user space).
- *
- * Unrecognized ep0 requests may be handled in user space.
- */
-
-static void make_qualifier (struct dev_data *dev)
-{
-       struct usb_qualifier_descriptor         qual;
-       struct usb_device_descriptor            *desc;
-
-       qual.bLength = sizeof qual;
-       qual.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
-       qual.bcdUSB = cpu_to_le16 (0x0200);
-
-       desc = dev->dev;
-       qual.bDeviceClass = desc->bDeviceClass;
-       qual.bDeviceSubClass = desc->bDeviceSubClass;
-       qual.bDeviceProtocol = desc->bDeviceProtocol;
-
-       /* assumes ep0 uses the same value for both speeds ... */
-       qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
-
-       qual.bNumConfigurations = 1;
-       qual.bRESERVED = 0;
-
-       memcpy (dev->rbuf, &qual, sizeof qual);
-}
-
-static int
-config_buf (struct dev_data *dev, u8 type, unsigned index)
-{
-       int             len;
-       int             hs = 0;
-
-       /* only one configuration */
-       if (index > 0)
-               return -EINVAL;
-
-       if (gadget_is_dualspeed(dev->gadget)) {
-               hs = (dev->gadget->speed == USB_SPEED_HIGH);
-               if (type == USB_DT_OTHER_SPEED_CONFIG)
-                       hs = !hs;
-       }
-       if (hs) {
-               dev->req->buf = dev->hs_config;
-               len = le16_to_cpu(dev->hs_config->wTotalLength);
-       } else {
-               dev->req->buf = dev->config;
-               len = le16_to_cpu(dev->config->wTotalLength);
-       }
-       ((u8 *)dev->req->buf) [1] = type;
-       return len;
-}
-
-static int
-gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
-{
-       struct dev_data                 *dev = get_gadget_data (gadget);
-       struct usb_request              *req = dev->req;
-       int                             value = -EOPNOTSUPP;
-       struct usb_gadgetfs_event       *event;
-       u16                             w_value = le16_to_cpu(ctrl->wValue);
-       u16                             w_length = le16_to_cpu(ctrl->wLength);
-
-       spin_lock (&dev->lock);
-       dev->setup_abort = 0;
-       if (dev->state == STATE_DEV_UNCONNECTED) {
-               if (gadget_is_dualspeed(gadget)
-                               && gadget->speed == USB_SPEED_HIGH
-                               && dev->hs_config == NULL) {
-                       spin_unlock(&dev->lock);
-                       ERROR (dev, "no high speed config??\n");
-                       return -EINVAL;
-               }
-
-               dev->state = STATE_DEV_CONNECTED;
-
-               INFO (dev, "connected\n");
-               event = next_event (dev, GADGETFS_CONNECT);
-               event->u.speed = gadget->speed;
-               ep0_readable (dev);
-
-       /* host may have given up waiting for response.  we can miss control
-        * requests handled lower down (device/endpoint status and features);
-        * then ep0_{read,write} will report the wrong status. controller
-        * driver will have aborted pending i/o.
-        */
-       } else if (dev->state == STATE_DEV_SETUP)
-               dev->setup_abort = 1;
-
-       req->buf = dev->rbuf;
-       req->context = NULL;
-       value = -EOPNOTSUPP;
-       switch (ctrl->bRequest) {
-
-       case USB_REQ_GET_DESCRIPTOR:
-               if (ctrl->bRequestType != USB_DIR_IN)
-                       goto unrecognized;
-               switch (w_value >> 8) {
-
-               case USB_DT_DEVICE:
-                       value = min (w_length, (u16) sizeof *dev->dev);
-                       dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
-                       req->buf = dev->dev;
-                       break;
-               case USB_DT_DEVICE_QUALIFIER:
-                       if (!dev->hs_config)
-                               break;
-                       value = min (w_length, (u16)
-                               sizeof (struct usb_qualifier_descriptor));
-                       make_qualifier (dev);
-                       break;
-               case USB_DT_OTHER_SPEED_CONFIG:
-                       // FALLTHROUGH
-               case USB_DT_CONFIG:
-                       value = config_buf (dev,
-                                       w_value >> 8,
-                                       w_value & 0xff);
-                       if (value >= 0)
-                               value = min (w_length, (u16) value);
-                       break;
-               case USB_DT_STRING:
-                       goto unrecognized;
-
-               default:                // all others are errors
-                       break;
-               }
-               break;
-
-       /* currently one config, two speeds */
-       case USB_REQ_SET_CONFIGURATION:
-               if (ctrl->bRequestType != 0)
-                       goto unrecognized;
-               if (0 == (u8) w_value) {
-                       value = 0;
-                       dev->current_config = 0;
-                       usb_gadget_vbus_draw(gadget, 8 /* mA */ );
-                       // user mode expected to disable endpoints
-               } else {
-                       u8      config, power;
-
-                       if (gadget_is_dualspeed(gadget)
-                                       && gadget->speed == USB_SPEED_HIGH) {
-                               config = dev->hs_config->bConfigurationValue;
-                               power = dev->hs_config->bMaxPower;
-                       } else {
-                               config = dev->config->bConfigurationValue;
-                               power = dev->config->bMaxPower;
-                       }
-
-                       if (config == (u8) w_value) {
-                               value = 0;
-                               dev->current_config = config;
-                               usb_gadget_vbus_draw(gadget, 2 * power);
-                       }
-               }
-
-               /* report SET_CONFIGURATION like any other control request,
-                * except that usermode may not stall this.  the next
-                * request mustn't be allowed start until this finishes:
-                * endpoints and threads set up, etc.
-                *
-                * NOTE:  older PXA hardware (before PXA 255: without UDCCFR)
-                * has bad/racey automagic that prevents synchronizing here.
-                * even kernel mode drivers often miss them.
-                */
-               if (value == 0) {
-                       INFO (dev, "configuration #%d\n", dev->current_config);
-                       usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);
-                       if (dev->usermode_setup) {
-                               dev->setup_can_stall = 0;
-                               goto delegate;
-                       }
-               }
-               break;
-
-#ifndef        CONFIG_USB_PXA25X
-       /* PXA automagically handles this request too */
-       case USB_REQ_GET_CONFIGURATION:
-               if (ctrl->bRequestType != 0x80)
-                       goto unrecognized;
-               *(u8 *)req->buf = dev->current_config;
-               value = min (w_length, (u16) 1);
-               break;
-#endif
-
-       default:
-unrecognized:
-               VDEBUG (dev, "%s req%02x.%02x v%04x i%04x l%d\n",
-                       dev->usermode_setup ? "delegate" : "fail",
-                       ctrl->bRequestType, ctrl->bRequest,
-                       w_value, le16_to_cpu(ctrl->wIndex), w_length);
-
-               /* if there's an ep0 reader, don't stall */
-               if (dev->usermode_setup) {
-                       dev->setup_can_stall = 1;
-delegate:
-                       dev->setup_in = (ctrl->bRequestType & USB_DIR_IN)
-                                               ? 1 : 0;
-                       dev->setup_wLength = w_length;
-                       dev->setup_out_ready = 0;
-                       dev->setup_out_error = 0;
-                       value = 0;
-
-                       /* read DATA stage for OUT right away */
-                       if (unlikely (!dev->setup_in && w_length)) {
-                               value = setup_req (gadget->ep0, dev->req,
-                                                       w_length);
-                               if (value < 0)
-                                       break;
-                               value = usb_ep_queue (gadget->ep0, dev->req,
-                                                       GFP_ATOMIC);
-                               if (value < 0) {
-                                       clean_req (gadget->ep0, dev->req);
-                                       break;
-                               }
-
-                               /* we can't currently stall these */
-                               dev->setup_can_stall = 0;
-                       }
-
-                       /* state changes when reader collects event */
-                       event = next_event (dev, GADGETFS_SETUP);
-                       event->u.setup = *ctrl;
-                       ep0_readable (dev);
-                       spin_unlock (&dev->lock);
-                       return 0;
-               }
-       }
-
-       /* proceed with data transfer and status phases? */
-       if (value >= 0 && dev->state != STATE_DEV_SETUP) {
-               req->length = value;
-               req->zero = value < w_length;
-               value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
-               if (value < 0) {
-                       DBG (dev, "ep_queue --> %d\n", value);
-                       req->status = 0;
-               }
-       }
-
-       /* device stalls when value < 0 */
-       spin_unlock (&dev->lock);
-       return value;
-}
-
-static void destroy_ep_files (struct dev_data *dev)
-{
-       DBG (dev, "%s %d\n", __func__, dev->state);
-
-       /* dev->state must prevent interference */
-       spin_lock_irq (&dev->lock);
-       while (!list_empty(&dev->epfiles)) {
-               struct ep_data  *ep;
-               struct inode    *parent;
-               struct dentry   *dentry;
-
-               /* break link to FS */
-               ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
-               list_del_init (&ep->epfiles);
-               dentry = ep->dentry;
-               ep->dentry = NULL;
-               parent = dentry->d_parent->d_inode;
-
-               /* break link to controller */
-               if (ep->state == STATE_EP_ENABLED)
-                       (void) usb_ep_disable (ep->ep);
-               ep->state = STATE_EP_UNBOUND;
-               usb_ep_free_request (ep->ep, ep->req);
-               ep->ep = NULL;
-               wake_up (&ep->wait);
-               put_ep (ep);
-
-               spin_unlock_irq (&dev->lock);
-
-               /* break link to dcache */
-               mutex_lock (&parent->i_mutex);
-               d_delete (dentry);
-               dput (dentry);
-               mutex_unlock (&parent->i_mutex);
-
-               spin_lock_irq (&dev->lock);
-       }
-       spin_unlock_irq (&dev->lock);
-}
-
-
-static struct inode *
-gadgetfs_create_file (struct super_block *sb, char const *name,
-               void *data, const struct file_operations *fops,
-               struct dentry **dentry_p);
-
-static int activate_ep_files (struct dev_data *dev)
-{
-       struct usb_ep   *ep;
-       struct ep_data  *data;
-
-       gadget_for_each_ep (ep, dev->gadget) {
-
-               data = kzalloc(sizeof(*data), GFP_KERNEL);
-               if (!data)
-                       goto enomem0;
-               data->state = STATE_EP_DISABLED;
-               mutex_init(&data->lock);
-               init_waitqueue_head (&data->wait);
-
-               strncpy (data->name, ep->name, sizeof (data->name) - 1);
-               atomic_set (&data->count, 1);
-               data->dev = dev;
-               get_dev (dev);
-
-               data->ep = ep;
-               ep->driver_data = data;
-
-               data->req = usb_ep_alloc_request (ep, GFP_KERNEL);
-               if (!data->req)
-                       goto enomem1;
-
-               data->inode = gadgetfs_create_file (dev->sb, data->name,
-                               data, &ep_config_operations,
-                               &data->dentry);
-               if (!data->inode)
-                       goto enomem2;
-               list_add_tail (&data->epfiles, &dev->epfiles);
-       }
-       return 0;
-
-enomem2:
-       usb_ep_free_request (ep, data->req);
-enomem1:
-       put_dev (dev);
-       kfree (data);
-enomem0:
-       DBG (dev, "%s enomem\n", __func__);
-       destroy_ep_files (dev);
-       return -ENOMEM;
-}
-
-static void
-gadgetfs_unbind (struct usb_gadget *gadget)
-{
-       struct dev_data         *dev = get_gadget_data (gadget);
-
-       DBG (dev, "%s\n", __func__);
-
-       spin_lock_irq (&dev->lock);
-       dev->state = STATE_DEV_UNBOUND;
-       spin_unlock_irq (&dev->lock);
-
-       destroy_ep_files (dev);
-       gadget->ep0->driver_data = NULL;
-       set_gadget_data (gadget, NULL);
-
-       /* we've already been disconnected ... no i/o is active */
-       if (dev->req)
-               usb_ep_free_request (gadget->ep0, dev->req);
-       DBG (dev, "%s done\n", __func__);
-       put_dev (dev);
-}
-
-static struct dev_data         *the_device;
-
-static int gadgetfs_bind(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver)
-{
-       struct dev_data         *dev = the_device;
-
-       if (!dev)
-               return -ESRCH;
-       if (0 != strcmp (CHIP, gadget->name)) {
-               pr_err("%s expected %s controller not %s\n",
-                       shortname, CHIP, gadget->name);
-               return -ENODEV;
-       }
-
-       set_gadget_data (gadget, dev);
-       dev->gadget = gadget;
-       gadget->ep0->driver_data = dev;
-
-       /* preallocate control response and buffer */
-       dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
-       if (!dev->req)
-               goto enomem;
-       dev->req->context = NULL;
-       dev->req->complete = epio_complete;
-
-       if (activate_ep_files (dev) < 0)
-               goto enomem;
-
-       INFO (dev, "bound to %s driver\n", gadget->name);
-       spin_lock_irq(&dev->lock);
-       dev->state = STATE_DEV_UNCONNECTED;
-       spin_unlock_irq(&dev->lock);
-       get_dev (dev);
-       return 0;
-
-enomem:
-       gadgetfs_unbind (gadget);
-       return -ENOMEM;
-}
-
-static void
-gadgetfs_disconnect (struct usb_gadget *gadget)
-{
-       struct dev_data         *dev = get_gadget_data (gadget);
-       unsigned long           flags;
-
-       spin_lock_irqsave (&dev->lock, flags);
-       if (dev->state == STATE_DEV_UNCONNECTED)
-               goto exit;
-       dev->state = STATE_DEV_UNCONNECTED;
-
-       INFO (dev, "disconnected\n");
-       next_event (dev, GADGETFS_DISCONNECT);
-       ep0_readable (dev);
-exit:
-       spin_unlock_irqrestore (&dev->lock, flags);
-}
-
-static void
-gadgetfs_suspend (struct usb_gadget *gadget)
-{
-       struct dev_data         *dev = get_gadget_data (gadget);
-
-       INFO (dev, "suspended from state %d\n", dev->state);
-       spin_lock (&dev->lock);
-       switch (dev->state) {
-       case STATE_DEV_SETUP:           // VERY odd... host died??
-       case STATE_DEV_CONNECTED:
-       case STATE_DEV_UNCONNECTED:
-               next_event (dev, GADGETFS_SUSPEND);
-               ep0_readable (dev);
-               /* FALLTHROUGH */
-       default:
-               break;
-       }
-       spin_unlock (&dev->lock);
-}
-
-static struct usb_gadget_driver gadgetfs_driver = {
-       .function       = (char *) driver_desc,
-       .bind           = gadgetfs_bind,
-       .unbind         = gadgetfs_unbind,
-       .setup          = gadgetfs_setup,
-       .disconnect     = gadgetfs_disconnect,
-       .suspend        = gadgetfs_suspend,
-
-       .driver = {
-               .name           = (char *) shortname,
-       },
-};
-
-/*----------------------------------------------------------------------*/
-
-static void gadgetfs_nop(struct usb_gadget *arg) { }
-
-static int gadgetfs_probe(struct usb_gadget *gadget,
-               struct usb_gadget_driver *driver)
-{
-       CHIP = gadget->name;
-       return -EISNAM;
-}
-
-static struct usb_gadget_driver probe_driver = {
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = gadgetfs_probe,
-       .unbind         = gadgetfs_nop,
-       .setup          = (void *)gadgetfs_nop,
-       .disconnect     = gadgetfs_nop,
-       .driver = {
-               .name           = "nop",
-       },
-};
-
-
-/* DEVICE INITIALIZATION
- *
- *     fd = open ("/dev/gadget/$CHIP", O_RDWR)
- *     status = write (fd, descriptors, sizeof descriptors)
- *
- * That write establishes the device configuration, so the kernel can
- * bind to the controller ... guaranteeing it can handle enumeration
- * at all necessary speeds.  Descriptor order is:
- *
- * . message tag (u32, host order) ... for now, must be zero; it
- *     would change to support features like multi-config devices
- * . full/low speed config ... all wTotalLength bytes (with interface,
- *     class, altsetting, endpoint, and other descriptors)
- * . high speed config ... all descriptors, for high speed operation;
- *     this one's optional except for high-speed hardware
- * . device descriptor
- *
- * Endpoints are not yet enabled. Drivers must wait until device
- * configuration and interface altsetting changes create
- * the need to configure (or unconfigure) them.
- *
- * After initialization, the device stays active for as long as that
- * $CHIP file is open.  Events must then be read from that descriptor,
- * such as configuration notifications.
- */
-
-static int is_valid_config (struct usb_config_descriptor *config)
-{
-       return config->bDescriptorType == USB_DT_CONFIG
-               && config->bLength == USB_DT_CONFIG_SIZE
-               && config->bConfigurationValue != 0
-               && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
-               && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0;
-       /* FIXME if gadget->is_otg, _must_ include an otg descriptor */
-       /* FIXME check lengths: walk to end */
-}
-
-static ssize_t
-dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct dev_data         *dev = fd->private_data;
-       ssize_t                 value = len, length = len;
-       unsigned                total;
-       u32                     tag;
-       char                    *kbuf;
-
-       if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
-               return -EINVAL;
-
-       /* we might need to change message format someday */
-       if (copy_from_user (&tag, buf, 4))
-               return -EFAULT;
-       if (tag != 0)
-               return -EINVAL;
-       buf += 4;
-       length -= 4;
-
-       kbuf = memdup_user(buf, length);
-       if (IS_ERR(kbuf))
-               return PTR_ERR(kbuf);
-
-       spin_lock_irq (&dev->lock);
-       value = -EINVAL;
-       if (dev->buf)
-               goto fail;
-       dev->buf = kbuf;
-
-       /* full or low speed config */
-       dev->config = (void *) kbuf;
-       total = le16_to_cpu(dev->config->wTotalLength);
-       if (!is_valid_config (dev->config) || total >= length)
-               goto fail;
-       kbuf += total;
-       length -= total;
-
-       /* optional high speed config */
-       if (kbuf [1] == USB_DT_CONFIG) {
-               dev->hs_config = (void *) kbuf;
-               total = le16_to_cpu(dev->hs_config->wTotalLength);
-               if (!is_valid_config (dev->hs_config) || total >= length)
-                       goto fail;
-               kbuf += total;
-               length -= total;
-       }
-
-       /* could support multiple configs, using another encoding! */
-
-       /* device descriptor (tweaked for paranoia) */
-       if (length != USB_DT_DEVICE_SIZE)
-               goto fail;
-       dev->dev = (void *)kbuf;
-       if (dev->dev->bLength != USB_DT_DEVICE_SIZE
-                       || dev->dev->bDescriptorType != USB_DT_DEVICE
-                       || dev->dev->bNumConfigurations != 1)
-               goto fail;
-       dev->dev->bNumConfigurations = 1;
-       dev->dev->bcdUSB = cpu_to_le16 (0x0200);
-
-       /* triggers gadgetfs_bind(); then we can enumerate. */
-       spin_unlock_irq (&dev->lock);
-       if (dev->hs_config)
-               gadgetfs_driver.max_speed = USB_SPEED_HIGH;
-       else
-               gadgetfs_driver.max_speed = USB_SPEED_FULL;
-
-       value = usb_gadget_probe_driver(&gadgetfs_driver);
-       if (value != 0) {
-               kfree (dev->buf);
-               dev->buf = NULL;
-       } else {
-               /* at this point "good" hardware has for the first time
-                * let the USB the host see us.  alternatively, if users
-                * unplug/replug that will clear all the error state.
-                *
-                * note:  everything running before here was guaranteed
-                * to choke driver model style diagnostics.  from here
-                * on, they can work ... except in cleanup paths that
-                * kick in after the ep0 descriptor is closed.
-                */
-               fd->f_op = &ep0_io_operations;
-               value = len;
-       }
-       return value;
-
-fail:
-       spin_unlock_irq (&dev->lock);
-       pr_debug ("%s: %s fail %Zd, %p\n", shortname, __func__, value, dev);
-       kfree (dev->buf);
-       dev->buf = NULL;
-       return value;
-}
-
-static int
-dev_open (struct inode *inode, struct file *fd)
-{
-       struct dev_data         *dev = inode->i_private;
-       int                     value = -EBUSY;
-
-       spin_lock_irq(&dev->lock);
-       if (dev->state == STATE_DEV_DISABLED) {
-               dev->ev_next = 0;
-               dev->state = STATE_DEV_OPENED;
-               fd->private_data = dev;
-               get_dev (dev);
-               value = 0;
-       }
-       spin_unlock_irq(&dev->lock);
-       return value;
-}
-
-static const struct file_operations dev_init_operations = {
-       .llseek =       no_llseek,
-
-       .open =         dev_open,
-       .write =        dev_config,
-       .fasync =       ep0_fasync,
-       .unlocked_ioctl = dev_ioctl,
-       .release =      dev_release,
-};
-
-/*----------------------------------------------------------------------*/
-
-/* FILESYSTEM AND SUPERBLOCK OPERATIONS
- *
- * Mounting the filesystem creates a controller file, used first for
- * device configuration then later for event monitoring.
- */
-
-
-/* FIXME PAM etc could set this security policy without mount options
- * if epfiles inherited ownership and permissons from ep0 ...
- */
-
-static unsigned default_uid;
-static unsigned default_gid;
-static unsigned default_perm = S_IRUSR | S_IWUSR;
-
-module_param (default_uid, uint, 0644);
-module_param (default_gid, uint, 0644);
-module_param (default_perm, uint, 0644);
-
-
-static struct inode *
-gadgetfs_make_inode (struct super_block *sb,
-               void *data, const struct file_operations *fops,
-               int mode)
-{
-       struct inode *inode = new_inode (sb);
-
-       if (inode) {
-               inode->i_ino = get_next_ino();
-               inode->i_mode = mode;
-               inode->i_uid = make_kuid(&init_user_ns, default_uid);
-               inode->i_gid = make_kgid(&init_user_ns, default_gid);
-               inode->i_atime = inode->i_mtime = inode->i_ctime
-                               = CURRENT_TIME;
-               inode->i_private = data;
-               inode->i_fop = fops;
-       }
-       return inode;
-}
-
-/* creates in fs root directory, so non-renamable and non-linkable.
- * so inode and dentry are paired, until device reconfig.
- */
-static struct inode *
-gadgetfs_create_file (struct super_block *sb, char const *name,
-               void *data, const struct file_operations *fops,
-               struct dentry **dentry_p)
-{
-       struct dentry   *dentry;
-       struct inode    *inode;
-
-       dentry = d_alloc_name(sb->s_root, name);
-       if (!dentry)
-               return NULL;
-
-       inode = gadgetfs_make_inode (sb, data, fops,
-                       S_IFREG | (default_perm & S_IRWXUGO));
-       if (!inode) {
-               dput(dentry);
-               return NULL;
-       }
-       d_add (dentry, inode);
-       *dentry_p = dentry;
-       return inode;
-}
-
-static const struct super_operations gadget_fs_operations = {
-       .statfs =       simple_statfs,
-       .drop_inode =   generic_delete_inode,
-};
-
-static int
-gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
-{
-       struct inode    *inode;
-       struct dev_data *dev;
-
-       if (the_device)
-               return -ESRCH;
-
-       /* fake probe to determine $CHIP */
-       CHIP = NULL;
-       usb_gadget_probe_driver(&probe_driver);
-       if (!CHIP)
-               return -ENODEV;
-
-       /* superblock */
-       sb->s_blocksize = PAGE_CACHE_SIZE;
-       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-       sb->s_magic = GADGETFS_MAGIC;
-       sb->s_op = &gadget_fs_operations;
-       sb->s_time_gran = 1;
-
-       /* root inode */
-       inode = gadgetfs_make_inode (sb,
-                       NULL, &simple_dir_operations,
-                       S_IFDIR | S_IRUGO | S_IXUGO);
-       if (!inode)
-               goto Enomem;
-       inode->i_op = &simple_dir_inode_operations;
-       if (!(sb->s_root = d_make_root (inode)))
-               goto Enomem;
-
-       /* the ep0 file is named after the controller we expect;
-        * user mode code can use it for sanity checks, like we do.
-        */
-       dev = dev_new ();
-       if (!dev)
-               goto Enomem;
-
-       dev->sb = sb;
-       if (!gadgetfs_create_file (sb, CHIP,
-                               dev, &dev_init_operations,
-                               &dev->dentry)) {
-               put_dev(dev);
-               goto Enomem;
-       }
-
-       /* other endpoint files are available after hardware setup,
-        * from binding to a controller.
-        */
-       the_device = dev;
-       return 0;
-
-Enomem:
-       return -ENOMEM;
-}
-
-/* "mount -t gadgetfs path /dev/gadget" ends up here */
-static struct dentry *
-gadgetfs_mount (struct file_system_type *t, int flags,
-               const char *path, void *opts)
-{
-       return mount_single (t, flags, opts, gadgetfs_fill_super);
-}
-
-static void
-gadgetfs_kill_sb (struct super_block *sb)
-{
-       kill_litter_super (sb);
-       if (the_device) {
-               put_dev (the_device);
-               the_device = NULL;
-       }
-}
-
-/*----------------------------------------------------------------------*/
-
-static struct file_system_type gadgetfs_type = {
-       .owner          = THIS_MODULE,
-       .name           = shortname,
-       .mount          = gadgetfs_mount,
-       .kill_sb        = gadgetfs_kill_sb,
-};
-MODULE_ALIAS_FS("gadgetfs");
-
-/*----------------------------------------------------------------------*/
-
-static int __init init (void)
-{
-       int status;
-
-       status = register_filesystem (&gadgetfs_type);
-       if (status == 0)
-               pr_info ("%s: %s, version " DRIVER_VERSION "\n",
-                       shortname, driver_desc);
-       return status;
-}
-module_init (init);
-
-static void __exit cleanup (void)
-{
-       pr_debug ("unregister %s\n", shortname);
-       unregister_filesystem (&gadgetfs_type);
-}
-module_exit (cleanup);
-
diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig
new file mode 100644 (file)
index 0000000..aa376f0
--- /dev/null
@@ -0,0 +1,475 @@
+#
+# USB Gadget support on a system involves
+#    (a) a peripheral controller, and
+#    (b) the gadget driver using it.
+#
+# NOTE:  Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !!
+#
+#  - Host systems (like PCs) need CONFIG_USB (with "A" jacks).
+#  - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks).
+#  - Some systems have both kinds of controllers.
+#
+# With help from a special transceiver and a "Mini-AB" jack, systems with
+# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
+#
+
+config USB_ZERO
+       tristate "Gadget Zero (DEVELOPMENT)"
+       select USB_LIBCOMPOSITE
+       select USB_F_SS_LB
+       help
+         Gadget Zero is a two-configuration device.  It either sinks and
+         sources bulk data; or it loops back a configurable number of
+         transfers.  It also implements control requests, for "chapter 9"
+         conformance.  The driver needs only two bulk-capable endpoints, so
+         it can work on top of most device-side usb controllers.  It's
+         useful for testing, and is also a working example showing how
+         USB "gadget drivers" can be written.
+
+         Make this be the first driver you try using on top of any new
+         USB peripheral controller driver.  Then you can use host-side
+         test software, like the "usbtest" driver, to put your hardware
+         and its driver through a basic set of functional tests.
+
+         Gadget Zero also works with the host-side "usb-skeleton" driver,
+         and with many kinds of host-side test software.  You may need
+         to tweak product and vendor IDs before host software knows about
+         this device, and arrange to select an appropriate configuration.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_zero".
+
+config USB_ZERO_HNPTEST
+       boolean "HNP Test Device"
+       depends on USB_ZERO && USB_OTG
+       help
+         You can configure this device to enumerate using the device
+         identifiers of the USB-OTG test device.  That means that when
+         this gadget connects to another OTG device, with this one using
+         the "B-Peripheral" role, that device will use HNP to let this
+         one serve as the USB host instead (in the "B-Host" role).
+
+config USB_AUDIO
+       tristate "Audio Gadget"
+       depends on SND
+       select USB_LIBCOMPOSITE
+       select SND_PCM
+       help
+         This Gadget Audio driver is compatible with USB Audio Class
+         specification 2.0. It implements 1 AudioControl interface,
+         1 AudioStreaming Interface each for USB-OUT and USB-IN.
+         Number of channels, sample rate and sample size can be
+         specified as module parameters.
+         This driver doesn't expect any real Audio codec to be present
+         on the device - the audio streams are simply sinked to and
+         sourced from a virtual ALSA sound card created. The user-space
+         application may choose to do whatever it wants with the data
+         received from the USB Host and choose to provide whatever it
+         wants as audio data to the USB Host.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_audio".
+
+config GADGET_UAC1
+       bool "UAC 1.0 (Legacy)"
+       depends on USB_AUDIO
+       help
+         If you instead want older UAC Spec-1.0 driver that also has audio
+         paths hardwired to the Audio codec chip on-board and doesn't work
+         without one.
+
+config USB_ETH
+       tristate "Ethernet Gadget (with CDC Ethernet support)"
+       depends on NET
+       select USB_LIBCOMPOSITE
+       select USB_U_ETHER
+       select USB_F_ECM
+       select USB_F_SUBSET
+       select CRC32
+       help
+         This driver implements Ethernet style communication, in one of
+         several ways:
+
+          - The "Communication Device Class" (CDC) Ethernet Control Model.
+            That protocol is often avoided with pure Ethernet adapters, in
+            favor of simpler vendor-specific hardware, but is widely
+            supported by firmware for smart network devices.
+
+          - On hardware can't implement that protocol, a simple CDC subset
+            is used, placing fewer demands on USB.
+
+          - CDC Ethernet Emulation Model (EEM) is a newer standard that has
+            a simpler interface that can be used by more USB hardware.
+
+         RNDIS support is an additional option, more demanding than than
+         subset.
+
+         Within the USB device, this gadget driver exposes a network device
+         "usbX", where X depends on what other networking devices you have.
+         Treat it like a two-node Ethernet link:  host, and gadget.
+
+         The Linux-USB host-side "usbnet" driver interoperates with this
+         driver, so that deep I/O queues can be supported.  On 2.4 kernels,
+         use "CDCEther" instead, if you're using the CDC option. That CDC
+         mode should also interoperate with standard CDC Ethernet class
+         drivers on other host operating systems.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_ether".
+
+config USB_ETH_RNDIS
+       bool "RNDIS support"
+       depends on USB_ETH
+       select USB_LIBCOMPOSITE
+       select USB_F_RNDIS
+       default y
+       help
+          Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol,
+          and Microsoft provides redistributable binary RNDIS drivers for
+          older versions of Windows.
+
+          If you say "y" here, the Ethernet gadget driver will try to provide
+          a second device configuration, supporting RNDIS to talk to such
+          Microsoft USB hosts.
+
+          To make MS-Windows work with this, use Documentation/usb/linux.inf
+          as the "driver info file".  For versions of MS-Windows older than
+          XP, you'll need to download drivers from Microsoft's website; a URL
+          is given in comments found in that info file.
+
+config USB_ETH_EEM
+       bool "Ethernet Emulation Model (EEM) support"
+       depends on USB_ETH
+       select USB_LIBCOMPOSITE
+       select USB_F_EEM
+       default n
+       help
+         CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
+         and therefore can be supported by more hardware.  Technically ECM and
+         EEM are designed for different applications.  The ECM model extends
+         the network interface to the target (e.g. a USB cable modem), and the
+         EEM model is for mobile devices to communicate with hosts using
+         ethernet over USB.  For Linux gadgets, however, the interface with
+         the host is the same (a usbX device), so the differences are minimal.
+
+         If you say "y" here, the Ethernet gadget driver will use the EEM
+         protocol rather than ECM.  If unsure, say "n".
+
+config USB_G_NCM
+       tristate "Network Control Model (NCM) support"
+       depends on NET
+       select USB_LIBCOMPOSITE
+       select USB_U_ETHER
+       select USB_F_NCM
+       select CRC32
+       help
+         This driver implements USB CDC NCM subclass standard. NCM is
+         an advanced protocol for Ethernet encapsulation, allows grouping
+         of several ethernet frames into one USB transfer and different
+         alignment possibilities.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_ncm".
+
+config USB_GADGETFS
+       tristate "Gadget Filesystem"
+       help
+         This driver provides a filesystem based API that lets user mode
+         programs implement a single-configuration USB device, including
+         endpoint I/O and control requests that don't relate to enumeration.
+         All endpoints, transfer speeds, and transfer types supported by
+         the hardware are available, through read() and write() calls.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "gadgetfs".
+
+config USB_FUNCTIONFS
+       tristate "Function Filesystem"
+       select USB_LIBCOMPOSITE
+       select USB_F_FS
+       select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
+       help
+         The Function Filesystem (FunctionFS) lets one create USB
+         composite functions in user space in the same way GadgetFS
+         lets one create USB gadgets in user space.  This allows creation
+         of composite gadgets such that some of the functions are
+         implemented in kernel space (for instance Ethernet, serial or
+         mass storage) and other are implemented in user space.
+
+         If you say "y" or "m" here you will be able what kind of
+         configurations the gadget will provide.
+
+         Say "y" to link the driver statically, or "m" to build
+         a dynamically linked module called "g_ffs".
+
+config USB_FUNCTIONFS_ETH
+       bool "Include configuration with CDC ECM (Ethernet)"
+       depends on USB_FUNCTIONFS && NET
+       select USB_U_ETHER
+       select USB_F_ECM
+       select USB_F_SUBSET
+       help
+         Include a configuration with CDC ECM function (Ethernet) and the
+         Function Filesystem.
+
+config USB_FUNCTIONFS_RNDIS
+       bool "Include configuration with RNDIS (Ethernet)"
+       depends on USB_FUNCTIONFS && NET
+       select USB_U_ETHER
+       select USB_F_RNDIS
+       help
+         Include a configuration with RNDIS function (Ethernet) and the Filesystem.
+
+config USB_FUNCTIONFS_GENERIC
+       bool "Include 'pure' configuration"
+       depends on USB_FUNCTIONFS
+       help
+         Include a configuration with the Function Filesystem alone with
+         no Ethernet interface.
+
+config USB_MASS_STORAGE
+       tristate "Mass Storage Gadget"
+       depends on BLOCK
+       select USB_LIBCOMPOSITE
+       select USB_F_MASS_STORAGE
+       help
+         The Mass Storage Gadget acts as a USB Mass Storage disk drive.
+         As its storage repository it can use a regular file or a block
+         device (in much the same way as the "loop" device driver),
+         specified as a module parameter or sysfs option.
+
+         This driver is a replacement for now removed File-backed
+         Storage Gadget (g_file_storage).
+
+         Say "y" to link the driver statically, or "m" to build
+         a dynamically linked module called "g_mass_storage".
+
+config USB_GADGET_TARGET
+       tristate "USB Gadget Target Fabric Module"
+       depends on TARGET_CORE
+       select USB_LIBCOMPOSITE
+       help
+         This fabric is an USB gadget. Two USB protocols are supported that is
+         BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is
+         advertised on alternative interface 0 (primary) and UAS is on
+         alternative interface 1. Both protocols can work on USB2.0 and USB3.0.
+         UAS utilizes the USB 3.0 feature called streams support.
+
+config USB_G_SERIAL
+       tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
+       depends on TTY
+       select USB_U_SERIAL
+       select USB_F_ACM
+       select USB_F_SERIAL
+       select USB_F_OBEX
+       select USB_LIBCOMPOSITE
+       help
+         The Serial Gadget talks to the Linux-USB generic serial driver.
+         This driver supports a CDC-ACM module option, which can be used
+         to interoperate with MS-Windows hosts or with the Linux-USB
+         "cdc-acm" driver.
+
+         This driver also supports a CDC-OBEX option.  You will need a
+         user space OBEX server talking to /dev/ttyGS*, since the kernel
+         itself doesn't implement the OBEX protocol.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_serial".
+
+         For more information, see Documentation/usb/gadget_serial.txt
+         which includes instructions and a "driver info file" needed to
+         make MS-Windows work with CDC ACM.
+
+config USB_MIDI_GADGET
+       tristate "MIDI Gadget"
+       depends on SND
+       select USB_LIBCOMPOSITE
+       select SND_RAWMIDI
+       help
+         The MIDI Gadget acts as a USB Audio device, with one MIDI
+         input and one MIDI output. These MIDI jacks appear as
+         a sound "card" in the ALSA sound system. Other MIDI
+         connections can then be made on the gadget system, using
+         ALSA's aconnect utility etc.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_midi".
+
+config USB_G_PRINTER
+       tristate "Printer Gadget"
+       select USB_LIBCOMPOSITE
+       help
+         The Printer Gadget channels data between the USB host and a
+         userspace program driving the print engine. The user space
+         program reads and writes the device file /dev/g_printer to
+         receive or send printer data. It can use ioctl calls to
+         the device file to get or set printer status.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_printer".
+
+         For more information, see Documentation/usb/gadget_printer.txt
+         which includes sample code for accessing the device file.
+
+if TTY
+
+config USB_CDC_COMPOSITE
+       tristate "CDC Composite Device (Ethernet and ACM)"
+       depends on NET
+       select USB_LIBCOMPOSITE
+       select USB_U_SERIAL
+       select USB_U_ETHER
+       select USB_F_ACM
+       select USB_F_ECM
+       help
+         This driver provides two functions in one configuration:
+         a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link.
+
+         This driver requires four bulk and two interrupt endpoints,
+         plus the ability to handle altsettings.  Not all peripheral
+         controllers are that capable.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module.
+
+config USB_G_NOKIA
+       tristate "Nokia composite gadget"
+       depends on PHONET
+       select USB_LIBCOMPOSITE
+       select USB_U_SERIAL
+       select USB_U_ETHER
+       select USB_F_ACM
+       select USB_F_OBEX
+       select USB_F_PHONET
+       select USB_F_ECM
+       help
+         The Nokia composite gadget provides support for acm, obex
+         and phonet in only one composite gadget driver.
+
+         It's only really useful for N900 hardware. If you're building
+         a kernel for N900, say Y or M here. If unsure, say N.
+
+config USB_G_ACM_MS
+       tristate "CDC Composite Device (ACM and mass storage)"
+       depends on BLOCK
+       select USB_LIBCOMPOSITE
+       select USB_U_SERIAL
+       select USB_F_ACM
+       select USB_F_MASS_STORAGE
+       help
+         This driver provides two functions in one configuration:
+         a mass storage, and a CDC ACM (serial port) link.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_acm_ms".
+
+config USB_G_MULTI
+       tristate "Multifunction Composite Gadget"
+       depends on BLOCK && NET
+       select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
+       select USB_LIBCOMPOSITE
+       select USB_U_SERIAL
+       select USB_U_ETHER
+       select USB_F_ACM
+       select USB_F_MASS_STORAGE
+       help
+         The Multifunction Composite Gadget provides Ethernet (RNDIS
+         and/or CDC Ethernet), mass storage and ACM serial link
+         interfaces.
+
+         You will be asked to choose which of the two configurations is
+         to be available in the gadget.  At least one configuration must
+         be chosen to make the gadget usable.  Selecting more than one
+         configuration will prevent Windows from automatically detecting
+         the gadget as a composite gadget, so an INF file will be needed to
+         use the gadget.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_multi".
+
+config USB_G_MULTI_RNDIS
+       bool "RNDIS + CDC Serial + Storage configuration"
+       depends on USB_G_MULTI
+       select USB_F_RNDIS
+       default y
+       help
+         This option enables a configuration with RNDIS, CDC Serial and
+         Mass Storage functions available in the Multifunction Composite
+         Gadget.  This is the configuration dedicated for Windows since RNDIS
+         is Microsoft's protocol.
+
+         If unsure, say "y".
+
+config USB_G_MULTI_CDC
+       bool "CDC Ethernet + CDC Serial + Storage configuration"
+       depends on USB_G_MULTI
+       default n
+       select USB_F_ECM
+       help
+         This option enables a configuration with CDC Ethernet (ECM), CDC
+         Serial and Mass Storage functions available in the Multifunction
+         Composite Gadget.
+
+         If unsure, say "y".
+
+endif # TTY
+
+config USB_G_HID
+       tristate "HID Gadget"
+       select USB_LIBCOMPOSITE
+       help
+         The HID gadget driver provides generic emulation of USB
+         Human Interface Devices (HID).
+
+         For more information, see Documentation/usb/gadget_hid.txt which
+         includes sample code for accessing the device files.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_hid".
+
+# Standalone / single function gadgets
+config USB_G_DBGP
+       tristate "EHCI Debug Device Gadget"
+       depends on TTY
+       select USB_LIBCOMPOSITE
+       help
+         This gadget emulates an EHCI Debug device. This is useful when you want
+         to interact with an EHCI Debug Port.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_dbgp".
+
+if USB_G_DBGP
+choice
+       prompt "EHCI Debug Device mode"
+       default USB_G_DBGP_SERIAL
+
+config USB_G_DBGP_PRINTK
+       depends on USB_G_DBGP
+       bool "printk"
+       help
+         Directly printk() received data. No interaction.
+
+config USB_G_DBGP_SERIAL
+       depends on USB_G_DBGP
+       select USB_U_SERIAL
+       bool "serial"
+       help
+         Userland can interact using /dev/ttyGSxxx.
+endchoice
+endif
+
+# put drivers that need isochronous transfer support (for audio
+# or video class gadget drivers), or specific hardware, here.
+config USB_G_WEBCAM
+       tristate "USB Webcam Gadget"
+       depends on VIDEO_DEV
+       select USB_LIBCOMPOSITE
+       select VIDEOBUF2_VMALLOC
+       help
+         The Webcam Gadget acts as a composite USB Audio and Video Class
+         device. It provides a userspace API to process UVC control requests
+         and stream video data to the host.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_webcam".
diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile
new file mode 100644 (file)
index 0000000..fbb32aa
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# USB gadget drivers
+#
+
+ccflags-y                      := -I$(PWD)/drivers/usb/gadget/
+
+g_zero-y                       := zero.o
+g_audio-y                      := audio.o
+g_ether-y                      := ether.o
+g_serial-y                     := serial.o
+g_midi-y                       := gmidi.o
+gadgetfs-y                     := inode.o
+g_mass_storage-y               := mass_storage.o
+g_printer-y                    := printer.o
+g_cdc-y                                := cdc2.o
+g_multi-y                      := multi.o
+g_hid-y                                := hid.o
+g_dbgp-y                       := dbgp.o
+g_nokia-y                      := nokia.o
+g_webcam-y                     := webcam.o
+g_ncm-y                                := ncm.o
+g_acm_ms-y                     := acm_ms.o
+g_tcm_usb_gadget-y             := tcm_usb_gadget.o
+
+obj-$(CONFIG_USB_ZERO)         += g_zero.o
+obj-$(CONFIG_USB_AUDIO)                += g_audio.o
+obj-$(CONFIG_USB_ETH)          += g_ether.o
+obj-$(CONFIG_USB_GADGETFS)     += gadgetfs.o
+obj-$(CONFIG_USB_FUNCTIONFS)   += g_ffs.o
+obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
+obj-$(CONFIG_USB_G_SERIAL)     += g_serial.o
+obj-$(CONFIG_USB_G_PRINTER)    += g_printer.o
+obj-$(CONFIG_USB_MIDI_GADGET)  += g_midi.o
+obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
+obj-$(CONFIG_USB_G_HID)                += g_hid.o
+obj-$(CONFIG_USB_G_DBGP)       += g_dbgp.o
+obj-$(CONFIG_USB_G_MULTI)      += g_multi.o
+obj-$(CONFIG_USB_G_NOKIA)      += g_nokia.o
+obj-$(CONFIG_USB_G_WEBCAM)     += g_webcam.o
+obj-$(CONFIG_USB_G_NCM)                += g_ncm.o
+obj-$(CONFIG_USB_G_ACM_MS)     += g_acm_ms.o
+obj-$(CONFIG_USB_GADGET_TARGET)        += tcm_usb_gadget.o
diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c
new file mode 100644 (file)
index 0000000..c30b7b5
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * acm_ms.c -- Composite driver, with ACM and mass storage support
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: David Brownell
+ * Modified: Klaus Schwarzkopf <schwarzkopf@sensortherm.de>
+ *
+ * Heavily based on multi.c and cdc2.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "u_serial.h"
+
+#define DRIVER_DESC            "Composite Gadget (ACM + MS)"
+#define DRIVER_VERSION         "2011/10/10"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define ACM_MS_VENDOR_NUM      0x1d6b  /* Linux Foundation */
+#define ACM_MS_PRODUCT_NUM     0x0106  /* Composite Gadget: ACM + MS*/
+
+#include "f_mass_storage.h"
+
+/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16(0x0200),
+
+       .bDeviceClass =         USB_CLASS_MISC /* 0xEF */,
+       .bDeviceSubClass =      2,
+       .bDeviceProtocol =      1,
+
+       /* .bMaxPacketSize0 = f(hardware) */
+
+       /* Vendor and product id can be overridden by module parameters.  */
+       .idVendor =             cpu_to_le16(ACM_MS_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(ACM_MS_PRODUCT_NUM),
+       /* .bcdDevice = f(hardware) */
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       /* NO SERIAL NUMBER */
+       /*.bNumConfigurations = DYNAMIC*/
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /*
+        * REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+/* string IDs are assigned dynamically */
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+/****************************** Configurations ******************************/
+
+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
+
+#else
+
+/*
+ * Number of buffers we will use.
+ * 2 is usually enough for good buffering pipeline
+ */
+#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+/*-------------------------------------------------------------------------*/
+static struct usb_function *f_acm;
+static struct usb_function_instance *f_acm_inst;
+
+static struct usb_function_instance *fi_msg;
+static struct usb_function *f_msg;
+
+/*
+ * We _always_ have both ACM and mass storage functions.
+ */
+static int __init acm_ms_do_config(struct usb_configuration *c)
+{
+       struct fsg_opts *opts;
+       int     status;
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       opts = fsg_opts_from_func_inst(fi_msg);
+
+       f_acm = usb_get_function(f_acm_inst);
+       if (IS_ERR(f_acm))
+               return PTR_ERR(f_acm);
+
+       f_msg = usb_get_function(fi_msg);
+       if (IS_ERR(f_msg)) {
+               status = PTR_ERR(f_msg);
+               goto put_acm;
+       }
+
+       status = usb_add_function(c, f_acm);
+       if (status < 0)
+               goto put_msg;
+
+       status = fsg_common_run_thread(opts->common);
+       if (status)
+               goto remove_acm;
+
+       status = usb_add_function(c, f_msg);
+       if (status)
+               goto remove_acm;
+
+       return 0;
+remove_acm:
+       usb_remove_function(c, f_acm);
+put_msg:
+       usb_put_function(f_msg);
+put_acm:
+       usb_put_function(f_acm);
+       return status;
+}
+
+static struct usb_configuration acm_ms_config_driver = {
+       .label                  = DRIVER_DESC,
+       .bConfigurationValue    = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init acm_ms_bind(struct usb_composite_dev *cdev)
+{
+       struct usb_gadget       *gadget = cdev->gadget;
+       struct fsg_opts         *opts;
+       struct fsg_config       config;
+       int                     status;
+
+       f_acm_inst = usb_get_function_instance("acm");
+       if (IS_ERR(f_acm_inst))
+               return PTR_ERR(f_acm_inst);
+
+       fi_msg = usb_get_function_instance("mass_storage");
+       if (IS_ERR(fi_msg)) {
+               status = PTR_ERR(fi_msg);
+               goto fail_get_msg;
+       }
+
+       /* set up mass storage function */
+       fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
+       opts = fsg_opts_from_func_inst(fi_msg);
+
+       opts->no_configfs = true;
+       status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
+       if (status)
+               goto fail;
+
+       status = fsg_common_set_nluns(opts->common, config.nluns);
+       if (status)
+               goto fail_set_nluns;
+
+       status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
+       if (status)
+               goto fail_set_cdev;
+
+       fsg_common_set_sysfs(opts->common, true);
+       status = fsg_common_create_luns(opts->common, &config);
+       if (status)
+               goto fail_set_cdev;
+
+       fsg_common_set_inquiry_string(opts->common, config.vendor_name,
+                                     config.product_name);
+       /*
+        * Allocate string descriptor numbers ... note that string
+        * contents can be overridden by the composite_dev glue.
+        */
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto fail_string_ids;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       /* register our configuration */
+       status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
+       if (status < 0)
+               goto fail_string_ids;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
+                       DRIVER_DESC);
+       return 0;
+
+       /* error recovery */
+fail_string_ids:
+       fsg_common_remove_luns(opts->common);
+fail_set_cdev:
+       fsg_common_free_luns(opts->common);
+fail_set_nluns:
+       fsg_common_free_buffers(opts->common);
+fail:
+       usb_put_function_instance(fi_msg);
+fail_get_msg:
+       usb_put_function_instance(f_acm_inst);
+       return status;
+}
+
+static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
+{
+       usb_put_function(f_msg);
+       usb_put_function_instance(fi_msg);
+       usb_put_function(f_acm);
+       usb_put_function_instance(f_acm_inst);
+       return 0;
+}
+
+static __refdata struct usb_composite_driver acm_ms_driver = {
+       .name           = "g_acm_ms",
+       .dev            = &device_desc,
+       .max_speed      = USB_SPEED_SUPER,
+       .strings        = dev_strings,
+       .bind           = acm_ms_bind,
+       .unbind         = __exit_p(acm_ms_unbind),
+};
+
+module_usb_composite_driver(acm_ms_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c
new file mode 100644 (file)
index 0000000..6eb695e
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * audio.c -- Audio gadget driver
+ *
+ * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+ * Copyright (C) 2008 Analog Devices, Inc
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb/composite.h>
+
+#include "gadget_chips.h"
+#define DRIVER_DESC            "Linux USB Audio Gadget"
+#define DRIVER_VERSION         "Feb 2, 2012"
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+/* string IDs are assigned dynamically */
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language = 0x0409,     /* en-us */
+       .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *audio_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+#ifdef CONFIG_GADGET_UAC1
+#include "u_uac1.h"
+#include "u_uac1.c"
+#include "f_uac1.c"
+#else
+#include "f_uac2.c"
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to Linux Foundation for donating this product ID. */
+#define AUDIO_VENDOR_NUM               0x1d6b  /* Linux Foundation */
+#define AUDIO_PRODUCT_NUM              0x0101  /* Linux-USB Audio Gadget */
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               __constant_cpu_to_le16(0x200),
+
+#ifdef CONFIG_GADGET_UAC1
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+#else
+       .bDeviceClass =         USB_CLASS_MISC,
+       .bDeviceSubClass =      0x02,
+       .bDeviceProtocol =      0x01,
+#endif
+       /* .bMaxPacketSize0 = f(hardware) */
+
+       /* Vendor and product id defaults change according to what configs
+        * we support.  (As does bNumConfigurations.)  These values can
+        * also be overridden by module parameters.
+        */
+       .idVendor =             __constant_cpu_to_le16(AUDIO_VENDOR_NUM),
+       .idProduct =            __constant_cpu_to_le16(AUDIO_PRODUCT_NUM),
+       /* .bcdDevice = f(hardware) */
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       /* NO SERIAL NUMBER */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init audio_do_config(struct usb_configuration *c)
+{
+       /* FIXME alloc iConfiguration string, set it in c->strings */
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       audio_bind_config(c);
+
+       return 0;
+}
+
+static struct usb_configuration audio_config_driver = {
+       .label                  = DRIVER_DESC,
+       .bConfigurationValue    = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+#ifndef CONFIG_GADGET_UAC1
+       .unbind                 = uac2_unbind_config,
+#endif
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init audio_bind(struct usb_composite_dev *cdev)
+{
+       int                     status;
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto fail;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
+       if (status < 0)
+               goto fail;
+       usb_composite_overwrite_options(cdev, &coverwrite);
+
+       INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
+       return 0;
+
+fail:
+       return status;
+}
+
+static int __exit audio_unbind(struct usb_composite_dev *cdev)
+{
+#ifdef CONFIG_GADGET_UAC1
+       gaudio_cleanup();
+#endif
+       return 0;
+}
+
+static __refdata struct usb_composite_driver audio_driver = {
+       .name           = "g_audio",
+       .dev            = &device_desc,
+       .strings        = audio_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = audio_bind,
+       .unbind         = __exit_p(audio_unbind),
+};
+
+module_usb_composite_driver(audio_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Bryan Wu <cooloney@kernel.org>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/legacy/cdc2.c b/drivers/usb/gadget/legacy/cdc2.c
new file mode 100644 (file)
index 0000000..2e85d94
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * cdc2.c -- CDC Composite driver, with ECM and ACM support
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "u_ether.h"
+#include "u_serial.h"
+#include "u_ecm.h"
+
+
+#define DRIVER_DESC            "CDC Composite Gadget"
+#define DRIVER_VERSION         "King Kamehameha Day 2008"
+
+/*-------------------------------------------------------------------------*/
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ * It's for devices with only this composite CDC configuration.
+ */
+#define CDC_VENDOR_NUM         0x0525  /* NetChip */
+#define CDC_PRODUCT_NUM                0xa4aa  /* CDC Composite: ECM + ACM */
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+USB_ETHERNET_MODULE_PARAMETERS();
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16(0x0200),
+
+       .bDeviceClass =         USB_CLASS_COMM,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       /* .bMaxPacketSize0 = f(hardware) */
+
+       /* Vendor and product id can be overridden by module parameters.  */
+       .idVendor =             cpu_to_le16(CDC_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(CDC_PRODUCT_NUM),
+       /* .bcdDevice = f(hardware) */
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       /* NO SERIAL NUMBER */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+
+/* string IDs are assigned dynamically */
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+static struct usb_function *f_acm;
+static struct usb_function_instance *fi_serial;
+
+static struct usb_function *f_ecm;
+static struct usb_function_instance *fi_ecm;
+
+/*
+ * We _always_ have both CDC ECM and CDC ACM functions.
+ */
+static int __init cdc_do_config(struct usb_configuration *c)
+{
+       int     status;
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       f_ecm = usb_get_function(fi_ecm);
+       if (IS_ERR(f_ecm)) {
+               status = PTR_ERR(f_ecm);
+               goto err_get_ecm;
+       }
+
+       status = usb_add_function(c, f_ecm);
+       if (status)
+               goto err_add_ecm;
+
+       f_acm = usb_get_function(fi_serial);
+       if (IS_ERR(f_acm)) {
+               status = PTR_ERR(f_acm);
+               goto err_get_acm;
+       }
+
+       status = usb_add_function(c, f_acm);
+       if (status)
+               goto err_add_acm;
+       return 0;
+
+err_add_acm:
+       usb_put_function(f_acm);
+err_get_acm:
+       usb_remove_function(c, f_ecm);
+err_add_ecm:
+       usb_put_function(f_ecm);
+err_get_ecm:
+       return status;
+}
+
+static struct usb_configuration cdc_config_driver = {
+       .label                  = "CDC Composite (ECM + ACM)",
+       .bConfigurationValue    = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init cdc_bind(struct usb_composite_dev *cdev)
+{
+       struct usb_gadget       *gadget = cdev->gadget;
+       struct f_ecm_opts       *ecm_opts;
+       int                     status;
+
+       if (!can_support_ecm(cdev->gadget)) {
+               dev_err(&gadget->dev, "controller '%s' not usable\n",
+                               gadget->name);
+               return -EINVAL;
+       }
+
+       fi_ecm = usb_get_function_instance("ecm");
+       if (IS_ERR(fi_ecm))
+               return PTR_ERR(fi_ecm);
+
+       ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
+
+       gether_set_qmult(ecm_opts->net, qmult);
+       if (!gether_set_host_addr(ecm_opts->net, host_addr))
+               pr_info("using host ethernet address: %s", host_addr);
+       if (!gether_set_dev_addr(ecm_opts->net, dev_addr))
+               pr_info("using self ethernet address: %s", dev_addr);
+
+       fi_serial = usb_get_function_instance("acm");
+       if (IS_ERR(fi_serial)) {
+               status = PTR_ERR(fi_serial);
+               goto fail;
+       }
+
+       /* Allocate string descriptor numbers ... note that string
+        * contents can be overridden by the composite_dev glue.
+        */
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto fail1;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       /* register our configuration */
+       status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config);
+       if (status < 0)
+               goto fail1;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
+                       DRIVER_DESC);
+
+       return 0;
+
+fail1:
+       usb_put_function_instance(fi_serial);
+fail:
+       usb_put_function_instance(fi_ecm);
+       return status;
+}
+
+static int __exit cdc_unbind(struct usb_composite_dev *cdev)
+{
+       usb_put_function(f_acm);
+       usb_put_function_instance(fi_serial);
+       if (!IS_ERR_OR_NULL(f_ecm))
+               usb_put_function(f_ecm);
+       if (!IS_ERR_OR_NULL(fi_ecm))
+               usb_put_function_instance(fi_ecm);
+       return 0;
+}
+
+static __refdata struct usb_composite_driver cdc_driver = {
+       .name           = "g_cdc",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = cdc_bind,
+       .unbind         = __exit_p(cdc_unbind),
+};
+
+module_usb_composite_driver(cdc_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/legacy/dbgp.c b/drivers/usb/gadget/legacy/dbgp.c
new file mode 100644 (file)
index 0000000..986fc51
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * dbgp.c -- EHCI Debug Port device gadget
+ *
+ * Copyright (C) 2010 Stephane Duverger
+ *
+ * Released under the GPLv2.
+ */
+
+/* verbose messages */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "u_serial.h"
+
+#define DRIVER_VENDOR_ID       0x0525 /* NetChip */
+#define DRIVER_PRODUCT_ID      0xc0de /* undefined */
+
+#define USB_DEBUG_MAX_PACKET_SIZE     8
+#define DBGP_REQ_EP0_LEN              128
+#define DBGP_REQ_LEN                  512
+
+static struct dbgp {
+       struct usb_gadget  *gadget;
+       struct usb_request *req;
+       struct usb_ep      *i_ep;
+       struct usb_ep      *o_ep;
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+       struct gserial     *serial;
+#endif
+} dbgp;
+
+static struct usb_device_descriptor device_desc = {
+       .bLength = sizeof device_desc,
+       .bDescriptorType = USB_DT_DEVICE,
+       .bcdUSB = __constant_cpu_to_le16(0x0200),
+       .bDeviceClass = USB_CLASS_VENDOR_SPEC,
+       .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),
+       .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),
+       .bNumConfigurations = 1,
+};
+
+static struct usb_debug_descriptor dbg_desc = {
+       .bLength = sizeof dbg_desc,
+       .bDescriptorType = USB_DT_DEBUG,
+};
+
+static struct usb_endpoint_descriptor i_desc = {
+       .bLength = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bmAttributes = USB_ENDPOINT_XFER_BULK,
+       .bEndpointAddress = USB_DIR_IN,
+};
+
+static struct usb_endpoint_descriptor o_desc = {
+       .bLength = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType = USB_DT_ENDPOINT,
+       .bmAttributes = USB_ENDPOINT_XFER_BULK,
+       .bEndpointAddress = USB_DIR_OUT,
+};
+
+#ifdef CONFIG_USB_G_DBGP_PRINTK
+static int dbgp_consume(char *buf, unsigned len)
+{
+       char c;
+
+       if (!len)
+               return 0;
+
+       c = buf[len-1];
+       if (c != 0)
+               buf[len-1] = 0;
+
+       printk(KERN_NOTICE "%s%c", buf, c);
+       return 0;
+}
+
+static void __disable_ep(struct usb_ep *ep)
+{
+       if (ep && ep->driver_data == dbgp.gadget) {
+               usb_ep_disable(ep);
+               ep->driver_data = NULL;
+       }
+}
+
+static void dbgp_disable_ep(void)
+{
+       __disable_ep(dbgp.i_ep);
+       __disable_ep(dbgp.o_ep);
+}
+
+static void dbgp_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       int stp;
+       int err = 0;
+       int status = req->status;
+
+       if (ep == dbgp.i_ep) {
+               stp = 1;
+               goto fail;
+       }
+
+       if (status != 0) {
+               stp = 2;
+               goto release_req;
+       }
+
+       dbgp_consume(req->buf, req->actual);
+
+       req->length = DBGP_REQ_LEN;
+       err = usb_ep_queue(ep, req, GFP_ATOMIC);
+       if (err < 0) {
+               stp = 3;
+               goto release_req;
+       }
+
+       return;
+
+release_req:
+       kfree(req->buf);
+       usb_ep_free_request(dbgp.o_ep, req);
+       dbgp_disable_ep();
+fail:
+       dev_dbg(&dbgp.gadget->dev,
+               "complete: failure (%d:%d) ==> %d\n", stp, err, status);
+}
+
+static int dbgp_enable_ep_req(struct usb_ep *ep)
+{
+       int err, stp;
+       struct usb_request *req;
+
+       req = usb_ep_alloc_request(ep, GFP_KERNEL);
+       if (!req) {
+               err = -ENOMEM;
+               stp = 1;
+               goto fail_1;
+       }
+
+       req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
+       if (!req->buf) {
+               err = -ENOMEM;
+               stp = 2;
+               goto fail_2;
+       }
+
+       req->complete = dbgp_complete;
+       req->length = DBGP_REQ_LEN;
+       err = usb_ep_queue(ep, req, GFP_ATOMIC);
+       if (err < 0) {
+               stp = 3;
+               goto fail_3;
+       }
+
+       return 0;
+
+fail_3:
+       kfree(req->buf);
+fail_2:
+       usb_ep_free_request(dbgp.o_ep, req);
+fail_1:
+       dev_dbg(&dbgp.gadget->dev,
+               "enable ep req: failure (%d:%d)\n", stp, err);
+       return err;
+}
+
+static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
+{
+       int err;
+       ep->desc = desc;
+       err = usb_ep_enable(ep);
+       ep->driver_data = dbgp.gadget;
+       return err;
+}
+
+static int dbgp_enable_ep(void)
+{
+       int err, stp;
+
+       err = __enable_ep(dbgp.i_ep, &i_desc);
+       if (err < 0) {
+               stp = 1;
+               goto fail_1;
+       }
+
+       err = __enable_ep(dbgp.o_ep, &o_desc);
+       if (err < 0) {
+               stp = 2;
+               goto fail_2;
+       }
+
+       err = dbgp_enable_ep_req(dbgp.o_ep);
+       if (err < 0) {
+               stp = 3;
+               goto fail_3;
+       }
+
+       return 0;
+
+fail_3:
+       __disable_ep(dbgp.o_ep);
+fail_2:
+       __disable_ep(dbgp.i_ep);
+fail_1:
+       dev_dbg(&dbgp.gadget->dev, "enable ep: failure (%d:%d)\n", stp, err);
+       return err;
+}
+#endif
+
+static void dbgp_disconnect(struct usb_gadget *gadget)
+{
+#ifdef CONFIG_USB_G_DBGP_PRINTK
+       dbgp_disable_ep();
+#else
+       gserial_disconnect(dbgp.serial);
+#endif
+}
+
+static void dbgp_unbind(struct usb_gadget *gadget)
+{
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+       kfree(dbgp.serial);
+#endif
+       if (dbgp.req) {
+               kfree(dbgp.req->buf);
+               usb_ep_free_request(gadget->ep0, dbgp.req);
+       }
+
+       gadget->ep0->driver_data = NULL;
+}
+
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+static unsigned char tty_line;
+#endif
+
+static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
+{
+       int stp;
+
+       usb_ep_autoconfig_reset(gadget);
+
+       dbgp.i_ep = usb_ep_autoconfig(gadget, &i_desc);
+       if (!dbgp.i_ep) {
+               stp = 1;
+               goto fail_1;
+       }
+
+       dbgp.i_ep->driver_data = gadget;
+       i_desc.wMaxPacketSize =
+               __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
+
+       dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
+       if (!dbgp.o_ep) {
+               dbgp.i_ep->driver_data = NULL;
+               stp = 2;
+               goto fail_2;
+       }
+
+       dbgp.o_ep->driver_data = gadget;
+       o_desc.wMaxPacketSize =
+               __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
+
+       dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress;
+       dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress;
+
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+       dbgp.serial->in = dbgp.i_ep;
+       dbgp.serial->out = dbgp.o_ep;
+
+       dbgp.serial->in->desc = &i_desc;
+       dbgp.serial->out->desc = &o_desc;
+
+       if (gserial_alloc_line(&tty_line)) {
+               stp = 3;
+               goto fail_3;
+       }
+
+       return 0;
+
+fail_3:
+       dbgp.o_ep->driver_data = NULL;
+#else
+       return 0;
+#endif
+fail_2:
+       dbgp.i_ep->driver_data = NULL;
+fail_1:
+       dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp);
+       return -ENODEV;
+}
+
+static int __init dbgp_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
+{
+       int err, stp;
+
+       dbgp.gadget = gadget;
+
+       dbgp.req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+       if (!dbgp.req) {
+               err = -ENOMEM;
+               stp = 1;
+               goto fail;
+       }
+
+       dbgp.req->buf = kmalloc(DBGP_REQ_EP0_LEN, GFP_KERNEL);
+       if (!dbgp.req->buf) {
+               err = -ENOMEM;
+               stp = 2;
+               goto fail;
+       }
+
+       dbgp.req->length = DBGP_REQ_EP0_LEN;
+       gadget->ep0->driver_data = gadget;
+
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+       dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
+       if (!dbgp.serial) {
+               stp = 3;
+               err = -ENOMEM;
+               goto fail;
+       }
+#endif
+       err = dbgp_configure_endpoints(gadget);
+       if (err < 0) {
+               stp = 4;
+               goto fail;
+       }
+
+       dev_dbg(&dbgp.gadget->dev, "bind: success\n");
+       return 0;
+
+fail:
+       dev_dbg(&gadget->dev, "bind: failure (%d:%d)\n", stp, err);
+       dbgp_unbind(gadget);
+       return err;
+}
+
+static void dbgp_setup_complete(struct usb_ep *ep,
+                               struct usb_request *req)
+{
+       dev_dbg(&dbgp.gadget->dev, "setup complete: %d, %d/%d\n",
+               req->status, req->actual, req->length);
+}
+
+static int dbgp_setup(struct usb_gadget *gadget,
+                     const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_request *req = dbgp.req;
+       u8 request = ctrl->bRequest;
+       u16 value = le16_to_cpu(ctrl->wValue);
+       u16 length = le16_to_cpu(ctrl->wLength);
+       int err = -EOPNOTSUPP;
+       void *data = NULL;
+       u16 len = 0;
+
+       gadget->ep0->driver_data = gadget;
+
+       if (request == USB_REQ_GET_DESCRIPTOR) {
+               switch (value>>8) {
+               case USB_DT_DEVICE:
+                       dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
+                       len = sizeof device_desc;
+                       data = &device_desc;
+                       device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+                       break;
+               case USB_DT_DEBUG:
+                       dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
+                       len = sizeof dbg_desc;
+                       data = &dbg_desc;
+                       break;
+               default:
+                       goto fail;
+               }
+               err = 0;
+       } else if (request == USB_REQ_SET_FEATURE &&
+                  value == USB_DEVICE_DEBUG_MODE) {
+               dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n");
+#ifdef CONFIG_USB_G_DBGP_PRINTK
+               err = dbgp_enable_ep();
+#else
+               err = gserial_connect(dbgp.serial, tty_line);
+#endif
+               if (err < 0)
+                       goto fail;
+       } else
+               goto fail;
+
+       req->length = min(length, len);
+       req->zero = len < req->length;
+       if (data && req->length)
+               memcpy(req->buf, data, req->length);
+
+       req->complete = dbgp_setup_complete;
+       return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+
+fail:
+       dev_dbg(&dbgp.gadget->dev,
+               "setup: failure req %x v %x\n", request, value);
+       return err;
+}
+
+static __refdata struct usb_gadget_driver dbgp_driver = {
+       .function = "dbgp",
+       .max_speed = USB_SPEED_HIGH,
+       .bind = dbgp_bind,
+       .unbind = dbgp_unbind,
+       .setup = dbgp_setup,
+       .disconnect = dbgp_disconnect,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "dbgp"
+       },
+};
+
+static int __init dbgp_init(void)
+{
+       return usb_gadget_probe_driver(&dbgp_driver);
+}
+
+static void __exit dbgp_exit(void)
+{
+       usb_gadget_unregister_driver(&dbgp_driver);
+#ifdef CONFIG_USB_G_DBGP_SERIAL
+       gserial_free_line(tty_line);
+#endif
+}
+
+MODULE_AUTHOR("Stephane Duverger");
+MODULE_LICENSE("GPL");
+module_init(dbgp_init);
+module_exit(dbgp_exit);
diff --git a/drivers/usb/gadget/legacy/ether.c b/drivers/usb/gadget/legacy/ether.c
new file mode 100644 (file)
index 0000000..c5fdc61
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * ether.c -- Ethernet gadget driver, with CDC and non-CDC options
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+
+#if defined USB_ETH_RNDIS
+#  undef USB_ETH_RNDIS
+#endif
+#ifdef CONFIG_USB_ETH_RNDIS
+#  define USB_ETH_RNDIS y
+#endif
+
+#include "u_ether.h"
+
+
+/*
+ * Ethernet gadget driver -- with CDC and non-CDC options
+ * Builds on hardware support for a full duplex link.
+ *
+ * CDC Ethernet is the standard USB solution for sending Ethernet frames
+ * using USB.  Real hardware tends to use the same framing protocol but look
+ * different for control features.  This driver strongly prefers to use
+ * this USB-IF standard as its open-systems interoperability solution;
+ * most host side USB stacks (except from Microsoft) support it.
+ *
+ * This is sometimes called "CDC ECM" (Ethernet Control Model) to support
+ * TLA-soup.  "CDC ACM" (Abstract Control Model) is for modems, and a new
+ * "CDC EEM" (Ethernet Emulation Model) is starting to spread.
+ *
+ * There's some hardware that can't talk CDC ECM.  We make that hardware
+ * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
+ * link-level setup only requires activating the configuration.  Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available.  Linux supports it, but other host operating
+ * systems may not.  (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs.  So we do that, making it easier to use
+ * those MS-Windows drivers.  Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all.  (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
+ *
+ * A third option is also in use.  Rather than CDC Ethernet, or something
+ * simpler, Microsoft pushes their own approach: RNDIS.  The published
+ * RNDIS specs are ambiguous and appear to be incomplete, and are also
+ * needlessly complex.  They borrow more from CDC ACM than CDC ECM.
+ */
+
+#define DRIVER_DESC            "Ethernet Gadget"
+#define DRIVER_VERSION         "Memorial Day 2008"
+
+#ifdef USB_ETH_RNDIS
+#define PREFIX                 "RNDIS/"
+#else
+#define PREFIX                 ""
+#endif
+
+/*
+ * This driver aims for interoperability by using CDC ECM unless
+ *
+ *             can_support_ecm()
+ *
+ * returns false, in which case it supports the CDC Subset.  By default,
+ * that returns true; most hardware has no problems with CDC ECM, that's
+ * a good default.  Previous versions of this driver had no default; this
+ * version changes that, removing overhead for new controller support.
+ *
+ *     IF YOUR HARDWARE CAN'T SUPPORT CDC ECM, UPDATE THAT ROUTINE!
+ */
+
+static inline bool has_rndis(void)
+{
+#ifdef USB_ETH_RNDIS
+       return true;
+#else
+       return false;
+#endif
+}
+
+#include <linux/module.h>
+
+#include "u_ecm.h"
+#include "u_gether.h"
+#ifdef USB_ETH_RNDIS
+#include "u_rndis.h"
+#include "rndis.h"
+#else
+#define rndis_borrow_net(...) do {} while (0)
+#endif
+#include "u_eem.h"
+
+/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
+
+USB_ETHERNET_MODULE_PARAMETERS();
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ * It's for devices with only CDC Ethernet configurations.
+ */
+#define CDC_VENDOR_NUM         0x0525  /* NetChip */
+#define CDC_PRODUCT_NUM                0xa4a1  /* Linux-USB Ethernet Gadget */
+
+/* For hardware that can't talk CDC, we use the same vendor ID that
+ * ARM Linux has used for ethernet-over-usb, both with sa1100 and
+ * with pxa250.  We're protocol-compatible, if the host-side drivers
+ * use the endpoint descriptors.  bcdDevice (version) is nonzero, so
+ * drivers that need to hard-wire endpoint numbers have a hook.
+ *
+ * The protocol is a minimal subset of CDC Ether, which works on any bulk
+ * hardware that's not deeply broken ... even on hardware that can't talk
+ * RNDIS (like SA-1100, with no interrupt endpoint, or anything that
+ * doesn't handle control-OUT).
+ */
+#define        SIMPLE_VENDOR_NUM       0x049f
+#define        SIMPLE_PRODUCT_NUM      0x505a
+
+/* For hardware that can talk RNDIS and either of the above protocols,
+ * use this ID ... the windows INF files will know it.  Unless it's
+ * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose
+ * the non-RNDIS configuration.
+ */
+#define RNDIS_VENDOR_NUM       0x0525  /* NetChip */
+#define RNDIS_PRODUCT_NUM      0xa4a2  /* Ethernet/RNDIS Gadget */
+
+/* For EEM gadgets */
+#define EEM_VENDOR_NUM         0x1d6b  /* Linux Foundation */
+#define EEM_PRODUCT_NUM                0x0102  /* EEM Gadget */
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16 (0x0200),
+
+       .bDeviceClass =         USB_CLASS_COMM,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       /* .bMaxPacketSize0 = f(hardware) */
+
+       /* Vendor and product id defaults change according to what configs
+        * we support.  (As does bNumConfigurations.)  These values can
+        * also be overridden by module parameters.
+        */
+       .idVendor =             cpu_to_le16 (CDC_VENDOR_NUM),
+       .idProduct =            cpu_to_le16 (CDC_PRODUCT_NUM),
+       /* .bcdDevice = f(hardware) */
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       /* NO SERIAL NUMBER */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = PREFIX DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+static struct usb_function_instance *fi_ecm;
+static struct usb_function *f_ecm;
+
+static struct usb_function_instance *fi_eem;
+static struct usb_function *f_eem;
+
+static struct usb_function_instance *fi_geth;
+static struct usb_function *f_geth;
+
+static struct usb_function_instance *fi_rndis;
+static struct usb_function *f_rndis;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * We may not have an RNDIS configuration, but if we do it needs to be
+ * the first one present.  That's to make Microsoft's drivers happy,
+ * and to follow DOCSIS 1.0 (cable modem standard).
+ */
+static int __init rndis_do_config(struct usb_configuration *c)
+{
+       int status;
+
+       /* FIXME alloc iConfiguration string, set it in c->strings */
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       f_rndis = usb_get_function(fi_rndis);
+       if (IS_ERR(f_rndis))
+               return PTR_ERR(f_rndis);
+
+       status = usb_add_function(c, f_rndis);
+       if (status < 0)
+               usb_put_function(f_rndis);
+
+       return status;
+}
+
+static struct usb_configuration rndis_config_driver = {
+       .label                  = "RNDIS",
+       .bConfigurationValue    = 2,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_USB_ETH_EEM
+static bool use_eem = 1;
+#else
+static bool use_eem;
+#endif
+module_param(use_eem, bool, 0);
+MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
+
+/*
+ * We _always_ have an ECM, CDC Subset, or EEM configuration.
+ */
+static int __init eth_do_config(struct usb_configuration *c)
+{
+       int status = 0;
+
+       /* FIXME alloc iConfiguration string, set it in c->strings */
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       if (use_eem) {
+               f_eem = usb_get_function(fi_eem);
+               if (IS_ERR(f_eem))
+                       return PTR_ERR(f_eem);
+
+               status = usb_add_function(c, f_eem);
+               if (status < 0)
+                       usb_put_function(f_eem);
+
+               return status;
+       } else if (can_support_ecm(c->cdev->gadget)) {
+               f_ecm = usb_get_function(fi_ecm);
+               if (IS_ERR(f_ecm))
+                       return PTR_ERR(f_ecm);
+
+               status = usb_add_function(c, f_ecm);
+               if (status < 0)
+                       usb_put_function(f_ecm);
+
+               return status;
+       } else {
+               f_geth = usb_get_function(fi_geth);
+               if (IS_ERR(f_geth))
+                       return PTR_ERR(f_geth);
+
+               status = usb_add_function(c, f_geth);
+               if (status < 0)
+                       usb_put_function(f_geth);
+
+               return status;
+       }
+
+}
+
+static struct usb_configuration eth_config_driver = {
+       /* .label = f(hardware) */
+       .bConfigurationValue    = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init eth_bind(struct usb_composite_dev *cdev)
+{
+       struct usb_gadget       *gadget = cdev->gadget;
+       struct f_eem_opts       *eem_opts = NULL;
+       struct f_ecm_opts       *ecm_opts = NULL;
+       struct f_gether_opts    *geth_opts = NULL;
+       struct net_device       *net;
+       int                     status;
+
+       /* set up main config label and device descriptor */
+       if (use_eem) {
+               /* EEM */
+               fi_eem = usb_get_function_instance("eem");
+               if (IS_ERR(fi_eem))
+                       return PTR_ERR(fi_eem);
+
+               eem_opts = container_of(fi_eem, struct f_eem_opts, func_inst);
+
+               net = eem_opts->net;
+
+               eth_config_driver.label = "CDC Ethernet (EEM)";
+               device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM);
+               device_desc.idProduct = cpu_to_le16(EEM_PRODUCT_NUM);
+       } else if (can_support_ecm(gadget)) {
+               /* ECM */
+
+               fi_ecm = usb_get_function_instance("ecm");
+               if (IS_ERR(fi_ecm))
+                       return PTR_ERR(fi_ecm);
+
+               ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
+
+               net = ecm_opts->net;
+
+               eth_config_driver.label = "CDC Ethernet (ECM)";
+       } else {
+               /* CDC Subset */
+
+               fi_geth = usb_get_function_instance("geth");
+               if (IS_ERR(fi_geth))
+                       return PTR_ERR(fi_geth);
+
+               geth_opts = container_of(fi_geth, struct f_gether_opts,
+                                        func_inst);
+
+               net = geth_opts->net;
+
+               eth_config_driver.label = "CDC Subset/SAFE";
+
+               device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM);
+               device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM);
+               if (!has_rndis())
+                       device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+       }
+
+       gether_set_qmult(net, qmult);
+       if (!gether_set_host_addr(net, host_addr))
+               pr_info("using host ethernet address: %s", host_addr);
+       if (!gether_set_dev_addr(net, dev_addr))
+               pr_info("using self ethernet address: %s", dev_addr);
+
+       if (has_rndis()) {
+               /* RNDIS plus ECM-or-Subset */
+               gether_set_gadget(net, cdev->gadget);
+               status = gether_register_netdev(net);
+               if (status)
+                       goto fail;
+
+               if (use_eem)
+                       eem_opts->bound = true;
+               else if (can_support_ecm(gadget))
+                       ecm_opts->bound = true;
+               else
+                       geth_opts->bound = true;
+
+               fi_rndis = usb_get_function_instance("rndis");
+               if (IS_ERR(fi_rndis)) {
+                       status = PTR_ERR(fi_rndis);
+                       goto fail;
+               }
+
+               rndis_borrow_net(fi_rndis, net);
+
+               device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM);
+               device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM);
+               device_desc.bNumConfigurations = 2;
+       }
+
+       /* Allocate string descriptor numbers ... note that string
+        * contents can be overridden by the composite_dev glue.
+        */
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto fail1;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       /* register our configuration(s); RNDIS first, if it's used */
+       if (has_rndis()) {
+               status = usb_add_config(cdev, &rndis_config_driver,
+                               rndis_do_config);
+               if (status < 0)
+                       goto fail1;
+       }
+
+       status = usb_add_config(cdev, &eth_config_driver, eth_do_config);
+       if (status < 0)
+               goto fail1;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
+                       DRIVER_DESC);
+
+       return 0;
+
+fail1:
+       if (has_rndis())
+               usb_put_function_instance(fi_rndis);
+fail:
+       if (use_eem)
+               usb_put_function_instance(fi_eem);
+       else if (can_support_ecm(gadget))
+               usb_put_function_instance(fi_ecm);
+       else
+               usb_put_function_instance(fi_geth);
+       return status;
+}
+
+static int __exit eth_unbind(struct usb_composite_dev *cdev)
+{
+       if (has_rndis()) {
+               usb_put_function(f_rndis);
+               usb_put_function_instance(fi_rndis);
+       }
+       if (use_eem) {
+               usb_put_function(f_eem);
+               usb_put_function_instance(fi_eem);
+       } else if (can_support_ecm(cdev->gadget)) {
+               usb_put_function(f_ecm);
+               usb_put_function_instance(fi_ecm);
+       } else {
+               usb_put_function(f_geth);
+               usb_put_function_instance(fi_geth);
+       }
+       return 0;
+}
+
+static __refdata struct usb_composite_driver eth_driver = {
+       .name           = "g_ether",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_SUPER,
+       .bind           = eth_bind,
+       .unbind         = __exit_p(eth_unbind),
+};
+
+module_usb_composite_driver(eth_driver);
+
+MODULE_DESCRIPTION(PREFIX DRIVER_DESC);
+MODULE_AUTHOR("David Brownell, Benedikt Spanger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c
new file mode 100644 (file)
index 0000000..06acfa5
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * g_ffs.c -- user mode file system API for USB composite function controllers
+ *
+ * Copyright (C) 2010 Samsung Electronics
+ * Author: Michal Nazarewicz <mina86@mina86.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "g_ffs: " fmt
+
+#include <linux/module.h>
+
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+#include <linux/netdevice.h>
+
+#  if defined USB_ETH_RNDIS
+#    undef USB_ETH_RNDIS
+#  endif
+#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+#    define USB_ETH_RNDIS y
+#  endif
+
+#  include "u_ecm.h"
+#  include "u_gether.h"
+#  ifdef USB_ETH_RNDIS
+#    include "u_rndis.h"
+#    include "rndis.h"
+#  endif
+#  include "u_ether.h"
+
+USB_ETHERNET_MODULE_PARAMETERS();
+
+#  ifdef CONFIG_USB_FUNCTIONFS_ETH
+static int eth_bind_config(struct usb_configuration *c);
+static struct usb_function_instance *fi_ecm;
+static struct usb_function *f_ecm;
+static struct usb_function_instance *fi_geth;
+static struct usb_function *f_geth;
+#  endif
+#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+static int bind_rndis_config(struct usb_configuration *c);
+static struct usb_function_instance *fi_rndis;
+static struct usb_function *f_rndis;
+#  endif
+#endif
+
+#include "u_fs.h"
+
+#define DRIVER_NAME    "g_ffs"
+#define DRIVER_DESC    "USB Function Filesystem"
+#define DRIVER_VERSION "24 Aug 2004"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Michal Nazarewicz");
+MODULE_LICENSE("GPL");
+
+#define GFS_VENDOR_ID  0x1d6b  /* Linux Foundation */
+#define GFS_PRODUCT_ID 0x0105  /* FunctionFS Gadget */
+
+#define GFS_MAX_DEVS   10
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+static struct usb_device_descriptor gfs_dev_desc = {
+       .bLength                = sizeof gfs_dev_desc,
+       .bDescriptorType        = USB_DT_DEVICE,
+
+       .bcdUSB                 = cpu_to_le16(0x0200),
+       .bDeviceClass           = USB_CLASS_PER_INTERFACE,
+
+       .idVendor               = cpu_to_le16(GFS_VENDOR_ID),
+       .idProduct              = cpu_to_le16(GFS_PRODUCT_ID),
+};
+
+static char *func_names[GFS_MAX_DEVS];
+static unsigned int func_num;
+
+module_param_named(bDeviceClass,    gfs_dev_desc.bDeviceClass,    byte,   0644);
+MODULE_PARM_DESC(bDeviceClass, "USB Device class");
+module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte,   0644);
+MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
+module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte,   0644);
+MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
+module_param_array_named(functions, func_names, charp, &func_num, 0);
+MODULE_PARM_DESC(functions, "USB Functions list");
+
+static const struct usb_descriptor_header *gfs_otg_desc[] = {
+       (const struct usb_descriptor_header *)
+       &(const struct usb_otg_descriptor) {
+               .bLength                = sizeof(struct usb_otg_descriptor),
+               .bDescriptorType        = USB_DT_OTG,
+
+               /*
+                * REVISIT SRP-only hardware is possible, although
+                * it would not be called "OTG" ...
+                */
+               .bmAttributes           = USB_OTG_SRP | USB_OTG_HNP,
+       },
+
+       NULL
+};
+
+/* String IDs are assigned dynamically */
+static struct usb_string gfs_strings[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+       { .s = "FunctionFS + RNDIS" },
+#endif
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+       { .s = "FunctionFS + ECM" },
+#endif
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+       { .s = "FunctionFS" },
+#endif
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings *gfs_dev_strings[] = {
+       &(struct usb_gadget_strings) {
+               .language       = 0x0409,       /* en-us */
+               .strings        = gfs_strings,
+       },
+       NULL,
+};
+
+struct gfs_configuration {
+       struct usb_configuration c;
+       int (*eth)(struct usb_configuration *c);
+       int num;
+} gfs_configurations[] = {
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+       {
+               .eth            = bind_rndis_config,
+       },
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+       {
+               .eth            = eth_bind_config,
+       },
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+       {
+       },
+#endif
+};
+
+static void *functionfs_acquire_dev(struct ffs_dev *dev);
+static void functionfs_release_dev(struct ffs_dev *dev);
+static int functionfs_ready_callback(struct ffs_data *ffs);
+static void functionfs_closed_callback(struct ffs_data *ffs);
+static int gfs_bind(struct usb_composite_dev *cdev);
+static int gfs_unbind(struct usb_composite_dev *cdev);
+static int gfs_do_config(struct usb_configuration *c);
+
+
+static __refdata struct usb_composite_driver gfs_driver = {
+       .name           = DRIVER_NAME,
+       .dev            = &gfs_dev_desc,
+       .strings        = gfs_dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = gfs_bind,
+       .unbind         = gfs_unbind,
+};
+
+static unsigned int missing_funcs;
+static bool gfs_registered;
+static bool gfs_single_func;
+static struct usb_function_instance **fi_ffs;
+static struct usb_function **f_ffs[] = {
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+       NULL,
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+       NULL,
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
+       NULL,
+#endif
+};
+
+#define N_CONF ARRAY_SIZE(f_ffs)
+
+static int __init gfs_init(void)
+{
+       struct f_fs_opts *opts;
+       int i;
+       int ret = 0;
+
+       ENTER();
+
+       if (func_num < 2) {
+               gfs_single_func = true;
+               func_num = 1;
+       }
+
+       /*
+        * Allocate in one chunk for easier maintenance
+        */
+       f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL);
+       if (!f_ffs[0]) {
+               ret = -ENOMEM;
+               goto no_func;
+       }
+       for (i = 1; i < N_CONF; ++i)
+               f_ffs[i] = f_ffs[0] + i * func_num;
+
+       fi_ffs = kcalloc(func_num, sizeof(*fi_ffs), GFP_KERNEL);
+       if (!fi_ffs) {
+               ret = -ENOMEM;
+               goto no_func;
+       }
+
+       for (i = 0; i < func_num; i++) {
+               fi_ffs[i] = usb_get_function_instance("ffs");
+               if (IS_ERR(fi_ffs[i])) {
+                       ret = PTR_ERR(fi_ffs[i]);
+                       --i;
+                       goto no_dev;
+               }
+               opts = to_f_fs_opts(fi_ffs[i]);
+               if (gfs_single_func)
+                       ret = ffs_single_dev(opts->dev);
+               else
+                       ret = ffs_name_dev(opts->dev, func_names[i]);
+               if (ret)
+                       goto no_dev;
+               opts->dev->ffs_ready_callback = functionfs_ready_callback;
+               opts->dev->ffs_closed_callback = functionfs_closed_callback;
+               opts->dev->ffs_acquire_dev_callback = functionfs_acquire_dev;
+               opts->dev->ffs_release_dev_callback = functionfs_release_dev;
+               opts->no_configfs = true;
+       }
+
+       missing_funcs = func_num;
+
+       return 0;
+no_dev:
+       while (i >= 0)
+               usb_put_function_instance(fi_ffs[i--]);
+       kfree(fi_ffs);
+no_func:
+       kfree(f_ffs[0]);
+       return ret;
+}
+module_init(gfs_init);
+
+static void __exit gfs_exit(void)
+{
+       int i;
+
+       ENTER();
+
+       if (gfs_registered)
+               usb_composite_unregister(&gfs_driver);
+       gfs_registered = false;
+
+       kfree(f_ffs[0]);
+
+       for (i = 0; i < func_num; i++)
+               usb_put_function_instance(fi_ffs[i]);
+
+       kfree(fi_ffs);
+}
+module_exit(gfs_exit);
+
+static void *functionfs_acquire_dev(struct ffs_dev *dev)
+{
+       if (!try_module_get(THIS_MODULE))
+               return ERR_PTR(-ENOENT);
+       
+       return 0;
+}
+
+static void functionfs_release_dev(struct ffs_dev *dev)
+{
+       module_put(THIS_MODULE);
+}
+
+/*
+ * The caller of this function takes ffs_lock 
+ */
+static int functionfs_ready_callback(struct ffs_data *ffs)
+{
+       int ret = 0;
+
+       if (--missing_funcs)
+               return 0;
+
+       if (gfs_registered)
+               return -EBUSY;
+
+       gfs_registered = true;
+
+       ret = usb_composite_probe(&gfs_driver);
+       if (unlikely(ret < 0))
+               gfs_registered = false;
+       
+       return ret;
+}
+
+/*
+ * The caller of this function takes ffs_lock 
+ */
+static void functionfs_closed_callback(struct ffs_data *ffs)
+{
+       missing_funcs++;
+
+       if (gfs_registered)
+               usb_composite_unregister(&gfs_driver);
+       gfs_registered = false;
+}
+
+/*
+ * It is assumed that gfs_bind is called from a context where ffs_lock is held
+ */
+static int gfs_bind(struct usb_composite_dev *cdev)
+{
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+       struct net_device *net;
+#endif
+       int ret, i;
+
+       ENTER();
+
+       if (missing_funcs)
+               return -ENODEV;
+#if defined CONFIG_USB_FUNCTIONFS_ETH
+       if (can_support_ecm(cdev->gadget)) {
+               struct f_ecm_opts *ecm_opts;
+
+               fi_ecm = usb_get_function_instance("ecm");
+               if (IS_ERR(fi_ecm))
+                       return PTR_ERR(fi_ecm);
+               ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
+               net = ecm_opts->net;
+       } else {
+               struct f_gether_opts *geth_opts;
+
+               fi_geth = usb_get_function_instance("geth");
+               if (IS_ERR(fi_geth))
+                       return PTR_ERR(fi_geth);
+               geth_opts = container_of(fi_geth, struct f_gether_opts,
+                                        func_inst);
+               net = geth_opts->net;
+       }
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+       {
+               struct f_rndis_opts *rndis_opts;
+
+               fi_rndis = usb_get_function_instance("rndis");
+               if (IS_ERR(fi_rndis)) {
+                       ret = PTR_ERR(fi_rndis);
+                       goto error;
+               }
+               rndis_opts = container_of(fi_rndis, struct f_rndis_opts,
+                                         func_inst);
+#ifndef CONFIG_USB_FUNCTIONFS_ETH
+               net = rndis_opts->net;
+#endif
+       }
+#endif
+
+#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS
+       gether_set_qmult(net, qmult);
+       if (!gether_set_host_addr(net, host_addr))
+               pr_info("using host ethernet address: %s", host_addr);
+       if (!gether_set_dev_addr(net, dev_addr))
+               pr_info("using self ethernet address: %s", dev_addr);
+#endif
+
+#if defined CONFIG_USB_FUNCTIONFS_RNDIS && defined CONFIG_USB_FUNCTIONFS_ETH
+       gether_set_gadget(net, cdev->gadget);
+       ret = gether_register_netdev(net);
+       if (ret)
+               goto error_rndis;
+
+       if (can_support_ecm(cdev->gadget)) {
+               struct f_ecm_opts *ecm_opts;
+
+               ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
+               ecm_opts->bound = true;
+       } else {
+               struct f_gether_opts *geth_opts;
+
+               geth_opts = container_of(fi_geth, struct f_gether_opts,
+                                        func_inst);
+               geth_opts->bound = true;
+       }
+
+       rndis_borrow_net(fi_rndis, net);
+#endif
+
+       /* TODO: gstrings_attach? */
+       ret = usb_string_ids_tab(cdev, gfs_strings);
+       if (unlikely(ret < 0))
+               goto error_rndis;
+       gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
+
+       for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
+               struct gfs_configuration *c = gfs_configurations + i;
+               int sid = USB_GADGET_FIRST_AVAIL_IDX + i;
+
+               c->c.label                      = gfs_strings[sid].s;
+               c->c.iConfiguration             = gfs_strings[sid].id;
+               c->c.bConfigurationValue        = 1 + i;
+               c->c.bmAttributes               = USB_CONFIG_ATT_SELFPOWER;
+
+               c->num = i;
+
+               ret = usb_add_config(cdev, &c->c, gfs_do_config);
+               if (unlikely(ret < 0))
+                       goto error_unbind;
+       }
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       return 0;
+
+/* TODO */
+error_unbind:
+error_rndis:
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+       usb_put_function_instance(fi_rndis);
+error:
+#endif
+#if defined CONFIG_USB_FUNCTIONFS_ETH
+       if (can_support_ecm(cdev->gadget))
+               usb_put_function_instance(fi_ecm);
+       else
+               usb_put_function_instance(fi_geth);
+#endif
+       return ret;
+}
+
+/*
+ * It is assumed that gfs_unbind is called from a context where ffs_lock is held
+ */
+static int gfs_unbind(struct usb_composite_dev *cdev)
+{
+       int i;
+
+       ENTER();
+
+
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+       usb_put_function(f_rndis);
+       usb_put_function_instance(fi_rndis);
+#endif
+
+#if defined CONFIG_USB_FUNCTIONFS_ETH
+       if (can_support_ecm(cdev->gadget)) {
+               usb_put_function(f_ecm);
+               usb_put_function_instance(fi_ecm);
+       } else {
+               usb_put_function(f_geth);
+               usb_put_function_instance(fi_geth);
+       }
+#endif
+       for (i = 0; i < N_CONF * func_num; ++i)
+               usb_put_function(*(f_ffs[0] + i));
+
+       return 0;
+}
+
+/*
+ * It is assumed that gfs_do_config is called from a context where
+ * ffs_lock is held
+ */
+static int gfs_do_config(struct usb_configuration *c)
+{
+       struct gfs_configuration *gc =
+               container_of(c, struct gfs_configuration, c);
+       int i;
+       int ret;
+
+       if (missing_funcs)
+               return -ENODEV;
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = gfs_otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       if (gc->eth) {
+               ret = gc->eth(c);
+               if (unlikely(ret < 0))
+                       return ret;
+       }
+
+       for (i = 0; i < func_num; i++) {
+               f_ffs[gc->num][i] = usb_get_function(fi_ffs[i]);
+               if (IS_ERR(f_ffs[gc->num][i])) {
+                       ret = PTR_ERR(f_ffs[gc->num][i]);
+                       goto error;
+               }
+               ret = usb_add_function(c, f_ffs[gc->num][i]);
+               if (ret < 0) {
+                       usb_put_function(f_ffs[gc->num][i]);
+                       goto error;
+               }
+       }
+
+       /*
+        * After previous do_configs there may be some invalid
+        * pointers in c->interface array.  This happens every time
+        * a user space function with fewer interfaces than a user
+        * space function that was run before the new one is run.  The
+        * compasit's set_config() assumes that if there is no more
+        * then MAX_CONFIG_INTERFACES interfaces in a configuration
+        * then there is a NULL pointer after the last interface in
+        * c->interface array.  We need to make sure this is true.
+        */
+       if (c->next_interface_id < ARRAY_SIZE(c->interface))
+               c->interface[c->next_interface_id] = NULL;
+
+       return 0;
+error:
+       while (--i >= 0) {
+               if (!IS_ERR(f_ffs[gc->num][i]))
+                       usb_remove_function(c, f_ffs[gc->num][i]);
+               usb_put_function(f_ffs[gc->num][i]);
+       }
+       return ret;
+}
+
+#ifdef CONFIG_USB_FUNCTIONFS_ETH
+
+static int eth_bind_config(struct usb_configuration *c)
+{
+       int status = 0;
+
+       if (can_support_ecm(c->cdev->gadget)) {
+               f_ecm = usb_get_function(fi_ecm);
+               if (IS_ERR(f_ecm))
+                       return PTR_ERR(f_ecm);
+
+               status = usb_add_function(c, f_ecm);
+               if (status < 0)
+                       usb_put_function(f_ecm);
+
+       } else {
+               f_geth = usb_get_function(fi_geth);
+               if (IS_ERR(f_geth))
+                       return PTR_ERR(f_geth);
+
+               status = usb_add_function(c, f_geth);
+               if (status < 0)
+                       usb_put_function(f_geth);
+       }
+       return status;
+}
+
+#endif
+
+#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
+
+static int bind_rndis_config(struct usb_configuration *c)
+{
+       int status = 0;
+
+       f_rndis = usb_get_function(fi_rndis);
+       if (IS_ERR(f_rndis))
+               return PTR_ERR(f_rndis);
+
+       status = usb_add_function(c, f_rndis);
+       if (status < 0)
+               usb_put_function(f_rndis);
+
+       return status;
+}
+
+#endif
diff --git a/drivers/usb/gadget/legacy/gmidi.c b/drivers/usb/gadget/legacy/gmidi.c
new file mode 100644 (file)
index 0000000..3d696b8
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * gmidi.c -- USB MIDI Gadget Driver
+ *
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Developed for Thumtronics by Grey Innovation
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License ("GPL") version 2, as published by the Free Software Foundation.
+ *
+ * This code is based in part on:
+ *
+ * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell.
+ * USB Audio driver, Copyright (C) 2002 by Takashi Iwai.
+ * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch.
+ *
+ * Refer to the USB Device Class Definition for MIDI Devices:
+ * http://www.usb.org/developers/devclass_docs/midi10.pdf
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
+
+#include "gadget_chips.h"
+
+#include "f_midi.c"
+
+/*-------------------------------------------------------------------------*/
+
+MODULE_AUTHOR("Ben Williamson");
+MODULE_LICENSE("GPL v2");
+
+static const char shortname[] = "g_midi";
+static const char longname[] = "MIDI Gadget";
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+static int index = SNDRV_DEFAULT_IDX1;
+module_param(index, int, S_IRUGO);
+MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
+
+static char *id = SNDRV_DEFAULT_STR1;
+module_param(id, charp, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
+
+static unsigned int buflen = 256;
+module_param(buflen, uint, S_IRUGO);
+MODULE_PARM_DESC(buflen, "MIDI buffer length");
+
+static unsigned int qlen = 32;
+module_param(qlen, uint, S_IRUGO);
+MODULE_PARM_DESC(qlen, "USB read request queue length");
+
+static unsigned int in_ports = 1;
+module_param(in_ports, uint, S_IRUGO);
+MODULE_PARM_DESC(in_ports, "Number of MIDI input ports");
+
+static unsigned int out_ports = 1;
+module_param(out_ports, uint, S_IRUGO);
+MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
+
+/* Thanks to Grey Innovation for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define DRIVER_VENDOR_NUM      0x17b3          /* Grey Innovation */
+#define DRIVER_PRODUCT_NUM     0x0004          /* Linux-USB "MIDI Gadget" */
+
+/* string IDs are assigned dynamically */
+
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              USB_DT_DEVICE_SIZE,
+       .bDescriptorType =      USB_DT_DEVICE,
+       .bcdUSB =               __constant_cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+       .idVendor =             __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+       .idProduct =            __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+       /* .iManufacturer =     DYNAMIC */
+       /* .iProduct =          DYNAMIC */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "Grey Innovation",
+       [USB_GADGET_PRODUCT_IDX].s      = "MIDI Gadget",
+       [USB_GADGET_SERIAL_IDX].s       = "",
+       [STRING_DESCRIPTION_IDX].s      = "MIDI",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+static int __exit midi_unbind(struct usb_composite_dev *dev)
+{
+       return 0;
+}
+
+static struct usb_configuration midi_config = {
+       .label          = "MIDI Gadget",
+       .bConfigurationValue = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes   = USB_CONFIG_ATT_ONE,
+       .MaxPower       = CONFIG_USB_GADGET_VBUS_DRAW,
+};
+
+static int __init midi_bind_config(struct usb_configuration *c)
+{
+       return f_midi_bind_config(c, index, id,
+                                 in_ports, out_ports,
+                                 buflen, qlen);
+}
+
+static int __init midi_bind(struct usb_composite_dev *cdev)
+{
+       int status;
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               return status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       midi_config.iConfiguration = strings_dev[STRING_DESCRIPTION_IDX].id;
+
+       status = usb_add_config(cdev, &midi_config, midi_bind_config);
+       if (status < 0)
+               return status;
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       pr_info("%s\n", longname);
+       return 0;
+}
+
+static __refdata struct usb_composite_driver midi_driver = {
+       .name           = (char *) longname,
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = midi_bind,
+       .unbind         = __exit_p(midi_unbind),
+};
+
+module_usb_composite_driver(midi_driver);
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c
new file mode 100644 (file)
index 0000000..778613e
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * hid.c -- HID Composite driver
+ *
+ * Based on multi.c
+ *
+ * Copyright (C) 2010 Fabien Chouteau <fabien.chouteau@barco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/usb/composite.h>
+
+#include "gadget_chips.h"
+#define DRIVER_DESC            "HID Gadget"
+#define DRIVER_VERSION         "2010/03/16"
+
+/*-------------------------------------------------------------------------*/
+
+#define HIDG_VENDOR_NUM                0x0525  /* XXX NetChip */
+#define HIDG_PRODUCT_NUM       0xa4ac  /* Linux-USB HID gadget */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "f_hid.c"
+
+
+struct hidg_func_node {
+       struct list_head node;
+       struct hidg_func_descriptor *func;
+};
+
+static LIST_HEAD(hidg_func_list);
+
+/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16(0x0200),
+
+       /* .bDeviceClass =              USB_CLASS_COMM, */
+       /* .bDeviceSubClass =   0, */
+       /* .bDeviceProtocol =   0, */
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       /* .bMaxPacketSize0 = f(hardware) */
+
+       /* Vendor and product id can be overridden by module parameters.  */
+       .idVendor =             cpu_to_le16(HIDG_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(HIDG_PRODUCT_NUM),
+       /* .bcdDevice = f(hardware) */
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       /* NO SERIAL NUMBER */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+
+/* string IDs are assigned dynamically */
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+
+
+/****************************** Configurations ******************************/
+
+static int __init do_config(struct usb_configuration *c)
+{
+       struct hidg_func_node *e;
+       int func = 0, status = 0;
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       list_for_each_entry(e, &hidg_func_list, node) {
+               status = hidg_bind_config(c, e->func, func++);
+               if (status)
+                       break;
+       }
+
+       return status;
+}
+
+static struct usb_configuration config_driver = {
+       .label                  = "HID Gadget",
+       .bConfigurationValue    = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/****************************** Gadget Bind ******************************/
+
+static int __init hid_bind(struct usb_composite_dev *cdev)
+{
+       struct usb_gadget *gadget = cdev->gadget;
+       struct list_head *tmp;
+       int status, funcs = 0;
+
+       list_for_each(tmp, &hidg_func_list)
+               funcs++;
+
+       if (!funcs)
+               return -ENODEV;
+
+       /* set up HID */
+       status = ghid_setup(cdev->gadget, funcs);
+       if (status < 0)
+               return status;
+
+       /* Allocate string descriptor numbers ... note that string
+        * contents can be overridden by the composite_dev glue.
+        */
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               return status;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       /* register our configuration */
+       status = usb_add_config(cdev, &config_driver, do_config);
+       if (status < 0)
+               return status;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+
+       return 0;
+}
+
+static int __exit hid_unbind(struct usb_composite_dev *cdev)
+{
+       ghid_cleanup();
+       return 0;
+}
+
+static int __init hidg_plat_driver_probe(struct platform_device *pdev)
+{
+       struct hidg_func_descriptor *func = dev_get_platdata(&pdev->dev);
+       struct hidg_func_node *entry;
+
+       if (!func) {
+               dev_err(&pdev->dev, "Platform data missing\n");
+               return -ENODEV;
+       }
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       entry->func = func;
+       list_add_tail(&entry->node, &hidg_func_list);
+
+       return 0;
+}
+
+static int hidg_plat_driver_remove(struct platform_device *pdev)
+{
+       struct hidg_func_node *e, *n;
+
+       list_for_each_entry_safe(e, n, &hidg_func_list, node) {
+               list_del(&e->node);
+               kfree(e);
+       }
+
+       return 0;
+}
+
+
+/****************************** Some noise ******************************/
+
+
+static __refdata struct usb_composite_driver hidg_driver = {
+       .name           = "g_hid",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = hid_bind,
+       .unbind         = __exit_p(hid_unbind),
+};
+
+static struct platform_driver hidg_plat_driver = {
+       .remove         = hidg_plat_driver_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "hidg",
+       },
+};
+
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard");
+MODULE_LICENSE("GPL");
+
+static int __init hidg_init(void)
+{
+       int status;
+
+       status = platform_driver_probe(&hidg_plat_driver,
+                               hidg_plat_driver_probe);
+       if (status < 0)
+               return status;
+
+       status = usb_composite_probe(&hidg_driver);
+       if (status < 0)
+               platform_driver_unregister(&hidg_plat_driver);
+
+       return status;
+}
+module_init(hidg_init);
+
+static void __exit hidg_cleanup(void)
+{
+       platform_driver_unregister(&hidg_plat_driver);
+       usb_composite_unregister(&hidg_driver);
+}
+module_exit(hidg_cleanup);
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
new file mode 100644 (file)
index 0000000..ee6c164
--- /dev/null
@@ -0,0 +1,2142 @@
+/*
+ * inode.c -- user mode filesystem api for usb gadget controllers
+ *
+ * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003 Agilent Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/uts.h>
+#include <linux/wait.h>
+#include <linux/compiler.h>
+#include <asm/uaccess.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/mmu_context.h>
+#include <linux/aio.h>
+
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <linux/usb/gadgetfs.h>
+#include <linux/usb/gadget.h>
+
+
+/*
+ * The gadgetfs API maps each endpoint to a file descriptor so that you
+ * can use standard synchronous read/write calls for I/O.  There's some
+ * O_NONBLOCK and O_ASYNC/FASYNC style i/o support.  Example usermode
+ * drivers show how this works in practice.  You can also use AIO to
+ * eliminate I/O gaps between requests, to help when streaming data.
+ *
+ * Key parts that must be USB-specific are protocols defining how the
+ * read/write operations relate to the hardware state machines.  There
+ * are two types of files.  One type is for the device, implementing ep0.
+ * The other type is for each IN or OUT endpoint.  In both cases, the
+ * user mode driver must configure the hardware before using it.
+ *
+ * - First, dev_config() is called when /dev/gadget/$CHIP is configured
+ *   (by writing configuration and device descriptors).  Afterwards it
+ *   may serve as a source of device events, used to handle all control
+ *   requests other than basic enumeration.
+ *
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ *   called when each /dev/gadget/ep* file is configured (by writing
+ *   endpoint descriptors).  Afterwards these files are used to write()
+ *   IN data or to read() OUT data.  To halt the endpoint, a "wrong
+ *   direction" request is issued (like reading an IN endpoint).
+ *
+ * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
+ * not possible on all hardware.  For example, precise fault handling with
+ * respect to data left in endpoint fifos after aborted operations; or
+ * selective clearing of endpoint halts, to implement SET_INTERFACE.
+ */
+
+#define        DRIVER_DESC     "USB Gadget filesystem"
+#define        DRIVER_VERSION  "24 Aug 2004"
+
+static const char driver_desc [] = DRIVER_DESC;
+static const char shortname [] = "gadgetfs";
+
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_AUTHOR ("David Brownell");
+MODULE_LICENSE ("GPL");
+
+
+/*----------------------------------------------------------------------*/
+
+#define GADGETFS_MAGIC         0xaee71ee7
+
+/* /dev/gadget/$CHIP represents ep0 and the whole device */
+enum ep0_state {
+       /* DISBLED is the initial state.
+        */
+       STATE_DEV_DISABLED = 0,
+
+       /* Only one open() of /dev/gadget/$CHIP; only one file tracks
+        * ep0/device i/o modes and binding to the controller.  Driver
+        * must always write descriptors to initialize the device, then
+        * the device becomes UNCONNECTED until enumeration.
+        */
+       STATE_DEV_OPENED,
+
+       /* From then on, ep0 fd is in either of two basic modes:
+        * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
+        * - SETUP: read/write will transfer control data and succeed;
+        *   or if "wrong direction", performs protocol stall
+        */
+       STATE_DEV_UNCONNECTED,
+       STATE_DEV_CONNECTED,
+       STATE_DEV_SETUP,
+
+       /* UNBOUND means the driver closed ep0, so the device won't be
+        * accessible again (DEV_DISABLED) until all fds are closed.
+        */
+       STATE_DEV_UNBOUND,
+};
+
+/* enough for the whole queue: most events invalidate others */
+#define        N_EVENT                 5
+
+struct dev_data {
+       spinlock_t                      lock;
+       atomic_t                        count;
+       enum ep0_state                  state;          /* P: lock */
+       struct usb_gadgetfs_event       event [N_EVENT];
+       unsigned                        ev_next;
+       struct fasync_struct            *fasync;
+       u8                              current_config;
+
+       /* drivers reading ep0 MUST handle control requests (SETUP)
+        * reported that way; else the host will time out.
+        */
+       unsigned                        usermode_setup : 1,
+                                       setup_in : 1,
+                                       setup_can_stall : 1,
+                                       setup_out_ready : 1,
+                                       setup_out_error : 1,
+                                       setup_abort : 1;
+       unsigned                        setup_wLength;
+
+       /* the rest is basically write-once */
+       struct usb_config_descriptor    *config, *hs_config;
+       struct usb_device_descriptor    *dev;
+       struct usb_request              *req;
+       struct usb_gadget               *gadget;
+       struct list_head                epfiles;
+       void                            *buf;
+       wait_queue_head_t               wait;
+       struct super_block              *sb;
+       struct dentry                   *dentry;
+
+       /* except this scratch i/o buffer for ep0 */
+       u8                              rbuf [256];
+};
+
+static inline void get_dev (struct dev_data *data)
+{
+       atomic_inc (&data->count);
+}
+
+static void put_dev (struct dev_data *data)
+{
+       if (likely (!atomic_dec_and_test (&data->count)))
+               return;
+       /* needs no more cleanup */
+       BUG_ON (waitqueue_active (&data->wait));
+       kfree (data);
+}
+
+static struct dev_data *dev_new (void)
+{
+       struct dev_data         *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+       dev->state = STATE_DEV_DISABLED;
+       atomic_set (&dev->count, 1);
+       spin_lock_init (&dev->lock);
+       INIT_LIST_HEAD (&dev->epfiles);
+       init_waitqueue_head (&dev->wait);
+       return dev;
+}
+
+/*----------------------------------------------------------------------*/
+
+/* other /dev/gadget/$ENDPOINT files represent endpoints */
+enum ep_state {
+       STATE_EP_DISABLED = 0,
+       STATE_EP_READY,
+       STATE_EP_ENABLED,
+       STATE_EP_UNBOUND,
+};
+
+struct ep_data {
+       struct mutex                    lock;
+       enum ep_state                   state;
+       atomic_t                        count;
+       struct dev_data                 *dev;
+       /* must hold dev->lock before accessing ep or req */
+       struct usb_ep                   *ep;
+       struct usb_request              *req;
+       ssize_t                         status;
+       char                            name [16];
+       struct usb_endpoint_descriptor  desc, hs_desc;
+       struct list_head                epfiles;
+       wait_queue_head_t               wait;
+       struct dentry                   *dentry;
+       struct inode                    *inode;
+};
+
+static inline void get_ep (struct ep_data *data)
+{
+       atomic_inc (&data->count);
+}
+
+static void put_ep (struct ep_data *data)
+{
+       if (likely (!atomic_dec_and_test (&data->count)))
+               return;
+       put_dev (data->dev);
+       /* needs no more cleanup */
+       BUG_ON (!list_empty (&data->epfiles));
+       BUG_ON (waitqueue_active (&data->wait));
+       kfree (data);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* most "how to use the hardware" policy choices are in userspace:
+ * mapping endpoint roles (which the driver needs) to the capabilities
+ * which the usb controller has.  most of those capabilities are exposed
+ * implicitly, starting with the driver name and then endpoint names.
+ */
+
+static const char *CHIP;
+
+/*----------------------------------------------------------------------*/
+
+/* NOTE:  don't use dev_printk calls before binding to the gadget
+ * at the end of ep0 configuration, or after unbind.
+ */
+
+/* too wordy: dev_printk(level , &(d)->gadget->dev , fmt , ## args) */
+#define xprintk(d,level,fmt,args...) \
+       printk(level "%s: " fmt , shortname , ## args)
+
+#ifdef DEBUG
+#define DBG(dev,fmt,args...) \
+       xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DBG(dev,fmt,args...) \
+       do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE_DEBUG
+#define VDEBUG DBG
+#else
+#define VDEBUG(dev,fmt,args...) \
+       do { } while (0)
+#endif /* DEBUG */
+
+#define ERROR(dev,fmt,args...) \
+       xprintk(dev , KERN_ERR , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+       xprintk(dev , KERN_INFO , fmt , ## args)
+
+
+/*----------------------------------------------------------------------*/
+
+/* SYNCHRONOUS ENDPOINT OPERATIONS (bulk/intr/iso)
+ *
+ * After opening, configure non-control endpoints.  Then use normal
+ * stream read() and write() requests; and maybe ioctl() to get more
+ * precise FIFO status when recovering from cancellation.
+ */
+
+static void epio_complete (struct usb_ep *ep, struct usb_request *req)
+{
+       struct ep_data  *epdata = ep->driver_data;
+
+       if (!req->context)
+               return;
+       if (req->status)
+               epdata->status = req->status;
+       else
+               epdata->status = req->actual;
+       complete ((struct completion *)req->context);
+}
+
+/* tasklock endpoint, returning when it's connected.
+ * still need dev->lock to use epdata->ep.
+ */
+static int
+get_ready_ep (unsigned f_flags, struct ep_data *epdata)
+{
+       int     val;
+
+       if (f_flags & O_NONBLOCK) {
+               if (!mutex_trylock(&epdata->lock))
+                       goto nonblock;
+               if (epdata->state != STATE_EP_ENABLED) {
+                       mutex_unlock(&epdata->lock);
+nonblock:
+                       val = -EAGAIN;
+               } else
+                       val = 0;
+               return val;
+       }
+
+       val = mutex_lock_interruptible(&epdata->lock);
+       if (val < 0)
+               return val;
+
+       switch (epdata->state) {
+       case STATE_EP_ENABLED:
+               break;
+       // case STATE_EP_DISABLED:              /* "can't happen" */
+       // case STATE_EP_READY:                 /* "can't happen" */
+       default:                                /* error! */
+               pr_debug ("%s: ep %p not available, state %d\n",
+                               shortname, epdata, epdata->state);
+               // FALLTHROUGH
+       case STATE_EP_UNBOUND:                  /* clean disconnect */
+               val = -ENODEV;
+               mutex_unlock(&epdata->lock);
+       }
+       return val;
+}
+
+static ssize_t
+ep_io (struct ep_data *epdata, void *buf, unsigned len)
+{
+       DECLARE_COMPLETION_ONSTACK (done);
+       int value;
+
+       spin_lock_irq (&epdata->dev->lock);
+       if (likely (epdata->ep != NULL)) {
+               struct usb_request      *req = epdata->req;
+
+               req->context = &done;
+               req->complete = epio_complete;
+               req->buf = buf;
+               req->length = len;
+               value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC);
+       } else
+               value = -ENODEV;
+       spin_unlock_irq (&epdata->dev->lock);
+
+       if (likely (value == 0)) {
+               value = wait_event_interruptible (done.wait, done.done);
+               if (value != 0) {
+                       spin_lock_irq (&epdata->dev->lock);
+                       if (likely (epdata->ep != NULL)) {
+                               DBG (epdata->dev, "%s i/o interrupted\n",
+                                               epdata->name);
+                               usb_ep_dequeue (epdata->ep, epdata->req);
+                               spin_unlock_irq (&epdata->dev->lock);
+
+                               wait_event (done.wait, done.done);
+                               if (epdata->status == -ECONNRESET)
+                                       epdata->status = -EINTR;
+                       } else {
+                               spin_unlock_irq (&epdata->dev->lock);
+
+                               DBG (epdata->dev, "endpoint gone\n");
+                               epdata->status = -ENODEV;
+                       }
+               }
+               return epdata->status;
+       }
+       return value;
+}
+
+
+/* handle a synchronous OUT bulk/intr/iso transfer */
+static ssize_t
+ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+{
+       struct ep_data          *data = fd->private_data;
+       void                    *kbuf;
+       ssize_t                 value;
+
+       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
+               return value;
+
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (usb_endpoint_dir_in(&data->desc)) {
+               if (usb_endpoint_xfer_isoc(&data->desc)) {
+                       mutex_unlock(&data->lock);
+                       return -EINVAL;
+               }
+               DBG (data->dev, "%s halt\n", data->name);
+               spin_lock_irq (&data->dev->lock);
+               if (likely (data->ep != NULL))
+                       usb_ep_set_halt (data->ep);
+               spin_unlock_irq (&data->dev->lock);
+               mutex_unlock(&data->lock);
+               return -EBADMSG;
+       }
+
+       /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
+
+       value = -ENOMEM;
+       kbuf = kmalloc (len, GFP_KERNEL);
+       if (unlikely (!kbuf))
+               goto free1;
+
+       value = ep_io (data, kbuf, len);
+       VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
+               data->name, len, (int) value);
+       if (value >= 0 && copy_to_user (buf, kbuf, value))
+               value = -EFAULT;
+
+free1:
+       mutex_unlock(&data->lock);
+       kfree (kbuf);
+       return value;
+}
+
+/* handle a synchronous IN bulk/intr/iso transfer */
+static ssize_t
+ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+{
+       struct ep_data          *data = fd->private_data;
+       void                    *kbuf;
+       ssize_t                 value;
+
+       if ((value = get_ready_ep (fd->f_flags, data)) < 0)
+               return value;
+
+       /* halt any endpoint by doing a "wrong direction" i/o call */
+       if (!usb_endpoint_dir_in(&data->desc)) {
+               if (usb_endpoint_xfer_isoc(&data->desc)) {
+                       mutex_unlock(&data->lock);
+                       return -EINVAL;
+               }
+               DBG (data->dev, "%s halt\n", data->name);
+               spin_lock_irq (&data->dev->lock);
+               if (likely (data->ep != NULL))
+                       usb_ep_set_halt (data->ep);
+               spin_unlock_irq (&data->dev->lock);
+               mutex_unlock(&data->lock);
+               return -EBADMSG;
+       }
+
+       /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
+
+       value = -ENOMEM;
+       kbuf = memdup_user(buf, len);
+       if (!kbuf) {
+               value = PTR_ERR(kbuf);
+               goto free1;
+       }
+
+       value = ep_io (data, kbuf, len);
+       VDEBUG (data->dev, "%s write %zu IN, status %d\n",
+               data->name, len, (int) value);
+free1:
+       mutex_unlock(&data->lock);
+       return value;
+}
+
+static int
+ep_release (struct inode *inode, struct file *fd)
+{
+       struct ep_data          *data = fd->private_data;
+       int value;
+
+       value = mutex_lock_interruptible(&data->lock);
+       if (value < 0)
+               return value;
+
+       /* clean up if this can be reopened */
+       if (data->state != STATE_EP_UNBOUND) {
+               data->state = STATE_EP_DISABLED;
+               data->desc.bDescriptorType = 0;
+               data->hs_desc.bDescriptorType = 0;
+               usb_ep_disable(data->ep);
+       }
+       mutex_unlock(&data->lock);
+       put_ep (data);
+       return 0;
+}
+
+static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
+{
+       struct ep_data          *data = fd->private_data;
+       int                     status;
+
+       if ((status = get_ready_ep (fd->f_flags, data)) < 0)
+               return status;
+
+       spin_lock_irq (&data->dev->lock);
+       if (likely (data->ep != NULL)) {
+               switch (code) {
+               case GADGETFS_FIFO_STATUS:
+                       status = usb_ep_fifo_status (data->ep);
+                       break;
+               case GADGETFS_FIFO_FLUSH:
+                       usb_ep_fifo_flush (data->ep);
+                       break;
+               case GADGETFS_CLEAR_HALT:
+                       status = usb_ep_clear_halt (data->ep);
+                       break;
+               default:
+                       status = -ENOTTY;
+               }
+       } else
+               status = -ENODEV;
+       spin_unlock_irq (&data->dev->lock);
+       mutex_unlock(&data->lock);
+       return status;
+}
+
+/*----------------------------------------------------------------------*/
+
+/* ASYNCHRONOUS ENDPOINT I/O OPERATIONS (bulk/intr/iso) */
+
+struct kiocb_priv {
+       struct usb_request      *req;
+       struct ep_data          *epdata;
+       struct kiocb            *iocb;
+       struct mm_struct        *mm;
+       struct work_struct      work;
+       void                    *buf;
+       const struct iovec      *iv;
+       unsigned long           nr_segs;
+       unsigned                actual;
+};
+
+static int ep_aio_cancel(struct kiocb *iocb)
+{
+       struct kiocb_priv       *priv = iocb->private;
+       struct ep_data          *epdata;
+       int                     value;
+
+       local_irq_disable();
+       epdata = priv->epdata;
+       // spin_lock(&epdata->dev->lock);
+       if (likely(epdata && epdata->ep && priv->req))
+               value = usb_ep_dequeue (epdata->ep, priv->req);
+       else
+               value = -EINVAL;
+       // spin_unlock(&epdata->dev->lock);
+       local_irq_enable();
+
+       return value;
+}
+
+static ssize_t ep_copy_to_user(struct kiocb_priv *priv)
+{
+       ssize_t                 len, total;
+       void                    *to_copy;
+       int                     i;
+
+       /* copy stuff into user buffers */
+       total = priv->actual;
+       len = 0;
+       to_copy = priv->buf;
+       for (i=0; i < priv->nr_segs; i++) {
+               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+               if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
+                       if (len == 0)
+                               len = -EFAULT;
+                       break;
+               }
+
+               total -= this;
+               len += this;
+               to_copy += this;
+               if (total == 0)
+                       break;
+       }
+
+       return len;
+}
+
+static void ep_user_copy_worker(struct work_struct *work)
+{
+       struct kiocb_priv *priv = container_of(work, struct kiocb_priv, work);
+       struct mm_struct *mm = priv->mm;
+       struct kiocb *iocb = priv->iocb;
+       size_t ret;
+
+       use_mm(mm);
+       ret = ep_copy_to_user(priv);
+       unuse_mm(mm);
+
+       /* completing the iocb can drop the ctx and mm, don't touch mm after */
+       aio_complete(iocb, ret, ret);
+
+       kfree(priv->buf);
+       kfree(priv);
+}
+
+static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct kiocb            *iocb = req->context;
+       struct kiocb_priv       *priv = iocb->private;
+       struct ep_data          *epdata = priv->epdata;
+
+       /* lock against disconnect (and ideally, cancel) */
+       spin_lock(&epdata->dev->lock);
+       priv->req = NULL;
+       priv->epdata = NULL;
+
+       /* if this was a write or a read returning no data then we
+        * don't need to copy anything to userspace, so we can
+        * complete the aio request immediately.
+        */
+       if (priv->iv == NULL || unlikely(req->actual == 0)) {
+               kfree(req->buf);
+               kfree(priv);
+               iocb->private = NULL;
+               /* aio_complete() reports bytes-transferred _and_ faults */
+               aio_complete(iocb, req->actual ? req->actual : req->status,
+                               req->status);
+       } else {
+               /* ep_copy_to_user() won't report both; we hide some faults */
+               if (unlikely(0 != req->status))
+                       DBG(epdata->dev, "%s fault %d len %d\n",
+                               ep->name, req->status, req->actual);
+
+               priv->buf = req->buf;
+               priv->actual = req->actual;
+               schedule_work(&priv->work);
+       }
+       spin_unlock(&epdata->dev->lock);
+
+       usb_ep_free_request(ep, req);
+       put_ep(epdata);
+}
+
+static ssize_t
+ep_aio_rwtail(
+       struct kiocb    *iocb,
+       char            *buf,
+       size_t          len,
+       struct ep_data  *epdata,
+       const struct iovec *iv,
+       unsigned long   nr_segs
+)
+{
+       struct kiocb_priv       *priv;
+       struct usb_request      *req;
+       ssize_t                 value;
+
+       priv = kmalloc(sizeof *priv, GFP_KERNEL);
+       if (!priv) {
+               value = -ENOMEM;
+fail:
+               kfree(buf);
+               return value;
+       }
+       iocb->private = priv;
+       priv->iocb = iocb;
+       priv->iv = iv;
+       priv->nr_segs = nr_segs;
+       INIT_WORK(&priv->work, ep_user_copy_worker);
+
+       value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
+       if (unlikely(value < 0)) {
+               kfree(priv);
+               goto fail;
+       }
+
+       kiocb_set_cancel_fn(iocb, ep_aio_cancel);
+       get_ep(epdata);
+       priv->epdata = epdata;
+       priv->actual = 0;
+       priv->mm = current->mm; /* mm teardown waits for iocbs in exit_aio() */
+
+       /* each kiocb is coupled to one usb_request, but we can't
+        * allocate or submit those if the host disconnected.
+        */
+       spin_lock_irq(&epdata->dev->lock);
+       if (likely(epdata->ep)) {
+               req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC);
+               if (likely(req)) {
+                       priv->req = req;
+                       req->buf = buf;
+                       req->length = len;
+                       req->complete = ep_aio_complete;
+                       req->context = iocb;
+                       value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC);
+                       if (unlikely(0 != value))
+                               usb_ep_free_request(epdata->ep, req);
+               } else
+                       value = -EAGAIN;
+       } else
+               value = -ENODEV;
+       spin_unlock_irq(&epdata->dev->lock);
+
+       mutex_unlock(&epdata->lock);
+
+       if (unlikely(value)) {
+               kfree(priv);
+               put_ep(epdata);
+       } else
+               value = -EIOCBQUEUED;
+       return value;
+}
+
+static ssize_t
+ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t o)
+{
+       struct ep_data          *epdata = iocb->ki_filp->private_data;
+       char                    *buf;
+
+       if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
+               return -EINVAL;
+
+       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
+       if (unlikely(!buf))
+               return -ENOMEM;
+
+       return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs);
+}
+
+static ssize_t
+ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
+               unsigned long nr_segs, loff_t o)
+{
+       struct ep_data          *epdata = iocb->ki_filp->private_data;
+       char                    *buf;
+       size_t                  len = 0;
+       int                     i = 0;
+
+       if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
+               return -EINVAL;
+
+       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
+       if (unlikely(!buf))
+               return -ENOMEM;
+
+       for (i=0; i < nr_segs; i++) {
+               if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
+                               iov[i].iov_len) != 0)) {
+                       kfree(buf);
+                       return -EFAULT;
+               }
+               len += iov[i].iov_len;
+       }
+       return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* used after endpoint configuration */
+static const struct file_operations ep_io_operations = {
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+
+       .read =         ep_read,
+       .write =        ep_write,
+       .unlocked_ioctl = ep_ioctl,
+       .release =      ep_release,
+
+       .aio_read =     ep_aio_read,
+       .aio_write =    ep_aio_write,
+};
+
+/* ENDPOINT INITIALIZATION
+ *
+ *     fd = open ("/dev/gadget/$ENDPOINT", O_RDWR)
+ *     status = write (fd, descriptors, sizeof descriptors)
+ *
+ * That write establishes the endpoint configuration, configuring
+ * the controller to process bulk, interrupt, or isochronous transfers
+ * at the right maxpacket size, and so on.
+ *
+ * The descriptors are message type 1, identified by a host order u32
+ * at the beginning of what's written.  Descriptor order is: full/low
+ * speed descriptor, then optional high speed descriptor.
+ */
+static ssize_t
+ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+{
+       struct ep_data          *data = fd->private_data;
+       struct usb_ep           *ep;
+       u32                     tag;
+       int                     value, length = len;
+
+       value = mutex_lock_interruptible(&data->lock);
+       if (value < 0)
+               return value;
+
+       if (data->state != STATE_EP_READY) {
+               value = -EL2HLT;
+               goto fail;
+       }
+
+       value = len;
+       if (len < USB_DT_ENDPOINT_SIZE + 4)
+               goto fail0;
+
+       /* we might need to change message format someday */
+       if (copy_from_user (&tag, buf, 4)) {
+               goto fail1;
+       }
+       if (tag != 1) {
+               DBG(data->dev, "config %s, bad tag %d\n", data->name, tag);
+               goto fail0;
+       }
+       buf += 4;
+       len -= 4;
+
+       /* NOTE:  audio endpoint extensions not accepted here;
+        * just don't include the extra bytes.
+        */
+
+       /* full/low speed descriptor, then high speed */
+       if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) {
+               goto fail1;
+       }
+       if (data->desc.bLength != USB_DT_ENDPOINT_SIZE
+                       || data->desc.bDescriptorType != USB_DT_ENDPOINT)
+               goto fail0;
+       if (len != USB_DT_ENDPOINT_SIZE) {
+               if (len != 2 * USB_DT_ENDPOINT_SIZE)
+                       goto fail0;
+               if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE,
+                                       USB_DT_ENDPOINT_SIZE)) {
+                       goto fail1;
+               }
+               if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE
+                               || data->hs_desc.bDescriptorType
+                                       != USB_DT_ENDPOINT) {
+                       DBG(data->dev, "config %s, bad hs length or type\n",
+                                       data->name);
+                       goto fail0;
+               }
+       }
+
+       spin_lock_irq (&data->dev->lock);
+       if (data->dev->state == STATE_DEV_UNBOUND) {
+               value = -ENOENT;
+               goto gone;
+       } else if ((ep = data->ep) == NULL) {
+               value = -ENODEV;
+               goto gone;
+       }
+       switch (data->dev->gadget->speed) {
+       case USB_SPEED_LOW:
+       case USB_SPEED_FULL:
+               ep->desc = &data->desc;
+               value = usb_ep_enable(ep);
+               if (value == 0)
+                       data->state = STATE_EP_ENABLED;
+               break;
+       case USB_SPEED_HIGH:
+               /* fails if caller didn't provide that descriptor... */
+               ep->desc = &data->hs_desc;
+               value = usb_ep_enable(ep);
+               if (value == 0)
+                       data->state = STATE_EP_ENABLED;
+               break;
+       default:
+               DBG(data->dev, "unconnected, %s init abandoned\n",
+                               data->name);
+               value = -EINVAL;
+       }
+       if (value == 0) {
+               fd->f_op = &ep_io_operations;
+               value = length;
+       }
+gone:
+       spin_unlock_irq (&data->dev->lock);
+       if (value < 0) {
+fail:
+               data->desc.bDescriptorType = 0;
+               data->hs_desc.bDescriptorType = 0;
+       }
+       mutex_unlock(&data->lock);
+       return value;
+fail0:
+       value = -EINVAL;
+       goto fail;
+fail1:
+       value = -EFAULT;
+       goto fail;
+}
+
+static int
+ep_open (struct inode *inode, struct file *fd)
+{
+       struct ep_data          *data = inode->i_private;
+       int                     value = -EBUSY;
+
+       if (mutex_lock_interruptible(&data->lock) != 0)
+               return -EINTR;
+       spin_lock_irq (&data->dev->lock);
+       if (data->dev->state == STATE_DEV_UNBOUND)
+               value = -ENOENT;
+       else if (data->state == STATE_EP_DISABLED) {
+               value = 0;
+               data->state = STATE_EP_READY;
+               get_ep (data);
+               fd->private_data = data;
+               VDEBUG (data->dev, "%s ready\n", data->name);
+       } else
+               DBG (data->dev, "%s state %d\n",
+                       data->name, data->state);
+       spin_unlock_irq (&data->dev->lock);
+       mutex_unlock(&data->lock);
+       return value;
+}
+
+/* used before endpoint configuration */
+static const struct file_operations ep_config_operations = {
+       .llseek =       no_llseek,
+
+       .open =         ep_open,
+       .write =        ep_config,
+       .release =      ep_release,
+};
+
+/*----------------------------------------------------------------------*/
+
+/* EP0 IMPLEMENTATION can be partly in userspace.
+ *
+ * Drivers that use this facility receive various events, including
+ * control requests the kernel doesn't handle.  Drivers that don't
+ * use this facility may be too simple-minded for real applications.
+ */
+
+static inline void ep0_readable (struct dev_data *dev)
+{
+       wake_up (&dev->wait);
+       kill_fasync (&dev->fasync, SIGIO, POLL_IN);
+}
+
+static void clean_req (struct usb_ep *ep, struct usb_request *req)
+{
+       struct dev_data         *dev = ep->driver_data;
+
+       if (req->buf != dev->rbuf) {
+               kfree(req->buf);
+               req->buf = dev->rbuf;
+       }
+       req->complete = epio_complete;
+       dev->setup_out_ready = 0;
+}
+
+static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
+{
+       struct dev_data         *dev = ep->driver_data;
+       unsigned long           flags;
+       int                     free = 1;
+
+       /* for control OUT, data must still get to userspace */
+       spin_lock_irqsave(&dev->lock, flags);
+       if (!dev->setup_in) {
+               dev->setup_out_error = (req->status != 0);
+               if (!dev->setup_out_error)
+                       free = 0;
+               dev->setup_out_ready = 1;
+               ep0_readable (dev);
+       }
+
+       /* clean up as appropriate */
+       if (free && req->buf != &dev->rbuf)
+               clean_req (ep, req);
+       req->complete = epio_complete;
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
+{
+       struct dev_data *dev = ep->driver_data;
+
+       if (dev->setup_out_ready) {
+               DBG (dev, "ep0 request busy!\n");
+               return -EBUSY;
+       }
+       if (len > sizeof (dev->rbuf))
+               req->buf = kmalloc(len, GFP_ATOMIC);
+       if (req->buf == NULL) {
+               req->buf = dev->rbuf;
+               return -ENOMEM;
+       }
+       req->complete = ep0_complete;
+       req->length = len;
+       req->zero = 0;
+       return 0;
+}
+
+static ssize_t
+ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+{
+       struct dev_data                 *dev = fd->private_data;
+       ssize_t                         retval;
+       enum ep0_state                  state;
+
+       spin_lock_irq (&dev->lock);
+
+       /* report fd mode change before acting on it */
+       if (dev->setup_abort) {
+               dev->setup_abort = 0;
+               retval = -EIDRM;
+               goto done;
+       }
+
+       /* control DATA stage */
+       if ((state = dev->state) == STATE_DEV_SETUP) {
+
+               if (dev->setup_in) {            /* stall IN */
+                       VDEBUG(dev, "ep0in stall\n");
+                       (void) usb_ep_set_halt (dev->gadget->ep0);
+                       retval = -EL2HLT;
+                       dev->state = STATE_DEV_CONNECTED;
+
+               } else if (len == 0) {          /* ack SET_CONFIGURATION etc */
+                       struct usb_ep           *ep = dev->gadget->ep0;
+                       struct usb_request      *req = dev->req;
+
+                       if ((retval = setup_req (ep, req, 0)) == 0)
+                               retval = usb_ep_queue (ep, req, GFP_ATOMIC);
+                       dev->state = STATE_DEV_CONNECTED;
+
+                       /* assume that was SET_CONFIGURATION */
+                       if (dev->current_config) {
+                               unsigned power;
+
+                               if (gadget_is_dualspeed(dev->gadget)
+                                               && (dev->gadget->speed
+                                                       == USB_SPEED_HIGH))
+                                       power = dev->hs_config->bMaxPower;
+                               else
+                                       power = dev->config->bMaxPower;
+                               usb_gadget_vbus_draw(dev->gadget, 2 * power);
+                       }
+
+               } else {                        /* collect OUT data */
+                       if ((fd->f_flags & O_NONBLOCK) != 0
+                                       && !dev->setup_out_ready) {
+                               retval = -EAGAIN;
+                               goto done;
+                       }
+                       spin_unlock_irq (&dev->lock);
+                       retval = wait_event_interruptible (dev->wait,
+                                       dev->setup_out_ready != 0);
+
+                       /* FIXME state could change from under us */
+                       spin_lock_irq (&dev->lock);
+                       if (retval)
+                               goto done;
+
+                       if (dev->state != STATE_DEV_SETUP) {
+                               retval = -ECANCELED;
+                               goto done;
+                       }
+                       dev->state = STATE_DEV_CONNECTED;
+
+                       if (dev->setup_out_error)
+                               retval = -EIO;
+                       else {
+                               len = min (len, (size_t)dev->req->actual);
+// FIXME don't call this with the spinlock held ...
+                               if (copy_to_user (buf, dev->req->buf, len))
+                                       retval = -EFAULT;
+                               else
+                                       retval = len;
+                               clean_req (dev->gadget->ep0, dev->req);
+                               /* NOTE userspace can't yet choose to stall */
+                       }
+               }
+               goto done;
+       }
+
+       /* else normal: return event data */
+       if (len < sizeof dev->event [0]) {
+               retval = -EINVAL;
+               goto done;
+       }
+       len -= len % sizeof (struct usb_gadgetfs_event);
+       dev->usermode_setup = 1;
+
+scan:
+       /* return queued events right away */
+       if (dev->ev_next != 0) {
+               unsigned                i, n;
+
+               n = len / sizeof (struct usb_gadgetfs_event);
+               if (dev->ev_next < n)
+                       n = dev->ev_next;
+
+               /* ep0 i/o has special semantics during STATE_DEV_SETUP */
+               for (i = 0; i < n; i++) {
+                       if (dev->event [i].type == GADGETFS_SETUP) {
+                               dev->state = STATE_DEV_SETUP;
+                               n = i + 1;
+                               break;
+                       }
+               }
+               spin_unlock_irq (&dev->lock);
+               len = n * sizeof (struct usb_gadgetfs_event);
+               if (copy_to_user (buf, &dev->event, len))
+                       retval = -EFAULT;
+               else
+                       retval = len;
+               if (len > 0) {
+                       /* NOTE this doesn't guard against broken drivers;
+                        * concurrent ep0 readers may lose events.
+                        */
+                       spin_lock_irq (&dev->lock);
+                       if (dev->ev_next > n) {
+                               memmove(&dev->event[0], &dev->event[n],
+                                       sizeof (struct usb_gadgetfs_event)
+                                               * (dev->ev_next - n));
+                       }
+                       dev->ev_next -= n;
+                       spin_unlock_irq (&dev->lock);
+               }
+               return retval;
+       }
+       if (fd->f_flags & O_NONBLOCK) {
+               retval = -EAGAIN;
+               goto done;
+       }
+
+       switch (state) {
+       default:
+               DBG (dev, "fail %s, state %d\n", __func__, state);
+               retval = -ESRCH;
+               break;
+       case STATE_DEV_UNCONNECTED:
+       case STATE_DEV_CONNECTED:
+               spin_unlock_irq (&dev->lock);
+               DBG (dev, "%s wait\n", __func__);
+
+               /* wait for events */
+               retval = wait_event_interruptible (dev->wait,
+                               dev->ev_next != 0);
+               if (retval < 0)
+                       return retval;
+               spin_lock_irq (&dev->lock);
+               goto scan;
+       }
+
+done:
+       spin_unlock_irq (&dev->lock);
+       return retval;
+}
+
+static struct usb_gadgetfs_event *
+next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
+{
+       struct usb_gadgetfs_event       *event;
+       unsigned                        i;
+
+       switch (type) {
+       /* these events purge the queue */
+       case GADGETFS_DISCONNECT:
+               if (dev->state == STATE_DEV_SETUP)
+                       dev->setup_abort = 1;
+               // FALL THROUGH
+       case GADGETFS_CONNECT:
+               dev->ev_next = 0;
+               break;
+       case GADGETFS_SETUP:            /* previous request timed out */
+       case GADGETFS_SUSPEND:          /* same effect */
+               /* these events can't be repeated */
+               for (i = 0; i != dev->ev_next; i++) {
+                       if (dev->event [i].type != type)
+                               continue;
+                       DBG(dev, "discard old event[%d] %d\n", i, type);
+                       dev->ev_next--;
+                       if (i == dev->ev_next)
+                               break;
+                       /* indices start at zero, for simplicity */
+                       memmove (&dev->event [i], &dev->event [i + 1],
+                               sizeof (struct usb_gadgetfs_event)
+                                       * (dev->ev_next - i));
+               }
+               break;
+       default:
+               BUG ();
+       }
+       VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
+       event = &dev->event [dev->ev_next++];
+       BUG_ON (dev->ev_next > N_EVENT);
+       memset (event, 0, sizeof *event);
+       event->type = type;
+       return event;
+}
+
+static ssize_t
+ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+{
+       struct dev_data         *dev = fd->private_data;
+       ssize_t                 retval = -ESRCH;
+
+       spin_lock_irq (&dev->lock);
+
+       /* report fd mode change before acting on it */
+       if (dev->setup_abort) {
+               dev->setup_abort = 0;
+               retval = -EIDRM;
+
+       /* data and/or status stage for control request */
+       } else if (dev->state == STATE_DEV_SETUP) {
+
+               /* IN DATA+STATUS caller makes len <= wLength */
+               if (dev->setup_in) {
+                       retval = setup_req (dev->gadget->ep0, dev->req, len);
+                       if (retval == 0) {
+                               dev->state = STATE_DEV_CONNECTED;
+                               spin_unlock_irq (&dev->lock);
+                               if (copy_from_user (dev->req->buf, buf, len))
+                                       retval = -EFAULT;
+                               else {
+                                       if (len < dev->setup_wLength)
+                                               dev->req->zero = 1;
+                                       retval = usb_ep_queue (
+                                               dev->gadget->ep0, dev->req,
+                                               GFP_KERNEL);
+                               }
+                               if (retval < 0) {
+                                       spin_lock_irq (&dev->lock);
+                                       clean_req (dev->gadget->ep0, dev->req);
+                                       spin_unlock_irq (&dev->lock);
+                               } else
+                                       retval = len;
+
+                               return retval;
+                       }
+
+               /* can stall some OUT transfers */
+               } else if (dev->setup_can_stall) {
+                       VDEBUG(dev, "ep0out stall\n");
+                       (void) usb_ep_set_halt (dev->gadget->ep0);
+                       retval = -EL2HLT;
+                       dev->state = STATE_DEV_CONNECTED;
+               } else {
+                       DBG(dev, "bogus ep0out stall!\n");
+               }
+       } else
+               DBG (dev, "fail %s, state %d\n", __func__, dev->state);
+
+       spin_unlock_irq (&dev->lock);
+       return retval;
+}
+
+static int
+ep0_fasync (int f, struct file *fd, int on)
+{
+       struct dev_data         *dev = fd->private_data;
+       // caller must F_SETOWN before signal delivery happens
+       VDEBUG (dev, "%s %s\n", __func__, on ? "on" : "off");
+       return fasync_helper (f, fd, on, &dev->fasync);
+}
+
+static struct usb_gadget_driver gadgetfs_driver;
+
+static int
+dev_release (struct inode *inode, struct file *fd)
+{
+       struct dev_data         *dev = fd->private_data;
+
+       /* closing ep0 === shutdown all */
+
+       usb_gadget_unregister_driver (&gadgetfs_driver);
+
+       /* at this point "good" hardware has disconnected the
+        * device from USB; the host won't see it any more.
+        * alternatively, all host requests will time out.
+        */
+
+       kfree (dev->buf);
+       dev->buf = NULL;
+       put_dev (dev);
+
+       return 0;
+}
+
+static unsigned int
+ep0_poll (struct file *fd, poll_table *wait)
+{
+       struct dev_data         *dev = fd->private_data;
+       int                     mask = 0;
+
+       poll_wait(fd, &dev->wait, wait);
+
+       spin_lock_irq (&dev->lock);
+
+       /* report fd mode change before acting on it */
+       if (dev->setup_abort) {
+               dev->setup_abort = 0;
+               mask = POLLHUP;
+               goto out;
+       }
+
+       if (dev->state == STATE_DEV_SETUP) {
+               if (dev->setup_in || dev->setup_can_stall)
+                       mask = POLLOUT;
+       } else {
+               if (dev->ev_next != 0)
+                       mask = POLLIN;
+       }
+out:
+       spin_unlock_irq(&dev->lock);
+       return mask;
+}
+
+static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
+{
+       struct dev_data         *dev = fd->private_data;
+       struct usb_gadget       *gadget = dev->gadget;
+       long ret = -ENOTTY;
+
+       if (gadget->ops->ioctl)
+               ret = gadget->ops->ioctl (gadget, code, value);
+
+       return ret;
+}
+
+/* used after device configuration */
+static const struct file_operations ep0_io_operations = {
+       .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
+
+       .read =         ep0_read,
+       .write =        ep0_write,
+       .fasync =       ep0_fasync,
+       .poll =         ep0_poll,
+       .unlocked_ioctl =       dev_ioctl,
+       .release =      dev_release,
+};
+
+/*----------------------------------------------------------------------*/
+
+/* The in-kernel gadget driver handles most ep0 issues, in particular
+ * enumerating the single configuration (as provided from user space).
+ *
+ * Unrecognized ep0 requests may be handled in user space.
+ */
+
+static void make_qualifier (struct dev_data *dev)
+{
+       struct usb_qualifier_descriptor         qual;
+       struct usb_device_descriptor            *desc;
+
+       qual.bLength = sizeof qual;
+       qual.bDescriptorType = USB_DT_DEVICE_QUALIFIER;
+       qual.bcdUSB = cpu_to_le16 (0x0200);
+
+       desc = dev->dev;
+       qual.bDeviceClass = desc->bDeviceClass;
+       qual.bDeviceSubClass = desc->bDeviceSubClass;
+       qual.bDeviceProtocol = desc->bDeviceProtocol;
+
+       /* assumes ep0 uses the same value for both speeds ... */
+       qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
+
+       qual.bNumConfigurations = 1;
+       qual.bRESERVED = 0;
+
+       memcpy (dev->rbuf, &qual, sizeof qual);
+}
+
+static int
+config_buf (struct dev_data *dev, u8 type, unsigned index)
+{
+       int             len;
+       int             hs = 0;
+
+       /* only one configuration */
+       if (index > 0)
+               return -EINVAL;
+
+       if (gadget_is_dualspeed(dev->gadget)) {
+               hs = (dev->gadget->speed == USB_SPEED_HIGH);
+               if (type == USB_DT_OTHER_SPEED_CONFIG)
+                       hs = !hs;
+       }
+       if (hs) {
+               dev->req->buf = dev->hs_config;
+               len = le16_to_cpu(dev->hs_config->wTotalLength);
+       } else {
+               dev->req->buf = dev->config;
+               len = le16_to_cpu(dev->config->wTotalLength);
+       }
+       ((u8 *)dev->req->buf) [1] = type;
+       return len;
+}
+
+static int
+gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+       struct dev_data                 *dev = get_gadget_data (gadget);
+       struct usb_request              *req = dev->req;
+       int                             value = -EOPNOTSUPP;
+       struct usb_gadgetfs_event       *event;
+       u16                             w_value = le16_to_cpu(ctrl->wValue);
+       u16                             w_length = le16_to_cpu(ctrl->wLength);
+
+       spin_lock (&dev->lock);
+       dev->setup_abort = 0;
+       if (dev->state == STATE_DEV_UNCONNECTED) {
+               if (gadget_is_dualspeed(gadget)
+                               && gadget->speed == USB_SPEED_HIGH
+                               && dev->hs_config == NULL) {
+                       spin_unlock(&dev->lock);
+                       ERROR (dev, "no high speed config??\n");
+                       return -EINVAL;
+               }
+
+               dev->state = STATE_DEV_CONNECTED;
+
+               INFO (dev, "connected\n");
+               event = next_event (dev, GADGETFS_CONNECT);
+               event->u.speed = gadget->speed;
+               ep0_readable (dev);
+
+       /* host may have given up waiting for response.  we can miss control
+        * requests handled lower down (device/endpoint status and features);
+        * then ep0_{read,write} will report the wrong status. controller
+        * driver will have aborted pending i/o.
+        */
+       } else if (dev->state == STATE_DEV_SETUP)
+               dev->setup_abort = 1;
+
+       req->buf = dev->rbuf;
+       req->context = NULL;
+       value = -EOPNOTSUPP;
+       switch (ctrl->bRequest) {
+
+       case USB_REQ_GET_DESCRIPTOR:
+               if (ctrl->bRequestType != USB_DIR_IN)
+                       goto unrecognized;
+               switch (w_value >> 8) {
+
+               case USB_DT_DEVICE:
+                       value = min (w_length, (u16) sizeof *dev->dev);
+                       dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
+                       req->buf = dev->dev;
+                       break;
+               case USB_DT_DEVICE_QUALIFIER:
+                       if (!dev->hs_config)
+                               break;
+                       value = min (w_length, (u16)
+                               sizeof (struct usb_qualifier_descriptor));
+                       make_qualifier (dev);
+                       break;
+               case USB_DT_OTHER_SPEED_CONFIG:
+                       // FALLTHROUGH
+               case USB_DT_CONFIG:
+                       value = config_buf (dev,
+                                       w_value >> 8,
+                                       w_value & 0xff);
+                       if (value >= 0)
+                               value = min (w_length, (u16) value);
+                       break;
+               case USB_DT_STRING:
+                       goto unrecognized;
+
+               default:                // all others are errors
+                       break;
+               }
+               break;
+
+       /* currently one config, two speeds */
+       case USB_REQ_SET_CONFIGURATION:
+               if (ctrl->bRequestType != 0)
+                       goto unrecognized;
+               if (0 == (u8) w_value) {
+                       value = 0;
+                       dev->current_config = 0;
+                       usb_gadget_vbus_draw(gadget, 8 /* mA */ );
+                       // user mode expected to disable endpoints
+               } else {
+                       u8      config, power;
+
+                       if (gadget_is_dualspeed(gadget)
+                                       && gadget->speed == USB_SPEED_HIGH) {
+                               config = dev->hs_config->bConfigurationValue;
+                               power = dev->hs_config->bMaxPower;
+                       } else {
+                               config = dev->config->bConfigurationValue;
+                               power = dev->config->bMaxPower;
+                       }
+
+                       if (config == (u8) w_value) {
+                               value = 0;
+                               dev->current_config = config;
+                               usb_gadget_vbus_draw(gadget, 2 * power);
+                       }
+               }
+
+               /* report SET_CONFIGURATION like any other control request,
+                * except that usermode may not stall this.  the next
+                * request mustn't be allowed start until this finishes:
+                * endpoints and threads set up, etc.
+                *
+                * NOTE:  older PXA hardware (before PXA 255: without UDCCFR)
+                * has bad/racey automagic that prevents synchronizing here.
+                * even kernel mode drivers often miss them.
+                */
+               if (value == 0) {
+                       INFO (dev, "configuration #%d\n", dev->current_config);
+                       usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);
+                       if (dev->usermode_setup) {
+                               dev->setup_can_stall = 0;
+                               goto delegate;
+                       }
+               }
+               break;
+
+#ifndef        CONFIG_USB_PXA25X
+       /* PXA automagically handles this request too */
+       case USB_REQ_GET_CONFIGURATION:
+               if (ctrl->bRequestType != 0x80)
+                       goto unrecognized;
+               *(u8 *)req->buf = dev->current_config;
+               value = min (w_length, (u16) 1);
+               break;
+#endif
+
+       default:
+unrecognized:
+               VDEBUG (dev, "%s req%02x.%02x v%04x i%04x l%d\n",
+                       dev->usermode_setup ? "delegate" : "fail",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, le16_to_cpu(ctrl->wIndex), w_length);
+
+               /* if there's an ep0 reader, don't stall */
+               if (dev->usermode_setup) {
+                       dev->setup_can_stall = 1;
+delegate:
+                       dev->setup_in = (ctrl->bRequestType & USB_DIR_IN)
+                                               ? 1 : 0;
+                       dev->setup_wLength = w_length;
+                       dev->setup_out_ready = 0;
+                       dev->setup_out_error = 0;
+                       value = 0;
+
+                       /* read DATA stage for OUT right away */
+                       if (unlikely (!dev->setup_in && w_length)) {
+                               value = setup_req (gadget->ep0, dev->req,
+                                                       w_length);
+                               if (value < 0)
+                                       break;
+                               value = usb_ep_queue (gadget->ep0, dev->req,
+                                                       GFP_ATOMIC);
+                               if (value < 0) {
+                                       clean_req (gadget->ep0, dev->req);
+                                       break;
+                               }
+
+                               /* we can't currently stall these */
+                               dev->setup_can_stall = 0;
+                       }
+
+                       /* state changes when reader collects event */
+                       event = next_event (dev, GADGETFS_SETUP);
+                       event->u.setup = *ctrl;
+                       ep0_readable (dev);
+                       spin_unlock (&dev->lock);
+                       return 0;
+               }
+       }
+
+       /* proceed with data transfer and status phases? */
+       if (value >= 0 && dev->state != STATE_DEV_SETUP) {
+               req->length = value;
+               req->zero = value < w_length;
+               value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0) {
+                       DBG (dev, "ep_queue --> %d\n", value);
+                       req->status = 0;
+               }
+       }
+
+       /* device stalls when value < 0 */
+       spin_unlock (&dev->lock);
+       return value;
+}
+
+static void destroy_ep_files (struct dev_data *dev)
+{
+       DBG (dev, "%s %d\n", __func__, dev->state);
+
+       /* dev->state must prevent interference */
+       spin_lock_irq (&dev->lock);
+       while (!list_empty(&dev->epfiles)) {
+               struct ep_data  *ep;
+               struct inode    *parent;
+               struct dentry   *dentry;
+
+               /* break link to FS */
+               ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
+               list_del_init (&ep->epfiles);
+               dentry = ep->dentry;
+               ep->dentry = NULL;
+               parent = dentry->d_parent->d_inode;
+
+               /* break link to controller */
+               if (ep->state == STATE_EP_ENABLED)
+                       (void) usb_ep_disable (ep->ep);
+               ep->state = STATE_EP_UNBOUND;
+               usb_ep_free_request (ep->ep, ep->req);
+               ep->ep = NULL;
+               wake_up (&ep->wait);
+               put_ep (ep);
+
+               spin_unlock_irq (&dev->lock);
+
+               /* break link to dcache */
+               mutex_lock (&parent->i_mutex);
+               d_delete (dentry);
+               dput (dentry);
+               mutex_unlock (&parent->i_mutex);
+
+               spin_lock_irq (&dev->lock);
+       }
+       spin_unlock_irq (&dev->lock);
+}
+
+
+static struct inode *
+gadgetfs_create_file (struct super_block *sb, char const *name,
+               void *data, const struct file_operations *fops,
+               struct dentry **dentry_p);
+
+static int activate_ep_files (struct dev_data *dev)
+{
+       struct usb_ep   *ep;
+       struct ep_data  *data;
+
+       gadget_for_each_ep (ep, dev->gadget) {
+
+               data = kzalloc(sizeof(*data), GFP_KERNEL);
+               if (!data)
+                       goto enomem0;
+               data->state = STATE_EP_DISABLED;
+               mutex_init(&data->lock);
+               init_waitqueue_head (&data->wait);
+
+               strncpy (data->name, ep->name, sizeof (data->name) - 1);
+               atomic_set (&data->count, 1);
+               data->dev = dev;
+               get_dev (dev);
+
+               data->ep = ep;
+               ep->driver_data = data;
+
+               data->req = usb_ep_alloc_request (ep, GFP_KERNEL);
+               if (!data->req)
+                       goto enomem1;
+
+               data->inode = gadgetfs_create_file (dev->sb, data->name,
+                               data, &ep_config_operations,
+                               &data->dentry);
+               if (!data->inode)
+                       goto enomem2;
+               list_add_tail (&data->epfiles, &dev->epfiles);
+       }
+       return 0;
+
+enomem2:
+       usb_ep_free_request (ep, data->req);
+enomem1:
+       put_dev (dev);
+       kfree (data);
+enomem0:
+       DBG (dev, "%s enomem\n", __func__);
+       destroy_ep_files (dev);
+       return -ENOMEM;
+}
+
+static void
+gadgetfs_unbind (struct usb_gadget *gadget)
+{
+       struct dev_data         *dev = get_gadget_data (gadget);
+
+       DBG (dev, "%s\n", __func__);
+
+       spin_lock_irq (&dev->lock);
+       dev->state = STATE_DEV_UNBOUND;
+       spin_unlock_irq (&dev->lock);
+
+       destroy_ep_files (dev);
+       gadget->ep0->driver_data = NULL;
+       set_gadget_data (gadget, NULL);
+
+       /* we've already been disconnected ... no i/o is active */
+       if (dev->req)
+               usb_ep_free_request (gadget->ep0, dev->req);
+       DBG (dev, "%s done\n", __func__);
+       put_dev (dev);
+}
+
+static struct dev_data         *the_device;
+
+static int gadgetfs_bind(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
+{
+       struct dev_data         *dev = the_device;
+
+       if (!dev)
+               return -ESRCH;
+       if (0 != strcmp (CHIP, gadget->name)) {
+               pr_err("%s expected %s controller not %s\n",
+                       shortname, CHIP, gadget->name);
+               return -ENODEV;
+       }
+
+       set_gadget_data (gadget, dev);
+       dev->gadget = gadget;
+       gadget->ep0->driver_data = dev;
+
+       /* preallocate control response and buffer */
+       dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+       if (!dev->req)
+               goto enomem;
+       dev->req->context = NULL;
+       dev->req->complete = epio_complete;
+
+       if (activate_ep_files (dev) < 0)
+               goto enomem;
+
+       INFO (dev, "bound to %s driver\n", gadget->name);
+       spin_lock_irq(&dev->lock);
+       dev->state = STATE_DEV_UNCONNECTED;
+       spin_unlock_irq(&dev->lock);
+       get_dev (dev);
+       return 0;
+
+enomem:
+       gadgetfs_unbind (gadget);
+       return -ENOMEM;
+}
+
+static void
+gadgetfs_disconnect (struct usb_gadget *gadget)
+{
+       struct dev_data         *dev = get_gadget_data (gadget);
+       unsigned long           flags;
+
+       spin_lock_irqsave (&dev->lock, flags);
+       if (dev->state == STATE_DEV_UNCONNECTED)
+               goto exit;
+       dev->state = STATE_DEV_UNCONNECTED;
+
+       INFO (dev, "disconnected\n");
+       next_event (dev, GADGETFS_DISCONNECT);
+       ep0_readable (dev);
+exit:
+       spin_unlock_irqrestore (&dev->lock, flags);
+}
+
+static void
+gadgetfs_suspend (struct usb_gadget *gadget)
+{
+       struct dev_data         *dev = get_gadget_data (gadget);
+
+       INFO (dev, "suspended from state %d\n", dev->state);
+       spin_lock (&dev->lock);
+       switch (dev->state) {
+       case STATE_DEV_SETUP:           // VERY odd... host died??
+       case STATE_DEV_CONNECTED:
+       case STATE_DEV_UNCONNECTED:
+               next_event (dev, GADGETFS_SUSPEND);
+               ep0_readable (dev);
+               /* FALLTHROUGH */
+       default:
+               break;
+       }
+       spin_unlock (&dev->lock);
+}
+
+static struct usb_gadget_driver gadgetfs_driver = {
+       .function       = (char *) driver_desc,
+       .bind           = gadgetfs_bind,
+       .unbind         = gadgetfs_unbind,
+       .setup          = gadgetfs_setup,
+       .disconnect     = gadgetfs_disconnect,
+       .suspend        = gadgetfs_suspend,
+
+       .driver = {
+               .name           = (char *) shortname,
+       },
+};
+
+/*----------------------------------------------------------------------*/
+
+static void gadgetfs_nop(struct usb_gadget *arg) { }
+
+static int gadgetfs_probe(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
+{
+       CHIP = gadget->name;
+       return -EISNAM;
+}
+
+static struct usb_gadget_driver probe_driver = {
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = gadgetfs_probe,
+       .unbind         = gadgetfs_nop,
+       .setup          = (void *)gadgetfs_nop,
+       .disconnect     = gadgetfs_nop,
+       .driver = {
+               .name           = "nop",
+       },
+};
+
+
+/* DEVICE INITIALIZATION
+ *
+ *     fd = open ("/dev/gadget/$CHIP", O_RDWR)
+ *     status = write (fd, descriptors, sizeof descriptors)
+ *
+ * That write establishes the device configuration, so the kernel can
+ * bind to the controller ... guaranteeing it can handle enumeration
+ * at all necessary speeds.  Descriptor order is:
+ *
+ * . message tag (u32, host order) ... for now, must be zero; it
+ *     would change to support features like multi-config devices
+ * . full/low speed config ... all wTotalLength bytes (with interface,
+ *     class, altsetting, endpoint, and other descriptors)
+ * . high speed config ... all descriptors, for high speed operation;
+ *     this one's optional except for high-speed hardware
+ * . device descriptor
+ *
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
+ * the need to configure (or unconfigure) them.
+ *
+ * After initialization, the device stays active for as long as that
+ * $CHIP file is open.  Events must then be read from that descriptor,
+ * such as configuration notifications.
+ */
+
+static int is_valid_config (struct usb_config_descriptor *config)
+{
+       return config->bDescriptorType == USB_DT_CONFIG
+               && config->bLength == USB_DT_CONFIG_SIZE
+               && config->bConfigurationValue != 0
+               && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
+               && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0;
+       /* FIXME if gadget->is_otg, _must_ include an otg descriptor */
+       /* FIXME check lengths: walk to end */
+}
+
+static ssize_t
+dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+{
+       struct dev_data         *dev = fd->private_data;
+       ssize_t                 value = len, length = len;
+       unsigned                total;
+       u32                     tag;
+       char                    *kbuf;
+
+       if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
+               return -EINVAL;
+
+       /* we might need to change message format someday */
+       if (copy_from_user (&tag, buf, 4))
+               return -EFAULT;
+       if (tag != 0)
+               return -EINVAL;
+       buf += 4;
+       length -= 4;
+
+       kbuf = memdup_user(buf, length);
+       if (IS_ERR(kbuf))
+               return PTR_ERR(kbuf);
+
+       spin_lock_irq (&dev->lock);
+       value = -EINVAL;
+       if (dev->buf)
+               goto fail;
+       dev->buf = kbuf;
+
+       /* full or low speed config */
+       dev->config = (void *) kbuf;
+       total = le16_to_cpu(dev->config->wTotalLength);
+       if (!is_valid_config (dev->config) || total >= length)
+               goto fail;
+       kbuf += total;
+       length -= total;
+
+       /* optional high speed config */
+       if (kbuf [1] == USB_DT_CONFIG) {
+               dev->hs_config = (void *) kbuf;
+               total = le16_to_cpu(dev->hs_config->wTotalLength);
+               if (!is_valid_config (dev->hs_config) || total >= length)
+                       goto fail;
+               kbuf += total;
+               length -= total;
+       }
+
+       /* could support multiple configs, using another encoding! */
+
+       /* device descriptor (tweaked for paranoia) */
+       if (length != USB_DT_DEVICE_SIZE)
+               goto fail;
+       dev->dev = (void *)kbuf;
+       if (dev->dev->bLength != USB_DT_DEVICE_SIZE
+                       || dev->dev->bDescriptorType != USB_DT_DEVICE
+                       || dev->dev->bNumConfigurations != 1)
+               goto fail;
+       dev->dev->bNumConfigurations = 1;
+       dev->dev->bcdUSB = cpu_to_le16 (0x0200);
+
+       /* triggers gadgetfs_bind(); then we can enumerate. */
+       spin_unlock_irq (&dev->lock);
+       if (dev->hs_config)
+               gadgetfs_driver.max_speed = USB_SPEED_HIGH;
+       else
+               gadgetfs_driver.max_speed = USB_SPEED_FULL;
+
+       value = usb_gadget_probe_driver(&gadgetfs_driver);
+       if (value != 0) {
+               kfree (dev->buf);
+               dev->buf = NULL;
+       } else {
+               /* at this point "good" hardware has for the first time
+                * let the USB the host see us.  alternatively, if users
+                * unplug/replug that will clear all the error state.
+                *
+                * note:  everything running before here was guaranteed
+                * to choke driver model style diagnostics.  from here
+                * on, they can work ... except in cleanup paths that
+                * kick in after the ep0 descriptor is closed.
+                */
+               fd->f_op = &ep0_io_operations;
+               value = len;
+       }
+       return value;
+
+fail:
+       spin_unlock_irq (&dev->lock);
+       pr_debug ("%s: %s fail %Zd, %p\n", shortname, __func__, value, dev);
+       kfree (dev->buf);
+       dev->buf = NULL;
+       return value;
+}
+
+static int
+dev_open (struct inode *inode, struct file *fd)
+{
+       struct dev_data         *dev = inode->i_private;
+       int                     value = -EBUSY;
+
+       spin_lock_irq(&dev->lock);
+       if (dev->state == STATE_DEV_DISABLED) {
+               dev->ev_next = 0;
+               dev->state = STATE_DEV_OPENED;
+               fd->private_data = dev;
+               get_dev (dev);
+               value = 0;
+       }
+       spin_unlock_irq(&dev->lock);
+       return value;
+}
+
+static const struct file_operations dev_init_operations = {
+       .llseek =       no_llseek,
+
+       .open =         dev_open,
+       .write =        dev_config,
+       .fasync =       ep0_fasync,
+       .unlocked_ioctl = dev_ioctl,
+       .release =      dev_release,
+};
+
+/*----------------------------------------------------------------------*/
+
+/* FILESYSTEM AND SUPERBLOCK OPERATIONS
+ *
+ * Mounting the filesystem creates a controller file, used first for
+ * device configuration then later for event monitoring.
+ */
+
+
+/* FIXME PAM etc could set this security policy without mount options
+ * if epfiles inherited ownership and permissons from ep0 ...
+ */
+
+static unsigned default_uid;
+static unsigned default_gid;
+static unsigned default_perm = S_IRUSR | S_IWUSR;
+
+module_param (default_uid, uint, 0644);
+module_param (default_gid, uint, 0644);
+module_param (default_perm, uint, 0644);
+
+
+static struct inode *
+gadgetfs_make_inode (struct super_block *sb,
+               void *data, const struct file_operations *fops,
+               int mode)
+{
+       struct inode *inode = new_inode (sb);
+
+       if (inode) {
+               inode->i_ino = get_next_ino();
+               inode->i_mode = mode;
+               inode->i_uid = make_kuid(&init_user_ns, default_uid);
+               inode->i_gid = make_kgid(&init_user_ns, default_gid);
+               inode->i_atime = inode->i_mtime = inode->i_ctime
+                               = CURRENT_TIME;
+               inode->i_private = data;
+               inode->i_fop = fops;
+       }
+       return inode;
+}
+
+/* creates in fs root directory, so non-renamable and non-linkable.
+ * so inode and dentry are paired, until device reconfig.
+ */
+static struct inode *
+gadgetfs_create_file (struct super_block *sb, char const *name,
+               void *data, const struct file_operations *fops,
+               struct dentry **dentry_p)
+{
+       struct dentry   *dentry;
+       struct inode    *inode;
+
+       dentry = d_alloc_name(sb->s_root, name);
+       if (!dentry)
+               return NULL;
+
+       inode = gadgetfs_make_inode (sb, data, fops,
+                       S_IFREG | (default_perm & S_IRWXUGO));
+       if (!inode) {
+               dput(dentry);
+               return NULL;
+       }
+       d_add (dentry, inode);
+       *dentry_p = dentry;
+       return inode;
+}
+
+static const struct super_operations gadget_fs_operations = {
+       .statfs =       simple_statfs,
+       .drop_inode =   generic_delete_inode,
+};
+
+static int
+gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
+{
+       struct inode    *inode;
+       struct dev_data *dev;
+
+       if (the_device)
+               return -ESRCH;
+
+       /* fake probe to determine $CHIP */
+       CHIP = NULL;
+       usb_gadget_probe_driver(&probe_driver);
+       if (!CHIP)
+               return -ENODEV;
+
+       /* superblock */
+       sb->s_blocksize = PAGE_CACHE_SIZE;
+       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+       sb->s_magic = GADGETFS_MAGIC;
+       sb->s_op = &gadget_fs_operations;
+       sb->s_time_gran = 1;
+
+       /* root inode */
+       inode = gadgetfs_make_inode (sb,
+                       NULL, &simple_dir_operations,
+                       S_IFDIR | S_IRUGO | S_IXUGO);
+       if (!inode)
+               goto Enomem;
+       inode->i_op = &simple_dir_inode_operations;
+       if (!(sb->s_root = d_make_root (inode)))
+               goto Enomem;
+
+       /* the ep0 file is named after the controller we expect;
+        * user mode code can use it for sanity checks, like we do.
+        */
+       dev = dev_new ();
+       if (!dev)
+               goto Enomem;
+
+       dev->sb = sb;
+       if (!gadgetfs_create_file (sb, CHIP,
+                               dev, &dev_init_operations,
+                               &dev->dentry)) {
+               put_dev(dev);
+               goto Enomem;
+       }
+
+       /* other endpoint files are available after hardware setup,
+        * from binding to a controller.
+        */
+       the_device = dev;
+       return 0;
+
+Enomem:
+       return -ENOMEM;
+}
+
+/* "mount -t gadgetfs path /dev/gadget" ends up here */
+static struct dentry *
+gadgetfs_mount (struct file_system_type *t, int flags,
+               const char *path, void *opts)
+{
+       return mount_single (t, flags, opts, gadgetfs_fill_super);
+}
+
+static void
+gadgetfs_kill_sb (struct super_block *sb)
+{
+       kill_litter_super (sb);
+       if (the_device) {
+               put_dev (the_device);
+               the_device = NULL;
+       }
+}
+
+/*----------------------------------------------------------------------*/
+
+static struct file_system_type gadgetfs_type = {
+       .owner          = THIS_MODULE,
+       .name           = shortname,
+       .mount          = gadgetfs_mount,
+       .kill_sb        = gadgetfs_kill_sb,
+};
+MODULE_ALIAS_FS("gadgetfs");
+
+/*----------------------------------------------------------------------*/
+
+static int __init init (void)
+{
+       int status;
+
+       status = register_filesystem (&gadgetfs_type);
+       if (status == 0)
+               pr_info ("%s: %s, version " DRIVER_VERSION "\n",
+                       shortname, driver_desc);
+       return status;
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+       pr_debug ("unregister %s\n", shortname);
+       unregister_filesystem (&gadgetfs_type);
+}
+module_exit (cleanup);
+
diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c
new file mode 100644 (file)
index 0000000..8e27a8c
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * mass_storage.c -- Mass Storage USB Gadget
+ *
+ * Copyright (C) 2003-2008 Alan Stern
+ * Copyright (C) 2009 Samsung Electronics
+ *                    Author: Michal Nazarewicz <mina86@mina86.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+/*
+ * The Mass Storage Gadget acts as a USB Mass Storage device,
+ * appearing to the host as a disk drive or as a CD-ROM drive.  In
+ * addition to providing an example of a genuinely useful gadget
+ * driver for a USB device, it also illustrates a technique of
+ * double-buffering for increased throughput.  Last but not least, it
+ * gives an easy way to probe the behavior of the Mass Storage drivers
+ * in a USB host.
+ *
+ * Since this file serves only administrative purposes and all the
+ * business logic is implemented in f_mass_storage.* file.  Read
+ * comments in this file for more detailed description.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/usb/ch9.h>
+#include <linux/module.h>
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_DESC            "Mass Storage Gadget"
+#define DRIVER_VERSION         "2009/09/11"
+
+/*
+ * Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define FSG_VENDOR_ID  0x0525  /* NetChip */
+#define FSG_PRODUCT_ID 0xa4a5  /* Linux-USB File-backed Storage Gadget */
+
+#include "f_mass_storage.h"
+
+/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
+
+static struct usb_device_descriptor msg_device_desc = {
+       .bLength =              sizeof msg_device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+
+       /* Vendor and product id can be overridden by module parameters.  */
+       .idVendor =             cpu_to_le16(FSG_VENDOR_ID),
+       .idProduct =            cpu_to_le16(FSG_PRODUCT_ID),
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /*
+        * REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+static struct usb_function_instance *fi_msg;
+static struct usb_function *f_msg;
+
+/****************************** Configurations ******************************/
+
+static struct fsg_module_parameters mod_data = {
+       .stall = 1
+};
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
+
+#else
+
+/*
+ * Number of buffers we will use.
+ * 2 is usually enough for good buffering pipeline
+ */
+#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
+
+static unsigned long msg_registered;
+static void msg_cleanup(void);
+
+static int msg_thread_exits(struct fsg_common *common)
+{
+       msg_cleanup();
+       return 0;
+}
+
+static int __init msg_do_config(struct usb_configuration *c)
+{
+       struct fsg_opts *opts;
+       int ret;
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       opts = fsg_opts_from_func_inst(fi_msg);
+
+       f_msg = usb_get_function(fi_msg);
+       if (IS_ERR(f_msg))
+               return PTR_ERR(f_msg);
+
+       ret = fsg_common_run_thread(opts->common);
+       if (ret)
+               goto put_func;
+
+       ret = usb_add_function(c, f_msg);
+       if (ret)
+               goto put_func;
+
+       return 0;
+
+put_func:
+       usb_put_function(f_msg);
+       return ret;
+}
+
+static struct usb_configuration msg_config_driver = {
+       .label                  = "Linux File-Backed Storage",
+       .bConfigurationValue    = 1,
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+
+/****************************** Gadget Bind ******************************/
+
+static int __init msg_bind(struct usb_composite_dev *cdev)
+{
+       static const struct fsg_operations ops = {
+               .thread_exits = msg_thread_exits,
+       };
+       struct fsg_opts *opts;
+       struct fsg_config config;
+       int status;
+
+       fi_msg = usb_get_function_instance("mass_storage");
+       if (IS_ERR(fi_msg))
+               return PTR_ERR(fi_msg);
+
+       fsg_config_from_params(&config, &mod_data, fsg_num_buffers);
+       opts = fsg_opts_from_func_inst(fi_msg);
+
+       opts->no_configfs = true;
+       status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
+       if (status)
+               goto fail;
+
+       status = fsg_common_set_nluns(opts->common, config.nluns);
+       if (status)
+               goto fail_set_nluns;
+
+       fsg_common_set_ops(opts->common, &ops);
+
+       status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
+       if (status)
+               goto fail_set_cdev;
+
+       fsg_common_set_sysfs(opts->common, true);
+       status = fsg_common_create_luns(opts->common, &config);
+       if (status)
+               goto fail_set_cdev;
+
+       fsg_common_set_inquiry_string(opts->common, config.vendor_name,
+                                     config.product_name);
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto fail_string_ids;
+       msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
+       if (status < 0)
+               goto fail_string_ids;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       dev_info(&cdev->gadget->dev,
+                DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+       set_bit(0, &msg_registered);
+       return 0;
+
+fail_string_ids:
+       fsg_common_remove_luns(opts->common);
+fail_set_cdev:
+       fsg_common_free_luns(opts->common);
+fail_set_nluns:
+       fsg_common_free_buffers(opts->common);
+fail:
+       usb_put_function_instance(fi_msg);
+       return status;
+}
+
+static int msg_unbind(struct usb_composite_dev *cdev)
+{
+       if (!IS_ERR(f_msg))
+               usb_put_function(f_msg);
+
+       if (!IS_ERR(fi_msg))
+               usb_put_function_instance(fi_msg);
+
+       return 0;
+}
+
+/****************************** Some noise ******************************/
+
+static __refdata struct usb_composite_driver msg_driver = {
+       .name           = "g_mass_storage",
+       .dev            = &msg_device_desc,
+       .max_speed      = USB_SPEED_SUPER,
+       .needs_serial   = 1,
+       .strings        = dev_strings,
+       .bind           = msg_bind,
+       .unbind         = msg_unbind,
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Michal Nazarewicz");
+MODULE_LICENSE("GPL");
+
+static int __init msg_init(void)
+{
+       return usb_composite_probe(&msg_driver);
+}
+module_init(msg_init);
+
+static void msg_cleanup(void)
+{
+       if (test_and_clear_bit(0, &msg_registered))
+               usb_composite_unregister(&msg_driver);
+}
+module_exit(msg_cleanup);
diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c
new file mode 100644 (file)
index 0000000..39d27bb
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * multi.c -- Multifunction Composite driver
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz (mina86@mina86.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "u_serial.h"
+#if defined USB_ETH_RNDIS
+#  undef USB_ETH_RNDIS
+#endif
+#ifdef CONFIG_USB_G_MULTI_RNDIS
+#  define USB_ETH_RNDIS y
+#endif
+
+
+#define DRIVER_DESC            "Multifunction Composite Gadget"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Michal Nazarewicz");
+MODULE_LICENSE("GPL");
+
+
+#include "f_mass_storage.h"
+
+#include "u_ecm.h"
+#ifdef USB_ETH_RNDIS
+#  include "u_rndis.h"
+#  include "rndis.h"
+#endif
+#include "u_ether.h"
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+USB_ETHERNET_MODULE_PARAMETERS();
+
+/***************************** Device Descriptor ****************************/
+
+#define MULTI_VENDOR_NUM       0x1d6b  /* Linux Foundation */
+#define MULTI_PRODUCT_NUM      0x0104  /* Multifunction Composite Gadget */
+
+
+enum {
+       __MULTI_NO_CONFIG,
+#ifdef CONFIG_USB_G_MULTI_RNDIS
+       MULTI_RNDIS_CONFIG_NUM,
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+       MULTI_CDC_CONFIG_NUM,
+#endif
+};
+
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16(0x0200),
+
+       .bDeviceClass =         USB_CLASS_MISC /* 0xEF */,
+       .bDeviceSubClass =      2,
+       .bDeviceProtocol =      1,
+
+       /* Vendor and product id can be overridden by module parameters.  */
+       .idVendor =             cpu_to_le16(MULTI_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(MULTI_PRODUCT_NUM),
+};
+
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
+               .bLength =              sizeof(struct usb_otg_descriptor),
+               .bDescriptorType =      USB_DT_OTG,
+
+               /*
+                * REVISIT SRP-only hardware is possible, although
+                * it would not be called "OTG" ...
+                */
+               .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+       },
+       NULL,
+};
+
+
+enum {
+       MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX,
+       MULTI_STRING_CDC_CONFIG_IDX,
+};
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
+       [MULTI_STRING_CDC_CONFIG_IDX].s   = "Multifunction with CDC ECM",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &(struct usb_gadget_strings){
+               .language       = 0x0409,       /* en-us */
+               .strings        = strings_dev,
+       },
+       NULL,
+};
+
+
+
+
+/****************************** Configurations ******************************/
+
+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
+
+#else
+
+/*
+ * Number of buffers we will use.
+ * 2 is usually enough for good buffering pipeline
+ */
+#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
+
+#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
+
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+static struct usb_function_instance *fi_acm;
+static struct usb_function_instance *fi_msg;
+
+/********** RNDIS **********/
+
+#ifdef USB_ETH_RNDIS
+static struct usb_function_instance *fi_rndis;
+static struct usb_function *f_acm_rndis;
+static struct usb_function *f_rndis;
+static struct usb_function *f_msg_rndis;
+
+static __init int rndis_do_config(struct usb_configuration *c)
+{
+       struct fsg_opts *fsg_opts;
+       int ret;
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       f_rndis = usb_get_function(fi_rndis);
+       if (IS_ERR(f_rndis))
+               return PTR_ERR(f_rndis);
+
+       ret = usb_add_function(c, f_rndis);
+       if (ret < 0)
+               goto err_func_rndis;
+
+       f_acm_rndis = usb_get_function(fi_acm);
+       if (IS_ERR(f_acm_rndis)) {
+               ret = PTR_ERR(f_acm_rndis);
+               goto err_func_acm;
+       }
+
+       ret = usb_add_function(c, f_acm_rndis);
+       if (ret)
+               goto err_conf;
+
+       f_msg_rndis = usb_get_function(fi_msg);
+       if (IS_ERR(f_msg_rndis)) {
+               ret = PTR_ERR(f_msg_rndis);
+               goto err_fsg;
+       }
+
+       fsg_opts = fsg_opts_from_func_inst(fi_msg);
+       ret = fsg_common_run_thread(fsg_opts->common);
+       if (ret)
+               goto err_run;
+
+       ret = usb_add_function(c, f_msg_rndis);
+       if (ret)
+               goto err_run;
+
+       return 0;
+err_run:
+       usb_put_function(f_msg_rndis);
+err_fsg:
+       usb_remove_function(c, f_acm_rndis);
+err_conf:
+       usb_put_function(f_acm_rndis);
+err_func_acm:
+       usb_remove_function(c, f_rndis);
+err_func_rndis:
+       usb_put_function(f_rndis);
+       return ret;
+}
+
+static __ref int rndis_config_register(struct usb_composite_dev *cdev)
+{
+       static struct usb_configuration config = {
+               .bConfigurationValue    = MULTI_RNDIS_CONFIG_NUM,
+               .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+       };
+
+       config.label          = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
+       config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
+
+       return usb_add_config(cdev, &config, rndis_do_config);
+}
+
+#else
+
+static __ref int rndis_config_register(struct usb_composite_dev *cdev)
+{
+       return 0;
+}
+
+#endif
+
+
+/********** CDC ECM **********/
+
+#ifdef CONFIG_USB_G_MULTI_CDC
+static struct usb_function_instance *fi_ecm;
+static struct usb_function *f_acm_multi;
+static struct usb_function *f_ecm;
+static struct usb_function *f_msg_multi;
+
+static __init int cdc_do_config(struct usb_configuration *c)
+{
+       struct fsg_opts *fsg_opts;
+       int ret;
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       f_ecm = usb_get_function(fi_ecm);
+       if (IS_ERR(f_ecm))
+               return PTR_ERR(f_ecm);
+
+       ret = usb_add_function(c, f_ecm);
+       if (ret < 0)
+               goto err_func_ecm;
+
+       /* implicit port_num is zero */
+       f_acm_multi = usb_get_function(fi_acm);
+       if (IS_ERR(f_acm_multi)) {
+               ret = PTR_ERR(f_acm_multi);
+               goto err_func_acm;
+       }
+
+       ret = usb_add_function(c, f_acm_multi);
+       if (ret)
+               goto err_conf;
+
+       f_msg_multi = usb_get_function(fi_msg);
+       if (IS_ERR(f_msg_multi)) {
+               ret = PTR_ERR(f_msg_multi);
+               goto err_fsg;
+       }
+
+       fsg_opts = fsg_opts_from_func_inst(fi_msg);
+       ret = fsg_common_run_thread(fsg_opts->common);
+       if (ret)
+               goto err_run;
+
+       ret = usb_add_function(c, f_msg_multi);
+       if (ret)
+               goto err_run;
+
+       return 0;
+err_run:
+       usb_put_function(f_msg_multi);
+err_fsg:
+       usb_remove_function(c, f_acm_multi);
+err_conf:
+       usb_put_function(f_acm_multi);
+err_func_acm:
+       usb_remove_function(c, f_ecm);
+err_func_ecm:
+       usb_put_function(f_ecm);
+       return ret;
+}
+
+static __ref int cdc_config_register(struct usb_composite_dev *cdev)
+{
+       static struct usb_configuration config = {
+               .bConfigurationValue    = MULTI_CDC_CONFIG_NUM,
+               .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+       };
+
+       config.label          = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
+       config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
+
+       return usb_add_config(cdev, &config, cdc_do_config);
+}
+
+#else
+
+static __ref int cdc_config_register(struct usb_composite_dev *cdev)
+{
+       return 0;
+}
+
+#endif
+
+
+
+/****************************** Gadget Bind ******************************/
+
+static int __ref multi_bind(struct usb_composite_dev *cdev)
+{
+       struct usb_gadget *gadget = cdev->gadget;
+#ifdef CONFIG_USB_G_MULTI_CDC
+       struct f_ecm_opts *ecm_opts;
+#endif
+#ifdef USB_ETH_RNDIS
+       struct f_rndis_opts *rndis_opts;
+#endif
+       struct fsg_opts *fsg_opts;
+       struct fsg_config config;
+       int status;
+
+       if (!can_support_ecm(cdev->gadget)) {
+               dev_err(&gadget->dev, "controller '%s' not usable\n",
+                       gadget->name);
+               return -EINVAL;
+       }
+
+#ifdef CONFIG_USB_G_MULTI_CDC
+       fi_ecm = usb_get_function_instance("ecm");
+       if (IS_ERR(fi_ecm))
+               return PTR_ERR(fi_ecm);
+
+       ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
+
+       gether_set_qmult(ecm_opts->net, qmult);
+       if (!gether_set_host_addr(ecm_opts->net, host_addr))
+               pr_info("using host ethernet address: %s", host_addr);
+       if (!gether_set_dev_addr(ecm_opts->net, dev_addr))
+               pr_info("using self ethernet address: %s", dev_addr);
+#endif
+
+#ifdef USB_ETH_RNDIS
+       fi_rndis = usb_get_function_instance("rndis");
+       if (IS_ERR(fi_rndis)) {
+               status = PTR_ERR(fi_rndis);
+               goto fail;
+       }
+
+       rndis_opts = container_of(fi_rndis, struct f_rndis_opts, func_inst);
+
+       gether_set_qmult(rndis_opts->net, qmult);
+       if (!gether_set_host_addr(rndis_opts->net, host_addr))
+               pr_info("using host ethernet address: %s", host_addr);
+       if (!gether_set_dev_addr(rndis_opts->net, dev_addr))
+               pr_info("using self ethernet address: %s", dev_addr);
+#endif
+
+#if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS)
+       /*
+        * If both ecm and rndis are selected then:
+        *      1) rndis borrows the net interface from ecm
+        *      2) since the interface is shared it must not be bound
+        *      twice - in ecm's _and_ rndis' binds, so do it here.
+        */
+       gether_set_gadget(ecm_opts->net, cdev->gadget);
+       status = gether_register_netdev(ecm_opts->net);
+       if (status)
+               goto fail0;
+
+       rndis_borrow_net(fi_rndis, ecm_opts->net);
+       ecm_opts->bound = true;
+#endif
+
+       /* set up serial link layer */
+       fi_acm = usb_get_function_instance("acm");
+       if (IS_ERR(fi_acm)) {
+               status = PTR_ERR(fi_acm);
+               goto fail0;
+       }
+
+       /* set up mass storage function */
+       fi_msg = usb_get_function_instance("mass_storage");
+       if (IS_ERR(fi_msg)) {
+               status = PTR_ERR(fi_msg);
+               goto fail1;
+       }
+       fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
+       fsg_opts = fsg_opts_from_func_inst(fi_msg);
+
+       fsg_opts->no_configfs = true;
+       status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers);
+       if (status)
+               goto fail2;
+
+       status = fsg_common_set_nluns(fsg_opts->common, config.nluns);
+       if (status)
+               goto fail_set_nluns;
+
+       status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall);
+       if (status)
+               goto fail_set_cdev;
+
+       fsg_common_set_sysfs(fsg_opts->common, true);
+       status = fsg_common_create_luns(fsg_opts->common, &config);
+       if (status)
+               goto fail_set_cdev;
+
+       fsg_common_set_inquiry_string(fsg_opts->common, config.vendor_name,
+                                     config.product_name);
+
+       /* allocate string IDs */
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (unlikely(status < 0))
+               goto fail_string_ids;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       /* register configurations */
+       status = rndis_config_register(cdev);
+       if (unlikely(status < 0))
+               goto fail_string_ids;
+
+       status = cdc_config_register(cdev);
+       if (unlikely(status < 0))
+               goto fail_string_ids;
+       usb_composite_overwrite_options(cdev, &coverwrite);
+
+       /* we're done */
+       dev_info(&gadget->dev, DRIVER_DESC "\n");
+       return 0;
+
+
+       /* error recovery */
+fail_string_ids:
+       fsg_common_remove_luns(fsg_opts->common);
+fail_set_cdev:
+       fsg_common_free_luns(fsg_opts->common);
+fail_set_nluns:
+       fsg_common_free_buffers(fsg_opts->common);
+fail2:
+       usb_put_function_instance(fi_msg);
+fail1:
+       usb_put_function_instance(fi_acm);
+fail0:
+#ifdef USB_ETH_RNDIS
+       usb_put_function_instance(fi_rndis);
+fail:
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+       usb_put_function_instance(fi_ecm);
+#endif
+       return status;
+}
+
+static int __exit multi_unbind(struct usb_composite_dev *cdev)
+{
+#ifdef CONFIG_USB_G_MULTI_CDC
+       usb_put_function(f_msg_multi);
+#endif
+#ifdef USB_ETH_RNDIS
+       usb_put_function(f_msg_rndis);
+#endif
+       usb_put_function_instance(fi_msg);
+#ifdef CONFIG_USB_G_MULTI_CDC
+       usb_put_function(f_acm_multi);
+#endif
+#ifdef USB_ETH_RNDIS
+       usb_put_function(f_acm_rndis);
+#endif
+       usb_put_function_instance(fi_acm);
+#ifdef USB_ETH_RNDIS
+       usb_put_function(f_rndis);
+       usb_put_function_instance(fi_rndis);
+#endif
+#ifdef CONFIG_USB_G_MULTI_CDC
+       usb_put_function(f_ecm);
+       usb_put_function_instance(fi_ecm);
+#endif
+       return 0;
+}
+
+
+/****************************** Some noise ******************************/
+
+
+static __refdata struct usb_composite_driver multi_driver = {
+       .name           = "g_multi",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = multi_bind,
+       .unbind         = __exit_p(multi_unbind),
+       .needs_serial   = 1,
+};
+
+module_usb_composite_driver(multi_driver);
diff --git a/drivers/usb/gadget/legacy/ncm.c b/drivers/usb/gadget/legacy/ncm.c
new file mode 100644 (file)
index 0000000..e90e23d
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * ncm.c -- NCM gadget driver
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Contact: Yauheni Kaliuta <yauheni.kaliuta@nokia.com>
+ *
+ * The driver borrows from ether.c which is:
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb/composite.h>
+
+#include "u_ether.h"
+#include "u_ncm.h"
+
+#define DRIVER_DESC            "NCM Gadget"
+
+/*-------------------------------------------------------------------------*/
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ * It's for devices with only CDC Ethernet configurations.
+ */
+#define CDC_VENDOR_NUM         0x0525  /* NetChip */
+#define CDC_PRODUCT_NUM                0xa4a1  /* Linux-USB Ethernet Gadget */
+
+/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
+
+USB_ETHERNET_MODULE_PARAMETERS();
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16 (0x0200),
+
+       .bDeviceClass =         USB_CLASS_COMM,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       /* .bMaxPacketSize0 = f(hardware) */
+
+       /* Vendor and product id defaults change according to what configs
+        * we support.  (As does bNumConfigurations.)  These values can
+        * also be overridden by module parameters.
+        */
+       .idVendor =             cpu_to_le16 (CDC_VENDOR_NUM),
+       .idProduct =            cpu_to_le16 (CDC_PRODUCT_NUM),
+       /* .bcdDevice = f(hardware) */
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       /* NO SERIAL NUMBER */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+/* string IDs are assigned dynamically */
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+static struct usb_function_instance *f_ncm_inst;
+static struct usb_function *f_ncm;
+
+/*-------------------------------------------------------------------------*/
+
+static int __init ncm_do_config(struct usb_configuration *c)
+{
+       int status;
+
+       /* FIXME alloc iConfiguration string, set it in c->strings */
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       f_ncm = usb_get_function(f_ncm_inst);
+       if (IS_ERR(f_ncm)) {
+               status = PTR_ERR(f_ncm);
+               return status;
+       }
+
+       status = usb_add_function(c, f_ncm);
+       if (status < 0) {
+               usb_put_function(f_ncm);
+               return status;
+       }
+
+       return 0;
+}
+
+static struct usb_configuration ncm_config_driver = {
+       /* .label = f(hardware) */
+       .label                  = "CDC Ethernet (NCM)",
+       .bConfigurationValue    = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init gncm_bind(struct usb_composite_dev *cdev)
+{
+       struct usb_gadget       *gadget = cdev->gadget;
+       struct f_ncm_opts       *ncm_opts;
+       int                     status;
+
+       f_ncm_inst = usb_get_function_instance("ncm");
+       if (IS_ERR(f_ncm_inst))
+               return PTR_ERR(f_ncm_inst);
+
+       ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst);
+
+       gether_set_qmult(ncm_opts->net, qmult);
+       if (!gether_set_host_addr(ncm_opts->net, host_addr))
+               pr_info("using host ethernet address: %s", host_addr);
+       if (!gether_set_dev_addr(ncm_opts->net, dev_addr))
+               pr_info("using self ethernet address: %s", dev_addr);
+
+       /* Allocate string descriptor numbers ... note that string
+        * contents can be overridden by the composite_dev glue.
+        */
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto fail;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+
+       status = usb_add_config(cdev, &ncm_config_driver,
+                               ncm_do_config);
+       if (status < 0)
+               goto fail;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
+
+       return 0;
+
+fail:
+       usb_put_function_instance(f_ncm_inst);
+       return status;
+}
+
+static int __exit gncm_unbind(struct usb_composite_dev *cdev)
+{
+       if (!IS_ERR_OR_NULL(f_ncm))
+               usb_put_function(f_ncm);
+       if (!IS_ERR_OR_NULL(f_ncm_inst))
+               usb_put_function_instance(f_ncm_inst);
+       return 0;
+}
+
+static __refdata struct usb_composite_driver ncm_driver = {
+       .name           = "g_ncm",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = gncm_bind,
+       .unbind         = __exit_p(gncm_unbind),
+};
+
+module_usb_composite_driver(ncm_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Yauheni Kaliuta");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c
new file mode 100644 (file)
index 0000000..9b8fd70
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * nokia.c -- Nokia Composite Gadget Driver
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This gadget driver borrows from serial.c which is:
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include "u_serial.h"
+#include "u_ether.h"
+#include "u_phonet.h"
+#include "u_ecm.h"
+#include "gadget_chips.h"
+
+/* Defines */
+
+#define NOKIA_VERSION_NUM              0x0211
+#define NOKIA_LONG_NAME                        "N900 (PC-Suite Mode)"
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+USB_ETHERNET_MODULE_PARAMETERS();
+
+#define NOKIA_VENDOR_ID                        0x0421  /* Nokia */
+#define NOKIA_PRODUCT_ID               0x01c8  /* Nokia Gadget */
+
+/* string IDs are assigned dynamically */
+
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
+
+static char manufacturer_nokia[] = "Nokia";
+static const char product_nokia[] = NOKIA_LONG_NAME;
+static const char description_nokia[] = "PC-Suite Configuration";
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia,
+       [USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       [STRING_DESCRIPTION_IDX].s = description_nokia,
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
+       .bLength                = USB_DT_DEVICE_SIZE,
+       .bDescriptorType        = USB_DT_DEVICE,
+       .bcdUSB                 = __constant_cpu_to_le16(0x0200),
+       .bDeviceClass           = USB_CLASS_COMM,
+       .idVendor               = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
+       .idProduct              = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
+       .bcdDevice              = cpu_to_le16(NOKIA_VERSION_NUM),
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       .bNumConfigurations =   1,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Module */
+MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------------*/
+static struct usb_function *f_acm_cfg1;
+static struct usb_function *f_acm_cfg2;
+static struct usb_function *f_ecm_cfg1;
+static struct usb_function *f_ecm_cfg2;
+static struct usb_function *f_obex1_cfg1;
+static struct usb_function *f_obex2_cfg1;
+static struct usb_function *f_obex1_cfg2;
+static struct usb_function *f_obex2_cfg2;
+static struct usb_function *f_phonet_cfg1;
+static struct usb_function *f_phonet_cfg2;
+
+
+static struct usb_configuration nokia_config_500ma_driver = {
+       .label          = "Bus Powered",
+       .bConfigurationValue = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes   = USB_CONFIG_ATT_ONE,
+       .MaxPower       = 500,
+};
+
+static struct usb_configuration nokia_config_100ma_driver = {
+       .label          = "Self Powered",
+       .bConfigurationValue = 2,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes   = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+       .MaxPower       = 100,
+};
+
+static struct usb_function_instance *fi_acm;
+static struct usb_function_instance *fi_ecm;
+static struct usb_function_instance *fi_obex1;
+static struct usb_function_instance *fi_obex2;
+static struct usb_function_instance *fi_phonet;
+
+static int __init nokia_bind_config(struct usb_configuration *c)
+{
+       struct usb_function *f_acm;
+       struct usb_function *f_phonet = NULL;
+       struct usb_function *f_obex1 = NULL;
+       struct usb_function *f_ecm;
+       struct usb_function *f_obex2 = NULL;
+       int status = 0;
+       int obex1_stat = -1;
+       int obex2_stat = -1;
+       int phonet_stat = -1;
+
+       if (!IS_ERR(fi_phonet)) {
+               f_phonet = usb_get_function(fi_phonet);
+               if (IS_ERR(f_phonet))
+                       pr_debug("could not get phonet function\n");
+       }
+
+       if (!IS_ERR(fi_obex1)) {
+               f_obex1 = usb_get_function(fi_obex1);
+               if (IS_ERR(f_obex1))
+                       pr_debug("could not get obex function 0\n");
+       }
+
+       if (!IS_ERR(fi_obex2)) {
+               f_obex2 = usb_get_function(fi_obex2);
+               if (IS_ERR(f_obex2))
+                       pr_debug("could not get obex function 1\n");
+       }
+
+       f_acm = usb_get_function(fi_acm);
+       if (IS_ERR(f_acm)) {
+               status = PTR_ERR(f_acm);
+               goto err_get_acm;
+       }
+
+       f_ecm = usb_get_function(fi_ecm);
+       if (IS_ERR(f_ecm)) {
+               status = PTR_ERR(f_ecm);
+               goto err_get_ecm;
+       }
+
+       if (!IS_ERR_OR_NULL(f_phonet)) {
+               phonet_stat = usb_add_function(c, f_phonet);
+               if (phonet_stat)
+                       pr_debug("could not add phonet function\n");
+       }
+
+       if (!IS_ERR_OR_NULL(f_obex1)) {
+               obex1_stat = usb_add_function(c, f_obex1);
+               if (obex1_stat)
+                       pr_debug("could not add obex function 0\n");
+       }
+
+       if (!IS_ERR_OR_NULL(f_obex2)) {
+               obex2_stat = usb_add_function(c, f_obex2);
+               if (obex2_stat)
+                       pr_debug("could not add obex function 1\n");
+       }
+
+       status = usb_add_function(c, f_acm);
+       if (status)
+               goto err_conf;
+
+       status = usb_add_function(c, f_ecm);
+       if (status) {
+               pr_debug("could not bind ecm config %d\n", status);
+               goto err_ecm;
+       }
+       if (c == &nokia_config_500ma_driver) {
+               f_acm_cfg1 = f_acm;
+               f_ecm_cfg1 = f_ecm;
+               f_phonet_cfg1 = f_phonet;
+               f_obex1_cfg1 = f_obex1;
+               f_obex2_cfg1 = f_obex2;
+       } else {
+               f_acm_cfg2 = f_acm;
+               f_ecm_cfg2 = f_ecm;
+               f_phonet_cfg2 = f_phonet;
+               f_obex1_cfg2 = f_obex1;
+               f_obex2_cfg2 = f_obex2;
+       }
+
+       return status;
+err_ecm:
+       usb_remove_function(c, f_acm);
+err_conf:
+       if (!obex2_stat)
+               usb_remove_function(c, f_obex2);
+       if (!obex1_stat)
+               usb_remove_function(c, f_obex1);
+       if (!phonet_stat)
+               usb_remove_function(c, f_phonet);
+       usb_put_function(f_ecm);
+err_get_ecm:
+       usb_put_function(f_acm);
+err_get_acm:
+       if (!IS_ERR_OR_NULL(f_obex2))
+               usb_put_function(f_obex2);
+       if (!IS_ERR_OR_NULL(f_obex1))
+               usb_put_function(f_obex1);
+       if (!IS_ERR_OR_NULL(f_phonet))
+               usb_put_function(f_phonet);
+       return status;
+}
+
+static int __init nokia_bind(struct usb_composite_dev *cdev)
+{
+       struct usb_gadget       *gadget = cdev->gadget;
+       int                     status;
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto err_usb;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       status = strings_dev[STRING_DESCRIPTION_IDX].id;
+       nokia_config_500ma_driver.iConfiguration = status;
+       nokia_config_100ma_driver.iConfiguration = status;
+
+       if (!gadget_supports_altsettings(gadget)) {
+               status = -ENODEV;
+               goto err_usb;
+       }
+
+       fi_phonet = usb_get_function_instance("phonet");
+       if (IS_ERR(fi_phonet))
+               pr_debug("could not find phonet function\n");
+
+       fi_obex1 = usb_get_function_instance("obex");
+       if (IS_ERR(fi_obex1))
+               pr_debug("could not find obex function 1\n");
+
+       fi_obex2 = usb_get_function_instance("obex");
+       if (IS_ERR(fi_obex2))
+               pr_debug("could not find obex function 2\n");
+
+       fi_acm = usb_get_function_instance("acm");
+       if (IS_ERR(fi_acm)) {
+               status = PTR_ERR(fi_acm);
+               goto err_obex2_inst;
+       }
+
+       fi_ecm = usb_get_function_instance("ecm");
+       if (IS_ERR(fi_ecm)) {
+               status = PTR_ERR(fi_ecm);
+               goto err_acm_inst;
+       }
+
+       /* finally register the configuration */
+       status = usb_add_config(cdev, &nokia_config_500ma_driver,
+                       nokia_bind_config);
+       if (status < 0)
+               goto err_ecm_inst;
+
+       status = usb_add_config(cdev, &nokia_config_100ma_driver,
+                       nokia_bind_config);
+       if (status < 0)
+               goto err_put_cfg1;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
+
+       return 0;
+
+err_put_cfg1:
+       usb_put_function(f_acm_cfg1);
+       if (!IS_ERR_OR_NULL(f_obex1_cfg1))
+               usb_put_function(f_obex1_cfg1);
+       if (!IS_ERR_OR_NULL(f_obex2_cfg1))
+               usb_put_function(f_obex2_cfg1);
+       if (!IS_ERR_OR_NULL(f_phonet_cfg1))
+               usb_put_function(f_phonet_cfg1);
+       usb_put_function(f_ecm_cfg1);
+err_ecm_inst:
+       usb_put_function_instance(fi_ecm);
+err_acm_inst:
+       usb_put_function_instance(fi_acm);
+err_obex2_inst:
+       if (!IS_ERR(fi_obex2))
+               usb_put_function_instance(fi_obex2);
+       if (!IS_ERR(fi_obex1))
+               usb_put_function_instance(fi_obex1);
+       if (!IS_ERR(fi_phonet))
+               usb_put_function_instance(fi_phonet);
+err_usb:
+       return status;
+}
+
+static int __exit nokia_unbind(struct usb_composite_dev *cdev)
+{
+       if (!IS_ERR_OR_NULL(f_obex1_cfg2))
+               usb_put_function(f_obex1_cfg2);
+       if (!IS_ERR_OR_NULL(f_obex2_cfg2))
+               usb_put_function(f_obex2_cfg2);
+       if (!IS_ERR_OR_NULL(f_obex1_cfg1))
+               usb_put_function(f_obex1_cfg1);
+       if (!IS_ERR_OR_NULL(f_obex2_cfg1))
+               usb_put_function(f_obex2_cfg1);
+       if (!IS_ERR_OR_NULL(f_phonet_cfg1))
+               usb_put_function(f_phonet_cfg1);
+       if (!IS_ERR_OR_NULL(f_phonet_cfg2))
+               usb_put_function(f_phonet_cfg2);
+       usb_put_function(f_acm_cfg1);
+       usb_put_function(f_acm_cfg2);
+       usb_put_function(f_ecm_cfg1);
+       usb_put_function(f_ecm_cfg2);
+
+       usb_put_function_instance(fi_ecm);
+       if (!IS_ERR(fi_obex2))
+               usb_put_function_instance(fi_obex2);
+       if (!IS_ERR(fi_obex1))
+               usb_put_function_instance(fi_obex1);
+       if (!IS_ERR(fi_phonet))
+               usb_put_function_instance(fi_phonet);
+       usb_put_function_instance(fi_acm);
+
+       return 0;
+}
+
+static __refdata struct usb_composite_driver nokia_driver = {
+       .name           = "g_nokia",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = nokia_bind,
+       .unbind         = __exit_p(nokia_unbind),
+};
+
+module_usb_composite_driver(nokia_driver);
diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c
new file mode 100644 (file)
index 0000000..6474081
--- /dev/null
@@ -0,0 +1,1305 @@
+/*
+ * printer.c -- Printer gadget driver
+ *
+ * Copyright (C) 2003-2005 David Brownell
+ * Copyright (C) 2006 Craig W. Nadler
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/cdev.h>
+
+#include <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/g_printer.h>
+
+#include "gadget_chips.h"
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+#define DRIVER_DESC            "Printer Gadget"
+#define DRIVER_VERSION         "2007 OCT 06"
+
+static DEFINE_MUTEX(printer_mutex);
+static const char shortname [] = "printer";
+static const char driver_desc [] = DRIVER_DESC;
+
+static dev_t g_printer_devno;
+
+static struct class *usb_gadget_class;
+
+/*-------------------------------------------------------------------------*/
+
+struct printer_dev {
+       spinlock_t              lock;           /* lock this structure */
+       /* lock buffer lists during read/write calls */
+       struct mutex            lock_printer_io;
+       struct usb_gadget       *gadget;
+       s8                      interface;
+       struct usb_ep           *in_ep, *out_ep;
+
+       struct list_head        rx_reqs;        /* List of free RX structs */
+       struct list_head        rx_reqs_active; /* List of Active RX xfers */
+       struct list_head        rx_buffers;     /* List of completed xfers */
+       /* wait until there is data to be read. */
+       wait_queue_head_t       rx_wait;
+       struct list_head        tx_reqs;        /* List of free TX structs */
+       struct list_head        tx_reqs_active; /* List of Active TX xfers */
+       /* Wait until there are write buffers available to use. */
+       wait_queue_head_t       tx_wait;
+       /* Wait until all write buffers have been sent. */
+       wait_queue_head_t       tx_flush_wait;
+       struct usb_request      *current_rx_req;
+       size_t                  current_rx_bytes;
+       u8                      *current_rx_buf;
+       u8                      printer_status;
+       u8                      reset_printer;
+       struct cdev             printer_cdev;
+       struct device           *pdev;
+       u8                      printer_cdev_open;
+       wait_queue_head_t       wait;
+       struct usb_function     function;
+};
+
+static struct printer_dev usb_printer_gadget;
+
+/*-------------------------------------------------------------------------*/
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ */
+#define PRINTER_VENDOR_NUM     0x0525          /* NetChip */
+#define PRINTER_PRODUCT_NUM    0xa4a8          /* Linux-USB Printer Gadget */
+
+/* Some systems will want different product identifiers published in the
+ * device descriptor, either numbers or strings or both.  These string
+ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNum, "1");
+
+static char *iPNPstring;
+module_param(iPNPstring, charp, S_IRUGO);
+MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
+
+/* Number of requests to allocate per endpoint, not used for ep0. */
+static unsigned qlen = 10;
+module_param(qlen, uint, S_IRUGO|S_IWUSR);
+
+#define QLEN   qlen
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand.
+ */
+
+/* holds our biggest descriptor */
+#define USB_DESC_BUFSIZE               256
+#define USB_BUFSIZE                    8192
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+       .bcdUSB =               cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       .idVendor =             cpu_to_le16(PRINTER_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(PRINTER_PRODUCT_NUM),
+       .bNumConfigurations =   1
+};
+
+static struct usb_interface_descriptor intf_desc = {
+       .bLength =              sizeof intf_desc,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bNumEndpoints =        2,
+       .bInterfaceClass =      USB_CLASS_PRINTER,
+       .bInterfaceSubClass =   1,      /* Printer Sub-Class */
+       .bInterfaceProtocol =   2,      /* Bi-Directional */
+       .iInterface =           0
+};
+
+static struct usb_endpoint_descriptor fs_ep_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK
+};
+
+static struct usb_endpoint_descriptor fs_ep_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK
+};
+
+static struct usb_descriptor_header *fs_printer_function[] = {
+       (struct usb_descriptor_header *) &intf_desc,
+       (struct usb_descriptor_header *) &fs_ep_in_desc,
+       (struct usb_descriptor_header *) &fs_ep_out_desc,
+       NULL
+};
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ */
+
+static struct usb_endpoint_descriptor hs_ep_in_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512)
+};
+
+static struct usb_endpoint_descriptor hs_ep_out_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512)
+};
+
+static struct usb_qualifier_descriptor dev_qualifier = {
+       .bLength =              sizeof dev_qualifier,
+       .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
+       .bcdUSB =               cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_PRINTER,
+       .bNumConfigurations =   1
+};
+
+static struct usb_descriptor_header *hs_printer_function[] = {
+       (struct usb_descriptor_header *) &intf_desc,
+       (struct usb_descriptor_header *) &hs_ep_in_desc,
+       (struct usb_descriptor_header *) &hs_ep_out_desc,
+       NULL
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+       .bmAttributes =         USB_OTG_SRP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
+
+/*-------------------------------------------------------------------------*/
+
+/* descriptors that are built on-demand */
+
+static char                            product_desc [40] = DRIVER_DESC;
+static char                            serial_num [40] = "1";
+static char                            pnp_string [1024] =
+       "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;";
+
+/* static strings, in UTF-8 */
+static struct usb_string               strings [] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = product_desc,
+       [USB_GADGET_SERIAL_IDX].s =     serial_num,
+       {  }            /* end of list */
+};
+
+static struct usb_gadget_strings       stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
+{
+       struct usb_request      *req;
+
+       req = usb_ep_alloc_request(ep, gfp_flags);
+
+       if (req != NULL) {
+               req->length = len;
+               req->buf = kmalloc(len, gfp_flags);
+               if (req->buf == NULL) {
+                       usb_ep_free_request(ep, req);
+                       return NULL;
+               }
+       }
+
+       return req;
+}
+
+static void
+printer_req_free(struct usb_ep *ep, struct usb_request *req)
+{
+       if (ep != NULL && req != NULL) {
+               kfree(req->buf);
+               usb_ep_free_request(ep, req);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct printer_dev      *dev = ep->driver_data;
+       int                     status = req->status;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       list_del_init(&req->list);      /* Remode from Active List */
+
+       switch (status) {
+
+       /* normal completion */
+       case 0:
+               if (req->actual > 0) {
+                       list_add_tail(&req->list, &dev->rx_buffers);
+                       DBG(dev, "G_Printer : rx length %d\n", req->actual);
+               } else {
+                       list_add(&req->list, &dev->rx_reqs);
+               }
+               break;
+
+       /* software-driven interface shutdown */
+       case -ECONNRESET:               /* unlink */
+       case -ESHUTDOWN:                /* disconnect etc */
+               VDBG(dev, "rx shutdown, code %d\n", status);
+               list_add(&req->list, &dev->rx_reqs);
+               break;
+
+       /* for hardware automagic (such as pxa) */
+       case -ECONNABORTED:             /* endpoint reset */
+               DBG(dev, "rx %s reset\n", ep->name);
+               list_add(&req->list, &dev->rx_reqs);
+               break;
+
+       /* data overrun */
+       case -EOVERFLOW:
+               /* FALLTHROUGH */
+
+       default:
+               DBG(dev, "rx status %d\n", status);
+               list_add(&req->list, &dev->rx_reqs);
+               break;
+       }
+
+       wake_up_interruptible(&dev->rx_wait);
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void tx_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct printer_dev      *dev = ep->driver_data;
+
+       switch (req->status) {
+       default:
+               VDBG(dev, "tx err %d\n", req->status);
+               /* FALLTHROUGH */
+       case -ECONNRESET:               /* unlink */
+       case -ESHUTDOWN:                /* disconnect etc */
+               break;
+       case 0:
+               break;
+       }
+
+       spin_lock(&dev->lock);
+       /* Take the request struct off the active list and put it on the
+        * free list.
+        */
+       list_del_init(&req->list);
+       list_add(&req->list, &dev->tx_reqs);
+       wake_up_interruptible(&dev->tx_wait);
+       if (likely(list_empty(&dev->tx_reqs_active)))
+               wake_up_interruptible(&dev->tx_flush_wait);
+
+       spin_unlock(&dev->lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+printer_open(struct inode *inode, struct file *fd)
+{
+       struct printer_dev      *dev;
+       unsigned long           flags;
+       int                     ret = -EBUSY;
+
+       mutex_lock(&printer_mutex);
+       dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       if (!dev->printer_cdev_open) {
+               dev->printer_cdev_open = 1;
+               fd->private_data = dev;
+               ret = 0;
+               /* Change the printer status to show that it's on-line. */
+               dev->printer_status |= PRINTER_SELECTED;
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       DBG(dev, "printer_open returned %x\n", ret);
+       mutex_unlock(&printer_mutex);
+       return ret;
+}
+
+static int
+printer_close(struct inode *inode, struct file *fd)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->printer_cdev_open = 0;
+       fd->private_data = NULL;
+       /* Change printer status to show that the printer is off-line. */
+       dev->printer_status &= ~PRINTER_SELECTED;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       DBG(dev, "printer_close\n");
+
+       return 0;
+}
+
+/* This function must be called with interrupts turned off. */
+static void
+setup_rx_reqs(struct printer_dev *dev)
+{
+       struct usb_request              *req;
+
+       while (likely(!list_empty(&dev->rx_reqs))) {
+               int error;
+
+               req = container_of(dev->rx_reqs.next,
+                               struct usb_request, list);
+               list_del_init(&req->list);
+
+               /* The USB Host sends us whatever amount of data it wants to
+                * so we always set the length field to the full USB_BUFSIZE.
+                * If the amount of data is more than the read() caller asked
+                * for it will be stored in the request buffer until it is
+                * asked for by read().
+                */
+               req->length = USB_BUFSIZE;
+               req->complete = rx_complete;
+
+               /* here, we unlock, and only unlock, to avoid deadlock. */
+               spin_unlock(&dev->lock);
+               error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
+               spin_lock(&dev->lock);
+               if (error) {
+                       DBG(dev, "rx submit --> %d\n", error);
+                       list_add(&req->list, &dev->rx_reqs);
+                       break;
+               }
+               /* if the req is empty, then add it into dev->rx_reqs_active. */
+               else if (list_empty(&req->list)) {
+                       list_add(&req->list, &dev->rx_reqs_active);
+               }
+       }
+}
+
+static ssize_t
+printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+{
+       struct printer_dev              *dev = fd->private_data;
+       unsigned long                   flags;
+       size_t                          size;
+       size_t                          bytes_copied;
+       struct usb_request              *req;
+       /* This is a pointer to the current USB rx request. */
+       struct usb_request              *current_rx_req;
+       /* This is the number of bytes in the current rx buffer. */
+       size_t                          current_rx_bytes;
+       /* This is a pointer to the current rx buffer. */
+       u8                              *current_rx_buf;
+
+       if (len == 0)
+               return -EINVAL;
+
+       DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
+
+       mutex_lock(&dev->lock_printer_io);
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* We will use this flag later to check if a printer reset happened
+        * after we turn interrupts back on.
+        */
+       dev->reset_printer = 0;
+
+       setup_rx_reqs(dev);
+
+       bytes_copied = 0;
+       current_rx_req = dev->current_rx_req;
+       current_rx_bytes = dev->current_rx_bytes;
+       current_rx_buf = dev->current_rx_buf;
+       dev->current_rx_req = NULL;
+       dev->current_rx_bytes = 0;
+       dev->current_rx_buf = NULL;
+
+       /* Check if there is any data in the read buffers. Please note that
+        * current_rx_bytes is the number of bytes in the current rx buffer.
+        * If it is zero then check if there are any other rx_buffers that
+        * are on the completed list. We are only out of data if all rx
+        * buffers are empty.
+        */
+       if ((current_rx_bytes == 0) &&
+                       (likely(list_empty(&dev->rx_buffers)))) {
+               /* Turn interrupts back on before sleeping. */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               /*
+                * If no data is available check if this is a NON-Blocking
+                * call or not.
+                */
+               if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
+                       mutex_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               /* Sleep until data is available */
+               wait_event_interruptible(dev->rx_wait,
+                               (likely(!list_empty(&dev->rx_buffers))));
+               spin_lock_irqsave(&dev->lock, flags);
+       }
+
+       /* We have data to return then copy it to the caller's buffer.*/
+       while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers)))
+                       && len) {
+               if (current_rx_bytes == 0) {
+                       req = container_of(dev->rx_buffers.next,
+                                       struct usb_request, list);
+                       list_del_init(&req->list);
+
+                       if (req->actual && req->buf) {
+                               current_rx_req = req;
+                               current_rx_bytes = req->actual;
+                               current_rx_buf = req->buf;
+                       } else {
+                               list_add(&req->list, &dev->rx_reqs);
+                               continue;
+                       }
+               }
+
+               /* Don't leave irqs off while doing memory copies */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               if (len > current_rx_bytes)
+                       size = current_rx_bytes;
+               else
+                       size = len;
+
+               size -= copy_to_user(buf, current_rx_buf, size);
+               bytes_copied += size;
+               len -= size;
+               buf += size;
+
+               spin_lock_irqsave(&dev->lock, flags);
+
+               /* We've disconnected or reset so return. */
+               if (dev->reset_printer) {
+                       list_add(&current_rx_req->list, &dev->rx_reqs);
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       mutex_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               /* If we not returning all the data left in this RX request
+                * buffer then adjust the amount of data left in the buffer.
+                * Othewise if we are done with this RX request buffer then
+                * requeue it to get any incoming data from the USB host.
+                */
+               if (size < current_rx_bytes) {
+                       current_rx_bytes -= size;
+                       current_rx_buf += size;
+               } else {
+                       list_add(&current_rx_req->list, &dev->rx_reqs);
+                       current_rx_bytes = 0;
+                       current_rx_buf = NULL;
+                       current_rx_req = NULL;
+               }
+       }
+
+       dev->current_rx_req = current_rx_req;
+       dev->current_rx_bytes = current_rx_bytes;
+       dev->current_rx_buf = current_rx_buf;
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->lock_printer_io);
+
+       DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied);
+
+       if (bytes_copied)
+               return bytes_copied;
+       else
+               return -EAGAIN;
+}
+
+static ssize_t
+printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+       size_t                  size;   /* Amount of data in a TX request. */
+       size_t                  bytes_copied = 0;
+       struct usb_request      *req;
+
+       DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
+
+       if (len == 0)
+               return -EINVAL;
+
+       mutex_lock(&dev->lock_printer_io);
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* Check if a printer reset happens while we have interrupts on */
+       dev->reset_printer = 0;
+
+       /* Check if there is any available write buffers */
+       if (likely(list_empty(&dev->tx_reqs))) {
+               /* Turn interrupts back on before sleeping. */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               /*
+                * If write buffers are available check if this is
+                * a NON-Blocking call or not.
+                */
+               if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
+                       mutex_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               /* Sleep until a write buffer is available */
+               wait_event_interruptible(dev->tx_wait,
+                               (likely(!list_empty(&dev->tx_reqs))));
+               spin_lock_irqsave(&dev->lock, flags);
+       }
+
+       while (likely(!list_empty(&dev->tx_reqs)) && len) {
+
+               if (len > USB_BUFSIZE)
+                       size = USB_BUFSIZE;
+               else
+                       size = len;
+
+               req = container_of(dev->tx_reqs.next, struct usb_request,
+                               list);
+               list_del_init(&req->list);
+
+               req->complete = tx_complete;
+               req->length = size;
+
+               /* Check if we need to send a zero length packet. */
+               if (len > size)
+                       /* They will be more TX requests so no yet. */
+                       req->zero = 0;
+               else
+                       /* If the data amount is not a multple of the
+                        * maxpacket size then send a zero length packet.
+                        */
+                       req->zero = ((len % dev->in_ep->maxpacket) == 0);
+
+               /* Don't leave irqs off while doing memory copies */
+               spin_unlock_irqrestore(&dev->lock, flags);
+
+               if (copy_from_user(req->buf, buf, size)) {
+                       list_add(&req->list, &dev->tx_reqs);
+                       mutex_unlock(&dev->lock_printer_io);
+                       return bytes_copied;
+               }
+
+               bytes_copied += size;
+               len -= size;
+               buf += size;
+
+               spin_lock_irqsave(&dev->lock, flags);
+
+               /* We've disconnected or reset so free the req and buffer */
+               if (dev->reset_printer) {
+                       list_add(&req->list, &dev->tx_reqs);
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       mutex_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
+                       list_add(&req->list, &dev->tx_reqs);
+                       spin_unlock_irqrestore(&dev->lock, flags);
+                       mutex_unlock(&dev->lock_printer_io);
+                       return -EAGAIN;
+               }
+
+               list_add(&req->list, &dev->tx_reqs_active);
+
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->lock_printer_io);
+
+       DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied);
+
+       if (bytes_copied) {
+               return bytes_copied;
+       } else {
+               return -EAGAIN;
+       }
+}
+
+static int
+printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync)
+{
+       struct printer_dev      *dev = fd->private_data;
+       struct inode *inode = file_inode(fd);
+       unsigned long           flags;
+       int                     tx_list_empty;
+
+       mutex_lock(&inode->i_mutex);
+       spin_lock_irqsave(&dev->lock, flags);
+       tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (!tx_list_empty) {
+               /* Sleep until all data has been sent */
+               wait_event_interruptible(dev->tx_flush_wait,
+                               (likely(list_empty(&dev->tx_reqs_active))));
+       }
+       mutex_unlock(&inode->i_mutex);
+
+       return 0;
+}
+
+static unsigned int
+printer_poll(struct file *fd, poll_table *wait)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+       int                     status = 0;
+
+       mutex_lock(&dev->lock_printer_io);
+       spin_lock_irqsave(&dev->lock, flags);
+       setup_rx_reqs(dev);
+       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->lock_printer_io);
+
+       poll_wait(fd, &dev->rx_wait, wait);
+       poll_wait(fd, &dev->tx_wait, wait);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (likely(!list_empty(&dev->tx_reqs)))
+               status |= POLLOUT | POLLWRNORM;
+
+       if (likely(dev->current_rx_bytes) ||
+                       likely(!list_empty(&dev->rx_buffers)))
+               status |= POLLIN | POLLRDNORM;
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return status;
+}
+
+static long
+printer_ioctl(struct file *fd, unsigned int code, unsigned long arg)
+{
+       struct printer_dev      *dev = fd->private_data;
+       unsigned long           flags;
+       int                     status = 0;
+
+       DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
+
+       /* handle ioctls */
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       switch (code) {
+       case GADGET_GET_PRINTER_STATUS:
+               status = (int)dev->printer_status;
+               break;
+       case GADGET_SET_PRINTER_STATUS:
+               dev->printer_status = (u8)arg;
+               break;
+       default:
+               /* could not handle ioctl */
+               DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n",
+                               code);
+               status = -ENOTTY;
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       return status;
+}
+
+/* used after endpoint configuration */
+static const struct file_operations printer_io_operations = {
+       .owner =        THIS_MODULE,
+       .open =         printer_open,
+       .read =         printer_read,
+       .write =        printer_write,
+       .fsync =        printer_fsync,
+       .poll =         printer_poll,
+       .unlocked_ioctl = printer_ioctl,
+       .release =      printer_close,
+       .llseek =       noop_llseek,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int
+set_printer_interface(struct printer_dev *dev)
+{
+       int                     result = 0;
+
+       dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+       dev->in_ep->driver_data = dev;
+
+       dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
+                                   &fs_ep_out_desc);
+       dev->out_ep->driver_data = dev;
+
+       result = usb_ep_enable(dev->in_ep);
+       if (result != 0) {
+               DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
+               goto done;
+       }
+
+       result = usb_ep_enable(dev->out_ep);
+       if (result != 0) {
+               DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
+               goto done;
+       }
+
+done:
+       /* on error, disable any endpoints  */
+       if (result != 0) {
+               (void) usb_ep_disable(dev->in_ep);
+               (void) usb_ep_disable(dev->out_ep);
+               dev->in_ep->desc = NULL;
+               dev->out_ep->desc = NULL;
+       }
+
+       /* caller is responsible for cleanup on error */
+       return result;
+}
+
+static void printer_reset_interface(struct printer_dev *dev)
+{
+       if (dev->interface < 0)
+               return;
+
+       DBG(dev, "%s\n", __func__);
+
+       if (dev->in_ep->desc)
+               usb_ep_disable(dev->in_ep);
+
+       if (dev->out_ep->desc)
+               usb_ep_disable(dev->out_ep);
+
+       dev->in_ep->desc = NULL;
+       dev->out_ep->desc = NULL;
+       dev->interface = -1;
+}
+
+/* Change our operational Interface. */
+static int set_interface(struct printer_dev *dev, unsigned number)
+{
+       int                     result = 0;
+
+       /* Free the current interface */
+       printer_reset_interface(dev);
+
+       result = set_printer_interface(dev);
+       if (result)
+               printer_reset_interface(dev);
+       else
+               dev->interface = number;
+
+       if (!result)
+               INFO(dev, "Using interface %x\n", number);
+
+       return result;
+}
+
+static void printer_soft_reset(struct printer_dev *dev)
+{
+       struct usb_request      *req;
+
+       INFO(dev, "Received Printer Reset Request\n");
+
+       if (usb_ep_disable(dev->in_ep))
+               DBG(dev, "Failed to disable USB in_ep\n");
+       if (usb_ep_disable(dev->out_ep))
+               DBG(dev, "Failed to disable USB out_ep\n");
+
+       if (dev->current_rx_req != NULL) {
+               list_add(&dev->current_rx_req->list, &dev->rx_reqs);
+               dev->current_rx_req = NULL;
+       }
+       dev->current_rx_bytes = 0;
+       dev->current_rx_buf = NULL;
+       dev->reset_printer = 1;
+
+       while (likely(!(list_empty(&dev->rx_buffers)))) {
+               req = container_of(dev->rx_buffers.next, struct usb_request,
+                               list);
+               list_del_init(&req->list);
+               list_add(&req->list, &dev->rx_reqs);
+       }
+
+       while (likely(!(list_empty(&dev->rx_reqs_active)))) {
+               req = container_of(dev->rx_buffers.next, struct usb_request,
+                               list);
+               list_del_init(&req->list);
+               list_add(&req->list, &dev->rx_reqs);
+       }
+
+       while (likely(!(list_empty(&dev->tx_reqs_active)))) {
+               req = container_of(dev->tx_reqs_active.next,
+                               struct usb_request, list);
+               list_del_init(&req->list);
+               list_add(&req->list, &dev->tx_reqs);
+       }
+
+       if (usb_ep_enable(dev->in_ep))
+               DBG(dev, "Failed to enable USB in_ep\n");
+       if (usb_ep_enable(dev->out_ep))
+               DBG(dev, "Failed to enable USB out_ep\n");
+
+       wake_up_interruptible(&dev->rx_wait);
+       wake_up_interruptible(&dev->tx_wait);
+       wake_up_interruptible(&dev->tx_flush_wait);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * The setup() callback implements all the ep0 functionality that's not
+ * handled lower down.
+ */
+static int printer_func_setup(struct usb_function *f,
+               const struct usb_ctrlrequest *ctrl)
+{
+       struct printer_dev *dev = container_of(f, struct printer_dev, function);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       struct usb_request      *req = cdev->req;
+       int                     value = -EOPNOTSUPP;
+       u16                     wIndex = le16_to_cpu(ctrl->wIndex);
+       u16                     wValue = le16_to_cpu(ctrl->wValue);
+       u16                     wLength = le16_to_cpu(ctrl->wLength);
+
+       DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
+               ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
+
+       switch (ctrl->bRequestType&USB_TYPE_MASK) {
+       case USB_TYPE_CLASS:
+               switch (ctrl->bRequest) {
+               case 0: /* Get the IEEE-1284 PNP String */
+                       /* Only one printer interface is supported. */
+                       if ((wIndex>>8) != dev->interface)
+                               break;
+
+                       value = (pnp_string[0]<<8)|pnp_string[1];
+                       memcpy(req->buf, pnp_string, value);
+                       DBG(dev, "1284 PNP String: %x %s\n", value,
+                                       &pnp_string[2]);
+                       break;
+
+               case 1: /* Get Port Status */
+                       /* Only one printer interface is supported. */
+                       if (wIndex != dev->interface)
+                               break;
+
+                       *(u8 *)req->buf = dev->printer_status;
+                       value = min(wLength, (u16) 1);
+                       break;
+
+               case 2: /* Soft Reset */
+                       /* Only one printer interface is supported. */
+                       if (wIndex != dev->interface)
+                               break;
+
+                       printer_soft_reset(dev);
+
+                       value = 0;
+                       break;
+
+               default:
+                       goto unknown;
+               }
+               break;
+
+       default:
+unknown:
+               VDBG(dev,
+                       "unknown ctrl req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       wValue, wIndex, wLength);
+               break;
+       }
+       /* host either stalls (value < 0) or reports success */
+       return value;
+}
+
+static int __init printer_func_bind(struct usb_configuration *c,
+               struct usb_function *f)
+{
+       struct printer_dev *dev = container_of(f, struct printer_dev, function);
+       struct usb_composite_dev *cdev = c->cdev;
+       struct usb_ep *in_ep;
+       struct usb_ep *out_ep = NULL;
+       int id;
+       int ret;
+
+       id = usb_interface_id(c, f);
+       if (id < 0)
+               return id;
+       intf_desc.bInterfaceNumber = id;
+
+       /* all we really need is bulk IN/OUT */
+       in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc);
+       if (!in_ep) {
+autoconf_fail:
+               dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n",
+                       cdev->gadget->name);
+               return -ENODEV;
+       }
+       in_ep->driver_data = in_ep;     /* claim */
+
+       out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
+       if (!out_ep)
+               goto autoconf_fail;
+       out_ep->driver_data = out_ep;   /* claim */
+
+       /* assumes that all endpoints are dual-speed */
+       hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
+       hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
+
+       ret = usb_assign_descriptors(f, fs_printer_function,
+                       hs_printer_function, NULL);
+       if (ret)
+               return ret;
+
+       dev->in_ep = in_ep;
+       dev->out_ep = out_ep;
+       return 0;
+}
+
+static void printer_func_unbind(struct usb_configuration *c,
+               struct usb_function *f)
+{
+       usb_free_all_descriptors(f);
+}
+
+static int printer_func_set_alt(struct usb_function *f,
+               unsigned intf, unsigned alt)
+{
+       struct printer_dev *dev = container_of(f, struct printer_dev, function);
+       int ret = -ENOTSUPP;
+
+       if (!alt)
+               ret = set_interface(dev, intf);
+
+       return ret;
+}
+
+static void printer_func_disable(struct usb_function *f)
+{
+       struct printer_dev *dev = container_of(f, struct printer_dev, function);
+       unsigned long           flags;
+
+       DBG(dev, "%s\n", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       printer_reset_interface(dev);
+       spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void printer_cfg_unbind(struct usb_configuration *c)
+{
+       struct printer_dev      *dev;
+       struct usb_request      *req;
+
+       dev = &usb_printer_gadget;
+
+       DBG(dev, "%s\n", __func__);
+
+       /* Remove sysfs files */
+       device_destroy(usb_gadget_class, g_printer_devno);
+
+       /* Remove Character Device */
+       cdev_del(&dev->printer_cdev);
+
+       /* we must already have been disconnected ... no i/o may be active */
+       WARN_ON(!list_empty(&dev->tx_reqs_active));
+       WARN_ON(!list_empty(&dev->rx_reqs_active));
+
+       /* Free all memory for this driver. */
+       while (!list_empty(&dev->tx_reqs)) {
+               req = container_of(dev->tx_reqs.next, struct usb_request,
+                               list);
+               list_del(&req->list);
+               printer_req_free(dev->in_ep, req);
+       }
+
+       if (dev->current_rx_req != NULL)
+               printer_req_free(dev->out_ep, dev->current_rx_req);
+
+       while (!list_empty(&dev->rx_reqs)) {
+               req = container_of(dev->rx_reqs.next,
+                               struct usb_request, list);
+               list_del(&req->list);
+               printer_req_free(dev->out_ep, req);
+       }
+
+       while (!list_empty(&dev->rx_buffers)) {
+               req = container_of(dev->rx_buffers.next,
+                               struct usb_request, list);
+               list_del(&req->list);
+               printer_req_free(dev->out_ep, req);
+       }
+}
+
+static struct usb_configuration printer_cfg_driver = {
+       .label                  = "printer",
+       .unbind                 = printer_cfg_unbind,
+       .bConfigurationValue    = 1,
+       .bmAttributes           = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+};
+
+static int __init printer_bind_config(struct usb_configuration *c)
+{
+       struct usb_gadget       *gadget = c->cdev->gadget;
+       struct printer_dev      *dev;
+       int                     status = -ENOMEM;
+       size_t                  len;
+       u32                     i;
+       struct usb_request      *req;
+
+       usb_ep_autoconfig_reset(gadget);
+
+       dev = &usb_printer_gadget;
+
+       dev->function.name = shortname;
+       dev->function.bind = printer_func_bind;
+       dev->function.setup = printer_func_setup;
+       dev->function.unbind = printer_func_unbind;
+       dev->function.set_alt = printer_func_set_alt;
+       dev->function.disable = printer_func_disable;
+
+       status = usb_add_function(c, &dev->function);
+       if (status)
+               return status;
+
+       /* Setup the sysfs files for the printer gadget. */
+       dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
+                                 NULL, "g_printer");
+       if (IS_ERR(dev->pdev)) {
+               ERROR(dev, "Failed to create device: g_printer\n");
+               status = PTR_ERR(dev->pdev);
+               goto fail;
+       }
+
+       /*
+        * Register a character device as an interface to a user mode
+        * program that handles the printer specific functionality.
+        */
+       cdev_init(&dev->printer_cdev, &printer_io_operations);
+       dev->printer_cdev.owner = THIS_MODULE;
+       status = cdev_add(&dev->printer_cdev, g_printer_devno, 1);
+       if (status) {
+               ERROR(dev, "Failed to open char device\n");
+               goto fail;
+       }
+
+       if (iPNPstring)
+               strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
+
+       len = strlen(pnp_string);
+       pnp_string[0] = (len >> 8) & 0xFF;
+       pnp_string[1] = len & 0xFF;
+
+       usb_gadget_set_selfpowered(gadget);
+
+       if (gadget_is_otg(gadget)) {
+               otg_descriptor.bmAttributes |= USB_OTG_HNP;
+               printer_cfg_driver.descriptors = otg_desc;
+               printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       spin_lock_init(&dev->lock);
+       mutex_init(&dev->lock_printer_io);
+       INIT_LIST_HEAD(&dev->tx_reqs);
+       INIT_LIST_HEAD(&dev->tx_reqs_active);
+       INIT_LIST_HEAD(&dev->rx_reqs);
+       INIT_LIST_HEAD(&dev->rx_reqs_active);
+       INIT_LIST_HEAD(&dev->rx_buffers);
+       init_waitqueue_head(&dev->rx_wait);
+       init_waitqueue_head(&dev->tx_wait);
+       init_waitqueue_head(&dev->tx_flush_wait);
+
+       dev->interface = -1;
+       dev->printer_cdev_open = 0;
+       dev->printer_status = PRINTER_NOT_ERROR;
+       dev->current_rx_req = NULL;
+       dev->current_rx_bytes = 0;
+       dev->current_rx_buf = NULL;
+
+       for (i = 0; i < QLEN; i++) {
+               req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
+               if (!req) {
+                       while (!list_empty(&dev->tx_reqs)) {
+                               req = container_of(dev->tx_reqs.next,
+                                               struct usb_request, list);
+                               list_del(&req->list);
+                               printer_req_free(dev->in_ep, req);
+                       }
+                       return -ENOMEM;
+               }
+               list_add(&req->list, &dev->tx_reqs);
+       }
+
+       for (i = 0; i < QLEN; i++) {
+               req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
+               if (!req) {
+                       while (!list_empty(&dev->rx_reqs)) {
+                               req = container_of(dev->rx_reqs.next,
+                                               struct usb_request, list);
+                               list_del(&req->list);
+                               printer_req_free(dev->out_ep, req);
+                       }
+                       return -ENOMEM;
+               }
+               list_add(&req->list, &dev->rx_reqs);
+       }
+
+       /* finish hookup to lower layer ... */
+       dev->gadget = gadget;
+
+       INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
+       return 0;
+
+fail:
+       printer_cfg_unbind(c);
+       return status;
+}
+
+static int printer_unbind(struct usb_composite_dev *cdev)
+{
+       return 0;
+}
+
+static int __init printer_bind(struct usb_composite_dev *cdev)
+{
+       int ret;
+
+       ret = usb_string_ids_tab(cdev, strings);
+       if (ret < 0)
+               return ret;
+       device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id;
+       device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id;
+
+       ret = usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+       if (ret)
+               return ret;
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       return ret;
+}
+
+static __refdata struct usb_composite_driver printer_driver = {
+       .name           = shortname,
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_HIGH,
+       .bind           = printer_bind,
+       .unbind         = printer_unbind,
+};
+
+static int __init
+init(void)
+{
+       int status;
+
+       usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
+       if (IS_ERR(usb_gadget_class)) {
+               status = PTR_ERR(usb_gadget_class);
+               pr_err("unable to create usb_gadget class %d\n", status);
+               return status;
+       }
+
+       status = alloc_chrdev_region(&g_printer_devno, 0, 1,
+                       "USB printer gadget");
+       if (status) {
+               pr_err("alloc_chrdev_region %d\n", status);
+               class_destroy(usb_gadget_class);
+               return status;
+       }
+
+       status = usb_composite_probe(&printer_driver);
+       if (status) {
+               class_destroy(usb_gadget_class);
+               unregister_chrdev_region(g_printer_devno, 1);
+               pr_err("usb_gadget_probe_driver %x\n", status);
+       }
+
+       return status;
+}
+module_init(init);
+
+static void __exit
+cleanup(void)
+{
+       mutex_lock(&usb_printer_gadget.lock_printer_io);
+       usb_composite_unregister(&printer_driver);
+       unregister_chrdev_region(g_printer_devno, 1);
+       class_destroy(usb_gadget_class);
+       mutex_unlock(&usb_printer_gadget.lock_printer_io);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Craig Nadler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/legacy/serial.c b/drivers/usb/gadget/legacy/serial.c
new file mode 100644 (file)
index 0000000..1f5f978
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * serial.c -- USB gadget serial driver
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * either version 2 of that License or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include "u_serial.h"
+#include "gadget_chips.h"
+
+
+/* Defines */
+
+#define GS_VERSION_STR                 "v2.4"
+#define GS_VERSION_NUM                 0x2400
+
+#define GS_LONG_NAME                   "Gadget Serial"
+#define GS_VERSION_NAME                        GS_LONG_NAME " " GS_VERSION_STR
+
+/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
+
+/* Thanks to NetChip Technologies for donating this product ID.
+*
+* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+* Instead:  allocate your own, using normal USB-IF procedures.
+*/
+#define GS_VENDOR_ID                   0x0525  /* NetChip */
+#define GS_PRODUCT_ID                  0xa4a6  /* Linux-USB Serial Gadget */
+#define GS_CDC_PRODUCT_ID              0xa4a7  /* ... as CDC-ACM */
+#define GS_CDC_OBEX_PRODUCT_ID         0xa4a9  /* ... as CDC-OBEX */
+
+/* string IDs are assigned dynamically */
+
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              USB_DT_DEVICE_SIZE,
+       .bDescriptorType =      USB_DT_DEVICE,
+       .bcdUSB =               cpu_to_le16(0x0200),
+       /* .bDeviceClass = f(use_acm) */
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       /* .bMaxPacketSize0 = f(hardware) */
+       .idVendor =             cpu_to_le16(GS_VENDOR_ID),
+       /* .idProduct = f(use_acm) */
+       .bcdDevice = cpu_to_le16(GS_VERSION_NUM),
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Module */
+MODULE_DESCRIPTION(GS_VERSION_NAME);
+MODULE_AUTHOR("Al Borchers");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
+
+static bool use_acm = true;
+module_param(use_acm, bool, 0);
+MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
+
+static bool use_obex = false;
+module_param(use_obex, bool, 0);
+MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no");
+
+static unsigned n_ports = 1;
+module_param(n_ports, uint, 0);
+MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_configuration serial_config_driver = {
+       /* .label = f(use_acm) */
+       /* .bConfigurationValue = f(use_acm) */
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
+};
+
+static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS];
+static struct usb_function *f_serial[MAX_U_SERIAL_PORTS];
+
+static int serial_register_ports(struct usb_composite_dev *cdev,
+               struct usb_configuration *c, const char *f_name)
+{
+       int i;
+       int ret;
+
+       ret = usb_add_config_only(cdev, c);
+       if (ret)
+               goto out;
+
+       for (i = 0; i < n_ports; i++) {
+
+               fi_serial[i] = usb_get_function_instance(f_name);
+               if (IS_ERR(fi_serial[i])) {
+                       ret = PTR_ERR(fi_serial[i]);
+                       goto fail;
+               }
+
+               f_serial[i] = usb_get_function(fi_serial[i]);
+               if (IS_ERR(f_serial[i])) {
+                       ret = PTR_ERR(f_serial[i]);
+                       goto err_get_func;
+               }
+
+               ret = usb_add_function(c, f_serial[i]);
+               if (ret)
+                       goto err_add_func;
+       }
+
+       return 0;
+
+err_add_func:
+       usb_put_function(f_serial[i]);
+err_get_func:
+       usb_put_function_instance(fi_serial[i]);
+
+fail:
+       i--;
+       while (i >= 0) {
+               usb_remove_function(c, f_serial[i]);
+               usb_put_function(f_serial[i]);
+               usb_put_function_instance(fi_serial[i]);
+               i--;
+       }
+out:
+       return ret;
+}
+
+static int __init gs_bind(struct usb_composite_dev *cdev)
+{
+       int                     status;
+
+       /* Allocate string descriptor numbers ... note that string
+        * contents can be overridden by the composite_dev glue.
+        */
+
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               goto fail;
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       status = strings_dev[STRING_DESCRIPTION_IDX].id;
+       serial_config_driver.iConfiguration = status;
+
+       if (gadget_is_otg(cdev->gadget)) {
+               serial_config_driver.descriptors = otg_desc;
+               serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       /* register our configuration */
+       if (use_acm) {
+               status  = serial_register_ports(cdev, &serial_config_driver,
+                               "acm");
+               usb_ep_autoconfig_reset(cdev->gadget);
+       } else if (use_obex)
+               status = serial_register_ports(cdev, &serial_config_driver,
+                               "obex");
+       else {
+               status = serial_register_ports(cdev, &serial_config_driver,
+                               "gser");
+       }
+       if (status < 0)
+               goto fail;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       INFO(cdev, "%s\n", GS_VERSION_NAME);
+
+       return 0;
+
+fail:
+       return status;
+}
+
+static int gs_unbind(struct usb_composite_dev *cdev)
+{
+       int i;
+
+       for (i = 0; i < n_ports; i++) {
+               usb_put_function(f_serial[i]);
+               usb_put_function_instance(fi_serial[i]);
+       }
+       return 0;
+}
+
+static __refdata struct usb_composite_driver gserial_driver = {
+       .name           = "g_serial",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_SUPER,
+       .bind           = gs_bind,
+       .unbind         = gs_unbind,
+};
+
+static int __init init(void)
+{
+       /* We *could* export two configs; that'd be much cleaner...
+        * but neither of these product IDs was defined that way.
+        */
+       if (use_acm) {
+               serial_config_driver.label = "CDC ACM config";
+               serial_config_driver.bConfigurationValue = 2;
+               device_desc.bDeviceClass = USB_CLASS_COMM;
+               device_desc.idProduct =
+                               cpu_to_le16(GS_CDC_PRODUCT_ID);
+       } else if (use_obex) {
+               serial_config_driver.label = "CDC OBEX config";
+               serial_config_driver.bConfigurationValue = 3;
+               device_desc.bDeviceClass = USB_CLASS_COMM;
+               device_desc.idProduct =
+                       cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
+       } else {
+               serial_config_driver.label = "Generic Serial config";
+               serial_config_driver.bConfigurationValue = 1;
+               device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+               device_desc.idProduct =
+                               cpu_to_le16(GS_PRODUCT_ID);
+       }
+       strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
+
+       return usb_composite_probe(&gserial_driver);
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+       usb_composite_unregister(&gserial_driver);
+}
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
new file mode 100644 (file)
index 0000000..6cdb7a5
--- /dev/null
@@ -0,0 +1,2473 @@
+/* Target based USB-Gadget
+ *
+ * UAS protocol handling, target callbacks, configfs handling,
+ * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
+ *
+ * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
+ * License: GPLv2 as published by FSF.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "tcm_usb_gadget.h"
+
+USB_GADGET_COMPOSITE_OPTIONS();
+
+static struct target_fabric_configfs *usbg_fabric_configfs;
+
+static inline struct f_uas *to_f_uas(struct usb_function *f)
+{
+       return container_of(f, struct f_uas, function);
+}
+
+static void usbg_cmd_release(struct kref *);
+
+static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
+{
+       kref_put(&cmd->ref, usbg_cmd_release);
+}
+
+/* Start bot.c code */
+
+static int bot_enqueue_cmd_cbw(struct f_uas *fu)
+{
+       int ret;
+
+       if (fu->flags & USBG_BOT_CMD_PEND)
+               return 0;
+
+       ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
+       if (!ret)
+               fu->flags |= USBG_BOT_CMD_PEND;
+       return ret;
+}
+
+static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct usbg_cmd *cmd = req->context;
+       struct f_uas *fu = cmd->fu;
+
+       usbg_cleanup_cmd(cmd);
+       if (req->status < 0) {
+               pr_err("ERR %s(%d)\n", __func__, __LINE__);
+               return;
+       }
+
+       /* CSW completed, wait for next CBW */
+       bot_enqueue_cmd_cbw(fu);
+}
+
+static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
+{
+       struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+       int ret;
+       u8 *sense;
+       unsigned int csw_stat;
+
+       csw_stat = cmd->csw_code;
+
+       /*
+        * We can't send SENSE as a response. So we take ASC & ASCQ from our
+        * sense buffer and queue it and hope the host sends a REQUEST_SENSE
+        * command where it learns why we failed.
+        */
+       sense = cmd->sense_iu.sense;
+
+       csw->Tag = cmd->bot_tag;
+       csw->Status = csw_stat;
+       fu->bot_status.req->context = cmd;
+       ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
+       if (ret)
+               pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+}
+
+static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
+{
+       struct usbg_cmd *cmd = req->context;
+       struct f_uas *fu = cmd->fu;
+
+       if (req->status < 0)
+               pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+       if (cmd->data_len) {
+               if (cmd->data_len > ep->maxpacket) {
+                       req->length = ep->maxpacket;
+                       cmd->data_len -= ep->maxpacket;
+               } else {
+                       req->length = cmd->data_len;
+                       cmd->data_len = 0;
+               }
+
+               usb_ep_queue(ep, req, GFP_ATOMIC);
+               return ;
+       }
+       bot_enqueue_sense_code(fu, cmd);
+}
+
+static void bot_send_bad_status(struct usbg_cmd *cmd)
+{
+       struct f_uas *fu = cmd->fu;
+       struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+       struct usb_request *req;
+       struct usb_ep *ep;
+
+       csw->Residue = cpu_to_le32(cmd->data_len);
+
+       if (cmd->data_len) {
+               if (cmd->is_read) {
+                       ep = fu->ep_in;
+                       req = fu->bot_req_in;
+               } else {
+                       ep = fu->ep_out;
+                       req = fu->bot_req_out;
+               }
+
+               if (cmd->data_len > fu->ep_in->maxpacket) {
+                       req->length = ep->maxpacket;
+                       cmd->data_len -= ep->maxpacket;
+               } else {
+                       req->length = cmd->data_len;
+                       cmd->data_len = 0;
+               }
+               req->complete = bot_err_compl;
+               req->context = cmd;
+               req->buf = fu->cmd.buf;
+               usb_ep_queue(ep, req, GFP_KERNEL);
+       } else {
+               bot_enqueue_sense_code(fu, cmd);
+       }
+}
+
+static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
+{
+       struct f_uas *fu = cmd->fu;
+       struct bulk_cs_wrap *csw = &fu->bot_status.csw;
+       int ret;
+
+       if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
+               if (!moved_data && cmd->data_len) {
+                       /*
+                        * the host wants to move data, we don't. Fill / empty
+                        * the pipe and then send the csw with reside set.
+                        */
+                       cmd->csw_code = US_BULK_STAT_OK;
+                       bot_send_bad_status(cmd);
+                       return 0;
+               }
+
+               csw->Tag = cmd->bot_tag;
+               csw->Residue = cpu_to_le32(0);
+               csw->Status = US_BULK_STAT_OK;
+               fu->bot_status.req->context = cmd;
+
+               ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
+               if (ret)
+                       pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
+       } else {
+               cmd->csw_code = US_BULK_STAT_FAIL;
+               bot_send_bad_status(cmd);
+       }
+       return 0;
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int bot_send_status_response(struct usbg_cmd *cmd)
+{
+       bool moved_data = false;
+
+       if (!cmd->is_read)
+               moved_data = true;
+       return bot_send_status(cmd, moved_data);
+}
+
+/* Read request completed, now we have to send the CSW */
+static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
+{
+       struct usbg_cmd *cmd = req->context;
+
+       if (req->status < 0)
+               pr_err("ERR %s(%d)\n", __func__, __LINE__);
+
+       bot_send_status(cmd, true);
+}
+
+static int bot_send_read_response(struct usbg_cmd *cmd)
+{
+       struct f_uas *fu = cmd->fu;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct usb_gadget *gadget = fuas_to_gadget(fu);
+       int ret;
+
+       if (!cmd->data_len) {
+               cmd->csw_code = US_BULK_STAT_PHASE;
+               bot_send_bad_status(cmd);
+               return 0;
+       }
+
+       if (!gadget->sg_supported) {
+               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+               if (!cmd->data_buf)
+                       return -ENOMEM;
+
+               sg_copy_to_buffer(se_cmd->t_data_sg,
+                               se_cmd->t_data_nents,
+                               cmd->data_buf,
+                               se_cmd->data_length);
+
+               fu->bot_req_in->buf = cmd->data_buf;
+       } else {
+               fu->bot_req_in->buf = NULL;
+               fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
+               fu->bot_req_in->sg = se_cmd->t_data_sg;
+       }
+
+       fu->bot_req_in->complete = bot_read_compl;
+       fu->bot_req_in->length = se_cmd->data_length;
+       fu->bot_req_in->context = cmd;
+       ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
+       if (ret)
+               pr_err("%s(%d)\n", __func__, __LINE__);
+       return 0;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
+static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
+
+static int bot_send_write_request(struct usbg_cmd *cmd)
+{
+       struct f_uas *fu = cmd->fu;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct usb_gadget *gadget = fuas_to_gadget(fu);
+       int ret;
+
+       init_completion(&cmd->write_complete);
+       cmd->fu = fu;
+
+       if (!cmd->data_len) {
+               cmd->csw_code = US_BULK_STAT_PHASE;
+               return -EINVAL;
+       }
+
+       if (!gadget->sg_supported) {
+               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+               if (!cmd->data_buf)
+                       return -ENOMEM;
+
+               fu->bot_req_out->buf = cmd->data_buf;
+       } else {
+               fu->bot_req_out->buf = NULL;
+               fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
+               fu->bot_req_out->sg = se_cmd->t_data_sg;
+       }
+
+       fu->bot_req_out->complete = usbg_data_write_cmpl;
+       fu->bot_req_out->length = se_cmd->data_length;
+       fu->bot_req_out->context = cmd;
+
+       ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
+       if (ret)
+               goto cleanup;
+       ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
+       if (ret)
+               pr_err("%s(%d)\n", __func__, __LINE__);
+
+       wait_for_completion(&cmd->write_complete);
+       target_execute_cmd(se_cmd);
+cleanup:
+       return ret;
+}
+
+static int bot_submit_command(struct f_uas *, void *, unsigned int);
+
+static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_uas *fu = req->context;
+       int ret;
+
+       fu->flags &= ~USBG_BOT_CMD_PEND;
+
+       if (req->status < 0)
+               return;
+
+       ret = bot_submit_command(fu, req->buf, req->actual);
+       if (ret)
+               pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
+}
+
+static int bot_prepare_reqs(struct f_uas *fu)
+{
+       int ret;
+
+       fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+       if (!fu->bot_req_in)
+               goto err;
+
+       fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+       if (!fu->bot_req_out)
+               goto err_out;
+
+       fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+       if (!fu->cmd.req)
+               goto err_cmd;
+
+       fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+       if (!fu->bot_status.req)
+               goto err_sts;
+
+       fu->bot_status.req->buf = &fu->bot_status.csw;
+       fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
+       fu->bot_status.req->complete = bot_status_complete;
+       fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
+
+       fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
+       if (!fu->cmd.buf)
+               goto err_buf;
+
+       fu->cmd.req->complete = bot_cmd_complete;
+       fu->cmd.req->buf = fu->cmd.buf;
+       fu->cmd.req->length = fu->ep_out->maxpacket;
+       fu->cmd.req->context = fu;
+
+       ret = bot_enqueue_cmd_cbw(fu);
+       if (ret)
+               goto err_queue;
+       return 0;
+err_queue:
+       kfree(fu->cmd.buf);
+       fu->cmd.buf = NULL;
+err_buf:
+       usb_ep_free_request(fu->ep_in, fu->bot_status.req);
+err_sts:
+       usb_ep_free_request(fu->ep_out, fu->cmd.req);
+       fu->cmd.req = NULL;
+err_cmd:
+       usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+       fu->bot_req_out = NULL;
+err_out:
+       usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+       fu->bot_req_in = NULL;
+err:
+       pr_err("BOT: endpoint setup failed\n");
+       return -ENOMEM;
+}
+
+static void bot_cleanup_old_alt(struct f_uas *fu)
+{
+       if (!(fu->flags & USBG_ENABLED))
+               return;
+
+       usb_ep_disable(fu->ep_in);
+       usb_ep_disable(fu->ep_out);
+
+       if (!fu->bot_req_in)
+               return;
+
+       usb_ep_free_request(fu->ep_in, fu->bot_req_in);
+       usb_ep_free_request(fu->ep_out, fu->bot_req_out);
+       usb_ep_free_request(fu->ep_out, fu->cmd.req);
+       usb_ep_free_request(fu->ep_out, fu->bot_status.req);
+
+       kfree(fu->cmd.buf);
+
+       fu->bot_req_in = NULL;
+       fu->bot_req_out = NULL;
+       fu->cmd.req = NULL;
+       fu->bot_status.req = NULL;
+       fu->cmd.buf = NULL;
+}
+
+static void bot_set_alt(struct f_uas *fu)
+{
+       struct usb_function *f = &fu->function;
+       struct usb_gadget *gadget = f->config->cdev->gadget;
+       int ret;
+
+       fu->flags = USBG_IS_BOT;
+
+       config_ep_by_speed(gadget, f, fu->ep_in);
+       ret = usb_ep_enable(fu->ep_in);
+       if (ret)
+               goto err_b_in;
+
+       config_ep_by_speed(gadget, f, fu->ep_out);
+       ret = usb_ep_enable(fu->ep_out);
+       if (ret)
+               goto err_b_out;
+
+       ret = bot_prepare_reqs(fu);
+       if (ret)
+               goto err_wq;
+       fu->flags |= USBG_ENABLED;
+       pr_info("Using the BOT protocol\n");
+       return;
+err_wq:
+       usb_ep_disable(fu->ep_out);
+err_b_out:
+       usb_ep_disable(fu->ep_in);
+err_b_in:
+       fu->flags = USBG_IS_BOT;
+}
+
+static int usbg_bot_setup(struct usb_function *f,
+               const struct usb_ctrlrequest *ctrl)
+{
+       struct f_uas *fu = to_f_uas(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       u16 w_value = le16_to_cpu(ctrl->wValue);
+       u16 w_length = le16_to_cpu(ctrl->wLength);
+       int luns;
+       u8 *ret_lun;
+
+       switch (ctrl->bRequest) {
+       case US_BULK_GET_MAX_LUN:
+               if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
+                                       USB_RECIP_INTERFACE))
+                       return -ENOTSUPP;
+
+               if (w_length < 1)
+                       return -EINVAL;
+               if (w_value != 0)
+                       return -EINVAL;
+               luns = atomic_read(&fu->tpg->tpg_port_count);
+               if (!luns) {
+                       pr_err("No LUNs configured?\n");
+                       return -EINVAL;
+               }
+               /*
+                * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
+                * accessed. The upper limit is 0xf
+                */
+               luns--;
+               if (luns > 0xf) {
+                       pr_info_once("Limiting the number of luns to 16\n");
+                       luns = 0xf;
+               }
+               ret_lun = cdev->req->buf;
+               *ret_lun = luns;
+               cdev->req->length = 1;
+               return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+               break;
+
+       case US_BULK_RESET_REQUEST:
+               /* XXX maybe we should remove previous requests for IN + OUT */
+               bot_enqueue_cmd_cbw(fu);
+               return 0;
+               break;
+       }
+       return -ENOTSUPP;
+}
+
+/* Start uas.c code */
+
+static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
+{
+       /* We have either all three allocated or none */
+       if (!stream->req_in)
+               return;
+
+       usb_ep_free_request(fu->ep_in, stream->req_in);
+       usb_ep_free_request(fu->ep_out, stream->req_out);
+       usb_ep_free_request(fu->ep_status, stream->req_status);
+
+       stream->req_in = NULL;
+       stream->req_out = NULL;
+       stream->req_status = NULL;
+}
+
+static void uasp_free_cmdreq(struct f_uas *fu)
+{
+       usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+       kfree(fu->cmd.buf);
+       fu->cmd.req = NULL;
+       fu->cmd.buf = NULL;
+}
+
+static void uasp_cleanup_old_alt(struct f_uas *fu)
+{
+       int i;
+
+       if (!(fu->flags & USBG_ENABLED))
+               return;
+
+       usb_ep_disable(fu->ep_in);
+       usb_ep_disable(fu->ep_out);
+       usb_ep_disable(fu->ep_status);
+       usb_ep_disable(fu->ep_cmd);
+
+       for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
+               uasp_cleanup_one_stream(fu, &fu->stream[i]);
+       uasp_free_cmdreq(fu);
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
+
+static int uasp_prepare_r_request(struct usbg_cmd *cmd)
+{
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct f_uas *fu = cmd->fu;
+       struct usb_gadget *gadget = fuas_to_gadget(fu);
+       struct uas_stream *stream = cmd->stream;
+
+       if (!gadget->sg_supported) {
+               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+               if (!cmd->data_buf)
+                       return -ENOMEM;
+
+               sg_copy_to_buffer(se_cmd->t_data_sg,
+                               se_cmd->t_data_nents,
+                               cmd->data_buf,
+                               se_cmd->data_length);
+
+               stream->req_in->buf = cmd->data_buf;
+       } else {
+               stream->req_in->buf = NULL;
+               stream->req_in->num_sgs = se_cmd->t_data_nents;
+               stream->req_in->sg = se_cmd->t_data_sg;
+       }
+
+       stream->req_in->complete = uasp_status_data_cmpl;
+       stream->req_in->length = se_cmd->data_length;
+       stream->req_in->context = cmd;
+
+       cmd->state = UASP_SEND_STATUS;
+       return 0;
+}
+
+static void uasp_prepare_status(struct usbg_cmd *cmd)
+{
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct sense_iu *iu = &cmd->sense_iu;
+       struct uas_stream *stream = cmd->stream;
+
+       cmd->state = UASP_QUEUE_COMMAND;
+       iu->iu_id = IU_ID_STATUS;
+       iu->tag = cpu_to_be16(cmd->tag);
+
+       /*
+        * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
+        */
+       iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
+       iu->status = se_cmd->scsi_status;
+       stream->req_status->context = cmd;
+       stream->req_status->length = se_cmd->scsi_sense_length + 16;
+       stream->req_status->buf = iu;
+       stream->req_status->complete = uasp_status_data_cmpl;
+}
+
+static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+       struct usbg_cmd *cmd = req->context;
+       struct uas_stream *stream = cmd->stream;
+       struct f_uas *fu = cmd->fu;
+       int ret;
+
+       if (req->status < 0)
+               goto cleanup;
+
+       switch (cmd->state) {
+       case UASP_SEND_DATA:
+               ret = uasp_prepare_r_request(cmd);
+               if (ret)
+                       goto cleanup;
+               ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+               if (ret)
+                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+               break;
+
+       case UASP_RECEIVE_DATA:
+               ret = usbg_prepare_w_request(cmd, stream->req_out);
+               if (ret)
+                       goto cleanup;
+               ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+               if (ret)
+                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+               break;
+
+       case UASP_SEND_STATUS:
+               uasp_prepare_status(cmd);
+               ret = usb_ep_queue(fu->ep_status, stream->req_status,
+                               GFP_ATOMIC);
+               if (ret)
+                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+               break;
+
+       case UASP_QUEUE_COMMAND:
+               usbg_cleanup_cmd(cmd);
+               usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+               break;
+
+       default:
+               BUG();
+       }
+       return;
+
+cleanup:
+       usbg_cleanup_cmd(cmd);
+}
+
+static int uasp_send_status_response(struct usbg_cmd *cmd)
+{
+       struct f_uas *fu = cmd->fu;
+       struct uas_stream *stream = cmd->stream;
+       struct sense_iu *iu = &cmd->sense_iu;
+
+       iu->tag = cpu_to_be16(cmd->tag);
+       stream->req_status->complete = uasp_status_data_cmpl;
+       stream->req_status->context = cmd;
+       cmd->fu = fu;
+       uasp_prepare_status(cmd);
+       return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
+}
+
+static int uasp_send_read_response(struct usbg_cmd *cmd)
+{
+       struct f_uas *fu = cmd->fu;
+       struct uas_stream *stream = cmd->stream;
+       struct sense_iu *iu = &cmd->sense_iu;
+       int ret;
+
+       cmd->fu = fu;
+
+       iu->tag = cpu_to_be16(cmd->tag);
+       if (fu->flags & USBG_USE_STREAMS) {
+
+               ret = uasp_prepare_r_request(cmd);
+               if (ret)
+                       goto out;
+               ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
+               if (ret) {
+                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+                       kfree(cmd->data_buf);
+                       cmd->data_buf = NULL;
+               }
+
+       } else {
+
+               iu->iu_id = IU_ID_READ_READY;
+               iu->tag = cpu_to_be16(cmd->tag);
+
+               stream->req_status->complete = uasp_status_data_cmpl;
+               stream->req_status->context = cmd;
+
+               cmd->state = UASP_SEND_DATA;
+               stream->req_status->buf = iu;
+               stream->req_status->length = sizeof(struct iu);
+
+               ret = usb_ep_queue(fu->ep_status, stream->req_status,
+                               GFP_ATOMIC);
+               if (ret)
+                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
+       }
+out:
+       return ret;
+}
+
+static int uasp_send_write_request(struct usbg_cmd *cmd)
+{
+       struct f_uas *fu = cmd->fu;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct uas_stream *stream = cmd->stream;
+       struct sense_iu *iu = &cmd->sense_iu;
+       int ret;
+
+       init_completion(&cmd->write_complete);
+       cmd->fu = fu;
+
+       iu->tag = cpu_to_be16(cmd->tag);
+
+       if (fu->flags & USBG_USE_STREAMS) {
+
+               ret = usbg_prepare_w_request(cmd, stream->req_out);
+               if (ret)
+                       goto cleanup;
+               ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
+               if (ret)
+                       pr_err("%s(%d)\n", __func__, __LINE__);
+
+       } else {
+
+               iu->iu_id = IU_ID_WRITE_READY;
+               iu->tag = cpu_to_be16(cmd->tag);
+
+               stream->req_status->complete = uasp_status_data_cmpl;
+               stream->req_status->context = cmd;
+
+               cmd->state = UASP_RECEIVE_DATA;
+               stream->req_status->buf = iu;
+               stream->req_status->length = sizeof(struct iu);
+
+               ret = usb_ep_queue(fu->ep_status, stream->req_status,
+                               GFP_ATOMIC);
+               if (ret)
+                       pr_err("%s(%d)\n", __func__, __LINE__);
+       }
+
+       wait_for_completion(&cmd->write_complete);
+       target_execute_cmd(se_cmd);
+cleanup:
+       return ret;
+}
+
+static int usbg_submit_command(struct f_uas *, void *, unsigned int);
+
+static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_uas *fu = req->context;
+       int ret;
+
+       if (req->status < 0)
+               return;
+
+       ret = usbg_submit_command(fu, req->buf, req->actual);
+       /*
+        * Once we tune for performance enqueue the command req here again so
+        * we can receive a second command while we processing this one. Pay
+        * attention to properly sync STAUS endpoint with DATA IN + OUT so you
+        * don't break HS.
+        */
+       if (!ret)
+               return;
+       usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+}
+
+static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
+{
+       stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
+       if (!stream->req_in)
+               goto out;
+
+       stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
+       if (!stream->req_out)
+               goto err_out;
+
+       stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
+       if (!stream->req_status)
+               goto err_sts;
+
+       return 0;
+err_sts:
+       usb_ep_free_request(fu->ep_status, stream->req_status);
+       stream->req_status = NULL;
+err_out:
+       usb_ep_free_request(fu->ep_out, stream->req_out);
+       stream->req_out = NULL;
+out:
+       return -ENOMEM;
+}
+
+static int uasp_alloc_cmd(struct f_uas *fu)
+{
+       fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
+       if (!fu->cmd.req)
+               goto err;
+
+       fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
+       if (!fu->cmd.buf)
+               goto err_buf;
+
+       fu->cmd.req->complete = uasp_cmd_complete;
+       fu->cmd.req->buf = fu->cmd.buf;
+       fu->cmd.req->length = fu->ep_cmd->maxpacket;
+       fu->cmd.req->context = fu;
+       return 0;
+
+err_buf:
+       usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
+err:
+       return -ENOMEM;
+}
+
+static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
+{
+       int i;
+
+       for (i = 0; i < max_streams; i++) {
+               struct uas_stream *s = &fu->stream[i];
+
+               s->req_in->stream_id = i + 1;
+               s->req_out->stream_id = i + 1;
+               s->req_status->stream_id = i + 1;
+       }
+}
+
+static int uasp_prepare_reqs(struct f_uas *fu)
+{
+       int ret;
+       int i;
+       int max_streams;
+
+       if (fu->flags & USBG_USE_STREAMS)
+               max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
+       else
+               max_streams = 1;
+
+       for (i = 0; i < max_streams; i++) {
+               ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
+               if (ret)
+                       goto err_cleanup;
+       }
+
+       ret = uasp_alloc_cmd(fu);
+       if (ret)
+               goto err_free_stream;
+       uasp_setup_stream_res(fu, max_streams);
+
+       ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
+       if (ret)
+               goto err_free_stream;
+
+       return 0;
+
+err_free_stream:
+       uasp_free_cmdreq(fu);
+
+err_cleanup:
+       if (i) {
+               do {
+                       uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
+                       i--;
+               } while (i);
+       }
+       pr_err("UASP: endpoint setup failed\n");
+       return ret;
+}
+
+static void uasp_set_alt(struct f_uas *fu)
+{
+       struct usb_function *f = &fu->function;
+       struct usb_gadget *gadget = f->config->cdev->gadget;
+       int ret;
+
+       fu->flags = USBG_IS_UAS;
+
+       if (gadget->speed == USB_SPEED_SUPER)
+               fu->flags |= USBG_USE_STREAMS;
+
+       config_ep_by_speed(gadget, f, fu->ep_in);
+       ret = usb_ep_enable(fu->ep_in);
+       if (ret)
+               goto err_b_in;
+
+       config_ep_by_speed(gadget, f, fu->ep_out);
+       ret = usb_ep_enable(fu->ep_out);
+       if (ret)
+               goto err_b_out;
+
+       config_ep_by_speed(gadget, f, fu->ep_cmd);
+       ret = usb_ep_enable(fu->ep_cmd);
+       if (ret)
+               goto err_cmd;
+       config_ep_by_speed(gadget, f, fu->ep_status);
+       ret = usb_ep_enable(fu->ep_status);
+       if (ret)
+               goto err_status;
+
+       ret = uasp_prepare_reqs(fu);
+       if (ret)
+               goto err_wq;
+       fu->flags |= USBG_ENABLED;
+
+       pr_info("Using the UAS protocol\n");
+       return;
+err_wq:
+       usb_ep_disable(fu->ep_status);
+err_status:
+       usb_ep_disable(fu->ep_cmd);
+err_cmd:
+       usb_ep_disable(fu->ep_out);
+err_b_out:
+       usb_ep_disable(fu->ep_in);
+err_b_in:
+       fu->flags = 0;
+}
+
+static int get_cmd_dir(const unsigned char *cdb)
+{
+       int ret;
+
+       switch (cdb[0]) {
+       case READ_6:
+       case READ_10:
+       case READ_12:
+       case READ_16:
+       case INQUIRY:
+       case MODE_SENSE:
+       case MODE_SENSE_10:
+       case SERVICE_ACTION_IN:
+       case MAINTENANCE_IN:
+       case PERSISTENT_RESERVE_IN:
+       case SECURITY_PROTOCOL_IN:
+       case ACCESS_CONTROL_IN:
+       case REPORT_LUNS:
+       case READ_BLOCK_LIMITS:
+       case READ_POSITION:
+       case READ_CAPACITY:
+       case READ_TOC:
+       case READ_FORMAT_CAPACITIES:
+       case REQUEST_SENSE:
+               ret = DMA_FROM_DEVICE;
+               break;
+
+       case WRITE_6:
+       case WRITE_10:
+       case WRITE_12:
+       case WRITE_16:
+       case MODE_SELECT:
+       case MODE_SELECT_10:
+       case WRITE_VERIFY:
+       case WRITE_VERIFY_12:
+       case PERSISTENT_RESERVE_OUT:
+       case MAINTENANCE_OUT:
+       case SECURITY_PROTOCOL_OUT:
+       case ACCESS_CONTROL_OUT:
+               ret = DMA_TO_DEVICE;
+               break;
+       case ALLOW_MEDIUM_REMOVAL:
+       case TEST_UNIT_READY:
+       case SYNCHRONIZE_CACHE:
+       case START_STOP:
+       case ERASE:
+       case REZERO_UNIT:
+       case SEEK_10:
+       case SPACE:
+       case VERIFY:
+       case WRITE_FILEMARKS:
+               ret = DMA_NONE;
+               break;
+       default:
+               pr_warn("target: Unknown data direction for SCSI Opcode "
+                               "0x%02x\n", cdb[0]);
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+       struct usbg_cmd *cmd = req->context;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+
+       if (req->status < 0) {
+               pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
+               goto cleanup;
+       }
+
+       if (req->num_sgs == 0) {
+               sg_copy_from_buffer(se_cmd->t_data_sg,
+                               se_cmd->t_data_nents,
+                               cmd->data_buf,
+                               se_cmd->data_length);
+       }
+
+       complete(&cmd->write_complete);
+       return;
+
+cleanup:
+       usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
+{
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct f_uas *fu = cmd->fu;
+       struct usb_gadget *gadget = fuas_to_gadget(fu);
+
+       if (!gadget->sg_supported) {
+               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
+               if (!cmd->data_buf)
+                       return -ENOMEM;
+
+               req->buf = cmd->data_buf;
+       } else {
+               req->buf = NULL;
+               req->num_sgs = se_cmd->t_data_nents;
+               req->sg = se_cmd->t_data_sg;
+       }
+
+       req->complete = usbg_data_write_cmpl;
+       req->length = se_cmd->data_length;
+       req->context = cmd;
+       return 0;
+}
+
+static int usbg_send_status_response(struct se_cmd *se_cmd)
+{
+       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+                       se_cmd);
+       struct f_uas *fu = cmd->fu;
+
+       if (fu->flags & USBG_IS_BOT)
+               return bot_send_status_response(cmd);
+       else
+               return uasp_send_status_response(cmd);
+}
+
+static int usbg_send_write_request(struct se_cmd *se_cmd)
+{
+       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+                       se_cmd);
+       struct f_uas *fu = cmd->fu;
+
+       if (fu->flags & USBG_IS_BOT)
+               return bot_send_write_request(cmd);
+       else
+               return uasp_send_write_request(cmd);
+}
+
+static int usbg_send_read_response(struct se_cmd *se_cmd)
+{
+       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+                       se_cmd);
+       struct f_uas *fu = cmd->fu;
+
+       if (fu->flags & USBG_IS_BOT)
+               return bot_send_read_response(cmd);
+       else
+               return uasp_send_read_response(cmd);
+}
+
+static void usbg_cmd_work(struct work_struct *work)
+{
+       struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+       struct se_cmd *se_cmd;
+       struct tcm_usbg_nexus *tv_nexus;
+       struct usbg_tpg *tpg;
+       int dir;
+
+       se_cmd = &cmd->se_cmd;
+       tpg = cmd->fu->tpg;
+       tv_nexus = tpg->tpg_nexus;
+       dir = get_cmd_dir(cmd->cmd_buf);
+       if (dir < 0) {
+               transport_init_se_cmd(se_cmd,
+                               tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+                               tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+                               cmd->prio_attr, cmd->sense_iu.sense);
+               goto out;
+       }
+
+       if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+                       cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+                       0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0)
+               goto out;
+
+       return;
+
+out:
+       transport_send_check_condition_and_sense(se_cmd,
+                       TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+       usbg_cleanup_cmd(cmd);
+}
+
+static int usbg_submit_command(struct f_uas *fu,
+               void *cmdbuf, unsigned int len)
+{
+       struct command_iu *cmd_iu = cmdbuf;
+       struct usbg_cmd *cmd;
+       struct usbg_tpg *tpg;
+       struct se_cmd *se_cmd;
+       struct tcm_usbg_nexus *tv_nexus;
+       u32 cmd_len;
+       int ret;
+
+       if (cmd_iu->iu_id != IU_ID_COMMAND) {
+               pr_err("Unsupported type %d\n", cmd_iu->iu_id);
+               return -EINVAL;
+       }
+
+       cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->fu = fu;
+
+       /* XXX until I figure out why I can't free in on complete */
+       kref_init(&cmd->ref);
+       kref_get(&cmd->ref);
+
+       tpg = fu->tpg;
+       cmd_len = (cmd_iu->len & ~0x3) + 16;
+       if (cmd_len > USBG_MAX_CMD)
+               goto err;
+
+       memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
+
+       cmd->tag = be16_to_cpup(&cmd_iu->tag);
+       if (fu->flags & USBG_USE_STREAMS) {
+               if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
+                       goto err;
+               if (!cmd->tag)
+                       cmd->stream = &fu->stream[0];
+               else
+                       cmd->stream = &fu->stream[cmd->tag - 1];
+       } else {
+               cmd->stream = &fu->stream[0];
+       }
+
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus) {
+               pr_err("Missing nexus, ignoring command\n");
+               goto err;
+       }
+
+       switch (cmd_iu->prio_attr & 0x7) {
+       case UAS_HEAD_TAG:
+               cmd->prio_attr = MSG_HEAD_TAG;
+               break;
+       case UAS_ORDERED_TAG:
+               cmd->prio_attr = MSG_ORDERED_TAG;
+               break;
+       case UAS_ACA:
+               cmd->prio_attr = MSG_ACA_TAG;
+               break;
+       default:
+               pr_debug_once("Unsupported prio_attr: %02x.\n",
+                               cmd_iu->prio_attr);
+       case UAS_SIMPLE_TAG:
+               cmd->prio_attr = MSG_SIMPLE_TAG;
+               break;
+       }
+
+       se_cmd = &cmd->se_cmd;
+       cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
+
+       INIT_WORK(&cmd->work, usbg_cmd_work);
+       ret = queue_work(tpg->workqueue, &cmd->work);
+       if (ret < 0)
+               goto err;
+
+       return 0;
+err:
+       kfree(cmd);
+       return -EINVAL;
+}
+
+static void bot_cmd_work(struct work_struct *work)
+{
+       struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
+       struct se_cmd *se_cmd;
+       struct tcm_usbg_nexus *tv_nexus;
+       struct usbg_tpg *tpg;
+       int dir;
+
+       se_cmd = &cmd->se_cmd;
+       tpg = cmd->fu->tpg;
+       tv_nexus = tpg->tpg_nexus;
+       dir = get_cmd_dir(cmd->cmd_buf);
+       if (dir < 0) {
+               transport_init_se_cmd(se_cmd,
+                               tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
+                               tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
+                               cmd->prio_attr, cmd->sense_iu.sense);
+               goto out;
+       }
+
+       if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
+                       cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
+                       cmd->data_len, cmd->prio_attr, dir, 0) < 0)
+               goto out;
+
+       return;
+
+out:
+       transport_send_check_condition_and_sense(se_cmd,
+                               TCM_UNSUPPORTED_SCSI_OPCODE, 1);
+       usbg_cleanup_cmd(cmd);
+}
+
+static int bot_submit_command(struct f_uas *fu,
+               void *cmdbuf, unsigned int len)
+{
+       struct bulk_cb_wrap *cbw = cmdbuf;
+       struct usbg_cmd *cmd;
+       struct usbg_tpg *tpg;
+       struct se_cmd *se_cmd;
+       struct tcm_usbg_nexus *tv_nexus;
+       u32 cmd_len;
+       int ret;
+
+       if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
+               pr_err("Wrong signature on CBW\n");
+               return -EINVAL;
+       }
+       if (len != 31) {
+               pr_err("Wrong length for CBW\n");
+               return -EINVAL;
+       }
+
+       cmd_len = cbw->Length;
+       if (cmd_len < 1 || cmd_len > 16)
+               return -EINVAL;
+
+       cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->fu = fu;
+
+       /* XXX until I figure out why I can't free in on complete */
+       kref_init(&cmd->ref);
+       kref_get(&cmd->ref);
+
+       tpg = fu->tpg;
+
+       memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
+
+       cmd->bot_tag = cbw->Tag;
+
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus) {
+               pr_err("Missing nexus, ignoring command\n");
+               goto err;
+       }
+
+       cmd->prio_attr = MSG_SIMPLE_TAG;
+       se_cmd = &cmd->se_cmd;
+       cmd->unpacked_lun = cbw->Lun;
+       cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
+       cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
+
+       INIT_WORK(&cmd->work, bot_cmd_work);
+       ret = queue_work(tpg->workqueue, &cmd->work);
+       if (ret < 0)
+               goto err;
+
+       return 0;
+err:
+       kfree(cmd);
+       return -EINVAL;
+}
+
+/* Start fabric.c code */
+
+static int usbg_check_true(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int usbg_check_false(struct se_portal_group *se_tpg)
+{
+       return 0;
+}
+
+static char *usbg_get_fabric_name(void)
+{
+       return "usb_gadget";
+}
+
+static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg,
+                               struct usbg_tpg, se_tpg);
+       struct usbg_tport *tport = tpg->tport;
+       u8 proto_id;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+       default:
+               proto_id = sas_get_fabric_proto_ident(se_tpg);
+               break;
+       }
+
+       return proto_id;
+}
+
+static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg,
+                               struct usbg_tpg, se_tpg);
+       struct usbg_tport *tport = tpg->tport;
+
+       return &tport->tport_name[0];
+}
+
+static u16 usbg_get_tag(struct se_portal_group *se_tpg)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg,
+                               struct usbg_tpg, se_tpg);
+       return tpg->tport_tpgt;
+}
+
+static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static u32 usbg_get_pr_transport_id(
+       struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl,
+       struct t10_pr_registration *pr_reg,
+       int *format_code,
+       unsigned char *buf)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg,
+                               struct usbg_tpg, se_tpg);
+       struct usbg_tport *tport = tpg->tport;
+       int ret = 0;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+       default:
+               ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+               break;
+       }
+
+       return ret;
+}
+
+static u32 usbg_get_pr_transport_id_len(
+       struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl,
+       struct t10_pr_registration *pr_reg,
+       int *format_code)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg,
+                               struct usbg_tpg, se_tpg);
+       struct usbg_tport *tport = tpg->tport;
+       int ret = 0;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+       default:
+               ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+               break;
+       }
+
+       return ret;
+}
+
+static char *usbg_parse_pr_out_transport_id(
+       struct se_portal_group *se_tpg,
+       const char *buf,
+       u32 *out_tid_len,
+       char **port_nexus_ptr)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg,
+                               struct usbg_tpg, se_tpg);
+       struct usbg_tport *tport = tpg->tport;
+       char *tid = NULL;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+       default:
+               tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       }
+
+       return tid;
+}
+
+static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+       struct usbg_nacl *nacl;
+
+       nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
+       if (!nacl)
+               return NULL;
+
+       return &nacl->se_node_acl;
+}
+
+static void usbg_release_fabric_acl(
+       struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl)
+{
+       struct usbg_nacl *nacl = container_of(se_nacl,
+                       struct usbg_nacl, se_node_acl);
+       kfree(nacl);
+}
+
+static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static void usbg_cmd_release(struct kref *ref)
+{
+       struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
+                       ref);
+
+       transport_generic_free_cmd(&cmd->se_cmd, 0);
+}
+
+static void usbg_release_cmd(struct se_cmd *se_cmd)
+{
+       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+                       se_cmd);
+       kfree(cmd->data_buf);
+       kfree(cmd);
+       return;
+}
+
+static int usbg_shutdown_session(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static void usbg_close_session(struct se_session *se_sess)
+{
+       return;
+}
+
+static u32 usbg_sess_get_index(struct se_session *se_sess)
+{
+       return 0;
+}
+
+/*
+ * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
+ */
+static int usbg_write_pending_status(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
+{
+       return;
+}
+
+static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
+{
+       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+                       se_cmd);
+       struct f_uas *fu = cmd->fu;
+
+       if (fu->flags & USBG_IS_BOT)
+               return le32_to_cpu(cmd->bot_tag);
+       else
+               return cmd->tag;
+}
+
+static int usbg_get_cmd_state(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+}
+
+static void usbg_aborted_task(struct se_cmd *se_cmd)
+{
+       return;
+}
+
+static const char *usbg_check_wwn(const char *name)
+{
+       const char *n;
+       unsigned int len;
+
+       n = strstr(name, "naa.");
+       if (!n)
+               return NULL;
+       n += 4;
+       len = strlen(n);
+       if (len == 0 || len > USBG_NAMELEN - 1)
+               return NULL;
+       return n;
+}
+
+static struct se_node_acl *usbg_make_nodeacl(
+       struct se_portal_group *se_tpg,
+       struct config_group *group,
+       const char *name)
+{
+       struct se_node_acl *se_nacl, *se_nacl_new;
+       struct usbg_nacl *nacl;
+       u64 wwpn = 0;
+       u32 nexus_depth;
+       const char *wnn_name;
+
+       wnn_name = usbg_check_wwn(name);
+       if (!wnn_name)
+               return ERR_PTR(-EINVAL);
+       se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
+       if (!(se_nacl_new))
+               return ERR_PTR(-ENOMEM);
+
+       nexus_depth = 1;
+       /*
+        * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+        * when converting a NodeACL from demo mode -> explict
+        */
+       se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+                               name, nexus_depth);
+       if (IS_ERR(se_nacl)) {
+               usbg_release_fabric_acl(se_tpg, se_nacl_new);
+               return se_nacl;
+       }
+       /*
+        * Locate our struct usbg_nacl and set the FC Nport WWPN
+        */
+       nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
+       nacl->iport_wwpn = wwpn;
+       snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
+       return se_nacl;
+}
+
+static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
+{
+       struct usbg_nacl *nacl = container_of(se_acl,
+                               struct usbg_nacl, se_node_acl);
+       core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+       kfree(nacl);
+}
+
+struct usbg_tpg *the_only_tpg_I_currently_have;
+
+static struct se_portal_group *usbg_make_tpg(
+       struct se_wwn *wwn,
+       struct config_group *group,
+       const char *name)
+{
+       struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
+                       tport_wwn);
+       struct usbg_tpg *tpg;
+       unsigned long tpgt;
+       int ret;
+
+       if (strstr(name, "tpgt_") != name)
+               return ERR_PTR(-EINVAL);
+       if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
+               return ERR_PTR(-EINVAL);
+       if (the_only_tpg_I_currently_have) {
+               pr_err("Until the gadget framework can't handle multiple\n");
+               pr_err("gadgets, you can't do this here.\n");
+               return ERR_PTR(-EBUSY);
+       }
+
+       tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
+       if (!tpg)
+               return ERR_PTR(-ENOMEM);
+       mutex_init(&tpg->tpg_mutex);
+       atomic_set(&tpg->tpg_port_count, 0);
+       tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
+       if (!tpg->workqueue) {
+               kfree(tpg);
+               return NULL;
+       }
+
+       tpg->tport = tport;
+       tpg->tport_tpgt = tpgt;
+
+       ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
+                               &tpg->se_tpg, tpg,
+                               TRANSPORT_TPG_TYPE_NORMAL);
+       if (ret < 0) {
+               destroy_workqueue(tpg->workqueue);
+               kfree(tpg);
+               return NULL;
+       }
+       the_only_tpg_I_currently_have = tpg;
+       return &tpg->se_tpg;
+}
+
+static void usbg_drop_tpg(struct se_portal_group *se_tpg)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg,
+                               struct usbg_tpg, se_tpg);
+
+       core_tpg_deregister(se_tpg);
+       destroy_workqueue(tpg->workqueue);
+       kfree(tpg);
+       the_only_tpg_I_currently_have = NULL;
+}
+
+static struct se_wwn *usbg_make_tport(
+       struct target_fabric_configfs *tf,
+       struct config_group *group,
+       const char *name)
+{
+       struct usbg_tport *tport;
+       const char *wnn_name;
+       u64 wwpn = 0;
+
+       wnn_name = usbg_check_wwn(name);
+       if (!wnn_name)
+               return ERR_PTR(-EINVAL);
+
+       tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
+       if (!(tport))
+               return ERR_PTR(-ENOMEM);
+       tport->tport_wwpn = wwpn;
+       snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);
+       return &tport->tport_wwn;
+}
+
+static void usbg_drop_tport(struct se_wwn *wwn)
+{
+       struct usbg_tport *tport = container_of(wwn,
+                               struct usbg_tport, tport_wwn);
+       kfree(tport);
+}
+
+/*
+ * If somebody feels like dropping the version property, go ahead.
+ */
+static ssize_t usbg_wwn_show_attr_version(
+       struct target_fabric_configfs *tf,
+       char *page)
+{
+       return sprintf(page, "usb-gadget fabric module\n");
+}
+TF_WWN_ATTR_RO(usbg, version);
+
+static struct configfs_attribute *usbg_wwn_attrs[] = {
+       &usbg_wwn_version.attr,
+       NULL,
+};
+
+static ssize_t tcm_usbg_tpg_show_enable(
+               struct se_portal_group *se_tpg,
+               char *page)
+{
+       struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+       return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
+}
+
+static int usbg_attach(struct usbg_tpg *);
+static void usbg_detach(struct usbg_tpg *);
+
+static ssize_t tcm_usbg_tpg_store_enable(
+               struct se_portal_group *se_tpg,
+               const char *page,
+               size_t count)
+{
+       struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+       unsigned long op;
+       ssize_t ret;
+
+       ret = kstrtoul(page, 0, &op);
+       if (ret < 0)
+               return -EINVAL;
+       if (op > 1)
+               return -EINVAL;
+
+       if (op && tpg->gadget_connect)
+               goto out;
+       if (!op && !tpg->gadget_connect)
+               goto out;
+
+       if (op) {
+               ret = usbg_attach(tpg);
+               if (ret)
+                       goto out;
+       } else {
+               usbg_detach(tpg);
+       }
+       tpg->gadget_connect = op;
+out:
+       return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
+
+static ssize_t tcm_usbg_tpg_show_nexus(
+               struct se_portal_group *se_tpg,
+               char *page)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+       struct tcm_usbg_nexus *tv_nexus;
+       ssize_t ret;
+
+       mutex_lock(&tpg->tpg_mutex);
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus) {
+               ret = -ENODEV;
+               goto out;
+       }
+       ret = snprintf(page, PAGE_SIZE, "%s\n",
+                       tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+out:
+       mutex_unlock(&tpg->tpg_mutex);
+       return ret;
+}
+
+static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
+{
+       struct se_portal_group *se_tpg;
+       struct tcm_usbg_nexus *tv_nexus;
+       int ret;
+
+       mutex_lock(&tpg->tpg_mutex);
+       if (tpg->tpg_nexus) {
+               ret = -EEXIST;
+               pr_debug("tpg->tpg_nexus already exists\n");
+               goto err_unlock;
+       }
+       se_tpg = &tpg->se_tpg;
+
+       ret = -ENOMEM;
+       tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
+       if (!tv_nexus)
+               goto err_unlock;
+       tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);
+       if (IS_ERR(tv_nexus->tvn_se_sess))
+               goto err_free;
+
+       /*
+        * Since we are running in 'demo mode' this call with generate a
+        * struct se_node_acl for the tcm_vhost struct se_portal_group with
+        * the SCSI Initiator port name of the passed configfs group 'name'.
+        */
+       tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+                       se_tpg, name);
+       if (!tv_nexus->tvn_se_sess->se_node_acl) {
+               pr_debug("core_tpg_check_initiator_node_acl() failed"
+                               " for %s\n", name);
+               goto err_session;
+       }
+       /*
+        * Now register the TCM vHost virtual I_T Nexus as active with the
+        * call to __transport_register_session()
+        */
+       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+                       tv_nexus->tvn_se_sess, tv_nexus);
+       tpg->tpg_nexus = tv_nexus;
+       mutex_unlock(&tpg->tpg_mutex);
+       return 0;
+
+err_session:
+       transport_free_session(tv_nexus->tvn_se_sess);
+err_free:
+       kfree(tv_nexus);
+err_unlock:
+       mutex_unlock(&tpg->tpg_mutex);
+       return ret;
+}
+
+static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
+{
+       struct se_session *se_sess;
+       struct tcm_usbg_nexus *tv_nexus;
+       int ret = -ENODEV;
+
+       mutex_lock(&tpg->tpg_mutex);
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus)
+               goto out;
+
+       se_sess = tv_nexus->tvn_se_sess;
+       if (!se_sess)
+               goto out;
+
+       if (atomic_read(&tpg->tpg_port_count)) {
+               ret = -EPERM;
+               pr_err("Unable to remove Host I_T Nexus with"
+                               " active TPG port count: %d\n",
+                               atomic_read(&tpg->tpg_port_count));
+               goto out;
+       }
+
+       pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
+                       tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+       /*
+        * Release the SCSI I_T Nexus to the emulated vHost Target Port
+        */
+       transport_deregister_session(tv_nexus->tvn_se_sess);
+       tpg->tpg_nexus = NULL;
+
+       kfree(tv_nexus);
+       ret = 0;
+out:
+       mutex_unlock(&tpg->tpg_mutex);
+       return ret;
+}
+
+static ssize_t tcm_usbg_tpg_store_nexus(
+               struct se_portal_group *se_tpg,
+               const char *page,
+               size_t count)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+       unsigned char i_port[USBG_NAMELEN], *ptr;
+       int ret;
+
+       if (!strncmp(page, "NULL", 4)) {
+               ret = tcm_usbg_drop_nexus(tpg);
+               return (!ret) ? count : ret;
+       }
+       if (strlen(page) >= USBG_NAMELEN) {
+               pr_err("Emulated NAA Sas Address: %s, exceeds"
+                               " max: %d\n", page, USBG_NAMELEN);
+               return -EINVAL;
+       }
+       snprintf(i_port, USBG_NAMELEN, "%s", page);
+
+       ptr = strstr(i_port, "naa.");
+       if (!ptr) {
+               pr_err("Missing 'naa.' prefix\n");
+               return -EINVAL;
+       }
+
+       if (i_port[strlen(i_port) - 1] == '\n')
+               i_port[strlen(i_port) - 1] = '\0';
+
+       ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
+       if (ret < 0)
+               return ret;
+       return count;
+}
+TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *usbg_base_attrs[] = {
+       &tcm_usbg_tpg_enable.attr,
+       &tcm_usbg_tpg_nexus.attr,
+       NULL,
+};
+
+static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+       atomic_inc(&tpg->tpg_port_count);
+       smp_mb__after_atomic();
+       return 0;
+}
+
+static void usbg_port_unlink(struct se_portal_group *se_tpg,
+               struct se_lun *se_lun)
+{
+       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
+
+       atomic_dec(&tpg->tpg_port_count);
+       smp_mb__after_atomic();
+}
+
+static int usbg_check_stop_free(struct se_cmd *se_cmd)
+{
+       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
+                       se_cmd);
+
+       kref_put(&cmd->ref, usbg_cmd_release);
+       return 1;
+}
+
+static struct target_core_fabric_ops usbg_ops = {
+       .get_fabric_name                = usbg_get_fabric_name,
+       .get_fabric_proto_ident         = usbg_get_fabric_proto_ident,
+       .tpg_get_wwn                    = usbg_get_fabric_wwn,
+       .tpg_get_tag                    = usbg_get_tag,
+       .tpg_get_default_depth          = usbg_get_default_depth,
+       .tpg_get_pr_transport_id        = usbg_get_pr_transport_id,
+       .tpg_get_pr_transport_id_len    = usbg_get_pr_transport_id_len,
+       .tpg_parse_pr_out_transport_id  = usbg_parse_pr_out_transport_id,
+       .tpg_check_demo_mode            = usbg_check_true,
+       .tpg_check_demo_mode_cache      = usbg_check_false,
+       .tpg_check_demo_mode_write_protect = usbg_check_false,
+       .tpg_check_prod_mode_write_protect = usbg_check_false,
+       .tpg_alloc_fabric_acl           = usbg_alloc_fabric_acl,
+       .tpg_release_fabric_acl         = usbg_release_fabric_acl,
+       .tpg_get_inst_index             = usbg_tpg_get_inst_index,
+       .release_cmd                    = usbg_release_cmd,
+       .shutdown_session               = usbg_shutdown_session,
+       .close_session                  = usbg_close_session,
+       .sess_get_index                 = usbg_sess_get_index,
+       .sess_get_initiator_sid         = NULL,
+       .write_pending                  = usbg_send_write_request,
+       .write_pending_status           = usbg_write_pending_status,
+       .set_default_node_attributes    = usbg_set_default_node_attrs,
+       .get_task_tag                   = usbg_get_task_tag,
+       .get_cmd_state                  = usbg_get_cmd_state,
+       .queue_data_in                  = usbg_send_read_response,
+       .queue_status                   = usbg_send_status_response,
+       .queue_tm_rsp                   = usbg_queue_tm_rsp,
+       .aborted_task                   = usbg_aborted_task,
+       .check_stop_free                = usbg_check_stop_free,
+
+       .fabric_make_wwn                = usbg_make_tport,
+       .fabric_drop_wwn                = usbg_drop_tport,
+       .fabric_make_tpg                = usbg_make_tpg,
+       .fabric_drop_tpg                = usbg_drop_tpg,
+       .fabric_post_link               = usbg_port_link,
+       .fabric_pre_unlink              = usbg_port_unlink,
+       .fabric_make_np                 = NULL,
+       .fabric_drop_np                 = NULL,
+       .fabric_make_nodeacl            = usbg_make_nodeacl,
+       .fabric_drop_nodeacl            = usbg_drop_nodeacl,
+};
+
+static int usbg_register_configfs(void)
+{
+       struct target_fabric_configfs *fabric;
+       int ret;
+
+       fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
+       if (IS_ERR(fabric)) {
+               printk(KERN_ERR "target_fabric_configfs_init() failed\n");
+               return PTR_ERR(fabric);
+       }
+
+       fabric->tf_ops = usbg_ops;
+       fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
+       fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
+       fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+       fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+       ret = target_fabric_configfs_register(fabric);
+       if (ret < 0) {
+               printk(KERN_ERR "target_fabric_configfs_register() failed"
+                               " for usb-gadget\n");
+               return ret;
+       }
+       usbg_fabric_configfs = fabric;
+       return 0;
+};
+
+static void usbg_deregister_configfs(void)
+{
+       if (!(usbg_fabric_configfs))
+               return;
+
+       target_fabric_configfs_deregister(usbg_fabric_configfs);
+       usbg_fabric_configfs = NULL;
+};
+
+/* Start gadget.c code */
+
+static struct usb_interface_descriptor bot_intf_desc = {
+       .bLength =              sizeof(bot_intf_desc),
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bNumEndpoints =        2,
+       .bAlternateSetting =    USB_G_ALT_INT_BBB,
+       .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
+       .bInterfaceSubClass =   USB_SC_SCSI,
+       .bInterfaceProtocol =   USB_PR_BULK,
+};
+
+static struct usb_interface_descriptor uasp_intf_desc = {
+       .bLength =              sizeof(uasp_intf_desc),
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bNumEndpoints =        4,
+       .bAlternateSetting =    USB_G_ALT_INT_UAS,
+       .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
+       .bInterfaceSubClass =   USB_SC_SCSI,
+       .bInterfaceProtocol =   USB_PR_UAS,
+};
+
+static struct usb_endpoint_descriptor uasp_bi_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
+       .bLength =              sizeof(uasp_bi_pipe_desc),
+       .bDescriptorType =      USB_DT_PIPE_USAGE,
+       .bPipeID =              DATA_IN_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
+       .bLength =              sizeof(uasp_bi_ep_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+       .bmAttributes =         UASP_SS_EP_COMP_LOG_STREAMS,
+       .wBytesPerInterval =    0,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
+       .bLength =              sizeof(bot_bi_ep_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bMaxBurst =            0,
+};
+
+static struct usb_endpoint_descriptor uasp_bo_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
+       .bLength =              sizeof(uasp_bo_pipe_desc),
+       .bDescriptorType =      USB_DT_PIPE_USAGE,
+       .bPipeID =              DATA_OUT_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(0x400),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
+       .bLength =              sizeof(uasp_bo_ep_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bmAttributes =         UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
+       .bLength =              sizeof(bot_bo_ep_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_endpoint_descriptor uasp_status_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_status_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
+       .bLength =              sizeof(uasp_status_pipe_desc),
+       .bDescriptorType =      USB_DT_PIPE_USAGE,
+       .bPipeID =              STATUS_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_status_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_IN,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
+       .bLength =              sizeof(uasp_status_in_ep_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+       .bmAttributes =         UASP_SS_EP_COMP_LOG_STREAMS,
+};
+
+static struct usb_endpoint_descriptor uasp_cmd_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
+       .bLength =              sizeof(uasp_cmd_pipe_desc),
+       .bDescriptorType =      USB_DT_PIPE_USAGE,
+       .bPipeID =              CMD_PIPE_ID,
+};
+
+static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize =       cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
+       .bLength =              sizeof(uasp_cmd_comp_desc),
+       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *uasp_fs_function_desc[] = {
+       (struct usb_descriptor_header *) &bot_intf_desc,
+       (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+       (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+
+       (struct usb_descriptor_header *) &uasp_intf_desc,
+       (struct usb_descriptor_header *) &uasp_fs_bi_desc,
+       (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_fs_bo_desc,
+       (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_fs_status_desc,
+       (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
+       (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+       NULL,
+};
+
+static struct usb_descriptor_header *uasp_hs_function_desc[] = {
+       (struct usb_descriptor_header *) &bot_intf_desc,
+       (struct usb_descriptor_header *) &uasp_bi_desc,
+       (struct usb_descriptor_header *) &uasp_bo_desc,
+
+       (struct usb_descriptor_header *) &uasp_intf_desc,
+       (struct usb_descriptor_header *) &uasp_bi_desc,
+       (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_bo_desc,
+       (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_status_desc,
+       (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_cmd_desc,
+       (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+       NULL,
+};
+
+static struct usb_descriptor_header *uasp_ss_function_desc[] = {
+       (struct usb_descriptor_header *) &bot_intf_desc,
+       (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+       (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
+       (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+       (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
+
+       (struct usb_descriptor_header *) &uasp_intf_desc,
+       (struct usb_descriptor_header *) &uasp_ss_bi_desc,
+       (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
+       (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_ss_bo_desc,
+       (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
+       (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_ss_status_desc,
+       (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
+       (struct usb_descriptor_header *) &uasp_status_pipe_desc,
+       (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
+       (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
+       (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
+       NULL,
+};
+
+#define UAS_VENDOR_ID  0x0525  /* NetChip */
+#define UAS_PRODUCT_ID 0xa4a5  /* Linux-USB File-backed Storage Gadget */
+
+static struct usb_device_descriptor usbg_device_desc = {
+       .bLength =              sizeof(usbg_device_desc),
+       .bDescriptorType =      USB_DT_DEVICE,
+       .bcdUSB =               cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+       .idVendor =             cpu_to_le16(UAS_VENDOR_ID),
+       .idProduct =            cpu_to_le16(UAS_PRODUCT_ID),
+       .bNumConfigurations =   1,
+};
+
+static struct usb_string       usbg_us_strings[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor",
+       [USB_GADGET_PRODUCT_IDX].s      = "Target Product",
+       [USB_GADGET_SERIAL_IDX].s       = "000000000001",
+       [USB_G_STR_CONFIG].s            = "default config",
+       [USB_G_STR_INT_UAS].s           = "USB Attached SCSI",
+       [USB_G_STR_INT_BBB].s           = "Bulk Only Transport",
+       { },
+};
+
+static struct usb_gadget_strings usbg_stringtab = {
+       .language = 0x0409,
+       .strings = usbg_us_strings,
+};
+
+static struct usb_gadget_strings *usbg_strings[] = {
+       &usbg_stringtab,
+       NULL,
+};
+
+static int guas_unbind(struct usb_composite_dev *cdev)
+{
+       return 0;
+}
+
+static struct usb_configuration usbg_config_driver = {
+       .label                  = "Linux Target",
+       .bConfigurationValue    = 1,
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+static void give_back_ep(struct usb_ep **pep)
+{
+       struct usb_ep *ep = *pep;
+       if (!ep)
+               return;
+       ep->driver_data = NULL;
+}
+
+static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct f_uas            *fu = to_f_uas(f);
+       struct usb_gadget       *gadget = c->cdev->gadget;
+       struct usb_ep           *ep;
+       int                     iface;
+       int                     ret;
+
+       iface = usb_interface_id(c, f);
+       if (iface < 0)
+               return iface;
+
+       bot_intf_desc.bInterfaceNumber = iface;
+       uasp_intf_desc.bInterfaceNumber = iface;
+       fu->iface = iface;
+       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
+                       &uasp_bi_ep_comp_desc);
+       if (!ep)
+               goto ep_fail;
+
+       ep->driver_data = fu;
+       fu->ep_in = ep;
+
+       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
+                       &uasp_bo_ep_comp_desc);
+       if (!ep)
+               goto ep_fail;
+       ep->driver_data = fu;
+       fu->ep_out = ep;
+
+       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
+                       &uasp_status_in_ep_comp_desc);
+       if (!ep)
+               goto ep_fail;
+       ep->driver_data = fu;
+       fu->ep_status = ep;
+
+       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
+                       &uasp_cmd_comp_desc);
+       if (!ep)
+               goto ep_fail;
+       ep->driver_data = fu;
+       fu->ep_cmd = ep;
+
+       /* Assume endpoint addresses are the same for both speeds */
+       uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+       uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+       uasp_status_desc.bEndpointAddress =
+               uasp_ss_status_desc.bEndpointAddress;
+       uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+       uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
+       uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
+       uasp_fs_status_desc.bEndpointAddress =
+               uasp_ss_status_desc.bEndpointAddress;
+       uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
+
+       ret = usb_assign_descriptors(f, uasp_fs_function_desc,
+                       uasp_hs_function_desc, uasp_ss_function_desc);
+       if (ret)
+               goto ep_fail;
+
+       return 0;
+ep_fail:
+       pr_err("Can't claim all required eps\n");
+
+       give_back_ep(&fu->ep_in);
+       give_back_ep(&fu->ep_out);
+       give_back_ep(&fu->ep_status);
+       give_back_ep(&fu->ep_cmd);
+       return -ENOTSUPP;
+}
+
+static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct f_uas *fu = to_f_uas(f);
+
+       usb_free_all_descriptors(f);
+       kfree(fu);
+}
+
+struct guas_setup_wq {
+       struct work_struct work;
+       struct f_uas *fu;
+       unsigned int alt;
+};
+
+static void usbg_delayed_set_alt(struct work_struct *wq)
+{
+       struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
+                       work);
+       struct f_uas *fu = work->fu;
+       int alt = work->alt;
+
+       kfree(work);
+
+       if (fu->flags & USBG_IS_BOT)
+               bot_cleanup_old_alt(fu);
+       if (fu->flags & USBG_IS_UAS)
+               uasp_cleanup_old_alt(fu);
+
+       if (alt == USB_G_ALT_INT_BBB)
+               bot_set_alt(fu);
+       else if (alt == USB_G_ALT_INT_UAS)
+               uasp_set_alt(fu);
+       usb_composite_setup_continue(fu->function.config->cdev);
+}
+
+static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+       struct f_uas *fu = to_f_uas(f);
+
+       if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
+               struct guas_setup_wq *work;
+
+               work = kmalloc(sizeof(*work), GFP_ATOMIC);
+               if (!work)
+                       return -ENOMEM;
+               INIT_WORK(&work->work, usbg_delayed_set_alt);
+               work->fu = fu;
+               work->alt = alt;
+               schedule_work(&work->work);
+               return USB_GADGET_DELAYED_STATUS;
+       }
+       return -EOPNOTSUPP;
+}
+
+static void usbg_disable(struct usb_function *f)
+{
+       struct f_uas *fu = to_f_uas(f);
+
+       if (fu->flags & USBG_IS_UAS)
+               uasp_cleanup_old_alt(fu);
+       else if (fu->flags & USBG_IS_BOT)
+               bot_cleanup_old_alt(fu);
+       fu->flags = 0;
+}
+
+static int usbg_setup(struct usb_function *f,
+               const struct usb_ctrlrequest *ctrl)
+{
+       struct f_uas *fu = to_f_uas(f);
+
+       if (!(fu->flags & USBG_IS_BOT))
+               return -EOPNOTSUPP;
+
+       return usbg_bot_setup(f, ctrl);
+}
+
+static int usbg_cfg_bind(struct usb_configuration *c)
+{
+       struct f_uas *fu;
+       int ret;
+
+       fu = kzalloc(sizeof(*fu), GFP_KERNEL);
+       if (!fu)
+               return -ENOMEM;
+       fu->function.name = "Target Function";
+       fu->function.bind = usbg_bind;
+       fu->function.unbind = usbg_unbind;
+       fu->function.set_alt = usbg_set_alt;
+       fu->function.setup = usbg_setup;
+       fu->function.disable = usbg_disable;
+       fu->tpg = the_only_tpg_I_currently_have;
+
+       bot_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_BBB].id;
+       uasp_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_UAS].id;
+
+       ret = usb_add_function(c, &fu->function);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       kfree(fu);
+       return ret;
+}
+
+static int usb_target_bind(struct usb_composite_dev *cdev)
+{
+       int ret;
+
+       ret = usb_string_ids_tab(cdev, usbg_us_strings);
+       if (ret)
+               return ret;
+
+       usbg_device_desc.iManufacturer =
+               usbg_us_strings[USB_GADGET_MANUFACTURER_IDX].id;
+       usbg_device_desc.iProduct = usbg_us_strings[USB_GADGET_PRODUCT_IDX].id;
+       usbg_device_desc.iSerialNumber =
+               usbg_us_strings[USB_GADGET_SERIAL_IDX].id;
+       usbg_config_driver.iConfiguration =
+               usbg_us_strings[USB_G_STR_CONFIG].id;
+
+       ret = usb_add_config(cdev, &usbg_config_driver,
+                       usbg_cfg_bind);
+       if (ret)
+               return ret;
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       return 0;
+}
+
+static __refdata struct usb_composite_driver usbg_driver = {
+       .name           = "g_target",
+       .dev            = &usbg_device_desc,
+       .strings        = usbg_strings,
+       .max_speed      = USB_SPEED_SUPER,
+       .bind           = usb_target_bind,
+       .unbind         = guas_unbind,
+};
+
+static int usbg_attach(struct usbg_tpg *tpg)
+{
+       return usb_composite_probe(&usbg_driver);
+}
+
+static void usbg_detach(struct usbg_tpg *tpg)
+{
+       usb_composite_unregister(&usbg_driver);
+}
+
+static int __init usb_target_gadget_init(void)
+{
+       int ret;
+
+       ret = usbg_register_configfs();
+       return ret;
+}
+module_init(usb_target_gadget_init);
+
+static void __exit usb_target_gadget_exit(void)
+{
+       usbg_deregister_configfs();
+}
+module_exit(usb_target_gadget_exit);
+
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
+MODULE_DESCRIPTION("usb-gadget fabric");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.h b/drivers/usb/gadget/legacy/tcm_usb_gadget.h
new file mode 100644 (file)
index 0000000..8289219
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef __TARGET_USB_GADGET_H__
+#define __TARGET_USB_GADGET_H__
+
+#include <linux/kref.h>
+/* #include <linux/usb/uas.h> */
+#include <linux/usb/composite.h>
+#include <linux/usb/uas.h>
+#include <linux/usb/storage.h>
+#include <scsi/scsi.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#define USBG_NAMELEN 32
+
+#define fuas_to_gadget(f)      (f->function.config->cdev->gadget)
+#define UASP_SS_EP_COMP_LOG_STREAMS 4
+#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
+
+enum {
+       USB_G_STR_CONFIG = USB_GADGET_FIRST_AVAIL_IDX,
+       USB_G_STR_INT_UAS,
+       USB_G_STR_INT_BBB,
+};
+
+#define USB_G_ALT_INT_BBB       0
+#define USB_G_ALT_INT_UAS       1
+
+struct usbg_nacl {
+       /* Binary World Wide unique Port Name for SAS Initiator port */
+       u64 iport_wwpn;
+       /* ASCII formatted WWPN for Sas Initiator port */
+       char iport_name[USBG_NAMELEN];
+       /* Returned by usbg_make_nodeacl() */
+       struct se_node_acl se_node_acl;
+};
+
+struct tcm_usbg_nexus {
+       struct se_session *tvn_se_sess;
+};
+
+struct usbg_tpg {
+       struct mutex tpg_mutex;
+       /* SAS port target portal group tag for TCM */
+       u16 tport_tpgt;
+       /* Pointer back to usbg_tport */
+       struct usbg_tport *tport;
+       struct workqueue_struct *workqueue;
+       /* Returned by usbg_make_tpg() */
+       struct se_portal_group se_tpg;
+       u32 gadget_connect;
+       struct tcm_usbg_nexus *tpg_nexus;
+       atomic_t tpg_port_count;
+};
+
+struct usbg_tport {
+       /* SCSI protocol the tport is providing */
+       u8 tport_proto_id;
+       /* Binary World Wide unique Port Name for SAS Target port */
+       u64 tport_wwpn;
+       /* ASCII formatted WWPN for SAS Target port */
+       char tport_name[USBG_NAMELEN];
+       /* Returned by usbg_make_tport() */
+       struct se_wwn tport_wwn;
+};
+
+enum uas_state {
+       UASP_SEND_DATA,
+       UASP_RECEIVE_DATA,
+       UASP_SEND_STATUS,
+       UASP_QUEUE_COMMAND,
+};
+
+#define USBG_MAX_CMD    64
+struct usbg_cmd {
+       /* common */
+       u8 cmd_buf[USBG_MAX_CMD];
+       u32 data_len;
+       struct work_struct work;
+       int unpacked_lun;
+       struct se_cmd se_cmd;
+       void *data_buf; /* used if no sg support available */
+       struct f_uas *fu;
+       struct completion write_complete;
+       struct kref ref;
+
+       /* UAS only */
+       u16 tag;
+       u16 prio_attr;
+       struct sense_iu sense_iu;
+       enum uas_state state;
+       struct uas_stream *stream;
+
+       /* BOT only */
+       __le32 bot_tag;
+       unsigned int csw_code;
+       unsigned is_read:1;
+
+};
+
+struct uas_stream {
+       struct usb_request      *req_in;
+       struct usb_request      *req_out;
+       struct usb_request      *req_status;
+};
+
+struct usbg_cdb {
+       struct usb_request      *req;
+       void                    *buf;
+};
+
+struct bot_status {
+       struct usb_request      *req;
+       struct bulk_cs_wrap     csw;
+};
+
+struct f_uas {
+       struct usbg_tpg         *tpg;
+       struct usb_function     function;
+       u16                     iface;
+
+       u32                     flags;
+#define USBG_ENABLED           (1 << 0)
+#define USBG_IS_UAS            (1 << 1)
+#define USBG_USE_STREAMS       (1 << 2)
+#define USBG_IS_BOT            (1 << 3)
+#define USBG_BOT_CMD_PEND      (1 << 4)
+
+       struct usbg_cdb         cmd;
+       struct usb_ep           *ep_in;
+       struct usb_ep           *ep_out;
+
+       /* UAS */
+       struct usb_ep           *ep_status;
+       struct usb_ep           *ep_cmd;
+       struct uas_stream       stream[UASP_SS_EP_COMP_NUM_STREAMS];
+
+       /* BOT */
+       struct bot_status       bot_status;
+       struct usb_request      *bot_req_in;
+       struct usb_request      *bot_req_out;
+};
+
+extern struct usbg_tpg *the_only_tpg_I_currently_have;
+
+#endif
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
new file mode 100644 (file)
index 0000000..a11d8e4
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ *     webcam.c -- USB webcam gadget driver
+ *
+ *     Copyright (C) 2009-2010
+ *         Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/usb/video.h>
+
+#include "f_uvc.h"
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "uvc_queue.c"
+#include "uvc_video.c"
+#include "uvc_v4l2.c"
+#include "f_uvc.c"
+
+USB_GADGET_COMPOSITE_OPTIONS();
+/* --------------------------------------------------------------------------
+ * Device descriptor
+ */
+
+#define WEBCAM_VENDOR_ID               0x1d6b  /* Linux Foundation */
+#define WEBCAM_PRODUCT_ID              0x0102  /* Webcam A/V gadget */
+#define WEBCAM_DEVICE_BCD              0x0010  /* 0.10 */
+
+static char webcam_vendor_label[] = "Linux Foundation";
+static char webcam_product_label[] = "Webcam gadget";
+static char webcam_config_label[] = "Video";
+
+/* string IDs are assigned dynamically */
+
+#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
+
+static struct usb_string webcam_strings[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label,
+       [USB_GADGET_PRODUCT_IDX].s = webcam_product_label,
+       [USB_GADGET_SERIAL_IDX].s = "",
+       [STRING_DESCRIPTION_IDX].s = webcam_config_label,
+       {  }
+};
+
+static struct usb_gadget_strings webcam_stringtab = {
+       .language = 0x0409,     /* en-us */
+       .strings = webcam_strings,
+};
+
+static struct usb_gadget_strings *webcam_device_strings[] = {
+       &webcam_stringtab,
+       NULL,
+};
+
+static struct usb_device_descriptor webcam_device_descriptor = {
+       .bLength                = USB_DT_DEVICE_SIZE,
+       .bDescriptorType        = USB_DT_DEVICE,
+       .bcdUSB                 = cpu_to_le16(0x0200),
+       .bDeviceClass           = USB_CLASS_MISC,
+       .bDeviceSubClass        = 0x02,
+       .bDeviceProtocol        = 0x01,
+       .bMaxPacketSize0        = 0, /* dynamic */
+       .idVendor               = cpu_to_le16(WEBCAM_VENDOR_ID),
+       .idProduct              = cpu_to_le16(WEBCAM_PRODUCT_ID),
+       .bcdDevice              = cpu_to_le16(WEBCAM_DEVICE_BCD),
+       .iManufacturer          = 0, /* dynamic */
+       .iProduct               = 0, /* dynamic */
+       .iSerialNumber          = 0, /* dynamic */
+       .bNumConfigurations     = 0, /* dynamic */
+};
+
+DECLARE_UVC_HEADER_DESCRIPTOR(1);
+
+static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
+       .bLength                = UVC_DT_HEADER_SIZE(1),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VC_HEADER,
+       .bcdUVC                 = cpu_to_le16(0x0100),
+       .wTotalLength           = 0, /* dynamic */
+       .dwClockFrequency       = cpu_to_le32(48000000),
+       .bInCollection          = 0, /* dynamic */
+       .baInterfaceNr[0]       = 0, /* dynamic */
+};
+
+static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
+       .bLength                = UVC_DT_CAMERA_TERMINAL_SIZE(3),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VC_INPUT_TERMINAL,
+       .bTerminalID            = 1,
+       .wTerminalType          = cpu_to_le16(0x0201),
+       .bAssocTerminal         = 0,
+       .iTerminal              = 0,
+       .wObjectiveFocalLengthMin       = cpu_to_le16(0),
+       .wObjectiveFocalLengthMax       = cpu_to_le16(0),
+       .wOcularFocalLength             = cpu_to_le16(0),
+       .bControlSize           = 3,
+       .bmControls[0]          = 2,
+       .bmControls[1]          = 0,
+       .bmControls[2]          = 0,
+};
+
+static const struct uvc_processing_unit_descriptor uvc_processing = {
+       .bLength                = UVC_DT_PROCESSING_UNIT_SIZE(2),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VC_PROCESSING_UNIT,
+       .bUnitID                = 2,
+       .bSourceID              = 1,
+       .wMaxMultiplier         = cpu_to_le16(16*1024),
+       .bControlSize           = 2,
+       .bmControls[0]          = 1,
+       .bmControls[1]          = 0,
+       .iProcessing            = 0,
+};
+
+static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
+       .bLength                = UVC_DT_OUTPUT_TERMINAL_SIZE,
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VC_OUTPUT_TERMINAL,
+       .bTerminalID            = 3,
+       .wTerminalType          = cpu_to_le16(0x0101),
+       .bAssocTerminal         = 0,
+       .bSourceID              = 2,
+       .iTerminal              = 0,
+};
+
+DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
+
+static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
+       .bLength                = UVC_DT_INPUT_HEADER_SIZE(1, 2),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_INPUT_HEADER,
+       .bNumFormats            = 2,
+       .wTotalLength           = 0, /* dynamic */
+       .bEndpointAddress       = 0, /* dynamic */
+       .bmInfo                 = 0,
+       .bTerminalLink          = 3,
+       .bStillCaptureMethod    = 0,
+       .bTriggerSupport        = 0,
+       .bTriggerUsage          = 0,
+       .bControlSize           = 1,
+       .bmaControls[0][0]      = 0,
+       .bmaControls[1][0]      = 4,
+};
+
+static const struct uvc_format_uncompressed uvc_format_yuv = {
+       .bLength                = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_FORMAT_UNCOMPRESSED,
+       .bFormatIndex           = 1,
+       .bNumFrameDescriptors   = 2,
+       .guidFormat             =
+               { 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00,
+                0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
+       .bBitsPerPixel          = 16,
+       .bDefaultFrameIndex     = 1,
+       .bAspectRatioX          = 0,
+       .bAspectRatioY          = 0,
+       .bmInterfaceFlags       = 0,
+       .bCopyProtect           = 0,
+};
+
+DECLARE_UVC_FRAME_UNCOMPRESSED(1);
+DECLARE_UVC_FRAME_UNCOMPRESSED(3);
+
+static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
+       .bLength                = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_FRAME_UNCOMPRESSED,
+       .bFrameIndex            = 1,
+       .bmCapabilities         = 0,
+       .wWidth                 = cpu_to_le16(640),
+       .wHeight                = cpu_to_le16(360),
+       .dwMinBitRate           = cpu_to_le32(18432000),
+       .dwMaxBitRate           = cpu_to_le32(55296000),
+       .dwMaxVideoFrameBufferSize      = cpu_to_le32(460800),
+       .dwDefaultFrameInterval = cpu_to_le32(666666),
+       .bFrameIntervalType     = 3,
+       .dwFrameInterval[0]     = cpu_to_le32(666666),
+       .dwFrameInterval[1]     = cpu_to_le32(1000000),
+       .dwFrameInterval[2]     = cpu_to_le32(5000000),
+};
+
+static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
+       .bLength                = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_FRAME_UNCOMPRESSED,
+       .bFrameIndex            = 2,
+       .bmCapabilities         = 0,
+       .wWidth                 = cpu_to_le16(1280),
+       .wHeight                = cpu_to_le16(720),
+       .dwMinBitRate           = cpu_to_le32(29491200),
+       .dwMaxBitRate           = cpu_to_le32(29491200),
+       .dwMaxVideoFrameBufferSize      = cpu_to_le32(1843200),
+       .dwDefaultFrameInterval = cpu_to_le32(5000000),
+       .bFrameIntervalType     = 1,
+       .dwFrameInterval[0]     = cpu_to_le32(5000000),
+};
+
+static const struct uvc_format_mjpeg uvc_format_mjpg = {
+       .bLength                = UVC_DT_FORMAT_MJPEG_SIZE,
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_FORMAT_MJPEG,
+       .bFormatIndex           = 2,
+       .bNumFrameDescriptors   = 2,
+       .bmFlags                = 0,
+       .bDefaultFrameIndex     = 1,
+       .bAspectRatioX          = 0,
+       .bAspectRatioY          = 0,
+       .bmInterfaceFlags       = 0,
+       .bCopyProtect           = 0,
+};
+
+DECLARE_UVC_FRAME_MJPEG(1);
+DECLARE_UVC_FRAME_MJPEG(3);
+
+static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
+       .bLength                = UVC_DT_FRAME_MJPEG_SIZE(3),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_FRAME_MJPEG,
+       .bFrameIndex            = 1,
+       .bmCapabilities         = 0,
+       .wWidth                 = cpu_to_le16(640),
+       .wHeight                = cpu_to_le16(360),
+       .dwMinBitRate           = cpu_to_le32(18432000),
+       .dwMaxBitRate           = cpu_to_le32(55296000),
+       .dwMaxVideoFrameBufferSize      = cpu_to_le32(460800),
+       .dwDefaultFrameInterval = cpu_to_le32(666666),
+       .bFrameIntervalType     = 3,
+       .dwFrameInterval[0]     = cpu_to_le32(666666),
+       .dwFrameInterval[1]     = cpu_to_le32(1000000),
+       .dwFrameInterval[2]     = cpu_to_le32(5000000),
+};
+
+static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
+       .bLength                = UVC_DT_FRAME_MJPEG_SIZE(1),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_FRAME_MJPEG,
+       .bFrameIndex            = 2,
+       .bmCapabilities         = 0,
+       .wWidth                 = cpu_to_le16(1280),
+       .wHeight                = cpu_to_le16(720),
+       .dwMinBitRate           = cpu_to_le32(29491200),
+       .dwMaxBitRate           = cpu_to_le32(29491200),
+       .dwMaxVideoFrameBufferSize      = cpu_to_le32(1843200),
+       .dwDefaultFrameInterval = cpu_to_le32(5000000),
+       .bFrameIntervalType     = 1,
+       .dwFrameInterval[0]     = cpu_to_le32(5000000),
+};
+
+static const struct uvc_color_matching_descriptor uvc_color_matching = {
+       .bLength                = UVC_DT_COLOR_MATCHING_SIZE,
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubType     = UVC_VS_COLORFORMAT,
+       .bColorPrimaries        = 1,
+       .bTransferCharacteristics       = 1,
+       .bMatrixCoefficients    = 4,
+};
+
+static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
+       (const struct uvc_descriptor_header *) &uvc_control_header,
+       (const struct uvc_descriptor_header *) &uvc_camera_terminal,
+       (const struct uvc_descriptor_header *) &uvc_processing,
+       (const struct uvc_descriptor_header *) &uvc_output_terminal,
+       NULL,
+};
+
+static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
+       (const struct uvc_descriptor_header *) &uvc_control_header,
+       (const struct uvc_descriptor_header *) &uvc_camera_terminal,
+       (const struct uvc_descriptor_header *) &uvc_processing,
+       (const struct uvc_descriptor_header *) &uvc_output_terminal,
+       NULL,
+};
+
+static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
+       (const struct uvc_descriptor_header *) &uvc_input_header,
+       (const struct uvc_descriptor_header *) &uvc_format_yuv,
+       (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
+       (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+       (const struct uvc_descriptor_header *) &uvc_format_mjpg,
+       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
+       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+       (const struct uvc_descriptor_header *) &uvc_color_matching,
+       NULL,
+};
+
+static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
+       (const struct uvc_descriptor_header *) &uvc_input_header,
+       (const struct uvc_descriptor_header *) &uvc_format_yuv,
+       (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
+       (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+       (const struct uvc_descriptor_header *) &uvc_format_mjpg,
+       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
+       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+       (const struct uvc_descriptor_header *) &uvc_color_matching,
+       NULL,
+};
+
+static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
+       (const struct uvc_descriptor_header *) &uvc_input_header,
+       (const struct uvc_descriptor_header *) &uvc_format_yuv,
+       (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
+       (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
+       (const struct uvc_descriptor_header *) &uvc_format_mjpg,
+       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
+       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
+       (const struct uvc_descriptor_header *) &uvc_color_matching,
+       NULL,
+};
+
+/* --------------------------------------------------------------------------
+ * USB configuration
+ */
+
+static int __init
+webcam_config_bind(struct usb_configuration *c)
+{
+       return uvc_bind_config(c, uvc_fs_control_cls, uvc_ss_control_cls,
+               uvc_fs_streaming_cls, uvc_hs_streaming_cls,
+               uvc_ss_streaming_cls);
+}
+
+static struct usb_configuration webcam_config_driver = {
+       .label                  = webcam_config_label,
+       .bConfigurationValue    = 1,
+       .iConfiguration         = 0, /* dynamic */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+       .MaxPower               = CONFIG_USB_GADGET_VBUS_DRAW,
+};
+
+static int /* __init_or_exit */
+webcam_unbind(struct usb_composite_dev *cdev)
+{
+       return 0;
+}
+
+static int __init
+webcam_bind(struct usb_composite_dev *cdev)
+{
+       int ret;
+
+       /* Allocate string descriptor numbers ... note that string contents
+        * can be overridden by the composite_dev glue.
+        */
+       ret = usb_string_ids_tab(cdev, webcam_strings);
+       if (ret < 0)
+               goto error;
+       webcam_device_descriptor.iManufacturer =
+               webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
+       webcam_device_descriptor.iProduct =
+               webcam_strings[USB_GADGET_PRODUCT_IDX].id;
+       webcam_config_driver.iConfiguration =
+               webcam_strings[STRING_DESCRIPTION_IDX].id;
+
+       /* Register our configuration. */
+       if ((ret = usb_add_config(cdev, &webcam_config_driver,
+                                       webcam_config_bind)) < 0)
+               goto error;
+
+       usb_composite_overwrite_options(cdev, &coverwrite);
+       INFO(cdev, "Webcam Video Gadget\n");
+       return 0;
+
+error:
+       webcam_unbind(cdev);
+       return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * Driver
+ */
+
+static __refdata struct usb_composite_driver webcam_driver = {
+       .name           = "g_webcam",
+       .dev            = &webcam_device_descriptor,
+       .strings        = webcam_device_strings,
+       .max_speed      = USB_SPEED_SUPER,
+       .bind           = webcam_bind,
+       .unbind         = webcam_unbind,
+};
+
+module_usb_composite_driver(webcam_driver);
+
+MODULE_AUTHOR("Laurent Pinchart");
+MODULE_DESCRIPTION("Webcam Video Gadget");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1.0");
+
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
new file mode 100644 (file)
index 0000000..c3d4968
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * zero.c -- Gadget Zero, for USB development
+ *
+ * Copyright (C) 2003-2008 David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * Gadget Zero only needs two bulk endpoints, and is an example of how you
+ * can write a hardware-agnostic gadget driver running inside a USB device.
+ * Some hardware details are visible, but don't affect most of the driver.
+ *
+ * Use it with the Linux host/master side "usbtest" driver to get a basic
+ * functional test of your device-side usb stack, or with "usb-skeleton".
+ *
+ * It supports two similar configurations.  One sinks whatever the usb host
+ * writes, and in return sources zeroes.  The other loops whatever the host
+ * writes back, so the host can read it.
+ *
+ * Many drivers will only have one configuration, letting them be much
+ * simpler if they also don't support high speed operation (like this
+ * driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions?  To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
+ */
+
+/*
+ * driver assumes self-powered hardware, and
+ * has no way for users to trigger remote wakeup.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/usb/composite.h>
+
+#include "g_zero.h"
+/*-------------------------------------------------------------------------*/
+USB_GADGET_COMPOSITE_OPTIONS();
+
+#define DRIVER_VERSION         "Cinco de Mayo 2008"
+
+static const char longname[] = "Gadget Zero";
+
+/*
+ * Normally the "loopback" configuration is second (index 1) so
+ * it's not the default.  Here's where to change that order, to
+ * work better with hosts where config changes are problematic or
+ * controllers (like original superh) that only support one config.
+ */
+static bool loopdefault = 0;
+module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
+
+static struct usb_zero_options gzero_options = {
+       .isoc_interval = GZERO_ISOC_INTERVAL,
+       .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
+       .bulk_buflen = GZERO_BULK_BUFLEN,
+       .qlen = GZERO_QLEN,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#ifndef        CONFIG_USB_ZERO_HNPTEST
+#define DRIVER_VENDOR_NUM      0x0525          /* NetChip */
+#define DRIVER_PRODUCT_NUM     0xa4a0          /* Linux-USB "Gadget Zero" */
+#define DEFAULT_AUTORESUME     0
+#else
+#define DRIVER_VENDOR_NUM      0x1a0a          /* OTG test device IDs */
+#define DRIVER_PRODUCT_NUM     0xbadd
+#define DEFAULT_AUTORESUME     5
+#endif
+
+/* If the optional "autoresume" mode is enabled, it provides good
+ * functional coverage for the "USBCV" test harness from USB-IF.
+ * It's always set if OTG mode is enabled.
+ */
+static unsigned autoresume = DEFAULT_AUTORESUME;
+module_param(autoresume, uint, S_IRUGO);
+MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
+
+/* Maximum Autoresume time */
+static unsigned max_autoresume;
+module_param(max_autoresume, uint, S_IRUGO);
+MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup");
+
+/* Interval between two remote wakeups */
+static unsigned autoresume_interval_ms;
+module_param(autoresume_interval_ms, uint, S_IRUGO);
+MODULE_PARM_DESC(autoresume_interval_ms,
+               "milliseconds to increase successive wakeup delays");
+
+static unsigned autoresume_step_ms;
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               cpu_to_le16(0x0200),
+       .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
+
+       .idVendor =             cpu_to_le16(DRIVER_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(DRIVER_PRODUCT_NUM),
+       .bNumConfigurations =   2,
+};
+
+#ifdef CONFIG_USB_OTG
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+#else
+#define otg_desc       NULL
+#endif
+
+/* string IDs are assigned dynamically */
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
+
+#define USB_GZERO_SS_DESC      (USB_GADGET_FIRST_AVAIL_IDX + 0)
+#define USB_GZERO_LB_DESC      (USB_GADGET_FIRST_AVAIL_IDX + 1)
+
+static struct usb_string strings_dev[] = {
+       [USB_GADGET_MANUFACTURER_IDX].s = "",
+       [USB_GADGET_PRODUCT_IDX].s = longname,
+       [USB_GADGET_SERIAL_IDX].s = serial,
+       [USB_GZERO_SS_DESC].s   = "source and sink data",
+       [USB_GZERO_LB_DESC].s   = "loop input to output",
+       {  }                    /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static struct timer_list       autoresume_timer;
+
+static void zero_autoresume(unsigned long _c)
+{
+       struct usb_composite_dev        *cdev = (void *)_c;
+       struct usb_gadget               *g = cdev->gadget;
+
+       /* unconfigured devices can't issue wakeups */
+       if (!cdev->config)
+               return;
+
+       /* Normally the host would be woken up for something
+        * more significant than just a timer firing; likely
+        * because of some direct user request.
+        */
+       if (g->speed != USB_SPEED_UNKNOWN) {
+               int status = usb_gadget_wakeup(g);
+               INFO(cdev, "%s --> %d\n", __func__, status);
+       }
+}
+
+static void zero_suspend(struct usb_composite_dev *cdev)
+{
+       if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
+               return;
+
+       if (autoresume) {
+               if (max_autoresume &&
+                       (autoresume_step_ms > max_autoresume * 1000))
+                               autoresume_step_ms = autoresume * 1000;
+
+               mod_timer(&autoresume_timer, jiffies +
+                       msecs_to_jiffies(autoresume_step_ms));
+               DBG(cdev, "suspend, wakeup in %d milliseconds\n",
+                       autoresume_step_ms);
+
+               autoresume_step_ms += autoresume_interval_ms;
+       } else
+               DBG(cdev, "%s\n", __func__);
+}
+
+static void zero_resume(struct usb_composite_dev *cdev)
+{
+       DBG(cdev, "%s\n", __func__);
+       del_timer(&autoresume_timer);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_configuration loopback_driver = {
+       .label          = "loopback",
+       .bConfigurationValue = 2,
+       .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
+       /* .iConfiguration = DYNAMIC */
+};
+
+static struct usb_function *func_ss;
+static struct usb_function_instance *func_inst_ss;
+
+static int ss_config_setup(struct usb_configuration *c,
+               const struct usb_ctrlrequest *ctrl)
+{
+       switch (ctrl->bRequest) {
+       case 0x5b:
+       case 0x5c:
+               return func_ss->setup(func_ss, ctrl);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static struct usb_configuration sourcesink_driver = {
+       .label                  = "source/sink",
+       .setup                  = ss_config_setup,
+       .bConfigurationValue    = 3,
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+       /* .iConfiguration      = DYNAMIC */
+};
+
+module_param_named(buflen, gzero_options.bulk_buflen, uint, 0);
+module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");
+
+module_param_named(isoc_interval, gzero_options.isoc_interval, uint,
+               S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_interval, "1 - 16");
+
+module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint,
+               S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+
+module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
+
+module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
+               S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
+
+static struct usb_function *func_lb;
+static struct usb_function_instance *func_inst_lb;
+
+module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(qlen, "depth of loopback queue");
+
+static int __init zero_bind(struct usb_composite_dev *cdev)
+{
+       struct f_ss_opts        *ss_opts;
+       struct f_lb_opts        *lb_opts;
+       int                     status;
+
+       /* Allocate string descriptor numbers ... note that string
+        * contents can be overridden by the composite_dev glue.
+        */
+       status = usb_string_ids_tab(cdev, strings_dev);
+       if (status < 0)
+               return status;
+
+       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
+       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
+       device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id;
+
+       setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
+
+       func_inst_ss = usb_get_function_instance("SourceSink");
+       if (IS_ERR(func_inst_ss))
+               return PTR_ERR(func_inst_ss);
+
+       ss_opts =  container_of(func_inst_ss, struct f_ss_opts, func_inst);
+       ss_opts->pattern = gzero_options.pattern;
+       ss_opts->isoc_interval = gzero_options.isoc_interval;
+       ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
+       ss_opts->isoc_mult = gzero_options.isoc_mult;
+       ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
+       ss_opts->bulk_buflen = gzero_options.bulk_buflen;
+
+       func_ss = usb_get_function(func_inst_ss);
+       if (IS_ERR(func_ss)) {
+               status = PTR_ERR(func_ss);
+               goto err_put_func_inst_ss;
+       }
+
+       func_inst_lb = usb_get_function_instance("Loopback");
+       if (IS_ERR(func_inst_lb)) {
+               status = PTR_ERR(func_inst_lb);
+               goto err_put_func_ss;
+       }
+
+       lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst);
+       lb_opts->bulk_buflen = gzero_options.bulk_buflen;
+       lb_opts->qlen = gzero_options.qlen;
+
+       func_lb = usb_get_function(func_inst_lb);
+       if (IS_ERR(func_lb)) {
+               status = PTR_ERR(func_lb);
+               goto err_put_func_inst_lb;
+       }
+
+       sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id;
+       loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id;
+
+       /* support autoresume for remote wakeup testing */
+       sourcesink_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
+       loopback_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
+       sourcesink_driver.descriptors = NULL;
+       loopback_driver.descriptors = NULL;
+       if (autoresume) {
+               sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               autoresume_step_ms = autoresume * 1000;
+       }
+
+       /* support OTG systems */
+       if (gadget_is_otg(cdev->gadget)) {
+               sourcesink_driver.descriptors = otg_desc;
+               sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+               loopback_driver.descriptors = otg_desc;
+               loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       /* Register primary, then secondary configuration.  Note that
+        * SH3 only allows one config...
+        */
+       if (loopdefault) {
+               usb_add_config_only(cdev, &loopback_driver);
+               usb_add_config_only(cdev, &sourcesink_driver);
+       } else {
+               usb_add_config_only(cdev, &sourcesink_driver);
+               usb_add_config_only(cdev, &loopback_driver);
+       }
+       status = usb_add_function(&sourcesink_driver, func_ss);
+       if (status)
+               goto err_conf_flb;
+
+       usb_ep_autoconfig_reset(cdev->gadget);
+       status = usb_add_function(&loopback_driver, func_lb);
+       if (status)
+               goto err_conf_flb;
+
+       usb_ep_autoconfig_reset(cdev->gadget);
+       usb_composite_overwrite_options(cdev, &coverwrite);
+
+       INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
+
+       return 0;
+
+err_conf_flb:
+       usb_put_function(func_lb);
+       func_lb = NULL;
+err_put_func_inst_lb:
+       usb_put_function_instance(func_inst_lb);
+       func_inst_lb = NULL;
+err_put_func_ss:
+       usb_put_function(func_ss);
+       func_ss = NULL;
+err_put_func_inst_ss:
+       usb_put_function_instance(func_inst_ss);
+       func_inst_ss = NULL;
+       return status;
+}
+
+static int zero_unbind(struct usb_composite_dev *cdev)
+{
+       del_timer_sync(&autoresume_timer);
+       if (!IS_ERR_OR_NULL(func_ss))
+               usb_put_function(func_ss);
+       usb_put_function_instance(func_inst_ss);
+       if (!IS_ERR_OR_NULL(func_lb))
+               usb_put_function(func_lb);
+       usb_put_function_instance(func_inst_lb);
+       return 0;
+}
+
+static __refdata struct usb_composite_driver zero_driver = {
+       .name           = "zero",
+       .dev            = &device_desc,
+       .strings        = dev_strings,
+       .max_speed      = USB_SPEED_SUPER,
+       .bind           = zero_bind,
+       .unbind         = zero_unbind,
+       .suspend        = zero_suspend,
+       .resume         = zero_resume,
+};
+
+module_usb_composite_driver(zero_driver);
+
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
deleted file mode 100644 (file)
index 8e27a8c..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * mass_storage.c -- Mass Storage USB Gadget
- *
- * Copyright (C) 2003-2008 Alan Stern
- * Copyright (C) 2009 Samsung Electronics
- *                    Author: Michal Nazarewicz <mina86@mina86.com>
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-
-/*
- * The Mass Storage Gadget acts as a USB Mass Storage device,
- * appearing to the host as a disk drive or as a CD-ROM drive.  In
- * addition to providing an example of a genuinely useful gadget
- * driver for a USB device, it also illustrates a technique of
- * double-buffering for increased throughput.  Last but not least, it
- * gives an easy way to probe the behavior of the Mass Storage drivers
- * in a USB host.
- *
- * Since this file serves only administrative purposes and all the
- * business logic is implemented in f_mass_storage.* file.  Read
- * comments in this file for more detailed description.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/usb/ch9.h>
-#include <linux/module.h>
-
-/*-------------------------------------------------------------------------*/
-
-#define DRIVER_DESC            "Mass Storage Gadget"
-#define DRIVER_VERSION         "2009/09/11"
-
-/*
- * Thanks to NetChip Technologies for donating this product ID.
- *
- * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-#define FSG_VENDOR_ID  0x0525  /* NetChip */
-#define FSG_PRODUCT_ID 0xa4a5  /* Linux-USB File-backed Storage Gadget */
-
-#include "f_mass_storage.h"
-
-/*-------------------------------------------------------------------------*/
-USB_GADGET_COMPOSITE_OPTIONS();
-
-static struct usb_device_descriptor msg_device_desc = {
-       .bLength =              sizeof msg_device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16(0x0200),
-       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
-
-       /* Vendor and product id can be overridden by module parameters.  */
-       .idVendor =             cpu_to_le16(FSG_VENDOR_ID),
-       .idProduct =            cpu_to_le16(FSG_PRODUCT_ID),
-       .bNumConfigurations =   1,
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /*
-        * REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-static struct usb_function_instance *fi_msg;
-static struct usb_function *f_msg;
-
-/****************************** Configurations ******************************/
-
-static struct fsg_module_parameters mod_data = {
-       .stall = 1
-};
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
-
-#else
-
-/*
- * Number of buffers we will use.
- * 2 is usually enough for good buffering pipeline
- */
-#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
-
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-
-FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
-
-static unsigned long msg_registered;
-static void msg_cleanup(void);
-
-static int msg_thread_exits(struct fsg_common *common)
-{
-       msg_cleanup();
-       return 0;
-}
-
-static int __init msg_do_config(struct usb_configuration *c)
-{
-       struct fsg_opts *opts;
-       int ret;
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       opts = fsg_opts_from_func_inst(fi_msg);
-
-       f_msg = usb_get_function(fi_msg);
-       if (IS_ERR(f_msg))
-               return PTR_ERR(f_msg);
-
-       ret = fsg_common_run_thread(opts->common);
-       if (ret)
-               goto put_func;
-
-       ret = usb_add_function(c, f_msg);
-       if (ret)
-               goto put_func;
-
-       return 0;
-
-put_func:
-       usb_put_function(f_msg);
-       return ret;
-}
-
-static struct usb_configuration msg_config_driver = {
-       .label                  = "Linux File-Backed Storage",
-       .bConfigurationValue    = 1,
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-
-/****************************** Gadget Bind ******************************/
-
-static int __init msg_bind(struct usb_composite_dev *cdev)
-{
-       static const struct fsg_operations ops = {
-               .thread_exits = msg_thread_exits,
-       };
-       struct fsg_opts *opts;
-       struct fsg_config config;
-       int status;
-
-       fi_msg = usb_get_function_instance("mass_storage");
-       if (IS_ERR(fi_msg))
-               return PTR_ERR(fi_msg);
-
-       fsg_config_from_params(&config, &mod_data, fsg_num_buffers);
-       opts = fsg_opts_from_func_inst(fi_msg);
-
-       opts->no_configfs = true;
-       status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers);
-       if (status)
-               goto fail;
-
-       status = fsg_common_set_nluns(opts->common, config.nluns);
-       if (status)
-               goto fail_set_nluns;
-
-       fsg_common_set_ops(opts->common, &ops);
-
-       status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
-       if (status)
-               goto fail_set_cdev;
-
-       fsg_common_set_sysfs(opts->common, true);
-       status = fsg_common_create_luns(opts->common, &config);
-       if (status)
-               goto fail_set_cdev;
-
-       fsg_common_set_inquiry_string(opts->common, config.vendor_name,
-                                     config.product_name);
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto fail_string_ids;
-       msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
-       if (status < 0)
-               goto fail_string_ids;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       dev_info(&cdev->gadget->dev,
-                DRIVER_DESC ", version: " DRIVER_VERSION "\n");
-       set_bit(0, &msg_registered);
-       return 0;
-
-fail_string_ids:
-       fsg_common_remove_luns(opts->common);
-fail_set_cdev:
-       fsg_common_free_luns(opts->common);
-fail_set_nluns:
-       fsg_common_free_buffers(opts->common);
-fail:
-       usb_put_function_instance(fi_msg);
-       return status;
-}
-
-static int msg_unbind(struct usb_composite_dev *cdev)
-{
-       if (!IS_ERR(f_msg))
-               usb_put_function(f_msg);
-
-       if (!IS_ERR(fi_msg))
-               usb_put_function_instance(fi_msg);
-
-       return 0;
-}
-
-/****************************** Some noise ******************************/
-
-static __refdata struct usb_composite_driver msg_driver = {
-       .name           = "g_mass_storage",
-       .dev            = &msg_device_desc,
-       .max_speed      = USB_SPEED_SUPER,
-       .needs_serial   = 1,
-       .strings        = dev_strings,
-       .bind           = msg_bind,
-       .unbind         = msg_unbind,
-};
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Michal Nazarewicz");
-MODULE_LICENSE("GPL");
-
-static int __init msg_init(void)
-{
-       return usb_composite_probe(&msg_driver);
-}
-module_init(msg_init);
-
-static void msg_cleanup(void)
-{
-       if (test_and_clear_bit(0, &msg_registered))
-               usb_composite_unregister(&msg_driver);
-}
-module_exit(msg_cleanup);
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
deleted file mode 100644 (file)
index 39d27bb..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * multi.c -- Multifunction Composite driver
- *
- * Copyright (C) 2008 David Brownell
- * Copyright (C) 2008 Nokia Corporation
- * Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (mina86@mina86.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-
-#include "u_serial.h"
-#if defined USB_ETH_RNDIS
-#  undef USB_ETH_RNDIS
-#endif
-#ifdef CONFIG_USB_G_MULTI_RNDIS
-#  define USB_ETH_RNDIS y
-#endif
-
-
-#define DRIVER_DESC            "Multifunction Composite Gadget"
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Michal Nazarewicz");
-MODULE_LICENSE("GPL");
-
-
-#include "f_mass_storage.h"
-
-#include "u_ecm.h"
-#ifdef USB_ETH_RNDIS
-#  include "u_rndis.h"
-#  include "rndis.h"
-#endif
-#include "u_ether.h"
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-USB_ETHERNET_MODULE_PARAMETERS();
-
-/***************************** Device Descriptor ****************************/
-
-#define MULTI_VENDOR_NUM       0x1d6b  /* Linux Foundation */
-#define MULTI_PRODUCT_NUM      0x0104  /* Multifunction Composite Gadget */
-
-
-enum {
-       __MULTI_NO_CONFIG,
-#ifdef CONFIG_USB_G_MULTI_RNDIS
-       MULTI_RNDIS_CONFIG_NUM,
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
-       MULTI_CDC_CONFIG_NUM,
-#endif
-};
-
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16(0x0200),
-
-       .bDeviceClass =         USB_CLASS_MISC /* 0xEF */,
-       .bDeviceSubClass =      2,
-       .bDeviceProtocol =      1,
-
-       /* Vendor and product id can be overridden by module parameters.  */
-       .idVendor =             cpu_to_le16(MULTI_VENDOR_NUM),
-       .idProduct =            cpu_to_le16(MULTI_PRODUCT_NUM),
-};
-
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
-               .bLength =              sizeof(struct usb_otg_descriptor),
-               .bDescriptorType =      USB_DT_OTG,
-
-               /*
-                * REVISIT SRP-only hardware is possible, although
-                * it would not be called "OTG" ...
-                */
-               .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-       },
-       NULL,
-};
-
-
-enum {
-       MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX,
-       MULTI_STRING_CDC_CONFIG_IDX,
-};
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
-       [MULTI_STRING_CDC_CONFIG_IDX].s   = "Multifunction with CDC ECM",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &(struct usb_gadget_strings){
-               .language       = 0x0409,       /* en-us */
-               .strings        = strings_dev,
-       },
-       NULL,
-};
-
-
-
-
-/****************************** Configurations ******************************/
-
-static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-
-static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
-
-#else
-
-/*
- * Number of buffers we will use.
- * 2 is usually enough for good buffering pipeline
- */
-#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
-
-#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-
-FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
-
-static struct usb_function_instance *fi_acm;
-static struct usb_function_instance *fi_msg;
-
-/********** RNDIS **********/
-
-#ifdef USB_ETH_RNDIS
-static struct usb_function_instance *fi_rndis;
-static struct usb_function *f_acm_rndis;
-static struct usb_function *f_rndis;
-static struct usb_function *f_msg_rndis;
-
-static __init int rndis_do_config(struct usb_configuration *c)
-{
-       struct fsg_opts *fsg_opts;
-       int ret;
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       f_rndis = usb_get_function(fi_rndis);
-       if (IS_ERR(f_rndis))
-               return PTR_ERR(f_rndis);
-
-       ret = usb_add_function(c, f_rndis);
-       if (ret < 0)
-               goto err_func_rndis;
-
-       f_acm_rndis = usb_get_function(fi_acm);
-       if (IS_ERR(f_acm_rndis)) {
-               ret = PTR_ERR(f_acm_rndis);
-               goto err_func_acm;
-       }
-
-       ret = usb_add_function(c, f_acm_rndis);
-       if (ret)
-               goto err_conf;
-
-       f_msg_rndis = usb_get_function(fi_msg);
-       if (IS_ERR(f_msg_rndis)) {
-               ret = PTR_ERR(f_msg_rndis);
-               goto err_fsg;
-       }
-
-       fsg_opts = fsg_opts_from_func_inst(fi_msg);
-       ret = fsg_common_run_thread(fsg_opts->common);
-       if (ret)
-               goto err_run;
-
-       ret = usb_add_function(c, f_msg_rndis);
-       if (ret)
-               goto err_run;
-
-       return 0;
-err_run:
-       usb_put_function(f_msg_rndis);
-err_fsg:
-       usb_remove_function(c, f_acm_rndis);
-err_conf:
-       usb_put_function(f_acm_rndis);
-err_func_acm:
-       usb_remove_function(c, f_rndis);
-err_func_rndis:
-       usb_put_function(f_rndis);
-       return ret;
-}
-
-static __ref int rndis_config_register(struct usb_composite_dev *cdev)
-{
-       static struct usb_configuration config = {
-               .bConfigurationValue    = MULTI_RNDIS_CONFIG_NUM,
-               .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-       };
-
-       config.label          = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
-       config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
-
-       return usb_add_config(cdev, &config, rndis_do_config);
-}
-
-#else
-
-static __ref int rndis_config_register(struct usb_composite_dev *cdev)
-{
-       return 0;
-}
-
-#endif
-
-
-/********** CDC ECM **********/
-
-#ifdef CONFIG_USB_G_MULTI_CDC
-static struct usb_function_instance *fi_ecm;
-static struct usb_function *f_acm_multi;
-static struct usb_function *f_ecm;
-static struct usb_function *f_msg_multi;
-
-static __init int cdc_do_config(struct usb_configuration *c)
-{
-       struct fsg_opts *fsg_opts;
-       int ret;
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       f_ecm = usb_get_function(fi_ecm);
-       if (IS_ERR(f_ecm))
-               return PTR_ERR(f_ecm);
-
-       ret = usb_add_function(c, f_ecm);
-       if (ret < 0)
-               goto err_func_ecm;
-
-       /* implicit port_num is zero */
-       f_acm_multi = usb_get_function(fi_acm);
-       if (IS_ERR(f_acm_multi)) {
-               ret = PTR_ERR(f_acm_multi);
-               goto err_func_acm;
-       }
-
-       ret = usb_add_function(c, f_acm_multi);
-       if (ret)
-               goto err_conf;
-
-       f_msg_multi = usb_get_function(fi_msg);
-       if (IS_ERR(f_msg_multi)) {
-               ret = PTR_ERR(f_msg_multi);
-               goto err_fsg;
-       }
-
-       fsg_opts = fsg_opts_from_func_inst(fi_msg);
-       ret = fsg_common_run_thread(fsg_opts->common);
-       if (ret)
-               goto err_run;
-
-       ret = usb_add_function(c, f_msg_multi);
-       if (ret)
-               goto err_run;
-
-       return 0;
-err_run:
-       usb_put_function(f_msg_multi);
-err_fsg:
-       usb_remove_function(c, f_acm_multi);
-err_conf:
-       usb_put_function(f_acm_multi);
-err_func_acm:
-       usb_remove_function(c, f_ecm);
-err_func_ecm:
-       usb_put_function(f_ecm);
-       return ret;
-}
-
-static __ref int cdc_config_register(struct usb_composite_dev *cdev)
-{
-       static struct usb_configuration config = {
-               .bConfigurationValue    = MULTI_CDC_CONFIG_NUM,
-               .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-       };
-
-       config.label          = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
-       config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
-
-       return usb_add_config(cdev, &config, cdc_do_config);
-}
-
-#else
-
-static __ref int cdc_config_register(struct usb_composite_dev *cdev)
-{
-       return 0;
-}
-
-#endif
-
-
-
-/****************************** Gadget Bind ******************************/
-
-static int __ref multi_bind(struct usb_composite_dev *cdev)
-{
-       struct usb_gadget *gadget = cdev->gadget;
-#ifdef CONFIG_USB_G_MULTI_CDC
-       struct f_ecm_opts *ecm_opts;
-#endif
-#ifdef USB_ETH_RNDIS
-       struct f_rndis_opts *rndis_opts;
-#endif
-       struct fsg_opts *fsg_opts;
-       struct fsg_config config;
-       int status;
-
-       if (!can_support_ecm(cdev->gadget)) {
-               dev_err(&gadget->dev, "controller '%s' not usable\n",
-                       gadget->name);
-               return -EINVAL;
-       }
-
-#ifdef CONFIG_USB_G_MULTI_CDC
-       fi_ecm = usb_get_function_instance("ecm");
-       if (IS_ERR(fi_ecm))
-               return PTR_ERR(fi_ecm);
-
-       ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst);
-
-       gether_set_qmult(ecm_opts->net, qmult);
-       if (!gether_set_host_addr(ecm_opts->net, host_addr))
-               pr_info("using host ethernet address: %s", host_addr);
-       if (!gether_set_dev_addr(ecm_opts->net, dev_addr))
-               pr_info("using self ethernet address: %s", dev_addr);
-#endif
-
-#ifdef USB_ETH_RNDIS
-       fi_rndis = usb_get_function_instance("rndis");
-       if (IS_ERR(fi_rndis)) {
-               status = PTR_ERR(fi_rndis);
-               goto fail;
-       }
-
-       rndis_opts = container_of(fi_rndis, struct f_rndis_opts, func_inst);
-
-       gether_set_qmult(rndis_opts->net, qmult);
-       if (!gether_set_host_addr(rndis_opts->net, host_addr))
-               pr_info("using host ethernet address: %s", host_addr);
-       if (!gether_set_dev_addr(rndis_opts->net, dev_addr))
-               pr_info("using self ethernet address: %s", dev_addr);
-#endif
-
-#if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS)
-       /*
-        * If both ecm and rndis are selected then:
-        *      1) rndis borrows the net interface from ecm
-        *      2) since the interface is shared it must not be bound
-        *      twice - in ecm's _and_ rndis' binds, so do it here.
-        */
-       gether_set_gadget(ecm_opts->net, cdev->gadget);
-       status = gether_register_netdev(ecm_opts->net);
-       if (status)
-               goto fail0;
-
-       rndis_borrow_net(fi_rndis, ecm_opts->net);
-       ecm_opts->bound = true;
-#endif
-
-       /* set up serial link layer */
-       fi_acm = usb_get_function_instance("acm");
-       if (IS_ERR(fi_acm)) {
-               status = PTR_ERR(fi_acm);
-               goto fail0;
-       }
-
-       /* set up mass storage function */
-       fi_msg = usb_get_function_instance("mass_storage");
-       if (IS_ERR(fi_msg)) {
-               status = PTR_ERR(fi_msg);
-               goto fail1;
-       }
-       fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers);
-       fsg_opts = fsg_opts_from_func_inst(fi_msg);
-
-       fsg_opts->no_configfs = true;
-       status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers);
-       if (status)
-               goto fail2;
-
-       status = fsg_common_set_nluns(fsg_opts->common, config.nluns);
-       if (status)
-               goto fail_set_nluns;
-
-       status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall);
-       if (status)
-               goto fail_set_cdev;
-
-       fsg_common_set_sysfs(fsg_opts->common, true);
-       status = fsg_common_create_luns(fsg_opts->common, &config);
-       if (status)
-               goto fail_set_cdev;
-
-       fsg_common_set_inquiry_string(fsg_opts->common, config.vendor_name,
-                                     config.product_name);
-
-       /* allocate string IDs */
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (unlikely(status < 0))
-               goto fail_string_ids;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       /* register configurations */
-       status = rndis_config_register(cdev);
-       if (unlikely(status < 0))
-               goto fail_string_ids;
-
-       status = cdc_config_register(cdev);
-       if (unlikely(status < 0))
-               goto fail_string_ids;
-       usb_composite_overwrite_options(cdev, &coverwrite);
-
-       /* we're done */
-       dev_info(&gadget->dev, DRIVER_DESC "\n");
-       return 0;
-
-
-       /* error recovery */
-fail_string_ids:
-       fsg_common_remove_luns(fsg_opts->common);
-fail_set_cdev:
-       fsg_common_free_luns(fsg_opts->common);
-fail_set_nluns:
-       fsg_common_free_buffers(fsg_opts->common);
-fail2:
-       usb_put_function_instance(fi_msg);
-fail1:
-       usb_put_function_instance(fi_acm);
-fail0:
-#ifdef USB_ETH_RNDIS
-       usb_put_function_instance(fi_rndis);
-fail:
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
-       usb_put_function_instance(fi_ecm);
-#endif
-       return status;
-}
-
-static int __exit multi_unbind(struct usb_composite_dev *cdev)
-{
-#ifdef CONFIG_USB_G_MULTI_CDC
-       usb_put_function(f_msg_multi);
-#endif
-#ifdef USB_ETH_RNDIS
-       usb_put_function(f_msg_rndis);
-#endif
-       usb_put_function_instance(fi_msg);
-#ifdef CONFIG_USB_G_MULTI_CDC
-       usb_put_function(f_acm_multi);
-#endif
-#ifdef USB_ETH_RNDIS
-       usb_put_function(f_acm_rndis);
-#endif
-       usb_put_function_instance(fi_acm);
-#ifdef USB_ETH_RNDIS
-       usb_put_function(f_rndis);
-       usb_put_function_instance(fi_rndis);
-#endif
-#ifdef CONFIG_USB_G_MULTI_CDC
-       usb_put_function(f_ecm);
-       usb_put_function_instance(fi_ecm);
-#endif
-       return 0;
-}
-
-
-/****************************** Some noise ******************************/
-
-
-static __refdata struct usb_composite_driver multi_driver = {
-       .name           = "g_multi",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = multi_bind,
-       .unbind         = __exit_p(multi_unbind),
-       .needs_serial   = 1,
-};
-
-module_usb_composite_driver(multi_driver);
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
deleted file mode 100644 (file)
index e90e23d..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * ncm.c -- NCM gadget driver
- *
- * Copyright (C) 2010 Nokia Corporation
- * Contact: Yauheni Kaliuta <yauheni.kaliuta@nokia.com>
- *
- * The driver borrows from ether.c which is:
- *
- * Copyright (C) 2003-2005,2008 David Brownell
- * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
- * Copyright (C) 2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/* #define DEBUG */
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/usb/composite.h>
-
-#include "u_ether.h"
-#include "u_ncm.h"
-
-#define DRIVER_DESC            "NCM Gadget"
-
-/*-------------------------------------------------------------------------*/
-
-/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-
-/* Thanks to NetChip Technologies for donating this product ID.
- * It's for devices with only CDC Ethernet configurations.
- */
-#define CDC_VENDOR_NUM         0x0525  /* NetChip */
-#define CDC_PRODUCT_NUM                0xa4a1  /* Linux-USB Ethernet Gadget */
-
-/*-------------------------------------------------------------------------*/
-USB_GADGET_COMPOSITE_OPTIONS();
-
-USB_ETHERNET_MODULE_PARAMETERS();
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16 (0x0200),
-
-       .bDeviceClass =         USB_CLASS_COMM,
-       .bDeviceSubClass =      0,
-       .bDeviceProtocol =      0,
-       /* .bMaxPacketSize0 = f(hardware) */
-
-       /* Vendor and product id defaults change according to what configs
-        * we support.  (As does bNumConfigurations.)  These values can
-        * also be overridden by module parameters.
-        */
-       .idVendor =             cpu_to_le16 (CDC_VENDOR_NUM),
-       .idProduct =            cpu_to_le16 (CDC_PRODUCT_NUM),
-       /* .bcdDevice = f(hardware) */
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       /* NO SERIAL NUMBER */
-       .bNumConfigurations =   1,
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-/* string IDs are assigned dynamically */
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = DRIVER_DESC,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-static struct usb_function_instance *f_ncm_inst;
-static struct usb_function *f_ncm;
-
-/*-------------------------------------------------------------------------*/
-
-static int __init ncm_do_config(struct usb_configuration *c)
-{
-       int status;
-
-       /* FIXME alloc iConfiguration string, set it in c->strings */
-
-       if (gadget_is_otg(c->cdev->gadget)) {
-               c->descriptors = otg_desc;
-               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       f_ncm = usb_get_function(f_ncm_inst);
-       if (IS_ERR(f_ncm)) {
-               status = PTR_ERR(f_ncm);
-               return status;
-       }
-
-       status = usb_add_function(c, f_ncm);
-       if (status < 0) {
-               usb_put_function(f_ncm);
-               return status;
-       }
-
-       return 0;
-}
-
-static struct usb_configuration ncm_config_driver = {
-       /* .label = f(hardware) */
-       .label                  = "CDC Ethernet (NCM)",
-       .bConfigurationValue    = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init gncm_bind(struct usb_composite_dev *cdev)
-{
-       struct usb_gadget       *gadget = cdev->gadget;
-       struct f_ncm_opts       *ncm_opts;
-       int                     status;
-
-       f_ncm_inst = usb_get_function_instance("ncm");
-       if (IS_ERR(f_ncm_inst))
-               return PTR_ERR(f_ncm_inst);
-
-       ncm_opts = container_of(f_ncm_inst, struct f_ncm_opts, func_inst);
-
-       gether_set_qmult(ncm_opts->net, qmult);
-       if (!gether_set_host_addr(ncm_opts->net, host_addr))
-               pr_info("using host ethernet address: %s", host_addr);
-       if (!gether_set_dev_addr(ncm_opts->net, dev_addr))
-               pr_info("using self ethernet address: %s", dev_addr);
-
-       /* Allocate string descriptor numbers ... note that string
-        * contents can be overridden by the composite_dev glue.
-        */
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto fail;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-
-       status = usb_add_config(cdev, &ncm_config_driver,
-                               ncm_do_config);
-       if (status < 0)
-               goto fail;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
-
-       return 0;
-
-fail:
-       usb_put_function_instance(f_ncm_inst);
-       return status;
-}
-
-static int __exit gncm_unbind(struct usb_composite_dev *cdev)
-{
-       if (!IS_ERR_OR_NULL(f_ncm))
-               usb_put_function(f_ncm);
-       if (!IS_ERR_OR_NULL(f_ncm_inst))
-               usb_put_function_instance(f_ncm_inst);
-       return 0;
-}
-
-static __refdata struct usb_composite_driver ncm_driver = {
-       .name           = "g_ncm",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = gncm_bind,
-       .unbind         = __exit_p(gncm_unbind),
-};
-
-module_usb_composite_driver(ncm_driver);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Yauheni Kaliuta");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
deleted file mode 100644 (file)
index 9b8fd70..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * nokia.c -- Nokia Composite Gadget Driver
- *
- * Copyright (C) 2008-2010 Nokia Corporation
- * Contact: Felipe Balbi <felipe.balbi@nokia.com>
- *
- * This gadget driver borrows from serial.c which is:
- *
- * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
- * Copyright (C) 2008 by David Brownell
- * Copyright (C) 2008 by Nokia Corporation
- *
- * This software is distributed under the terms of the GNU General
- * Public License ("GPL") as published by the Free Software Foundation,
- * version 2 of that License.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include "u_serial.h"
-#include "u_ether.h"
-#include "u_phonet.h"
-#include "u_ecm.h"
-#include "gadget_chips.h"
-
-/* Defines */
-
-#define NOKIA_VERSION_NUM              0x0211
-#define NOKIA_LONG_NAME                        "N900 (PC-Suite Mode)"
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-USB_ETHERNET_MODULE_PARAMETERS();
-
-#define NOKIA_VENDOR_ID                        0x0421  /* Nokia */
-#define NOKIA_PRODUCT_ID               0x01c8  /* Nokia Gadget */
-
-/* string IDs are assigned dynamically */
-
-#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
-
-static char manufacturer_nokia[] = "Nokia";
-static const char product_nokia[] = NOKIA_LONG_NAME;
-static const char description_nokia[] = "PC-Suite Configuration";
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = manufacturer_nokia,
-       [USB_GADGET_PRODUCT_IDX].s = NOKIA_LONG_NAME,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       [STRING_DESCRIPTION_IDX].s = description_nokia,
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-static struct usb_device_descriptor device_desc = {
-       .bLength                = USB_DT_DEVICE_SIZE,
-       .bDescriptorType        = USB_DT_DEVICE,
-       .bcdUSB                 = __constant_cpu_to_le16(0x0200),
-       .bDeviceClass           = USB_CLASS_COMM,
-       .idVendor               = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
-       .idProduct              = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
-       .bcdDevice              = cpu_to_le16(NOKIA_VERSION_NUM),
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       .bNumConfigurations =   1,
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* Module */
-MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
-MODULE_AUTHOR("Felipe Balbi");
-MODULE_LICENSE("GPL");
-
-/*-------------------------------------------------------------------------*/
-static struct usb_function *f_acm_cfg1;
-static struct usb_function *f_acm_cfg2;
-static struct usb_function *f_ecm_cfg1;
-static struct usb_function *f_ecm_cfg2;
-static struct usb_function *f_obex1_cfg1;
-static struct usb_function *f_obex2_cfg1;
-static struct usb_function *f_obex1_cfg2;
-static struct usb_function *f_obex2_cfg2;
-static struct usb_function *f_phonet_cfg1;
-static struct usb_function *f_phonet_cfg2;
-
-
-static struct usb_configuration nokia_config_500ma_driver = {
-       .label          = "Bus Powered",
-       .bConfigurationValue = 1,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes   = USB_CONFIG_ATT_ONE,
-       .MaxPower       = 500,
-};
-
-static struct usb_configuration nokia_config_100ma_driver = {
-       .label          = "Self Powered",
-       .bConfigurationValue = 2,
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes   = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-       .MaxPower       = 100,
-};
-
-static struct usb_function_instance *fi_acm;
-static struct usb_function_instance *fi_ecm;
-static struct usb_function_instance *fi_obex1;
-static struct usb_function_instance *fi_obex2;
-static struct usb_function_instance *fi_phonet;
-
-static int __init nokia_bind_config(struct usb_configuration *c)
-{
-       struct usb_function *f_acm;
-       struct usb_function *f_phonet = NULL;
-       struct usb_function *f_obex1 = NULL;
-       struct usb_function *f_ecm;
-       struct usb_function *f_obex2 = NULL;
-       int status = 0;
-       int obex1_stat = -1;
-       int obex2_stat = -1;
-       int phonet_stat = -1;
-
-       if (!IS_ERR(fi_phonet)) {
-               f_phonet = usb_get_function(fi_phonet);
-               if (IS_ERR(f_phonet))
-                       pr_debug("could not get phonet function\n");
-       }
-
-       if (!IS_ERR(fi_obex1)) {
-               f_obex1 = usb_get_function(fi_obex1);
-               if (IS_ERR(f_obex1))
-                       pr_debug("could not get obex function 0\n");
-       }
-
-       if (!IS_ERR(fi_obex2)) {
-               f_obex2 = usb_get_function(fi_obex2);
-               if (IS_ERR(f_obex2))
-                       pr_debug("could not get obex function 1\n");
-       }
-
-       f_acm = usb_get_function(fi_acm);
-       if (IS_ERR(f_acm)) {
-               status = PTR_ERR(f_acm);
-               goto err_get_acm;
-       }
-
-       f_ecm = usb_get_function(fi_ecm);
-       if (IS_ERR(f_ecm)) {
-               status = PTR_ERR(f_ecm);
-               goto err_get_ecm;
-       }
-
-       if (!IS_ERR_OR_NULL(f_phonet)) {
-               phonet_stat = usb_add_function(c, f_phonet);
-               if (phonet_stat)
-                       pr_debug("could not add phonet function\n");
-       }
-
-       if (!IS_ERR_OR_NULL(f_obex1)) {
-               obex1_stat = usb_add_function(c, f_obex1);
-               if (obex1_stat)
-                       pr_debug("could not add obex function 0\n");
-       }
-
-       if (!IS_ERR_OR_NULL(f_obex2)) {
-               obex2_stat = usb_add_function(c, f_obex2);
-               if (obex2_stat)
-                       pr_debug("could not add obex function 1\n");
-       }
-
-       status = usb_add_function(c, f_acm);
-       if (status)
-               goto err_conf;
-
-       status = usb_add_function(c, f_ecm);
-       if (status) {
-               pr_debug("could not bind ecm config %d\n", status);
-               goto err_ecm;
-       }
-       if (c == &nokia_config_500ma_driver) {
-               f_acm_cfg1 = f_acm;
-               f_ecm_cfg1 = f_ecm;
-               f_phonet_cfg1 = f_phonet;
-               f_obex1_cfg1 = f_obex1;
-               f_obex2_cfg1 = f_obex2;
-       } else {
-               f_acm_cfg2 = f_acm;
-               f_ecm_cfg2 = f_ecm;
-               f_phonet_cfg2 = f_phonet;
-               f_obex1_cfg2 = f_obex1;
-               f_obex2_cfg2 = f_obex2;
-       }
-
-       return status;
-err_ecm:
-       usb_remove_function(c, f_acm);
-err_conf:
-       if (!obex2_stat)
-               usb_remove_function(c, f_obex2);
-       if (!obex1_stat)
-               usb_remove_function(c, f_obex1);
-       if (!phonet_stat)
-               usb_remove_function(c, f_phonet);
-       usb_put_function(f_ecm);
-err_get_ecm:
-       usb_put_function(f_acm);
-err_get_acm:
-       if (!IS_ERR_OR_NULL(f_obex2))
-               usb_put_function(f_obex2);
-       if (!IS_ERR_OR_NULL(f_obex1))
-               usb_put_function(f_obex1);
-       if (!IS_ERR_OR_NULL(f_phonet))
-               usb_put_function(f_phonet);
-       return status;
-}
-
-static int __init nokia_bind(struct usb_composite_dev *cdev)
-{
-       struct usb_gadget       *gadget = cdev->gadget;
-       int                     status;
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto err_usb;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-       status = strings_dev[STRING_DESCRIPTION_IDX].id;
-       nokia_config_500ma_driver.iConfiguration = status;
-       nokia_config_100ma_driver.iConfiguration = status;
-
-       if (!gadget_supports_altsettings(gadget)) {
-               status = -ENODEV;
-               goto err_usb;
-       }
-
-       fi_phonet = usb_get_function_instance("phonet");
-       if (IS_ERR(fi_phonet))
-               pr_debug("could not find phonet function\n");
-
-       fi_obex1 = usb_get_function_instance("obex");
-       if (IS_ERR(fi_obex1))
-               pr_debug("could not find obex function 1\n");
-
-       fi_obex2 = usb_get_function_instance("obex");
-       if (IS_ERR(fi_obex2))
-               pr_debug("could not find obex function 2\n");
-
-       fi_acm = usb_get_function_instance("acm");
-       if (IS_ERR(fi_acm)) {
-               status = PTR_ERR(fi_acm);
-               goto err_obex2_inst;
-       }
-
-       fi_ecm = usb_get_function_instance("ecm");
-       if (IS_ERR(fi_ecm)) {
-               status = PTR_ERR(fi_ecm);
-               goto err_acm_inst;
-       }
-
-       /* finally register the configuration */
-       status = usb_add_config(cdev, &nokia_config_500ma_driver,
-                       nokia_bind_config);
-       if (status < 0)
-               goto err_ecm_inst;
-
-       status = usb_add_config(cdev, &nokia_config_100ma_driver,
-                       nokia_bind_config);
-       if (status < 0)
-               goto err_put_cfg1;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
-
-       return 0;
-
-err_put_cfg1:
-       usb_put_function(f_acm_cfg1);
-       if (!IS_ERR_OR_NULL(f_obex1_cfg1))
-               usb_put_function(f_obex1_cfg1);
-       if (!IS_ERR_OR_NULL(f_obex2_cfg1))
-               usb_put_function(f_obex2_cfg1);
-       if (!IS_ERR_OR_NULL(f_phonet_cfg1))
-               usb_put_function(f_phonet_cfg1);
-       usb_put_function(f_ecm_cfg1);
-err_ecm_inst:
-       usb_put_function_instance(fi_ecm);
-err_acm_inst:
-       usb_put_function_instance(fi_acm);
-err_obex2_inst:
-       if (!IS_ERR(fi_obex2))
-               usb_put_function_instance(fi_obex2);
-       if (!IS_ERR(fi_obex1))
-               usb_put_function_instance(fi_obex1);
-       if (!IS_ERR(fi_phonet))
-               usb_put_function_instance(fi_phonet);
-err_usb:
-       return status;
-}
-
-static int __exit nokia_unbind(struct usb_composite_dev *cdev)
-{
-       if (!IS_ERR_OR_NULL(f_obex1_cfg2))
-               usb_put_function(f_obex1_cfg2);
-       if (!IS_ERR_OR_NULL(f_obex2_cfg2))
-               usb_put_function(f_obex2_cfg2);
-       if (!IS_ERR_OR_NULL(f_obex1_cfg1))
-               usb_put_function(f_obex1_cfg1);
-       if (!IS_ERR_OR_NULL(f_obex2_cfg1))
-               usb_put_function(f_obex2_cfg1);
-       if (!IS_ERR_OR_NULL(f_phonet_cfg1))
-               usb_put_function(f_phonet_cfg1);
-       if (!IS_ERR_OR_NULL(f_phonet_cfg2))
-               usb_put_function(f_phonet_cfg2);
-       usb_put_function(f_acm_cfg1);
-       usb_put_function(f_acm_cfg2);
-       usb_put_function(f_ecm_cfg1);
-       usb_put_function(f_ecm_cfg2);
-
-       usb_put_function_instance(fi_ecm);
-       if (!IS_ERR(fi_obex2))
-               usb_put_function_instance(fi_obex2);
-       if (!IS_ERR(fi_obex1))
-               usb_put_function_instance(fi_obex1);
-       if (!IS_ERR(fi_phonet))
-               usb_put_function_instance(fi_phonet);
-       usb_put_function_instance(fi_acm);
-
-       return 0;
-}
-
-static __refdata struct usb_composite_driver nokia_driver = {
-       .name           = "g_nokia",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = nokia_bind,
-       .unbind         = __exit_p(nokia_unbind),
-};
-
-module_usb_composite_driver(nokia_driver);
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
deleted file mode 100644 (file)
index 6474081..0000000
+++ /dev/null
@@ -1,1305 +0,0 @@
-/*
- * printer.c -- Printer gadget driver
- *
- * Copyright (C) 2003-2005 David Brownell
- * Copyright (C) 2006 Craig W. Nadler
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/moduleparam.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/cdev.h>
-
-#include <asm/byteorder.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/uaccess.h>
-#include <asm/unaligned.h>
-
-#include <linux/usb/ch9.h>
-#include <linux/usb/composite.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/g_printer.h>
-
-#include "gadget_chips.h"
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-#define DRIVER_DESC            "Printer Gadget"
-#define DRIVER_VERSION         "2007 OCT 06"
-
-static DEFINE_MUTEX(printer_mutex);
-static const char shortname [] = "printer";
-static const char driver_desc [] = DRIVER_DESC;
-
-static dev_t g_printer_devno;
-
-static struct class *usb_gadget_class;
-
-/*-------------------------------------------------------------------------*/
-
-struct printer_dev {
-       spinlock_t              lock;           /* lock this structure */
-       /* lock buffer lists during read/write calls */
-       struct mutex            lock_printer_io;
-       struct usb_gadget       *gadget;
-       s8                      interface;
-       struct usb_ep           *in_ep, *out_ep;
-
-       struct list_head        rx_reqs;        /* List of free RX structs */
-       struct list_head        rx_reqs_active; /* List of Active RX xfers */
-       struct list_head        rx_buffers;     /* List of completed xfers */
-       /* wait until there is data to be read. */
-       wait_queue_head_t       rx_wait;
-       struct list_head        tx_reqs;        /* List of free TX structs */
-       struct list_head        tx_reqs_active; /* List of Active TX xfers */
-       /* Wait until there are write buffers available to use. */
-       wait_queue_head_t       tx_wait;
-       /* Wait until all write buffers have been sent. */
-       wait_queue_head_t       tx_flush_wait;
-       struct usb_request      *current_rx_req;
-       size_t                  current_rx_bytes;
-       u8                      *current_rx_buf;
-       u8                      printer_status;
-       u8                      reset_printer;
-       struct cdev             printer_cdev;
-       struct device           *pdev;
-       u8                      printer_cdev_open;
-       wait_queue_head_t       wait;
-       struct usb_function     function;
-};
-
-static struct printer_dev usb_printer_gadget;
-
-/*-------------------------------------------------------------------------*/
-
-/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-
-/* Thanks to NetChip Technologies for donating this product ID.
- */
-#define PRINTER_VENDOR_NUM     0x0525          /* NetChip */
-#define PRINTER_PRODUCT_NUM    0xa4a8          /* Linux-USB Printer Gadget */
-
-/* Some systems will want different product identifiers published in the
- * device descriptor, either numbers or strings or both.  These string
- * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
- */
-
-module_param_named(iSerialNum, coverwrite.serial_number, charp, S_IRUGO);
-MODULE_PARM_DESC(iSerialNum, "1");
-
-static char *iPNPstring;
-module_param(iPNPstring, charp, S_IRUGO);
-MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;");
-
-/* Number of requests to allocate per endpoint, not used for ep0. */
-static unsigned qlen = 10;
-module_param(qlen, uint, S_IRUGO|S_IWUSR);
-
-#define QLEN   qlen
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * DESCRIPTORS ... most are static, but strings and (full) configuration
- * descriptors are built on demand.
- */
-
-/* holds our biggest descriptor */
-#define USB_DESC_BUFSIZE               256
-#define USB_BUFSIZE                    8192
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-       .bcdUSB =               cpu_to_le16(0x0200),
-       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
-       .bDeviceSubClass =      0,
-       .bDeviceProtocol =      0,
-       .idVendor =             cpu_to_le16(PRINTER_VENDOR_NUM),
-       .idProduct =            cpu_to_le16(PRINTER_PRODUCT_NUM),
-       .bNumConfigurations =   1
-};
-
-static struct usb_interface_descriptor intf_desc = {
-       .bLength =              sizeof intf_desc,
-       .bDescriptorType =      USB_DT_INTERFACE,
-       .bNumEndpoints =        2,
-       .bInterfaceClass =      USB_CLASS_PRINTER,
-       .bInterfaceSubClass =   1,      /* Printer Sub-Class */
-       .bInterfaceProtocol =   2,      /* Bi-Directional */
-       .iInterface =           0
-};
-
-static struct usb_endpoint_descriptor fs_ep_in_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK
-};
-
-static struct usb_endpoint_descriptor fs_ep_out_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK
-};
-
-static struct usb_descriptor_header *fs_printer_function[] = {
-       (struct usb_descriptor_header *) &intf_desc,
-       (struct usb_descriptor_header *) &fs_ep_in_desc,
-       (struct usb_descriptor_header *) &fs_ep_out_desc,
-       NULL
-};
-
-/*
- * usb 2.0 devices need to expose both high speed and full speed
- * descriptors, unless they only run at full speed.
- */
-
-static struct usb_endpoint_descriptor hs_ep_in_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(512)
-};
-
-static struct usb_endpoint_descriptor hs_ep_out_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(512)
-};
-
-static struct usb_qualifier_descriptor dev_qualifier = {
-       .bLength =              sizeof dev_qualifier,
-       .bDescriptorType =      USB_DT_DEVICE_QUALIFIER,
-       .bcdUSB =               cpu_to_le16(0x0200),
-       .bDeviceClass =         USB_CLASS_PRINTER,
-       .bNumConfigurations =   1
-};
-
-static struct usb_descriptor_header *hs_printer_function[] = {
-       (struct usb_descriptor_header *) &intf_desc,
-       (struct usb_descriptor_header *) &hs_ep_in_desc,
-       (struct usb_descriptor_header *) &hs_ep_out_desc,
-       NULL
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-       .bmAttributes =         USB_OTG_SRP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
-
-/*-------------------------------------------------------------------------*/
-
-/* descriptors that are built on-demand */
-
-static char                            product_desc [40] = DRIVER_DESC;
-static char                            serial_num [40] = "1";
-static char                            pnp_string [1024] =
-       "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;";
-
-/* static strings, in UTF-8 */
-static struct usb_string               strings [] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = product_desc,
-       [USB_GADGET_SERIAL_IDX].s =     serial_num,
-       {  }            /* end of list */
-};
-
-static struct usb_gadget_strings       stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_request *
-printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags)
-{
-       struct usb_request      *req;
-
-       req = usb_ep_alloc_request(ep, gfp_flags);
-
-       if (req != NULL) {
-               req->length = len;
-               req->buf = kmalloc(len, gfp_flags);
-               if (req->buf == NULL) {
-                       usb_ep_free_request(ep, req);
-                       return NULL;
-               }
-       }
-
-       return req;
-}
-
-static void
-printer_req_free(struct usb_ep *ep, struct usb_request *req)
-{
-       if (ep != NULL && req != NULL) {
-               kfree(req->buf);
-               usb_ep_free_request(ep, req);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void rx_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       struct printer_dev      *dev = ep->driver_data;
-       int                     status = req->status;
-       unsigned long           flags;
-
-       spin_lock_irqsave(&dev->lock, flags);
-
-       list_del_init(&req->list);      /* Remode from Active List */
-
-       switch (status) {
-
-       /* normal completion */
-       case 0:
-               if (req->actual > 0) {
-                       list_add_tail(&req->list, &dev->rx_buffers);
-                       DBG(dev, "G_Printer : rx length %d\n", req->actual);
-               } else {
-                       list_add(&req->list, &dev->rx_reqs);
-               }
-               break;
-
-       /* software-driven interface shutdown */
-       case -ECONNRESET:               /* unlink */
-       case -ESHUTDOWN:                /* disconnect etc */
-               VDBG(dev, "rx shutdown, code %d\n", status);
-               list_add(&req->list, &dev->rx_reqs);
-               break;
-
-       /* for hardware automagic (such as pxa) */
-       case -ECONNABORTED:             /* endpoint reset */
-               DBG(dev, "rx %s reset\n", ep->name);
-               list_add(&req->list, &dev->rx_reqs);
-               break;
-
-       /* data overrun */
-       case -EOVERFLOW:
-               /* FALLTHROUGH */
-
-       default:
-               DBG(dev, "rx status %d\n", status);
-               list_add(&req->list, &dev->rx_reqs);
-               break;
-       }
-
-       wake_up_interruptible(&dev->rx_wait);
-       spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-static void tx_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       struct printer_dev      *dev = ep->driver_data;
-
-       switch (req->status) {
-       default:
-               VDBG(dev, "tx err %d\n", req->status);
-               /* FALLTHROUGH */
-       case -ECONNRESET:               /* unlink */
-       case -ESHUTDOWN:                /* disconnect etc */
-               break;
-       case 0:
-               break;
-       }
-
-       spin_lock(&dev->lock);
-       /* Take the request struct off the active list and put it on the
-        * free list.
-        */
-       list_del_init(&req->list);
-       list_add(&req->list, &dev->tx_reqs);
-       wake_up_interruptible(&dev->tx_wait);
-       if (likely(list_empty(&dev->tx_reqs_active)))
-               wake_up_interruptible(&dev->tx_flush_wait);
-
-       spin_unlock(&dev->lock);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int
-printer_open(struct inode *inode, struct file *fd)
-{
-       struct printer_dev      *dev;
-       unsigned long           flags;
-       int                     ret = -EBUSY;
-
-       mutex_lock(&printer_mutex);
-       dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
-
-       spin_lock_irqsave(&dev->lock, flags);
-
-       if (!dev->printer_cdev_open) {
-               dev->printer_cdev_open = 1;
-               fd->private_data = dev;
-               ret = 0;
-               /* Change the printer status to show that it's on-line. */
-               dev->printer_status |= PRINTER_SELECTED;
-       }
-
-       spin_unlock_irqrestore(&dev->lock, flags);
-
-       DBG(dev, "printer_open returned %x\n", ret);
-       mutex_unlock(&printer_mutex);
-       return ret;
-}
-
-static int
-printer_close(struct inode *inode, struct file *fd)
-{
-       struct printer_dev      *dev = fd->private_data;
-       unsigned long           flags;
-
-       spin_lock_irqsave(&dev->lock, flags);
-       dev->printer_cdev_open = 0;
-       fd->private_data = NULL;
-       /* Change printer status to show that the printer is off-line. */
-       dev->printer_status &= ~PRINTER_SELECTED;
-       spin_unlock_irqrestore(&dev->lock, flags);
-
-       DBG(dev, "printer_close\n");
-
-       return 0;
-}
-
-/* This function must be called with interrupts turned off. */
-static void
-setup_rx_reqs(struct printer_dev *dev)
-{
-       struct usb_request              *req;
-
-       while (likely(!list_empty(&dev->rx_reqs))) {
-               int error;
-
-               req = container_of(dev->rx_reqs.next,
-                               struct usb_request, list);
-               list_del_init(&req->list);
-
-               /* The USB Host sends us whatever amount of data it wants to
-                * so we always set the length field to the full USB_BUFSIZE.
-                * If the amount of data is more than the read() caller asked
-                * for it will be stored in the request buffer until it is
-                * asked for by read().
-                */
-               req->length = USB_BUFSIZE;
-               req->complete = rx_complete;
-
-               /* here, we unlock, and only unlock, to avoid deadlock. */
-               spin_unlock(&dev->lock);
-               error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
-               spin_lock(&dev->lock);
-               if (error) {
-                       DBG(dev, "rx submit --> %d\n", error);
-                       list_add(&req->list, &dev->rx_reqs);
-                       break;
-               }
-               /* if the req is empty, then add it into dev->rx_reqs_active. */
-               else if (list_empty(&req->list)) {
-                       list_add(&req->list, &dev->rx_reqs_active);
-               }
-       }
-}
-
-static ssize_t
-printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
-{
-       struct printer_dev              *dev = fd->private_data;
-       unsigned long                   flags;
-       size_t                          size;
-       size_t                          bytes_copied;
-       struct usb_request              *req;
-       /* This is a pointer to the current USB rx request. */
-       struct usb_request              *current_rx_req;
-       /* This is the number of bytes in the current rx buffer. */
-       size_t                          current_rx_bytes;
-       /* This is a pointer to the current rx buffer. */
-       u8                              *current_rx_buf;
-
-       if (len == 0)
-               return -EINVAL;
-
-       DBG(dev, "printer_read trying to read %d bytes\n", (int)len);
-
-       mutex_lock(&dev->lock_printer_io);
-       spin_lock_irqsave(&dev->lock, flags);
-
-       /* We will use this flag later to check if a printer reset happened
-        * after we turn interrupts back on.
-        */
-       dev->reset_printer = 0;
-
-       setup_rx_reqs(dev);
-
-       bytes_copied = 0;
-       current_rx_req = dev->current_rx_req;
-       current_rx_bytes = dev->current_rx_bytes;
-       current_rx_buf = dev->current_rx_buf;
-       dev->current_rx_req = NULL;
-       dev->current_rx_bytes = 0;
-       dev->current_rx_buf = NULL;
-
-       /* Check if there is any data in the read buffers. Please note that
-        * current_rx_bytes is the number of bytes in the current rx buffer.
-        * If it is zero then check if there are any other rx_buffers that
-        * are on the completed list. We are only out of data if all rx
-        * buffers are empty.
-        */
-       if ((current_rx_bytes == 0) &&
-                       (likely(list_empty(&dev->rx_buffers)))) {
-               /* Turn interrupts back on before sleeping. */
-               spin_unlock_irqrestore(&dev->lock, flags);
-
-               /*
-                * If no data is available check if this is a NON-Blocking
-                * call or not.
-                */
-               if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
-                       mutex_unlock(&dev->lock_printer_io);
-                       return -EAGAIN;
-               }
-
-               /* Sleep until data is available */
-               wait_event_interruptible(dev->rx_wait,
-                               (likely(!list_empty(&dev->rx_buffers))));
-               spin_lock_irqsave(&dev->lock, flags);
-       }
-
-       /* We have data to return then copy it to the caller's buffer.*/
-       while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers)))
-                       && len) {
-               if (current_rx_bytes == 0) {
-                       req = container_of(dev->rx_buffers.next,
-                                       struct usb_request, list);
-                       list_del_init(&req->list);
-
-                       if (req->actual && req->buf) {
-                               current_rx_req = req;
-                               current_rx_bytes = req->actual;
-                               current_rx_buf = req->buf;
-                       } else {
-                               list_add(&req->list, &dev->rx_reqs);
-                               continue;
-                       }
-               }
-
-               /* Don't leave irqs off while doing memory copies */
-               spin_unlock_irqrestore(&dev->lock, flags);
-
-               if (len > current_rx_bytes)
-                       size = current_rx_bytes;
-               else
-                       size = len;
-
-               size -= copy_to_user(buf, current_rx_buf, size);
-               bytes_copied += size;
-               len -= size;
-               buf += size;
-
-               spin_lock_irqsave(&dev->lock, flags);
-
-               /* We've disconnected or reset so return. */
-               if (dev->reset_printer) {
-                       list_add(&current_rx_req->list, &dev->rx_reqs);
-                       spin_unlock_irqrestore(&dev->lock, flags);
-                       mutex_unlock(&dev->lock_printer_io);
-                       return -EAGAIN;
-               }
-
-               /* If we not returning all the data left in this RX request
-                * buffer then adjust the amount of data left in the buffer.
-                * Othewise if we are done with this RX request buffer then
-                * requeue it to get any incoming data from the USB host.
-                */
-               if (size < current_rx_bytes) {
-                       current_rx_bytes -= size;
-                       current_rx_buf += size;
-               } else {
-                       list_add(&current_rx_req->list, &dev->rx_reqs);
-                       current_rx_bytes = 0;
-                       current_rx_buf = NULL;
-                       current_rx_req = NULL;
-               }
-       }
-
-       dev->current_rx_req = current_rx_req;
-       dev->current_rx_bytes = current_rx_bytes;
-       dev->current_rx_buf = current_rx_buf;
-
-       spin_unlock_irqrestore(&dev->lock, flags);
-       mutex_unlock(&dev->lock_printer_io);
-
-       DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied);
-
-       if (bytes_copied)
-               return bytes_copied;
-       else
-               return -EAGAIN;
-}
-
-static ssize_t
-printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
-{
-       struct printer_dev      *dev = fd->private_data;
-       unsigned long           flags;
-       size_t                  size;   /* Amount of data in a TX request. */
-       size_t                  bytes_copied = 0;
-       struct usb_request      *req;
-
-       DBG(dev, "printer_write trying to send %d bytes\n", (int)len);
-
-       if (len == 0)
-               return -EINVAL;
-
-       mutex_lock(&dev->lock_printer_io);
-       spin_lock_irqsave(&dev->lock, flags);
-
-       /* Check if a printer reset happens while we have interrupts on */
-       dev->reset_printer = 0;
-
-       /* Check if there is any available write buffers */
-       if (likely(list_empty(&dev->tx_reqs))) {
-               /* Turn interrupts back on before sleeping. */
-               spin_unlock_irqrestore(&dev->lock, flags);
-
-               /*
-                * If write buffers are available check if this is
-                * a NON-Blocking call or not.
-                */
-               if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) {
-                       mutex_unlock(&dev->lock_printer_io);
-                       return -EAGAIN;
-               }
-
-               /* Sleep until a write buffer is available */
-               wait_event_interruptible(dev->tx_wait,
-                               (likely(!list_empty(&dev->tx_reqs))));
-               spin_lock_irqsave(&dev->lock, flags);
-       }
-
-       while (likely(!list_empty(&dev->tx_reqs)) && len) {
-
-               if (len > USB_BUFSIZE)
-                       size = USB_BUFSIZE;
-               else
-                       size = len;
-
-               req = container_of(dev->tx_reqs.next, struct usb_request,
-                               list);
-               list_del_init(&req->list);
-
-               req->complete = tx_complete;
-               req->length = size;
-
-               /* Check if we need to send a zero length packet. */
-               if (len > size)
-                       /* They will be more TX requests so no yet. */
-                       req->zero = 0;
-               else
-                       /* If the data amount is not a multple of the
-                        * maxpacket size then send a zero length packet.
-                        */
-                       req->zero = ((len % dev->in_ep->maxpacket) == 0);
-
-               /* Don't leave irqs off while doing memory copies */
-               spin_unlock_irqrestore(&dev->lock, flags);
-
-               if (copy_from_user(req->buf, buf, size)) {
-                       list_add(&req->list, &dev->tx_reqs);
-                       mutex_unlock(&dev->lock_printer_io);
-                       return bytes_copied;
-               }
-
-               bytes_copied += size;
-               len -= size;
-               buf += size;
-
-               spin_lock_irqsave(&dev->lock, flags);
-
-               /* We've disconnected or reset so free the req and buffer */
-               if (dev->reset_printer) {
-                       list_add(&req->list, &dev->tx_reqs);
-                       spin_unlock_irqrestore(&dev->lock, flags);
-                       mutex_unlock(&dev->lock_printer_io);
-                       return -EAGAIN;
-               }
-
-               if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) {
-                       list_add(&req->list, &dev->tx_reqs);
-                       spin_unlock_irqrestore(&dev->lock, flags);
-                       mutex_unlock(&dev->lock_printer_io);
-                       return -EAGAIN;
-               }
-
-               list_add(&req->list, &dev->tx_reqs_active);
-
-       }
-
-       spin_unlock_irqrestore(&dev->lock, flags);
-       mutex_unlock(&dev->lock_printer_io);
-
-       DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied);
-
-       if (bytes_copied) {
-               return bytes_copied;
-       } else {
-               return -EAGAIN;
-       }
-}
-
-static int
-printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync)
-{
-       struct printer_dev      *dev = fd->private_data;
-       struct inode *inode = file_inode(fd);
-       unsigned long           flags;
-       int                     tx_list_empty;
-
-       mutex_lock(&inode->i_mutex);
-       spin_lock_irqsave(&dev->lock, flags);
-       tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
-       spin_unlock_irqrestore(&dev->lock, flags);
-
-       if (!tx_list_empty) {
-               /* Sleep until all data has been sent */
-               wait_event_interruptible(dev->tx_flush_wait,
-                               (likely(list_empty(&dev->tx_reqs_active))));
-       }
-       mutex_unlock(&inode->i_mutex);
-
-       return 0;
-}
-
-static unsigned int
-printer_poll(struct file *fd, poll_table *wait)
-{
-       struct printer_dev      *dev = fd->private_data;
-       unsigned long           flags;
-       int                     status = 0;
-
-       mutex_lock(&dev->lock_printer_io);
-       spin_lock_irqsave(&dev->lock, flags);
-       setup_rx_reqs(dev);
-       spin_unlock_irqrestore(&dev->lock, flags);
-       mutex_unlock(&dev->lock_printer_io);
-
-       poll_wait(fd, &dev->rx_wait, wait);
-       poll_wait(fd, &dev->tx_wait, wait);
-
-       spin_lock_irqsave(&dev->lock, flags);
-       if (likely(!list_empty(&dev->tx_reqs)))
-               status |= POLLOUT | POLLWRNORM;
-
-       if (likely(dev->current_rx_bytes) ||
-                       likely(!list_empty(&dev->rx_buffers)))
-               status |= POLLIN | POLLRDNORM;
-
-       spin_unlock_irqrestore(&dev->lock, flags);
-
-       return status;
-}
-
-static long
-printer_ioctl(struct file *fd, unsigned int code, unsigned long arg)
-{
-       struct printer_dev      *dev = fd->private_data;
-       unsigned long           flags;
-       int                     status = 0;
-
-       DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg);
-
-       /* handle ioctls */
-
-       spin_lock_irqsave(&dev->lock, flags);
-
-       switch (code) {
-       case GADGET_GET_PRINTER_STATUS:
-               status = (int)dev->printer_status;
-               break;
-       case GADGET_SET_PRINTER_STATUS:
-               dev->printer_status = (u8)arg;
-               break;
-       default:
-               /* could not handle ioctl */
-               DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n",
-                               code);
-               status = -ENOTTY;
-       }
-
-       spin_unlock_irqrestore(&dev->lock, flags);
-
-       return status;
-}
-
-/* used after endpoint configuration */
-static const struct file_operations printer_io_operations = {
-       .owner =        THIS_MODULE,
-       .open =         printer_open,
-       .read =         printer_read,
-       .write =        printer_write,
-       .fsync =        printer_fsync,
-       .poll =         printer_poll,
-       .unlocked_ioctl = printer_ioctl,
-       .release =      printer_close,
-       .llseek =       noop_llseek,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int
-set_printer_interface(struct printer_dev *dev)
-{
-       int                     result = 0;
-
-       dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
-       dev->in_ep->driver_data = dev;
-
-       dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
-                                   &fs_ep_out_desc);
-       dev->out_ep->driver_data = dev;
-
-       result = usb_ep_enable(dev->in_ep);
-       if (result != 0) {
-               DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
-               goto done;
-       }
-
-       result = usb_ep_enable(dev->out_ep);
-       if (result != 0) {
-               DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
-               goto done;
-       }
-
-done:
-       /* on error, disable any endpoints  */
-       if (result != 0) {
-               (void) usb_ep_disable(dev->in_ep);
-               (void) usb_ep_disable(dev->out_ep);
-               dev->in_ep->desc = NULL;
-               dev->out_ep->desc = NULL;
-       }
-
-       /* caller is responsible for cleanup on error */
-       return result;
-}
-
-static void printer_reset_interface(struct printer_dev *dev)
-{
-       if (dev->interface < 0)
-               return;
-
-       DBG(dev, "%s\n", __func__);
-
-       if (dev->in_ep->desc)
-               usb_ep_disable(dev->in_ep);
-
-       if (dev->out_ep->desc)
-               usb_ep_disable(dev->out_ep);
-
-       dev->in_ep->desc = NULL;
-       dev->out_ep->desc = NULL;
-       dev->interface = -1;
-}
-
-/* Change our operational Interface. */
-static int set_interface(struct printer_dev *dev, unsigned number)
-{
-       int                     result = 0;
-
-       /* Free the current interface */
-       printer_reset_interface(dev);
-
-       result = set_printer_interface(dev);
-       if (result)
-               printer_reset_interface(dev);
-       else
-               dev->interface = number;
-
-       if (!result)
-               INFO(dev, "Using interface %x\n", number);
-
-       return result;
-}
-
-static void printer_soft_reset(struct printer_dev *dev)
-{
-       struct usb_request      *req;
-
-       INFO(dev, "Received Printer Reset Request\n");
-
-       if (usb_ep_disable(dev->in_ep))
-               DBG(dev, "Failed to disable USB in_ep\n");
-       if (usb_ep_disable(dev->out_ep))
-               DBG(dev, "Failed to disable USB out_ep\n");
-
-       if (dev->current_rx_req != NULL) {
-               list_add(&dev->current_rx_req->list, &dev->rx_reqs);
-               dev->current_rx_req = NULL;
-       }
-       dev->current_rx_bytes = 0;
-       dev->current_rx_buf = NULL;
-       dev->reset_printer = 1;
-
-       while (likely(!(list_empty(&dev->rx_buffers)))) {
-               req = container_of(dev->rx_buffers.next, struct usb_request,
-                               list);
-               list_del_init(&req->list);
-               list_add(&req->list, &dev->rx_reqs);
-       }
-
-       while (likely(!(list_empty(&dev->rx_reqs_active)))) {
-               req = container_of(dev->rx_buffers.next, struct usb_request,
-                               list);
-               list_del_init(&req->list);
-               list_add(&req->list, &dev->rx_reqs);
-       }
-
-       while (likely(!(list_empty(&dev->tx_reqs_active)))) {
-               req = container_of(dev->tx_reqs_active.next,
-                               struct usb_request, list);
-               list_del_init(&req->list);
-               list_add(&req->list, &dev->tx_reqs);
-       }
-
-       if (usb_ep_enable(dev->in_ep))
-               DBG(dev, "Failed to enable USB in_ep\n");
-       if (usb_ep_enable(dev->out_ep))
-               DBG(dev, "Failed to enable USB out_ep\n");
-
-       wake_up_interruptible(&dev->rx_wait);
-       wake_up_interruptible(&dev->tx_wait);
-       wake_up_interruptible(&dev->tx_flush_wait);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * The setup() callback implements all the ep0 functionality that's not
- * handled lower down.
- */
-static int printer_func_setup(struct usb_function *f,
-               const struct usb_ctrlrequest *ctrl)
-{
-       struct printer_dev *dev = container_of(f, struct printer_dev, function);
-       struct usb_composite_dev *cdev = f->config->cdev;
-       struct usb_request      *req = cdev->req;
-       int                     value = -EOPNOTSUPP;
-       u16                     wIndex = le16_to_cpu(ctrl->wIndex);
-       u16                     wValue = le16_to_cpu(ctrl->wValue);
-       u16                     wLength = le16_to_cpu(ctrl->wLength);
-
-       DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
-               ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
-
-       switch (ctrl->bRequestType&USB_TYPE_MASK) {
-       case USB_TYPE_CLASS:
-               switch (ctrl->bRequest) {
-               case 0: /* Get the IEEE-1284 PNP String */
-                       /* Only one printer interface is supported. */
-                       if ((wIndex>>8) != dev->interface)
-                               break;
-
-                       value = (pnp_string[0]<<8)|pnp_string[1];
-                       memcpy(req->buf, pnp_string, value);
-                       DBG(dev, "1284 PNP String: %x %s\n", value,
-                                       &pnp_string[2]);
-                       break;
-
-               case 1: /* Get Port Status */
-                       /* Only one printer interface is supported. */
-                       if (wIndex != dev->interface)
-                               break;
-
-                       *(u8 *)req->buf = dev->printer_status;
-                       value = min(wLength, (u16) 1);
-                       break;
-
-               case 2: /* Soft Reset */
-                       /* Only one printer interface is supported. */
-                       if (wIndex != dev->interface)
-                               break;
-
-                       printer_soft_reset(dev);
-
-                       value = 0;
-                       break;
-
-               default:
-                       goto unknown;
-               }
-               break;
-
-       default:
-unknown:
-               VDBG(dev,
-                       "unknown ctrl req%02x.%02x v%04x i%04x l%d\n",
-                       ctrl->bRequestType, ctrl->bRequest,
-                       wValue, wIndex, wLength);
-               break;
-       }
-       /* host either stalls (value < 0) or reports success */
-       return value;
-}
-
-static int __init printer_func_bind(struct usb_configuration *c,
-               struct usb_function *f)
-{
-       struct printer_dev *dev = container_of(f, struct printer_dev, function);
-       struct usb_composite_dev *cdev = c->cdev;
-       struct usb_ep *in_ep;
-       struct usb_ep *out_ep = NULL;
-       int id;
-       int ret;
-
-       id = usb_interface_id(c, f);
-       if (id < 0)
-               return id;
-       intf_desc.bInterfaceNumber = id;
-
-       /* all we really need is bulk IN/OUT */
-       in_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_in_desc);
-       if (!in_ep) {
-autoconf_fail:
-               dev_err(&cdev->gadget->dev, "can't autoconfigure on %s\n",
-                       cdev->gadget->name);
-               return -ENODEV;
-       }
-       in_ep->driver_data = in_ep;     /* claim */
-
-       out_ep = usb_ep_autoconfig(cdev->gadget, &fs_ep_out_desc);
-       if (!out_ep)
-               goto autoconf_fail;
-       out_ep->driver_data = out_ep;   /* claim */
-
-       /* assumes that all endpoints are dual-speed */
-       hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
-       hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
-
-       ret = usb_assign_descriptors(f, fs_printer_function,
-                       hs_printer_function, NULL);
-       if (ret)
-               return ret;
-
-       dev->in_ep = in_ep;
-       dev->out_ep = out_ep;
-       return 0;
-}
-
-static void printer_func_unbind(struct usb_configuration *c,
-               struct usb_function *f)
-{
-       usb_free_all_descriptors(f);
-}
-
-static int printer_func_set_alt(struct usb_function *f,
-               unsigned intf, unsigned alt)
-{
-       struct printer_dev *dev = container_of(f, struct printer_dev, function);
-       int ret = -ENOTSUPP;
-
-       if (!alt)
-               ret = set_interface(dev, intf);
-
-       return ret;
-}
-
-static void printer_func_disable(struct usb_function *f)
-{
-       struct printer_dev *dev = container_of(f, struct printer_dev, function);
-       unsigned long           flags;
-
-       DBG(dev, "%s\n", __func__);
-
-       spin_lock_irqsave(&dev->lock, flags);
-       printer_reset_interface(dev);
-       spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-static void printer_cfg_unbind(struct usb_configuration *c)
-{
-       struct printer_dev      *dev;
-       struct usb_request      *req;
-
-       dev = &usb_printer_gadget;
-
-       DBG(dev, "%s\n", __func__);
-
-       /* Remove sysfs files */
-       device_destroy(usb_gadget_class, g_printer_devno);
-
-       /* Remove Character Device */
-       cdev_del(&dev->printer_cdev);
-
-       /* we must already have been disconnected ... no i/o may be active */
-       WARN_ON(!list_empty(&dev->tx_reqs_active));
-       WARN_ON(!list_empty(&dev->rx_reqs_active));
-
-       /* Free all memory for this driver. */
-       while (!list_empty(&dev->tx_reqs)) {
-               req = container_of(dev->tx_reqs.next, struct usb_request,
-                               list);
-               list_del(&req->list);
-               printer_req_free(dev->in_ep, req);
-       }
-
-       if (dev->current_rx_req != NULL)
-               printer_req_free(dev->out_ep, dev->current_rx_req);
-
-       while (!list_empty(&dev->rx_reqs)) {
-               req = container_of(dev->rx_reqs.next,
-                               struct usb_request, list);
-               list_del(&req->list);
-               printer_req_free(dev->out_ep, req);
-       }
-
-       while (!list_empty(&dev->rx_buffers)) {
-               req = container_of(dev->rx_buffers.next,
-                               struct usb_request, list);
-               list_del(&req->list);
-               printer_req_free(dev->out_ep, req);
-       }
-}
-
-static struct usb_configuration printer_cfg_driver = {
-       .label                  = "printer",
-       .unbind                 = printer_cfg_unbind,
-       .bConfigurationValue    = 1,
-       .bmAttributes           = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-};
-
-static int __init printer_bind_config(struct usb_configuration *c)
-{
-       struct usb_gadget       *gadget = c->cdev->gadget;
-       struct printer_dev      *dev;
-       int                     status = -ENOMEM;
-       size_t                  len;
-       u32                     i;
-       struct usb_request      *req;
-
-       usb_ep_autoconfig_reset(gadget);
-
-       dev = &usb_printer_gadget;
-
-       dev->function.name = shortname;
-       dev->function.bind = printer_func_bind;
-       dev->function.setup = printer_func_setup;
-       dev->function.unbind = printer_func_unbind;
-       dev->function.set_alt = printer_func_set_alt;
-       dev->function.disable = printer_func_disable;
-
-       status = usb_add_function(c, &dev->function);
-       if (status)
-               return status;
-
-       /* Setup the sysfs files for the printer gadget. */
-       dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
-                                 NULL, "g_printer");
-       if (IS_ERR(dev->pdev)) {
-               ERROR(dev, "Failed to create device: g_printer\n");
-               status = PTR_ERR(dev->pdev);
-               goto fail;
-       }
-
-       /*
-        * Register a character device as an interface to a user mode
-        * program that handles the printer specific functionality.
-        */
-       cdev_init(&dev->printer_cdev, &printer_io_operations);
-       dev->printer_cdev.owner = THIS_MODULE;
-       status = cdev_add(&dev->printer_cdev, g_printer_devno, 1);
-       if (status) {
-               ERROR(dev, "Failed to open char device\n");
-               goto fail;
-       }
-
-       if (iPNPstring)
-               strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2);
-
-       len = strlen(pnp_string);
-       pnp_string[0] = (len >> 8) & 0xFF;
-       pnp_string[1] = len & 0xFF;
-
-       usb_gadget_set_selfpowered(gadget);
-
-       if (gadget_is_otg(gadget)) {
-               otg_descriptor.bmAttributes |= USB_OTG_HNP;
-               printer_cfg_driver.descriptors = otg_desc;
-               printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       spin_lock_init(&dev->lock);
-       mutex_init(&dev->lock_printer_io);
-       INIT_LIST_HEAD(&dev->tx_reqs);
-       INIT_LIST_HEAD(&dev->tx_reqs_active);
-       INIT_LIST_HEAD(&dev->rx_reqs);
-       INIT_LIST_HEAD(&dev->rx_reqs_active);
-       INIT_LIST_HEAD(&dev->rx_buffers);
-       init_waitqueue_head(&dev->rx_wait);
-       init_waitqueue_head(&dev->tx_wait);
-       init_waitqueue_head(&dev->tx_flush_wait);
-
-       dev->interface = -1;
-       dev->printer_cdev_open = 0;
-       dev->printer_status = PRINTER_NOT_ERROR;
-       dev->current_rx_req = NULL;
-       dev->current_rx_bytes = 0;
-       dev->current_rx_buf = NULL;
-
-       for (i = 0; i < QLEN; i++) {
-               req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
-               if (!req) {
-                       while (!list_empty(&dev->tx_reqs)) {
-                               req = container_of(dev->tx_reqs.next,
-                                               struct usb_request, list);
-                               list_del(&req->list);
-                               printer_req_free(dev->in_ep, req);
-                       }
-                       return -ENOMEM;
-               }
-               list_add(&req->list, &dev->tx_reqs);
-       }
-
-       for (i = 0; i < QLEN; i++) {
-               req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL);
-               if (!req) {
-                       while (!list_empty(&dev->rx_reqs)) {
-                               req = container_of(dev->rx_reqs.next,
-                                               struct usb_request, list);
-                               list_del(&req->list);
-                               printer_req_free(dev->out_ep, req);
-                       }
-                       return -ENOMEM;
-               }
-               list_add(&req->list, &dev->rx_reqs);
-       }
-
-       /* finish hookup to lower layer ... */
-       dev->gadget = gadget;
-
-       INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
-       return 0;
-
-fail:
-       printer_cfg_unbind(c);
-       return status;
-}
-
-static int printer_unbind(struct usb_composite_dev *cdev)
-{
-       return 0;
-}
-
-static int __init printer_bind(struct usb_composite_dev *cdev)
-{
-       int ret;
-
-       ret = usb_string_ids_tab(cdev, strings);
-       if (ret < 0)
-               return ret;
-       device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id;
-       device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id;
-
-       ret = usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
-       if (ret)
-               return ret;
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       return ret;
-}
-
-static __refdata struct usb_composite_driver printer_driver = {
-       .name           = shortname,
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_HIGH,
-       .bind           = printer_bind,
-       .unbind         = printer_unbind,
-};
-
-static int __init
-init(void)
-{
-       int status;
-
-       usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
-       if (IS_ERR(usb_gadget_class)) {
-               status = PTR_ERR(usb_gadget_class);
-               pr_err("unable to create usb_gadget class %d\n", status);
-               return status;
-       }
-
-       status = alloc_chrdev_region(&g_printer_devno, 0, 1,
-                       "USB printer gadget");
-       if (status) {
-               pr_err("alloc_chrdev_region %d\n", status);
-               class_destroy(usb_gadget_class);
-               return status;
-       }
-
-       status = usb_composite_probe(&printer_driver);
-       if (status) {
-               class_destroy(usb_gadget_class);
-               unregister_chrdev_region(g_printer_devno, 1);
-               pr_err("usb_gadget_probe_driver %x\n", status);
-       }
-
-       return status;
-}
-module_init(init);
-
-static void __exit
-cleanup(void)
-{
-       mutex_lock(&usb_printer_gadget.lock_printer_io);
-       usb_composite_unregister(&printer_driver);
-       unregister_chrdev_region(g_printer_devno, 1);
-       class_destroy(usb_gadget_class);
-       mutex_unlock(&usb_printer_gadget.lock_printer_io);
-}
-module_exit(cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Craig Nadler");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
deleted file mode 100644 (file)
index 1f5f978..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * serial.c -- USB gadget serial driver
- *
- * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
- * Copyright (C) 2008 by David Brownell
- * Copyright (C) 2008 by Nokia Corporation
- *
- * This software is distributed under the terms of the GNU General
- * Public License ("GPL") as published by the Free Software Foundation,
- * either version 2 of that License or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-
-#include "u_serial.h"
-#include "gadget_chips.h"
-
-
-/* Defines */
-
-#define GS_VERSION_STR                 "v2.4"
-#define GS_VERSION_NUM                 0x2400
-
-#define GS_LONG_NAME                   "Gadget Serial"
-#define GS_VERSION_NAME                        GS_LONG_NAME " " GS_VERSION_STR
-
-/*-------------------------------------------------------------------------*/
-USB_GADGET_COMPOSITE_OPTIONS();
-
-/* Thanks to NetChip Technologies for donating this product ID.
-*
-* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
-* Instead:  allocate your own, using normal USB-IF procedures.
-*/
-#define GS_VENDOR_ID                   0x0525  /* NetChip */
-#define GS_PRODUCT_ID                  0xa4a6  /* Linux-USB Serial Gadget */
-#define GS_CDC_PRODUCT_ID              0xa4a7  /* ... as CDC-ACM */
-#define GS_CDC_OBEX_PRODUCT_ID         0xa4a9  /* ... as CDC-OBEX */
-
-/* string IDs are assigned dynamically */
-
-#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = GS_VERSION_NAME,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
-       {  } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              USB_DT_DEVICE_SIZE,
-       .bDescriptorType =      USB_DT_DEVICE,
-       .bcdUSB =               cpu_to_le16(0x0200),
-       /* .bDeviceClass = f(use_acm) */
-       .bDeviceSubClass =      0,
-       .bDeviceProtocol =      0,
-       /* .bMaxPacketSize0 = f(hardware) */
-       .idVendor =             cpu_to_le16(GS_VENDOR_ID),
-       /* .idProduct = f(use_acm) */
-       .bcdDevice = cpu_to_le16(GS_VERSION_NUM),
-       /* .iManufacturer = DYNAMIC */
-       /* .iProduct = DYNAMIC */
-       .bNumConfigurations =   1,
-};
-
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* Module */
-MODULE_DESCRIPTION(GS_VERSION_NAME);
-MODULE_AUTHOR("Al Borchers");
-MODULE_AUTHOR("David Brownell");
-MODULE_LICENSE("GPL");
-
-static bool use_acm = true;
-module_param(use_acm, bool, 0);
-MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
-
-static bool use_obex = false;
-module_param(use_obex, bool, 0);
-MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no");
-
-static unsigned n_ports = 1;
-module_param(n_ports, uint, 0);
-MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_configuration serial_config_driver = {
-       /* .label = f(use_acm) */
-       /* .bConfigurationValue = f(use_acm) */
-       /* .iConfiguration = DYNAMIC */
-       .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
-};
-
-static struct usb_function_instance *fi_serial[MAX_U_SERIAL_PORTS];
-static struct usb_function *f_serial[MAX_U_SERIAL_PORTS];
-
-static int serial_register_ports(struct usb_composite_dev *cdev,
-               struct usb_configuration *c, const char *f_name)
-{
-       int i;
-       int ret;
-
-       ret = usb_add_config_only(cdev, c);
-       if (ret)
-               goto out;
-
-       for (i = 0; i < n_ports; i++) {
-
-               fi_serial[i] = usb_get_function_instance(f_name);
-               if (IS_ERR(fi_serial[i])) {
-                       ret = PTR_ERR(fi_serial[i]);
-                       goto fail;
-               }
-
-               f_serial[i] = usb_get_function(fi_serial[i]);
-               if (IS_ERR(f_serial[i])) {
-                       ret = PTR_ERR(f_serial[i]);
-                       goto err_get_func;
-               }
-
-               ret = usb_add_function(c, f_serial[i]);
-               if (ret)
-                       goto err_add_func;
-       }
-
-       return 0;
-
-err_add_func:
-       usb_put_function(f_serial[i]);
-err_get_func:
-       usb_put_function_instance(fi_serial[i]);
-
-fail:
-       i--;
-       while (i >= 0) {
-               usb_remove_function(c, f_serial[i]);
-               usb_put_function(f_serial[i]);
-               usb_put_function_instance(fi_serial[i]);
-               i--;
-       }
-out:
-       return ret;
-}
-
-static int __init gs_bind(struct usb_composite_dev *cdev)
-{
-       int                     status;
-
-       /* Allocate string descriptor numbers ... note that string
-        * contents can be overridden by the composite_dev glue.
-        */
-
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               goto fail;
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-       status = strings_dev[STRING_DESCRIPTION_IDX].id;
-       serial_config_driver.iConfiguration = status;
-
-       if (gadget_is_otg(cdev->gadget)) {
-               serial_config_driver.descriptors = otg_desc;
-               serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       /* register our configuration */
-       if (use_acm) {
-               status  = serial_register_ports(cdev, &serial_config_driver,
-                               "acm");
-               usb_ep_autoconfig_reset(cdev->gadget);
-       } else if (use_obex)
-               status = serial_register_ports(cdev, &serial_config_driver,
-                               "obex");
-       else {
-               status = serial_register_ports(cdev, &serial_config_driver,
-                               "gser");
-       }
-       if (status < 0)
-               goto fail;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       INFO(cdev, "%s\n", GS_VERSION_NAME);
-
-       return 0;
-
-fail:
-       return status;
-}
-
-static int gs_unbind(struct usb_composite_dev *cdev)
-{
-       int i;
-
-       for (i = 0; i < n_ports; i++) {
-               usb_put_function(f_serial[i]);
-               usb_put_function_instance(fi_serial[i]);
-       }
-       return 0;
-}
-
-static __refdata struct usb_composite_driver gserial_driver = {
-       .name           = "g_serial",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_SUPER,
-       .bind           = gs_bind,
-       .unbind         = gs_unbind,
-};
-
-static int __init init(void)
-{
-       /* We *could* export two configs; that'd be much cleaner...
-        * but neither of these product IDs was defined that way.
-        */
-       if (use_acm) {
-               serial_config_driver.label = "CDC ACM config";
-               serial_config_driver.bConfigurationValue = 2;
-               device_desc.bDeviceClass = USB_CLASS_COMM;
-               device_desc.idProduct =
-                               cpu_to_le16(GS_CDC_PRODUCT_ID);
-       } else if (use_obex) {
-               serial_config_driver.label = "CDC OBEX config";
-               serial_config_driver.bConfigurationValue = 3;
-               device_desc.bDeviceClass = USB_CLASS_COMM;
-               device_desc.idProduct =
-                       cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
-       } else {
-               serial_config_driver.label = "Generic Serial config";
-               serial_config_driver.bConfigurationValue = 1;
-               device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
-               device_desc.idProduct =
-                               cpu_to_le16(GS_PRODUCT_ID);
-       }
-       strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
-
-       return usb_composite_probe(&gserial_driver);
-}
-module_init(init);
-
-static void __exit cleanup(void)
-{
-       usb_composite_unregister(&gserial_driver);
-}
-module_exit(cleanup);
diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c
deleted file mode 100644 (file)
index 6cdb7a5..0000000
+++ /dev/null
@@ -1,2473 +0,0 @@
-/* Target based USB-Gadget
- *
- * UAS protocol handling, target callbacks, configfs handling,
- * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling.
- *
- * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de>
- * License: GPLv2 as published by FSF.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/configfs.h>
-#include <linux/ctype.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/composite.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/storage.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_tcq.h>
-#include <target/target_core_base.h>
-#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/target_core_configfs.h>
-#include <target/configfs_macros.h>
-#include <asm/unaligned.h>
-
-#include "tcm_usb_gadget.h"
-
-USB_GADGET_COMPOSITE_OPTIONS();
-
-static struct target_fabric_configfs *usbg_fabric_configfs;
-
-static inline struct f_uas *to_f_uas(struct usb_function *f)
-{
-       return container_of(f, struct f_uas, function);
-}
-
-static void usbg_cmd_release(struct kref *);
-
-static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd)
-{
-       kref_put(&cmd->ref, usbg_cmd_release);
-}
-
-/* Start bot.c code */
-
-static int bot_enqueue_cmd_cbw(struct f_uas *fu)
-{
-       int ret;
-
-       if (fu->flags & USBG_BOT_CMD_PEND)
-               return 0;
-
-       ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC);
-       if (!ret)
-               fu->flags |= USBG_BOT_CMD_PEND;
-       return ret;
-}
-
-static void bot_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       struct usbg_cmd *cmd = req->context;
-       struct f_uas *fu = cmd->fu;
-
-       usbg_cleanup_cmd(cmd);
-       if (req->status < 0) {
-               pr_err("ERR %s(%d)\n", __func__, __LINE__);
-               return;
-       }
-
-       /* CSW completed, wait for next CBW */
-       bot_enqueue_cmd_cbw(fu);
-}
-
-static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd)
-{
-       struct bulk_cs_wrap *csw = &fu->bot_status.csw;
-       int ret;
-       u8 *sense;
-       unsigned int csw_stat;
-
-       csw_stat = cmd->csw_code;
-
-       /*
-        * We can't send SENSE as a response. So we take ASC & ASCQ from our
-        * sense buffer and queue it and hope the host sends a REQUEST_SENSE
-        * command where it learns why we failed.
-        */
-       sense = cmd->sense_iu.sense;
-
-       csw->Tag = cmd->bot_tag;
-       csw->Status = csw_stat;
-       fu->bot_status.req->context = cmd;
-       ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC);
-       if (ret)
-               pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
-}
-
-static void bot_err_compl(struct usb_ep *ep, struct usb_request *req)
-{
-       struct usbg_cmd *cmd = req->context;
-       struct f_uas *fu = cmd->fu;
-
-       if (req->status < 0)
-               pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
-       if (cmd->data_len) {
-               if (cmd->data_len > ep->maxpacket) {
-                       req->length = ep->maxpacket;
-                       cmd->data_len -= ep->maxpacket;
-               } else {
-                       req->length = cmd->data_len;
-                       cmd->data_len = 0;
-               }
-
-               usb_ep_queue(ep, req, GFP_ATOMIC);
-               return ;
-       }
-       bot_enqueue_sense_code(fu, cmd);
-}
-
-static void bot_send_bad_status(struct usbg_cmd *cmd)
-{
-       struct f_uas *fu = cmd->fu;
-       struct bulk_cs_wrap *csw = &fu->bot_status.csw;
-       struct usb_request *req;
-       struct usb_ep *ep;
-
-       csw->Residue = cpu_to_le32(cmd->data_len);
-
-       if (cmd->data_len) {
-               if (cmd->is_read) {
-                       ep = fu->ep_in;
-                       req = fu->bot_req_in;
-               } else {
-                       ep = fu->ep_out;
-                       req = fu->bot_req_out;
-               }
-
-               if (cmd->data_len > fu->ep_in->maxpacket) {
-                       req->length = ep->maxpacket;
-                       cmd->data_len -= ep->maxpacket;
-               } else {
-                       req->length = cmd->data_len;
-                       cmd->data_len = 0;
-               }
-               req->complete = bot_err_compl;
-               req->context = cmd;
-               req->buf = fu->cmd.buf;
-               usb_ep_queue(ep, req, GFP_KERNEL);
-       } else {
-               bot_enqueue_sense_code(fu, cmd);
-       }
-}
-
-static int bot_send_status(struct usbg_cmd *cmd, bool moved_data)
-{
-       struct f_uas *fu = cmd->fu;
-       struct bulk_cs_wrap *csw = &fu->bot_status.csw;
-       int ret;
-
-       if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) {
-               if (!moved_data && cmd->data_len) {
-                       /*
-                        * the host wants to move data, we don't. Fill / empty
-                        * the pipe and then send the csw with reside set.
-                        */
-                       cmd->csw_code = US_BULK_STAT_OK;
-                       bot_send_bad_status(cmd);
-                       return 0;
-               }
-
-               csw->Tag = cmd->bot_tag;
-               csw->Residue = cpu_to_le32(0);
-               csw->Status = US_BULK_STAT_OK;
-               fu->bot_status.req->context = cmd;
-
-               ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL);
-               if (ret)
-                       pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret);
-       } else {
-               cmd->csw_code = US_BULK_STAT_FAIL;
-               bot_send_bad_status(cmd);
-       }
-       return 0;
-}
-
-/*
- * Called after command (no data transfer) or after the write (to device)
- * operation is completed
- */
-static int bot_send_status_response(struct usbg_cmd *cmd)
-{
-       bool moved_data = false;
-
-       if (!cmd->is_read)
-               moved_data = true;
-       return bot_send_status(cmd, moved_data);
-}
-
-/* Read request completed, now we have to send the CSW */
-static void bot_read_compl(struct usb_ep *ep, struct usb_request *req)
-{
-       struct usbg_cmd *cmd = req->context;
-
-       if (req->status < 0)
-               pr_err("ERR %s(%d)\n", __func__, __LINE__);
-
-       bot_send_status(cmd, true);
-}
-
-static int bot_send_read_response(struct usbg_cmd *cmd)
-{
-       struct f_uas *fu = cmd->fu;
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct usb_gadget *gadget = fuas_to_gadget(fu);
-       int ret;
-
-       if (!cmd->data_len) {
-               cmd->csw_code = US_BULK_STAT_PHASE;
-               bot_send_bad_status(cmd);
-               return 0;
-       }
-
-       if (!gadget->sg_supported) {
-               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
-               if (!cmd->data_buf)
-                       return -ENOMEM;
-
-               sg_copy_to_buffer(se_cmd->t_data_sg,
-                               se_cmd->t_data_nents,
-                               cmd->data_buf,
-                               se_cmd->data_length);
-
-               fu->bot_req_in->buf = cmd->data_buf;
-       } else {
-               fu->bot_req_in->buf = NULL;
-               fu->bot_req_in->num_sgs = se_cmd->t_data_nents;
-               fu->bot_req_in->sg = se_cmd->t_data_sg;
-       }
-
-       fu->bot_req_in->complete = bot_read_compl;
-       fu->bot_req_in->length = se_cmd->data_length;
-       fu->bot_req_in->context = cmd;
-       ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC);
-       if (ret)
-               pr_err("%s(%d)\n", __func__, __LINE__);
-       return 0;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *);
-static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *);
-
-static int bot_send_write_request(struct usbg_cmd *cmd)
-{
-       struct f_uas *fu = cmd->fu;
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct usb_gadget *gadget = fuas_to_gadget(fu);
-       int ret;
-
-       init_completion(&cmd->write_complete);
-       cmd->fu = fu;
-
-       if (!cmd->data_len) {
-               cmd->csw_code = US_BULK_STAT_PHASE;
-               return -EINVAL;
-       }
-
-       if (!gadget->sg_supported) {
-               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
-               if (!cmd->data_buf)
-                       return -ENOMEM;
-
-               fu->bot_req_out->buf = cmd->data_buf;
-       } else {
-               fu->bot_req_out->buf = NULL;
-               fu->bot_req_out->num_sgs = se_cmd->t_data_nents;
-               fu->bot_req_out->sg = se_cmd->t_data_sg;
-       }
-
-       fu->bot_req_out->complete = usbg_data_write_cmpl;
-       fu->bot_req_out->length = se_cmd->data_length;
-       fu->bot_req_out->context = cmd;
-
-       ret = usbg_prepare_w_request(cmd, fu->bot_req_out);
-       if (ret)
-               goto cleanup;
-       ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL);
-       if (ret)
-               pr_err("%s(%d)\n", __func__, __LINE__);
-
-       wait_for_completion(&cmd->write_complete);
-       target_execute_cmd(se_cmd);
-cleanup:
-       return ret;
-}
-
-static int bot_submit_command(struct f_uas *, void *, unsigned int);
-
-static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       struct f_uas *fu = req->context;
-       int ret;
-
-       fu->flags &= ~USBG_BOT_CMD_PEND;
-
-       if (req->status < 0)
-               return;
-
-       ret = bot_submit_command(fu, req->buf, req->actual);
-       if (ret)
-               pr_err("%s(%d): %d\n", __func__, __LINE__, ret);
-}
-
-static int bot_prepare_reqs(struct f_uas *fu)
-{
-       int ret;
-
-       fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
-       if (!fu->bot_req_in)
-               goto err;
-
-       fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
-       if (!fu->bot_req_out)
-               goto err_out;
-
-       fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
-       if (!fu->cmd.req)
-               goto err_cmd;
-
-       fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
-       if (!fu->bot_status.req)
-               goto err_sts;
-
-       fu->bot_status.req->buf = &fu->bot_status.csw;
-       fu->bot_status.req->length = US_BULK_CS_WRAP_LEN;
-       fu->bot_status.req->complete = bot_status_complete;
-       fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN);
-
-       fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL);
-       if (!fu->cmd.buf)
-               goto err_buf;
-
-       fu->cmd.req->complete = bot_cmd_complete;
-       fu->cmd.req->buf = fu->cmd.buf;
-       fu->cmd.req->length = fu->ep_out->maxpacket;
-       fu->cmd.req->context = fu;
-
-       ret = bot_enqueue_cmd_cbw(fu);
-       if (ret)
-               goto err_queue;
-       return 0;
-err_queue:
-       kfree(fu->cmd.buf);
-       fu->cmd.buf = NULL;
-err_buf:
-       usb_ep_free_request(fu->ep_in, fu->bot_status.req);
-err_sts:
-       usb_ep_free_request(fu->ep_out, fu->cmd.req);
-       fu->cmd.req = NULL;
-err_cmd:
-       usb_ep_free_request(fu->ep_out, fu->bot_req_out);
-       fu->bot_req_out = NULL;
-err_out:
-       usb_ep_free_request(fu->ep_in, fu->bot_req_in);
-       fu->bot_req_in = NULL;
-err:
-       pr_err("BOT: endpoint setup failed\n");
-       return -ENOMEM;
-}
-
-static void bot_cleanup_old_alt(struct f_uas *fu)
-{
-       if (!(fu->flags & USBG_ENABLED))
-               return;
-
-       usb_ep_disable(fu->ep_in);
-       usb_ep_disable(fu->ep_out);
-
-       if (!fu->bot_req_in)
-               return;
-
-       usb_ep_free_request(fu->ep_in, fu->bot_req_in);
-       usb_ep_free_request(fu->ep_out, fu->bot_req_out);
-       usb_ep_free_request(fu->ep_out, fu->cmd.req);
-       usb_ep_free_request(fu->ep_out, fu->bot_status.req);
-
-       kfree(fu->cmd.buf);
-
-       fu->bot_req_in = NULL;
-       fu->bot_req_out = NULL;
-       fu->cmd.req = NULL;
-       fu->bot_status.req = NULL;
-       fu->cmd.buf = NULL;
-}
-
-static void bot_set_alt(struct f_uas *fu)
-{
-       struct usb_function *f = &fu->function;
-       struct usb_gadget *gadget = f->config->cdev->gadget;
-       int ret;
-
-       fu->flags = USBG_IS_BOT;
-
-       config_ep_by_speed(gadget, f, fu->ep_in);
-       ret = usb_ep_enable(fu->ep_in);
-       if (ret)
-               goto err_b_in;
-
-       config_ep_by_speed(gadget, f, fu->ep_out);
-       ret = usb_ep_enable(fu->ep_out);
-       if (ret)
-               goto err_b_out;
-
-       ret = bot_prepare_reqs(fu);
-       if (ret)
-               goto err_wq;
-       fu->flags |= USBG_ENABLED;
-       pr_info("Using the BOT protocol\n");
-       return;
-err_wq:
-       usb_ep_disable(fu->ep_out);
-err_b_out:
-       usb_ep_disable(fu->ep_in);
-err_b_in:
-       fu->flags = USBG_IS_BOT;
-}
-
-static int usbg_bot_setup(struct usb_function *f,
-               const struct usb_ctrlrequest *ctrl)
-{
-       struct f_uas *fu = to_f_uas(f);
-       struct usb_composite_dev *cdev = f->config->cdev;
-       u16 w_value = le16_to_cpu(ctrl->wValue);
-       u16 w_length = le16_to_cpu(ctrl->wLength);
-       int luns;
-       u8 *ret_lun;
-
-       switch (ctrl->bRequest) {
-       case US_BULK_GET_MAX_LUN:
-               if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS |
-                                       USB_RECIP_INTERFACE))
-                       return -ENOTSUPP;
-
-               if (w_length < 1)
-                       return -EINVAL;
-               if (w_value != 0)
-                       return -EINVAL;
-               luns = atomic_read(&fu->tpg->tpg_port_count);
-               if (!luns) {
-                       pr_err("No LUNs configured?\n");
-                       return -EINVAL;
-               }
-               /*
-                * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be
-                * accessed. The upper limit is 0xf
-                */
-               luns--;
-               if (luns > 0xf) {
-                       pr_info_once("Limiting the number of luns to 16\n");
-                       luns = 0xf;
-               }
-               ret_lun = cdev->req->buf;
-               *ret_lun = luns;
-               cdev->req->length = 1;
-               return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
-               break;
-
-       case US_BULK_RESET_REQUEST:
-               /* XXX maybe we should remove previous requests for IN + OUT */
-               bot_enqueue_cmd_cbw(fu);
-               return 0;
-               break;
-       }
-       return -ENOTSUPP;
-}
-
-/* Start uas.c code */
-
-static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream)
-{
-       /* We have either all three allocated or none */
-       if (!stream->req_in)
-               return;
-
-       usb_ep_free_request(fu->ep_in, stream->req_in);
-       usb_ep_free_request(fu->ep_out, stream->req_out);
-       usb_ep_free_request(fu->ep_status, stream->req_status);
-
-       stream->req_in = NULL;
-       stream->req_out = NULL;
-       stream->req_status = NULL;
-}
-
-static void uasp_free_cmdreq(struct f_uas *fu)
-{
-       usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
-       kfree(fu->cmd.buf);
-       fu->cmd.req = NULL;
-       fu->cmd.buf = NULL;
-}
-
-static void uasp_cleanup_old_alt(struct f_uas *fu)
-{
-       int i;
-
-       if (!(fu->flags & USBG_ENABLED))
-               return;
-
-       usb_ep_disable(fu->ep_in);
-       usb_ep_disable(fu->ep_out);
-       usb_ep_disable(fu->ep_status);
-       usb_ep_disable(fu->ep_cmd);
-
-       for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++)
-               uasp_cleanup_one_stream(fu, &fu->stream[i]);
-       uasp_free_cmdreq(fu);
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req);
-
-static int uasp_prepare_r_request(struct usbg_cmd *cmd)
-{
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct f_uas *fu = cmd->fu;
-       struct usb_gadget *gadget = fuas_to_gadget(fu);
-       struct uas_stream *stream = cmd->stream;
-
-       if (!gadget->sg_supported) {
-               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
-               if (!cmd->data_buf)
-                       return -ENOMEM;
-
-               sg_copy_to_buffer(se_cmd->t_data_sg,
-                               se_cmd->t_data_nents,
-                               cmd->data_buf,
-                               se_cmd->data_length);
-
-               stream->req_in->buf = cmd->data_buf;
-       } else {
-               stream->req_in->buf = NULL;
-               stream->req_in->num_sgs = se_cmd->t_data_nents;
-               stream->req_in->sg = se_cmd->t_data_sg;
-       }
-
-       stream->req_in->complete = uasp_status_data_cmpl;
-       stream->req_in->length = se_cmd->data_length;
-       stream->req_in->context = cmd;
-
-       cmd->state = UASP_SEND_STATUS;
-       return 0;
-}
-
-static void uasp_prepare_status(struct usbg_cmd *cmd)
-{
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct sense_iu *iu = &cmd->sense_iu;
-       struct uas_stream *stream = cmd->stream;
-
-       cmd->state = UASP_QUEUE_COMMAND;
-       iu->iu_id = IU_ID_STATUS;
-       iu->tag = cpu_to_be16(cmd->tag);
-
-       /*
-        * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?);
-        */
-       iu->len = cpu_to_be16(se_cmd->scsi_sense_length);
-       iu->status = se_cmd->scsi_status;
-       stream->req_status->context = cmd;
-       stream->req_status->length = se_cmd->scsi_sense_length + 16;
-       stream->req_status->buf = iu;
-       stream->req_status->complete = uasp_status_data_cmpl;
-}
-
-static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
-       struct usbg_cmd *cmd = req->context;
-       struct uas_stream *stream = cmd->stream;
-       struct f_uas *fu = cmd->fu;
-       int ret;
-
-       if (req->status < 0)
-               goto cleanup;
-
-       switch (cmd->state) {
-       case UASP_SEND_DATA:
-               ret = uasp_prepare_r_request(cmd);
-               if (ret)
-                       goto cleanup;
-               ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
-               if (ret)
-                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-               break;
-
-       case UASP_RECEIVE_DATA:
-               ret = usbg_prepare_w_request(cmd, stream->req_out);
-               if (ret)
-                       goto cleanup;
-               ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
-               if (ret)
-                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-               break;
-
-       case UASP_SEND_STATUS:
-               uasp_prepare_status(cmd);
-               ret = usb_ep_queue(fu->ep_status, stream->req_status,
-                               GFP_ATOMIC);
-               if (ret)
-                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-               break;
-
-       case UASP_QUEUE_COMMAND:
-               usbg_cleanup_cmd(cmd);
-               usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-               break;
-
-       default:
-               BUG();
-       }
-       return;
-
-cleanup:
-       usbg_cleanup_cmd(cmd);
-}
-
-static int uasp_send_status_response(struct usbg_cmd *cmd)
-{
-       struct f_uas *fu = cmd->fu;
-       struct uas_stream *stream = cmd->stream;
-       struct sense_iu *iu = &cmd->sense_iu;
-
-       iu->tag = cpu_to_be16(cmd->tag);
-       stream->req_status->complete = uasp_status_data_cmpl;
-       stream->req_status->context = cmd;
-       cmd->fu = fu;
-       uasp_prepare_status(cmd);
-       return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC);
-}
-
-static int uasp_send_read_response(struct usbg_cmd *cmd)
-{
-       struct f_uas *fu = cmd->fu;
-       struct uas_stream *stream = cmd->stream;
-       struct sense_iu *iu = &cmd->sense_iu;
-       int ret;
-
-       cmd->fu = fu;
-
-       iu->tag = cpu_to_be16(cmd->tag);
-       if (fu->flags & USBG_USE_STREAMS) {
-
-               ret = uasp_prepare_r_request(cmd);
-               if (ret)
-                       goto out;
-               ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC);
-               if (ret) {
-                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-                       kfree(cmd->data_buf);
-                       cmd->data_buf = NULL;
-               }
-
-       } else {
-
-               iu->iu_id = IU_ID_READ_READY;
-               iu->tag = cpu_to_be16(cmd->tag);
-
-               stream->req_status->complete = uasp_status_data_cmpl;
-               stream->req_status->context = cmd;
-
-               cmd->state = UASP_SEND_DATA;
-               stream->req_status->buf = iu;
-               stream->req_status->length = sizeof(struct iu);
-
-               ret = usb_ep_queue(fu->ep_status, stream->req_status,
-                               GFP_ATOMIC);
-               if (ret)
-                       pr_err("%s(%d) => %d\n", __func__, __LINE__, ret);
-       }
-out:
-       return ret;
-}
-
-static int uasp_send_write_request(struct usbg_cmd *cmd)
-{
-       struct f_uas *fu = cmd->fu;
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct uas_stream *stream = cmd->stream;
-       struct sense_iu *iu = &cmd->sense_iu;
-       int ret;
-
-       init_completion(&cmd->write_complete);
-       cmd->fu = fu;
-
-       iu->tag = cpu_to_be16(cmd->tag);
-
-       if (fu->flags & USBG_USE_STREAMS) {
-
-               ret = usbg_prepare_w_request(cmd, stream->req_out);
-               if (ret)
-                       goto cleanup;
-               ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC);
-               if (ret)
-                       pr_err("%s(%d)\n", __func__, __LINE__);
-
-       } else {
-
-               iu->iu_id = IU_ID_WRITE_READY;
-               iu->tag = cpu_to_be16(cmd->tag);
-
-               stream->req_status->complete = uasp_status_data_cmpl;
-               stream->req_status->context = cmd;
-
-               cmd->state = UASP_RECEIVE_DATA;
-               stream->req_status->buf = iu;
-               stream->req_status->length = sizeof(struct iu);
-
-               ret = usb_ep_queue(fu->ep_status, stream->req_status,
-                               GFP_ATOMIC);
-               if (ret)
-                       pr_err("%s(%d)\n", __func__, __LINE__);
-       }
-
-       wait_for_completion(&cmd->write_complete);
-       target_execute_cmd(se_cmd);
-cleanup:
-       return ret;
-}
-
-static int usbg_submit_command(struct f_uas *, void *, unsigned int);
-
-static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req)
-{
-       struct f_uas *fu = req->context;
-       int ret;
-
-       if (req->status < 0)
-               return;
-
-       ret = usbg_submit_command(fu, req->buf, req->actual);
-       /*
-        * Once we tune for performance enqueue the command req here again so
-        * we can receive a second command while we processing this one. Pay
-        * attention to properly sync STAUS endpoint with DATA IN + OUT so you
-        * don't break HS.
-        */
-       if (!ret)
-               return;
-       usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-}
-
-static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream)
-{
-       stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL);
-       if (!stream->req_in)
-               goto out;
-
-       stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL);
-       if (!stream->req_out)
-               goto err_out;
-
-       stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL);
-       if (!stream->req_status)
-               goto err_sts;
-
-       return 0;
-err_sts:
-       usb_ep_free_request(fu->ep_status, stream->req_status);
-       stream->req_status = NULL;
-err_out:
-       usb_ep_free_request(fu->ep_out, stream->req_out);
-       stream->req_out = NULL;
-out:
-       return -ENOMEM;
-}
-
-static int uasp_alloc_cmd(struct f_uas *fu)
-{
-       fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL);
-       if (!fu->cmd.req)
-               goto err;
-
-       fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL);
-       if (!fu->cmd.buf)
-               goto err_buf;
-
-       fu->cmd.req->complete = uasp_cmd_complete;
-       fu->cmd.req->buf = fu->cmd.buf;
-       fu->cmd.req->length = fu->ep_cmd->maxpacket;
-       fu->cmd.req->context = fu;
-       return 0;
-
-err_buf:
-       usb_ep_free_request(fu->ep_cmd, fu->cmd.req);
-err:
-       return -ENOMEM;
-}
-
-static void uasp_setup_stream_res(struct f_uas *fu, int max_streams)
-{
-       int i;
-
-       for (i = 0; i < max_streams; i++) {
-               struct uas_stream *s = &fu->stream[i];
-
-               s->req_in->stream_id = i + 1;
-               s->req_out->stream_id = i + 1;
-               s->req_status->stream_id = i + 1;
-       }
-}
-
-static int uasp_prepare_reqs(struct f_uas *fu)
-{
-       int ret;
-       int i;
-       int max_streams;
-
-       if (fu->flags & USBG_USE_STREAMS)
-               max_streams = UASP_SS_EP_COMP_NUM_STREAMS;
-       else
-               max_streams = 1;
-
-       for (i = 0; i < max_streams; i++) {
-               ret = uasp_alloc_stream_res(fu, &fu->stream[i]);
-               if (ret)
-                       goto err_cleanup;
-       }
-
-       ret = uasp_alloc_cmd(fu);
-       if (ret)
-               goto err_free_stream;
-       uasp_setup_stream_res(fu, max_streams);
-
-       ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC);
-       if (ret)
-               goto err_free_stream;
-
-       return 0;
-
-err_free_stream:
-       uasp_free_cmdreq(fu);
-
-err_cleanup:
-       if (i) {
-               do {
-                       uasp_cleanup_one_stream(fu, &fu->stream[i - 1]);
-                       i--;
-               } while (i);
-       }
-       pr_err("UASP: endpoint setup failed\n");
-       return ret;
-}
-
-static void uasp_set_alt(struct f_uas *fu)
-{
-       struct usb_function *f = &fu->function;
-       struct usb_gadget *gadget = f->config->cdev->gadget;
-       int ret;
-
-       fu->flags = USBG_IS_UAS;
-
-       if (gadget->speed == USB_SPEED_SUPER)
-               fu->flags |= USBG_USE_STREAMS;
-
-       config_ep_by_speed(gadget, f, fu->ep_in);
-       ret = usb_ep_enable(fu->ep_in);
-       if (ret)
-               goto err_b_in;
-
-       config_ep_by_speed(gadget, f, fu->ep_out);
-       ret = usb_ep_enable(fu->ep_out);
-       if (ret)
-               goto err_b_out;
-
-       config_ep_by_speed(gadget, f, fu->ep_cmd);
-       ret = usb_ep_enable(fu->ep_cmd);
-       if (ret)
-               goto err_cmd;
-       config_ep_by_speed(gadget, f, fu->ep_status);
-       ret = usb_ep_enable(fu->ep_status);
-       if (ret)
-               goto err_status;
-
-       ret = uasp_prepare_reqs(fu);
-       if (ret)
-               goto err_wq;
-       fu->flags |= USBG_ENABLED;
-
-       pr_info("Using the UAS protocol\n");
-       return;
-err_wq:
-       usb_ep_disable(fu->ep_status);
-err_status:
-       usb_ep_disable(fu->ep_cmd);
-err_cmd:
-       usb_ep_disable(fu->ep_out);
-err_b_out:
-       usb_ep_disable(fu->ep_in);
-err_b_in:
-       fu->flags = 0;
-}
-
-static int get_cmd_dir(const unsigned char *cdb)
-{
-       int ret;
-
-       switch (cdb[0]) {
-       case READ_6:
-       case READ_10:
-       case READ_12:
-       case READ_16:
-       case INQUIRY:
-       case MODE_SENSE:
-       case MODE_SENSE_10:
-       case SERVICE_ACTION_IN:
-       case MAINTENANCE_IN:
-       case PERSISTENT_RESERVE_IN:
-       case SECURITY_PROTOCOL_IN:
-       case ACCESS_CONTROL_IN:
-       case REPORT_LUNS:
-       case READ_BLOCK_LIMITS:
-       case READ_POSITION:
-       case READ_CAPACITY:
-       case READ_TOC:
-       case READ_FORMAT_CAPACITIES:
-       case REQUEST_SENSE:
-               ret = DMA_FROM_DEVICE;
-               break;
-
-       case WRITE_6:
-       case WRITE_10:
-       case WRITE_12:
-       case WRITE_16:
-       case MODE_SELECT:
-       case MODE_SELECT_10:
-       case WRITE_VERIFY:
-       case WRITE_VERIFY_12:
-       case PERSISTENT_RESERVE_OUT:
-       case MAINTENANCE_OUT:
-       case SECURITY_PROTOCOL_OUT:
-       case ACCESS_CONTROL_OUT:
-               ret = DMA_TO_DEVICE;
-               break;
-       case ALLOW_MEDIUM_REMOVAL:
-       case TEST_UNIT_READY:
-       case SYNCHRONIZE_CACHE:
-       case START_STOP:
-       case ERASE:
-       case REZERO_UNIT:
-       case SEEK_10:
-       case SPACE:
-       case VERIFY:
-       case WRITE_FILEMARKS:
-               ret = DMA_NONE;
-               break;
-       default:
-               pr_warn("target: Unknown data direction for SCSI Opcode "
-                               "0x%02x\n", cdb[0]);
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req)
-{
-       struct usbg_cmd *cmd = req->context;
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-
-       if (req->status < 0) {
-               pr_err("%s() state %d transfer failed\n", __func__, cmd->state);
-               goto cleanup;
-       }
-
-       if (req->num_sgs == 0) {
-               sg_copy_from_buffer(se_cmd->t_data_sg,
-                               se_cmd->t_data_nents,
-                               cmd->data_buf,
-                               se_cmd->data_length);
-       }
-
-       complete(&cmd->write_complete);
-       return;
-
-cleanup:
-       usbg_cleanup_cmd(cmd);
-}
-
-static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req)
-{
-       struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct f_uas *fu = cmd->fu;
-       struct usb_gadget *gadget = fuas_to_gadget(fu);
-
-       if (!gadget->sg_supported) {
-               cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC);
-               if (!cmd->data_buf)
-                       return -ENOMEM;
-
-               req->buf = cmd->data_buf;
-       } else {
-               req->buf = NULL;
-               req->num_sgs = se_cmd->t_data_nents;
-               req->sg = se_cmd->t_data_sg;
-       }
-
-       req->complete = usbg_data_write_cmpl;
-       req->length = se_cmd->data_length;
-       req->context = cmd;
-       return 0;
-}
-
-static int usbg_send_status_response(struct se_cmd *se_cmd)
-{
-       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-                       se_cmd);
-       struct f_uas *fu = cmd->fu;
-
-       if (fu->flags & USBG_IS_BOT)
-               return bot_send_status_response(cmd);
-       else
-               return uasp_send_status_response(cmd);
-}
-
-static int usbg_send_write_request(struct se_cmd *se_cmd)
-{
-       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-                       se_cmd);
-       struct f_uas *fu = cmd->fu;
-
-       if (fu->flags & USBG_IS_BOT)
-               return bot_send_write_request(cmd);
-       else
-               return uasp_send_write_request(cmd);
-}
-
-static int usbg_send_read_response(struct se_cmd *se_cmd)
-{
-       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-                       se_cmd);
-       struct f_uas *fu = cmd->fu;
-
-       if (fu->flags & USBG_IS_BOT)
-               return bot_send_read_response(cmd);
-       else
-               return uasp_send_read_response(cmd);
-}
-
-static void usbg_cmd_work(struct work_struct *work)
-{
-       struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
-       struct se_cmd *se_cmd;
-       struct tcm_usbg_nexus *tv_nexus;
-       struct usbg_tpg *tpg;
-       int dir;
-
-       se_cmd = &cmd->se_cmd;
-       tpg = cmd->fu->tpg;
-       tv_nexus = tpg->tpg_nexus;
-       dir = get_cmd_dir(cmd->cmd_buf);
-       if (dir < 0) {
-               transport_init_se_cmd(se_cmd,
-                               tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
-                               tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
-                               cmd->prio_attr, cmd->sense_iu.sense);
-               goto out;
-       }
-
-       if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
-                       cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
-                       0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE) < 0)
-               goto out;
-
-       return;
-
-out:
-       transport_send_check_condition_and_sense(se_cmd,
-                       TCM_UNSUPPORTED_SCSI_OPCODE, 1);
-       usbg_cleanup_cmd(cmd);
-}
-
-static int usbg_submit_command(struct f_uas *fu,
-               void *cmdbuf, unsigned int len)
-{
-       struct command_iu *cmd_iu = cmdbuf;
-       struct usbg_cmd *cmd;
-       struct usbg_tpg *tpg;
-       struct se_cmd *se_cmd;
-       struct tcm_usbg_nexus *tv_nexus;
-       u32 cmd_len;
-       int ret;
-
-       if (cmd_iu->iu_id != IU_ID_COMMAND) {
-               pr_err("Unsupported type %d\n", cmd_iu->iu_id);
-               return -EINVAL;
-       }
-
-       cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
-       if (!cmd)
-               return -ENOMEM;
-
-       cmd->fu = fu;
-
-       /* XXX until I figure out why I can't free in on complete */
-       kref_init(&cmd->ref);
-       kref_get(&cmd->ref);
-
-       tpg = fu->tpg;
-       cmd_len = (cmd_iu->len & ~0x3) + 16;
-       if (cmd_len > USBG_MAX_CMD)
-               goto err;
-
-       memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len);
-
-       cmd->tag = be16_to_cpup(&cmd_iu->tag);
-       if (fu->flags & USBG_USE_STREAMS) {
-               if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS)
-                       goto err;
-               if (!cmd->tag)
-                       cmd->stream = &fu->stream[0];
-               else
-                       cmd->stream = &fu->stream[cmd->tag - 1];
-       } else {
-               cmd->stream = &fu->stream[0];
-       }
-
-       tv_nexus = tpg->tpg_nexus;
-       if (!tv_nexus) {
-               pr_err("Missing nexus, ignoring command\n");
-               goto err;
-       }
-
-       switch (cmd_iu->prio_attr & 0x7) {
-       case UAS_HEAD_TAG:
-               cmd->prio_attr = MSG_HEAD_TAG;
-               break;
-       case UAS_ORDERED_TAG:
-               cmd->prio_attr = MSG_ORDERED_TAG;
-               break;
-       case UAS_ACA:
-               cmd->prio_attr = MSG_ACA_TAG;
-               break;
-       default:
-               pr_debug_once("Unsupported prio_attr: %02x.\n",
-                               cmd_iu->prio_attr);
-       case UAS_SIMPLE_TAG:
-               cmd->prio_attr = MSG_SIMPLE_TAG;
-               break;
-       }
-
-       se_cmd = &cmd->se_cmd;
-       cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun);
-
-       INIT_WORK(&cmd->work, usbg_cmd_work);
-       ret = queue_work(tpg->workqueue, &cmd->work);
-       if (ret < 0)
-               goto err;
-
-       return 0;
-err:
-       kfree(cmd);
-       return -EINVAL;
-}
-
-static void bot_cmd_work(struct work_struct *work)
-{
-       struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work);
-       struct se_cmd *se_cmd;
-       struct tcm_usbg_nexus *tv_nexus;
-       struct usbg_tpg *tpg;
-       int dir;
-
-       se_cmd = &cmd->se_cmd;
-       tpg = cmd->fu->tpg;
-       tv_nexus = tpg->tpg_nexus;
-       dir = get_cmd_dir(cmd->cmd_buf);
-       if (dir < 0) {
-               transport_init_se_cmd(se_cmd,
-                               tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo,
-                               tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE,
-                               cmd->prio_attr, cmd->sense_iu.sense);
-               goto out;
-       }
-
-       if (target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess,
-                       cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun,
-                       cmd->data_len, cmd->prio_attr, dir, 0) < 0)
-               goto out;
-
-       return;
-
-out:
-       transport_send_check_condition_and_sense(se_cmd,
-                               TCM_UNSUPPORTED_SCSI_OPCODE, 1);
-       usbg_cleanup_cmd(cmd);
-}
-
-static int bot_submit_command(struct f_uas *fu,
-               void *cmdbuf, unsigned int len)
-{
-       struct bulk_cb_wrap *cbw = cmdbuf;
-       struct usbg_cmd *cmd;
-       struct usbg_tpg *tpg;
-       struct se_cmd *se_cmd;
-       struct tcm_usbg_nexus *tv_nexus;
-       u32 cmd_len;
-       int ret;
-
-       if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) {
-               pr_err("Wrong signature on CBW\n");
-               return -EINVAL;
-       }
-       if (len != 31) {
-               pr_err("Wrong length for CBW\n");
-               return -EINVAL;
-       }
-
-       cmd_len = cbw->Length;
-       if (cmd_len < 1 || cmd_len > 16)
-               return -EINVAL;
-
-       cmd = kzalloc(sizeof *cmd, GFP_ATOMIC);
-       if (!cmd)
-               return -ENOMEM;
-
-       cmd->fu = fu;
-
-       /* XXX until I figure out why I can't free in on complete */
-       kref_init(&cmd->ref);
-       kref_get(&cmd->ref);
-
-       tpg = fu->tpg;
-
-       memcpy(cmd->cmd_buf, cbw->CDB, cmd_len);
-
-       cmd->bot_tag = cbw->Tag;
-
-       tv_nexus = tpg->tpg_nexus;
-       if (!tv_nexus) {
-               pr_err("Missing nexus, ignoring command\n");
-               goto err;
-       }
-
-       cmd->prio_attr = MSG_SIMPLE_TAG;
-       se_cmd = &cmd->se_cmd;
-       cmd->unpacked_lun = cbw->Lun;
-       cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0;
-       cmd->data_len = le32_to_cpu(cbw->DataTransferLength);
-
-       INIT_WORK(&cmd->work, bot_cmd_work);
-       ret = queue_work(tpg->workqueue, &cmd->work);
-       if (ret < 0)
-               goto err;
-
-       return 0;
-err:
-       kfree(cmd);
-       return -EINVAL;
-}
-
-/* Start fabric.c code */
-
-static int usbg_check_true(struct se_portal_group *se_tpg)
-{
-       return 1;
-}
-
-static int usbg_check_false(struct se_portal_group *se_tpg)
-{
-       return 0;
-}
-
-static char *usbg_get_fabric_name(void)
-{
-       return "usb_gadget";
-}
-
-static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg,
-                               struct usbg_tpg, se_tpg);
-       struct usbg_tport *tport = tpg->tport;
-       u8 proto_id;
-
-       switch (tport->tport_proto_id) {
-       case SCSI_PROTOCOL_SAS:
-       default:
-               proto_id = sas_get_fabric_proto_ident(se_tpg);
-               break;
-       }
-
-       return proto_id;
-}
-
-static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg,
-                               struct usbg_tpg, se_tpg);
-       struct usbg_tport *tport = tpg->tport;
-
-       return &tport->tport_name[0];
-}
-
-static u16 usbg_get_tag(struct se_portal_group *se_tpg)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg,
-                               struct usbg_tpg, se_tpg);
-       return tpg->tport_tpgt;
-}
-
-static u32 usbg_get_default_depth(struct se_portal_group *se_tpg)
-{
-       return 1;
-}
-
-static u32 usbg_get_pr_transport_id(
-       struct se_portal_group *se_tpg,
-       struct se_node_acl *se_nacl,
-       struct t10_pr_registration *pr_reg,
-       int *format_code,
-       unsigned char *buf)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg,
-                               struct usbg_tpg, se_tpg);
-       struct usbg_tport *tport = tpg->tport;
-       int ret = 0;
-
-       switch (tport->tport_proto_id) {
-       case SCSI_PROTOCOL_SAS:
-       default:
-               ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
-                                       format_code, buf);
-               break;
-       }
-
-       return ret;
-}
-
-static u32 usbg_get_pr_transport_id_len(
-       struct se_portal_group *se_tpg,
-       struct se_node_acl *se_nacl,
-       struct t10_pr_registration *pr_reg,
-       int *format_code)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg,
-                               struct usbg_tpg, se_tpg);
-       struct usbg_tport *tport = tpg->tport;
-       int ret = 0;
-
-       switch (tport->tport_proto_id) {
-       case SCSI_PROTOCOL_SAS:
-       default:
-               ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
-                                       format_code);
-               break;
-       }
-
-       return ret;
-}
-
-static char *usbg_parse_pr_out_transport_id(
-       struct se_portal_group *se_tpg,
-       const char *buf,
-       u32 *out_tid_len,
-       char **port_nexus_ptr)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg,
-                               struct usbg_tpg, se_tpg);
-       struct usbg_tport *tport = tpg->tport;
-       char *tid = NULL;
-
-       switch (tport->tport_proto_id) {
-       case SCSI_PROTOCOL_SAS:
-       default:
-               tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
-                                       port_nexus_ptr);
-       }
-
-       return tid;
-}
-
-static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)
-{
-       struct usbg_nacl *nacl;
-
-       nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL);
-       if (!nacl)
-               return NULL;
-
-       return &nacl->se_node_acl;
-}
-
-static void usbg_release_fabric_acl(
-       struct se_portal_group *se_tpg,
-       struct se_node_acl *se_nacl)
-{
-       struct usbg_nacl *nacl = container_of(se_nacl,
-                       struct usbg_nacl, se_node_acl);
-       kfree(nacl);
-}
-
-static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg)
-{
-       return 1;
-}
-
-static void usbg_cmd_release(struct kref *ref)
-{
-       struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd,
-                       ref);
-
-       transport_generic_free_cmd(&cmd->se_cmd, 0);
-}
-
-static void usbg_release_cmd(struct se_cmd *se_cmd)
-{
-       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-                       se_cmd);
-       kfree(cmd->data_buf);
-       kfree(cmd);
-       return;
-}
-
-static int usbg_shutdown_session(struct se_session *se_sess)
-{
-       return 0;
-}
-
-static void usbg_close_session(struct se_session *se_sess)
-{
-       return;
-}
-
-static u32 usbg_sess_get_index(struct se_session *se_sess)
-{
-       return 0;
-}
-
-/*
- * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be
- */
-static int usbg_write_pending_status(struct se_cmd *se_cmd)
-{
-       return 0;
-}
-
-static void usbg_set_default_node_attrs(struct se_node_acl *nacl)
-{
-       return;
-}
-
-static u32 usbg_get_task_tag(struct se_cmd *se_cmd)
-{
-       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-                       se_cmd);
-       struct f_uas *fu = cmd->fu;
-
-       if (fu->flags & USBG_IS_BOT)
-               return le32_to_cpu(cmd->bot_tag);
-       else
-               return cmd->tag;
-}
-
-static int usbg_get_cmd_state(struct se_cmd *se_cmd)
-{
-       return 0;
-}
-
-static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)
-{
-}
-
-static void usbg_aborted_task(struct se_cmd *se_cmd)
-{
-       return;
-}
-
-static const char *usbg_check_wwn(const char *name)
-{
-       const char *n;
-       unsigned int len;
-
-       n = strstr(name, "naa.");
-       if (!n)
-               return NULL;
-       n += 4;
-       len = strlen(n);
-       if (len == 0 || len > USBG_NAMELEN - 1)
-               return NULL;
-       return n;
-}
-
-static struct se_node_acl *usbg_make_nodeacl(
-       struct se_portal_group *se_tpg,
-       struct config_group *group,
-       const char *name)
-{
-       struct se_node_acl *se_nacl, *se_nacl_new;
-       struct usbg_nacl *nacl;
-       u64 wwpn = 0;
-       u32 nexus_depth;
-       const char *wnn_name;
-
-       wnn_name = usbg_check_wwn(name);
-       if (!wnn_name)
-               return ERR_PTR(-EINVAL);
-       se_nacl_new = usbg_alloc_fabric_acl(se_tpg);
-       if (!(se_nacl_new))
-               return ERR_PTR(-ENOMEM);
-
-       nexus_depth = 1;
-       /*
-        * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
-        * when converting a NodeACL from demo mode -> explict
-        */
-       se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
-                               name, nexus_depth);
-       if (IS_ERR(se_nacl)) {
-               usbg_release_fabric_acl(se_tpg, se_nacl_new);
-               return se_nacl;
-       }
-       /*
-        * Locate our struct usbg_nacl and set the FC Nport WWPN
-        */
-       nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl);
-       nacl->iport_wwpn = wwpn;
-       snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name);
-       return se_nacl;
-}
-
-static void usbg_drop_nodeacl(struct se_node_acl *se_acl)
-{
-       struct usbg_nacl *nacl = container_of(se_acl,
-                               struct usbg_nacl, se_node_acl);
-       core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
-       kfree(nacl);
-}
-
-struct usbg_tpg *the_only_tpg_I_currently_have;
-
-static struct se_portal_group *usbg_make_tpg(
-       struct se_wwn *wwn,
-       struct config_group *group,
-       const char *name)
-{
-       struct usbg_tport *tport = container_of(wwn, struct usbg_tport,
-                       tport_wwn);
-       struct usbg_tpg *tpg;
-       unsigned long tpgt;
-       int ret;
-
-       if (strstr(name, "tpgt_") != name)
-               return ERR_PTR(-EINVAL);
-       if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX)
-               return ERR_PTR(-EINVAL);
-       if (the_only_tpg_I_currently_have) {
-               pr_err("Until the gadget framework can't handle multiple\n");
-               pr_err("gadgets, you can't do this here.\n");
-               return ERR_PTR(-EBUSY);
-       }
-
-       tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL);
-       if (!tpg)
-               return ERR_PTR(-ENOMEM);
-       mutex_init(&tpg->tpg_mutex);
-       atomic_set(&tpg->tpg_port_count, 0);
-       tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1);
-       if (!tpg->workqueue) {
-               kfree(tpg);
-               return NULL;
-       }
-
-       tpg->tport = tport;
-       tpg->tport_tpgt = tpgt;
-
-       ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn,
-                               &tpg->se_tpg, tpg,
-                               TRANSPORT_TPG_TYPE_NORMAL);
-       if (ret < 0) {
-               destroy_workqueue(tpg->workqueue);
-               kfree(tpg);
-               return NULL;
-       }
-       the_only_tpg_I_currently_have = tpg;
-       return &tpg->se_tpg;
-}
-
-static void usbg_drop_tpg(struct se_portal_group *se_tpg)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg,
-                               struct usbg_tpg, se_tpg);
-
-       core_tpg_deregister(se_tpg);
-       destroy_workqueue(tpg->workqueue);
-       kfree(tpg);
-       the_only_tpg_I_currently_have = NULL;
-}
-
-static struct se_wwn *usbg_make_tport(
-       struct target_fabric_configfs *tf,
-       struct config_group *group,
-       const char *name)
-{
-       struct usbg_tport *tport;
-       const char *wnn_name;
-       u64 wwpn = 0;
-
-       wnn_name = usbg_check_wwn(name);
-       if (!wnn_name)
-               return ERR_PTR(-EINVAL);
-
-       tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL);
-       if (!(tport))
-               return ERR_PTR(-ENOMEM);
-       tport->tport_wwpn = wwpn;
-       snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);
-       return &tport->tport_wwn;
-}
-
-static void usbg_drop_tport(struct se_wwn *wwn)
-{
-       struct usbg_tport *tport = container_of(wwn,
-                               struct usbg_tport, tport_wwn);
-       kfree(tport);
-}
-
-/*
- * If somebody feels like dropping the version property, go ahead.
- */
-static ssize_t usbg_wwn_show_attr_version(
-       struct target_fabric_configfs *tf,
-       char *page)
-{
-       return sprintf(page, "usb-gadget fabric module\n");
-}
-TF_WWN_ATTR_RO(usbg, version);
-
-static struct configfs_attribute *usbg_wwn_attrs[] = {
-       &usbg_wwn_version.attr,
-       NULL,
-};
-
-static ssize_t tcm_usbg_tpg_show_enable(
-               struct se_portal_group *se_tpg,
-               char *page)
-{
-       struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
-       return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
-}
-
-static int usbg_attach(struct usbg_tpg *);
-static void usbg_detach(struct usbg_tpg *);
-
-static ssize_t tcm_usbg_tpg_store_enable(
-               struct se_portal_group *se_tpg,
-               const char *page,
-               size_t count)
-{
-       struct usbg_tpg  *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-       unsigned long op;
-       ssize_t ret;
-
-       ret = kstrtoul(page, 0, &op);
-       if (ret < 0)
-               return -EINVAL;
-       if (op > 1)
-               return -EINVAL;
-
-       if (op && tpg->gadget_connect)
-               goto out;
-       if (!op && !tpg->gadget_connect)
-               goto out;
-
-       if (op) {
-               ret = usbg_attach(tpg);
-               if (ret)
-                       goto out;
-       } else {
-               usbg_detach(tpg);
-       }
-       tpg->gadget_connect = op;
-out:
-       return count;
-}
-TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
-
-static ssize_t tcm_usbg_tpg_show_nexus(
-               struct se_portal_group *se_tpg,
-               char *page)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-       struct tcm_usbg_nexus *tv_nexus;
-       ssize_t ret;
-
-       mutex_lock(&tpg->tpg_mutex);
-       tv_nexus = tpg->tpg_nexus;
-       if (!tv_nexus) {
-               ret = -ENODEV;
-               goto out;
-       }
-       ret = snprintf(page, PAGE_SIZE, "%s\n",
-                       tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
-out:
-       mutex_unlock(&tpg->tpg_mutex);
-       return ret;
-}
-
-static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)
-{
-       struct se_portal_group *se_tpg;
-       struct tcm_usbg_nexus *tv_nexus;
-       int ret;
-
-       mutex_lock(&tpg->tpg_mutex);
-       if (tpg->tpg_nexus) {
-               ret = -EEXIST;
-               pr_debug("tpg->tpg_nexus already exists\n");
-               goto err_unlock;
-       }
-       se_tpg = &tpg->se_tpg;
-
-       ret = -ENOMEM;
-       tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL);
-       if (!tv_nexus)
-               goto err_unlock;
-       tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);
-       if (IS_ERR(tv_nexus->tvn_se_sess))
-               goto err_free;
-
-       /*
-        * Since we are running in 'demo mode' this call with generate a
-        * struct se_node_acl for the tcm_vhost struct se_portal_group with
-        * the SCSI Initiator port name of the passed configfs group 'name'.
-        */
-       tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
-                       se_tpg, name);
-       if (!tv_nexus->tvn_se_sess->se_node_acl) {
-               pr_debug("core_tpg_check_initiator_node_acl() failed"
-                               " for %s\n", name);
-               goto err_session;
-       }
-       /*
-        * Now register the TCM vHost virtual I_T Nexus as active with the
-        * call to __transport_register_session()
-        */
-       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
-                       tv_nexus->tvn_se_sess, tv_nexus);
-       tpg->tpg_nexus = tv_nexus;
-       mutex_unlock(&tpg->tpg_mutex);
-       return 0;
-
-err_session:
-       transport_free_session(tv_nexus->tvn_se_sess);
-err_free:
-       kfree(tv_nexus);
-err_unlock:
-       mutex_unlock(&tpg->tpg_mutex);
-       return ret;
-}
-
-static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg)
-{
-       struct se_session *se_sess;
-       struct tcm_usbg_nexus *tv_nexus;
-       int ret = -ENODEV;
-
-       mutex_lock(&tpg->tpg_mutex);
-       tv_nexus = tpg->tpg_nexus;
-       if (!tv_nexus)
-               goto out;
-
-       se_sess = tv_nexus->tvn_se_sess;
-       if (!se_sess)
-               goto out;
-
-       if (atomic_read(&tpg->tpg_port_count)) {
-               ret = -EPERM;
-               pr_err("Unable to remove Host I_T Nexus with"
-                               " active TPG port count: %d\n",
-                               atomic_read(&tpg->tpg_port_count));
-               goto out;
-       }
-
-       pr_debug("Removing I_T Nexus to Initiator Port: %s\n",
-                       tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
-       /*
-        * Release the SCSI I_T Nexus to the emulated vHost Target Port
-        */
-       transport_deregister_session(tv_nexus->tvn_se_sess);
-       tpg->tpg_nexus = NULL;
-
-       kfree(tv_nexus);
-       ret = 0;
-out:
-       mutex_unlock(&tpg->tpg_mutex);
-       return ret;
-}
-
-static ssize_t tcm_usbg_tpg_store_nexus(
-               struct se_portal_group *se_tpg,
-               const char *page,
-               size_t count)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-       unsigned char i_port[USBG_NAMELEN], *ptr;
-       int ret;
-
-       if (!strncmp(page, "NULL", 4)) {
-               ret = tcm_usbg_drop_nexus(tpg);
-               return (!ret) ? count : ret;
-       }
-       if (strlen(page) >= USBG_NAMELEN) {
-               pr_err("Emulated NAA Sas Address: %s, exceeds"
-                               " max: %d\n", page, USBG_NAMELEN);
-               return -EINVAL;
-       }
-       snprintf(i_port, USBG_NAMELEN, "%s", page);
-
-       ptr = strstr(i_port, "naa.");
-       if (!ptr) {
-               pr_err("Missing 'naa.' prefix\n");
-               return -EINVAL;
-       }
-
-       if (i_port[strlen(i_port) - 1] == '\n')
-               i_port[strlen(i_port) - 1] = '\0';
-
-       ret = tcm_usbg_make_nexus(tpg, &i_port[4]);
-       if (ret < 0)
-               return ret;
-       return count;
-}
-TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
-
-static struct configfs_attribute *usbg_base_attrs[] = {
-       &tcm_usbg_tpg_enable.attr,
-       &tcm_usbg_tpg_nexus.attr,
-       NULL,
-};
-
-static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
-       atomic_inc(&tpg->tpg_port_count);
-       smp_mb__after_atomic();
-       return 0;
-}
-
-static void usbg_port_unlink(struct se_portal_group *se_tpg,
-               struct se_lun *se_lun)
-{
-       struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
-
-       atomic_dec(&tpg->tpg_port_count);
-       smp_mb__after_atomic();
-}
-
-static int usbg_check_stop_free(struct se_cmd *se_cmd)
-{
-       struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd,
-                       se_cmd);
-
-       kref_put(&cmd->ref, usbg_cmd_release);
-       return 1;
-}
-
-static struct target_core_fabric_ops usbg_ops = {
-       .get_fabric_name                = usbg_get_fabric_name,
-       .get_fabric_proto_ident         = usbg_get_fabric_proto_ident,
-       .tpg_get_wwn                    = usbg_get_fabric_wwn,
-       .tpg_get_tag                    = usbg_get_tag,
-       .tpg_get_default_depth          = usbg_get_default_depth,
-       .tpg_get_pr_transport_id        = usbg_get_pr_transport_id,
-       .tpg_get_pr_transport_id_len    = usbg_get_pr_transport_id_len,
-       .tpg_parse_pr_out_transport_id  = usbg_parse_pr_out_transport_id,
-       .tpg_check_demo_mode            = usbg_check_true,
-       .tpg_check_demo_mode_cache      = usbg_check_false,
-       .tpg_check_demo_mode_write_protect = usbg_check_false,
-       .tpg_check_prod_mode_write_protect = usbg_check_false,
-       .tpg_alloc_fabric_acl           = usbg_alloc_fabric_acl,
-       .tpg_release_fabric_acl         = usbg_release_fabric_acl,
-       .tpg_get_inst_index             = usbg_tpg_get_inst_index,
-       .release_cmd                    = usbg_release_cmd,
-       .shutdown_session               = usbg_shutdown_session,
-       .close_session                  = usbg_close_session,
-       .sess_get_index                 = usbg_sess_get_index,
-       .sess_get_initiator_sid         = NULL,
-       .write_pending                  = usbg_send_write_request,
-       .write_pending_status           = usbg_write_pending_status,
-       .set_default_node_attributes    = usbg_set_default_node_attrs,
-       .get_task_tag                   = usbg_get_task_tag,
-       .get_cmd_state                  = usbg_get_cmd_state,
-       .queue_data_in                  = usbg_send_read_response,
-       .queue_status                   = usbg_send_status_response,
-       .queue_tm_rsp                   = usbg_queue_tm_rsp,
-       .aborted_task                   = usbg_aborted_task,
-       .check_stop_free                = usbg_check_stop_free,
-
-       .fabric_make_wwn                = usbg_make_tport,
-       .fabric_drop_wwn                = usbg_drop_tport,
-       .fabric_make_tpg                = usbg_make_tpg,
-       .fabric_drop_tpg                = usbg_drop_tpg,
-       .fabric_post_link               = usbg_port_link,
-       .fabric_pre_unlink              = usbg_port_unlink,
-       .fabric_make_np                 = NULL,
-       .fabric_drop_np                 = NULL,
-       .fabric_make_nodeacl            = usbg_make_nodeacl,
-       .fabric_drop_nodeacl            = usbg_drop_nodeacl,
-};
-
-static int usbg_register_configfs(void)
-{
-       struct target_fabric_configfs *fabric;
-       int ret;
-
-       fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget");
-       if (IS_ERR(fabric)) {
-               printk(KERN_ERR "target_fabric_configfs_init() failed\n");
-               return PTR_ERR(fabric);
-       }
-
-       fabric->tf_ops = usbg_ops;
-       fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs;
-       fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs;
-       fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
-       fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
-       fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
-       fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL;
-       fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
-       fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
-       fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;
-       ret = target_fabric_configfs_register(fabric);
-       if (ret < 0) {
-               printk(KERN_ERR "target_fabric_configfs_register() failed"
-                               " for usb-gadget\n");
-               return ret;
-       }
-       usbg_fabric_configfs = fabric;
-       return 0;
-};
-
-static void usbg_deregister_configfs(void)
-{
-       if (!(usbg_fabric_configfs))
-               return;
-
-       target_fabric_configfs_deregister(usbg_fabric_configfs);
-       usbg_fabric_configfs = NULL;
-};
-
-/* Start gadget.c code */
-
-static struct usb_interface_descriptor bot_intf_desc = {
-       .bLength =              sizeof(bot_intf_desc),
-       .bDescriptorType =      USB_DT_INTERFACE,
-       .bNumEndpoints =        2,
-       .bAlternateSetting =    USB_G_ALT_INT_BBB,
-       .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
-       .bInterfaceSubClass =   USB_SC_SCSI,
-       .bInterfaceProtocol =   USB_PR_BULK,
-};
-
-static struct usb_interface_descriptor uasp_intf_desc = {
-       .bLength =              sizeof(uasp_intf_desc),
-       .bDescriptorType =      USB_DT_INTERFACE,
-       .bNumEndpoints =        4,
-       .bAlternateSetting =    USB_G_ALT_INT_UAS,
-       .bInterfaceClass =      USB_CLASS_MASS_STORAGE,
-       .bInterfaceSubClass =   USB_SC_SCSI,
-       .bInterfaceProtocol =   USB_PR_UAS,
-};
-
-static struct usb_endpoint_descriptor uasp_bi_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bi_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = {
-       .bLength =              sizeof(uasp_bi_pipe_desc),
-       .bDescriptorType =      USB_DT_PIPE_USAGE,
-       .bPipeID =              DATA_IN_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bi_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = {
-       .bLength =              sizeof(uasp_bi_ep_comp_desc),
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-       .bMaxBurst =            0,
-       .bmAttributes =         UASP_SS_EP_COMP_LOG_STREAMS,
-       .wBytesPerInterval =    0,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = {
-       .bLength =              sizeof(bot_bi_ep_comp_desc),
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-       .bMaxBurst =            0,
-};
-
-static struct usb_endpoint_descriptor uasp_bo_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_bo_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = {
-       .bLength =              sizeof(uasp_bo_pipe_desc),
-       .bDescriptorType =      USB_DT_PIPE_USAGE,
-       .bPipeID =              DATA_OUT_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_bo_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(0x400),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = {
-       .bLength =              sizeof(uasp_bo_ep_comp_desc),
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-       .bmAttributes =         UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = {
-       .bLength =              sizeof(bot_bo_ep_comp_desc),
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_endpoint_descriptor uasp_status_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_status_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = {
-       .bLength =              sizeof(uasp_status_pipe_desc),
-       .bDescriptorType =      USB_DT_PIPE_USAGE,
-       .bPipeID =              STATUS_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_status_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_IN,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = {
-       .bLength =              sizeof(uasp_status_in_ep_comp_desc),
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-       .bmAttributes =         UASP_SS_EP_COMP_LOG_STREAMS,
-};
-
-static struct usb_endpoint_descriptor uasp_cmd_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor uasp_fs_cmd_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = {
-       .bLength =              sizeof(uasp_cmd_pipe_desc),
-       .bDescriptorType =      USB_DT_PIPE_USAGE,
-       .bPipeID =              CMD_PIPE_ID,
-};
-
-static struct usb_endpoint_descriptor uasp_ss_cmd_desc = {
-       .bLength =              USB_DT_ENDPOINT_SIZE,
-       .bDescriptorType =      USB_DT_ENDPOINT,
-       .bEndpointAddress =     USB_DIR_OUT,
-       .bmAttributes =         USB_ENDPOINT_XFER_BULK,
-       .wMaxPacketSize =       cpu_to_le16(1024),
-};
-
-static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = {
-       .bLength =              sizeof(uasp_cmd_comp_desc),
-       .bDescriptorType =      USB_DT_SS_ENDPOINT_COMP,
-};
-
-static struct usb_descriptor_header *uasp_fs_function_desc[] = {
-       (struct usb_descriptor_header *) &bot_intf_desc,
-       (struct usb_descriptor_header *) &uasp_fs_bi_desc,
-       (struct usb_descriptor_header *) &uasp_fs_bo_desc,
-
-       (struct usb_descriptor_header *) &uasp_intf_desc,
-       (struct usb_descriptor_header *) &uasp_fs_bi_desc,
-       (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_fs_bo_desc,
-       (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_fs_status_desc,
-       (struct usb_descriptor_header *) &uasp_status_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_fs_cmd_desc,
-       (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
-       NULL,
-};
-
-static struct usb_descriptor_header *uasp_hs_function_desc[] = {
-       (struct usb_descriptor_header *) &bot_intf_desc,
-       (struct usb_descriptor_header *) &uasp_bi_desc,
-       (struct usb_descriptor_header *) &uasp_bo_desc,
-
-       (struct usb_descriptor_header *) &uasp_intf_desc,
-       (struct usb_descriptor_header *) &uasp_bi_desc,
-       (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_bo_desc,
-       (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_status_desc,
-       (struct usb_descriptor_header *) &uasp_status_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_cmd_desc,
-       (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
-       NULL,
-};
-
-static struct usb_descriptor_header *uasp_ss_function_desc[] = {
-       (struct usb_descriptor_header *) &bot_intf_desc,
-       (struct usb_descriptor_header *) &uasp_ss_bi_desc,
-       (struct usb_descriptor_header *) &bot_bi_ep_comp_desc,
-       (struct usb_descriptor_header *) &uasp_ss_bo_desc,
-       (struct usb_descriptor_header *) &bot_bo_ep_comp_desc,
-
-       (struct usb_descriptor_header *) &uasp_intf_desc,
-       (struct usb_descriptor_header *) &uasp_ss_bi_desc,
-       (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc,
-       (struct usb_descriptor_header *) &uasp_bi_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_ss_bo_desc,
-       (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc,
-       (struct usb_descriptor_header *) &uasp_bo_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_ss_status_desc,
-       (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc,
-       (struct usb_descriptor_header *) &uasp_status_pipe_desc,
-       (struct usb_descriptor_header *) &uasp_ss_cmd_desc,
-       (struct usb_descriptor_header *) &uasp_cmd_comp_desc,
-       (struct usb_descriptor_header *) &uasp_cmd_pipe_desc,
-       NULL,
-};
-
-#define UAS_VENDOR_ID  0x0525  /* NetChip */
-#define UAS_PRODUCT_ID 0xa4a5  /* Linux-USB File-backed Storage Gadget */
-
-static struct usb_device_descriptor usbg_device_desc = {
-       .bLength =              sizeof(usbg_device_desc),
-       .bDescriptorType =      USB_DT_DEVICE,
-       .bcdUSB =               cpu_to_le16(0x0200),
-       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
-       .idVendor =             cpu_to_le16(UAS_VENDOR_ID),
-       .idProduct =            cpu_to_le16(UAS_PRODUCT_ID),
-       .bNumConfigurations =   1,
-};
-
-static struct usb_string       usbg_us_strings[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor",
-       [USB_GADGET_PRODUCT_IDX].s      = "Target Product",
-       [USB_GADGET_SERIAL_IDX].s       = "000000000001",
-       [USB_G_STR_CONFIG].s            = "default config",
-       [USB_G_STR_INT_UAS].s           = "USB Attached SCSI",
-       [USB_G_STR_INT_BBB].s           = "Bulk Only Transport",
-       { },
-};
-
-static struct usb_gadget_strings usbg_stringtab = {
-       .language = 0x0409,
-       .strings = usbg_us_strings,
-};
-
-static struct usb_gadget_strings *usbg_strings[] = {
-       &usbg_stringtab,
-       NULL,
-};
-
-static int guas_unbind(struct usb_composite_dev *cdev)
-{
-       return 0;
-}
-
-static struct usb_configuration usbg_config_driver = {
-       .label                  = "Linux Target",
-       .bConfigurationValue    = 1,
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-};
-
-static void give_back_ep(struct usb_ep **pep)
-{
-       struct usb_ep *ep = *pep;
-       if (!ep)
-               return;
-       ep->driver_data = NULL;
-}
-
-static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
-{
-       struct f_uas            *fu = to_f_uas(f);
-       struct usb_gadget       *gadget = c->cdev->gadget;
-       struct usb_ep           *ep;
-       int                     iface;
-       int                     ret;
-
-       iface = usb_interface_id(c, f);
-       if (iface < 0)
-               return iface;
-
-       bot_intf_desc.bInterfaceNumber = iface;
-       uasp_intf_desc.bInterfaceNumber = iface;
-       fu->iface = iface;
-       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc,
-                       &uasp_bi_ep_comp_desc);
-       if (!ep)
-               goto ep_fail;
-
-       ep->driver_data = fu;
-       fu->ep_in = ep;
-
-       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc,
-                       &uasp_bo_ep_comp_desc);
-       if (!ep)
-               goto ep_fail;
-       ep->driver_data = fu;
-       fu->ep_out = ep;
-
-       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc,
-                       &uasp_status_in_ep_comp_desc);
-       if (!ep)
-               goto ep_fail;
-       ep->driver_data = fu;
-       fu->ep_status = ep;
-
-       ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc,
-                       &uasp_cmd_comp_desc);
-       if (!ep)
-               goto ep_fail;
-       ep->driver_data = fu;
-       fu->ep_cmd = ep;
-
-       /* Assume endpoint addresses are the same for both speeds */
-       uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
-       uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
-       uasp_status_desc.bEndpointAddress =
-               uasp_ss_status_desc.bEndpointAddress;
-       uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
-       uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress;
-       uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress;
-       uasp_fs_status_desc.bEndpointAddress =
-               uasp_ss_status_desc.bEndpointAddress;
-       uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
-
-       ret = usb_assign_descriptors(f, uasp_fs_function_desc,
-                       uasp_hs_function_desc, uasp_ss_function_desc);
-       if (ret)
-               goto ep_fail;
-
-       return 0;
-ep_fail:
-       pr_err("Can't claim all required eps\n");
-
-       give_back_ep(&fu->ep_in);
-       give_back_ep(&fu->ep_out);
-       give_back_ep(&fu->ep_status);
-       give_back_ep(&fu->ep_cmd);
-       return -ENOTSUPP;
-}
-
-static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-       struct f_uas *fu = to_f_uas(f);
-
-       usb_free_all_descriptors(f);
-       kfree(fu);
-}
-
-struct guas_setup_wq {
-       struct work_struct work;
-       struct f_uas *fu;
-       unsigned int alt;
-};
-
-static void usbg_delayed_set_alt(struct work_struct *wq)
-{
-       struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq,
-                       work);
-       struct f_uas *fu = work->fu;
-       int alt = work->alt;
-
-       kfree(work);
-
-       if (fu->flags & USBG_IS_BOT)
-               bot_cleanup_old_alt(fu);
-       if (fu->flags & USBG_IS_UAS)
-               uasp_cleanup_old_alt(fu);
-
-       if (alt == USB_G_ALT_INT_BBB)
-               bot_set_alt(fu);
-       else if (alt == USB_G_ALT_INT_UAS)
-               uasp_set_alt(fu);
-       usb_composite_setup_continue(fu->function.config->cdev);
-}
-
-static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
-{
-       struct f_uas *fu = to_f_uas(f);
-
-       if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) {
-               struct guas_setup_wq *work;
-
-               work = kmalloc(sizeof(*work), GFP_ATOMIC);
-               if (!work)
-                       return -ENOMEM;
-               INIT_WORK(&work->work, usbg_delayed_set_alt);
-               work->fu = fu;
-               work->alt = alt;
-               schedule_work(&work->work);
-               return USB_GADGET_DELAYED_STATUS;
-       }
-       return -EOPNOTSUPP;
-}
-
-static void usbg_disable(struct usb_function *f)
-{
-       struct f_uas *fu = to_f_uas(f);
-
-       if (fu->flags & USBG_IS_UAS)
-               uasp_cleanup_old_alt(fu);
-       else if (fu->flags & USBG_IS_BOT)
-               bot_cleanup_old_alt(fu);
-       fu->flags = 0;
-}
-
-static int usbg_setup(struct usb_function *f,
-               const struct usb_ctrlrequest *ctrl)
-{
-       struct f_uas *fu = to_f_uas(f);
-
-       if (!(fu->flags & USBG_IS_BOT))
-               return -EOPNOTSUPP;
-
-       return usbg_bot_setup(f, ctrl);
-}
-
-static int usbg_cfg_bind(struct usb_configuration *c)
-{
-       struct f_uas *fu;
-       int ret;
-
-       fu = kzalloc(sizeof(*fu), GFP_KERNEL);
-       if (!fu)
-               return -ENOMEM;
-       fu->function.name = "Target Function";
-       fu->function.bind = usbg_bind;
-       fu->function.unbind = usbg_unbind;
-       fu->function.set_alt = usbg_set_alt;
-       fu->function.setup = usbg_setup;
-       fu->function.disable = usbg_disable;
-       fu->tpg = the_only_tpg_I_currently_have;
-
-       bot_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_BBB].id;
-       uasp_intf_desc.iInterface = usbg_us_strings[USB_G_STR_INT_UAS].id;
-
-       ret = usb_add_function(c, &fu->function);
-       if (ret)
-               goto err;
-
-       return 0;
-err:
-       kfree(fu);
-       return ret;
-}
-
-static int usb_target_bind(struct usb_composite_dev *cdev)
-{
-       int ret;
-
-       ret = usb_string_ids_tab(cdev, usbg_us_strings);
-       if (ret)
-               return ret;
-
-       usbg_device_desc.iManufacturer =
-               usbg_us_strings[USB_GADGET_MANUFACTURER_IDX].id;
-       usbg_device_desc.iProduct = usbg_us_strings[USB_GADGET_PRODUCT_IDX].id;
-       usbg_device_desc.iSerialNumber =
-               usbg_us_strings[USB_GADGET_SERIAL_IDX].id;
-       usbg_config_driver.iConfiguration =
-               usbg_us_strings[USB_G_STR_CONFIG].id;
-
-       ret = usb_add_config(cdev, &usbg_config_driver,
-                       usbg_cfg_bind);
-       if (ret)
-               return ret;
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       return 0;
-}
-
-static __refdata struct usb_composite_driver usbg_driver = {
-       .name           = "g_target",
-       .dev            = &usbg_device_desc,
-       .strings        = usbg_strings,
-       .max_speed      = USB_SPEED_SUPER,
-       .bind           = usb_target_bind,
-       .unbind         = guas_unbind,
-};
-
-static int usbg_attach(struct usbg_tpg *tpg)
-{
-       return usb_composite_probe(&usbg_driver);
-}
-
-static void usbg_detach(struct usbg_tpg *tpg)
-{
-       usb_composite_unregister(&usbg_driver);
-}
-
-static int __init usb_target_gadget_init(void)
-{
-       int ret;
-
-       ret = usbg_register_configfs();
-       return ret;
-}
-module_init(usb_target_gadget_init);
-
-static void __exit usb_target_gadget_exit(void)
-{
-       usbg_deregister_configfs();
-}
-module_exit(usb_target_gadget_exit);
-
-MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
-MODULE_DESCRIPTION("usb-gadget fabric");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/tcm_usb_gadget.h
deleted file mode 100644 (file)
index 8289219..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifndef __TARGET_USB_GADGET_H__
-#define __TARGET_USB_GADGET_H__
-
-#include <linux/kref.h>
-/* #include <linux/usb/uas.h> */
-#include <linux/usb/composite.h>
-#include <linux/usb/uas.h>
-#include <linux/usb/storage.h>
-#include <scsi/scsi.h>
-#include <target/target_core_base.h>
-#include <target/target_core_fabric.h>
-
-#define USBG_NAMELEN 32
-
-#define fuas_to_gadget(f)      (f->function.config->cdev->gadget)
-#define UASP_SS_EP_COMP_LOG_STREAMS 4
-#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS)
-
-enum {
-       USB_G_STR_CONFIG = USB_GADGET_FIRST_AVAIL_IDX,
-       USB_G_STR_INT_UAS,
-       USB_G_STR_INT_BBB,
-};
-
-#define USB_G_ALT_INT_BBB       0
-#define USB_G_ALT_INT_UAS       1
-
-struct usbg_nacl {
-       /* Binary World Wide unique Port Name for SAS Initiator port */
-       u64 iport_wwpn;
-       /* ASCII formatted WWPN for Sas Initiator port */
-       char iport_name[USBG_NAMELEN];
-       /* Returned by usbg_make_nodeacl() */
-       struct se_node_acl se_node_acl;
-};
-
-struct tcm_usbg_nexus {
-       struct se_session *tvn_se_sess;
-};
-
-struct usbg_tpg {
-       struct mutex tpg_mutex;
-       /* SAS port target portal group tag for TCM */
-       u16 tport_tpgt;
-       /* Pointer back to usbg_tport */
-       struct usbg_tport *tport;
-       struct workqueue_struct *workqueue;
-       /* Returned by usbg_make_tpg() */
-       struct se_portal_group se_tpg;
-       u32 gadget_connect;
-       struct tcm_usbg_nexus *tpg_nexus;
-       atomic_t tpg_port_count;
-};
-
-struct usbg_tport {
-       /* SCSI protocol the tport is providing */
-       u8 tport_proto_id;
-       /* Binary World Wide unique Port Name for SAS Target port */
-       u64 tport_wwpn;
-       /* ASCII formatted WWPN for SAS Target port */
-       char tport_name[USBG_NAMELEN];
-       /* Returned by usbg_make_tport() */
-       struct se_wwn tport_wwn;
-};
-
-enum uas_state {
-       UASP_SEND_DATA,
-       UASP_RECEIVE_DATA,
-       UASP_SEND_STATUS,
-       UASP_QUEUE_COMMAND,
-};
-
-#define USBG_MAX_CMD    64
-struct usbg_cmd {
-       /* common */
-       u8 cmd_buf[USBG_MAX_CMD];
-       u32 data_len;
-       struct work_struct work;
-       int unpacked_lun;
-       struct se_cmd se_cmd;
-       void *data_buf; /* used if no sg support available */
-       struct f_uas *fu;
-       struct completion write_complete;
-       struct kref ref;
-
-       /* UAS only */
-       u16 tag;
-       u16 prio_attr;
-       struct sense_iu sense_iu;
-       enum uas_state state;
-       struct uas_stream *stream;
-
-       /* BOT only */
-       __le32 bot_tag;
-       unsigned int csw_code;
-       unsigned is_read:1;
-
-};
-
-struct uas_stream {
-       struct usb_request      *req_in;
-       struct usb_request      *req_out;
-       struct usb_request      *req_status;
-};
-
-struct usbg_cdb {
-       struct usb_request      *req;
-       void                    *buf;
-};
-
-struct bot_status {
-       struct usb_request      *req;
-       struct bulk_cs_wrap     csw;
-};
-
-struct f_uas {
-       struct usbg_tpg         *tpg;
-       struct usb_function     function;
-       u16                     iface;
-
-       u32                     flags;
-#define USBG_ENABLED           (1 << 0)
-#define USBG_IS_UAS            (1 << 1)
-#define USBG_USE_STREAMS       (1 << 2)
-#define USBG_IS_BOT            (1 << 3)
-#define USBG_BOT_CMD_PEND      (1 << 4)
-
-       struct usbg_cdb         cmd;
-       struct usb_ep           *ep_in;
-       struct usb_ep           *ep_out;
-
-       /* UAS */
-       struct usb_ep           *ep_status;
-       struct usb_ep           *ep_cmd;
-       struct uas_stream       stream[UASP_SS_EP_COMP_NUM_STREAMS];
-
-       /* BOT */
-       struct bot_status       bot_status;
-       struct usb_request      *bot_req_in;
-       struct usb_request      *bot_req_out;
-};
-
-extern struct usbg_tpg *the_only_tpg_I_currently_have;
-
-#endif
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
deleted file mode 100644 (file)
index a11d8e4..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- *     webcam.c -- USB webcam gadget driver
- *
- *     Copyright (C) 2009-2010
- *         Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/usb/video.h>
-
-#include "f_uvc.h"
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
-#include "uvc_queue.c"
-#include "uvc_video.c"
-#include "uvc_v4l2.c"
-#include "f_uvc.c"
-
-USB_GADGET_COMPOSITE_OPTIONS();
-/* --------------------------------------------------------------------------
- * Device descriptor
- */
-
-#define WEBCAM_VENDOR_ID               0x1d6b  /* Linux Foundation */
-#define WEBCAM_PRODUCT_ID              0x0102  /* Webcam A/V gadget */
-#define WEBCAM_DEVICE_BCD              0x0010  /* 0.10 */
-
-static char webcam_vendor_label[] = "Linux Foundation";
-static char webcam_product_label[] = "Webcam gadget";
-static char webcam_config_label[] = "Video";
-
-/* string IDs are assigned dynamically */
-
-#define STRING_DESCRIPTION_IDX         USB_GADGET_FIRST_AVAIL_IDX
-
-static struct usb_string webcam_strings[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = webcam_vendor_label,
-       [USB_GADGET_PRODUCT_IDX].s = webcam_product_label,
-       [USB_GADGET_SERIAL_IDX].s = "",
-       [STRING_DESCRIPTION_IDX].s = webcam_config_label,
-       {  }
-};
-
-static struct usb_gadget_strings webcam_stringtab = {
-       .language = 0x0409,     /* en-us */
-       .strings = webcam_strings,
-};
-
-static struct usb_gadget_strings *webcam_device_strings[] = {
-       &webcam_stringtab,
-       NULL,
-};
-
-static struct usb_device_descriptor webcam_device_descriptor = {
-       .bLength                = USB_DT_DEVICE_SIZE,
-       .bDescriptorType        = USB_DT_DEVICE,
-       .bcdUSB                 = cpu_to_le16(0x0200),
-       .bDeviceClass           = USB_CLASS_MISC,
-       .bDeviceSubClass        = 0x02,
-       .bDeviceProtocol        = 0x01,
-       .bMaxPacketSize0        = 0, /* dynamic */
-       .idVendor               = cpu_to_le16(WEBCAM_VENDOR_ID),
-       .idProduct              = cpu_to_le16(WEBCAM_PRODUCT_ID),
-       .bcdDevice              = cpu_to_le16(WEBCAM_DEVICE_BCD),
-       .iManufacturer          = 0, /* dynamic */
-       .iProduct               = 0, /* dynamic */
-       .iSerialNumber          = 0, /* dynamic */
-       .bNumConfigurations     = 0, /* dynamic */
-};
-
-DECLARE_UVC_HEADER_DESCRIPTOR(1);
-
-static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
-       .bLength                = UVC_DT_HEADER_SIZE(1),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VC_HEADER,
-       .bcdUVC                 = cpu_to_le16(0x0100),
-       .wTotalLength           = 0, /* dynamic */
-       .dwClockFrequency       = cpu_to_le32(48000000),
-       .bInCollection          = 0, /* dynamic */
-       .baInterfaceNr[0]       = 0, /* dynamic */
-};
-
-static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = {
-       .bLength                = UVC_DT_CAMERA_TERMINAL_SIZE(3),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VC_INPUT_TERMINAL,
-       .bTerminalID            = 1,
-       .wTerminalType          = cpu_to_le16(0x0201),
-       .bAssocTerminal         = 0,
-       .iTerminal              = 0,
-       .wObjectiveFocalLengthMin       = cpu_to_le16(0),
-       .wObjectiveFocalLengthMax       = cpu_to_le16(0),
-       .wOcularFocalLength             = cpu_to_le16(0),
-       .bControlSize           = 3,
-       .bmControls[0]          = 2,
-       .bmControls[1]          = 0,
-       .bmControls[2]          = 0,
-};
-
-static const struct uvc_processing_unit_descriptor uvc_processing = {
-       .bLength                = UVC_DT_PROCESSING_UNIT_SIZE(2),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VC_PROCESSING_UNIT,
-       .bUnitID                = 2,
-       .bSourceID              = 1,
-       .wMaxMultiplier         = cpu_to_le16(16*1024),
-       .bControlSize           = 2,
-       .bmControls[0]          = 1,
-       .bmControls[1]          = 0,
-       .iProcessing            = 0,
-};
-
-static const struct uvc_output_terminal_descriptor uvc_output_terminal = {
-       .bLength                = UVC_DT_OUTPUT_TERMINAL_SIZE,
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VC_OUTPUT_TERMINAL,
-       .bTerminalID            = 3,
-       .wTerminalType          = cpu_to_le16(0x0101),
-       .bAssocTerminal         = 0,
-       .bSourceID              = 2,
-       .iTerminal              = 0,
-};
-
-DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2);
-
-static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
-       .bLength                = UVC_DT_INPUT_HEADER_SIZE(1, 2),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_INPUT_HEADER,
-       .bNumFormats            = 2,
-       .wTotalLength           = 0, /* dynamic */
-       .bEndpointAddress       = 0, /* dynamic */
-       .bmInfo                 = 0,
-       .bTerminalLink          = 3,
-       .bStillCaptureMethod    = 0,
-       .bTriggerSupport        = 0,
-       .bTriggerUsage          = 0,
-       .bControlSize           = 1,
-       .bmaControls[0][0]      = 0,
-       .bmaControls[1][0]      = 4,
-};
-
-static const struct uvc_format_uncompressed uvc_format_yuv = {
-       .bLength                = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_FORMAT_UNCOMPRESSED,
-       .bFormatIndex           = 1,
-       .bNumFrameDescriptors   = 2,
-       .guidFormat             =
-               { 'Y',  'U',  'Y',  '2', 0x00, 0x00, 0x10, 0x00,
-                0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
-       .bBitsPerPixel          = 16,
-       .bDefaultFrameIndex     = 1,
-       .bAspectRatioX          = 0,
-       .bAspectRatioY          = 0,
-       .bmInterfaceFlags       = 0,
-       .bCopyProtect           = 0,
-};
-
-DECLARE_UVC_FRAME_UNCOMPRESSED(1);
-DECLARE_UVC_FRAME_UNCOMPRESSED(3);
-
-static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
-       .bLength                = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_FRAME_UNCOMPRESSED,
-       .bFrameIndex            = 1,
-       .bmCapabilities         = 0,
-       .wWidth                 = cpu_to_le16(640),
-       .wHeight                = cpu_to_le16(360),
-       .dwMinBitRate           = cpu_to_le32(18432000),
-       .dwMaxBitRate           = cpu_to_le32(55296000),
-       .dwMaxVideoFrameBufferSize      = cpu_to_le32(460800),
-       .dwDefaultFrameInterval = cpu_to_le32(666666),
-       .bFrameIntervalType     = 3,
-       .dwFrameInterval[0]     = cpu_to_le32(666666),
-       .dwFrameInterval[1]     = cpu_to_le32(1000000),
-       .dwFrameInterval[2]     = cpu_to_le32(5000000),
-};
-
-static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
-       .bLength                = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_FRAME_UNCOMPRESSED,
-       .bFrameIndex            = 2,
-       .bmCapabilities         = 0,
-       .wWidth                 = cpu_to_le16(1280),
-       .wHeight                = cpu_to_le16(720),
-       .dwMinBitRate           = cpu_to_le32(29491200),
-       .dwMaxBitRate           = cpu_to_le32(29491200),
-       .dwMaxVideoFrameBufferSize      = cpu_to_le32(1843200),
-       .dwDefaultFrameInterval = cpu_to_le32(5000000),
-       .bFrameIntervalType     = 1,
-       .dwFrameInterval[0]     = cpu_to_le32(5000000),
-};
-
-static const struct uvc_format_mjpeg uvc_format_mjpg = {
-       .bLength                = UVC_DT_FORMAT_MJPEG_SIZE,
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_FORMAT_MJPEG,
-       .bFormatIndex           = 2,
-       .bNumFrameDescriptors   = 2,
-       .bmFlags                = 0,
-       .bDefaultFrameIndex     = 1,
-       .bAspectRatioX          = 0,
-       .bAspectRatioY          = 0,
-       .bmInterfaceFlags       = 0,
-       .bCopyProtect           = 0,
-};
-
-DECLARE_UVC_FRAME_MJPEG(1);
-DECLARE_UVC_FRAME_MJPEG(3);
-
-static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
-       .bLength                = UVC_DT_FRAME_MJPEG_SIZE(3),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_FRAME_MJPEG,
-       .bFrameIndex            = 1,
-       .bmCapabilities         = 0,
-       .wWidth                 = cpu_to_le16(640),
-       .wHeight                = cpu_to_le16(360),
-       .dwMinBitRate           = cpu_to_le32(18432000),
-       .dwMaxBitRate           = cpu_to_le32(55296000),
-       .dwMaxVideoFrameBufferSize      = cpu_to_le32(460800),
-       .dwDefaultFrameInterval = cpu_to_le32(666666),
-       .bFrameIntervalType     = 3,
-       .dwFrameInterval[0]     = cpu_to_le32(666666),
-       .dwFrameInterval[1]     = cpu_to_le32(1000000),
-       .dwFrameInterval[2]     = cpu_to_le32(5000000),
-};
-
-static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
-       .bLength                = UVC_DT_FRAME_MJPEG_SIZE(1),
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_FRAME_MJPEG,
-       .bFrameIndex            = 2,
-       .bmCapabilities         = 0,
-       .wWidth                 = cpu_to_le16(1280),
-       .wHeight                = cpu_to_le16(720),
-       .dwMinBitRate           = cpu_to_le32(29491200),
-       .dwMaxBitRate           = cpu_to_le32(29491200),
-       .dwMaxVideoFrameBufferSize      = cpu_to_le32(1843200),
-       .dwDefaultFrameInterval = cpu_to_le32(5000000),
-       .bFrameIntervalType     = 1,
-       .dwFrameInterval[0]     = cpu_to_le32(5000000),
-};
-
-static const struct uvc_color_matching_descriptor uvc_color_matching = {
-       .bLength                = UVC_DT_COLOR_MATCHING_SIZE,
-       .bDescriptorType        = USB_DT_CS_INTERFACE,
-       .bDescriptorSubType     = UVC_VS_COLORFORMAT,
-       .bColorPrimaries        = 1,
-       .bTransferCharacteristics       = 1,
-       .bMatrixCoefficients    = 4,
-};
-
-static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
-       (const struct uvc_descriptor_header *) &uvc_control_header,
-       (const struct uvc_descriptor_header *) &uvc_camera_terminal,
-       (const struct uvc_descriptor_header *) &uvc_processing,
-       (const struct uvc_descriptor_header *) &uvc_output_terminal,
-       NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
-       (const struct uvc_descriptor_header *) &uvc_control_header,
-       (const struct uvc_descriptor_header *) &uvc_camera_terminal,
-       (const struct uvc_descriptor_header *) &uvc_processing,
-       (const struct uvc_descriptor_header *) &uvc_output_terminal,
-       NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
-       (const struct uvc_descriptor_header *) &uvc_input_header,
-       (const struct uvc_descriptor_header *) &uvc_format_yuv,
-       (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
-       (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
-       (const struct uvc_descriptor_header *) &uvc_format_mjpg,
-       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
-       (const struct uvc_descriptor_header *) &uvc_color_matching,
-       NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
-       (const struct uvc_descriptor_header *) &uvc_input_header,
-       (const struct uvc_descriptor_header *) &uvc_format_yuv,
-       (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
-       (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
-       (const struct uvc_descriptor_header *) &uvc_format_mjpg,
-       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
-       (const struct uvc_descriptor_header *) &uvc_color_matching,
-       NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
-       (const struct uvc_descriptor_header *) &uvc_input_header,
-       (const struct uvc_descriptor_header *) &uvc_format_yuv,
-       (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
-       (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
-       (const struct uvc_descriptor_header *) &uvc_format_mjpg,
-       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
-       (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
-       (const struct uvc_descriptor_header *) &uvc_color_matching,
-       NULL,
-};
-
-/* --------------------------------------------------------------------------
- * USB configuration
- */
-
-static int __init
-webcam_config_bind(struct usb_configuration *c)
-{
-       return uvc_bind_config(c, uvc_fs_control_cls, uvc_ss_control_cls,
-               uvc_fs_streaming_cls, uvc_hs_streaming_cls,
-               uvc_ss_streaming_cls);
-}
-
-static struct usb_configuration webcam_config_driver = {
-       .label                  = webcam_config_label,
-       .bConfigurationValue    = 1,
-       .iConfiguration         = 0, /* dynamic */
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-       .MaxPower               = CONFIG_USB_GADGET_VBUS_DRAW,
-};
-
-static int /* __init_or_exit */
-webcam_unbind(struct usb_composite_dev *cdev)
-{
-       return 0;
-}
-
-static int __init
-webcam_bind(struct usb_composite_dev *cdev)
-{
-       int ret;
-
-       /* Allocate string descriptor numbers ... note that string contents
-        * can be overridden by the composite_dev glue.
-        */
-       ret = usb_string_ids_tab(cdev, webcam_strings);
-       if (ret < 0)
-               goto error;
-       webcam_device_descriptor.iManufacturer =
-               webcam_strings[USB_GADGET_MANUFACTURER_IDX].id;
-       webcam_device_descriptor.iProduct =
-               webcam_strings[USB_GADGET_PRODUCT_IDX].id;
-       webcam_config_driver.iConfiguration =
-               webcam_strings[STRING_DESCRIPTION_IDX].id;
-
-       /* Register our configuration. */
-       if ((ret = usb_add_config(cdev, &webcam_config_driver,
-                                       webcam_config_bind)) < 0)
-               goto error;
-
-       usb_composite_overwrite_options(cdev, &coverwrite);
-       INFO(cdev, "Webcam Video Gadget\n");
-       return 0;
-
-error:
-       webcam_unbind(cdev);
-       return ret;
-}
-
-/* --------------------------------------------------------------------------
- * Driver
- */
-
-static __refdata struct usb_composite_driver webcam_driver = {
-       .name           = "g_webcam",
-       .dev            = &webcam_device_descriptor,
-       .strings        = webcam_device_strings,
-       .max_speed      = USB_SPEED_SUPER,
-       .bind           = webcam_bind,
-       .unbind         = webcam_unbind,
-};
-
-module_usb_composite_driver(webcam_driver);
-
-MODULE_AUTHOR("Laurent Pinchart");
-MODULE_DESCRIPTION("Webcam Video Gadget");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1.0");
-
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
deleted file mode 100644 (file)
index c3d4968..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * zero.c -- Gadget Zero, for USB development
- *
- * Copyright (C) 2003-2008 David Brownell
- * Copyright (C) 2008 by Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-/*
- * Gadget Zero only needs two bulk endpoints, and is an example of how you
- * can write a hardware-agnostic gadget driver running inside a USB device.
- * Some hardware details are visible, but don't affect most of the driver.
- *
- * Use it with the Linux host/master side "usbtest" driver to get a basic
- * functional test of your device-side usb stack, or with "usb-skeleton".
- *
- * It supports two similar configurations.  One sinks whatever the usb host
- * writes, and in return sources zeroes.  The other loops whatever the host
- * writes back, so the host can read it.
- *
- * Many drivers will only have one configuration, letting them be much
- * simpler if they also don't support high speed operation (like this
- * driver does).
- *
- * Why is *this* driver using two configurations, rather than setting up
- * two interfaces with different functions?  To help verify that multiple
- * configuration infrastucture is working correctly; also, so that it can
- * work with low capability USB controllers without four bulk endpoints.
- */
-
-/*
- * driver assumes self-powered hardware, and
- * has no way for users to trigger remote wakeup.
- */
-
-/* #define VERBOSE_DEBUG */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/usb/composite.h>
-
-#include "g_zero.h"
-/*-------------------------------------------------------------------------*/
-USB_GADGET_COMPOSITE_OPTIONS();
-
-#define DRIVER_VERSION         "Cinco de Mayo 2008"
-
-static const char longname[] = "Gadget Zero";
-
-/*
- * Normally the "loopback" configuration is second (index 1) so
- * it's not the default.  Here's where to change that order, to
- * work better with hosts where config changes are problematic or
- * controllers (like original superh) that only support one config.
- */
-static bool loopdefault = 0;
-module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
-
-static struct usb_zero_options gzero_options = {
-       .isoc_interval = GZERO_ISOC_INTERVAL,
-       .isoc_maxpacket = GZERO_ISOC_MAXPACKET,
-       .bulk_buflen = GZERO_BULK_BUFLEN,
-       .qlen = GZERO_QLEN,
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* Thanks to NetChip Technologies for donating this product ID.
- *
- * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
-#ifndef        CONFIG_USB_ZERO_HNPTEST
-#define DRIVER_VENDOR_NUM      0x0525          /* NetChip */
-#define DRIVER_PRODUCT_NUM     0xa4a0          /* Linux-USB "Gadget Zero" */
-#define DEFAULT_AUTORESUME     0
-#else
-#define DRIVER_VENDOR_NUM      0x1a0a          /* OTG test device IDs */
-#define DRIVER_PRODUCT_NUM     0xbadd
-#define DEFAULT_AUTORESUME     5
-#endif
-
-/* If the optional "autoresume" mode is enabled, it provides good
- * functional coverage for the "USBCV" test harness from USB-IF.
- * It's always set if OTG mode is enabled.
- */
-static unsigned autoresume = DEFAULT_AUTORESUME;
-module_param(autoresume, uint, S_IRUGO);
-MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup");
-
-/* Maximum Autoresume time */
-static unsigned max_autoresume;
-module_param(max_autoresume, uint, S_IRUGO);
-MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup");
-
-/* Interval between two remote wakeups */
-static unsigned autoresume_interval_ms;
-module_param(autoresume_interval_ms, uint, S_IRUGO);
-MODULE_PARM_DESC(autoresume_interval_ms,
-               "milliseconds to increase successive wakeup delays");
-
-static unsigned autoresume_step_ms;
-/*-------------------------------------------------------------------------*/
-
-static struct usb_device_descriptor device_desc = {
-       .bLength =              sizeof device_desc,
-       .bDescriptorType =      USB_DT_DEVICE,
-
-       .bcdUSB =               cpu_to_le16(0x0200),
-       .bDeviceClass =         USB_CLASS_VENDOR_SPEC,
-
-       .idVendor =             cpu_to_le16(DRIVER_VENDOR_NUM),
-       .idProduct =            cpu_to_le16(DRIVER_PRODUCT_NUM),
-       .bNumConfigurations =   2,
-};
-
-#ifdef CONFIG_USB_OTG
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-#else
-#define otg_desc       NULL
-#endif
-
-/* string IDs are assigned dynamically */
-/* default serial number takes at least two packets */
-static char serial[] = "0123456789.0123456789.0123456789";
-
-#define USB_GZERO_SS_DESC      (USB_GADGET_FIRST_AVAIL_IDX + 0)
-#define USB_GZERO_LB_DESC      (USB_GADGET_FIRST_AVAIL_IDX + 1)
-
-static struct usb_string strings_dev[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "",
-       [USB_GADGET_PRODUCT_IDX].s = longname,
-       [USB_GADGET_SERIAL_IDX].s = serial,
-       [USB_GZERO_SS_DESC].s   = "source and sink data",
-       [USB_GZERO_LB_DESC].s   = "loop input to output",
-       {  }                    /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
-       .language       = 0x0409,       /* en-us */
-       .strings        = strings_dev,
-};
-
-static struct usb_gadget_strings *dev_strings[] = {
-       &stringtab_dev,
-       NULL,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static struct timer_list       autoresume_timer;
-
-static void zero_autoresume(unsigned long _c)
-{
-       struct usb_composite_dev        *cdev = (void *)_c;
-       struct usb_gadget               *g = cdev->gadget;
-
-       /* unconfigured devices can't issue wakeups */
-       if (!cdev->config)
-               return;
-
-       /* Normally the host would be woken up for something
-        * more significant than just a timer firing; likely
-        * because of some direct user request.
-        */
-       if (g->speed != USB_SPEED_UNKNOWN) {
-               int status = usb_gadget_wakeup(g);
-               INFO(cdev, "%s --> %d\n", __func__, status);
-       }
-}
-
-static void zero_suspend(struct usb_composite_dev *cdev)
-{
-       if (cdev->gadget->speed == USB_SPEED_UNKNOWN)
-               return;
-
-       if (autoresume) {
-               if (max_autoresume &&
-                       (autoresume_step_ms > max_autoresume * 1000))
-                               autoresume_step_ms = autoresume * 1000;
-
-               mod_timer(&autoresume_timer, jiffies +
-                       msecs_to_jiffies(autoresume_step_ms));
-               DBG(cdev, "suspend, wakeup in %d milliseconds\n",
-                       autoresume_step_ms);
-
-               autoresume_step_ms += autoresume_interval_ms;
-       } else
-               DBG(cdev, "%s\n", __func__);
-}
-
-static void zero_resume(struct usb_composite_dev *cdev)
-{
-       DBG(cdev, "%s\n", __func__);
-       del_timer(&autoresume_timer);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_configuration loopback_driver = {
-       .label          = "loopback",
-       .bConfigurationValue = 2,
-       .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
-       /* .iConfiguration = DYNAMIC */
-};
-
-static struct usb_function *func_ss;
-static struct usb_function_instance *func_inst_ss;
-
-static int ss_config_setup(struct usb_configuration *c,
-               const struct usb_ctrlrequest *ctrl)
-{
-       switch (ctrl->bRequest) {
-       case 0x5b:
-       case 0x5c:
-               return func_ss->setup(func_ss, ctrl);
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-static struct usb_configuration sourcesink_driver = {
-       .label                  = "source/sink",
-       .setup                  = ss_config_setup,
-       .bConfigurationValue    = 3,
-       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
-       /* .iConfiguration      = DYNAMIC */
-};
-
-module_param_named(buflen, gzero_options.bulk_buflen, uint, 0);
-module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");
-
-module_param_named(isoc_interval, gzero_options.isoc_interval, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_interval, "1 - 16");
-
-module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
-
-module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
-
-module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
-               S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
-
-static struct usb_function *func_lb;
-static struct usb_function_instance *func_inst_lb;
-
-module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(qlen, "depth of loopback queue");
-
-static int __init zero_bind(struct usb_composite_dev *cdev)
-{
-       struct f_ss_opts        *ss_opts;
-       struct f_lb_opts        *lb_opts;
-       int                     status;
-
-       /* Allocate string descriptor numbers ... note that string
-        * contents can be overridden by the composite_dev glue.
-        */
-       status = usb_string_ids_tab(cdev, strings_dev);
-       if (status < 0)
-               return status;
-
-       device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
-       device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
-       device_desc.iSerialNumber = strings_dev[USB_GADGET_SERIAL_IDX].id;
-
-       setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev);
-
-       func_inst_ss = usb_get_function_instance("SourceSink");
-       if (IS_ERR(func_inst_ss))
-               return PTR_ERR(func_inst_ss);
-
-       ss_opts =  container_of(func_inst_ss, struct f_ss_opts, func_inst);
-       ss_opts->pattern = gzero_options.pattern;
-       ss_opts->isoc_interval = gzero_options.isoc_interval;
-       ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
-       ss_opts->isoc_mult = gzero_options.isoc_mult;
-       ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
-       ss_opts->bulk_buflen = gzero_options.bulk_buflen;
-
-       func_ss = usb_get_function(func_inst_ss);
-       if (IS_ERR(func_ss)) {
-               status = PTR_ERR(func_ss);
-               goto err_put_func_inst_ss;
-       }
-
-       func_inst_lb = usb_get_function_instance("Loopback");
-       if (IS_ERR(func_inst_lb)) {
-               status = PTR_ERR(func_inst_lb);
-               goto err_put_func_ss;
-       }
-
-       lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst);
-       lb_opts->bulk_buflen = gzero_options.bulk_buflen;
-       lb_opts->qlen = gzero_options.qlen;
-
-       func_lb = usb_get_function(func_inst_lb);
-       if (IS_ERR(func_lb)) {
-               status = PTR_ERR(func_lb);
-               goto err_put_func_inst_lb;
-       }
-
-       sourcesink_driver.iConfiguration = strings_dev[USB_GZERO_SS_DESC].id;
-       loopback_driver.iConfiguration = strings_dev[USB_GZERO_LB_DESC].id;
-
-       /* support autoresume for remote wakeup testing */
-       sourcesink_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
-       loopback_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP;
-       sourcesink_driver.descriptors = NULL;
-       loopback_driver.descriptors = NULL;
-       if (autoresume) {
-               sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-               loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-               autoresume_step_ms = autoresume * 1000;
-       }
-
-       /* support OTG systems */
-       if (gadget_is_otg(cdev->gadget)) {
-               sourcesink_driver.descriptors = otg_desc;
-               sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-               loopback_driver.descriptors = otg_desc;
-               loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-       }
-
-       /* Register primary, then secondary configuration.  Note that
-        * SH3 only allows one config...
-        */
-       if (loopdefault) {
-               usb_add_config_only(cdev, &loopback_driver);
-               usb_add_config_only(cdev, &sourcesink_driver);
-       } else {
-               usb_add_config_only(cdev, &sourcesink_driver);
-               usb_add_config_only(cdev, &loopback_driver);
-       }
-       status = usb_add_function(&sourcesink_driver, func_ss);
-       if (status)
-               goto err_conf_flb;
-
-       usb_ep_autoconfig_reset(cdev->gadget);
-       status = usb_add_function(&loopback_driver, func_lb);
-       if (status)
-               goto err_conf_flb;
-
-       usb_ep_autoconfig_reset(cdev->gadget);
-       usb_composite_overwrite_options(cdev, &coverwrite);
-
-       INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
-
-       return 0;
-
-err_conf_flb:
-       usb_put_function(func_lb);
-       func_lb = NULL;
-err_put_func_inst_lb:
-       usb_put_function_instance(func_inst_lb);
-       func_inst_lb = NULL;
-err_put_func_ss:
-       usb_put_function(func_ss);
-       func_ss = NULL;
-err_put_func_inst_ss:
-       usb_put_function_instance(func_inst_ss);
-       func_inst_ss = NULL;
-       return status;
-}
-
-static int zero_unbind(struct usb_composite_dev *cdev)
-{
-       del_timer_sync(&autoresume_timer);
-       if (!IS_ERR_OR_NULL(func_ss))
-               usb_put_function(func_ss);
-       usb_put_function_instance(func_inst_ss);
-       if (!IS_ERR_OR_NULL(func_lb))
-               usb_put_function(func_lb);
-       usb_put_function_instance(func_inst_lb);
-       return 0;
-}
-
-static __refdata struct usb_composite_driver zero_driver = {
-       .name           = "zero",
-       .dev            = &device_desc,
-       .strings        = dev_strings,
-       .max_speed      = USB_SPEED_SUPER,
-       .bind           = zero_bind,
-       .unbind         = zero_unbind,
-       .suspend        = zero_suspend,
-       .resume         = zero_resume,
-};
-
-module_usb_composite_driver(zero_driver);
-
-MODULE_AUTHOR("David Brownell");
-MODULE_LICENSE("GPL");