Update: USB "gadget" API [3 of 3]
From: | David Brownell <david-b@pacbell.net> | |
To: | linux-usb-devel@lists.sourceforge.net | |
Subject: | [linux-usb-devel] Update: USB "gadget" API [3 of 3] | |
Date: | Fri, 07 Feb 2003 10:21:59 -0800 |
This is IMO more interesting/suggestive than just the API spec, which has been posted before ... it's a driver using the API! So it lets you see the kinds of issues that a USB "gadget" driver will need to deal with, and how they're handled. Things to notice (and maybe comment on) as you skim this: - Ready to run on three different kinds of controller, with different capabilities. This uses compile-time configuration to statically define most descriptors. - String and configuration descriptors are computed on the fly ... including "other speed" descriptors. - Almost all ep0 logic is part of the gadget driver. - Configuration management is handled by the gadget driver ... or at any rate, not by the lower level hardware driver, which can't know how the gadget wants to expose hardware capabilities. - Two configurations advertised. Source/sink is now working. Loopback isn't quite coded yet (sorry!) Only uses two of N potential hardware endpoints. - Handles 2.4 and 2.5 environments, with minor rough spots (and unfinished bits) in both. Gadget drivers can be simpler than this ... perhaps by not supporting high speed operation, multiple configurations, or more than one kind of usb peripheral hardware. Since I think the "reusable code" case has to be the main goal of API designs, "Gadget Zero" should a good example to start with: it's a realistic level of complexity for everything except the functions (source/sink, loopback) that it's implementing. Those functions hardly take up any code -- just read/write buffers to endpoints -- and that's where a "real" driver would be most different. If you have a driver for USB peripheral/device hardware that can support "Gadget Zero" (*), you can write a similar gadget driver to implement a lot of other USB functions: storage, networking, printer, scanner, HID, TTY, and more. ISO transfers would be a bit different, since there's a lot of hardware that doesn't support it, but the I/O calls would work the same for endpoints that are configured as ISO: just queue the request, and catch its completion. Comments? - Dave (*) In the works ... stay tuned! /* * zero.c -- Gadget Zero, for USB development * * 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 */ /* * 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. * * 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). */ #include <linux/config.h> //#ifdef CONFIG_USB_DEBUG # define DEBUG 1 //#endif #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 <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 __DATE__ 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"; /* for device descriptor ... these are what 'usb-skeleton' uses. * in this driver, DRIVER_VERSION_NUM is hardware-specific. */ #define DRIVER_VENDOR_NUM 0xfff0 /* buy one from usb-if */ #define DRIVER_PRODUCT_NUM 0xfff0 /* then pick this */ /*-------------------------------------------------------------------------*/ /* * 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 * * 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 */ #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. */ #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 */ #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? */ #endif /*-------------------------------------------------------------------------*/ #ifndef EP0_MAXPACKET # error "configure some usb device 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 or 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_request *in, *out; struct usb_ep *in_ep, *out_ep; }; #ifdef HAVE_DRIVER_MODEL #define xprintk(dev,level,fmt,args...) \ dev_printk(level , &dev->gadget->dev , fmt , ## args) #else #define xprintk(dev,level,fmt,args...) \ printk(level "%s %s: " fmt , shortname, dev->gadget->bus_id , ## args) #endif /* HAVE_DRIVER_MODEL */ #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) /*-------------------------------------------------------------------------*/ /* * 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 */ /* Dynamically construct most strings; it's easier that way. */ static const u8 string0 [] = { 4, USB_DT_STRING, /* length of string0, descriptor tag */ 0x09, 0x04, /* en-us */ }; static char serial [40]; static const int get_string (int n, u8 *buf) { const char *s; int len; switch (n) { case 0: /* return language id(s) */ memcpy (buf, string0, sizeof string0); return sizeof string0; default: /* unrecognized: stall. */ return -EINVAL; /* these constant strings MUST be in iso-8859-1 */ case STRING_MANUFACTURER: s = UTS_SYSNAME " " UTS_RELEASE " with " CHIP; break; case STRING_PRODUCT: s = longname; break; case STRING_SERIAL: s = serial; break; case STRING_SOURCE_SINK: s = source_sink; break; case STRING_LOOPBACK: s = loopback; break; } /* string descriptors have length, tag, then UTF16-LE text */ len = min ((size_t) 127, strlen (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 [len - 1]; len--; } return buf [0]; } /* * config descriptors are also handcrafted. these must agree with code * that sets configurations, and with code managing interface altsettings. * other complexity may come from from: * * - high speed support, including "other speed config" rules * - multiple configurations * - interfaces with atlernate 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 including altsettings to test interrupt transfers, including * high bandwidth modes at high speed. */ static int config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index) { 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; /* config (or other speed config) */ if (index == 0) 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 (index == 0) 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; } /*-------------------------------------------------------------------------*/ /* 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->length; 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 void reinit_write_data ( struct zero_dev *dev, struct usb_ep *ep, struct usb_request *req ) { } /* 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. */ 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 */ DEBUG (dev, "%s off, %d/%d\n", ep->name, req->actual, req->length); goto stop_ep; case -ESHUTDOWN: /* disconnect from host */ DEBUG (dev, "%s disconnect, %d/%d\n", ep->name, req->actual, req->length); goto stop_ep; case -EOVERFLOW: /* buffer overrun */ 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 */ } return; stop_ep: // spin_lock (&dev->lock); usb_ep_free_buffer (ep, req->buf, req->dma, req->length); usb_ep_free_request (ep, req); if (req == dev->in) { dev->in = 0; usb_ep_disable (dev->in_ep); dev->in_ep = 0; } else { dev->out = 0; usb_ep_disable (dev->out_ep); dev->out_ep = 0; } // spin_unlock (&dev->lock); } static int buflen = 4096; MODULE_PARM (buflen, "i"); MODULE_PARM_DESC (buflen, "size of source/sink buffers"); static struct usb_request * source_sink_start_ep (struct usb_ep *ep, int gfp_flags) { struct usb_request *req; int status; req = usb_ep_alloc_request (ep, gfp_flags); if (!req) return 0; req->length = buflen; req->buf = usb_ep_alloc_buffer (ep, req->length, &req->dma, gfp_flags); if (!req->buf) { usb_ep_free_request (ep, 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); usb_ep_free_buffer (ep, req->buf, req->dma, req->length); usb_ep_free_request (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; dev->in = source_sink_start_ep (ep, gfp_flags); if (dev->in) { 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; dev->out = source_sink_start_ep (ep, gfp_flags); if (dev->out) { 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; } /* caller is responsible for cleanup on error */ return result; } /*-------------------------------------------------------------------------*/ static int set_loopback_config (struct zero_dev *dev, int gfp_flags) { /* * FIXME: * - start by posting a one packet read on dev->out * - dev->out completion writes that packet on dev->in, * and posts a new one packet read on dev->out * - dev->in completion can free the request and its buffer * - optionally queue multiple requests on dev->out * * We succeed here (for now) to look more ch9-compliant. */ WARN (dev, "not really setting up a loopback config yet\n"); return 0; } /*-------------------------------------------------------------------------*/ /* returns nonzero if completion irq(s) needed */ static int zero_reset_config (struct zero_dev *dev) { int synch = 0; int stat; if (dev->config == 0) return 0; DEBUG (dev, "reset config\n"); /* stop any i/o we started. completion callback * is what disables the endpoints. */ if (dev->in_ep) { stat = usb_ep_dequeue (dev->in_ep, dev->in); DEBUG (dev, "ep dq --> %d\n", stat); synch = 1; } if (dev->out_ep) { stat = usb_ep_dequeue (dev->out_ep, dev->out); DEBUG (dev, "ep dq --> %d\n", stat); synch = 1; } dev->config = 0; return synch; } /* 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 if (zero_reset_config (dev)) { // FIXME this is a synchronization problem. // we can't exactly wait for IRQs here... // ... but the endpoint may still be tied up!!! WARN (dev, "no wait for completion irqs (1) ...\n"); } 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 || !dev->out)) result = -ENODEV; if (result) { if (zero_reset_config (dev)) { // FIXME as above, but not very troublesome // unless the next SET_CONFIGURATION request // comes in _really_ quickly. WARN (dev, "no wait for completion irqs (2) ...\n"); } } 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) { struct zero_dev *dev = ep->driver_data; DEBUG (dev, "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; req->complete = zero_setup_complete; /* usually this copies into the pre-allocated ep0 buffer, * but config change events will reconfigure hardware. */ switch (ctrl->bRequest) { case USB_REQ_GET_DESCRIPTOR: if (ctrl->bRequestType != 0x80) 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 = get_string (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 != ... 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 != ... *(u8 *)req->buf = dev->config; value = min (ctrl->wLength, (u16) 1); break; /* until we add altsetting support, only 0/0 are possible */ case USB_REQ_SET_INTERFACE: // if ctrl->bRequestType != ... spin_lock (&dev->lock); if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) { /* change hardware configuration! * no response queued, just zero status == success */ usb_ep_clear_halt (dev->in_ep); usb_ep_clear_halt (dev->out_ep); value = 0; } spin_unlock (&dev->lock); break; case USB_REQ_GET_INTERFACE: // if ctrl->bRequestType != ... if (ctrl->wIndex != 0) { value = -EDOM; break; } *(u8 *)req->buf = 0; value = min (ctrl->wLength, (u16) 1); break; default: DEBUG (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); } } /* host 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); 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) { if (dev->req->buf) usb_ep_free_buffer (gadget->ep0, dev->req->buf, dev->req->dma, USB_BUFSIZ); usb_ep_free_request (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); /* 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->gadget = gadget; set_gadget_data (gadget, dev); gadget->ep0->driver_data = dev; INFO (dev, "%s, driver " 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, #ifdef HAVE_DRIVER_MODEL .driver = { .name = (char *) shortname, // .shutdown = ... // .suspend = ... // .resume = ... }, #else .name = (char *) shortname, #endif }; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,40) MODULE_DESCRIPTION (longname); #endif MODULE_AUTHOR ("David Brownell"); MODULE_LICENSE ("GPL"); static int __init init (void) { /* real value would likely come through some id prom */ 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);