summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2003-05-08 00:20:25 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2003-05-08 00:20:25 -0700
commite3b7d74040cda0050447d7fe848d8fe71a254f40 (patch)
treea7359da75009d0068c5fbc50fbeea2ed20803ff4
parentf4b8904266070f05c41b53366a05ab6ab5db0b5f (diff)
parentd93c8ad696263a48bc14c82eb15866930393fb9b (diff)
Merge kroah.com:/home/linux/linux/BK/bleed-2.5
into kroah.com:/home/linux/linux/BK/gadget-2.5
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/Makefile4
-rw-r--r--drivers/usb/gadget/Kconfig153
-rw-r--r--drivers/usb/gadget/Makefile14
-rw-r--r--drivers/usb/gadget/ether.c1640
-rw-r--r--drivers/usb/gadget/net2280.c2660
-rw-r--r--drivers/usb/gadget/net2280.h709
-rw-r--r--drivers/usb/gadget/usbstring.c71
-rw-r--r--drivers/usb/gadget/zero.c1223
-rw-r--r--include/linux/usb_gadget.h696
10 files changed, 7172 insertions, 0 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 6024f359cb63..f4badc2e4045 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -91,5 +91,7 @@ source "drivers/usb/serial/Kconfig"
source "drivers/usb/misc/Kconfig"
+source "drivers/usb/gadget/Kconfig"
+
endmenu
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c661791206f8..794bcdf44acf 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -58,3 +58,7 @@ obj-$(CONFIG_USB_SPEEDTOUCH) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TIGL) += misc/
obj-$(CONFIG_USB_USS720) += misc/
+
+obj-$(CONFIG_USB_NET2280) += gadget/
+obj-$(CONFIG_USB_ZERO) += gadget/
+obj-$(CONFIG_USB_ETH) += gadget/
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
new file mode 100644
index 000000000000..030768c4cf6c
--- /dev/null
+++ b/drivers/usb/gadget/Kconfig
@@ -0,0 +1,153 @@
+#
+# USB Gadget support on a system involves
+# (a) a peripheral controller, and
+# (b) the gadget driver using it.
+#
+# for 2.5 kbuild, drivers/usb/gadget/Kconfig
+# source this at the end of drivers/usb/Kconfig
+#
+menuconfig USB_GADGET
+ tristate "Support for USB Gadgets"
+ depends on EXPERIMENTAL
+ help
+ USB is a master/slave protocol, organized with with one master
+ host (such as a PC) controlling up to 127 peripheral devices.
+ The USB hardware is asymmetric, which makes it easier to set up:
+ you can't connect two "to-the-host" connectors to each other.
+
+ Linux can run in the host, or in the peripheral. In both cases
+ you need a low level bus controller driver, and some software
+ talking to it. Peripheral controllers are often discrete silicon,
+ or are integrated with the CPU in a microcontroller. The more
+ familiar host side controllers have names like like "EHCI", "OHCI",
+ or "UHCI", and are usually integrated into southbridges on PC
+ motherboards.
+
+ Enable this configuration option if you want to run Linux inside
+ a USB peripheral device. Configure one hardware driver for your
+ peripheral/device side bus controller, and a "gadget driver" for
+ your peripheral protocol. (If you use modular gadget drivers,
+ you may configure more than one.)
+
+ If in doubt, say "N" and don't enable these drivers; most people
+ don't have this kind of hardware (except maybe inside Linux PDAs).
+
+#
+# USB Peripheral Controller Support
+#
+# FIXME convert to tristate choice when "choice" behaves as specified
+#
+comment "USB Peripheral Controller Support"
+ depends on USB_GADGET
+
+config USB_NET2280
+ tristate "NetChip 2280 USB Peripheral Controller"
+ depends on PCI && USB_GADGET
+ help
+ NetChip 2280 is a PCI based USB peripheral controller which
+ supports both full and high speed USB 2.0 data transfers.
+
+ It has six configurable endpoints, as well as endpoint zero
+ (for control transfers) and several endpoints with dedicated
+ functions.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "net2280" and force all
+ gadget drivers to also be dynamically linked.
+
+#
+# USB Gadget Drivers
+#
+# FIXME only one of these may be statically linked; choice/endchoice.
+#
+comment "USB Gadget Drivers"
+ depends on USB_GADGET
+
+# FIXME want better dependency/config approach for drivers. with only
+# two knobs to tweak (driver y/m/n, and a hardware symbol) there's no
+# good excuse for Kconfig to cause such trouble here. there are clear
+# bugs (coredumps, multiple choices enabled, and more) in its (boolean)
+# "choice" logic too ...
+
+config USB_ZERO
+ tristate "Gadget Zero (DEVELOPMENT)"
+ depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA250 || USB_SA1100)
+ 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_NET2280
+ bool
+ # for now, treat the "dummy" hcd as if it were a net2280
+ depends on USB_ZERO && (USB_NET2280 || USB_DUMMY_HCD)
+ default y
+
+config USB_ZERO_PXA250
+ bool
+ depends on USB_ZERO && USB_PXA250
+ default y
+
+config USB_ZERO_SA1100
+ bool
+ depends on USB_ZERO && USB_SA1100
+ default y
+
+
+config USB_ETH
+ tristate "Ethernet Gadget"
+ depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA250 || USB_SA1100)
+ help
+ This driver implements 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.
+
+ 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.) Deep queues are especially important with
+ high speed devices. It 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_NET2280
+ bool
+ # for now, treat the "dummy" hcd as if it were a net2280
+ depends on USB_ETH && (USB_NET2280 || USB_DUMMY_HCD)
+ default y
+
+config USB_ETH_PXA250
+ bool
+ depends on USB_ETH && USB_PXA250
+ default y
+
+config USB_ETH_SA1100
+ bool
+ depends on USB_ETH && USB_SA1100
+ default y
+
+# endmenuconfig
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
new file mode 100644
index 000000000000..0575e6d8b1f0
--- /dev/null
+++ b/drivers/usb/gadget/Makefile
@@ -0,0 +1,14 @@
+#
+# USB peripheral controller drivers
+#
+obj-$(CONFIG_USB_NET2280) += net2280.o
+
+#
+# USB gadget drivers
+#
+g_zero-objs := zero.o usbstring.o
+g_ether-objs := ether.o usbstring.o
+
+obj-$(CONFIG_USB_ZERO) += g_zero.o
+obj-$(CONFIG_USB_ETH) += g_ether.o
+
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
new file mode 100644
index 000000000000..36ef1b93ffab
--- /dev/null
+++ b/drivers/usb/gadget/ether.c
@@ -0,0 +1,1640 @@
+/*
+ * ether.c -- CDC 1.1 Ethernet gadget driver
+ *
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#define DEBUG 1
+// #define VERBOSE
+
+#include <linux/config.h>
+#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/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <linux/random.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * "Communications Device Class" (CDC) Ethernet class driver
+ *
+ * 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. And Microsoft pushes their own approach
+ * (RNDIS) instead of the standard.
+ */
+
+#define DRIVER_DESC "CDC Ethernet Gadget"
+#define DRIVER_VERSION "29 April 2003"
+
+static const char shortname [] = "ether";
+static const char driver_desc [] = DRIVER_DESC;
+static const char control_name [] = "Communications Control";
+static const char data_name [] = "CDC Ethernet Data";
+
+#define MIN_PACKET sizeof(struct ethhdr)
+#define MAX_PACKET ETH_DATA_LEN /* biggest packet we'll rx/tx */
+
+/* FIXME allow high speed jumbograms */
+
+/*-------------------------------------------------------------------------*/
+
+struct eth_dev {
+ spinlock_t lock;
+ struct usb_gadget *gadget;
+ struct usb_request *req; /* for control responses */
+
+ u8 config;
+ struct usb_ep *in_ep, *out_ep, *status_ep;
+ const struct usb_endpoint_descriptor
+ *in, *out, *status;
+
+ struct semaphore mutex;
+ struct net_device net;
+ struct net_device_stats stats;
+ atomic_t tx_qlen;
+
+ struct work_struct work;
+ unsigned long todo;
+#define WORK_RX_MEMORY 0
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* This driver keeps a variable number of requests queued, more at
+ * high speeds. (Numbers are just educated guesses, untuned.)
+ * Shrink the queue if memory is tight, or make it bigger to
+ * handle bigger traffic bursts between IRQs.
+ */
+
+static unsigned qmult = 4;
+
+#define HS_FACTOR 15
+
+#define qlen(gadget) \
+ (qmult*((gadget->speed == USB_SPEED_HIGH) ? HS_FACTOR : 1))
+
+/* defer IRQs on highspeed TX */
+#define TX_DELAY 8
+
+
+module_param (qmult, uint, S_IRUGO|S_IWUSR);
+
+
+/*-------------------------------------------------------------------------*/
+
+/* 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 DRIVER_VENDOR_NUM 0x0525 /* NetChip */
+#define DRIVER_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * hardware-specific configuration, controlled by which device
+ * controller driver was configured.
+ *
+ * CHIP ... hardware identifier
+ * DRIVER_VERSION_NUM ... alerts the host side driver to differences
+ * EP0_MAXPACKET ... controls packetization of control requests
+ * EP_*_NAME ... which endpoints do we use for which purpose?
+ * EP_*_NUM ... numbers for them (often limited by hardware)
+ * HIGHSPEED ... define if ep0 and descriptors need high speed support
+ * MAX_USB_POWER ... define if we use other than 100 mA bus current
+ * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER
+ * WAKEUP ... if hardware supports remote wakeup AND we will issue the
+ * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
+ *
+ * hw_optimize(gadget) ... for any hardware tweaks we want to kick in
+ * before we enable our endpoints
+ *
+ * add other defines for other portability issues, like hardware that
+ * for some reason doesn't handle full speed bulk maxpacket of 64.
+ */
+
+/*
+ * NetChip 2280, PCI based.
+ *
+ * use DMA with fat fifos for all data traffic, PIO for the status channel
+ * where its 64 byte maxpacket ceiling is no issue.
+ *
+ * performance note: only PIO needs per-usb-packet IRQs (ep0, ep-e, ep-f)
+ * otherwise IRQs are per-Ethernet-packet unless TX_DELAY and chaining help.
+ */
+#ifdef CONFIG_USB_ETH_NET2280
+#define CHIP "net2280"
+#define DRIVER_VERSION_NUM cpu_to_le16(0x0101)
+#define EP0_MAXPACKET 64
+static const char EP_OUT_NAME [] = "ep-a";
+#define EP_OUT_NUM 2
+static const char EP_IN_NAME [] = "ep-b";
+#define EP_IN_NUM 2
+static const char EP_STATUS_NAME [] = "ep-f";
+#define EP_STATUS_NUM 3
+#define HIGHSPEED
+/* specific hardware configs could be bus-powered */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
+static inline void hw_optimize (struct usb_gadget *gadget)
+{
+ /* we can have bigger ep-a/ep-b fifos (2KB each, 4 USB packets
+ * for highspeed bulk) because we're not using ep-c/ep-d.
+ */
+ net2280_set_fifo_mode (gadget, 1);
+}
+#endif
+
+/*
+ * PXA-250 UDC: widely used in second gen Linux-capable PDAs.
+ *
+ * no limitations except from set_interface: docs say "no" to a third
+ * interface. and the interrupt-only endpoints don't toggle, so we'll
+ * just use a bulk-capable one instead.
+ */
+#ifdef CONFIG_USB_ETH_PXA250
+#define CHIP "pxa250"
+#define DRIVER_VERSION_NUM cpu_to_le16(0x0103)
+#define EP0_MAXPACKET 16
+static const char EP_OUT_NAME [] = "ep12out-bulk";
+#define EP_OUT_NUM 12
+static const char EP_IN_NAME [] = "ep11in-bulk";
+#define EP_IN_NUM 11
+static const char EP_STATUS_NAME [] = "ep6in-bulk";
+#define EP_STATUS_NUM 6
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*
+ * SA-1100 UDC: widely used in first gen Linux-capable PDAs.
+ *
+ * can't have a notification endpoint, since there are only the two
+ * bulk-capable ones. the CDC spec allows that.
+ */
+#ifdef CONFIG_USB_ETH_SA1100
+#define CHIP "sa1100"
+#define DRIVER_VERSION_NUM cpu_to_le16(0x0105)
+#define EP0_MAXPACKET 8
+static const char EP_OUT_NAME [] = "ep1out-bulk";
+#define EP_OUT_NUM 1
+static const char EP_IN_NAME [] = "ep2in-bulk";
+#define EP_IN_NUM 2
+// EP_STATUS_NUM is undefined
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* doesn't support remote wakeup? */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef EP0_MAXPACKET
+# error Configure some USB peripheral controller driver!
+#endif
+
+/* power usage is config specific.
+ * hardware that supports remote wakeup defaults to disabling it.
+ */
+
+#ifndef SELFPOWER
+/* default: say we rely on bus power */
+#define SELFPOWER 0
+/* else:
+ * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER
+ * - MAX_USB_POWER may be nonzero.
+ */
+#endif
+
+#ifndef MAX_USB_POWER
+/* any hub supports this steady state bus power consumption */
+#define MAX_USB_POWER 100 /* mA */
+#endif
+
+#ifndef WAKEUP
+/* default: this driver won't do remote wakeup */
+#define WAKEUP 0
+/* else value must be USB_CONFIG_ATT_WAKEUP */
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(d,level,fmt,args...) \
+ dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(dev,fmt,args...) \
+ xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG DEBUG
+#else
+#define VDEBUG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#define ERROR(dev,fmt,args...) \
+ xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+ xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+ xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
+ * ep0 implementation: descriptors, config management, setup().
+ * also optional class-specific notification interrupt transfer.
+ */
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand. Notice how most of the cdc descriptors
+ * add no value to simple (typical) configurations.
+ */
+
+#define STRING_MANUFACTURER 1
+#define STRING_PRODUCT 2
+#define STRING_ETHADDR 3
+#define STRING_DATA 4
+#define STRING_CONTROL 5
+
+#define USB_BUFSIZ 256 /* holds our biggest descriptor */
+
+/*
+ * This device advertises one configuration.
+ */
+#define CONFIG_CDC_ETHER 3
+
+static const 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 = EP0_MAXPACKET,
+
+ .idVendor = cpu_to_le16 (DRIVER_VENDOR_NUM),
+ .idProduct = cpu_to_le16 (DRIVER_PRODUCT_NUM),
+ .bcdDevice = cpu_to_le16 (DRIVER_VERSION_NUM),
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .bNumConfigurations = 1,
+};
+
+static const struct usb_config_descriptor
+eth_config = {
+ .bLength = sizeof eth_config,
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* compute wTotalLength on the fly */
+ .bNumInterfaces = 2,
+ .bConfigurationValue = CONFIG_CDC_ETHER,
+ .iConfiguration = STRING_PRODUCT,
+ .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
+ .bMaxPower = (MAX_USB_POWER + 1) / 2,
+};
+
+/* master comm interface optionally has a status notification endpoint */
+
+static const struct usb_interface_descriptor
+control_intf = {
+ .bLength = sizeof control_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 0,
+#ifdef EP_STATUS_NUM
+ .bNumEndpoints = 1,
+#else
+ .bNumEndpoints = 0,
+#endif
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = 6, /* ethernet control model */
+ .bInterfaceProtocol = 0,
+ .iInterface = STRING_CONTROL,
+};
+
+/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
+struct header_desc {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bDescriptorSubType;
+
+ u16 bcdCDC;
+} __attribute__ ((packed));
+
+static const struct header_desc header_desc = {
+ .bLength = sizeof header_desc,
+ .bDescriptorType = 0x24,
+ .bDescriptorSubType = 0,
+
+ .bcdCDC = cpu_to_le16 (0x0110),
+};
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
+struct union_desc {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bDescriptorSubType;
+
+ u8 bMasterInterface0;
+ u8 bSlaveInterface0;
+ /* ... and there could be other slave interfaces */
+} __attribute__ ((packed));
+
+static const struct union_desc union_desc = {
+ .bLength = sizeof union_desc,
+ .bDescriptorType = 0x24,
+ .bDescriptorSubType = 6,
+
+ .bMasterInterface0 = 0, /* index of control interface */
+ .bSlaveInterface0 = 1, /* index of DATA interface */
+};
+
+/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
+struct ether_desc {
+ u8 bLength;
+ u8 bDescriptorType;
+ u8 bDescriptorSubType;
+
+ u8 iMACAddress;
+ u32 bmEthernetStatistics;
+ u16 wMaxSegmentSize;
+ u16 wNumberMCFilters;
+ u8 bNumberPowerFilters;
+} __attribute__ ((packed));
+
+static const struct ether_desc ether_desc = {
+ .bLength = sizeof ether_desc,
+ .bDescriptorType = 0x24,
+ .bDescriptorSubType = 0x0f,
+
+ /* this descriptor actually adds value, surprise! */
+ .iMACAddress = STRING_ETHADDR,
+ .bmEthernetStatistics = cpu_to_le32 (0), /* no statistics */
+ .wMaxSegmentSize = cpu_to_le16 (MAX_PACKET + ETH_HLEN),
+ .wNumberMCFilters = cpu_to_le16 (0),
+ .bNumberPowerFilters = 0,
+};
+
+#ifdef EP_STATUS_NUM
+
+/* include the status endpoint if we can, even though it's optional.
+ *
+ * some drivers (like current Linux cdc-ether!) "need" it to exist even
+ * if they ignore the connect/disconnect notifications that real aether
+ * can provide. more advanced cdc configurations might want to support
+ * encapsulated commands.
+ */
+
+#define LOG2_STATUS_INTERVAL_MSEC 6
+#define STATUS_BYTECOUNT 16 /* 8 byte header + data */
+static const struct usb_endpoint_descriptor
+fs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16 (STATUS_BYTECOUNT),
+ .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+#endif
+
+/* the default data interface has no endpoints ... */
+
+static const struct usb_interface_descriptor
+data_nop_intf = {
+ .bLength = sizeof data_nop_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = STRING_DATA,
+};
+
+/* ... but the "real" data interface has two full speed bulk endpoints */
+
+static const struct usb_interface_descriptor
+data_intf = {
+ .bLength = sizeof data_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = STRING_DATA,
+};
+
+static const struct usb_endpoint_descriptor
+fs_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_IN_NUM | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (64),
+};
+
+static const struct usb_endpoint_descriptor
+fs_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_OUT_NUM,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (64),
+};
+
+#ifdef HIGHSPEED
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ */
+
+#ifdef EP_STATUS_NUM
+static const struct usb_endpoint_descriptor
+hs_status_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_STATUS_NUM | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16 (STATUS_BYTECOUNT),
+ .bInterval = LOG2_STATUS_INTERVAL_MSEC + 3,
+};
+#endif
+
+static const struct usb_endpoint_descriptor
+hs_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_IN_NUM | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (512),
+ .bInterval = 1,
+};
+
+static const struct usb_endpoint_descriptor
+hs_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_OUT_NUM,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (512),
+ .bInterval = 1,
+};
+
+static const struct usb_qualifier_descriptor
+dev_qualifier = {
+ .bLength = sizeof dev_qualifier,
+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+
+ .bcdUSB = cpu_to_le16 (0x0200),
+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
+
+ /* assumes ep0 uses the same value for both speeds ... */
+ .bMaxPacketSize0 = EP0_MAXPACKET,
+
+ .bNumConfigurations = 2,
+};
+
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+
+#else
+
+/* if there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g,hs,fs) fs
+
+#endif /* !HIGHSPEED */
+
+/* address that the host will use ... usually assigned at random */
+static char ethaddr [2 * ETH_ALEN + 1];
+
+/* static strings, in iso 8859/1 */
+static struct usb_string strings [] = {
+ { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE "/" CHIP, },
+ { STRING_PRODUCT, driver_desc, },
+ { STRING_ETHADDR, ethaddr, },
+ { STRING_CONTROL, control_name, },
+ { STRING_DATA, data_name, },
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = strings,
+};
+
+/*
+ * one config, two interfaces: control, data.
+ * complications: class descriptors, and an altsetting.
+ */
+static int
+config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index)
+{
+ const unsigned config_len = USB_DT_CONFIG_SIZE
+ + 3 * USB_DT_INTERFACE_SIZE
+ + sizeof header_desc
+ + sizeof union_desc
+ + sizeof ether_desc
+#ifdef EP_STATUS_NUM
+ + USB_DT_ENDPOINT_SIZE
+#endif
+ + 2 * USB_DT_ENDPOINT_SIZE;
+#ifdef HIGHSPEED
+ int hs;
+#endif
+ /* a single configuration must always be index 0 */
+ if (index > 0)
+ return -EINVAL;
+ if (config_len > USB_BUFSIZ)
+ return -EDOM;
+
+ /* config (or other speed config) */
+ memcpy (buf, &eth_config, USB_DT_CONFIG_SIZE);
+ buf [1] = type;
+ ((struct usb_config_descriptor *) buf)->wTotalLength
+ = cpu_to_le16 (config_len);
+ buf += USB_DT_CONFIG_SIZE;
+#ifdef HIGHSPEED
+ hs = (speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+#endif
+
+ /* control interface, class descriptors, optional status endpoint */
+ memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE);
+ buf += USB_DT_INTERFACE_SIZE;
+
+ memcpy (buf, &header_desc, sizeof header_desc);
+ buf += sizeof header_desc;
+ memcpy (buf, &union_desc, sizeof union_desc);
+ buf += sizeof union_desc;
+ memcpy (buf, &ether_desc, sizeof ether_desc);
+ buf += sizeof ether_desc;
+
+#ifdef EP_STATUS_NUM
+#ifdef HIGHSPEED
+ if (hs)
+ memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE);
+ else
+#endif /* HIGHSPEED */
+ memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+#endif /* EP_STATUS_NUM */
+
+ /* default data altsetting has no endpoints */
+ memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE);
+ buf += USB_DT_INTERFACE_SIZE;
+
+ /* the "real" data interface has two endpoints */
+ memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE);
+ buf += USB_DT_INTERFACE_SIZE;
+#ifdef HIGHSPEED
+ if (hs) {
+ memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ } else
+#endif
+ {
+ memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ }
+
+ return config_len;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+set_ether_config (struct eth_dev *dev, int gfp_flags)
+{
+ int result = 0;
+ struct usb_ep *ep;
+ struct usb_gadget *gadget = dev->gadget;
+
+ gadget_for_each_ep (ep, gadget) {
+ const struct usb_endpoint_descriptor *d;
+
+ /* NOTE: the host isn't allowed to use these two data
+ * endpoints in the default altsetting for the interface.
+ * so we don't activate them yet.
+ */
+
+ /* one endpoint writes data back IN to the host */
+ if (strcmp (ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
+ ep->driver_data = dev;
+ dev->in_ep = ep;
+ dev->in = d;
+ continue;
+
+ /* one endpoint just reads OUT packets */
+ } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
+ ep->driver_data = dev;
+ dev->out_ep = ep;
+ dev->out = d;
+ continue;
+
+#ifdef EP_STATUS_NUM
+ /* optional status/notification endpoint */
+ } else if (strcmp (ep->name, EP_STATUS_NAME) == 0) {
+ d = ep_desc (gadget, &hs_status_desc, &fs_status_desc);
+ result = usb_ep_enable (ep, d);
+ if (result == 0) {
+ ep->driver_data = dev;
+ dev->status_ep = ep;
+ dev->status = d;
+ continue;
+ }
+#endif
+
+ /* ignore any other endpoints */
+ } else
+ continue;
+
+ /* stop on error */
+ ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+ break;
+ }
+
+ if (result == 0)
+ DEBUG (dev, "qlen %d\n", qlen (gadget));
+
+ /* caller is responsible for cleanup on error */
+ return result;
+}
+
+static void eth_reset_config (struct eth_dev *dev)
+{
+ if (dev->config == 0)
+ return;
+
+ DEBUG (dev, "%s\n", __FUNCTION__);
+
+ netif_stop_queue (&dev->net);
+ netif_carrier_off (&dev->net);
+
+ /* just disable endpoints, forcing completion of pending i/o.
+ * all our completion handlers free their requests in this case.
+ */
+ if (dev->in_ep) {
+ usb_ep_disable (dev->in_ep);
+ dev->in_ep = 0;
+ }
+ if (dev->out_ep) {
+ usb_ep_disable (dev->out_ep);
+ dev->out_ep = 0;
+ }
+#ifdef EP_STATUS_NUM
+ if (dev->status_ep) {
+ usb_ep_disable (dev->status_ep);
+ dev->status_ep = 0;
+ }
+#endif
+ dev->config = 0;
+}
+
+/* change our operational config. must agree with the code
+ * that returns config descriptors, and altsetting code.
+ */
+static int
+eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
+{
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+ if (number == dev->config)
+ return 0;
+
+#ifdef CONFIG_USB_ETH_SA1100
+ if (dev->config && atomic_read (&dev->tx_qlen) != 0) {
+ /* tx fifo is full, but we can't clear it...*/
+ INFO (dev, "can't change configurations\n");
+ return -ESPIPE;
+ }
+#endif
+ eth_reset_config (dev);
+ hw_optimize (gadget);
+
+ switch (number) {
+ case CONFIG_CDC_ETHER:
+ result = set_ether_config (dev, gfp_flags);
+ break;
+ default:
+ result = -EINVAL;
+ /* FALL THROUGH */
+ case 0:
+ return result;
+ }
+
+ if (!result && (!dev->in_ep || !dev->out_ep))
+ result = -ENODEV;
+ if (result)
+ eth_reset_config (dev);
+ else {
+ char *speed;
+
+ switch (gadget->speed) {
+ case USB_SPEED_FULL: speed = "full"; break;
+#ifdef HIGHSPEED
+ case USB_SPEED_HIGH: speed = "high"; break;
+#endif
+ default: speed = "?"; break;
+ }
+
+ dev->config = number;
+ INFO (dev, "%s speed config #%d: %s\n", speed, number,
+ driver_desc);
+ }
+ return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef EP_STATUS_NUM
+
+/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications */
+#define CDC_NOTIFY_NETWORK_CONNECTION 0x00 /* required; 6.3.1 */
+#define CDC_NOTIFY_SPEED_CHANGE 0x2a /* required; 6.3.8 */
+
+struct cdc_notification {
+ u8 bmRequestType;
+ u8 bNotificationType;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+
+ /* SPEED_CHANGE data looks like this */
+ u32 data [2];
+};
+
+static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
+{
+ struct cdc_notification *event = req->buf;
+ int value = req->status;
+ struct eth_dev *dev = ep->driver_data;
+
+ /* issue the second notification if host reads the first */
+ if (event->bNotificationType == CDC_NOTIFY_NETWORK_CONNECTION
+ && value == 0) {
+ event->bmRequestType = 0xA1;
+ event->bNotificationType = CDC_NOTIFY_SPEED_CHANGE;
+ event->wValue = cpu_to_le16 (0);
+ event->wIndex = cpu_to_le16 (1);
+ event->wLength = cpu_to_le16 (8);
+
+ /* SPEED_CHANGE data is up/down speeds in bits/sec */
+ event->data [0] = event->data [1] =
+ (dev->gadget->speed == USB_SPEED_HIGH)
+ ? (13 * 512 * 8 * 1000 * 8)
+ : (19 * 64 * 1 * 1000 * 8);
+
+ req->length = 16;
+ value = usb_ep_queue (ep, req, GFP_ATOMIC);
+ DEBUG (dev, "send SPEED_CHANGE --> %d\n", value);
+ if (value == 0)
+ return;
+ } else
+ DEBUG (dev, "event %02x --> %d\n",
+ event->bNotificationType, value);
+
+ /* free when done */
+ usb_ep_free_buffer (ep, req->buf, req->dma, 16);
+ usb_ep_free_request (ep, req);
+}
+
+static void issue_start_status (struct eth_dev *dev)
+{
+ struct usb_request *req;
+ struct cdc_notification *event;
+ int value;
+
+ DEBUG (dev, "%s, flush old status first\n", __FUNCTION__);
+
+ /* flush old status
+ *
+ * FIXME ugly idiom, maybe we'd be better with just
+ * a "cancel the whole queue" primitive since any
+ * unlink-one primitive has way too many error modes.
+ */
+ usb_ep_disable (dev->status_ep);
+ usb_ep_enable (dev->status_ep, dev->status);
+
+ /* FIXME make these allocations static like dev->req */
+ req = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC);
+ if (req == 0) {
+ DEBUG (dev, "status ENOMEM\n");
+ return;
+ }
+ req->buf = usb_ep_alloc_buffer (dev->status_ep, 16,
+ &dev->req->dma, GFP_ATOMIC);
+ if (req->buf == 0) {
+ DEBUG (dev, "status buf ENOMEM\n");
+free_req:
+ usb_ep_free_request (dev->status_ep, req);
+ return;
+ }
+
+ /* 3.8.1 says to issue first NETWORK_CONNECTION, then
+ * a SPEED_CHANGE. could be useful in some configs.
+ */
+ event = req->buf;
+ event->bmRequestType = 0xA1;
+ event->bNotificationType = CDC_NOTIFY_NETWORK_CONNECTION;
+ event->wValue = cpu_to_le16 (1); /* connected */
+ event->wIndex = cpu_to_le16 (1);
+ event->wLength = 0;
+
+ req->length = 8;
+ req->complete = eth_status_complete;
+ value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
+ if (value < 0) {
+ DEBUG (dev, "status buf queue --> %d\n", value);
+ usb_ep_free_buffer (dev->status_ep,
+ req->buf, dev->req->dma, 16);
+ goto free_req;
+ }
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req)
+{
+ if (req->status || req->actual != req->length)
+ DEBUG ((struct eth_dev *) ep->driver_data,
+ "setup complete --> %d, %d/%d\n",
+ req->status, req->actual, req->length);
+}
+
+/* see section 3.8.2 table 10 of the CDC spec for more ethernet
+ * requests, mostly for filters (multicast, pm) and statistics
+ */
+#define CDC_SET_ETHERNET_PACKET_FILTER 0x43 /* required */
+
+static void eth_start (struct eth_dev *dev, int gfp_flags);
+
+/*
+ * The setup() callback implements all the ep0 functionality that's not
+ * handled lower down. CDC has a number of less-common features:
+ *
+ * - two interfaces: control, and ethernet data
+ * - data interface has two altsettings: default, and active
+ * - class-specific descriptors for the control interface
+ * - a mandatory class-specific control request
+ */
+static int
+eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+ struct eth_dev *dev = get_gadget_data (gadget);
+ struct usb_request *req = dev->req;
+ int value = -EOPNOTSUPP;
+
+ /* descriptors just go into the pre-allocated ep0 buffer,
+ * while config change events may enable network traffic.
+ */
+ switch (ctrl->bRequest) {
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ switch (ctrl->wValue >> 8) {
+
+ case USB_DT_DEVICE:
+ value = min (ctrl->wLength, (u16) sizeof device_desc);
+ memcpy (req->buf, &device_desc, value);
+ break;
+#ifdef HIGHSPEED
+ case USB_DT_DEVICE_QUALIFIER:
+ value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+ memcpy (req->buf, &dev_qualifier, value);
+ break;
+
+ case USB_DT_OTHER_SPEED_CONFIG:
+ // FALLTHROUGH
+#endif /* HIGHSPEED */
+ case USB_DT_CONFIG:
+ value = config_buf (gadget->speed, req->buf,
+ ctrl->wValue >> 8,
+ ctrl->wValue & 0xff);
+ if (value >= 0)
+ value = min (ctrl->wLength, (u16) value);
+ break;
+
+ case USB_DT_STRING:
+ value = usb_gadget_get_string (&stringtab,
+ ctrl->wValue & 0xff, req->buf);
+ if (value >= 0)
+ value = min (ctrl->wLength, (u16) value);
+ break;
+ }
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (ctrl->bRequestType != 0)
+ break;
+ spin_lock (&dev->lock);
+ value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+ spin_unlock (&dev->lock);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ *(u8 *)req->buf = dev->config;
+ value = min (ctrl->wLength, (u16) 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ if (ctrl->bRequestType != USB_RECIP_INTERFACE
+ || !dev->config
+ || ctrl->wIndex > 1)
+ break;
+ spin_lock (&dev->lock);
+ switch (ctrl->wIndex) {
+ case 0: /* control/master intf */
+ if (ctrl->wValue != 0)
+ break;
+#ifdef EP_STATUS_NUM
+ if (dev->status_ep) {
+ usb_ep_disable (dev->status_ep);
+ usb_ep_enable (dev->status_ep, dev->status);
+ }
+#endif
+ value = 0;
+ break;
+ case 1: /* data intf */
+ if (ctrl->wValue > 1)
+ break;
+ usb_ep_disable (dev->in_ep);
+ usb_ep_disable (dev->out_ep);
+
+ /* CDC requires the data transfers not be done from
+ * the default interface setting ... also, setting
+ * the non-default interface clears filters etc.
+ */
+ if (ctrl->wValue == 1) {
+ usb_ep_enable (dev->in_ep, dev->in);
+ usb_ep_enable (dev->out_ep, dev->out);
+ netif_carrier_on (&dev->net);
+#ifdef EP_STATUS_NUM
+ issue_start_status (dev);
+#endif
+ if (netif_running (&dev->net))
+ eth_start (dev, GFP_ATOMIC);
+ } else {
+ netif_stop_queue (&dev->net);
+ netif_carrier_off (&dev->net);
+ }
+ value = 0;
+ break;
+ }
+ spin_unlock (&dev->lock);
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+ || !dev->config
+ || ctrl->wIndex > 1)
+ break;
+
+ /* if carrier is on, data interface is active. */
+ *(u8 *)req->buf =
+ ((ctrl->wIndex == 1) && netif_carrier_ok (&dev->net))
+ ? 1
+ : 0,
+ value = min (ctrl->wLength, (u16) 1);
+ break;
+
+ case CDC_SET_ETHERNET_PACKET_FILTER:
+ /* see 6.2.30: no data, wIndex = interface,
+ * wValue = packet filter bitmap
+ */
+ if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+ || ctrl->wLength != 0
+ || ctrl->wIndex > 1)
+ DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue);
+ /* NOTE: table 62 has 5 filter bits to reduce traffic,
+ * and we "must" support multicast and promiscuous.
+ * this NOP implements a bad filter...
+ */
+ value = 0;
+ break;
+
+ default:
+ VDEBUG (dev,
+ "unknown control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+ }
+
+ /* respond with data transfer before status phase? */
+ if (value > 0) {
+ req->length = value;
+ value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ DEBUG (dev, "ep_queue --> %d\n", value);
+ req->status = 0;
+ eth_setup_complete (gadget->ep0, req);
+ }
+ }
+
+ /* host either stalls (value < 0) or reports success */
+ return value;
+}
+
+static void
+eth_disconnect (struct usb_gadget *gadget)
+{
+ struct eth_dev *dev = get_gadget_data (gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave (&dev->lock, flags);
+ netif_stop_queue (&dev->net);
+ netif_carrier_off (&dev->net);
+ eth_reset_config (dev);
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ /* next we may get setup() calls to enumerate new connections;
+ * or an unbind() during shutdown (including removing module).
+ */
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
+
+static int eth_change_mtu (struct net_device *net, int new_mtu)
+{
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
+
+ if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET)
+ return -ERANGE;
+ /* no zero-length packet read wanted after mtu-sized packets */
+ if (((new_mtu + sizeof (struct ethhdr)) % dev->in_ep->maxpacket) == 0)
+ return -EDOM;
+ net->mtu = new_mtu;
+ return 0;
+}
+
+static struct net_device_stats *eth_get_stats (struct net_device *net)
+{
+ return &((struct eth_dev *) net->priv)->stats;
+}
+
+static int eth_ethtool_ioctl (struct net_device *net, void *useraddr)
+{
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
+ u32 cmd;
+
+ if (get_user (cmd, (u32 *)useraddr))
+ return -EFAULT;
+ switch (cmd) {
+
+ case ETHTOOL_GDRVINFO: { /* get driver info */
+ struct ethtool_drvinfo info;
+
+ memset (&info, 0, sizeof info);
+ info.cmd = ETHTOOL_GDRVINFO;
+ strncpy (info.driver, shortname, sizeof info.driver);
+ strncpy (info.version, DRIVER_VERSION, sizeof info.version);
+ strncpy (info.fw_version, CHIP, sizeof info.fw_version);
+ strncpy (info.bus_info, dev->gadget->dev.bus_id,
+ sizeof info.bus_info);
+ if (copy_to_user (useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case ETHTOOL_GLINK: { /* get link status */
+ struct ethtool_value edata = { ETHTOOL_GLINK };
+
+ edata.data = (dev->gadget->speed != USB_SPEED_UNKNOWN);
+ if (copy_to_user (useraddr, &edata, sizeof (edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ }
+ /* Note that the ethtool user space code requires EOPNOTSUPP */
+ return -EOPNOTSUPP;
+}
+
+static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+{
+ switch (cmd) {
+ case SIOCETHTOOL:
+ return eth_ethtool_ioctl (net, (void *)rq->ifr_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void defer_kevent (struct eth_dev *dev, int flag)
+{
+ set_bit (flag, &dev->todo);
+ if (!schedule_work (&dev->work))
+ ERROR (dev, "kevent %d may have been dropped\n", flag);
+ else
+ DEBUG (dev, "kevent %d scheduled\n", flag);
+}
+
+static void rx_complete (struct usb_ep *ep, struct usb_request *req);
+
+static int
+rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
+{
+ struct sk_buff *skb;
+ int retval = 0;
+ size_t size;
+
+ size = (sizeof (struct ethhdr) + dev->net.mtu);
+
+ if ((skb = alloc_skb (size, gfp_flags)) == 0) {
+ DEBUG (dev, "no rx skb\n");
+ defer_kevent (dev, WORK_RX_MEMORY);
+ usb_ep_free_request (dev->out_ep, req);
+ return -ENOMEM;
+ }
+
+ req->buf = skb->data;
+ req->length = size;
+ req->complete = rx_complete;
+ req->context = skb;
+
+ if (netif_running (&dev->net)) {
+ retval = usb_ep_queue (dev->out_ep, req, gfp_flags);
+ if (retval == -ENOMEM)
+ defer_kevent (dev, WORK_RX_MEMORY);
+ if (retval)
+ DEBUG (dev, "%s %d\n", __FUNCTION__, retval);
+ } else {
+ DEBUG (dev, "%s stopped\n", __FUNCTION__);
+ retval = -ENOLINK;
+ }
+ if (retval) {
+ DEBUG (dev, "rx submit --> %d\n", retval);
+ dev_kfree_skb_any (skb);
+ usb_ep_free_request (dev->out_ep, req);
+ }
+ return retval;
+}
+
+static void rx_complete (struct usb_ep *ep, struct usb_request *req)
+{
+ struct sk_buff *skb = req->context;
+ struct eth_dev *dev = ep->driver_data;
+ int status = req->status;
+
+ switch (status) {
+
+ /* normal completion */
+ case 0:
+ skb_put (skb, req->actual);
+ if (MIN_PACKET > skb->len
+ || skb->len > (MAX_PACKET + ETH_HLEN)) {
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ DEBUG (dev, "rx length %d\n", skb->len);
+ break;
+ }
+
+ skb->dev = &dev->net;
+ skb->protocol = eth_type_trans (skb, &dev->net);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+
+ /* no buffer copies needed, unless hardware can't
+ * use skb buffers.
+ */
+ status = netif_rx (skb);
+ skb = 0;
+ break;
+
+ /* software-driven interface shutdown */
+ case -ECONNRESET: // unlink
+ case -ESHUTDOWN: // disconnect etc
+ VDEBUG (dev, "rx shutdown, code %d\n", status);
+ usb_ep_free_request (dev->out_ep, req);
+ req = 0;
+ break;
+
+ /* data overrun */
+ case -EOVERFLOW:
+ dev->stats.rx_over_errors++;
+ // FALLTHROUGH
+
+ default:
+ dev->stats.rx_errors++;
+ DEBUG (dev, "rx status %d\n", status);
+ break;
+ }
+
+ if (skb)
+ dev_kfree_skb_any (skb);
+
+ if (req)
+ rx_submit (dev, req, GFP_ATOMIC);
+}
+
+static void eth_work (void *_dev)
+{
+ struct eth_dev *dev = _dev;
+
+ if (test_bit (WORK_RX_MEMORY, &dev->todo)) {
+ struct usb_request *req = 0;
+
+ if (netif_running (&dev->net))
+ req = usb_ep_alloc_request (dev->in_ep, GFP_KERNEL);
+ else
+ clear_bit (WORK_RX_MEMORY, &dev->todo);
+ if (req != 0) {
+ clear_bit (WORK_RX_MEMORY, &dev->todo);
+ rx_submit (dev, req, GFP_KERNEL);
+ }
+ }
+
+ if (dev->todo)
+ DEBUG (dev, "work done, flags = 0x%lx\n", dev->todo);
+}
+
+static void tx_complete (struct usb_ep *ep, struct usb_request *req)
+{
+ struct sk_buff *skb = req->context;
+ struct eth_dev *dev = ep->driver_data;
+
+ if (req->status)
+ dev->stats.tx_errors++;
+ else
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+
+ usb_ep_free_request (ep, req);
+ dev_kfree_skb_any (skb);
+
+ atomic_inc (&dev->tx_qlen);
+ if (netif_carrier_ok (&dev->net))
+ netif_wake_queue (&dev->net);
+}
+
+static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
+{
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
+ int length = skb->len;
+ int retval;
+ struct usb_request *req = 0;
+
+ if (!(req = usb_ep_alloc_request (dev->in_ep, GFP_ATOMIC))) {
+ DEBUG (dev, "no request\n");
+ goto drop;
+ }
+
+ /* no buffer copies needed, unless the network stack did it
+ * or the hardware can't use skb buffers.
+ */
+ req->buf = skb->data;
+ req->context = skb;
+ req->complete = tx_complete;
+
+#ifdef CONFIG_USB_ETH_SA1100
+ /* don't demand zlp (req->zero) support from all hardware */
+ if ((length % dev->in_ep->maxpacket) == 0)
+ length++;
+#else
+ /* use zlp framing on tx for strict CDC-Ether conformance,
+ * though any robust network rx path ignores extra padding.
+ */
+ req->zero = 1;
+#endif
+ req->length = length;
+
+#ifdef HIGHSPEED
+ /* throttle highspeed IRQ rate back slightly */
+ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+ ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
+ : 0;
+#endif
+
+ retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+ switch (retval) {
+ default:
+ DEBUG (dev, "tx queue err %d\n", retval);
+ break;
+ case 0:
+ net->trans_start = jiffies;
+ if (atomic_dec_and_test (&dev->tx_qlen))
+ netif_stop_queue (net);
+ }
+
+ if (retval) {
+ DEBUG (dev, "drop, code %d\n", retval);
+drop:
+ dev->stats.tx_dropped++;
+ dev_kfree_skb_any (skb);
+ usb_ep_free_request (dev->in_ep, req);
+ }
+ return 0;
+}
+
+static void eth_start (struct eth_dev *dev, int gfp_flags)
+{
+ struct usb_request *req;
+ int retval = 0;
+ unsigned i;
+ int size = qlen (dev->gadget);
+
+ DEBUG (dev, "%s\n", __FUNCTION__);
+
+ /* fill the rx queue */
+ for (i = 0; retval == 0 && i < size; i++) {
+ req = usb_ep_alloc_request (dev->in_ep, gfp_flags);
+ if (req)
+ retval = rx_submit (dev, req, gfp_flags);
+ else if (i > 0)
+ defer_kevent (dev, WORK_RX_MEMORY);
+ else
+ retval = -ENOMEM;
+ }
+
+ /* and open the tx floodgates */
+ atomic_set (&dev->tx_qlen, size);
+ netif_wake_queue (&dev->net);
+}
+
+static int eth_open (struct net_device *net)
+{
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
+
+ DEBUG (dev, "%s\n", __FUNCTION__);
+ down (&dev->mutex);
+ if (netif_carrier_ok (&dev->net))
+ eth_start (dev, GFP_KERNEL);
+ up (&dev->mutex);
+ return 0;
+}
+
+static int eth_stop (struct net_device *net)
+{
+ struct eth_dev *dev = (struct eth_dev *) net->priv;
+
+ DEBUG (dev, "%s\n", __FUNCTION__);
+ down (&dev->mutex);
+ netif_stop_queue (net);
+
+ DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+ dev->stats.rx_packets, dev->stats.tx_packets,
+ dev->stats.rx_errors, dev->stats.tx_errors
+ );
+
+ /* ensure there are no more active requests */
+ if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+ usb_ep_disable (dev->in_ep);
+ usb_ep_disable (dev->out_ep);
+ if (netif_carrier_ok (&dev->net)) {
+ DEBUG (dev, "host still using in/out endpoints\n");
+ usb_ep_enable (dev->in_ep, dev->in);
+ usb_ep_enable (dev->out_ep, dev->out);
+ }
+#ifdef EP_STATUS_NUM
+ usb_ep_disable (dev->status_ep);
+ usb_ep_enable (dev->status_ep, dev->status);
+#endif
+ }
+
+ up (&dev->mutex);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+eth_unbind (struct usb_gadget *gadget)
+{
+ struct eth_dev *dev = get_gadget_data (gadget);
+
+ DEBUG (dev, "unbind\n");
+ down (&dev->mutex);
+
+ /* we've already been disconnected ... no i/o is active */
+ if (dev->req) {
+ usb_ep_free_buffer (gadget->ep0,
+ dev->req->buf, dev->req->dma,
+ USB_BUFSIZ);
+ usb_ep_free_request (gadget->ep0, dev->req);
+ }
+
+ unregister_netdev (&dev->net);
+ up (&dev->mutex);
+
+ /* assuming we used keventd, it must quiesce too */
+ flush_scheduled_work ();
+
+ kfree (dev);
+ set_gadget_data (gadget, 0);
+}
+
+static int
+eth_bind (struct usb_gadget *gadget)
+{
+ struct eth_dev *dev;
+ struct net_device *net;
+ u8 node_id [ETH_ALEN];
+
+ /* just one upstream link at a time */
+ if (ethaddr [0] != 0)
+ return -ENODEV;
+
+ dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ memset (dev, 0, sizeof *dev);
+ spin_lock_init (&dev->lock);
+ init_MUTEX_LOCKED (&dev->mutex);
+ INIT_WORK (&dev->work, eth_work, dev);
+
+ /* network device setup */
+ net = &dev->net;
+ SET_MODULE_OWNER (net);
+ net->priv = dev;
+ strcpy (net->name, "usb%d");
+ ether_setup (net);
+
+ /* one random address for the gadget device ... both of these could
+ * reasonably come from an id prom or a module parameter.
+ */
+ get_random_bytes (net->dev_addr, ETH_ALEN);
+ net->dev_addr [0] &= 0xfe; // clear multicast bit
+ net->dev_addr [0] |= 0x02; // set local assignment bit (IEEE802)
+
+ /* ... another address for the host, on the other end of the
+ * link, gets exported through CDC (see CDC spec table 41)
+ */
+ get_random_bytes (node_id, sizeof node_id);
+ node_id [0] &= 0xfe; // clear multicast bit
+ node_id [0] |= 0x02; // set local assignment bit (IEEE802)
+ snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+ node_id [0], node_id [1], node_id [2],
+ node_id [3], node_id [4], node_id [5]);
+
+ net->change_mtu = eth_change_mtu;
+ net->get_stats = eth_get_stats;
+ net->hard_start_xmit = eth_start_xmit;
+ net->open = eth_open;
+ net->stop = eth_stop;
+ // watchdog_timeo, tx_timeout ...
+ // set_multicast_list
+ net->do_ioctl = eth_ioctl;
+
+ /* preallocate control response and buffer */
+ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+ if (!dev->req)
+ goto enomem;
+ dev->req->complete = eth_setup_complete;
+ dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
+ &dev->req->dma, GFP_KERNEL);
+ if (!dev->req->buf) {
+ usb_ep_free_request (gadget->ep0, dev->req);
+ goto enomem;
+ }
+
+ /* finish hookup to lower layer ... */
+ dev->gadget = gadget;
+ set_gadget_data (gadget, dev);
+ gadget->ep0->driver_data = dev;
+
+ /* two kinds of host-initiated state changes:
+ * - iff DATA transfer is active, carrier is "on"
+ * - tx queueing enabled if open *and* carrier is "on"
+ */
+ INFO (dev, "%s, host enet %s, version: " DRIVER_VERSION "\n",
+ driver_desc, ethaddr);
+ register_netdev (&dev->net);
+ netif_stop_queue (&dev->net);
+ netif_carrier_off (&dev->net);
+
+ up (&dev->mutex);
+ return 0;
+
+enomem:
+ eth_unbind (gadget);
+ return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver eth_driver = {
+#ifdef HIGHSPEED
+ .speed = USB_SPEED_HIGH,
+#else
+ .speed = USB_SPEED_FULL,
+#endif
+ .function = (char *) driver_desc,
+ .bind = eth_bind,
+ .unbind = eth_unbind,
+
+ .setup = eth_setup,
+ .disconnect = eth_disconnect,
+
+ .driver = {
+ .name = (char *) shortname,
+ // .shutdown = ...
+ // .suspend = ...
+ // .resume = ...
+ },
+};
+
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_AUTHOR ("David Brownell");
+MODULE_LICENSE ("GPL");
+
+
+static int __init init (void)
+{
+ return usb_gadget_register_driver (&eth_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+ usb_gadget_unregister_driver (&eth_driver);
+}
+module_exit (cleanup);
+
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
new file mode 100644
index 000000000000..af680a81dede
--- /dev/null
+++ b/drivers/usb/gadget/net2280.c
@@ -0,0 +1,2660 @@
+/*
+ * Driver for the NetChip 2280 USB device controller.
+ * Specs and errata are available from <http://www.netchip.com>.
+ *
+ * NetChip Technology Inc. supported the development of this driver.
+ *
+ *
+ * CODE STATUS HIGHLIGHTS
+ *
+ * Used with a gadget driver like "zero.c" this enumerates fine to Windows
+ * or Linux hosts; handles disconnect, reconnect, and reset, for full or
+ * high speed operation; and passes USB-IF "chapter 9" tests.
+ *
+ * Handles standard stress loads from the Linux "usbtest" driver, with
+ * either DMA (default) or PIO (use_dma=n) used for ep-{a,b,c,d}. Testing
+ * with "ttcp" (and the "ether.c" driver) behaves nicely too.
+ *
+ * DMA is enabled by default. Drivers using transfer queues might use
+ * DMA chaining to remove IRQ latencies between transfers. (Except when
+ * short OUT transfers happen.) Drivers can use the req->no_interrupt
+ * hint to completely eliminate some IRQs, if a later IRQ is guaranteed
+ * and DMA chaining is enabled.
+ */
+
+// #define NET2280_DMA_OUT_WORKAROUND
+// #define USE_DMA_CHAINING
+
+
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define DEBUG 1
+// #define VERBOSE /* extra debug messages (success too) */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+#define DRIVER_DESC "NetChip 2280 USB Peripheral Controller"
+#define DRIVER_VERSION "May Day 2003"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+#define EP_DONTUSE 13 /* nonzero */
+
+#define USE_RDK_LEDS /* GPIO pins control three LEDs */
+#define USE_SYSFS_DEBUG_FILES
+
+
+static const char driver_name [] = "net2280";
+static const char driver_desc [] = DRIVER_DESC;
+
+static const char ep0name [] = "ep0";
+static const char *ep_name [] = {
+ ep0name,
+ "ep-a", "ep-b", "ep-c", "ep-d",
+ "ep-e", "ep-f",
+};
+
+static int use_dma = 1;
+
+/* "modprobe net2280 use_dma=n" etc */
+module_param (use_dma, bool, S_IRUGO|S_IWUSR);
+
+#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+#if defined(USE_SYSFS_DEBUG_FILES) || defined (DEBUG)
+static char *type_string (u8 bmAttributes)
+{
+ switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK: return "bulk";
+ case USB_ENDPOINT_XFER_ISOC: return "iso";
+ case USB_ENDPOINT_XFER_INT: return "intr";
+ };
+ return "control";
+}
+#endif
+
+#include "net2280.h"
+
+#define valid_bit cpu_to_le32 (1 << VALID_BIT)
+#define dma_done_ie cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+ struct net2280 *dev;
+ struct net2280_ep *ep;
+ u32 max, tmp;
+ unsigned long flags;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || !desc || ep->desc || _ep->name == ep0name
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* erratum 0119 workaround ties up an endpoint number */
+ if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE)
+ return -EDOM;
+
+ /* sanity check ep-e/ep-f since their fifos are small */
+ max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
+ if (ep->num > 4 && max > 64)
+ return -ERANGE;
+
+ spin_lock_irqsave (&dev->lock, flags);
+ _ep->maxpacket = max & 0x7ff;
+ ep->desc = desc;
+
+ /* ep_reset() has already been called */
+ ep->stopped = 0;
+
+ /* set speed-dependent max packet; may kick in high bandwidth */
+ set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max);
+
+ /* FIFO lines can't go to different packets. PIO is ok, so
+ * use it instead of troublesome (non-bulk) multi-packet DMA.
+ */
+ if (ep->is_in && ep->dma && (max % 4) != 0) {
+ DEBUG (ep->dev, "%s, no IN dma for maxpacket %d\n",
+ ep->ep.name, ep->ep.maxpacket);
+ ep->dma = 0;
+ }
+
+ /* set type, direction, address; reset fifo counters */
+ writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
+ tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ if (tmp == USB_ENDPOINT_XFER_INT) {
+ /* not just because of erratum 0105; avoid ever
+ * kicking in the "toggle-irrelevant" mode.
+ */
+ tmp = USB_ENDPOINT_XFER_BULK;
+ }
+ ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
+ tmp <<= ENDPOINT_TYPE;
+ tmp |= desc->bEndpointAddress;
+ tmp |= (4 << ENDPOINT_BYTE_COUNT); /* default full fifo lines */
+ tmp |= 1 << ENDPOINT_ENABLE;
+ wmb ();
+
+ /* for OUT transfers, block the rx fifo until a read is posted */
+ ep->is_in = (tmp & USB_DIR_IN) != 0;
+ if (!ep->is_in)
+ writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+
+ writel (tmp, &ep->regs->ep_cfg);
+
+#ifdef NET2280_DMA_OUT_WORKAROUND
+ if (!ep->is_in)
+ ep->dma = 0;
+#endif
+
+ /* enable irqs */
+ if (!ep->dma) { /* pio, per-packet */
+ tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
+ writel (tmp, &dev->regs->pciirqenb0);
+
+ tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
+ | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
+ | readl (&ep->regs->ep_irqenb);
+ writel (tmp, &ep->regs->ep_irqenb);
+ } else { /* dma, per-request */
+ tmp = (1 << (8 + ep->num)); /* completion */
+ tmp |= readl (&dev->regs->pciirqenb1);
+ writel (tmp, &dev->regs->pciirqenb1);
+
+ /* for short OUT transfers, dma completions can't
+ * advance the queue; do it pio-style, by hand.
+ * NOTE erratum 0112 workaround #2
+ */
+ if ((desc->bEndpointAddress & USB_DIR_IN) == 0) {
+ tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE);
+ writel (tmp, &ep->regs->ep_irqenb);
+
+ tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
+ writel (tmp, &dev->regs->pciirqenb0);
+ }
+ }
+
+ tmp = desc->bEndpointAddress;
+ DEBUG (dev, "enabled %s (ep%d%s-%s) %s max %04x\n",
+ _ep->name, tmp & 0x0f, DIR_STRING (tmp),
+ type_string (desc->bmAttributes),
+ ep->dma ? "dma" : "pio", max);
+
+ /* pci writes may still be posted */
+ spin_unlock_irqrestore (&dev->lock, flags);
+ return 0;
+}
+
+static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = readl (ptr);
+ if (result == ~(u32)0) /* "device unplugged" */
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay (1);
+ usec--;
+ } while (usec > 0);
+#ifdef DEBUG
+ if (done == 0) dump_stack (); /* ignore out_flush timeout */
+#endif
+ return -ETIMEDOUT;
+}
+
+static struct usb_ep_ops net2280_ep_ops;
+
+static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep)
+{
+ u32 tmp;
+
+ ep->desc = 0;
+ INIT_LIST_HEAD (&ep->queue);
+
+ ep->ep.maxpacket = ~0;
+ ep->ep.ops = &net2280_ep_ops;
+
+ /* disable the dma, irqs, endpoint... */
+ if (ep->dma) {
+ writel (0, &ep->dma->dmactl);
+ writel ( (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT)
+ | (1 << DMA_TRANSACTION_DONE_INTERRUPT)
+ | (1 << DMA_ABORT)
+ , &ep->dma->dmastat);
+
+ tmp = readl (&regs->pciirqenb0);
+ tmp &= ~(1 << ep->num);
+ writel (tmp, &regs->pciirqenb0);
+ } else {
+ tmp = readl (&regs->pciirqenb1);
+ tmp &= ~(1 << (8 + ep->num)); /* completion */
+ writel (tmp, &regs->pciirqenb1);
+ }
+ writel (0, &ep->regs->ep_irqenb);
+
+ /* init to our chosen defaults, notably so that we NAK OUT
+ * packets until the driver queues a read (+note erratum 0112)
+ */
+ writel ( (1 << SET_NAK_OUT_PACKETS_MODE)
+ | (1 << SET_NAK_OUT_PACKETS)
+ | (1 << CLEAR_EP_HIDE_STATUS_PHASE)
+ | (1 << CLEAR_INTERRUPT_MODE)
+ | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+ | (1 << CLEAR_ENDPOINT_TOGGLE)
+ | (1 << CLEAR_ENDPOINT_HALT)
+ , &ep->regs->ep_rsp);
+
+ /* scrub most status bits, and flush any fifo state */
+ writel ( (1 << TIMEOUT)
+ | (1 << USB_STALL_SENT)
+ | (1 << USB_IN_NAK_SENT)
+ | (1 << USB_IN_ACK_RCVD)
+ | (1 << USB_OUT_PING_NAK_SENT)
+ | (1 << USB_OUT_ACK_SENT)
+ | (1 << FIFO_OVERFLOW)
+ | (1 << FIFO_UNDERFLOW)
+ | (1 << FIFO_FLUSH)
+ | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
+ | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
+ | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+ | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+ | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ | (1 << DATA_IN_TOKEN_INTERRUPT)
+ , &ep->regs->ep_stat);
+
+ /* fifo size is handled separately */
+}
+
+static void nuke (struct net2280_ep *);
+
+static int net2280_disable (struct usb_ep *_ep)
+{
+ struct net2280_ep *ep;
+ unsigned long flags;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || !ep->desc || _ep->name == ep0name)
+ return -EINVAL;
+
+ spin_lock_irqsave (&ep->dev->lock, flags);
+ nuke (ep);
+ ep_reset (ep->dev->regs, ep);
+
+ VDEBUG (ep->dev, "disabled %s %s\n",
+ ep->dma ? "dma" : "pio", _ep->name);
+
+ /* synch memory views with the device */
+ (void) readl (&ep->regs->ep_cfg);
+
+ if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
+ ep->dma = &ep->dev->dma [ep->num - 1];
+
+ spin_unlock_irqrestore (&ep->dev->lock, flags);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+net2280_alloc_request (struct usb_ep *_ep, int gfp_flags)
+{
+ struct net2280_ep *ep;
+ struct net2280_request *req;
+
+ if (!_ep)
+ return 0;
+ ep = container_of (_ep, struct net2280_ep, ep);
+
+ req = kmalloc (sizeof *req, gfp_flags);
+ if (!req)
+ return 0;
+
+ memset (req, 0, sizeof *req);
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD (&req->queue);
+
+ /* this dma descriptor may be swapped with the previous dummy */
+ if (ep->dma) {
+ struct net2280_dma *td;
+
+ td = pci_pool_alloc (ep->dev->requests, gfp_flags,
+ &req->td_dma);
+ if (!td) {
+ kfree (req);
+ return 0;
+ }
+ td->dmacount = 0; /* not VALID */
+ td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
+ req->td = td;
+ }
+ return &req->req;
+}
+
+static void
+net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct net2280_ep *ep;
+ struct net2280_request *req;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!ep || !_req || (!ep->desc && ep->num != 0))
+ return;
+
+ req = container_of (_req, struct net2280_request, req);
+ WARN_ON (!list_empty (&req->queue));
+ if (req->td)
+ pci_pool_free (ep->dev->requests, req->td, req->td_dma);
+ kfree (req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#undef USE_KMALLOC
+
+/* many common platforms have dma-coherent caches, which means that it's
+ * safe to use kmalloc() memory for all i/o buffers without using any
+ * cache flushing calls. (unless you're trying to share cache lines
+ * between dma and non-dma activities, which is a slow idea in any case.)
+ *
+ * other platforms need more care, with 2.5 having a moderately general
+ * solution (which falls down for allocations smaller than one page)
+ * that improves significantly on the 2.4 PCI allocators by removing
+ * the restriction that memory never be freed in_interrupt().
+ */
+#if defined(CONFIG_X86)
+#define USE_KMALLOC
+
+#elif define(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+#define USE_KMALLOC
+
+/* FIXME there are other cases, including an x86-64 one ... */
+#endif
+
+/* allocating buffers this way eliminates dma mapping overhead, which
+ * on some platforms will mean eliminating a per-io buffer copy. with
+ * some kinds of system caches, further tweaks may still be needed.
+ */
+static void *
+net2280_alloc_buffer (
+ struct usb_ep *_ep,
+ unsigned bytes,
+ dma_addr_t *dma,
+ int gfp_flags
+)
+{
+ void *retval;
+ struct net2280_ep *ep;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!ep || (!ep->desc && ep->num != 0))
+ return 0;
+
+ *dma = DMA_ADDR_INVALID;
+ if (ep->dma) {
+#if defined(USE_KMALLOC)
+ retval = kmalloc (bytes, gfp_flags);
+ if (retval)
+ *dma = virt_to_phys (retval);
+
+#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,5,58)
+#warning Using dma_alloc_consistent even with sub-page allocations
+ /* the main problem with this call is that it wastes memory
+ * on typical 1/N page allocations: it allocates 1-N pages.
+ */
+ retval = dma_alloc_coherent (&ep->dev->pdev->dev,
+ bytes, dma, gfp_flags);
+#else
+#error No dma-coherent memory allocator is available
+ /* pci_alloc_consistent works, but pci_free_consistent()
+ * isn't safe in_interrupt(). plus, in addition to the
+ * 1/Nth page weakness, it doesn't understand gfp_flags.
+ */
+#endif
+ } else
+ retval = kmalloc (bytes, gfp_flags);
+
+ return retval;
+}
+
+static void
+net2280_free_buffer (
+ struct usb_ep *_ep,
+ void *buf,
+ dma_addr_t dma,
+ unsigned bytes
+) {
+ /* free memory into the right allocator */
+#ifndef USE_KMALLOC
+ if (dma != DMA_ADDR_INVALID)
+ dma_free_coherent (ep->dev->pdev, bytes, dma);
+ else
+#endif
+ kfree (buf);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* load a packet into the fifo we use for usb IN transfers.
+ * works for all endpoints.
+ *
+ * NOTE: pio with ep-a..ep-d could stuff multiple packets into the fifo
+ * at a time, but this code is simpler because it knows it only writes
+ * one packet. ep-a..ep-d should use dma instead.
+ */
+static void
+write_fifo (struct net2280_ep *ep, struct usb_request *req)
+{
+ struct net2280_ep_regs *regs = ep->regs;
+ u8 *buf;
+ unsigned count, total;
+
+ /* INVARIANT: fifo is currently empty. (testable) */
+
+ if (req) {
+ total = req->length - req->actual;
+ buf = req->buf + req->actual;
+ } else {
+ total = 0;
+ buf = 0;
+ }
+
+ /* write just one packet at a time */
+ count = min (ep->ep.maxpacket, total);
+ VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n",
+ ep->ep.name, count,
+ (count != ep->ep.maxpacket) ? " (short)" : "",
+ req);
+ while (count >= 4) {
+ /* NOTE be careful if you try to align these. fifo lines
+ * should normally be full (4 bytes) and successive partial
+ * lines are ok only in certain cases.
+ */
+ writel (get_unaligned ((u32 *)buf), &regs->ep_data);
+ buf += 4;
+ count -= 4;
+ }
+
+ /* last fifo entry is "short" unless we wrote a full packet */
+ if (total < ep->ep.maxpacket) {
+ u32 tmp = count ? get_unaligned ((u32 *)buf) : count;
+ set_fifo_bytecount (ep, count & 0x03);
+ writel (tmp, &regs->ep_data);
+ }
+
+ /* pci writes may still be posted */
+}
+
+/* work around erratum 0106: PCI and USB race over the OUT fifo.
+ * caller guarantees chiprev 0100, out endpoint is NAKing, and
+ * there's no real data in the fifo.
+ */
+static void out_flush (struct net2280_ep *ep)
+{
+ u32 *statp, tmp;
+
+ ASSERT_OUT_NAKING (ep);
+
+ statp = &ep->regs->ep_stat;
+ writel ( (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+ , statp);
+ writel ((1 << FIFO_FLUSH), statp);
+ mb ();
+ tmp = readl (statp);
+ if (tmp & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) {
+ unsigned usec;
+
+ if (ep->dev->gadget.speed == USB_SPEED_HIGH) {
+ if (ep->ep.maxpacket <= 512)
+ usec = 10; /* 512 byte bulk */
+ else
+ usec = 21; /* 1024 byte interrupt */
+ } else
+ usec = 50; /* 64 byte bulk/interrupt */
+ handshake (statp, (1 << USB_OUT_PING_NAK_SENT),
+ (1 << USB_OUT_PING_NAK_SENT), usec);
+ /* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */
+ }
+}
+
+/* unload packet(s) from the fifo we use for usb OUT transfers.
+ * returns true iff the request completed, because of short packet
+ * or the request buffer having filled with full packets.
+ *
+ * for ep-a..ep-d this will read multiple packets out when they
+ * have been accepted.
+ */
+static int
+read_fifo (struct net2280_ep *ep, struct net2280_request *req)
+{
+ struct net2280_ep_regs *regs = ep->regs;
+ u8 *buf = req->req.buf + req->req.actual;
+ unsigned count, tmp, is_short;
+ unsigned cleanup = 0, prevent = 0;
+
+ /* erratum 0106 ... packets coming in during fifo reads might
+ * be incompletely rejected. not all cases have workarounds.
+ */
+ if (ep->dev->chiprev == 0x0100) {
+ tmp = readl (&ep->regs->ep_stat);
+ if ((tmp & (1 << NAK_OUT_PACKETS)))
+ /* cleanup = 1 */;
+ else if ((tmp & (1 << FIFO_FULL))
+ /* don't break hs PING protocol ... */
+ || ep->dev->gadget.speed == USB_SPEED_FULL) {
+ start_out_naking (ep);
+ prevent = 1;
+ }
+ /* else: hope we don't see the problem */
+ }
+
+ /* never overflow the rx buffer. the fifo reads packets until
+ * it sees a short one; we might not be ready for them all.
+ */
+ count = readl (&regs->ep_avail);
+ tmp = req->req.length - req->req.actual;
+ if (count > tmp) {
+ unsigned over = tmp % ep->ep.maxpacket;
+
+ /* FIXME handle this consistently between PIO and DMA */
+ if (over) {
+ ERROR (ep->dev,
+ "%s out fifo %d bytes, over %d extra %d\n",
+ ep->ep.name, count, over, count - tmp);
+ req->req.status = -EOVERFLOW;
+ tmp -= over;
+ }
+ count = tmp;
+ }
+ req->req.actual += count;
+
+ is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0);
+
+ VDEBUG (ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n",
+ ep->ep.name, count, is_short ? " (short)" : "",
+ cleanup ? " flush" : "", prevent ? " nak" : "",
+ req, req->req.actual, req->req.length);
+
+ while (count >= 4) {
+ put_unaligned (readl (&regs->ep_data), (u32 *)buf);
+ buf += 4;
+ count -= 4;
+ }
+ if (count) {
+ tmp = readl (&regs->ep_data);
+ do {
+ *buf++ = (u8) tmp;
+ tmp >>= 8;
+ } while (--count);
+ }
+ if (cleanup)
+ out_flush (ep);
+ if (prevent) {
+ writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+ (void) readl (&ep->regs->ep_rsp);
+ }
+
+ return is_short || ((req->req.actual == req->req.length)
+ && !req->req.zero);
+}
+
+/* fill out dma descriptor to match a given request */
+static inline void
+fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
+{
+ struct net2280_dma *td = req->td;
+ u32 dmacount = req->req.length;
+
+ /* don't let DMA continue after a short OUT packet,
+ * so overruns can't affect the next transfer.
+ */
+ if (ep->is_in)
+ dmacount |= (1 << DMA_DIRECTION);
+ else if ((dmacount % ep->ep.maxpacket) != 0)
+ dmacount |= (1 << END_OF_CHAIN);
+
+ req->valid = valid;
+ if (valid)
+ dmacount |= (1 << VALID_BIT);
+#ifdef USE_DMA_CHAINING
+ if (!req->req.no_interrupt)
+#endif
+ dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
+
+ /* td->dmadesc = previously set by caller */
+ td->dmaaddr = cpu_to_le32p (&req->req.dma);
+
+ /* 2280 may be polling VALID_BIT through ep->dma->dmadesc */
+ wmb ();
+ td->dmacount = cpu_to_le32p (&dmacount);
+}
+
+static const u32 dmactl_default =
+ (1 << DMA_CLEAR_COUNT_ENABLE)
+ /* erratum 0116 workaround part 1 (use POLLING) */
+ | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE)
+ | (1 << DMA_VALID_BIT_POLLING_ENABLE)
+ | (1 << DMA_VALID_BIT_ENABLE)
+ | (1 << DMA_SCATTER_GATHER_ENABLE)
+ /* erratum 0116 workaround part 2 (no AUTOSTART) */
+ | (1 << DMA_ENABLE);
+
+static inline void spin_stop_dma (struct net2280_dma_regs *dma)
+{
+ handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50);
+}
+
+static inline void stop_dma (struct net2280_dma_regs *dma)
+{
+ writel (dmactl_default & ~(1 << DMA_ENABLE), &dma->dmactl);
+ spin_stop_dma (dma);
+}
+
+static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
+{
+ u32 tmp;
+ int clear_nak = 0;
+ struct net2280_dma_regs *dma = ep->dma;
+
+ /* FIXME can't use DMA for ZLPs */
+
+ /* previous OUT packet might have been short */
+ if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
+ & (1 << NAK_OUT_PACKETS)) != 0) {
+ writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
+ &ep->regs->ep_stat);
+
+ tmp = readl (&ep->regs->ep_avail);
+ if (tmp == 0)
+ clear_nak = 1;
+ else {
+ /* transfer all/some fifo data */
+ writel (req->req.dma, &dma->dmaaddr);
+ tmp = min (tmp, req->req.length);
+
+ /* dma irq, faking scatterlist status */
+ req->td->dmacount = cpu_to_le32 (req->req.length - tmp);
+ writel ((1 << DMA_DONE_INTERRUPT_ENABLE)
+ | tmp, &dma->dmacount);
+
+ writel ((1 << DMA_ENABLE), &dma->dmactl);
+ writel ((1 << DMA_START), &dma->dmastat);
+ return;
+ }
+ }
+
+ /* on this path we know there's no dma queue (yet) */
+ WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE));
+ tmp = dmactl_default;
+
+ /* force packet boundaries between dma requests, but prevent the
+ * controller from automagically writing a last "short" packet
+ * (zero length) unless the driver explicitly said to do that.
+ */
+ if (ep->is_in) {
+ if (likely ((req->req.length % ep->ep.maxpacket) != 0
+ || req->req.zero)) {
+ tmp |= (1 << DMA_FIFO_VALIDATE);
+ ep->in_fifo_validate = 1;
+ } else
+ ep->in_fifo_validate = 0;
+ }
+
+ /* init req->td, pointing to the current dummy */
+ req->td->dmadesc = cpu_to_le32 (ep->td_dma);
+ fill_dma_desc (ep, req, 1);
+
+#ifdef USE_DMA_CHAINING
+ writel ( (1 << VALID_BIT)
+ | (ep->is_in << DMA_DIRECTION)
+ | 0, &dma->dmacount);
+#else
+ req->td->dmacount |= cpu_to_le32 (1 << END_OF_CHAIN);
+#endif
+
+ writel (req->td_dma, &dma->dmadesc);
+ writel (tmp, &dma->dmactl);
+
+ /* erratum 0116 workaround part 3: pci arbiter away from net2280 */
+ (void) readl (&ep->dev->pci->pcimstctl);
+
+ writel ((1 << DMA_START), &dma->dmastat);
+
+ /* recover from previous short read; erratum 0112 workaround #1 */
+ if (clear_nak)
+ writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+}
+
+static inline void
+queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid)
+{
+ struct net2280_dma *end;
+ dma_addr_t tmp;
+
+ /* swap new dummy for old, link; fill and maybe activate */
+ end = ep->dummy;
+ ep->dummy = req->td;
+ req->td = end;
+
+ tmp = ep->td_dma;
+ ep->td_dma = req->td_dma;
+ req->td_dma = tmp;
+
+ end->dmadesc = cpu_to_le32 (ep->td_dma);
+
+ fill_dma_desc (ep, req, valid);
+}
+
+static void
+done (struct net2280_ep *ep, struct net2280_request *req, int status)
+{
+ struct net2280 *dev;
+ unsigned stopped = ep->stopped;
+
+ list_del_init (&req->queue);
+
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ dev = ep->dev;
+ if (req->mapped) {
+ pci_unmap_single (dev->pdev, req->req.dma, req->req.length,
+ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+
+ if (status && status != -ESHUTDOWN)
+ VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+ spin_unlock (&dev->lock);
+ req->req.complete (&ep->ep, &req->req);
+ spin_lock (&dev->lock);
+ ep->stopped = stopped;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+{
+ struct net2280_request *req;
+ struct net2280_ep *ep;
+ struct net2280 *dev;
+ unsigned long flags;
+
+ /* we always require a cpu-view buffer, so that we can
+ * always use pio (as fallback or whatever).
+ */
+ req = container_of (_req, struct net2280_request, req);
+ if (!_req || !_req->complete || !_req->buf
+ || !list_empty (&req->queue))
+ return -EINVAL;
+ if (_req->length > (~0 & DMA_BYTE_COUNT_MASK))
+ return -EDOM;
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || (!ep->desc && ep->num != 0))
+ return -EINVAL;
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* FIXME implement PIO fallback for ZLPs with DMA */
+ if (ep->dma && _req->length == 0)
+ return -EOPNOTSUPP;
+
+ /* set up dma mapping in case the caller didn't */
+ if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
+ _req->dma = pci_map_single (dev->pdev, _req->buf, _req->length,
+ ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ req->mapped = 1;
+ }
+
+#if 0
+ VDEBUG (dev, "%s queue req %p, len %d buf %p\n",
+ _ep->name, _req, _req->length, _req->buf);
+#endif
+
+ spin_lock_irqsave (&dev->lock, flags);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+ req->dma_done = 0;
+
+ /* kickstart this i/o queue? */
+ if (list_empty (&ep->queue) && !ep->stopped) {
+ /* use DMA if the endpoint supports it, else pio */
+ if (ep->dma)
+ start_dma (ep, req);
+ else {
+ /* maybe there's no control data, just status ack */
+ if (ep->num == 0 && _req->length == 0)
+ goto done;
+
+ /* PIO ... stuff the fifo, or unblock it. */
+ if (ep->is_in)
+ write_fifo (ep, _req);
+ else if (list_empty (&ep->queue)) {
+ u32 s;
+
+ /* OUT FIFO might have packet(s) buffered */
+ s = readl (&ep->regs->ep_stat);
+ if ((s & (1 << FIFO_EMPTY)) == 0) {
+ /* note: _req->short_not_ok is
+ * ignored here since PIO _always_
+ * stops queue advance here, and
+ * _req->status doesn't change for
+ * short reads (only _req->actual)
+ */
+ if (read_fifo (ep, req)) {
+ done (ep, req, 0);
+ /* don't queue it */
+ req = 0;
+ } else
+ s = readl (&ep->regs->ep_stat);
+ }
+
+ /* don't NAK, let the fifo fill */
+ if (req && (s & (1 << NAK_OUT_PACKETS)))
+ writel ((1 << CLEAR_NAK_OUT_PACKETS),
+ &ep->regs->ep_rsp);
+ }
+ }
+
+ } else if (ep->dma) {
+ int valid = 1;
+
+ if (ep->is_in) {
+ int expect;
+
+ /* preventing magic zlps is per-engine state, not
+ * per-transfer; irq logic must recover hiccups.
+ */
+ expect = likely (req->req.zero
+ || (req->req.length % ep->ep.maxpacket) != 0);
+ if (expect != ep->in_fifo_validate)
+ valid = 0;
+ }
+ queue_dma (ep, req, valid);
+
+ } /* else the irq handler advances the queue. */
+
+ if (req) {
+done:
+ list_add_tail (&req->queue, &ep->queue);
+ }
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ /* pci writes may still be posted */
+ return 0;
+}
+
+static inline void
+dma_done (
+ struct net2280_ep *ep,
+ struct net2280_request *req,
+ u32 dmacount,
+ int status
+)
+{
+ req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount);
+ rmb ();
+ done (ep, req, status);
+}
+
+static void scan_dma_completions (struct net2280_ep *ep)
+{
+ /* only look at descriptors that were "naturally" retired,
+ * so fifo and list head state won't matter
+ */
+ while (!list_empty (&ep->queue)) {
+ struct net2280_request *req;
+ u32 tmp;
+
+ req = list_entry (ep->queue.next,
+ struct net2280_request, queue);
+ if (!req->valid)
+ break;
+ rmb ();
+ tmp = le32_to_cpup (&req->td->dmacount);
+ if ((tmp & (1 << VALID_BIT)) != 0)
+ break;
+
+ /* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
+ * packets, including overruns, even when the transfer was
+ * exactly the length requested (dmacount now zero).
+ */
+ if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) {
+ req->dma_done = 1;
+ break;
+ }
+ dma_done (ep, req, tmp, 0);
+ }
+}
+
+static void restart_dma (struct net2280_ep *ep)
+{
+ struct net2280_request *req;
+
+ if (ep->stopped)
+ return;
+ req = list_entry (ep->queue.next, struct net2280_request, queue);
+
+#ifdef USE_DMA_CHAINING
+ /* the 2280 will be processing the queue unless queue hiccups after
+ * the previous transfer:
+ * IN: wanted automagic zlp, head doesn't (or vice versa)
+ * OUT: was "usb-short", we must restart.
+ */
+ if (!req->valid) {
+ struct net2280_request *entry, *prev = 0;
+ int qmode, reqmode, done = 0;
+
+ DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
+ qmode = likely (req->req.zero
+ || (req->req.length % ep->ep.maxpacket) != 0);
+ list_for_each_entry (entry, &ep->queue, queue) {
+ u32 dmacount;
+
+ if (entry != req)
+ continue;
+ dmacount = entry->td->dmacount;
+ if (!done) {
+ reqmode = likely (entry->req.zero
+ || (entry->req.length
+ % ep->ep.maxpacket) != 0);
+ if (reqmode == qmode) {
+ entry->valid = 1;
+ dmacount |= valid_bit;
+ entry->td->dmacount = dmacount;
+ prev = entry;
+ continue;
+ } else {
+ prev->td->dmacount |= dma_done_ie;
+ done = 1;
+ }
+ }
+
+ /* walk the rest of the queue so unlinks behave */
+ entry->valid = 0;
+ dmacount &= ~valid_bit;
+ entry->td->dmacount = dmacount;
+ prev = entry;
+ }
+ start_dma (ep, req);
+ } else if (!ep->is_in
+ && (readl (&ep->regs->ep_stat)
+ & (1 << NAK_OUT_PACKETS)) != 0)
+ start_dma (ep, req);
+#else
+ start_dma (ep, req);
+#endif
+}
+
+static inline void abort_dma (struct net2280_ep *ep)
+{
+ /* abort the current transfer */
+ writel ((1 << DMA_ABORT), &ep->dma->dmastat);
+
+ /* collect completed transfers (except the current one) */
+ scan_dma_completions (ep);
+}
+
+/* dequeue ALL requests */
+static void nuke (struct net2280_ep *ep)
+{
+ struct net2280_request *req;
+
+ /* called with spinlock held */
+ ep->stopped = 1;
+ if (ep->dma)
+ abort_dma (ep);
+ while (!list_empty (&ep->queue)) {
+ req = list_entry (ep->queue.next,
+ struct net2280_request,
+ queue);
+ done (ep, req, -ESHUTDOWN);
+ }
+}
+
+/* dequeue JUST ONE request */
+static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct net2280_ep *ep;
+ struct net2280_request *req;
+ unsigned long flags;
+ u32 dmactl;
+ int stopped;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ req = container_of (_req, struct net2280_request, req);
+ if (!_ep || (!ep->desc && ep->num != 0) || !_req)
+ return -EINVAL;
+
+ spin_lock_irqsave (&ep->dev->lock, flags);
+ stopped = ep->stopped;
+
+ /* pause dma while we scan the queue */
+ dmactl = 0;
+ ep->stopped = 1;
+ if (ep->dma) {
+ dmactl = readl (&ep->dma->dmactl);
+ writel (dmactl & ~(1 << DMA_ENABLE), &ep->dma->dmactl);
+ /* force synch, clean any completed requests */
+ spin_stop_dma (ep->dma);
+ scan_dma_completions (ep);
+ }
+
+ /* queue head may be partially complete. */
+ if (ep->queue.next == &req->queue) {
+ if (ep->dma) {
+ DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name);
+ _req->status = -ECONNRESET;
+ abort_dma (ep);
+ if (likely (ep->queue.next == &req->queue))
+ dma_done (ep, req,
+ le32_to_cpup (&req->td->dmacount),
+ -ECONNRESET);
+ } else {
+ DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name);
+ done (ep, req, -ECONNRESET);
+ }
+ req = 0;
+
+#ifdef USE_DMA_CHAINING
+ /* patch up hardware chaining data */
+ } else if (ep->dma) {
+ if (req->queue.prev == ep->queue.next) {
+ writel (le32_to_cpu (req->td->dmadesc),
+ &ep->dma->dmadesc);
+ if (req->td->dmacount & dma_done_ie)
+ writel (readl (&ep->dma->dmacount)
+ | dma_done_ie,
+ &ep->dma->dmacount);
+ } else {
+ struct net2280_request *prev;
+
+ prev = list_entry (req->queue.prev,
+ struct net2280_request, queue);
+ prev->td->dmadesc = req->td->dmadesc;
+ if (req->td->dmacount & dma_done_ie)
+ prev->td->dmacount |= dma_done_ie;
+ }
+#endif
+ }
+
+ if (req)
+ done (ep, req, -ECONNRESET);
+ ep->stopped = stopped;
+
+ if (ep->dma) {
+ /* turn off dma on inactive queues */
+ if (list_empty (&ep->queue))
+ stop_dma (ep->dma);
+ else if (!ep->stopped) {
+ /* resume current request, or start new one */
+ if (req)
+ writel (dmactl, &ep->dma->dmactl);
+ else
+ start_dma (ep, list_entry (ep->queue.next,
+ struct net2280_request, queue));
+ }
+ }
+
+ spin_unlock_irqrestore (&ep->dev->lock, flags);
+ return req ? 0 : -EOPNOTSUPP;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_set_halt (struct usb_ep *_ep, int value)
+{
+ struct net2280_ep *ep;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || (!ep->desc && ep->num != 0))
+ return -EINVAL;
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+ if ((ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC)
+ return -EINVAL;
+
+ VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
+
+ /* set/clear, then synch memory views with the device */
+ if (value)
+ set_halt (ep);
+ else
+ clear_halt (ep);
+ (void) readl (&ep->regs->ep_rsp);
+
+ return 0;
+}
+
+static int
+net2280_fifo_status (struct usb_ep *_ep)
+{
+ struct net2280_ep *ep;
+ u32 avail;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || (!ep->desc && ep->num != 0))
+ return -EINVAL;
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ avail = readl (&ep->regs->ep_avail);
+ if (ep->is_in)
+ avail = ep->fifo_size - avail;
+ return avail;
+}
+
+static void
+net2280_fifo_flush (struct usb_ep *_ep)
+{
+ struct net2280_ep *ep;
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ if (!_ep || (!ep->desc && ep->num != 0))
+ return;
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return;
+
+ writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
+ (void) readl (&ep->regs->ep_rsp);
+}
+
+static struct usb_ep_ops net2280_ep_ops = {
+ .enable = net2280_enable,
+ .disable = net2280_disable,
+
+ .alloc_request = net2280_alloc_request,
+ .free_request = net2280_free_request,
+
+ .alloc_buffer = net2280_alloc_buffer,
+ .free_buffer = net2280_free_buffer,
+
+ .queue = net2280_queue,
+ .dequeue = net2280_dequeue,
+
+ .set_halt = net2280_set_halt,
+ .fifo_status = net2280_fifo_status,
+ .fifo_flush = net2280_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int net2280_get_frame (struct usb_gadget *_gadget)
+{
+ struct net2280 *dev;
+ unsigned long flags;
+ u16 retval;
+
+ if (!_gadget)
+ return -ENODEV;
+ dev = container_of (_gadget, struct net2280, gadget);
+ spin_lock_irqsave (&dev->lock, flags);
+ retval = get_idx_reg (dev->regs, REG_FRAME) & 0x03ff;
+ spin_unlock_irqrestore (&dev->lock, flags);
+ return retval;
+}
+
+static int net2280_wakeup (struct usb_gadget *_gadget)
+{
+ struct net2280 *dev;
+
+ if (!_gadget)
+ return 0;
+ dev = container_of (_gadget, struct net2280, gadget);
+ writel (1 << GENERATE_RESUME, dev->usb->usbstat);
+
+ /* pci writes may still be posted */
+ return 0;
+}
+
+static const struct usb_gadget_ops net2280_ops = {
+ .get_frame = net2280_get_frame,
+ .wakeup = net2280_wakeup,
+
+ // .set_selfpowered = net2280_set_selfpowered,
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef USE_SYSFS_DEBUG_FILES
+
+/* "function" sysfs attribute */
+static ssize_t
+show_function (struct device *_dev, char *buf)
+{
+ struct net2280 *dev = dev_get_drvdata (_dev);
+
+ if (!dev->driver
+ || !dev->driver->function
+ || strlen (dev->driver->function) > PAGE_SIZE)
+ return 0;
+ return snprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
+}
+static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+
+static ssize_t
+show_registers (struct device *_dev, char *buf)
+{
+ struct net2280 *dev;
+ char *next;
+ unsigned size, t;
+ unsigned long flags;
+ int i;
+ u32 t1, t2;
+ char *s;
+
+ dev = dev_get_drvdata (_dev);
+ next = buf;
+ size = PAGE_SIZE;
+ spin_lock_irqsave (&dev->lock, flags);
+
+ if (dev->driver)
+ s = dev->driver->driver.name;
+ else
+ s = "(none)";
+
+ /* Main Control Registers */
+ t = snprintf (next, size, "%s " DRIVER_VERSION "\n"
+ "devinit %03x fifoctl %08x gadget '%s'\n"
+ "pci irqenb0 %02x irqenb1 %08x "
+ "irqstat0 %04x irqstat1 %08x\n",
+ driver_name,
+ readl (&dev->regs->devinit),
+ readl (&dev->regs->fifoctl),
+ s,
+ readl (&dev->regs->pciirqenb0),
+ readl (&dev->regs->pciirqenb1),
+ readl (&dev->regs->irqstat0),
+ readl (&dev->regs->irqstat1));
+ size -= t;
+ next += t;
+
+ /* USB Control Registers */
+ t1 = readl (&dev->usb->usbctl);
+ t2 = readl (&dev->usb->usbstat);
+ if (t1 & (1 << VBUS_PIN)) {
+ if (t2 & (1 << HIGH_SPEED))
+ s = "high speed";
+ else if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+ s = "powered";
+ else
+ s = "full speed";
+ /* full speed bit (6) not working?? */
+ } else
+ s = "not attached";
+ t = snprintf (next, size,
+ "stdrsp %08x usbctl %08x usbstat %08x "
+ "addr 0x%02x (%s)\n",
+ readl (&dev->usb->stdrsp), t1, t2,
+ readl (&dev->usb->ouraddr), s);
+ size -= t;
+ next += t;
+
+ /* PCI Master Control Registers */
+
+ /* DMA Control Registers */
+
+ /* Configurable EP Control Registers */
+ for (i = 0; i < 7; i++) {
+ struct net2280_ep *ep;
+
+ ep = &dev->ep [i];
+ if (i && !ep->desc)
+ continue;
+
+ t1 = readl (&ep->regs->ep_cfg);
+ t = snprintf (next, size,
+ "%s\tcfg %05x rsp %02x enb %02x ",
+ ep->ep.name, t1,
+ readl (&ep->regs->ep_rsp) & 0xff,
+ readl (&ep->regs->ep_irqenb));
+ size -= t;
+ next += t;
+
+ t = snprintf (next, size,
+ "stat %08x avail %04x "
+ "(ep%d%s-%s)%s\n",
+ readl (&ep->regs->ep_stat),
+ readl (&ep->regs->ep_avail),
+ t1 & 0x0f, DIR_STRING (t1),
+ type_string (t1 >> 8),
+ ep->stopped ? "*" : "");
+ size -= t;
+ next += t;
+
+ if (!ep->dma)
+ continue;
+
+ t = snprintf (next, size,
+ " dma\tctl %08x stat %08x count %08x\n"
+ "\taddr %08x desc %08x\n",
+ readl (&ep->dma->dmactl),
+ readl (&ep->dma->dmastat),
+ readl (&ep->dma->dmacount),
+ readl (&ep->dma->dmaaddr),
+ readl (&ep->dma->dmadesc));
+ size -= t;
+ next += t;
+
+ }
+
+ /* Indexed Registers */
+ // none yet
+
+ /* Statistics */
+ t = snprintf (next, size, "irqs: ");
+ size -= t;
+ next += t;
+ for (i = 0; i < 7; i++) {
+ struct net2280_ep *ep;
+
+ ep = &dev->ep [i];
+ if (i && !ep->irqs)
+ continue;
+ t = snprintf (next, size, " %s/%ld", ep->ep.name, ep->irqs);
+ size -= t;
+ next += t;
+
+ }
+ t = snprintf (next, size, "\n");
+ size -= t;
+ next += t;
+
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+static ssize_t
+show_queues (struct device *_dev, char *buf)
+{
+ struct net2280 *dev;
+ char *next;
+ unsigned size;
+ unsigned long flags;
+ int i;
+
+ dev = dev_get_drvdata (_dev);
+ next = buf;
+ size = PAGE_SIZE;
+ spin_lock_irqsave (&dev->lock, flags);
+
+ for (i = 0; i < 7; i++) {
+ struct net2280_ep *ep = &dev->ep [i];
+ struct net2280_request *req;
+ int t;
+
+ if (i != 0) {
+ const struct usb_endpoint_descriptor *d;
+
+ d = ep->desc;
+ if (!d)
+ continue;
+ t = d->bEndpointAddress;
+ t = snprintf (next, size,
+ "%s (ep%d%s-%s) max %04x %s\n",
+ ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
+ (t & USB_DIR_IN) ? "in" : "out",
+ ({ char *val;
+ switch (d->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_BULK:
+ val = "bulk"; break;
+ case USB_ENDPOINT_XFER_INT:
+ val = "intr"; break;
+ default:
+ val = "iso"; break;
+ }; val; }),
+ le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
+ ep->dma ? "dma" : "pio"
+ );
+ } else /* ep0 should only have one transfer queued */
+ t = snprintf (next, size, "ep0 max 64 pio %s\n",
+ ep->is_in ? "in" : "out");
+ if (t <= 0 || t > size)
+ goto done;
+ size -= t;
+ next += t;
+
+ if (list_empty (&ep->queue)) {
+ t = snprintf (next, size, "\t(nothing queued)\n");
+ if (t <= 0 || t > size)
+ goto done;
+ size -= t;
+ next += t;
+ continue;
+ }
+ list_for_each_entry (req, &ep->queue, queue) {
+ if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc))
+ t = snprintf (next, size,
+ "\treq %p len %d/%d "
+ "buf %p (dmacount %08x)\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf,
+ readl (&ep->dma->dmacount));
+ else
+ t = snprintf (next, size,
+ "\treq %p len %d/%d buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ if (t <= 0 || t > size)
+ goto done;
+ size -= t;
+ next += t;
+ }
+ }
+
+done:
+ spin_unlock_irqrestore (&dev->lock, flags);
+ return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
+
+
+#else
+
+#define device_create_file(a,b) do {} while (0)
+#define device_remove_file device_create_file
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* another driver-specific mode might be a request type doing dma
+ * to/from another device fifo instead of to/from memory.
+ */
+
+static void set_fifo_mode (struct net2280 *dev, int mode)
+{
+ /* keeping high bits preserves BAR2 */
+ writel ((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl);
+
+ /* always ep-{a,b,e,f} ... maybe not ep-c or ep-d */
+ INIT_LIST_HEAD (&dev->gadget.ep_list);
+ list_add_tail (&dev->ep [1].ep.ep_list, &dev->gadget.ep_list);
+ list_add_tail (&dev->ep [2].ep.ep_list, &dev->gadget.ep_list);
+ switch (mode) {
+ case 0:
+ list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list);
+ list_add_tail (&dev->ep [4].ep.ep_list, &dev->gadget.ep_list);
+ dev->ep [1].fifo_size = dev->ep [2].fifo_size = 1024;
+ break;
+ case 1:
+ dev->ep [1].fifo_size = dev->ep [2].fifo_size = 2048;
+ break;
+ case 2:
+ list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list);
+ dev->ep [1].fifo_size = 2048;
+ dev->ep [2].fifo_size = 1024;
+ break;
+ }
+ /* fifo sizes for ep0, ep-c, ep-d, ep-e, and ep-f never change */
+ list_add_tail (&dev->ep [5].ep.ep_list, &dev->gadget.ep_list);
+ list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
+}
+
+/**
+ * net2280_set_fifo_mode - change allocation of fifo buffers
+ * @gadget: access to the net2280 device that will be updated
+ * @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
+ * 1 for two 2kB buffers (ep-a and ep-b only);
+ * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
+ *
+ * returns zero on success, else negative errno. when this succeeds,
+ * the contents of gadget->ep_list may have changed.
+ *
+ * you may only call this function when endpoints a-d are all disabled.
+ * use it whenever extra hardware buffering can help performance, such
+ * as before enabling "high bandwidth" interrupt endpoints that use
+ * maxpacket bigger than 512 (when double buffering would otherwise
+ * be unavailable).
+ */
+int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
+{
+ int i;
+ struct net2280 *dev;
+ int status = 0;
+ unsigned long flags;
+
+ if (!gadget)
+ return -ENODEV;
+ dev = container_of (gadget, struct net2280, gadget);
+
+ spin_lock_irqsave (&dev->lock, flags);
+
+ for (i = 1; i <= 4; i++)
+ if (dev->ep [i].desc) {
+ status = -EINVAL;
+ break;
+ }
+ if (mode < 0 || mode > 2)
+ status = -EINVAL;
+ if (status == 0)
+ set_fifo_mode (dev, mode);
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ if (status == 0) {
+ if (mode == 1)
+ DEBUG (dev, "fifo: ep-a 2K, ep-b 2K\n");
+ else if (mode == 2)
+ DEBUG (dev, "fifo: ep-a 2K, ep-b 1K, ep-c 1K\n");
+ /* else all are 1K */
+ }
+ return status;
+}
+EXPORT_SYMBOL (net2280_set_fifo_mode);
+
+/*-------------------------------------------------------------------------*/
+
+/* keeping it simple:
+ * - one bus driver, initted first;
+ * - one function driver, initted second
+ *
+ * most of the work to support multiple net2280 controllers would
+ * be to associate this gadget driver (yes?) with all of them, or
+ * perhaps to bind specific drivers to specific devices.
+ */
+
+static struct net2280 *the_controller;
+
+static void usb_reset (struct net2280 *dev)
+{
+ u32 tmp;
+
+ /* force immediate bus disconnect, and synch through pci */
+ writel (0, &dev->usb->usbctl);
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+ (void) readl (&dev->usb->usbctl);
+
+ net2280_led_init (dev);
+
+ /* disable automatic responses, and irqs */
+ writel (0, &dev->usb->stdrsp);
+ writel (0, &dev->regs->pciirqenb0);
+ writel (0, &dev->regs->pciirqenb1);
+
+ /* clear old dma and irq state */
+ for (tmp = 0; tmp < 4; tmp++) {
+ writel ((1 << DMA_ABORT), &dev->dma [tmp].dmastat);
+ stop_dma (&dev->dma [tmp]);
+ }
+ writel (~0, &dev->regs->irqstat0),
+ writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1),
+
+ /* reset, and enable pci */
+ tmp = readl (&dev->regs->devinit)
+ | (1 << PCI_ENABLE)
+ | (1 << FIFO_SOFT_RESET)
+ | (1 << USB_SOFT_RESET)
+ | (1 << M8051_RESET);
+ writel (tmp, &dev->regs->devinit);
+
+ /* standard fifo and endpoint allocations */
+ set_fifo_mode (dev, 0);
+}
+
+static void usb_reinit (struct net2280 *dev)
+{
+ u32 tmp;
+ int init_dma;
+
+ /* use_dma changes are ignored till next device re-init */
+ init_dma = use_dma;
+
+ /* basic endpoint init */
+ for (tmp = 0; tmp < 7; tmp++) {
+ struct net2280_ep *ep = &dev->ep [tmp];
+
+ ep->ep.name = ep_name [tmp];
+ ep->dev = dev;
+ ep->num = tmp;
+
+ if (tmp > 0 && tmp <= 4) {
+ ep->fifo_size = 1024;
+ if (init_dma)
+ ep->dma = &dev->dma [tmp - 1];
+ } else
+ ep->fifo_size = 64;
+ ep->regs = &dev->epregs [tmp];
+ ep_reset (dev->regs, ep);
+ }
+ dev->ep [0].ep.maxpacket = 64;
+ dev->ep [5].ep.maxpacket = 64;
+ dev->ep [6].ep.maxpacket = 64;
+
+ dev->gadget.ep0 = &dev->ep [0].ep;
+ dev->ep [0].stopped = 0;
+ INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+
+ /* we want to prevent lowlevel/insecure access from the USB host,
+ * but erratum 0119 means this enable bit is ignored
+ */
+ for (tmp = 0; tmp < 5; tmp++)
+ writel (EP_DONTUSE, &dev->dep [tmp].dep_cfg);
+}
+
+static void ep0_start (struct net2280 *dev)
+{
+ writel ( (1 << SET_EP_HIDE_STATUS_PHASE)
+ | (1 << CLEAR_NAK_OUT_PACKETS)
+ | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+ , &dev->epregs [0].ep_rsp);
+
+ /*
+ * hardware optionally handles a bunch of standard requests
+ * that the API hides from drivers anyway. have it do so.
+ * endpoint status/features are handled in software, to
+ * help pass tests for some dubious behavior.
+ */
+ writel ( (1 << SET_TEST_MODE)
+ | (1 << SET_ADDRESS)
+ | (1 << DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP)
+ | (1 << GET_DEVICE_STATUS)
+ | (1 << GET_INTERFACE_STATUS)
+ , &dev->usb->stdrsp);
+ writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE)
+ | (1 << SELF_POWERED_USB_DEVICE)
+ | (1 << REMOTE_WAKEUP_SUPPORT)
+ | (1 << USB_DETECT_ENABLE)
+ | (1 << DEVICE_REMOTE_WAKEUP_ENABLE)
+ , &dev->usb->usbctl);
+
+ /* enable irqs so we can see ep0 and general operation */
+ writel ( (1 << SETUP_PACKET_INTERRUPT_ENABLE)
+ | (1 << ENDPOINT_0_INTERRUPT_ENABLE)
+ , &dev->regs->pciirqenb0);
+ writel ( (1 << PCI_INTERRUPT_ENABLE)
+ | (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE)
+ | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE)
+ | (1 << PCI_RETRY_ABORT_INTERRUPT_ENABLE)
+ | (1 << VBUS_INTERRUPT_ENABLE)
+ | (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE)
+ , &dev->regs->pciirqenb1);
+
+ /* don't leave any writes posted */
+ (void) readl (&dev->usb->usbctl);
+}
+
+/* when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests. then usb traffic follows until a
+ * disconnect is reported. then a host may connect again, or
+ * the driver might get unbound.
+ */
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+ struct net2280 *dev = the_controller;
+ int retval;
+ unsigned i;
+
+ /* insist on high speed support from the driver, since
+ * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
+ * "must not be used in normal operation"
+ */
+ if (!driver
+ || driver->speed != USB_SPEED_HIGH
+ || !driver->bind
+ || !driver->unbind
+ || !driver->setup)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+ for (i = 0; i < 7; i++)
+ dev->ep [i].irqs = 0;
+
+ /* hook up the driver ... */
+ dev->driver = driver;
+ dev->gadget.dev.driver = &driver->driver;
+ retval = driver->bind (&dev->gadget);
+ if (retval) {
+ DEBUG (dev, "bind to driver %s --> %d\n",
+ driver->driver.name, retval);
+ dev->driver = 0;
+ dev->gadget.dev.driver = 0;
+ return retval;
+ }
+
+ // FIXME
+ // driver_register (&driver->driver);
+ // device_register (&dev->gadget.dev);
+
+ device_create_file (&dev->pdev->dev, &dev_attr_function);
+ device_create_file (&dev->pdev->dev, &dev_attr_queues);
+
+ /* ... then enable host detection and ep0; and we're ready
+ * for set_configuration as well as eventual disconnect.
+ */
+ net2280_led_active (dev, 1);
+ ep0_start (dev);
+
+ DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n",
+ driver->driver.name,
+ readl (&dev->usb->usbctl),
+ readl (&dev->usb->stdrsp));
+
+ /* pci writes may still be posted */
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+static void
+stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
+{
+ int i;
+
+ /* don't disconnect if it's not connected */
+ if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = 0;
+
+ /* stop hardware; prevent new request submissions;
+ * and kill any outstanding requests.
+ */
+ usb_reset (dev);
+ for (i = 0; i < 7; i++)
+ nuke (&dev->ep [i]);
+
+ /* report disconnect; the driver is already quiesced */
+ if (driver) {
+ spin_unlock (&dev->lock);
+ driver->disconnect (&dev->gadget);
+ spin_lock (&dev->lock);
+ }
+
+ usb_reinit (dev);
+}
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+ struct net2280 *dev = the_controller;
+ unsigned long flags;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver)
+ return -EINVAL;
+
+ spin_lock_irqsave (&dev->lock, flags);
+ stop_activity (dev, driver);
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ driver->unbind (&dev->gadget);
+ dev->driver = 0;
+
+ net2280_led_active (dev, 0);
+ device_remove_file (&dev->pdev->dev, &dev_attr_function);
+ device_remove_file (&dev->pdev->dev, &dev_attr_queues);
+
+ // FIXME
+ // device_unregister()
+ // driver_unregister (&driver->driver);
+
+ DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+
+/*-------------------------------------------------------------------------*/
+
+/* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq.
+ * also works for dma-capable endpoints, in pio mode or just
+ * to manually advance the queue after short OUT transfers.
+ */
+static void handle_ep_small (struct net2280_ep *ep)
+{
+ struct net2280_request *req;
+ u32 t;
+ /* 0 error, 1 mid-data, 2 done */
+ int mode = 1;
+
+ if (!list_empty (&ep->queue))
+ req = list_entry (ep->queue.next,
+ struct net2280_request, queue);
+ else
+ req = 0;
+
+ /* ack all, and handle what we care about */
+ t = readl (&ep->regs->ep_stat);
+ ep->irqs++;
+#if 0
+ VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n",
+ ep->ep.name, t, req ? &req->req : 0);
+#endif
+ writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat);
+
+ /* for ep0, monitor token irqs to catch data stage length errors
+ * and to synchronize on status.
+ *
+ * also, to defer reporting of protocol stalls ... here's where
+ * data or status first appears, handling stalls here should never
+ * cause trouble on the host side..
+ *
+ * control requests could be slightly faster without token synch for
+ * status, but status can jam up that way.
+ */
+ if (unlikely (ep->num == 0)) {
+ if (ep->is_in) {
+ /* status; stop NAKing */
+ if (t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) {
+ if (ep->dev->protocol_stall)
+ set_halt (ep);
+ mode = 2;
+ /* reply to extra IN tokens with a zlp */
+ } else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) {
+ if (ep->dev->protocol_stall) {
+ set_halt (ep);
+ mode = 2;
+ } else if (!req)
+ write_fifo (ep, 0);
+ }
+ } else {
+ /* status; stop NAKing */
+ if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) {
+ if (ep->dev->protocol_stall)
+ set_halt (ep);
+ mode = 2;
+ /* an extra OUT token is an error */
+ } else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT))
+ && req
+ && req->req.actual == req->req.length)
+ || !req) {
+ ep->dev->protocol_stall = 1;
+ set_halt (ep);
+ ep->stopped = 1;
+ if (req)
+ done (ep, req, -EOVERFLOW);
+ req = 0;
+ }
+ }
+ }
+
+ if (unlikely (!req))
+ return;
+
+ /* manual DMA queue advance after short OUT */
+ if (likely (ep->dma != 0)) {
+ if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
+ u32 count;
+
+ /* TRANSFERRED works around OUT_DONE erratum 0112.
+ * we expect (N <= maxpacket) bytes; host wrote M.
+ * iff (M < N) we won't ever see a DMA interrupt.
+ */
+ count = readl (&ep->dma->dmacount);
+ count &= DMA_BYTE_COUNT_MASK;
+ if (!req->dma_done) {
+ /* dma can finish with the FIFO non-empty,
+ * on (M > N) errors.
+ */
+ while (count && (t & (1 << FIFO_EMPTY)) == 0) {
+ cpu_relax ();
+ t = readl (&ep->regs->ep_stat);
+ count = readl (&ep->dma->dmacount);
+ count &= DMA_BYTE_COUNT_MASK;
+ }
+ }
+
+ /* stop DMA, leave ep NAKing */
+ writel ((1 << DMA_ABORT), &ep->dma->dmastat);
+ spin_stop_dma (ep->dma);
+
+ /* buffer might have been too small */
+ t = readl (&ep->regs->ep_avail);
+ if (t != 0)
+ DEBUG (ep->dev, "%s dma, discard %d len %d\n",
+ ep->ep.name, t, count);
+ dma_done (ep, req, count, t ? -EOVERFLOW : 0);
+
+ /* also flush to prevent erratum 0106 trouble */
+ if (t || ep->dev->chiprev == 0x0100)
+ out_flush (ep);
+
+ /* restart dma (still NAKing OUT!) if needed */
+ if (!list_empty (&ep->queue))
+ restart_dma (ep);
+ } else
+ DEBUG (ep->dev, "%s dma ep_stat %08x ??\n",
+ ep->ep.name, t);
+ return;
+
+ /* data packet(s) received (in the fifo, OUT) */
+ } else if (t & (1 << DATA_PACKET_RECEIVED_INTERRUPT)) {
+ if (read_fifo (ep, req) && ep->num != 0)
+ mode = 2;
+
+ /* data packet(s) transmitted (IN) */
+ } else if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) {
+ unsigned len;
+
+ len = req->req.length - req->req.actual;
+ len = min (ep->ep.maxpacket, len);
+ req->req.actual += len;
+
+ /* if we wrote it all, we're usually done */
+ if (req->req.actual == req->req.length) {
+ if (ep->num == 0) {
+ /* wait for control status */
+ if (mode != 2)
+ req = 0;
+ } else if (!req->req.zero || len != ep->ep.maxpacket)
+ mode = 2;
+ }
+
+ /* there was nothing to do ... */
+ } else if (mode == 1)
+ return;
+
+ /* done */
+ if (mode == 2) {
+ /* stream endpoints often resubmit/unlink in completion */
+ done (ep, req, 0);
+
+ /* maybe advance queue to next request */
+ if (ep->num == 0) {
+ allow_status (ep);
+ req = 0;
+ } else {
+ if (!list_empty (&ep->queue) && !ep->stopped)
+ req = list_entry (ep->queue.next,
+ struct net2280_request, queue);
+ else
+ req = 0;
+ if (req && !ep->is_in)
+ stop_out_naking (ep);
+ }
+ }
+
+ /* is there a buffer for the next packet?
+ * for best streaming performance, make sure there is one.
+ */
+ if (req && !ep->stopped) {
+
+ /* load IN fifo with next packet (may be zlp) */
+ if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))
+ write_fifo (ep, &req->req);
+ }
+}
+
+static struct net2280_ep *
+get_ep_by_addr (struct net2280 *dev, u16 wIndex)
+{
+ struct net2280_ep *ep;
+
+ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+ return &dev->ep [0];
+ list_for_each_entry (ep, &dev->gadget.ep_list, ep.ep_list) {
+ u8 bEndpointAddress;
+
+ if (!ep->desc)
+ continue;
+ bEndpointAddress = ep->desc->bEndpointAddress;
+ if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+ continue;
+ if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f))
+ return ep;
+ }
+ return 0;
+}
+
+static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
+{
+ struct net2280_ep *ep;
+ u32 num, scratch;
+
+ /* most of these don't need individual acks */
+ stat &= ~(1 << INTA_ASSERTED);
+ if (!stat)
+ return;
+ // DEBUG (dev, "irqstat0 %04x\n", stat);
+
+ /* starting a control request? */
+ if (unlikely (stat & (1 << SETUP_PACKET_INTERRUPT))) {
+ union {
+ u32 raw [2];
+ struct usb_ctrlrequest r;
+ } u;
+ int tmp = 0;
+ struct net2280_request *req;
+
+ if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
+ if (readl (&dev->usb->usbstat) & (1 << HIGH_SPEED))
+ dev->gadget.speed = USB_SPEED_HIGH;
+ else
+ dev->gadget.speed = USB_SPEED_FULL;
+ net2280_led_speed (dev, dev->gadget.speed);
+ DEBUG (dev, "%s speed\n",
+ (dev->gadget.speed == USB_SPEED_HIGH)
+ ? "high" : "full");
+ }
+
+ ep = &dev->ep [0];
+ ep->irqs++;
+
+ /* make sure any leftover request state is cleared */
+ stat &= ~(1 << ENDPOINT_0_INTERRUPT);
+ while (!list_empty (&ep->queue)) {
+ req = list_entry (ep->queue.next,
+ struct net2280_request, queue);
+ done (ep, req, (req->req.actual == req->req.length)
+ ? 0 : -EPROTO);
+ }
+ ep->stopped = 0;
+ dev->protocol_stall = 0;
+ writel ( (1 << TIMEOUT)
+ | (1 << USB_STALL_SENT)
+ | (1 << USB_IN_NAK_SENT)
+ | (1 << USB_IN_ACK_RCVD)
+ | (1 << USB_OUT_PING_NAK_SENT)
+ | (1 << USB_OUT_ACK_SENT)
+ | (1 << FIFO_OVERFLOW)
+ | (1 << FIFO_UNDERFLOW)
+ | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
+ | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
+ | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+ | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+ | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ | (1 << DATA_IN_TOKEN_INTERRUPT)
+ , &ep->regs->ep_stat);
+ u.raw [0] = readl (&dev->usb->setup0123);
+ u.raw [1] = readl (&dev->usb->setup4567);
+ le16_to_cpus (&u.r.wValue);
+ le16_to_cpus (&u.r.wIndex);
+ le16_to_cpus (&u.r.wLength);
+
+ /* ack the irq */
+ writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
+ stat ^= (1 << SETUP_PACKET_INTERRUPT);
+
+ /* watch control traffic at the token level, and force
+ * synchronization before letting the status stage happen.
+ */
+ ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
+ if (ep->is_in)
+ scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+ | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ | (1 << DATA_IN_TOKEN_INTERRUPT);
+ else
+ scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+ | (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+ | (1 << DATA_IN_TOKEN_INTERRUPT);
+ writel (scratch, &dev->epregs [0].ep_irqenb);
+
+ /* we made the hardware handle most lowlevel requests;
+ * everything else goes uplevel to the gadget code.
+ */
+ switch (u.r.bRequest) {
+ case USB_REQ_GET_STATUS: {
+ struct net2280_ep *e;
+ u16 status;
+
+ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
+ goto delegate;
+ if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0
+ || u.r.wLength > 2)
+ goto do_stall;
+
+ if (readl (&e->regs->ep_rsp)
+ & (1 << SET_ENDPOINT_HALT))
+ status = cpu_to_le16 (1);
+ else
+ status = cpu_to_le16 (0);
+
+ /* don't bother with a request object! */
+ writel (0, &dev->epregs [0].ep_irqenb);
+ set_fifo_bytecount (ep, u.r.wLength);
+ writel (status, &dev->epregs [0].ep_data);
+ allow_status (ep);
+ goto next_endpoints;
+ }
+ break;
+ case USB_REQ_CLEAR_FEATURE: {
+ struct net2280_ep *e;
+
+ if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+ goto delegate;
+ if (u.r.wIndex != 0 /* HALT feature */
+ || u.r.wLength != 0)
+ goto do_stall;
+ if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+ goto do_stall;
+ clear_halt (e);
+ }
+ break;
+ case USB_REQ_SET_FEATURE: {
+ struct net2280_ep *e;
+
+ if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+ goto delegate;
+ if (u.r.wIndex != 0 /* HALT feature */
+ || u.r.wLength != 0)
+ goto do_stall;
+ if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+ goto do_stall;
+ set_halt (e);
+ }
+ break;
+ default:
+delegate:
+ VDEBUG (dev, "setup %02x.%02x v%04x i%04x "
+ "ep_cfg %08x\n",
+ u.r.bRequestType, u.r.bRequest,
+ u.r.wValue, u.r.wIndex,
+ readl (&ep->regs->ep_cfg));
+ spin_unlock (&dev->lock);
+ tmp = dev->driver->setup (&dev->gadget, &u.r);
+ spin_lock (&dev->lock);
+ }
+
+ /* stall ep0 on error */
+ if (tmp < 0) {
+do_stall:
+ VDEBUG (dev, "req %02x.%02x protocol STALL; stat %d\n",
+ u.r.bRequestType, u.r.bRequest, tmp);
+ dev->protocol_stall = 1;
+
+ /* when there's no data, queueing a response is optional */
+ } else if (list_empty (&ep->queue)) {
+ if (u.r.wLength == 0) {
+ /* done() not possible/requested */
+ allow_status (ep);
+ } else {
+ DEBUG (dev, "req %02x.%02x v%04x "
+ "gadget error, len %d, stat %d\n",
+ u.r.bRequestType, u.r.bRequest,
+ le16_to_cpu (u.r.wValue),
+ u.r.wLength, tmp);
+ dev->protocol_stall = 1;
+ }
+ }
+
+ /* some in/out token irq should follow; maybe stall then. */
+ }
+
+next_endpoints:
+ /* endpoint data irq ? */
+ scratch = stat & 0x7f;
+ stat &= ~0x7f;
+ for (num = 0; scratch; num++) {
+ u32 t;
+
+ /* do this endpoint's FIFO and queue need tending? */
+ t = 1 << num;
+ if ((scratch & t) == 0)
+ continue;
+ scratch ^= t;
+
+ ep = &dev->ep [num];
+ handle_ep_small (ep);
+ }
+
+ if (stat)
+ DEBUG (dev, "unhandled irqstat0 %08x\n", stat);
+}
+
+#define DMA_INTERRUPTS ( \
+ (1 << DMA_D_INTERRUPT) \
+ | (1 << DMA_C_INTERRUPT) \
+ | (1 << DMA_B_INTERRUPT) \
+ | (1 << DMA_A_INTERRUPT))
+#define PCI_ERROR_INTERRUPTS ( \
+ (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT) \
+ | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT) \
+ | (1 << PCI_RETRY_ABORT_INTERRUPT))
+
+static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
+{
+ struct net2280_ep *ep;
+ u32 tmp, num, scratch;
+
+ /* after disconnect there's nothing else to do! */
+ tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT);
+ if (stat & tmp) {
+ writel (tmp, &dev->regs->irqstat1);
+ if (((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) != 0
+ || (readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0
+ ) && dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ DEBUG (dev, "disconnect %s\n",
+ dev->driver->driver.name);
+ stop_activity (dev, dev->driver);
+ ep0_start (dev);
+ return;
+ }
+ stat &= ~tmp;
+
+ /* vBUS can bounce ... one of many reasons to ignore the
+ * notion of hotplug events on bus connect/disconnect!
+ */
+ if (!stat)
+ return;
+ }
+
+ /* NOTE: we don't actually suspend the hardware; that starts to
+ * interact with PCI power management, and needs something like a
+ * controller->suspend() call to clear SUSPEND_REQUEST_INTERRUPT.
+ * we shouldn't see resume interrupts.
+ * for rev 0100, this also avoids erratum 0102.
+ */
+ tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT);
+ if (stat & tmp) {
+ if (dev->driver->suspend)
+ dev->driver->suspend (&dev->gadget);
+ stat &= ~tmp;
+ }
+ stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
+
+ /* clear any other status/irqs */
+ if (stat)
+ writel (stat, &dev->regs->irqstat1);
+
+ /* some status we can just ignore */
+ stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+ | (1 << RESUME_INTERRUPT)
+ | (1 << SOF_INTERRUPT));
+ if (!stat)
+ return;
+ // DEBUG (dev, "irqstat1 %08x\n", stat);
+
+ /* DMA status, for ep-{a,b,c,d} */
+ scratch = stat & DMA_INTERRUPTS;
+ stat &= ~DMA_INTERRUPTS;
+ scratch >>= 9;
+ for (num = 0; scratch; num++) {
+ struct net2280_dma_regs *dma;
+
+ tmp = 1 << num;
+ if ((tmp & scratch) == 0)
+ continue;
+ scratch ^= tmp;
+
+ ep = &dev->ep [num + 1];
+ dma = ep->dma;
+
+ if (!dma)
+ continue;
+
+ /* clear ep's dma status */
+ tmp = readl (&dma->dmastat);
+ writel (tmp, &dma->dmastat);
+
+#ifdef USE_DMA_CHAINING
+ /* chaining should stop only on error (which?)
+ * or (stat0 codepath) short OUT transfer.
+ */
+#else
+ if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) == 0) {
+ DEBUG (ep->dev, "%s no xact done? %08x\n",
+ ep->ep.name, tmp);
+ continue;
+ }
+ stop_dma (ep->dma);
+#endif
+
+ /* OUT transfers terminate when the data from the
+ * host is in our memory. Process whatever's done.
+ * On this path, we know transfer's last packet wasn't
+ * less than req->length. NAK_OUT_PACKETS may be set,
+ * or the FIFO may already be holding new packets.
+ *
+ * IN transfers can linger in the FIFO for a very
+ * long time ... we ignore that for now, accounting
+ * precisely (like PIO does) needs per-packet irqs
+ */
+ scan_dma_completions (ep);
+
+ /* disable dma on inactive queues; else maybe restart */
+ if (list_empty (&ep->queue)) {
+#ifdef USE_DMA_CHAINING
+ stop_dma (ep->dma);
+#endif
+ } else {
+ tmp = readl (&dma->dmactl);
+ if ((tmp & (1 << DMA_SCATTER_GATHER_ENABLE)) == 0
+ || (tmp & (1 << DMA_ENABLE)) == 0)
+ restart_dma (ep);
+ }
+ ep->irqs++;
+ }
+
+ /* NOTE: there are other PCI errors we might usefully notice.
+ * if they appear very often, here's where to try recovering.
+ */
+ if (stat & PCI_ERROR_INTERRUPTS) {
+ ERROR (dev, "pci dma error; stat %08x\n", stat);
+ stat &= ~PCI_ERROR_INTERRUPTS;
+ /* these are fatal errors, but "maybe" they won't
+ * happen again ...
+ */
+ stop_activity (dev, dev->driver);
+ ep0_start (dev);
+ stat = 0;
+ }
+
+ if (stat)
+ DEBUG (dev, "unhandled irqstat1 %08x\n", stat);
+}
+
+static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r)
+{
+ struct net2280 *dev = _dev;
+
+ spin_lock (&dev->lock);
+
+ /* handle disconnect, dma, and more */
+ handle_stat1_irqs (dev, readl (&dev->regs->irqstat1));
+
+ /* control requests and PIO */
+ handle_stat0_irqs (dev, readl (&dev->regs->irqstat0));
+
+ spin_unlock (&dev->lock);
+
+ return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* tear down the binding between this driver and the pci device */
+
+static void net2280_remove (struct pci_dev *pdev)
+{
+ struct net2280 *dev = pci_get_drvdata (pdev);
+
+ /* start with the driver above us */
+ if (dev->driver) {
+ /* should have been done already by driver model core */
+ WARN (dev, "pci remove, driver '%s' is still registered\n",
+ dev->driver->driver.name);
+ usb_gadget_unregister_driver (dev->driver);
+ }
+
+ /* then clean up the resources we allocated during probe() */
+ net2280_led_shutdown (dev);
+ if (dev->requests) {
+ int i;
+ for (i = 1; i < 5; i++) {
+ if (!dev->ep [i].dummy)
+ continue;
+ pci_pool_free (dev->requests, dev->ep [i].dummy,
+ dev->ep [i].td_dma);
+ }
+ pci_pool_destroy (dev->requests);
+ }
+ if (dev->got_irq)
+ free_irq (pdev->irq, dev);
+ if (dev->regs)
+ iounmap (dev->regs);
+ if (dev->region)
+ release_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+ if (dev->enabled)
+ pci_disable_device (pdev);
+ device_remove_file (&pdev->dev, &dev_attr_registers);
+ pci_set_drvdata (pdev, 0);
+
+ INFO (dev, "unbind from pci %s\n", pdev->slot_name);
+
+ kfree (dev);
+ the_controller = 0;
+}
+
+/* wrap this driver around the specified device, but
+ * don't respond over USB until a gadget driver binds to us.
+ */
+
+static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct net2280 *dev;
+ unsigned long resource, len;
+ void *base = 0;
+ int retval, i;
+ char buf [8], *bufp;
+
+ /* if you want to support more than one controller in a system,
+ * usb_gadget_driver_{register,unregister}() must change.
+ */
+ if (the_controller) {
+ WARN (the_controller, "ignoring %s\n", pdev->slot_name);
+ return -EBUSY;
+ }
+
+ /* alloc, and start init */
+ dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+ if (dev == NULL){
+ retval = -ENOMEM;
+ goto done;
+ }
+
+ memset (dev, 0, sizeof *dev);
+ spin_lock_init (&dev->lock);
+ dev->pdev = pdev;
+ dev->gadget.ops = &net2280_ops;
+
+ strcpy (dev->gadget.dev.bus_id, pdev->slot_name);
+ strcpy (dev->gadget.dev.name, pdev->dev.name);
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ dev->gadget.name = driver_name;
+
+ /* now all the pci goodies ... */
+ if (pci_enable_device (pdev) < 0) {
+ retval = -ENODEV;
+ goto done;
+ }
+ dev->enabled = 1;
+
+ /* BAR 0 holds all the registers
+ * BAR 1 is 8051 memory; unused here (note erratum 0103)
+ * BAR 2 is fifo memory; unused here
+ */
+ resource = pci_resource_start (pdev, 0);
+ len = pci_resource_len (pdev, 0);
+ if (!request_mem_region (resource, len, driver_name)) {
+ DEBUG (dev, "controller already in use\n");
+ retval = -EBUSY;
+ goto done;
+ }
+ dev->region = 1;
+
+ base = ioremap_nocache (resource, len);
+ if (base == NULL) {
+ DEBUG (dev, "can't map memory\n");
+ retval = -EFAULT;
+ goto done;
+ }
+ dev->regs = (struct net2280_regs *) base;
+ dev->usb = (struct net2280_usb_regs *) (base + 0x0080);
+ dev->pci = (struct net2280_pci_regs *) (base + 0x0100);
+ dev->dma = (struct net2280_dma_regs *) (base + 0x0180);
+ dev->dep = (struct net2280_dep_regs *) (base + 0x0200);
+ dev->epregs = (struct net2280_ep_regs *) (base + 0x0300);
+
+ /* put into initial config, link up all endpoints */
+ usb_reset (dev);
+ usb_reinit (dev);
+
+ /* irq setup after old hardware is cleaned up */
+ if (!pdev->irq) {
+ ERROR (dev, "No IRQ. Check PCI setup!\n");
+ retval = -ENODEV;
+ goto done;
+ }
+#ifndef __sparc__
+ snprintf (buf, sizeof buf, "%d", pdev->irq);
+ bufp = buf;
+#else
+ bufp = __irq_itoa(pdev->irq);
+#endif
+ if (request_irq (pdev->irq, net2280_irq, SA_SHIRQ, driver_name, dev)
+ != 0) {
+ ERROR (dev, "request interrupt %s failed\n", bufp);
+ retval = -EBUSY;
+ goto done;
+ }
+ dev->got_irq = 1;
+
+ /* DMA setup */
+ dev->requests = pci_pool_create ("requests", pdev,
+ sizeof (struct net2280_dma),
+ 0 /* no alignment requirements */,
+ 0 /* or page-crossing issues */);
+ if (!dev->requests) {
+ DEBUG (dev, "can't get request pool\n");
+ retval = -ENOMEM;
+ goto done;
+ }
+ for (i = 1; i < 5; i++) {
+ struct net2280_dma *td;
+
+ td = pci_pool_alloc (dev->requests, GFP_KERNEL,
+ &dev->ep [i].td_dma);
+ if (!td) {
+ DEBUG (dev, "can't get dummy %d\n", i);
+ retval = -ENOMEM;
+ goto done;
+ }
+ td->dmacount = 0; /* not VALID */
+ td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID);
+ dev->ep [i].dummy = td;
+ }
+
+ /* enable lower-overhead pci memory bursts during DMA */
+ writel ((1 << PCI_RETRY_ABORT_ENABLE)
+ | (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE)
+ | (1 << DMA_READ_MULTIPLE_ENABLE)
+ | (1 << DMA_READ_LINE_ENABLE)
+ , &dev->pci->pcimstctl);
+ /* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */
+ pci_set_master (pdev);
+ pci_set_mwi (pdev);
+
+ /* ... also flushes any posted pci writes */
+ dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
+
+ /* done */
+ pci_set_drvdata (pdev, dev);
+ INFO (dev, "%s\n", driver_desc);
+ INFO (dev, "irq %s, pci mem %p, chip rev %04x\n",
+ bufp, base, dev->chiprev);
+ bufp = DRIVER_VERSION
+#ifndef USE_DMA_CHAINING
+ " (no dma chain)"
+#endif
+#ifdef NET2280_DMA_OUT_WORKAROUND
+ " (no dma out)"
+#endif
+ ;
+ INFO (dev, "version: %s\n", bufp);
+ the_controller = dev;
+
+ device_create_file (&pdev->dev, &dev_attr_registers);
+
+ return 0;
+
+done:
+ if (dev)
+ net2280_remove (pdev);
+ return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class_mask = ~0,
+ .vendor = 0x17cc,
+ .device = 0x2280,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+
+}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver net2280_pci_driver = {
+ .name = (char *) driver_name,
+ .id_table = pci_ids,
+
+ .probe = net2280_probe,
+ .remove = net2280_remove,
+
+ /* FIXME add power management support */
+};
+
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_AUTHOR ("David Brownell");
+MODULE_LICENSE ("GPL");
+
+static int __init init (void)
+{
+ return pci_module_init (&net2280_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+ pci_unregister_driver (&net2280_pci_driver);
+}
+module_exit (cleanup);
diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
new file mode 100644
index 000000000000..7e25111a8721
--- /dev/null
+++ b/drivers/usb/gadget/net2280.h
@@ -0,0 +1,709 @@
+/*
+ * NetChip 2280 high/full speed USB device controller.
+ * Unlike many such controllers, this one talks PCI.
+ */
+
+/*
+ * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* NET2280 MEMORY MAPPED REGISTERS
+ *
+ * The register layout came from the chip documentation, and the bit
+ * number definitions were extracted from chip specification.
+ *
+ * Use the shift operator ('<<') to build bit masks, with readl/writel
+ * to access the registers through PCI.
+ */
+
+/* main registers, BAR0 + 0x0000 */
+struct net2280_regs {
+ // offset 0x0000
+ u32 devinit;
+#define LOCAL_CLOCK_FREQUENCY 8
+#define FORCE_PCI_RESET 7
+#define PCI_ID 6
+#define PCI_ENABLE 5
+#define FIFO_SOFT_RESET 4
+#define CFG_SOFT_RESET 3
+#define PCI_SOFT_RESET 2
+#define USB_SOFT_RESET 1
+#define M8051_RESET 0
+ u32 eectl;
+#define EEPROM_ADDRESS_WIDTH 23
+#define EEPROM_CHIP_SELECT_ACTIVE 22
+#define EEPROM_PRESENT 21
+#define EEPROM_VALID 20
+#define EEPROM_BUSY 19
+#define EEPROM_CHIP_SELECT_ENABLE 18
+#define EEPROM_BYTE_READ_START 17
+#define EEPROM_BYTE_WRITE_START 16
+#define EEPROM_READ_DATA 8
+#define EEPROM_WRITE_DATA 0
+ u32 eeclkfreq;
+ u32 _unused0;
+ // offset 0x0010
+
+ u32 pciirqenb0; /* interrupt PCI master ... */
+#define SETUP_PACKET_INTERRUPT_ENABLE 7
+#define ENDPOINT_F_INTERRUPT_ENABLE 6
+#define ENDPOINT_E_INTERRUPT_ENABLE 5
+#define ENDPOINT_D_INTERRUPT_ENABLE 4
+#define ENDPOINT_C_INTERRUPT_ENABLE 3
+#define ENDPOINT_B_INTERRUPT_ENABLE 2
+#define ENDPOINT_A_INTERRUPT_ENABLE 1
+#define ENDPOINT_0_INTERRUPT_ENABLE 0
+ u32 pciirqenb1;
+#define PCI_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+ u32 cpu_irqenb0; /* ... or onboard 8051 */
+#define SETUP_PACKET_INTERRUPT_ENABLE 7
+#define ENDPOINT_F_INTERRUPT_ENABLE 6
+#define ENDPOINT_E_INTERRUPT_ENABLE 5
+#define ENDPOINT_D_INTERRUPT_ENABLE 4
+#define ENDPOINT_C_INTERRUPT_ENABLE 3
+#define ENDPOINT_B_INTERRUPT_ENABLE 2
+#define ENDPOINT_A_INTERRUPT_ENABLE 1
+#define ENDPOINT_0_INTERRUPT_ENABLE 0
+ u32 cpu_irqenb1;
+#define CPU_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_INTA_INTERRUPT_ENABLE 24
+#define PCI_PME_INTERRUPT_ENABLE 23
+#define PCI_SERR_INTERRUPT_ENABLE 22
+#define PCI_PERR_INTERRUPT_ENABLE 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+
+ // offset 0x0020
+ u32 _unused1;
+ u32 usbirqenb1;
+#define USB_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_INTA_INTERRUPT_ENABLE 24
+#define PCI_PME_INTERRUPT_ENABLE 23
+#define PCI_SERR_INTERRUPT_ENABLE 22
+#define PCI_PERR_INTERRUPT_ENABLE 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+ u32 irqstat0;
+#define INTA_ASSERTED 12
+#define SETUP_PACKET_INTERRUPT 7
+#define ENDPOINT_F_INTERRUPT 6
+#define ENDPOINT_E_INTERRUPT 5
+#define ENDPOINT_D_INTERRUPT 4
+#define ENDPOINT_C_INTERRUPT 3
+#define ENDPOINT_B_INTERRUPT 2
+#define ENDPOINT_A_INTERRUPT 1
+#define ENDPOINT_0_INTERRUPT 0
+ u32 irqstat1;
+#define POWER_STATE_CHANGE_INTERRUPT 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT 26
+#define PCI_PARITY_ERROR_INTERRUPT 25
+#define PCI_INTA_INTERRUPT 24
+#define PCI_PME_INTERRUPT 23
+#define PCI_SERR_INTERRUPT 22
+#define PCI_PERR_INTERRUPT 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19
+#define PCI_RETRY_ABORT_INTERRUPT 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16
+#define GPIO_INTERRUPT 13
+#define DMA_D_INTERRUPT 12
+#define DMA_C_INTERRUPT 11
+#define DMA_B_INTERRUPT 10
+#define DMA_A_INTERRUPT 9
+#define EEPROM_DONE_INTERRUPT 8
+#define VBUS_INTERRUPT 7
+#define CONTROL_STATUS_INTERRUPT 6
+#define ROOT_PORT_RESET_INTERRUPT 4
+#define SUSPEND_REQUEST_INTERRUPT 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2
+#define RESUME_INTERRUPT 1
+#define SOF_INTERRUPT 0
+ // offset 0x0030
+ u32 idxaddr;
+ u32 idxdata;
+ u32 fifoctl;
+#define PCI_BASE2_RANGE 16
+#define IGNORE_FIFO_AVAILABILITY 3
+#define PCI_BASE2_SELECT 2
+#define FIFO_CONFIGURATION_SELECT 0
+ u32 _unused2;
+ // offset 0x0040
+ u32 memaddr;
+#define START 28
+#define DIRECTION 27
+#define FIFO_DIAGNOSTIC_SELECT 24
+#define MEMORY_ADDRESS 0
+ u32 memdata0;
+ u32 memdata1;
+ u32 _unused3;
+ // offset 0x0050
+ u32 gpioctl;
+#define GPIO3_LED_SELECT 12
+#define GPIO3_INTERRUPT_ENABLE 11
+#define GPIO2_INTERRUPT_ENABLE 10
+#define GPIO1_INTERRUPT_ENABLE 9
+#define GPIO0_INTERRUPT_ENABLE 8
+#define GPIO3_OUTPUT_ENABLE 7
+#define GPIO2_OUTPUT_ENABLE 6
+#define GPIO1_OUTPUT_ENABLE 5
+#define GPIO0_OUTPUT_ENABLE 4
+#define GPIO3_DATA 3
+#define GPIO2_DATA 2
+#define GPIO1_DATA 1
+#define GPIO0_DATA 0
+ u32 gpiostat;
+#define GPIO3_INTERRUPT 3
+#define GPIO2_INTERRUPT 2
+#define GPIO1_INTERRUPT 1
+#define GPIO0_INTERRUPT 0
+} __attribute__ ((packed));
+
+/* usb control, BAR0 + 0x0080 */
+struct net2280_usb_regs {
+ // offset 0x0080
+ u32 stdrsp;
+#define STALL_UNSUPPORTED_REQUESTS 31
+#define SET_TEST_MODE 16
+#define GET_OTHER_SPEED_CONFIGURATION 15
+#define GET_DEVICE_QUALIFIER 14
+#define SET_ADDRESS 13
+#define ENDPOINT_SET_CLEAR_HALT 12
+#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11
+#define GET_STRING_DESCRIPTOR_2 10
+#define GET_STRING_DESCRIPTOR_1 9
+#define GET_STRING_DESCRIPTOR_0 8
+#define GET_SET_INTERFACE 6
+#define GET_SET_CONFIGURATION 5
+#define GET_CONFIGURATION_DESCRIPTOR 4
+#define GET_DEVICE_DESCRIPTOR 3
+#define GET_ENDPOINT_STATUS 2
+#define GET_INTERFACE_STATUS 1
+#define GET_DEVICE_STATUS 0
+ u32 prodvendid;
+#define PRODUCT_ID 16
+#define VENDOR_ID 0
+ u32 relnum;
+ u32 usbctl;
+#define SERIAL_NUMBER_INDEX 16
+#define PRODUCT_ID_STRING_ENABLE 13
+#define VENDOR_ID_STRING_ENABLE 12
+#define USB_ROOT_PORT_WAKEUP_ENABLE 11
+#define VBUS_PIN 10
+#define TIMED_DISCONNECT 9
+#define SUSPEND_IMMEDIATELY 7
+#define SELF_POWERED_USB_DEVICE 6
+#define REMOTE_WAKEUP_SUPPORT 5
+#define PME_POLARITY 4
+#define USB_DETECT_ENABLE 3
+#define PME_WAKEUP_ENABLE 2
+#define DEVICE_REMOTE_WAKEUP_ENABLE 1
+#define SELF_POWERED_STATUS 0
+ // offset 0x0090
+ u32 usbstat;
+#define HIGH_SPEED 7
+#define FULL_SPEED 6
+#define GENERATE_RESUME 5
+#define GENERATE_DEVICE_REMOTE_WAKEUP 4
+ u32 xcvrdiag;
+#define FORCE_HIGH_SPEED_MODE 31
+#define FORCE_FULL_SPEED_MODE 30
+#define USB_TEST_MODE 24
+#define LINE_STATE 16
+#define TRANSCEIVER_OPERATION_MODE 2
+#define TRANSCEIVER_SELECT 1
+#define TERMINATION_SELECT 0
+ u32 setup0123;
+ u32 setup4567;
+ // offset 0x0090
+ u32 _unused0;
+ u32 ouraddr;
+#define FORCE_IMMEDIATE 7
+#define OUR_USB_ADDRESS 0
+ u32 ourconfig;
+} __attribute__ ((packed));
+
+/* pci control, BAR0 + 0x0100 */
+struct net2280_pci_regs {
+ // offset 0x0100
+ u32 pcimstctl;
+#define PCI_ARBITER_PARK_SELECT 13
+#define PCI_MULTI LEVEL_ARBITER 12
+#define PCI_RETRY_ABORT_ENABLE 11
+#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10
+#define DMA_READ_MULTIPLE_ENABLE 9
+#define DMA_READ_LINE_ENABLE 8
+#define PCI_MASTER_COMMAND_SELECT 6
+#define MEM_READ_OR_WRITE 0
+#define IO_READ_OR_WRITE 1
+#define CFG_READ_OR_WRITE 2
+#define PCI_MASTER_START 5
+#define PCI_MASTER_READ_WRITE 4
+#define PCI_MASTER_WRITE 0
+#define PCI_MASTER_READ 1
+#define PCI_MASTER_BYTE_WRITE_ENABLES 0
+ u32 pcimstaddr;
+ u32 pcimstdata;
+ u32 pcimststat;
+#define PCI_ARBITER_CLEAR 2
+#define PCI_EXTERNAL_ARBITER 1
+#define PCI_HOST_MODE 0
+} __attribute__ ((packed));
+
+/* dma control, BAR0 + 0x0180 ... array of four structs like this,
+ * for channels 0..3. see also struct net2280_dma: descriptor
+ * that can be loaded into some of these registers.
+ */
+struct net2280_dma_regs { /* [11.7] */
+ // offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
+ u32 dmactl;
+#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25
+#define DMA_CLEAR_COUNT_ENABLE 21
+#define DESCRIPTOR_POLLING_RATE 19
+#define POLL_CONTINUOUS 0
+#define POLL_1_USEC 1
+#define POLL_100_USEC 2
+#define POLL_1_MSEC 3
+#define DMA_VALID_BIT_POLLING_ENABLE 18
+#define DMA_VALID_BIT_ENABLE 17
+#define DMA_SCATTER_GATHER_ENABLE 16
+#define DMA_OUT_AUTO_START_ENABLE 4
+#define DMA_PREEMPT_ENABLE 3
+#define DMA_FIFO_VALIDATE 2
+#define DMA_ENABLE 1
+#define DMA_ADDRESS_HOLD 0
+ u32 dmastat;
+#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25
+#define DMA_TRANSACTION_DONE_INTERRUPT 24
+#define DMA_ABORT 1
+#define DMA_START 0
+ u32 _unused0 [2];
+ // offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
+ u32 dmacount;
+#define VALID_BIT 31
+#define DMA_DIRECTION 30
+#define DMA_DONE_INTERRUPT_ENABLE 29
+#define END_OF_CHAIN 28
+#define DMA_BYTE_COUNT_MASK ((1<<24)-1)
+#define DMA_BYTE_COUNT 0
+ u32 dmaaddr;
+ u32 dmadesc;
+ u32 _unused1;
+} __attribute__ ((packed));
+
+/* dedicated endpoint registers, BAR0 + 0x0200 */
+
+struct net2280_dep_regs { /* [11.8] */
+ // offset 0x0200, 0x0210, 0x220, 0x230, 0x240
+ u32 dep_cfg;
+ // offset 0x0204, 0x0214, 0x224, 0x234, 0x244
+ u32 dep_rsp;
+ u32 _unused [2];
+} __attribute__ ((packed));
+
+/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
+ * like this, for ep0 then the configurable endpoints A..F
+ * ep0 reserved for control; E and F have only 64 bytes of fifo
+ */
+struct net2280_ep_regs { /* [11.9] */
+ // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
+ u32 ep_cfg;
+#define ENDPOINT_BYTE_COUNT 16
+#define ENDPOINT_ENABLE 10
+#define ENDPOINT_TYPE 8
+#define ENDPOINT_DIRECTION 7
+#define ENDPOINT_NUMBER 0
+ u32 ep_rsp;
+#define SET_NAK_OUT_PACKETS 15
+#define SET_EP_HIDE_STATUS_PHASE 14
+#define SET_INTERRUPT_MODE 12
+#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11
+#define SET_NAK_OUT_PACKETS_MODE 10
+#define SET_ENDPOINT_TOGGLE 9
+#define SET_ENDPOINT_HALT 8
+#define CLEAR_NAK_OUT_PACKETS 7
+#define CLEAR_EP_HIDE_STATUS_PHASE 6
+#define CLEAR_INTERRUPT_MODE 4
+#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3
+#define CLEAR_NAK_OUT_PACKETS_MODE 2
+#define CLEAR_ENDPOINT_TOGGLE 1
+#define CLEAR_ENDPOINT_HALT 0
+ u32 ep_irqenb;
+#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6
+#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5
+#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3
+#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2
+#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1
+#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0
+ u32 ep_stat;
+#define FIFO_VALID_COUNT 24
+#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22
+#define TIMEOUT 21
+#define USB_STALL_SENT 20
+#define USB_IN_NAK_SENT 19
+#define USB_IN_ACK_RCVD 18
+#define USB_OUT_PING_NAK_SENT 17
+#define USB_OUT_ACK_SENT 16
+#define FIFO_OVERFLOW 13
+#define FIFO_UNDERFLOW 12
+#define FIFO_FULL 11
+#define FIFO_EMPTY 10
+#define FIFO_FLUSH 9
+#define SHORT_PACKET_OUT_DONE_INTERRUPT 6
+#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5
+#define NAK_OUT_PACKETS 4
+#define DATA_PACKET_RECEIVED_INTERRUPT 3
+#define DATA_PACKET_TRANSMITTED_INTERRUPT 2
+#define DATA_OUT_PING_TOKEN_INTERRUPT 1
+#define DATA_IN_TOKEN_INTERRUPT 0
+ // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
+ u32 ep_avail;
+ u32 ep_data;
+ u32 _unused0 [2];
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/* indexed registers [11.10] are accessed indirectly
+ * caller must own the device lock.
+ */
+
+static inline u32
+get_idx_reg (struct net2280_regs *regs, u32 index)
+{
+ writel (index, &regs->idxaddr);
+ /* NOTE: synchs device/cpu memory views */
+ return readl (&regs->idxdata);
+}
+
+static inline void
+set_idx_reg (struct net2280_regs *regs, u32 index, u32 value)
+{
+ writel (index, &regs->idxaddr);
+ writel (value, &regs->idxdata);
+ /* posted, may not be visible yet */
+}
+
+#define REG_DIAG 0x0
+#define RETRY_COUNTER 16
+#define FORCE_PCI_SERR 11
+#define FORCE_PCI_INTERRUPT 10
+#define FORCE_USB_INTERRUPT 9
+#define FORCE_CPU_INTERRUPT 8
+#define ILLEGAL_BYTE_ENABLES 5
+#define FAST_TIMES 4
+#define FORCE_RECEIVE_ERROR 2
+#define FORCE_TRANSMIT_CRC_ERROR 0
+#define REG_FRAME 0x02 /* from last sof */
+#define REG_CHIPREV 0x03 /* in bcd */
+#define REG_HS_NAK_RATE 0x0a /* NAK per N uframes */
+
+/* ep a-f highspeed and fullspeed maxpacket, addresses
+ * computed from ep->num
+ */
+#define REG_EP_MAXPKT(dev,num) (((num) + 1) * 0x10 + \
+ (((dev)->gadget.speed == USB_SPEED_HIGH) ? 0 : 1))
+
+/*-------------------------------------------------------------------------*/
+
+/* [8.3] for scatter/gather i/o
+ * use struct net2280_dma_regs bitfields
+ */
+struct net2280_dma {
+ u32 dmacount;
+ u32 dmaaddr; /* the buffer */
+ u32 dmadesc; /* next dma descriptor */
+ u32 _reserved;
+} __attribute__ ((aligned (16)));
+
+/*-------------------------------------------------------------------------*/
+
+/* DRIVER DATA STRUCTURES and UTILITIES */
+
+struct net2280_ep {
+ struct usb_ep ep;
+ struct net2280_ep_regs *regs;
+ struct net2280_dma_regs *dma;
+ struct net2280_dma *dummy;
+ dma_addr_t td_dma; /* of dummy */
+ struct net2280 *dev;
+ unsigned long irqs;
+
+ /* analogous to a host-side qh */
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+ unsigned num : 8,
+ fifo_size : 12,
+ in_fifo_validate : 1,
+ stopped : 1,
+ is_in : 1,
+ is_iso : 1;
+};
+
+static inline void allow_status (struct net2280_ep *ep)
+{
+ /* ep0 only */
+ writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+ | (1 << CLEAR_NAK_OUT_PACKETS_MODE)
+ , &ep->regs->ep_rsp);
+}
+
+static inline void set_halt (struct net2280_ep *ep)
+{
+ /* ep0 and bulk/intr endpoints */
+ writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+ /* set NAK_OUT for erratum 0114 */
+ | (1 << SET_NAK_OUT_PACKETS)
+ | (1 << SET_ENDPOINT_HALT)
+ , &ep->regs->ep_rsp);
+}
+
+static inline void clear_halt (struct net2280_ep *ep)
+{
+ /* bulk/intr endpoints */
+ writel ( (1 << CLEAR_ENDPOINT_HALT)
+ | (1 << CLEAR_ENDPOINT_TOGGLE)
+ , &ep->regs->ep_rsp);
+}
+
+/* count (<= 4) bytes in the next fifo write will be valid */
+static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count)
+{
+ writeb (count, 2 + (u8 *) &ep->regs->ep_cfg);
+}
+
+struct net2280_request {
+ struct usb_request req;
+ struct net2280_dma *td;
+ dma_addr_t td_dma;
+ struct list_head queue;
+ unsigned mapped : 1,
+ dma_done : 1,
+ valid : 1;
+};
+
+struct net2280 {
+ /* each pci device provides one gadget, several endpoints */
+ struct usb_gadget gadget;
+ spinlock_t lock;
+ struct net2280_ep ep [7];
+ struct usb_gadget_driver *driver;
+ unsigned enabled : 1,
+ protocol_stall : 1,
+ got_irq : 1,
+ region : 1,
+ selfpowered : 1;
+ u16 chiprev;
+
+ /* pci state used to access those endpoints */
+ struct pci_dev *pdev;
+ struct net2280_regs *regs;
+ struct net2280_usb_regs *usb;
+ struct net2280_pci_regs *pci;
+ struct net2280_dma_regs *dma;
+ struct net2280_dep_regs *dep;
+ struct net2280_ep_regs *epregs;
+
+ struct pci_pool *requests;
+ // statistics...
+};
+
+#ifdef USE_RDK_LEDS
+
+static inline void net2280_led_init (struct net2280 *dev)
+{
+ /* LED3 (green) is on during USB activity. note erratum 0113. */
+ writel ((1 << GPIO3_LED_SELECT)
+ | (1 << GPIO3_OUTPUT_ENABLE)
+ | (1 << GPIO2_OUTPUT_ENABLE)
+ | (1 << GPIO1_OUTPUT_ENABLE)
+ | (1 << GPIO0_OUTPUT_ENABLE)
+ , &dev->regs->gpioctl);
+}
+
+/* indicate speed with bi-color LED 0/1 */
+static inline
+void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed)
+{
+ u32 val = readl (&dev->regs->gpioctl);
+ switch (speed) {
+ case USB_SPEED_HIGH: /* green */
+ val &= ~(1 << GPIO0_DATA);
+ val |= (1 << GPIO1_DATA);
+ break;
+ case USB_SPEED_FULL: /* red */
+ val &= ~(1 << GPIO1_DATA);
+ val |= (1 << GPIO0_DATA);
+ break;
+ default: /* (off/black) */
+ val &= ~((1 << GPIO1_DATA) | (1 << GPIO0_DATA));
+ break;
+ }
+ writel (val, &dev->regs->gpioctl);
+}
+
+/* indicate power with LED 2 */
+static inline void net2280_led_active (struct net2280 *dev, int is_active)
+{
+ u32 val = readl (&dev->regs->gpioctl);
+
+ // FIXME this LED never seems to turn on.
+ if (is_active)
+ val |= GPIO2_DATA;
+ else
+ val &= ~GPIO2_DATA;
+ writel (val, &dev->regs->gpioctl);
+}
+static inline void net2280_led_shutdown (struct net2280 *dev)
+{
+ /* turn off all four GPIO*_DATA bits */
+ writel (readl (&dev->regs->gpioctl) & ~0x0f,
+ &dev->regs->gpioctl);
+}
+
+#else
+
+#define net2280_led_init(dev) do { } while (0)
+#define net2280_led_speed(dev, speed) do { } while (0)
+#define net2280_led_shutdown(dev) do { } while (0)
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(dev,level,fmt,args...) \
+ printk(level "%s %s: " fmt , driver_name , \
+ dev->pdev->slot_name , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(dev,fmt,args...) \
+ xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG DEBUG
+#else
+#define VDEBUG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* VERBOSE */
+
+#define ERROR(dev,fmt,args...) \
+ xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+ xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+ xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+static inline void start_out_naking (struct net2280_ep *ep)
+{
+ /* NOTE: hardware races lurk here, and PING protocol issues */
+ writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+ /* synch with device */
+ readl (&ep->regs->ep_rsp);
+}
+
+#ifdef DEBUG
+static inline void assert_out_naking (struct net2280_ep *ep, const char *where)
+{
+ u32 tmp = readl (&ep->regs->ep_stat);
+
+ if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
+ DEBUG (ep->dev, "%s %s %08x !NAK\n",
+ ep->ep.name, where, tmp);
+ writel ((1 << SET_NAK_OUT_PACKETS),
+ &ep->regs->ep_rsp);
+ }
+}
+#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep,__FUNCTION__)
+#else
+#define ASSERT_OUT_NAKING(ep) do {} while (0)
+#endif
+
+static inline void stop_out_naking (struct net2280_ep *ep)
+{
+ u32 tmp;
+
+ tmp = readl (&ep->regs->ep_stat);
+ if ((tmp & (1 << NAK_OUT_PACKETS)) != 0)
+ writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+}
+
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
new file mode 100644
index 000000000000..8ccb62ef1cf8
--- /dev/null
+++ b/drivers/usb/gadget/usbstring.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+
+/**
+ * usb_gadget_get_string - fill out a string descriptor
+ * @table: of c strings using iso latin/1 characters
+ * @id: string id, from low byte of wValue in get string descriptor
+ * @buf: at least 256 bytes
+ *
+ * Finds the iso latin/1 string matching the ID, and converts it into a
+ * string descriptor in utf16-le.
+ * Returns length of descriptor (always even) or negative errno
+ *
+ * If your driver needs stings in multiple languages, you'll need to
+ * to use some alternate solution for languages where the ISO 8859/1
+ * (latin/1) character set can't be used. For example, they can't be
+ * used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other
+ * languages. You'd likely "switch (wIndex) { ... }" in your ep0
+ * string descriptor logic, using this routine in cases where "western
+ * european" characters suffice for the strings being returned.
+ */
+int
+usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
+{
+ struct usb_string *s;
+ int len;
+
+ /* descriptor 0 has the language id */
+ if (id == 0) {
+ buf [0] = 4;
+ buf [1] = USB_DT_STRING;
+ buf [2] = (u8) table->language;
+ buf [3] = (u8) (table->language >> 8);
+ return 4;
+ }
+ for (s = table->strings; s && s->s; s++)
+ if (s->id == id)
+ break;
+
+ /* unrecognized: stall. */
+ if (!s || !s->s)
+ return -EINVAL;
+
+ /* string descriptors have length, tag, then UTF16-LE text */
+ len = min ((size_t) 126, strlen (s->s));
+ buf [0] = (len + 1) * 2;
+ buf [1] = USB_DT_STRING;
+ memset (buf + 2, 0, 2 * len); /* zero all the high bytes */
+ while (len) {
+ buf [2 * len] = s->s [len - 1];
+ len--;
+ }
+ return buf [0];
+}
+
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
new file mode 100644
index 000000000000..388e1657bcd5
--- /dev/null
+++ b/drivers/usb/gadget/zero.c
@@ -0,0 +1,1223 @@
+/*
+ * zero.c -- Gadget Zero, for USB development
+ *
+ * Copyright (C) 2003 David Brownell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ * 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.
+ *
+ * Hardware details are visible (see CONFIG_USB_ZERO_* below) 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. Module options include:
+ *
+ * buflen=N default N=4096, buffer size used
+ * qlen=N default N=32, how many buffers in the loopback queue
+ * loopdefault default false, list loopback config first
+ *
+ * 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).
+ */
+
+#define DEBUG 1
+// #define VERBOSE
+
+#include <linux/config.h>
+#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/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_VERSION "19 Feb 2003"
+
+static const char shortname [] = "zero";
+static const char longname [] = "Gadget Zero";
+
+static const char source_sink [] = "source and sink data";
+static const char loopback [] = "loop input to output";
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * hardware-specific configuration, controlled by which device
+ * controller driver was configured.
+ *
+ * CHIP ... hardware identifier
+ * DRIVER_VERSION_NUM ... alerts the host side driver to differences
+ * EP0_MAXPACKET ... controls packetization of control requests
+ * EP_*_NAME ... which endpoints do we use for which purpose?
+ * EP_*_NUM ... numbers for them (often limited by hardware)
+ * HIGHSPEED ... define if ep0 and descriptors need high speed support
+ * MAX_USB_POWER ... define if we use other than 100 mA bus current
+ * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER
+ * WAKEUP ... if hardware supports remote wakeup AND we will issue the
+ * usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
+ *
+ * hw_optimize(gadget) ... for any hardware tweaks we want to kick in
+ * before we enable our endpoints
+ *
+ * add other defines for other portability issues, like hardware that
+ * for some reason doesn't handle full speed bulk maxpacket of 64.
+ */
+
+/*
+ * DRIVER_VERSION_NUM 0x0000 (?): Martin Diehl's ezusb an21/fx code
+ */
+
+/*
+ * NetChip 2280, PCI based.
+ *
+ * This has half a dozen configurable endpoints, four with dedicated
+ * DMA channels to manage their FIFOs. It supports high speed.
+ * Those endpoints can be arranged in any desired configuration.
+ */
+#ifdef CONFIG_USB_ZERO_NET2280
+#define CHIP "net2280"
+#define DRIVER_VERSION_NUM cpu_to_le16(0x0101)
+#define EP0_MAXPACKET 64
+static const char EP_OUT_NAME [] = "ep-a";
+#define EP_OUT_NUM 2
+static const char EP_IN_NAME [] = "ep-b";
+#define EP_IN_NUM 2
+#define HIGHSPEED
+/* specific hardware configs could be bus-powered */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
+static inline void hw_optimize (struct usb_gadget *gadget)
+{
+ /* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets
+ * for highspeed bulk) because we're not using ep-c/ep-d.
+ */
+ net2280_set_fifo_mode (gadget, 1);
+}
+#endif
+
+/*
+ * PXA-250 UDC: widely used in second gen Linux-capable PDAs.
+ *
+ * This has fifteen fixed-function full speed endpoints, and it
+ * can support all USB transfer types.
+ *
+ * It only supports three configurations (numbered 1, 2, or 3)
+ * with two interfaces each ... there's partial hardware support
+ * for set_configuration and set_interface, preventing some more
+ * interesting config/interface/endpoint arrangements.
+ */
+#ifdef CONFIG_USB_ZERO_PXA250
+#define CHIP "pxa250"
+#define DRIVER_VERSION_NUM cpu_to_le16(0x0103)
+#define EP0_MAXPACKET 16
+static const char EP_OUT_NAME [] = "ep12out-bulk";
+#define EP_OUT_NUM 12
+static const char EP_IN_NAME [] = "ep11in-bulk";
+#define EP_IN_NUM 11
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*
+ * SA-1100 UDC: widely used in first gen Linux-capable PDAs.
+ *
+ * This has only two fixed function endpoints, which can only
+ * be used for bulk (or interrupt) transfers. (Plus control.)
+ *
+ * Since it can't flush its TX fifos without disabling the UDC,
+ * the current configuration or altsettings can't change except
+ * in special situations. So this is a case of "choose it right
+ * during enumeration" ...
+ */
+#ifdef CONFIG_USB_ZERO_SA1100
+#define CHIP "sa1100"
+#define DRIVER_VERSION_NUM cpu_to_le16(0x0105)
+#define EP0_MAXPACKET 8
+static const char EP_OUT_NAME [] = "ep1out-bulk";
+#define EP_OUT_NUM 1
+static const char EP_IN_NAME [] = "ep2in-bulk";
+#define EP_IN_NUM 2
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* doesn't support remote wakeup? */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef EP0_MAXPACKET
+# error Configure some USB peripheral controller driver!
+#endif
+
+/* power usage is config specific.
+ * hardware that supports remote wakeup defaults to disabling it.
+ */
+
+#ifndef SELFPOWER
+/* default: say we rely on bus power */
+#define SELFPOWER 0
+/* else:
+ * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER
+ * - MAX_USB_POWER may be nonzero.
+ */
+#endif
+
+#ifndef MAX_USB_POWER
+/* any hub supports this steady state bus power consumption */
+#define MAX_USB_POWER 100 /* mA */
+#endif
+
+#ifndef WAKEUP
+/* default: this driver won't do remote wakeup */
+#define WAKEUP 0
+/* else value must be USB_CONFIG_ATT_WAKEUP */
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* big enough to hold our biggest descriptor */
+#define USB_BUFSIZ 256
+
+struct zero_dev {
+ spinlock_t lock;
+ struct usb_gadget *gadget;
+ struct usb_request *req; /* for control responses */
+
+ /* when configured, we have one of two configs:
+ * - source data (in to host) and sink it (out from host)
+ * - or loop it back (out from host back in to host)
+ */
+ u8 config;
+ struct usb_ep *in_ep, *out_ep;
+};
+
+#define xprintk(d,level,fmt,args...) \
+ dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(dev,fmt,args...) \
+ xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG DEBUG
+#else
+#define VDEBUG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#define ERROR(dev,fmt,args...) \
+ xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+ xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+ xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+static unsigned buflen = 4096;
+static unsigned qlen = 32;
+
+module_param (buflen, uint, S_IRUGO|S_IWUSR);
+module_param (qlen, uint, S_IRUGO|S_IWUSR);
+
+/*
+ * 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 (like Linux ... for now!) where config
+ * changes are problematic.
+ */
+static int loopdefault = 0;
+
+module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
+
+/*-------------------------------------------------------------------------*/
+
+/* 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 DRIVER_VENDOR_NUM 0x0525 /* NetChip */
+#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full)
+ * configuration descriptors are built on demand.
+ */
+
+#define STRING_MANUFACTURER 25
+#define STRING_PRODUCT 42
+#define STRING_SERIAL 101
+#define STRING_SOURCE_SINK 250
+#define STRING_LOOPBACK 251
+
+/*
+ * This device advertises two configurations; these numbers work
+ * on a pxa250 as well as more flexible hardware.
+ */
+#define CONFIG_SOURCE_SINK 3
+#define CONFIG_LOOPBACK 2
+
+static const struct usb_device_descriptor
+device_desc = {
+ .bLength = sizeof device_desc,
+ .bDescriptorType = USB_DT_DEVICE,
+
+ .bcdUSB = cpu_to_le16 (0x0200),
+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
+ .bMaxPacketSize0 = EP0_MAXPACKET,
+
+ .idVendor = cpu_to_le16 (DRIVER_VENDOR_NUM),
+ .idProduct = cpu_to_le16 (DRIVER_PRODUCT_NUM),
+ .bcdDevice = cpu_to_le16 (DRIVER_VERSION_NUM),
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .iSerialNumber = STRING_SERIAL,
+ .bNumConfigurations = 2,
+};
+
+static const struct usb_config_descriptor
+source_sink_config = {
+ .bLength = sizeof source_sink_config,
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* compute wTotalLength on the fly */
+ .bNumInterfaces = 1,
+ .bConfigurationValue = CONFIG_SOURCE_SINK,
+ .iConfiguration = STRING_SOURCE_SINK,
+ .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
+ .bMaxPower = (MAX_USB_POWER + 1) / 2,
+};
+
+static const struct usb_config_descriptor
+loopback_config = {
+ .bLength = sizeof loopback_config,
+ .bDescriptorType = USB_DT_CONFIG,
+
+ /* compute wTotalLength on the fly */
+ .bNumInterfaces = 1,
+ .bConfigurationValue = CONFIG_LOOPBACK,
+ .iConfiguration = STRING_LOOPBACK,
+ .bmAttributes = USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
+ .bMaxPower = (MAX_USB_POWER + 1) / 2,
+};
+
+/* one interface in each configuration */
+
+static const struct usb_interface_descriptor
+source_sink_intf = {
+ .bLength = sizeof source_sink_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = STRING_SOURCE_SINK,
+};
+
+static const struct usb_interface_descriptor
+loopback_intf = {
+ .bLength = sizeof loopback_intf,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .iInterface = STRING_LOOPBACK,
+};
+
+/* two full speed bulk endpoints; their use is config-dependent */
+
+static const struct usb_endpoint_descriptor
+fs_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_IN_NUM | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (64),
+};
+
+static const struct usb_endpoint_descriptor
+fs_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_OUT_NUM,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (64),
+};
+
+#ifdef HIGHSPEED
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ *
+ * that means alternate endpoint descriptors (bigger packets)
+ * and a "device qualifier" ... plus more construction options
+ * for the config descriptor.
+ */
+
+static const struct usb_endpoint_descriptor
+hs_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_IN_NUM | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (512),
+};
+
+static const struct usb_endpoint_descriptor
+hs_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = EP_OUT_NUM,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16 (512),
+};
+
+static const struct usb_qualifier_descriptor
+dev_qualifier = {
+ .bLength = sizeof dev_qualifier,
+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+
+ .bcdUSB = cpu_to_le16 (0x0200),
+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
+
+ /* assumes ep0 uses the same value for both speeds ... */
+ .bMaxPacketSize0 = EP0_MAXPACKET,
+
+ .bNumConfigurations = 2,
+};
+
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+
+#else
+
+/* if there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g,hs,fs) fs
+
+#endif /* !HIGHSPEED */
+
+static char serial [40];
+
+/* static strings, in iso 8859/1 */
+static struct usb_string strings [] = {
+ { STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, },
+ { STRING_PRODUCT, longname, },
+ { STRING_SERIAL, serial, },
+ { STRING_LOOPBACK, loopback, },
+ { STRING_SOURCE_SINK, source_sink, },
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = strings,
+};
+
+/*
+ * config descriptors are also handcrafted. these must agree with code
+ * that sets configurations, and with code managing interface altsettings.
+ * other complexity may come from:
+ *
+ * - high speed support, including "other speed config" rules
+ * - multiple configurations
+ * - interfaces with alternate settings
+ * - embedded class or vendor-specific descriptors
+ *
+ * this handles high speed, and has a second config that could as easily
+ * have been an alternate interface setting.
+ *
+ * NOTE: to demonstrate (and test) more USB capabilities, this driver
+ * should include an altsetting to test interrupt transfers, including
+ * high bandwidth modes at high speed. (Maybe work like Intel's test
+ * device?)
+ */
+static int
+config_buf (enum usb_device_speed speed,
+ u8 *buf, u8 type, unsigned index)
+{
+ int is_source_sink;
+ const unsigned config_len = USB_DT_CONFIG_SIZE
+ + USB_DT_INTERFACE_SIZE
+ + 2 * USB_DT_ENDPOINT_SIZE;
+#ifdef HIGHSPEED
+ int hs;
+#endif
+ /* two configurations will always be index 0 and index 1 */
+ if (index > 1)
+ return -EINVAL;
+ if (config_len > USB_BUFSIZ)
+ return -EDOM;
+ is_source_sink = loopdefault ? (index == 1) : (index == 0);
+
+ /* config (or other speed config) */
+ if (is_source_sink)
+ memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE);
+ else
+ memcpy (buf, &loopback_config, USB_DT_CONFIG_SIZE);
+ buf [1] = type;
+ ((struct usb_config_descriptor *) buf)->wTotalLength
+ = cpu_to_le16 (config_len);
+ buf += USB_DT_CONFIG_SIZE;
+
+ /* one interface */
+ if (is_source_sink)
+ memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE);
+ else
+ memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE);
+ buf += USB_DT_INTERFACE_SIZE;
+
+ /* the endpoints in that interface (at that speed) */
+#ifdef HIGHSPEED
+ hs = (speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ if (hs) {
+ memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ } else
+#endif
+ {
+ memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
+ buf += USB_DT_ENDPOINT_SIZE;
+ }
+
+ return config_len;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+alloc_ep_req (struct usb_ep *ep, unsigned length)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request (ep, GFP_ATOMIC);
+ if (req) {
+ req->length = length;
+ req->buf = usb_ep_alloc_buffer (ep, length,
+ &req->dma, GFP_ATOMIC);
+ if (!req->buf) {
+ usb_ep_free_request (ep, req);
+ req = 0;
+ }
+ }
+ return req;
+}
+
+static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
+{
+ if (req->buf)
+ usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+ usb_ep_free_request (ep, req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* optionally require specific source/sink data patterns */
+
+static inline int
+check_read_data (
+ struct zero_dev *dev,
+ struct usb_ep *ep,
+ struct usb_request *req
+)
+{
+ int i;
+
+ for (i = 0; i < req->actual; i++) {
+ if (((u8 *)req->buf) [i] != 0) {
+ ERROR (dev, "nonzero OUT byte from host, "
+ "buf [%d] = %d\n",
+ i, ((u8 *)req->buf) [i]);
+ usb_ep_set_halt (ep);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static inline void
+reinit_write_data (
+ struct zero_dev *dev,
+ struct usb_ep *ep,
+ struct usb_request *req
+)
+{
+ memset (req->buf, 0, req->length);
+}
+
+/* if there is only one request in the queue, there'll always be an
+ * irq delay between end of one request and start of the next.
+ * that prevents using hardware dma queues.
+ */
+static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
+{
+ struct zero_dev *dev = ep->driver_data;
+ int status = req->status;
+
+ switch (status) {
+
+ case 0: /* normal completion? */
+ if (ep == dev->out_ep)
+ check_read_data (dev, ep, req);
+ else
+ reinit_write_data (dev, ep, req);
+ break;
+
+ /* this endpoint is normally active while we're configured */
+ case -ECONNRESET: /* request dequeued */
+ case -ESHUTDOWN: /* disconnect from host */
+ DEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+ req->actual, req->length);
+ free_ep_req (ep, req);
+ return;
+
+ case -EOVERFLOW: /* buffer overrun on read means that
+ * we didn't provide a big enough
+ * buffer.
+ */
+ default:
+#if 1
+ DEBUG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+ status, req->actual, req->length);
+#endif
+ case -EREMOTEIO: /* short read */
+ break;
+ }
+
+ status = usb_ep_queue (ep, req, GFP_ATOMIC);
+ if (status) {
+ ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
+ ep->name, req->length, status);
+ usb_ep_set_halt (ep);
+ /* FIXME recover later ... somehow */
+ }
+}
+
+static struct usb_request *
+source_sink_start_ep (struct usb_ep *ep, int gfp_flags)
+{
+ struct usb_request *req;
+ int status;
+
+ req = alloc_ep_req (ep, buflen);
+ if (!req)
+ return 0;
+
+ memset (req->buf, 0, req->length);
+ req->complete = source_sink_complete;
+
+ status = usb_ep_queue (ep, req, gfp_flags);
+ if (status) {
+ struct zero_dev *dev = ep->driver_data;
+
+ ERROR (dev, "start %s --> %d\n", ep->name, status);
+ free_ep_req (ep, req);
+ req = 0;
+ }
+
+ return req;
+}
+
+static int
+set_source_sink_config (struct zero_dev *dev, int gfp_flags)
+{
+ int result = 0;
+ struct usb_ep *ep;
+ struct usb_gadget *gadget = dev->gadget;
+
+ gadget_for_each_ep (ep, gadget) {
+ const struct usb_endpoint_descriptor *d;
+
+ /* one endpoint writes (sources) zeroes in (to the host) */
+ if (strcmp (ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable (ep, d);
+ if (result == 0) {
+ ep->driver_data = dev;
+ if (source_sink_start_ep (ep, gfp_flags) != 0) {
+ dev->in_ep = ep;
+ continue;
+ }
+ usb_ep_disable (ep);
+ result = -EIO;
+ }
+
+ /* one endpoint reads (sinks) anything out (from the host) */
+ } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable (ep, d);
+ if (result == 0) {
+ ep->driver_data = dev;
+ if (source_sink_start_ep (ep, gfp_flags) != 0) {
+ dev->out_ep = ep;
+ continue;
+ }
+ usb_ep_disable (ep);
+ result = -EIO;
+ }
+
+ /* ignore any other endpoints */
+ } else
+ continue;
+
+ /* stop on error */
+ ERROR (dev, "can't start %s, result %d\n", ep->name, result);
+ break;
+ }
+ if (result == 0)
+ DEBUG (dev, "buflen %d\n", buflen);
+
+ /* caller is responsible for cleanup on error */
+ return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
+{
+ struct zero_dev *dev = ep->driver_data;
+ int status = req->status;
+
+ switch (status) {
+
+ case 0: /* normal completion? */
+ if (ep == dev->out_ep) {
+ /* loop this OUT packet back IN to the host */
+ req->zero = (req->actual < req->length);
+ req->length = req->actual;
+ status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+ if (status == 0)
+ return;
+
+ /* "should never get here" */
+ ERROR (dev, "can't loop %s to %s: %d\n",
+ ep->name, dev->in_ep->name,
+ status);
+ }
+
+ /* queue the buffer for some later OUT packet */
+ req->length = buflen;
+ status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
+ if (status == 0)
+ return;
+
+ /* "should never get here" */
+ /* FALLTHROUGH */
+
+ default:
+ ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+ status, req->actual, req->length);
+ /* FALLTHROUGH */
+
+ /* NOTE: since this driver doesn't maintain an explicit record
+ * of requests it submitted (just maintains qlen count), we
+ * rely on the hardware driver to clean up on disconnect or
+ * endpoint disable.
+ */
+ case -ESHUTDOWN: /* disconnect from host */
+ free_ep_req (ep, req);
+ return;
+ }
+}
+
+static int
+set_loopback_config (struct zero_dev *dev, int gfp_flags)
+{
+ int result = 0;
+ struct usb_ep *ep;
+ struct usb_gadget *gadget = dev->gadget;
+
+ gadget_for_each_ep (ep, gadget) {
+ const struct usb_endpoint_descriptor *d;
+
+ /* one endpoint writes data back IN to the host */
+ if (strcmp (ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable (ep, d);
+ if (result == 0) {
+ ep->driver_data = dev;
+ dev->in_ep = ep;
+ continue;
+ }
+
+ /* one endpoint just reads OUT packets */
+ } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable (ep, d);
+ if (result == 0) {
+ ep->driver_data = dev;
+ dev->out_ep = ep;
+ continue;
+ }
+
+ /* ignore any other endpoints */
+ } else
+ continue;
+
+ /* stop on error */
+ ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+ break;
+ }
+
+ /* allocate a bunch of read buffers and queue them all at once.
+ * we buffer at most 'qlen' transfers; fewer if any need more
+ * than 'buflen' bytes each.
+ */
+ if (result == 0) {
+ struct usb_request *req;
+ unsigned i;
+
+ ep = dev->out_ep;
+ for (i = 0; i < qlen && result == 0; i++) {
+ req = alloc_ep_req (ep, buflen);
+ if (req) {
+ req->complete = loopback_complete;
+ result = usb_ep_queue (ep, req, GFP_ATOMIC);
+ if (result)
+ DEBUG (dev, "%s queue req --> %d\n",
+ ep->name, result);
+ } else
+ result = -ENOMEM;
+ }
+ }
+ if (result == 0)
+ DEBUG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+
+ /* caller is responsible for cleanup on error */
+ return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void zero_reset_config (struct zero_dev *dev)
+{
+ if (dev->config == 0)
+ return;
+
+ DEBUG (dev, "reset config\n");
+
+ /* just disable endpoints, forcing completion of pending i/o.
+ * all our completion handlers free their requests in this case.
+ */
+ if (dev->in_ep) {
+ usb_ep_disable (dev->in_ep);
+ dev->in_ep = 0;
+ }
+ if (dev->out_ep) {
+ usb_ep_disable (dev->out_ep);
+ dev->out_ep = 0;
+ }
+ dev->config = 0;
+}
+
+/* change our operational config. this code must agree with the code
+ * that returns config descriptors, and altsetting code.
+ *
+ * it's also responsible for power management interactions. some
+ * configurations might not work with our current power sources.
+ *
+ * note that some device controller hardware will constrain what this
+ * code can do, perhaps by disallowing more than one configuration or
+ * by limiting configuration choices (like the pxa250).
+ */
+static int
+zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
+{
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+ if (number == dev->config)
+ return 0;
+
+#ifdef CONFIG_USB_ZERO_SA1100
+ if (dev->config) {
+ /* tx fifo is full, but we can't clear it...*/
+ INFO (dev, "can't change configurations\n");
+ return -ESPIPE;
+ }
+#endif
+ zero_reset_config (dev);
+ hw_optimize (gadget);
+
+ switch (number) {
+ case CONFIG_SOURCE_SINK:
+ result = set_source_sink_config (dev, gfp_flags);
+ break;
+ case CONFIG_LOOPBACK:
+ result = set_loopback_config (dev, gfp_flags);
+ break;
+ default:
+ result = -EINVAL;
+ /* FALL THROUGH */
+ case 0:
+ return result;
+ }
+
+ if (!result && (!dev->in_ep || !dev->out_ep))
+ result = -ENODEV;
+ if (result)
+ zero_reset_config (dev);
+ else {
+ char *speed;
+
+ switch (gadget->speed) {
+ case USB_SPEED_LOW: speed = "low"; break;
+ case USB_SPEED_FULL: speed = "full"; break;
+ case USB_SPEED_HIGH: speed = "high"; break;
+ default: speed = "?"; break;
+ }
+
+ dev->config = number;
+ INFO (dev, "%s speed config #%d: %s\n", speed, number,
+ (number == CONFIG_SOURCE_SINK)
+ ? source_sink : loopback);
+ }
+ return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
+{
+ if (req->status || req->actual != req->length)
+ DEBUG ((struct zero_dev *) ep->driver_data,
+ "setup complete --> %d, %d/%d\n",
+ req->status, req->actual, req->length);
+}
+
+/*
+ * The setup() callback implements all the ep0 functionality that's
+ * not handled lower down, in hardware or the hardware driver (like
+ * device and endpoint feature flags, and their status). It's all
+ * housekeeping for the gadget function we're implementing. Most of
+ * the work is in config-specific setup.
+ */
+static int
+zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+ struct zero_dev *dev = get_gadget_data (gadget);
+ struct usb_request *req = dev->req;
+ int value = -EOPNOTSUPP;
+
+ /* usually this stores reply data in the pre-allocated ep0 buffer,
+ * but config change events will reconfigure hardware.
+ */
+ switch (ctrl->bRequest) {
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ switch (ctrl->wValue >> 8) {
+
+ case USB_DT_DEVICE:
+ value = min (ctrl->wLength, (u16) sizeof device_desc);
+ memcpy (req->buf, &device_desc, value);
+ break;
+#ifdef HIGHSPEED
+ case USB_DT_DEVICE_QUALIFIER:
+ value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+ memcpy (req->buf, &dev_qualifier, value);
+ break;
+
+ case USB_DT_OTHER_SPEED_CONFIG:
+ // FALLTHROUGH
+#endif /* HIGHSPEED */
+ case USB_DT_CONFIG:
+ value = config_buf (gadget->speed, req->buf,
+ ctrl->wValue >> 8,
+ ctrl->wValue & 0xff);
+ if (value >= 0)
+ value = min (ctrl->wLength, (u16) value);
+ break;
+
+ case USB_DT_STRING:
+ /* wIndex == language code.
+ * this driver only handles one language, you can
+ * add others even if they don't use iso8859/1
+ */
+ value = usb_gadget_get_string (&stringtab,
+ ctrl->wValue & 0xff, req->buf);
+ if (value >= 0)
+ value = min (ctrl->wLength, (u16) value);
+ break;
+ }
+ break;
+
+ /* currently two configs, two speeds */
+ case USB_REQ_SET_CONFIGURATION:
+ if (ctrl->bRequestType != 0)
+ break;
+ spin_lock (&dev->lock);
+ /* change hardware configuration!
+ * no response queued, just zero status == success
+ */
+ value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+ spin_unlock (&dev->lock);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ if (ctrl->bRequestType != USB_DIR_IN)
+ break;
+ *(u8 *)req->buf = dev->config;
+ value = min (ctrl->wLength, (u16) 1);
+ break;
+
+ /* until we add altsetting support, or other interfaces,
+ * only 0/0 are possible.
+ */
+ case USB_REQ_SET_INTERFACE:
+ if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+ break;
+ spin_lock (&dev->lock);
+ if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) {
+ u8 config = dev->config;
+
+ /* resets interface configuration, forgets about
+ * previous transaction state (queued bufs, etc)
+ * and re-inits endpoint state (toggle etc)
+ * no response queued, just zero status == success.
+ * if we had more than one interface we couldn't
+ * use this "reset the config" shortcut.
+ */
+ zero_reset_config (dev);
+ zero_set_config (dev, config, GFP_ATOMIC);
+ value = 0;
+ }
+ spin_unlock (&dev->lock);
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+ break;
+ if (!dev->config)
+ break;
+ if (ctrl->wIndex != 0) {
+ value = -EDOM;
+ break;
+ }
+ *(u8 *)req->buf = 0;
+ value = min (ctrl->wLength, (u16) 1);
+ break;
+
+ default:
+ VDEBUG (dev,
+ "unknown control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+ }
+
+ /* respond with data transfer before status phase? */
+ if (value > 0) {
+ req->length = value;
+ value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ DEBUG (dev, "ep_queue --> %d\n", value);
+ req->status = 0;
+ zero_setup_complete (gadget->ep0, req);
+ }
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+static void
+zero_disconnect (struct usb_gadget *gadget)
+{
+ struct zero_dev *dev = get_gadget_data (gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave (&dev->lock, flags);
+ zero_reset_config (dev);
+
+ /* a more significant application might have some non-usb
+ * activities to quiesce here, saving resources like power
+ * or pushing the notification up a network stack.
+ */
+ spin_unlock_irqrestore (&dev->lock, flags);
+
+ /* next we may get setup() calls to enumerate new connections;
+ * or an unbind() during shutdown (including removing module).
+ */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+zero_unbind (struct usb_gadget *gadget)
+{
+ struct zero_dev *dev = get_gadget_data (gadget);
+
+ DEBUG (dev, "unbind\n");
+
+ /* we've already been disconnected ... no i/o is active */
+ if (dev->req)
+ free_ep_req (gadget->ep0, dev->req);
+ kfree (dev);
+ set_gadget_data (gadget, 0);
+}
+
+static int
+zero_bind (struct usb_gadget *gadget)
+{
+ struct zero_dev *dev;
+
+ dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ memset (dev, 0, sizeof *dev);
+ spin_lock_init (&dev->lock);
+ dev->gadget = gadget;
+ set_gadget_data (gadget, dev);
+
+ /* preallocate control response and buffer */
+ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+ if (!dev->req)
+ goto enomem;
+ dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
+ &dev->req->dma, GFP_KERNEL);
+ if (!dev->req->buf)
+ goto enomem;
+
+ dev->req->complete = zero_setup_complete;
+
+ gadget->ep0->driver_data = dev;
+
+ INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
+ return 0;
+
+enomem:
+ zero_unbind (gadget);
+ return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver zero_driver = {
+#ifdef HIGHSPEED
+ .speed = USB_SPEED_HIGH,
+#else
+ .speed = USB_SPEED_FULL,
+#endif
+ .function = (char *) longname,
+ .bind = zero_bind,
+ .unbind = zero_unbind,
+
+ .setup = zero_setup,
+ .disconnect = zero_disconnect,
+
+ .driver = {
+ .name = (char *) shortname,
+ // .shutdown = ...
+ // .suspend = ...
+ // .resume = ...
+ },
+};
+
+MODULE_AUTHOR ("David Brownell");
+MODULE_LICENSE ("Dual BSD/GPL");
+
+
+static int __init init (void)
+{
+ /* a real value would likely come through some id prom
+ * or module option. this one takes at least two packets.
+ */
+ strncpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
+ serial [sizeof serial - 1] = 0;
+
+ return usb_gadget_register_driver (&zero_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+ usb_gadget_unregister_driver (&zero_driver);
+}
+module_exit (cleanup);
+
diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
new file mode 100644
index 000000000000..3a1455017f09
--- /dev/null
+++ b/include/linux/usb_gadget.h
@@ -0,0 +1,696 @@
+/*
+ * <linux/usb_gadget.h>
+ *
+ * We call the USB code inside a Linux-based peripheral device a "gadget"
+ * driver, except for the hardware-specific bus glue. One USB host can
+ * master many USB gadgets, but the gadgets are only slaved to one host.
+ *
+ *
+ * (c) Copyright 2002-2003 by David Brownell
+ * All Rights Reserved.
+ *
+ * This software is licensed under the GNU GPL version 2.
+ *
+ * ALTERNATIVELY, the kernel API documentation which is included in this
+ * software may also be licenced under the "GNU Free Documentation
+ * License" (version 1.2 or, at your choice, any later version), when
+ * used as part of the "USB Gadget API for Linux" documentation.
+ */
+
+#ifndef __LINUX_USB_GADGET_H
+#define __LINUX_USB_GADGET_H
+
+#ifdef __KERNEL__
+
+struct usb_ep;
+
+/**
+ * struct usb_request - describes one i/o request
+ * @buf: Buffer used for data. Always provide this; some controllers
+ * only use PIO, or don't use DMA for some endpoints.
+ * @dma: DMA address corresponding to 'buf'. If you don't set this
+ * field, and the usb controller needs one, it is responsible
+ * for mapping and unmapping the buffer.
+ * @length: Length of that data
+ * @no_interrupt: If true, hints that no completion irq is needed.
+ * Helpful sometimes with deep request queues.
+ * @zero: If true, when writing data, makes the last packet be "short"
+ * by adding a zero length packet as needed;
+ * @short_not_ok: When reading data, makes short packets be
+ * treated as errors (queue stops advancing till cleanup).
+ * @complete: Function called when request completes
+ * @context: For use by the completion callback
+ * @list: For use by the gadget driver.
+ * @status: Reports completion code, zero or a negative errno.
+ * Normally, faults block the transfer queue from advancing until
+ * the completion callback returns.
+ * Code "-ESHUTDOWN" indicates completion caused by device disconnect,
+ * or when the driver disabled the endpoint.
+ * @actual: Reports actual bytes transferred. For reads (OUT
+ * transfers) this may be less than the requested length. If the
+ * short_not_ok flag is set, short reads are treated as errors
+ * even when status otherwise indicates successful completion.
+ * Note that for writes (IN transfers) the data bytes may still
+ * reside in a device-side FIFO.
+ *
+ * These are allocated/freed through the endpoint they're used with. The
+ * hardware's driver can add extra per-request data to the memory it returns,
+ * which often avoids separate memory allocations (potential failures),
+ * later when the request is queued.
+ *
+ * Request flags affect request handling, such as whether a zero length
+ * packet is written (the "zero" flag), whether a short read should be
+ * treated as an error (blocking request queue advance, the "short_not_ok"
+ * flag), or hinting that an interrupt is not required (the "no_interrupt"
+ * flag, for use with deep request queues).
+ *
+ * Bulk endpoints can use any size buffers, and can also be used for interrupt
+ * transfers. interrupt-only endpoints can be much less functional.
+ */
+ // NOTE this is analagous to 'struct urb' on the host side,
+ // except that it's thinner and promotes more pre-allocation.
+ //
+ // ISSUE should this be allocated through the device?
+
+struct usb_request {
+ void *buf;
+ unsigned length;
+ dma_addr_t dma;
+
+ unsigned no_interrupt : 1,
+ zero : 1,
+ short_not_ok : 1;
+
+ void (*complete)(struct usb_ep *ep,
+ struct usb_request *req);
+ void *context;
+ struct list_head list;
+
+ int status;
+ unsigned actual;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* endpoint-specific parts of the api to the usb controller hardware.
+ * unlike the urb model, (de)multiplexing layers are not required.
+ * (so this api could slash overhead if used on the host side...)
+ *
+ * note that device side usb controllers commonly differ in how many
+ * endpoints they support, as well as their capabilities.
+ */
+struct usb_ep_ops {
+ int (*enable) (struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc);
+ int (*disable) (struct usb_ep *ep);
+
+ struct usb_request *(*alloc_request) (struct usb_ep *ep,
+ int gfp_flags);
+ void (*free_request) (struct usb_ep *ep, struct usb_request *req);
+
+ void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes,
+ dma_addr_t *dma, int gfp_flags);
+ void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
+ unsigned bytes);
+ // NOTE: on 2.5, drivers may also use dma_map() and
+ // dma_sync_single() to manage dma overhead.
+
+ int (*queue) (struct usb_ep *ep, struct usb_request *req,
+ int gfp_flags);
+ int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
+
+ int (*set_halt) (struct usb_ep *ep, int value);
+ int (*fifo_status) (struct usb_ep *ep);
+ void (*fifo_flush) (struct usb_ep *ep);
+};
+
+/**
+ * struct usb_ep - device side representation of USB endpoint
+ * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
+ * @ep_list:the gadget's ep_list holds all of its endpoints
+ * @maxpacket:the maximum packet size used on this endpoint, as
+ * configured when the endpoint was enabled.
+ * @driver_data:for use by the gadget driver. all other fields are
+ * read-only to gadget drivers.
+ *
+ * the bus controller driver lists all the general purpose endpoints in
+ * gadget->ep_list. the control endpoint (gadget->ep0) is not in that list,
+ * and is accessed only in response to a driver setup() callback.
+ */
+struct usb_ep {
+ void *driver_data;
+
+ const char *name;
+ const struct usb_ep_ops *ops;
+ struct list_head ep_list;
+ unsigned maxpacket : 16;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_ep_enable - configure endpoint, making it usable
+ * @ep:the endpoint being configured. may not be the endpoint named "ep0".
+ * drivers discover endpoints through the ep_list of a usb_gadget.
+ * @desc:descriptor for desired behavior. caller guarantees this pointer
+ * remains valid until the endpoint is disabled; the data byte order
+ * is little-endian (usb-standard).
+ *
+ * when configurations are set, or when interface settings change, the driver
+ * will enable or disable the relevant endpoints. while it is enabled, an
+ * endpoint may be used for i/o until the driver receives a disconnect() from
+ * the host or until the endpoint is disabled.
+ *
+ * the ep0 implementation (which calls this routine) must ensure that the
+ * hardware capabilities of each endpoint match the descriptor provided
+ * for it. for example, an endpoint named "ep2in-bulk" would be usable
+ * for interrupt transfers as well as bulk, but it likely couldn't be used
+ * for iso transfers or for endpoint 14. some endpoints are fully
+ * configurable, with more generic names like "ep-a". (remember that for
+ * USB, "in" means "towards the USB master".)
+ *
+ * returns zero, or a negative error code.
+ */
+static inline int
+usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+{
+ return ep->ops->enable (ep, desc);
+}
+
+/**
+ * usb_ep_disable - endpoint is no longer usable
+ * @ep:the endpoint being unconfigured. may not be the endpoint named "ep0".
+ *
+ * no other task may be using this endpoint when this is called.
+ * any pending and uncompleted requests will complete with status
+ * indicating disconnect (-ESHUTDOWN) before this call returns.
+ * gadget drivers must call usb_ep_enable() again before queueing
+ * requests to the endpoint.
+ *
+ * returns zero, or a negative error code.
+ */
+static inline int
+usb_ep_disable (struct usb_ep *ep)
+{
+ return ep->ops->disable (ep);
+}
+
+/**
+ * usb_ep_alloc_request - allocate a request object to use with this endpoint
+ * @ep:the endpoint to be used with with the request
+ * @gfp_flags:GFP_* flags to use
+ *
+ * Request objects must be allocated with this call, since they normally
+ * need controller-specific setup and may even need endpoint-specific
+ * resources such as allocation of DMA descriptors.
+ * Requests may be submitted with usb_ep_queue(), and receive a single
+ * completion callback. Free requests with usb_ep_free_request(), when
+ * they are no longer needed.
+ *
+ * Returns the request, or null if one could not be allocated.
+ */
+static inline struct usb_request *
+usb_ep_alloc_request (struct usb_ep *ep, int gfp_flags)
+{
+ return ep->ops->alloc_request (ep, gfp_flags);
+}
+
+/**
+ * usb_ep_free_request - frees a request object
+ * @ep:the endpoint associated with the request
+ * @req:the request being freed
+ *
+ * Reverses the effect of usb_ep_alloc_request().
+ * Caller guarantees the request is not queued, and that it will
+ * no longer be requeued (or otherwise used).
+ */
+static inline void
+usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
+{
+ ep->ops->free_request (ep, req);
+}
+
+/**
+ * usb_ep_alloc_buffer - allocate an I/O buffer
+ * @ep:the endpoint associated with the buffer
+ * @len:length of the desired buffer
+ * @dma:pointer to the buffer's DMA address; must be valid
+ * @gfp_flags:GFP_* flags to use
+ *
+ * Returns a new buffer, or null if one could not be allocated.
+ * The buffer is suitably aligned for dma, if that endpoint uses DMA,
+ * and the caller won't have to care about dma-inconsistency
+ * or any hidden "bounce buffer" mechanism. No additional per-request
+ * DMA mapping will be required for such buffers.
+ * Free it later with usb_ep_free_buffer().
+ *
+ * You don't need to use this call to allocate I/O buffers unless you
+ * want to make sure drivers don't incur costs for such "bounce buffer"
+ * copies or per-request DMA mappings.
+ */
+static inline void *
+usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma,
+ int gfp_flags)
+{
+ return ep->ops->alloc_buffer (ep, len, dma, gfp_flags);
+}
+
+/**
+ * usb_ep_free_buffer - frees an i/o buffer
+ * @ep:the endpoint associated with the buffer
+ * @buf:CPU view address of the buffer
+ * @dma:the buffer's DMA address
+ * @len:length of the buffer
+ *
+ * reverses the effect of usb_ep_alloc_buffer().
+ * caller guarantees the buffer will no longer be accessed
+ */
+static inline void
+usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len)
+{
+ ep->ops->free_buffer (ep, buf, dma, len);
+}
+
+/**
+ * usb_ep_queue - queues (submits) an I/O request to an endpoint.
+ * @ep:the endpoint associated with the request
+ * @req:the request being submitted
+ * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
+ * pre-allocate all necessary memory with the request.
+ *
+ * This tells the device controller to perform the specified request through
+ * that endpoint (reading or writing a buffer). When the request completes,
+ * including being canceled by usb_ep_dequeue(), the request's completion
+ * routine is called to return the request to the driver. Any endpoint
+ * (except control endpoints like ep0) may have more than one transfer
+ * request queued; they complete in FIFO order. Once a gadget driver
+ * submits a request, that request may not be examined or modified until it
+ * is given back to that driver through the completion callback.
+ *
+ * Each request is turned into one or more packets. The controller driver
+ * never merges adjacent requests into the same packet. OUT transfers
+ * will sometimes use data that's already buffered in the hardware.
+ *
+ * Bulk endpoints can queue any amount of data; the transfer is packetized
+ * automatically. The last packet will be short if the request doesn't fill it
+ * out completely. Zero length packets (ZLPs) should be avoided in portable
+ * protocols since not all usb hardware can successfully handle zero length
+ * packets. (ZLPs may be explicitly written, and may be implicitly written if
+ * the request 'zero' flag is set.) Bulk endpoints may also be used
+ * for interrupt transfers; but the reverse is not true, and some endpoints
+ * won't support every interrupt transfer. (Such as 768 byte packets.)
+ *
+ * Interrupt-only endpoints are less functional than bulk endpoints, for
+ * example by not supporting queueing or not handling buffers that are
+ * larger than the endpoint's maxpacket size. They may also treat data
+ * toggle differently.
+ *
+ * Control endpoints ... after getting a setup() callback, the driver queues
+ * one response (optional if it would be zero length). That enables the
+ * status ack, after transfering data as specified in the response. Setup
+ * functions may return negative error codes to generate protocol stalls.
+ *
+ * For periodic endpoints, like interrupt or isochronous ones, the usb host
+ * arranges to poll once per interval, and the gadget driver usually will
+ * have queued some data to transfer at that time.
+ *
+ * Returns zero, or a negative error code. Endpoints that are not enabled,
+ * or which are enabled but halted, report errors; errors will also be
+ * reported when the usb peripheral is disconnected.
+ */
+static inline int
+usb_ep_queue (struct usb_ep *ep, struct usb_request *req, int gfp_flags)
+{
+ return ep->ops->queue (ep, req, gfp_flags);
+}
+
+/**
+ * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint
+ * @ep:the endpoint associated with the request
+ * @req:the request being canceled
+ *
+ * if the request is still active on the endpoint, it is dequeued and its
+ * completion routine is called (with status -ECONNRESET); else a negative
+ * error code is returned.
+ *
+ * note that some hardware can't clear out write fifos (to unlink the request
+ * at the head of the queue) except as part of disconnecting from usb. such
+ * restrictions prevent drivers from supporting configuration changes,
+ * even to configuration zero (a "chapter 9" requirement).
+ */
+static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
+{
+ return ep->ops->dequeue (ep, req);
+}
+
+/**
+ * usb_ep_set_halt - sets the endpoint halt feature.
+ * @ep: the non-isochronous endpoint being stalled
+ *
+ * Use this to stall an endpoint, perhaps as an error report.
+ * Except for control endpoints,
+ * the endpoint stays halted (will not stream any data) until the host
+ * clears this feature; drivers may need to empty the endpoint's request
+ * queue first, to make sure no inappropriate transfers happen.
+ *
+ * Returns zero, or a negative error code. On success, this call sets
+ * underlying hardware state that blocks data transfers.
+ */
+static inline int
+usb_ep_set_halt (struct usb_ep *ep)
+{
+ return ep->ops->set_halt (ep, 1);
+}
+
+/**
+ * usb_ep_clear_halt - clears endpoint halt, and resets toggle
+ * @ep:the bulk or interrupt endpoint being reset
+ *
+ * use this when responding to the standard usb "set interface" request,
+ * for endpoints that aren't reconfigured, after clearing any other state
+ * in the endpoint's i/o queue.
+ *
+ * returns zero, or a negative error code. on success, this call clears
+ * the underlying hardware state reflecting endpoint halt and data toggle.
+ */
+static inline int
+usb_ep_clear_halt (struct usb_ep *ep)
+{
+ return ep->ops->set_halt (ep, 0);
+}
+
+/**
+ * usb_ep_fifo_status - returns number of bytes in fifo, or error
+ * @ep: the endpoint whose fifo status is being checked.
+ *
+ * FIFO endpoints may have "unclaimed data" in them in certain cases,
+ * such as after aborted transfers. Hosts may not have collected all
+ * the IN data written by the gadget driver, as reported by a request
+ * completion. The gadget driver may not have collected all the data
+ * written OUT to it by the host. Drivers that need precise handling for
+ * fault reporting or recovery may need to use this call.
+ *
+ * This returns the number of such bytes in the fifo, or a negative
+ * errno if the endpoint doesn't use a FIFO or doesn't support such
+ * precise handling.
+ */
+static inline int
+usb_ep_fifo_status (struct usb_ep *ep)
+{
+ if (ep->ops->fifo_status)
+ return ep->ops->fifo_status (ep);
+ else
+ return -EOPNOTSUPP;
+}
+
+/**
+ * usb_ep_fifo_flush - flushes contents of a fifo
+ * @ep: the endpoint whose fifo is being flushed.
+ *
+ * This call may be used to flush the "unclaimed data" that may exist in
+ * an endpoint fifo after abnormal transaction terminations. The call
+ * must never be used except when endpoint is not being used for any
+ * protocol translation.
+ */
+static inline void
+usb_ep_fifo_flush (struct usb_ep *ep)
+{
+ if (ep->ops->fifo_flush)
+ ep->ops->fifo_flush (ep);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_gadget;
+
+/* the rest of the api to the controller hardware: device operations,
+ * which don't involve endpoints (or i/o).
+ */
+struct usb_gadget_ops {
+ int (*get_frame)(struct usb_gadget *);
+ int (*wakeup)(struct usb_gadget *);
+ int (*set_selfpowered) (struct usb_gadget *, int value);
+ int (*ioctl)(struct usb_gadget *,
+ unsigned code, unsigned long param);
+};
+
+/**
+ * struct usb_gadget - represents a usb slave device
+ * @ep0: Endpoint zero, used when reading or writing responses to
+ * driver setup() requests
+ * @ep_list: List of other endpoints supported by the device.
+ * @speed: Speed of current connection to USB host.
+ * @name: Identifies the controller hardware type. Used in diagnostics
+ * and sometimes configuration.
+ *
+ * Gadgets have a mostly-portable "gadget driver" implementing device
+ * functions, handling all usb configurations and interfaces. They
+ * also have a hardware-specific driver (accessed through ops vectors),
+ * which insulates the gadget driver from hardware details and packages
+ * the hardware endpoints through generic i/o queues.
+ *
+ * Except for the driver data, all fields in this structure are
+ * read-only to the gadget driver. That driver data is part of the
+ * "driver model" infrastructure in 2.5 (and later) kernels, and for
+ * earlier systems is grouped in a similar structure that's not known
+ * to the rest of the kernel.
+ */
+struct usb_gadget {
+ /* readonly to gadget driver */
+ const struct usb_gadget_ops *ops;
+ struct usb_ep *ep0;
+ struct list_head ep_list; /* of usb_ep */
+ enum usb_device_speed speed;
+ const char *name;
+
+ /* use this to allocate dma-coherent buffers or set up
+ * dma mappings. or print diagnostics, etc.
+ */
+ struct device dev;
+};
+
+static inline void set_gadget_data (struct usb_gadget *gadget, void *data)
+ { dev_set_drvdata (&gadget->dev, data); }
+static inline void *get_gadget_data (struct usb_gadget *gadget)
+ { return dev_get_drvdata (&gadget->dev); }
+
+/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
+#define gadget_for_each_ep(tmp,gadget) \
+ list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
+
+
+/**
+ * usb_gadget_frame_number - returns the current frame number
+ * @gadget: controller that reports the frame number
+ *
+ * Returns the usb frame number, normally eleven bits from a SOF packet,
+ * or negative errno if this device doesn't support this capability.
+ */
+static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
+{
+ return gadget->ops->get_frame (gadget);
+}
+
+/**
+ * usb_gadget_wakeup - tries to wake up the host connected to this gadget
+ * @gadget: controller used to wake up the host
+ *
+ * Returns zero on success, else negative error code if the hardware
+ * doesn't support such attempts, or its support has not been enabled
+ * by the usb host. Drivers must return device descriptors that report
+ * their ability to support this, or hosts won't enable it.
+ */
+static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
+{
+ if (!gadget->ops->wakeup)
+ return -EOPNOTSUPP;
+ return gadget->ops->wakeup (gadget);
+}
+
+/**
+ * usb_gadget_set_selfpowered - sets the device selfpowered feature.
+ * @gadget:the device being declared as self-powered
+ *
+ * this affects the device status reported by the hardware driver
+ * to reflect that it now has a local power supply.
+ *
+ * returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_set_selfpowered (struct usb_gadget *gadget)
+{
+ if (!gadget->ops->set_selfpowered)
+ return -EOPNOTSUPP;
+ return gadget->ops->set_selfpowered (gadget, 1);
+}
+
+/**
+ * usb_gadget_clear_selfpowered - clear the device selfpowered feature.
+ * @gadget:the device being declared as bus-powered
+ *
+ * this affects the device status reported by the hardware driver.
+ * some hardware may not support bus-powered operation, in which
+ * case this feature's value can never change.
+ *
+ * returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
+{
+ if (!gadget->ops->set_selfpowered)
+ return -EOPNOTSUPP;
+ return gadget->ops->set_selfpowered (gadget, 0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * struct usb_gadget_driver - driver for usb 'slave' devices
+ * @function: String describing the gadget's function
+ * @speed: Highest speed the driver handles.
+ * @bind: Invoked when the driver is bound to a gadget, usually
+ * after registering the driver.
+ * At that point, ep0 is fully initialized, and ep_list holds
+ * the currently-available endpoints.
+ * Called in a context that permits sleeping.
+ * @setup: Invoked for ep0 control requests that aren't handled by
+ * the hardware level driver. Most calls must be handled by
+ * the gadget driver, including descriptor and configuration
+ * management. The 16 bit members of the setup data are in
+ * cpu order. Called in_interrupt; this may not sleep. Driver
+ * queues a response to ep0, or returns negative to stall.
+ * @disconnect: Invoked after all transfers have been stopped,
+ * when the host is disconnected. May be called in_interrupt; this
+ * may not sleep.
+ * @unbind: Invoked when the driver is unbound from a gadget,
+ * usually from rmmod (after a disconnect is reported).
+ * Called in a context that permits sleeping.
+ * @suspend: Invoked on USB suspend. May be called in_interrupt.
+ * @resume: Invoked on USB resume. May be called in_interrupt.
+ *
+ * Devices are disabled till a gadget driver successfully bind()s, which
+ * means the driver will handle setup() requests needed to enumerate (and
+ * meet "chapter 9" requirements) then do some useful work.
+ *
+ * Drivers use hardware-specific knowledge to configure the usb hardware.
+ * endpoint addressing is only one of several hardware characteristics that
+ * are in descriptors the ep0 implementation returns from setup() calls.
+ *
+ * Except for ep0 implementation, most driver code shouldn't need change to
+ * run on top of different usb controllers. It'll use endpoints set up by
+ * that ep0 implementation.
+ *
+ * The usb controller driver handles a few standard usb requests. Those
+ * include set_address, and feature flags for devices, interfaces, and
+ * endpoints (the get_status, set_feature, and clear_feature requests).
+ *
+ * Accordingly, the driver's setup() callback must always implement all
+ * get_descriptor requests, returning at least a device descriptor and
+ * a configuration descriptor. Drivers must make sure the endpoint
+ * descriptors match any hardware constraints. Some hardware also constrains
+ * other descriptors. (The pxa250 allows only configurations 1, 2, or 3).
+ *
+ * The driver's setup() callback must also implement set_configuration,
+ * and should also implement set_interface, get_configuration, and
+ * get_interface. Setting a configuration (or interface) is where
+ * endpoints should be activated or (config 0) shut down.
+ *
+ * (Note that only the default control endpoint is supported. Neither
+ * hosts nor devices generally support control traffic except to ep0.)
+ *
+ * Most devices will ignore USB suspend/resume operations, and so will
+ * not provide those callbacks. However, some may need to change modes
+ * when the host is not longer directing those activities. For example,
+ * local controls (buttons, dials, etc) may need to be re-enabled since
+ * the (remote) host can't do that any longer.
+ */
+struct usb_gadget_driver {
+ char *function;
+ enum usb_device_speed speed;
+ int (*bind)(struct usb_gadget *);
+ void (*unbind)(struct usb_gadget *);
+ int (*setup)(struct usb_gadget *,
+ const struct usb_ctrlrequest *);
+ void (*disconnect)(struct usb_gadget *);
+ void (*suspend)(struct usb_gadget *);
+ void (*resume)(struct usb_gadget *);
+
+ // FIXME support safe rmmod
+ struct device_driver driver;
+};
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/* driver modules register and unregister, as usual.
+ * these calls must be made in a context that can sleep.
+ *
+ * these will usually be implemented directly by the hardware-dependent
+ * usb bus interface driver, which will only support a single driver.
+ */
+
+/**
+ * usb_gadget_register_driver - register a gadget driver
+ * @driver:the driver being registered
+ *
+ * Call this in your gadget driver's module initialization function,
+ * to tell the underlying usb controller driver about your driver.
+ * The driver's bind() function will be called to bind it to a
+ * gadget. This function must be called in a context that can sleep.
+ */
+int usb_gadget_register_driver (struct usb_gadget_driver *driver);
+
+/**
+ * usb_gadget_unregister_driver - unregister a gadget driver
+ * @driver:the driver being unregistered
+ *
+ * Call this in your gadget driver's module cleanup function,
+ * to tell the underlying usb controller that your driver is
+ * going away. If the controller is connected to a USB host,
+ * it will first disconnect(). The driver is also requested
+ * to unbind() and clean up any device state, before this procedure
+ * finally returns.
+ * This function must be called in a context that can sleep.
+ */
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
+
+/*-------------------------------------------------------------------------*/
+
+/* utility to simplify dealing with string descriptors */
+
+/**
+ * struct usb_string - wraps a C string and its USB id
+ * @id:the (nonzero) ID for this string
+ * @s:the string, in ISO-8859/1 characters
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap a string
+ * together with its ID.
+ */
+struct usb_string {
+ u8 id;
+ const char *s;
+};
+
+/**
+ * struct usb_gadget_strings - a set of USB strings in a given language
+ * @language:identifies the strings' language (0x0409 for en-us)
+ * @strings:array of strings with their ids
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap all the
+ * strings for a given language.
+ */
+struct usb_gadget_strings {
+ u16 language; /* 0x0409 for en-us */
+ struct usb_string *strings;
+};
+
+/* put descriptor for string with that id into buf (buflen >= 256) */
+int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
+
+
+#endif /* __KERNEL__ */
+
+#endif /* __LINUX_USB_GADGET_H */