patch-2.4.27 linux-2.4.27/drivers/usb/gadget/zero.c
Next file: linux-2.4.27/drivers/usb/hiddev.c
Previous file: linux-2.4.27/drivers/usb/gadget/usbstring.c
Back to the patch index
Back to the overall index
- Lines: 484
- Date:
2004-08-07 16:26:05.703389881 -0700
- Orig file:
linux-2.4.26/drivers/usb/gadget/zero.c
- Orig date:
2004-04-14 06:05:32.000000000 -0700
diff -urN linux-2.4.26/drivers/usb/gadget/zero.c linux-2.4.27/drivers/usb/gadget/zero.c
@@ -87,10 +87,12 @@
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
+#include "gadget_chips.h"
+
/*-------------------------------------------------------------------------*/
-#define DRIVER_VERSION "Bastille Day 2003"
+#define DRIVER_VERSION "St Patrick's Day 2004"
static const char shortname [] = "zero";
static const char longname [] = "Gadget Zero";
@@ -103,100 +105,12 @@
/*
* driver assumes self-powered hardware, and
* has no way for users to trigger remote wakeup.
- */
-
-/*
- * hardware-specific configuration, controlled by which device
- * controller driver was configured.
- *
- * CHIP ... hardware identifier
- * DRIVER_VERSION_NUM ... alerts the host side driver to differences
- * EP_*_NAME ... which endpoints do we use for which purpose?
- * EP_*_NUM ... numbers for them (often limited by hardware)
*
- * add other defines for other portability issues, like hardware that
- * for some reason doesn't handle full speed bulk maxpacket of 64.
+ * this version autoconfigures as much as possible,
+ * which is reasonable for most "bulk-only" drivers.
*/
-
-/*
- * 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_GADGET_NET2280
-#define CHIP "net2280"
-#define DRIVER_VERSION_NUM 0x0111
-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
-#endif
-
-/*
- * PXA-2xx 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.
- *
- * These supports three or four configurations, with fixed numbers.
- * The hardware interprets SET_INTERFACE, net effect is that you
- * can't use altsettings or reset the interfaces independently.
- * So stick to a single interface.
- */
-#ifdef CONFIG_USB_GADGET_PXA2XX
-#define CHIP "pxa2xx"
-#define DRIVER_VERSION_NUM 0x0113
-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
-#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_GADGET_SA1100
-#define CHIP "sa1100"
-#define DRIVER_VERSION_NUM 0x0115
-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
-#endif
-
-/*
- * Toshiba TC86C001 ("Goku-S") UDC
- *
- * This has three semi-configurable full speed bulk/interrupt endpoints.
- */
-#ifdef CONFIG_USB_GADGET_GOKU
-#define CHIP "goku"
-#define DRIVER_VERSION_NUM 0x0116
-static const char EP_OUT_NAME [] = "ep1-bulk";
-#define EP_OUT_NUM 1
-static const char EP_IN_NAME [] = "ep2-bulk";
-#define EP_IN_NUM 2
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-#ifndef EP_OUT_NUM
-# error Configure some USB peripheral controller driver!
-#endif
+static const char *EP_IN_NAME; /* source */
+static const char *EP_OUT_NAME; /* sink */
/*-------------------------------------------------------------------------*/
@@ -214,6 +128,9 @@
*/
u8 config;
struct usb_ep *in_ep, *out_ep;
+
+ /* autoresume timer */
+ struct timer_list resume;
};
#define xprintk(d,level,fmt,args...) \
@@ -221,20 +138,19 @@
## args)
#ifdef DEBUG
-#undef DEBUG
-#define DEBUG(dev,fmt,args...) \
+#define DBG(dev,fmt,args...) \
xprintk(dev , KERN_DEBUG , fmt , ## args)
#else
-#define DEBUG(dev,fmt,args...) \
+#define DBG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
-#define VDEBUG DEBUG
+#define VDBG DBG
#else
-#define VDEBUG(dev,fmt,args...) \
+#define VDBG(dev,fmt,args...) \
do { } while (0)
-#endif /* DEBUG */
+#endif /* VERBOSE */
#define ERROR(dev,fmt,args...) \
xprintk(dev , KERN_ERR , fmt , ## args)
@@ -270,6 +186,13 @@
MODULE_PARM (loopdefault, "b");
MODULE_PARM_DESC (loopdefault, "true to have default config be loopback");
+/*
+ * if it's nonzero, autoresume says how many seconds to wait
+ * before trying to wake up the host after suspend.
+ */
+static unsigned autoresume = 0;
+MODULE_PARM (autoresume, "i");
+
/*-------------------------------------------------------------------------*/
/* Thanks to NetChip Technologies for donating this product ID.
@@ -310,14 +233,13 @@
.idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
.idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
- .bcdDevice = __constant_cpu_to_le16 (DRIVER_VERSION_NUM),
.iManufacturer = STRING_MANUFACTURER,
.iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIAL,
.bNumConfigurations = 2,
};
-static const struct usb_config_descriptor
+static struct usb_config_descriptor
source_sink_config = {
.bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -330,7 +252,7 @@
.bMaxPower = 1, /* self-powered */
};
-static const struct usb_config_descriptor
+static struct usb_config_descriptor
loopback_config = {
.bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -367,24 +289,22 @@
/* two full speed bulk endpoints; their use is config-dependent */
-static const struct usb_endpoint_descriptor
+static struct usb_endpoint_descriptor
fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = EP_IN_NUM | USB_DIR_IN,
+ .bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (64),
};
-static const struct usb_endpoint_descriptor
+static struct usb_endpoint_descriptor
fs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = EP_OUT_NUM,
+ .bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (64),
};
static const struct usb_descriptor_header *fs_source_sink_function [] = {
@@ -648,7 +568,7 @@
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
- VDEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+ VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
req->actual, req->length);
if (ep == dev->out_ep)
check_read_data (dev, ep, req);
@@ -661,7 +581,7 @@
*/
default:
#if 1
- DEBUG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+ DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
#endif
case -EREMOTEIO: /* short read */
@@ -752,7 +672,7 @@
break;
}
if (result == 0)
- DEBUG (dev, "buflen %d\n", buflen);
+ DBG (dev, "buflen %d\n", buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -863,14 +783,14 @@
req->complete = loopback_complete;
result = usb_ep_queue (ep, req, GFP_ATOMIC);
if (result)
- DEBUG (dev, "%s queue req --> %d\n",
+ DBG (dev, "%s queue req --> %d\n",
ep->name, result);
} else
result = -ENOMEM;
}
}
if (result == 0)
- DEBUG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+ DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -883,7 +803,7 @@
if (dev->config == 0)
return;
- DEBUG (dev, "reset config\n");
+ DBG (dev, "reset config\n");
/* just disable endpoints, forcing completion of pending i/o.
* all our completion handlers free their requests in this case.
@@ -918,13 +838,11 @@
if (number == dev->config)
return 0;
-#ifdef CONFIG_USB_GADGET_SA1100
- if (dev->config) {
+ if (gadget_is_sa1100 (gadget) && 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);
switch (number) {
@@ -968,7 +886,7 @@
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,
+ DBG ((struct zero_dev *) ep->driver_data,
"setup complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
}
@@ -1116,7 +1034,7 @@
default:
unknown:
- VDEBUG (dev,
+ VDBG (dev,
"unknown control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
ctrl->wValue, ctrl->wIndex, ctrl->wLength);
@@ -1127,7 +1045,7 @@
req->length = value;
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
- DEBUG (dev, "ep_queue --> %d\n", value);
+ DBG (dev, "ep_queue --> %d\n", value);
req->status = 0;
zero_setup_complete (gadget->ep0, req);
}
@@ -1157,6 +1075,19 @@
*/
}
+static void
+zero_autoresume (unsigned long _dev)
+{
+ struct zero_dev *dev = (struct zero_dev *) _dev;
+ int status;
+
+ /* normally the host would be woken up for something
+ * more significant than just a timer firing...
+ */
+ status = usb_gadget_wakeup (dev->gadget);
+ DBG (dev, "wakeup --> %d\n", status);
+}
+
/*-------------------------------------------------------------------------*/
static void
@@ -1164,11 +1095,12 @@
{
struct zero_dev *dev = get_gadget_data (gadget);
- DEBUG (dev, "unbind\n");
+ DBG (dev, "unbind\n");
/* we've already been disconnected ... no i/o is active */
if (dev->req)
free_ep_req (gadget->ep0, dev->req);
+ del_timer_sync (&dev->resume);
kfree (dev);
set_gadget_data (gadget, 0);
}
@@ -1177,7 +1109,70 @@
zero_bind (struct usb_gadget *gadget)
{
struct zero_dev *dev;
+ struct usb_ep *ep;
+
+ /* Bulk-only drivers like this one SHOULD be able to
+ * autoconfigure on any sane usb controller driver,
+ * but there may also be important quirks to address.
+ */
+ usb_ep_autoconfig_reset (gadget);
+ ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+ if (!ep) {
+autoconf_fail:
+ printk (KERN_ERR "%s: can't autoconfigure on %s\n",
+ shortname, gadget->name);
+ return -ENODEV;
+ }
+ EP_IN_NAME = ep->name;
+ ep->driver_data = ep; /* claim */
+
+ ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+ if (!ep)
+ goto autoconf_fail;
+ EP_OUT_NAME = ep->name;
+ ep->driver_data = ep; /* claim */
+
+
+ /*
+ * DRIVER POLICY CHOICE: you may want to do this differently.
+ * One thing to avoid is reusing a bcdDevice revision code
+ * with different host-visible configurations or behavior
+ * restrictions -- using ep1in/ep2out vs ep1out/ep3in, etc
+ */
+ if (gadget_is_net2280 (gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0201);
+ } else if (gadget_is_pxa (gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0203);
+#if 0
+ } else if (gadget_is_sh(gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0204);
+ /* SH has only one configuration; see "loopdefault" */
+ device_desc.bNumConfigurations = 1;
+ /* FIXME make 1 == default.bConfigurationValue */
+#endif
+ } else if (gadget_is_sa1100 (gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0205);
+ } else if (gadget_is_goku (gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0206);
+ } else if (gadget_is_mq11xx (gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0207);
+ } else if (gadget_is_omap (gadget)) {
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x0208);
+ } else {
+ /* gadget zero is so simple (for now, no altsettings) that
+ * it SHOULD NOT have problems with bulk-capable hardware.
+ * so warn about unrcognized controllers, don't panic.
+ *
+ * things like configuration and altsetting numbering
+ * can need hardware-specific attention though.
+ */
+ printk (KERN_WARNING "%s: controller '%s' not recognized\n",
+ shortname, gadget->name);
+ device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
+ }
+
+ /* ok, we made sense of the hardware ... */
dev = kmalloc (sizeof *dev, SLAB_KERNEL);
if (!dev)
return -ENOMEM;
@@ -1208,6 +1203,16 @@
hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
#endif
+ usb_gadget_set_selfpowered (gadget);
+
+ init_timer (&dev->resume);
+ dev->resume.function = zero_autoresume;
+ dev->resume.data = (unsigned long) dev;
+ if (autoresume) {
+ source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ }
+
gadget->ep0->driver_data = dev;
INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
@@ -1227,6 +1232,33 @@
/*-------------------------------------------------------------------------*/
+static void
+zero_suspend (struct usb_gadget *gadget)
+{
+ struct zero_dev *dev = get_gadget_data (gadget);
+
+ if (gadget->speed == USB_SPEED_UNKNOWN)
+ return;
+
+ if (autoresume) {
+ mod_timer (&dev->resume, jiffies + (HZ * autoresume));
+ DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+ } else
+ DBG (dev, "suspend\n");
+}
+
+static void
+zero_resume (struct usb_gadget *gadget)
+{
+ struct zero_dev *dev = get_gadget_data (gadget);
+
+ DBG (dev, "resume\n");
+ del_timer (&dev->resume);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
static struct usb_gadget_driver zero_driver = {
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
@@ -1240,6 +1272,9 @@
.setup = zero_setup,
.disconnect = zero_disconnect,
+ .suspend = zero_suspend,
+ .resume = zero_resume,
+
.driver = {
.name = (char *) shortname,
// .shutdown = ...
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)