Index: firmware/export/usb_gadget.h =================================================================== --- firmware/export/usb_gadget.h (revision 0) +++ firmware/export/usb_gadget.h (revision 0) @@ -0,0 +1,884 @@ +/* + * + * + * 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-2004 by David Brownell + * All Rights Reserved. + * + * This software is licensed under the GNU GPL version 2. + */ + +#ifndef __LINUX_USB_GADGET_H +#define __LINUX_USB_GADGET_H + +#include +#include + +/* TODO move this macro? */ +/* more about this macro: http://www.kroah.com/log/linux/container_of.html */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#include "usb_ch9.h" + +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. + * @length: Length of that data + * @no_interrupt: If true, hints that no completion irq is needed. + * Helpful sometimes with deep request queues that are handled + * directly by DMA controllers. + * @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, so this request and + * its buffer may be re-used. + * Reads terminate with a short packet, or when the buffer fills, + * whichever comes first. When writes terminate, some data bytes + * will usually still be in flight (often in a hardware fifo). + * Errors (for reads or writes) stop the queue from advancing + * until the completion function returns, so that any transfers + * invalidated by the error may first be dequeued. + * @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 bytes transferred to/from the buffer. 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) some data bytes may still + * reside in a device-side FIFO when the request is reported as + * complete. + * + * 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. + +struct usb_request { + void *buf; + unsigned length; + + unsigned no_interrupt:1; + unsigned zero:1; + unsigned 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/*, + gfp_t 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, gfp_t gfp_flags); + void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma, + unsigned bytes);*/ + // NOTE: on 2.6, drivers may also use dma_map() and + // dma_sync_single_*() to directly manage dma overhead. + + int (*queue) (struct usb_ep *ep, struct usb_request *req/*, + gfp_t 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" + * @ops: Function pointers used to access hardware-specific operations. + * @ep_list:the gadget's ep_list holds all of its endpoints + * @maxpacket:The maximum packet size used on this endpoint. The initial + * value can sometimes be reduced (hardware allowing), according to + * the endpoint descriptor used to configure the endpoint. + * @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/*, gfp_t 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, + gfp_t 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. + * Drivers can rely on the fact that the first byte of the request's buffer + * always corresponds to the first byte of some USB packet, for both + * IN and OUT transfers. + * + * 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 (even 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. + * (Note that some USB device controllers disallow protocol stall responses + * in some cases.) When control responses are deferred (the response is + * written after the setup callback returns), then usb_ep_set_halt() may be + * used on ep0 to trigger 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 + * 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/*, gfp_t 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. + * + * Note that while an endpoint CLEAR_FEATURE will be invisible to the + * gadget driver, a SET_INTERFACE will not be. To reset endpoints for the + * current altsetting, see usb_ep_clear_halt(). When switching altsettings, + * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints. + * + * Returns zero, or a negative error code. On success, this call sets + * underlying hardware state that blocks data transfers. + * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any + * transfer requests are still queued, or if the controller hardware + * (usually a FIFO) still holds bytes that the host hasn't collected. + */ +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. + * Note that some hardware can't support this request (like pxa2xx_udc), + * and accordingly can't correctly implement interface altsettings. + */ +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 (and 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 is_selfpowered); + int (*vbus_session) (struct usb_gadget *, int is_active); + int (*vbus_draw) (struct usb_gadget *, unsigned mA); + int (*pullup) (struct usb_gadget *, int is_on); + int (*ioctl)(struct usb_gadget *, + unsigned code, unsigned long param); +}; + +/** + * struct usb_gadget - represents a usb slave device + * @ops: Function pointers used to access hardware-specific operations. + * @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. + * @is_dualspeed: True if the controller supports both high and full speed + * operation. If it does, the gadget driver must also support both. + * @is_otg: True if the USB device port uses a Mini-AB jack, so that the + * gadget driver must provide a USB OTG descriptor. + * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable + * is in the Mini-AB jack, and HNP has been used to switch roles + * so that the "A" device currently acts as A-Peripheral, not A-Host. + * @a_hnp_support: OTG device feature flag, indicating that the A-Host + * supports HNP at this port. + * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host + * only supports HNP on a different root port. + * @b_hnp_enable: OTG device feature flag, indicating that the A-Host + * enabled HNP support. + * @name: Identifies the controller hardware type. Used in diagnostics + * and sometimes configuration. + * @dev: Driver model state for this abstract device. + * + * Gadgets have a mostly-portable "gadget driver" implementing device + * functions, handling all usb configurations and interfaces. Gadget + * drivers talk to hardware-specific code indirectly, through ops vectors. + * That insulates the gadget driver from hardware details, and packages + * the hardware endpoints through generic i/o queues. The "usb_gadget" + * and "usb_ep" interfaces provide that insulation from the hardware. + * + * 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.6 (and later) kernels, and for + * earlier systems is grouped in a similar structure that's not known + * to the rest of the kernel. + * + * Values of the three OTG device feature flags are updated before the + * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before + * driver suspend() calls. They are valid only when is_otg, and when the + * device is acting as a B-Peripheral (so is_a_peripheral is false). + */ +struct usb_gadget { + /* readonly to gadget driver */ + const struct usb_gadget_ops *ops; + struct usb_ep *ep0; + /*truct list_head ep_list;*/ /* of usb_ep */ + enum usb_device_speed speed; + unsigned is_dualspeed:1; + unsigned is_otg:1; + unsigned is_a_peripheral:1; + unsigned b_hnp_enable:1; + unsigned a_hnp_support:1; + unsigned a_alt_hnp_support:1; + const char *name; +/* 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. + * + * This may also try to use SRP to wake the host and start enumeration, + * even if OTG isn't otherwise in use. OTG devices may also start + * remote wakeup even when hosts don't explicitly 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); +} + +/** + * usb_gadget_vbus_connect - Notify controller that VBUS is powered + * @gadget:The device which now has VBUS power. + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session starting. Common responses include + * resuming the controller, activating the D+ (or D-) pullup to let the + * host detect that a USB device is attached, and starting to draw power + * (8mA or possibly more, especially after SET_CONFIGURATION). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_connect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 1); +} + +/** + * usb_gadget_vbus_draw - constrain controller's VBUS power usage + * @gadget:The device whose VBUS usage is being described + * @mA:How much current to draw, in milliAmperes. This should be twice + * the value listed in the configuration descriptor bMaxPower field. + * + * This call is used by gadget drivers during SET_CONFIGURATION calls, + * reporting how much power the device may consume. For example, this + * could affect how quickly batteries are recharged. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) +{ + if (!gadget->ops->vbus_draw) + return -EOPNOTSUPP; + return gadget->ops->vbus_draw (gadget, mA); +} + +/** + * usb_gadget_vbus_disconnect - notify controller about VBUS session end + * @gadget:the device whose VBUS supply is being described + * + * This call is used by a driver for an external transceiver (or GPIO) + * that detects a VBUS power session ending. Common responses include + * reversing everything done in usb_gadget_vbus_connect(). + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_vbus_disconnect(struct usb_gadget *gadget) +{ + if (!gadget->ops->vbus_session) + return -EOPNOTSUPP; + return gadget->ops->vbus_session (gadget, 0); +} + +/** + * usb_gadget_connect - software-controlled connect to USB host + * @gadget:the peripheral being connected + * + * Enables the D+ (or potentially D-) pullup. The host will start + * enumerating this gadget when the pullup is active and a VBUS session + * is active (the link is powered). This pullup is always enabled unless + * usb_gadget_disconnect() has been used to disable it. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_connect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (gadget, 1); +} + +/** + * usb_gadget_disconnect - software-controlled disconnect from USB host + * @gadget:the peripheral being disconnected + * + * Disables the D+ (or potentially D-) pullup, which the host may see + * as a disconnect (when a VBUS session is active). Not all systems + * support software pullup controls. + * + * This routine may be used during the gadget driver bind() call to prevent + * the peripheral from ever being visible to the USB host, unless later + * usb_gadget_connect() is called. For example, user mode components may + * need to be activated before the system can talk to hosts. + * + * Returns zero on success, else negative errno. + */ +static inline int +usb_gadget_disconnect (struct usb_gadget *gadget) +{ + if (!gadget->ops->pullup) + return -EOPNOTSUPP; + return gadget->ops->pullup (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 + * USB byte 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. Some devices can't detect disconnect, so this might + * not be called except as part of controller shutdown. + * @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. + * @driver: Driver model state for this driver. + * + * 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. + * + * If gadget->is_otg is true, the gadget driver must provide an OTG + * descriptor during enumeration, or else fail the bind() call. In such + * cases, no USB traffic may flow until both bind() returns without + * having called usb_gadget_disconnect(), and the USB host stack has + * initialized. + * + * 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; or an error state might + * be cleared, to make the device behave identically whether or not + * power is maintained. + */ +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 before this registration call returns. It's expected that + * the bind() functions will be in init sections. + * 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. It's expected that the unbind() functions + * will in in exit sections, so may not be linked in some kernels. + * 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 UTF-8 encoding + * + * 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); + +/*-------------------------------------------------------------------------*/ + +/* utility to simplify managing config descriptors */ + +/* write vector of descriptors into buffer */ +int usb_descriptor_fillbuf(void *, unsigned, + const struct usb_descriptor_header **); + +/* build config descriptor from single descriptor vector */ +int usb_gadget_config_buf(const struct usb_config_descriptor *config, + void *buf, unsigned buflen, const struct usb_descriptor_header **desc); + +/*-------------------------------------------------------------------------*/ + +/* utility wrapping a simple endpoint selection policy */ + +extern struct usb_ep *usb_ep_autoconfig (struct usb_gadget *, + struct usb_endpoint_descriptor *); + +extern void usb_ep_autoconfig_reset (struct usb_gadget *); + +#endif /* __LINUX_USB_GADGET_H */ Index: firmware/export/arcotg_udc.h =================================================================== --- firmware/export/arcotg_udc.h (revision 13728) +++ firmware/export/arcotg_udc.h (working copy) @@ -36,8 +36,10 @@ #define __ARCOTG_UDC_H #include "cpu.h" +#include "usb_gadget.h" -#define ETIMEDOUT 1 +#define TRUE 1 +#define FALSE 0 #define USB_MAX_ENDPOINTS 8 #define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2) @@ -312,9 +314,190 @@ #define USB_CTRL_IOENB (0x00000004) #define USB_CTRL_ULPI_INT0EN (0x00000001) +/* Endpoint Queue Head Bit Masks */ +#define EP_QUEUE_HEAD_MULT_POS (30) +#define EP_QUEUE_HEAD_ZLT_SEL (0x20000000) +#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS (16) +#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff) +#define EP_QUEUE_HEAD_IOS (0x00008000) +#define EP_QUEUE_HEAD_NEXT_TERMINATE (0x00000001) +#define EP_QUEUE_HEAD_IOC (0x00008000) +#define EP_QUEUE_HEAD_MULTO (0x00000C00) +#define EP_QUEUE_HEAD_STATUS_HALT (0x00000040) +#define EP_QUEUE_HEAD_STATUS_ACTIVE (0x00000080) +#define EP_QUEUE_CURRENT_OFFSET_MASK (0x00000FFF) +#define EP_QUEUE_HEAD_NEXT_POINTER_MASK (0xFFFFFFE0) +#define EP_QUEUE_FRINDEX_MASK (0x000007FF) +#define EP_MAX_LENGTH_TRANSFER (0x4000) + +/* + * Controller driver data structures + */ + +/* Endpoint Queue Head data struct + * Rem: all the variables of qh are LittleEndian Mode + * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr + */ +struct ep_queue_head { + u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len + * and IOS(15) */ + u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */ + u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */ + u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15), + * MultO(11-10), STS (7-0) */ + u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */ + u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */ + u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */ + u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */ + u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */ + u32 res1; + u8 setup_buffer[8]; /* Setup data 8 bytes */ + u32 res2[4]; /* pad out to 64 bytes */ +}; + +/* Endpoint Transfer Descriptor data struct */ +/* Rem: all the variables of td are LittleEndian Mode */ +struct ep_td_struct { + u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set + * indicate invalid */ + u32 size_ioc_sts; /* Total bytes (30-16), IOC (15), + * MultO(11-10), STS (7-0) */ + u32 buff_ptr0; /* Buffer pointer Page 0 */ + u32 buff_ptr1; /* Buffer pointer Page 1 */ + u32 buff_ptr2; /* Buffer pointer Page 2 */ + u32 buff_ptr3; /* Buffer pointer Page 3 */ + u32 buff_ptr4; /* Buffer pointer Page 4 */ + u32 res; /* make it an even 8 words */ +}; + +struct arcotg_req { + struct usb_request req; +/* struct list_head queue;*/ + /* ep_queue() func will add + * a request->queue into a udc_ep->queue 'd tail */ + struct arcotg_ep *ep; + unsigned mapped; + struct ep_td_struct *head, *tail; /* For dTD List this is a BigEndian Virtual addr */ + unsigned int dtd_count; + int used; +}; + +/* TODO: find best fitting sizes */ +#define CONTOLLER_BUFFER_SIZE 100 + +struct arcotg_ep { + struct usb_ep ep; + struct arcotg_udc *udc; + const struct usb_endpoint_descriptor *desc; + struct usb_gadget *gadget; /* is this really needed? ep.udc->gadget */ + + /* buffers for requests and dtds */ + struct arcotg_req req[CONTOLLER_BUFFER_SIZE]; + struct ep_td_struct td[CONTOLLER_BUFFER_SIZE]; + + u8 already_seen; + u8 setup_stage; + u32 last_io; /* timestamp */ + char name[14]; + unsigned double_buf:1; + unsigned stopped:1; + unsigned fnf:1; + unsigned has_dma:1; + u8 ackwait; + u8 dma_channel; + u16 dma_counter; + int lch; + +/* struct timer_list timer;*/ +}; + +#define EP_DIR_IN 1 +#define EP_DIR_OUT 0 + +struct arcotg_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct arcotg_ep eps[USB_MAX_ENDPOINTS * 2]; + struct usb_ctrlrequest local_setup_buff; + struct mutex lock; + //struct arc_usb_config *config; + u32 xcvr_type; + //struct otg_transceiver *transceiver; + unsigned softconnect; + unsigned vbus_active; + unsigned stopped; + + struct ep_queue_head ep_qh[USB_MAX_PIPES]; /* Endpoints Queue-Head */ + struct arcotg_req *status_req; /* ep0 status request */ + + u32 max_pipes; /* Device max pipes */ + u32 max_use_endpts; /* Max endpointes to be used */ + u32 bus_reset; /* Device is bus reseting */ + u32 resume_state; /* USB state to resume */ + u32 usb_state; /* USB current state */ + u32 usb_next_state; /* USB next state */ + u32 ep0_state; /* Enpoint zero state */ + u32 ep0_dir; /* Enpoint zero direction: can be + * USB_DIR_IN or USB_DIR_OUT */ + u32 usb_sof_count; /* SOF count */ + u32 errors; /* USB ERRORs count */ + u8 device_address; /* Device USB address */ + + struct completion *done; /* to make sure release() is done */ +}; + +/* Shared components used in all subparts of this driver */ +/* we will use the names for nicer debug logs */ +static const char *const ep_name[] = { + "ep0-control", NULL, /* everyone has ep0 */ + /* 7 configurable endpoints */ + "ep1out", + "ep1in", + "ep2out", + "ep2in", + "ep3out", + "ep3in", + "ep4out", + "ep4in", + "ep5out", + "ep5in", + "ep6out", + "ep6in", + "ep7out", + "ep7in" +}; + +const struct usb_ep_ops arcotg_ep_ops; +const struct usb_gadget_ops arcotg_gadget_ops; + /* Externally used functions */ int dr_controller_setup(void); void dr_controller_run(void); void dr_controller_stop(void); +void struct_ep_qh_setup(void *handle, unsigned char ep_num, + unsigned char dir, unsigned char ep_type, + unsigned int max_pkt_len, + unsigned int zlt, unsigned char mult); + + +/* + * ## pipe direction macro from device view + */ +#define USB_RECV (0) /* OUT EP */ +#define USB_SEND (1) /* IN EP */ + +/* + * ## internal used help routines. + */ +#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF) +#define ep_maxpacket(EP) ((EP)->ep.maxpacket) + +#define ep_is_in(EP) ( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \ + USB_DIR_IN ):((EP)->desc->bEndpointAddress \ + & USB_DIR_IN)==USB_DIR_IN) + +#define get_ep_by_pipe(udc, pipe) ((pipe == 1)? &udc->eps[0]: \ + &udc->eps[pipe]) + #endif /* __ARCOTG_UDC_H */ Index: firmware/export/usb_ch9.h =================================================================== --- firmware/export/usb_ch9.h (revision 0) +++ firmware/export/usb_ch9.h (revision 0) @@ -0,0 +1,586 @@ +/* + * This file holds USB constants and structures that are needed for + * USB device APIs. These are used by the USB device model, which is + * defined in chapter 9 of the USB 2.0 specification and in the + * Wireless USB 1.0 (spread around). Linux has several APIs in C that + * need these: + * + * - the master/host side Linux-USB kernel driver API; + * - the "usbfs" user space API; and + * - the Linux "gadget" slave/device/peripheral side driver API. + * + * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems + * act either as a USB master/host or as a USB slave/device. That means + * the master and slave side APIs benefit from working well together. + * + * There's also "Wireless USB", using low power short range radios for + * peripheral interconnection but otherwise building on the USB framework. + * + * Note all descriptors are declared '__attribute__((packed))' so that: + * + * [a] they never get padded, either internally (USB spec writers + * probably handled that) or externally; + * + * [b] so that accessing bigger-than-a-bytes fields will never + * generate bus errors on any platform, even when the location of + * its descriptor inside a bundle isn't "naturally aligned", and + * + * [c] for consistency, removing all doubt even when it appears to + * someone that the two other points are non-issues for that + * particular descriptor type. + */ + +#ifndef __LINUX_USB_CH9_H +#define __LINUX_USB_CH9_H + +#include + +/* This part here is neede do map rockbox datatypes to linux datatypes */ +#define __u8 uint8_t +#define __u16 uint16_t +#define __u32 uint32_t +#define __le16 __u16 +#define u8 __u8 +#define u16 __u16 +#define u32 __u32 + +/*-------------------------------------------------------------------------*/ + +/* CONTROL REQUEST SUPPORT */ + +/* + * USB directions + * + * This bit flag is used in endpoint descriptors' bEndpointAddress field. + * It's also one of three fields in control requests bRequestType. + */ +#define USB_DIR_OUT 0 /* to device */ +#define USB_DIR_IN 0x80 /* to host */ + +/* + * USB types, the second of three bRequestType fields + */ +#define USB_TYPE_MASK (0x03 << 5) +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +/* + * USB recipients, the third of three bRequestType fields + */ +#define USB_RECIP_MASK 0x1f +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 +/* From Wireless USB 1.0 */ +#define USB_RECIP_PORT 0x04 +#define USB_RECIP_RPIPE 0x05 + +/* + * Standard requests, for the bRequest field of a SETUP packet. + * + * These are qualified by the bRequestType field, so that for example + * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved + * by a GET_STATUS request. + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */ +#define USB_REQ_GET_ENCRYPTION 0x0E +#define USB_REQ_RPIPE_ABORT 0x0E +#define USB_REQ_SET_HANDSHAKE 0x0F +#define USB_REQ_RPIPE_RESET 0x0F +#define USB_REQ_GET_HANDSHAKE 0x10 +#define USB_REQ_SET_CONNECTION 0x11 +#define USB_REQ_SET_SECURITY_DATA 0x12 +#define USB_REQ_GET_SECURITY_DATA 0x13 +#define USB_REQ_SET_WUSB_DATA 0x14 +#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 +#define USB_REQ_LOOPBACK_DATA_READ 0x16 +#define USB_REQ_SET_INTERFACE_DS 0x17 + +/* + * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and + * are read as a bit array returned by USB_REQ_GET_STATUS. (So there + * are at most sixteen features of each type.) + */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ +#define USB_DEVICE_BATTERY 2 /* (wireless) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ +#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ +#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ + +#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ + + +/** + * struct usb_ctrlrequest - SETUP data for a USB device control request + * @bRequestType: matches the USB bmRequestType field + * @bRequest: matches the USB bRequest field + * @wValue: matches the USB wValue field (le16 byte order) + * @wIndex: matches the USB wIndex field (le16 byte order) + * @wLength: matches the USB wLength field (le16 byte order) + * + * This structure is used to send control requests to a USB device. It matches + * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the + * USB spec for a fuller description of the different fields, and what they are + * used for. + * + * Note that the driver for any interface can issue control requests. + * For most devices, interfaces don't coordinate with each other, so + * such requests may be made at any time. + */ +struct usb_ctrlrequest { + __u8 bRequestType; + __u8 bRequest; + __le16 wValue; + __le16 wIndex; + __le16 wLength; +} __attribute__ ((packed)); + +/*-------------------------------------------------------------------------*/ + +/* + * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or + * (rarely) accepted by SET_DESCRIPTOR. + * + * Note that all multi-byte values here are encoded in little endian + * byte order "on the wire". But when exposed through Linux-USB APIs, + * they've been converted to cpu byte order. + */ + +/* + * Descriptor types ... USB 2.0 spec table 9.5 + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_DEVICE_QUALIFIER 0x06 +#define USB_DT_OTHER_SPEED_CONFIG 0x07 +#define USB_DT_INTERFACE_POWER 0x08 +/* these are from a minor usb 2.0 revision (ECN) */ +#define USB_DT_OTG 0x09 +#define USB_DT_DEBUG 0x0a +#define USB_DT_INTERFACE_ASSOCIATION 0x0b +/* these are from the Wireless USB spec */ +#define USB_DT_SECURITY 0x0c +#define USB_DT_KEY 0x0d +#define USB_DT_ENCRYPTION_TYPE 0x0e +#define USB_DT_BOS 0x0f +#define USB_DT_DEVICE_CAPABILITY 0x10 +#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11 +#define USB_DT_WIRE_ADAPTER 0x21 +#define USB_DT_RPIPE 0x22 + +/* conventional codes for class-specific descriptors */ +#define USB_DT_CS_DEVICE 0x21 +#define USB_DT_CS_CONFIG 0x22 +#define USB_DT_CS_STRING 0x23 +#define USB_DT_CS_INTERFACE 0x24 +#define USB_DT_CS_ENDPOINT 0x25 + +/* All standard descriptors have these 2 fields at the beginning */ +struct usb_descriptor_header { + __u8 bLength; + __u8 bDescriptorType; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE: Device descriptor */ +struct usb_device_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __le16 idVendor; + __le16 idProduct; + __le16 bcdDevice; + __u8 iManufacturer; + __u8 iProduct; + __u8 iSerialNumber; + __u8 bNumConfigurations; +} __attribute__ ((packed)); + +#define USB_DT_DEVICE_SIZE 18 + + +/* + * Device and/or Interface Class codes + * as found in bDeviceClass or bInterfaceClass + * and defined by www.usb.org documents + */ +#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PHYSICAL 5 +#define USB_CLASS_STILL_IMAGE 6 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_CSCID 0x0b /* chip+ smart card */ +#define USB_CLASS_CONTENT_SEC 0x0d /* content security */ +#define USB_CLASS_VIDEO 0x0e +#define USB_CLASS_WIRELESS_CONTROLLER 0xe0 +#define USB_CLASS_MISC 0xef +#define USB_CLASS_APP_SPEC 0xfe +#define USB_CLASS_VENDOR_SPEC 0xff + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_CONFIG: Configuration descriptor information. + * + * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the + * descriptor type is different. Highspeed-capable devices can look + * different depending on what speed they're currently running. Only + * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG + * descriptors. + */ +struct usb_config_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumInterfaces; + __u8 bConfigurationValue; + __u8 iConfiguration; + __u8 bmAttributes; + __u8 bMaxPower; +} __attribute__ ((packed)); + +#define USB_DT_CONFIG_SIZE 9 + +/* from config descriptor bmAttributes */ +#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */ +#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */ +#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */ +#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_STRING: String descriptor */ +struct usb_string_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wData[1]; /* UTF-16LE encoded */ +} __attribute__ ((packed)); + +/* note that "string" zero is special, it holds language codes that + * the device supports, not Unicode characters. + */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE: Interface descriptor */ +struct usb_interface_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bInterfaceNumber; + __u8 bAlternateSetting; + __u8 bNumEndpoints; + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + __u8 iInterface; +} __attribute__ ((packed)); + +#define USB_DT_INTERFACE_SIZE 9 + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENDPOINT: Endpoint descriptor */ +struct usb_endpoint_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bEndpointAddress; + __u8 bmAttributes; + __le16 wMaxPacketSize; + __u8 bInterval; + + /* NOTE: these two are _only_ in audio endpoints. */ + /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ + __u8 bRefresh; + __u8 bSynchAddress; +} __attribute__ ((packed)); + +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ + + +/* + * Endpoints + */ +#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */ +#define USB_ENDPOINT_DIR_MASK 0x80 + +#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */ +#define USB_ENDPOINT_XFER_CONTROL 0 +#define USB_ENDPOINT_XFER_ISOC 1 +#define USB_ENDPOINT_XFER_BULK 2 +#define USB_ENDPOINT_XFER_INT 3 +#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80 + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u8 bNumConfigurations; + __u8 bRESERVED; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_OTG (from OTG 1.0a supplement) */ +struct usb_otg_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bmAttributes; /* support for HNP, SRP, etc */ +} __attribute__ ((packed)); + +/* from usb_otg_descriptor.bmAttributes */ +#define USB_OTG_SRP (1 << 0) +#define USB_OTG_HNP (1 << 1) /* swap host/device roles */ + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */ +struct usb_debug_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + /* bulk endpoints with 8 byte maxpacket */ + __u8 bDebugInEndpoint; + __u8 bDebugOutEndpoint; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */ +struct usb_interface_assoc_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bFirstInterface; + __u8 bInterfaceCount; + __u8 bFunctionClass; + __u8 bFunctionSubClass; + __u8 bFunctionProtocol; + __u8 iFunction; +} __attribute__ ((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_SECURITY: group of wireless security descriptors, including + * encryption types available for setting up a CC/association. + */ +struct usb_security_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumEncryptionTypes; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys + * may be retrieved. + */ +struct usb_key_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 tTKID[3]; + __u8 bReserved; + __u8 bKeyData[0]; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */ +struct usb_encryption_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bEncryptionType; +#define USB_ENC_TYPE_UNSECURE 0 +#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */ +#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */ +#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */ + __u8 bEncryptionValue; /* use in SET_ENCRYPTION */ + __u8 bAuthKeyIndex; +} __attribute__((packed)); + + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_BOS: group of wireless capabilities */ +struct usb_bos_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __le16 wTotalLength; + __u8 bNumDeviceCaps; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */ +struct usb_dev_cap_header { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; +} __attribute__((packed)); + +#define USB_CAP_TYPE_WIRELESS_USB 1 + +struct usb_wireless_cap_descriptor { /* Ultra Wide Band */ + __u8 bLength; + __u8 bDescriptorType; + __u8 bDevCapabilityType; + + __u8 bmAttributes; +#define USB_WIRELESS_P2P_DRD (1 << 1) +#define USB_WIRELESS_BEACON_MASK (3 << 2) +#define USB_WIRELESS_BEACON_SELF (1 << 2) +#define USB_WIRELESS_BEACON_DIRECTED (2 << 2) +#define USB_WIRELESS_BEACON_NONE (3 << 2) + __le16 wPHYRates; /* bit rates, Mbps */ +#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */ +#define USB_WIRELESS_PHY_80 (1 << 1) +#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */ +#define USB_WIRELESS_PHY_160 (1 << 3) +#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */ +#define USB_WIRELESS_PHY_320 (1 << 5) +#define USB_WIRELESS_PHY_400 (1 << 6) +#define USB_WIRELESS_PHY_480 (1 << 7) + __u8 bmTFITXPowerInfo; /* TFI power levels */ + __u8 bmFFITXPowerInfo; /* FFI power levels */ + __le16 bmBandGroup; + __u8 bReserved; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with + * each endpoint descriptor for a wireless device + */ +struct usb_wireless_ep_comp_descriptor { + __u8 bLength; + __u8 bDescriptorType; + + __u8 bMaxBurst; + __u8 bMaxSequence; + __le16 wMaxStreamDelay; + __le16 wOverTheAirPacketSize; + __u8 bOverTheAirInterval; + __u8 bmCompAttributes; +#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */ +#define USB_ENDPOINT_SWITCH_NO 0 +#define USB_ENDPOINT_SWITCH_SWITCH 1 +#define USB_ENDPOINT_SWITCH_SCALE 2 +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless + * host and a device for connection set up, mutual authentication, and + * exchanging short lived session keys. The handshake depends on a CC. + */ +struct usb_handshake { + __u8 bMessageNumber; + __u8 bStatus; + __u8 tTKID[3]; + __u8 bReserved; + __u8 CDID[16]; + __u8 nonce[16]; + __u8 MIC[8]; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC). + * A CC may also be set up using non-wireless secure channels (including + * wired USB!), and some devices may support CCs with multiple hosts. + */ +struct usb_connection_context { + __u8 CHID[16]; /* persistent host id */ + __u8 CDID[16]; /* device id (unique w/in host context) */ + __u8 CK[16]; /* connection key */ +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + +/* USB 2.0 defines three speeds, here's how Linux identifies them */ + +enum usb_device_speed { + USB_SPEED_UNKNOWN = 0, /* enumerating */ + USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ + USB_SPEED_HIGH, /* usb 2.0 */ + USB_SPEED_VARIABLE, /* wireless (usb 2.5) */ +}; + +enum usb_device_state { + /* NOTATTACHED isn't in the USB spec, and this state acts + * the same as ATTACHED ... but it's clearer this way. + */ + USB_STATE_NOTATTACHED = 0, + + /* chapter 9 and authentication (wireless) device states */ + USB_STATE_ATTACHED, + USB_STATE_POWERED, /* wired */ + USB_STATE_UNAUTHENTICATED, /* auth */ + USB_STATE_RECONNECTING, /* auth */ + USB_STATE_DEFAULT, /* limited function */ + USB_STATE_ADDRESS, + USB_STATE_CONFIGURED, /* most functions */ + + USB_STATE_SUSPENDED + + /* NOTE: there are actually four different SUSPENDED + * states, returning to POWERED, DEFAULT, ADDRESS, or + * CONFIGURED respectively when SOF tokens flow again. + */ +}; + +#endif /* __LINUX_USB_CH9_H */ Index: firmware/SOURCES =================================================================== --- firmware/SOURCES (revision 13728) +++ firmware/SOURCES (working copy) @@ -227,7 +227,9 @@ #if CONFIG_USBOTG == USBOTG_M5636 drivers/m5636.c #elif CONFIG_USBOTG == USBOTG_ARC -drivers/arcotg_udc.c +drivers/usb/arcotg_udc_ep_mgnt.c +drivers/usb/arcotg_udc_gadget.c +drivers/usb/arcotg_udc.c #endif /* CONFIG_USBOTG */ #endif /* !defined(BOOTLOADER) */ #endif /* !defined(SIMULATOR) */ Index: firmware/target/arm/usb-pp.c =================================================================== --- firmware/target/arm/usb-pp.c (revision 13728) +++ firmware/target/arm/usb-pp.c (working copy) @@ -45,6 +45,11 @@ void usb_init_device(void) { int r0; + +#ifdef SANSA_E200 + GPIOB_INT_EN &= ~(1 << 4); +#endif + outl(inl(0x70000084) | 0x200, 0x70000084); outl(inl(0x7000002C) | 0x3000000, 0x7000002C); @@ -86,7 +91,28 @@ udelay(0x186A0); + /* enable interrupts */ +#if defined(SANSA_E200) + /*Enable DR irq reg */ + UDC_USBINTR = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN | + USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN | + USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; + GPIOB_OUTPUT_EN &= ~(1 << 4); + GPIOB_ENABLE |= (1 << 4); + GPIOB_INT_LEV = (GPIOB_INT_LEV & ~(1 << 4)) | + (~GPIOB_INPUT_VAL & (1 << 4)); + + /* enable gpio interrupt in cpu */ + CPU_INT_EN = HI_MASK; + CPU_HI_INT_EN = GPIO0_MASK; + + /* ack interrupt */ + GPIOB_INT_CLR = (1 << 4); + /* enable gpiob interupt */ + GPIOB_INT_EN |= (1 << 4); +#endif + dr_controller_setup(); } Index: firmware/target/arm/system-pp502x.c =================================================================== --- firmware/target/arm/system-pp502x.c (revision 13728) +++ firmware/target/arm/system-pp502x.c (working copy) @@ -58,6 +58,7 @@ /* TODO: Even if it isn't in the target tree, this should be the default case */ extern void button_int(void); extern void clickwheel_int(void); +extern void usbdevice_irq(void); void irq(void) { @@ -68,6 +69,11 @@ else if (CPU_INT_STAT & TIMER2_MASK) TIMER2(); #ifdef SANSA_E200 + else if (CPU_HI_INT_STAT & GPIO0_MASK) + { + if (GPIOB_INT_STAT & 0x10) + usbdevice_irq(); + } else if (CPU_HI_INT_STAT & GPIO1_MASK) { if (GPIOF_INT_STAT & 0xff) Index: firmware/drivers/arcotg_udc.c =================================================================== --- firmware/drivers/arcotg_udc.c (revision 13728) +++ firmware/drivers/arcotg_udc.c (working copy) @@ -1,135 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 by Barry Wardell - * - * Based on code from the Linux Target Image Builder from Freescale - * available at http://www.bitshrine.org/ and - * http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch - * Adapted for Rockbox in January 2007 - * Original file: drivers/usb/gadget/arcotg_udc.c - * - * USB Device Controller Driver - * Driver for ARC OTG USB module in the i.MX31 platform, etc. - * - * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. - * - * Based on mpc-udc.h - * Author: Li Yang (leoli@freescale.com) - * Jiang Bo (Tanya.jiang@freescale.com) - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "arcotg_udc.h" -#include "logf.h" - -static int timeout; - -/* @qh_addr is the aligned virt addr of ep QH addr - * it is used to set endpointlistaddr Reg */ -/* was static int dr_controller_setup(void *qh_addr) */ -int dr_controller_setup(void) -{ -#if 0 - struct arc_usb_config *config; - - config = udc_controller->config; - - /* before here, make sure usb_slave_regs has been initialized */ - if (!qh_addr) - return -EINVAL; -#endif - - /* Stop and reset the usb controller */ - UDC_USBCMD &= ~USB_CMD_RUN_STOP; - - UDC_USBCMD |= USB_CMD_CTRL_RESET; - - /* Wait for reset to complete */ - timeout = 10000000; - while ((UDC_USBCMD & USB_CMD_CTRL_RESET) && - --timeout) { - continue; - } - if (timeout == 0) { - logf("%s: TIMEOUT", __FUNCTION__); - return -ETIMEDOUT; - } - - /* Set the controller as device mode and disable setup lockout */ - UDC_USBMODE |= (USB_MODE_CTRL_MODE_DEVICE | USB_MODE_SETUP_LOCK_OFF); - - /* Clear the setup status */ - UDC_USBSTS = 0; -#if 0 - UDC_ENDPOINTLISTADDR = (unsigned int)qh_addr & USB_EP_LIST_ADDRESS_MASK; - - VDBG("qh_addr=0x%x epla_reg=0x%8x", qh_addr, UOG_ASYNCLISTADDR); -#endif - UDC_PORTSC1 = (UDC_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_UTMI; -#if 0 - if (config->set_vbus_power) - config->set_vbus_power(0); -#endif - - return 0; -} - -/* just Enable DR irq reg and Set Dr controller Run */ -/* was static void dr_controller_run(struct arcotg_udc *udc) */ -void dr_controller_run(void) -{ - /*Enable DR irq reg */ - UDC_USBINTR = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN | - USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN | - USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; -#if 0 - /* Clear stopped bit */ - udc->stopped = 0; -#endif - /* Set the controller as device mode */ - UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; - - /* Set controller to Run */ - UDC_USBCMD |= USB_CMD_RUN_STOP; - - return; -} - -/* just Enable DR irq reg and Set Dr controller Run */ -/* was static void dr_controller_stop(struct arcotg_udc *udc) */ -void dr_controller_stop(void) -{ -#if 0 - /* if we're in OTG mode, and the Host is currently using the port, - * stop now and don't rip the controller out from under the - * ehci driver - */ - if (udc->gadget.is_otg) { - if (!(UDC_OTGSC & OTGSC_STS_USB_ID)) { - logf("Leaving early"); - return; - } - } -#endif - - /* disable all INTR */ - UDC_USBINTR = 0; -#if 0 - /* Set stopped bit */ - udc->stopped = 1; -#endif - /* Set controller to Stop */ - UDC_USBCMD &= ~USB_CMD_RUN_STOP; -} Index: firmware/drivers/usb/arcotg_udc_ep_mgnt.c =================================================================== --- firmware/drivers/usb/arcotg_udc_ep_mgnt.c (revision 0) +++ firmware/drivers/usb/arcotg_udc_ep_mgnt.c (revision 0) @@ -0,0 +1,162 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $ + * + * Copyright (C) 2007 by Christian Gmeiner + * + * Based on code from the Linux Target Image Builder from Freescale + * available at http://www.bitshrine.org/ and + * http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch + * Adapted for Rockbox in January 2007 + * Original file: drivers/usb/gadget/arcotg_udc.c + * + * USB Device Controller Driver + * Driver for ARC OTG USB module in the i.MX31 platform, etc. + * + * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Based on mpc-udc.h + * Author: Li Yang (leoli@freescale.com) + * Jiang Bo (Tanya.jiang@freescale.com) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "arcotg_udc.h" +#include "logf.h" + +/*********************************************************************** + Endpoint Management Functions +***********************************************************************/ + +static int arcotg_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { + struct arcotg_udc *udc = NULL; + struct arcotg_ep *ep = NULL; + unsigned short max = 0; + unsigned char mult = 0, zlt = 0; + int retval = 0; + unsigned long flags = 0; + char *val = NULL; /* for debug */ + + ep = container_of(_ep, struct arcotg_ep, ep); + logf("%s ep.name=%s", __FUNCTION__, ep->ep.name); + /* catch various bogus parameters */ + if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] || (desc->bDescriptorType != USB_DT_ENDPOINT)) { + /* FIXME: add judge for ep->bEndpointAddress */ + return -EINVAL; + } + udc = ep->udc; + + if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) { + return -ESHUTDOWN; + } + + max = desc->wMaxPacketSize; + retval = -EINVAL; + + /* here initialize variable of ep */ + //spin_lock_irqsave(&udc->lock, flags); + ep->ep.maxpacket = max; + ep->desc = desc; + ep->stopped = 0; + + /* hardware special operation */ + + /* Init EPx Queue Head (Ep Capabilites field in QH + * according to max, zlt, mult) */ + struct_ep_qh_setup( (void *)udc, (unsigned char)ep_index(ep), + (unsigned char) + ((desc->bEndpointAddress & USB_DIR_IN) ? + USB_SEND : USB_RECV), (unsigned char) + (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK), + max, zlt, mult); + + /* Init endpoint x at here */ + /* 83xx RM chapter 16.3.2.24, here init the endpoint ctrl reg */ + dr_ep_setup((unsigned char)ep_index(ep), + (unsigned char)((desc->bEndpointAddress & USB_DIR_IN) ? USB_SEND : USB_RECV), + (unsigned char)(desc->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK)); + + /* Now HW will be NAKing transfers to that EP, + * until a buffer is queued to it. */ + + /* should have stop the lock */ + retval = 0; + switch (desc->bmAttributes & 0x03) { + case USB_ENDPOINT_XFER_BULK: + val = "bulk"; + break; + case USB_ENDPOINT_XFER_ISOC: + val = "iso"; + break; + case USB_ENDPOINT_XFER_INT: + val = "intr"; + break; + default: + val = "ctrl"; + break; + } + + logf("enabled %s (ep%d%s-%s) maxpacket %d", ep->ep.name, + ep->desc->bEndpointAddress & 0x0f, + (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", val, max); + + return 0; + +en_done: + return retval; +} + +/*--------------------------------------------------------------------- + * @ep : the ep being unconfigured. May not be ep0 + * Any pending and uncomplete req will complete with status (-ESHUTDOWN) +*---------------------------------------------------------------------*/ +static int arcotg_ep_disable(struct usb_ep *_ep) { + struct arcotg_udc *udc = NULL; + struct arcotg_ep *ep = NULL; + + ep = container_of(_ep, struct arcotg_ep, ep); + if (!_ep || !ep->desc) { + logf("%s not enabled", _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + udc = (struct arcotg_udc *)ep->udc; + + /* Nuke all pending requests (does flush) */ +#if 0 + nuke(ep, -ESHUTDOWN); +#endif + ep->desc = 0; + ep->stopped = 1; + + logf("disabled %s OK", _ep->name); + return 0; +} + +const struct usb_ep_ops arcotg_ep_ops = { + .enable = arcotg_ep_enable, + .disable = arcotg_ep_disable, +/* + .alloc_request = NULL, + .free_request = NULL, + + .alloc_buffer = NULL, + .free_buffer = NULL,*/ + + .queue = NULL, + .dequeue = NULL, + + .set_halt = NULL, +}; Index: firmware/drivers/usb/arcotg_udc_gadget.c =================================================================== --- firmware/drivers/usb/arcotg_udc_gadget.c (revision 0) +++ firmware/drivers/usb/arcotg_udc_gadget.c (revision 0) @@ -0,0 +1,55 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: arcotg_udc.c 12340 2007-02-16 22:13:21Z barrywardell $ + * + * Copyright (C) 2007 by Christian Gmeiner + * + * Based on code from the Linux Target Image Builder from Freescale + * available at http://www.bitshrine.org/ and + * http://www.bitshrine.org/gpp/linux-2.6.16-mx31-usb-2.patch + * Adapted for Rockbox in January 2007 + * Original file: drivers/usb/gadget/arcotg_udc.c + * + * USB Device Controller Driver + * Driver for ARC OTG USB module in the i.MX31 platform, etc. + * + * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Based on mpc-udc.h + * Author: Li Yang (leoli@freescale.com) + * Jiang Bo (Tanya.jiang@freescale.com) + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "arcotg_udc.h" + +/*********************************************************************** + Gadget Functions +***********************************************************************/ + +/** + * @return the current frame number + */ +static int arcotg_get_frame(struct usb_gadget *gadget) { + return (int) (UDC_FRINDEX & USB_FRINDEX_MASKS); +} + +const struct usb_gadget_ops arcotg_gadget_ops = { + .get_frame = arcotg_get_frame, + .wakeup = NULL, + .set_selfpowered = NULL, + .vbus_session = NULL, + .vbus_draw = NULL, + .pullup = NULL, +}; Index: firmware/drivers/usb/arcotg_udc.c =================================================================== --- firmware/drivers/usb/arcotg_udc.c (revision 0) +++ firmware/drivers/usb/arcotg_udc.c (working copy) @@ -8,6 +8,7 @@ * $Id$ * * Copyright (C) 2007 by Barry Wardell + * Copyright (C) 2007 by Christian Gmeiner * * Based on code from the Linux Target Image Builder from Freescale * available at http://www.bitshrine.org/ and @@ -31,16 +32,821 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "system.h" +#include #include "arcotg_udc.h" #include "logf.h" +/* it is initialized in dr_controller_setup() */ +static struct arcotg_udc udc_controller; +static int initialized = 0; static int timeout; +/* ep0's endpoint descriptor */ +static struct usb_endpoint_descriptor arcotg_ep0_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = 0, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, +}; + +/** + * As we dont want to use dynamic memory management we do it + * in a static way. + * This means that every endpoint as an array of requests. + */ +static struct arcotg_req* get_free_request(struct arcotg_ep ep) { + + int i; + struct arcotg_req* result = NULL; + + for (i = 0; i < CONTOLLER_BUFFER_SIZE; i++) { + if (ep.req[i].used == 0) { + result = &ep.req[i]; + /* reset */ + memset(result, 0, sizeof *result); + /* set as used */ + ep.req[i].used = 1; + break; + } + } + + if (result == NULL) { + logf("no free req buffer!"); + } + + return result; +} + +static void free_request(struct arcotg_req* req) { + + if (req == NULL) { + return; + } + + req->used = 0; +} + +/* if direction is EP_IN, the status is Device->Host + * if direction is EP_OUT, the status transaction is Device<-Host + */ +static int ep0_prime_status(int direction) { + + struct arcotg_req *req = udc_controller.status_req; + struct arcotg_ep *ep; + int status = 0; + + if (direction == EP_DIR_IN) { + udc_controller.ep0_dir = USB_DIR_IN; + } else { + udc_controller.ep0_dir = USB_DIR_OUT; + } + + ep = &udc_controller.eps[0]; + udc_controller.ep0_state = WAIT_FOR_OUT_STATUS; + logf("ep0_state now WAIT_FOR_OUT_STATUS"); + + req->ep = ep; + req->req.length = 0; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + req->req.complete = NULL; + req->dtd_count = 0; + + //spin_lock_irqsave(&udc->lock, flags); + +#if 0 ++ if ((arcotg_req_to_dtd(req, udc->gadget.dev.parent) == 0)) ++ status = arcotg_queue_td(ep, req); ++ if (status) ++ printk(KERN_ERR "Can't get control status request \n"); + + list_add_tail(&req->queue, &ep->queue); + dump_ep_queue(ep); +#endif + + //spin_unlock_irqrestore(&udc->lock, flags); + status = 1; + return status; +} + +static void Ep0Stall(void) { + u32 tmp_epctrl; + + /* a protocol stall */ + tmp_epctrl = UDC_ENDPTCTRL(0); + tmp_epctrl |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL; + UDC_ENDPTCTRL(0) = tmp_epctrl; + + udc_controller.ep0_state = WAIT_FOR_SETUP; + logf("ep0_state now WAIT_FOR_SETUP"); + udc_controller.ep0_dir = 0; +} + +/*---------------------------------------------------------------- + * set up the arcotg_ep struct for eps + * ep0out isnot used so do nothing here + * ep0in should be taken care + * It also link this arcotg_ep->ep to gadget->ep_list + *--------------------------------------------------------------*/ +static int struct_ep_setup(unsigned char pipe_num) { + struct arcotg_udc *udc = &udc_controller; + struct arcotg_ep *ep = get_ep_by_pipe(udc, pipe_num); + + ep->udc = udc; + strcpy(ep->name, ep_name[pipe_num]); + ep->ep.name = ep_name[pipe_num]; + ep->ep.ops = &arcotg_ep_ops; + ep->stopped = 0; + + /* for ep0: the desc defined here; + * for other eps, gadget layer called ep_enable with defined desc + */ + /* for ep0: maxP defined in desc + * for other eps, maxP is set by epautoconfig() called by gadget layer + */ + if (pipe_num == 0) { + ep->desc = &arcotg_ep0_desc; + ep->ep.maxpacket = USB_MAX_CTRL_PAYLOAD; + } else { + ep->ep.maxpacket = (unsigned short)~0; + ep->desc = NULL; + } + +#if 0 + /* the queue lists any req for this ep */ + INIT_LIST_HEAD(&ep->queue); + + /* arcotg_ep->ep.ep_list: gadget ep_list hold all of its eps + * so only the first should init--it is ep0' */ + + /* gagdet.ep_list used for ep_autoconfig so no ep0 */ + if (pipe_num != 0) + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); +#endif + + ep->gadget = &udc->gadget; + return 0; +} + +static void ch9GetStatus(struct usb_ctrlrequest *setup) { + + struct arcotg_req *req; + struct arcotg_ep ep; + int status = 0; + unsigned long flags; + + ep = udc_controller.eps[0]; + req = get_free_request(ep); + + req->req.length = 2; + req->req.buf = &udc_controller.usb_state; + req->req.status = -EINPROGRESS; + req->req.actual = 0; + + +// spin_lock_irqsave(&udc->lock, flags); +#if 0 + /* data phase */ + if ((arcotg_req_to_dtd(req, udc_controller.gadget.dev.parent) == 0)) + status = arcotg_queue_td(ep, req); + if (status) { + logf("Can't respond to getstatus request \n"); + Ep0Stall(); + } else { + udc->ep0_state = DATA_STATE_XMIT; + logf("ep0_state now DATA_STATE_XMIT"); + } + + list_add_tail(&req->queue, &ep->queue); + dump_ep_queue(ep); +// spin_unlock_irqrestore(&udc->lock, flags); +#endif +} + +static void ch9SetAddress(struct usb_ctrlrequest *setup) { + logf("new addr=%d", setup->wValue); + + /* Save the new address to device struct */ + udc_controller.device_address = (u8) setup->wValue; + + /* Update usb state */ + udc_controller.usb_state = USB_STATE_ADDRESS; + + /* Status phase */ + if (ep0_prime_status(EP_DIR_IN)) + Ep0Stall(); +} + +static void ch9SetConfig(struct usb_ctrlrequest *setup) { + logf("calling gadget driver->setup"); + udc_controller.ep0_dir = USB_DIR_IN; + +#if 0 + if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff) >= 0) { + /* gadget layer deal with the status phase */ + udc_controller.usb_state = USB_STATE_CONFIGURED; + udc_controller.ep0_state = WAIT_FOR_OUT_STATUS; + logf("ep0_state now WAIT_FOR_OUT_STATUS"); + } +#endif +} + +#if 0 +static int arcotg_req_to_dtd(struct arcotg_req *req, struct device *dev) +{ + unsigned max; + unsigned count; + int is_last; + int is_first = 1; + struct ep_td_struct *last_addr = NULL, *addr; + + logf("req=0x%p", req); + + max = EP_MAX_LENGTH_TRANSFER; + do { + count = arcotg_build_dtd(req, max, &addr); + + if (is_first) { + is_first = 0; + req->head = addr; + } else { + if (!last_addr) { + /* FIXME last_addr not set. iso only + * case, which we don't do yet + */ + logf("*** wiping out something at 0!!"); + } + + last_addr->next_td_ptr = + cpu_to_le32(virt_to_phys(addr)); +#if 0 +#ifdef CONFIG_ARM + logf("1 doing consistent_sync(dtd=0x%p, l=%d)", + last_addr, sizeof(struct ep_td_struct)); + consistent_sync(last_addr, sizeof(struct ep_td_struct), + DMA_TO_DEVICE); +#else + flush_dcache_range((unsigned long)last_addr, + (unsigned long)last_addr + + sizeof(struct ep_td_struct)); +#endif +#endif + last_addr = addr; + } + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = 1; + else if (likely(req->req.length != req->req.actual) || + req->req.zero) + is_last = 0; + else + is_last = 1; + + req->dtd_count++; + } while (!is_last); + + addr->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE); + +#if 0 +#ifdef CONFIG_ARM + VDBG("2 doing consistent_sync(last dtd=0x%p, l=%d)", + addr, sizeof(struct ep_td_struct)); + consistent_sync(addr, sizeof(struct ep_td_struct), DMA_TO_DEVICE); +#else + flush_dcache_range((unsigned long)addr, (unsigned long)addr + + sizeof(struct ep_td_struct)); +#endif +#endif + req->tail = addr; + + return 0; +} + +static int +arcotg_build_dtd(struct arcotg_req *req, unsigned max, + struct ep_td_struct **address) +{ + unsigned length; + u32 swap_temp; + struct ep_td_struct *dtd; + + /* how big will this packet be? */ + length = min(req->req.length - req->req.actual, max); + + /* Assume CACHELINE alignment guarantees 32-byte alignment */ + dtd = kmalloc(sizeof(struct ep_td_struct), GFP_KERNEL | GFP_DMA); + + /* check alignment - must be 32 byte aligned (bits 4:0 == 0) */ + if ((u32) dtd & ~DTD_ADDR_MASK) + panic("Can not allocate aligned memory for dtd"); + + memset(dtd, 0, sizeof(struct ep_td_struct)); + + /* Fill in the transfer size; set interrupt on every dtd; + set active bit */ + swap_temp = ((length << DTD_LENGTH_BIT_POS) | DTD_IOC + | DTD_STATUS_ACTIVE); + + dtd->size_ioc_sts = cpu_to_le32(swap_temp); + + /* Clear reserved field */ + swap_temp = cpu_to_le32(dtd->size_ioc_sts); + swap_temp &= ~DTD_RESERVED_FIELDS; + dtd->size_ioc_sts = cpu_to_le32(swap_temp); + + VDBG("req=0x%p dtd=0x%p req.dma=0x%x req.length=%d " + "length=%d size_ioc_sts=0x%x", + req, dtd, req->req.dma, req->req.length, + length, dtd->size_ioc_sts); + + /* Init all of buffer page pointers */ + swap_temp = (u32) (req->req.dma + req->req.actual); + dtd->buff_ptr0 = cpu_to_le32(swap_temp); + dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000); + dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000); + dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000); + dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000); + + req->req.actual += length; + *address = dtd; + + return length; +} +#endif +/** + * + */ +void struct_ep_qh_setup(void *handle, unsigned char ep_num, + unsigned char dir, unsigned char ep_type, + unsigned int max_pkt_len, + unsigned int zlt, unsigned char mult) +{ + struct arcotg_udc *udc = NULL; + struct ep_queue_head *p_QH = NULL; + unsigned int tmp = 0; + + udc = (struct arcotg_udc *)handle; + + p_QH = &udc->ep_qh[2 * ep_num + dir]; + + /* set the Endpoint Capabilites Reg of QH */ + switch (ep_type) { + case USB_ENDPOINT_XFER_CONTROL: + /* Interrupt On Setup (IOS). for control ep */ + tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) | EP_QUEUE_HEAD_IOS; + break; + case USB_ENDPOINT_XFER_ISOC: + tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) | (mult << EP_QUEUE_HEAD_MULT_POS); + break; + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS; + if (zlt) { + tmp |= EP_QUEUE_HEAD_ZLT_SEL; + } + break; + default: + logf("error ep type is %d", ep_type); + return; + } + p_QH->max_pkt_length = tmp; + + return; +} + +void dr_ep_setup(unsigned char ep_num, unsigned char dir, unsigned char ep_type) { + unsigned int tmp_epctrl = 0; + + tmp_epctrl = UDC_ENDPTCTRL(ep_num); + if (dir) { + if (ep_num) { + tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; + } + tmp_epctrl |= EPCTRL_TX_ENABLE; + tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT); + } else { + if (ep_num) { + tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; + } + tmp_epctrl |= EPCTRL_RX_ENABLE; + tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT); + } + + UDC_ENDPTCTRL(ep_num) = tmp_epctrl; + + /* wait for the write reg to finish */ + timeout = 10000000; + while ((!(UDC_ENDPTCTRL(ep_num) & (tmp_epctrl & (EPCTRL_TX_ENABLE | EPCTRL_RX_ENABLE)))) && --timeout) { + continue; + } + if (timeout == 0) { + logf("%s: TIMEOUT\n", __FUNCTION__); + } +} + +static void tripwire_handler(u8 ep_num) { + + struct ep_queue_head *qh; + + qh = &(udc_controller.ep_qh[ep_num * 2 + EP_DIR_OUT]); + + //VDBG("doing consistent_sync(QH=0x%p, l=%d)", qh, sizeof(struct ep_queue_head)); + + //consistent_sync(qh, sizeof(struct ep_queue_head), DMA_FROM_DEVICE); + + // example "struct S { short f[3]; } __attribute__ ((aligned (8)));" + + /* Clear bit in ENDPTSETUPSTAT */ + UDC_ENDPTSETUPSTAT |= (1 << ep_num); + + /* while a hazard exists when setup package arrives */ + //do { + /* Set Setup Tripwire */ + UDC_USBCMD |= USB_CMD_SUTW; + + /* Copy the setup packet to local buffer */ + //logf("qh=0x%p copy setup buffer from 0x%p to 0x%p", qh, qh->setup_buffer, buffer_ptr); + logf("copy setup buffer from"); + //logf("from 0x%p", qh->setup_buffer); + //logf("to 0x%p", &udc_controller.local_setup_buff); + memcpy(&udc_controller.local_setup_buff, (u8 *) qh->setup_buffer, 8); +// } while (! (UDC_USBCMD & USB_CMD_SUTW)); + + /* Clear Setup Tripwire */ + UDC_USBCMD &= ~USB_CMD_SUTW; + + /* timeout = 10000000; + while ((UDC_ENDPTSETUPSTAT & 1) && --timeout) { + continue; + } + if (timeout == 0) { + logf("%s: TIMEOUT\n", __FUNCTION__); + }*/ +} + +static void setup_received_irq(struct usb_ctrlrequest *setup) { + int handled = 1; /* set to zero if we do not handle the message, */ + /* and should pass it to the gadget driver */ + int rc = -EOPNOTSUPP; + logf("request=0x%x", setup->bRequest); + + /* We asume setup only occurs on EP0 */ + if (setup->bRequestType & USB_DIR_IN) { + udc_controller.ep0_dir = USB_DIR_IN; + } else { + udc_controller.ep0_dir = USB_DIR_OUT; + } + + if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { + logf("class request"); + + } else if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + logf("standard request"); + + /* handle standard requests */ + switch (setup->bRequest) { + case USB_REQ_GET_STATUS: + logf("get status"); + if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD)) != (USB_DIR_IN | USB_TYPE_STANDARD)) { + break; + } + logf("get status2"); + ch9GetStatus(setup); + break; + + case USB_REQ_SET_ADDRESS: + logf("set address"); + if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { + break; + } + logf("set address2"); + ch9SetAddress(setup); + break; + + case USB_REQ_SET_CONFIGURATION: + logf("set configuration"); + if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { + break; + } + logf("set configuration2"); + /* gadget layer take over the status phase */ + ch9SetConfig(setup); + break; + + case USB_REQ_SET_INTERFACE: + logf("set interface"); + if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE)) { + break; + } + udc_controller.ep0_dir = USB_DIR_IN; +#if 0 + if (udc_controller.driver->setup(&udc->gadget, &udc->local_setup_buff) >= 0) { + /* gadget layer take over the status phase */ + break; + } +#endif + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + /* status transaction */ + + if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) { + break; + } + + /* we only support set/clear feature for endpoint */ + if (setup->bRequestType == USB_RECIP_ENDPOINT) { + int dir = (setup->wIndex & 0x0080) ? EP_DIR_IN : EP_DIR_OUT; + int num = (setup->wIndex & 0x000f); + struct arcotg_ep *ep; + + if (setup->wValue != 0 || setup->wLength != 0 || (num * 2 + dir) > USB_MAX_PIPES) { + break; + } + ep = &udc_controller.eps[num * 2 + dir]; + + if (setup->bRequest == USB_REQ_SET_FEATURE) { + logf("SET_FEATURE doing set_halt"); +#if 0 + rc = _arcotg_ep_set_halt(&ep->ep, 1); +#endif + } else { + logf("CLEAR_FEATURE doing clear_halt"); +#if 0 + rc = _arcotg_ep_set_halt(&ep->ep, 0); +#endif + } + + } else if (setup->bRequestType == USB_RECIP_DEVICE) { + + if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) { + udc_controller.gadget.b_hnp_enable = 1; + } else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) { + udc_controller.gadget.a_hnp_support = 1; + } else if (setup->bRequest == USB_DEVICE_A_ALT_HNP_SUPPORT) { + udc_controller.gadget.a_alt_hnp_support = 1; + } + + rc = 0; + } + + if (rc == 0) { + /* send status only if _arcotg_ep_set_halt success */ + if (ep0_prime_status(EP_DIR_IN)) { + Ep0Stall(); + } + } + break; + + default: + handled = 0; + break; + } + } else { + /* vendor */ + handled = 0; + } + + if (!handled) { +#if 0 + if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff) != 0) { + Ep0Stall(); + } else +#endif + if (setup->bRequestType & USB_DIR_IN) { + udc_controller.ep0_state = DATA_STATE_XMIT; + logf("ep0_state now DATA_STATE_XMIT"); + } else { + udc_controller.ep0_state = DATA_STATE_RECV; + logf("ep0_state now DATA_STATE_RECV"); + } + } +} + +/* -------------------------------- */ +/* Interrupt handler */ +/* -------------------------------- */ + +static void reset_irq(void); +static void port_change_irq(void); +static void suspend_irq(void); +static void resume_irq(void); + +/* + * This function represents the main dispatcher + * for all interrupts happen for us. + */ +void usbdevice_irq(void) { + + unsigned int irq_src = 0; + + if (udc_controller.stopped) { + return; /* ignore irq if we're not running */ + } + + spinlock_lock(&udc_controller.lock); + + /* Read interrupt source */ + irq_src = UDC_USBSTS & 0x1ff; + + /* TODO shoud not happen - or? maybe our irq code ist not correct*/ + if (irq_src == 0x0) { + /* ack interrupt */ + GPIOB_INT_CLR = (1 << 4); + spinlock_unlock(&udc_controller.lock); + return; + } + + /* hmmm...is this right? seems to work though */ + GPIOB_INT_LEV = (GPIOB_INT_LEV & ~(1 << 4)) | + (~GPIOB_INPUT_VAL & (1 << 4)); + + /* Clear notification bits */ + UDC_USBSTS &= irq_src; + logf("irq_src [0x%08x]", irq_src); + + /* Look what kind of interrupt */ + + /* USB Interrupt */ + if (irq_src & USB_STS_INT) { + + logf("!!!!!!!!!!!!!!!!!"); + logf("endptsetupstat=0x%x", UDC_ENDPTSETUPSTAT); + logf("endptcomplete=0x%x", UDC_ENDPTCOMPLETE); + + /* Setup packet, we only support ep0 as control ep */ + if (UDC_ENDPTSETUPSTAT & EP_SETUP_STATUS_EP0) { + logf("usb: setup request"); + tripwire_handler(0); + setup_received_irq(&udc_controller.local_setup_buff); + } + + if (UDC_ENDPTCOMPLETE) { + } + } + + /* SOF (for ISO transfer) */ + if (irq_src & USB_STS_SOF) { + logf("usb: start of frame"); + } + + /* Port Change */ + if (irq_src & USB_STS_PORT_CHANGE) { + port_change_irq(); + } + + /* Reset Received */ + if (irq_src & USB_STS_RESET) { + reset_irq(); + } + + /* Sleep Enable (Suspend) */ + /* + if (irq_src & USB_STS_SUSPEND) { + logf("suspend_irq start"); + suspend_irq(); + logf("suspend_irq start"); + } else if (udc_controller.resume_state) { + logf("resume_irq start"); + resume_irq(); + logf("resume_irq start"); + }*/ + + if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { + logf("arcotg: error"); + } + + /* ack interrupt */ + GPIOB_INT_CLR = (1 << 4); + + spinlock_unlock(&udc_controller.lock); +} + +static void suspend_irq(void) { + udc_controller.resume_state = udc_controller.usb_state; + udc_controller.usb_state = USB_STATE_SUSPENDED; + + /* report suspend to the driver */ + if (udc_controller.driver->suspend) { + udc_controller.driver->suspend(&udc_controller.gadget); + } +} + +static void resume_irq(void) { + udc_controller.usb_state = udc_controller.resume_state; + udc_controller.resume_state = 0; + + /* report resume to the driver */ + if (udc_controller.driver->resume) { + udc_controller.driver->resume(&udc_controller.gadget); + } +} + +static void reset_irq(void) { + + /* Clear the device address */ + UDC_DEVICEADDR &= ~USB_DEVICE_ADDRESS_MASK; + logf("arcotg: set deviceaddr to %d", UDC_DEVICEADDR >> USB_DEVICE_ADDRESS_BIT_POS); + udc_controller.device_address = 0; + + /* Clear usb state */ + udc_controller.usb_state = USB_STATE_DEFAULT; + + /* Clear all the setup token semaphores */ + UDC_ENDPTSETUPSTAT = UDC_ENDPTSETUPSTAT; + + /* Clear all the endpoint complete status bits */ + UDC_ENDPTCOMPLETE = UDC_ENDPTCOMPLETE; + + timeout = 10000000; + /* Wait until all endptprime bits cleared */ + while (UDC_ENDPTPRIME && --timeout) { + continue; + } + + if (timeout == 0) { + logf("arcotg: %s: TIMEOUT\n", __FUNCTION__); + } + + /* Write 1s to the Flush register */ + UDC_ENDPTFLUSH = 0xFFFFFFFF; + + if (UDC_PORTSC1 & PORTSCX_PORT_RESET) { + logf("arcotg: Bus RESET"); + /* Bus is reseting */ + udc_controller.bus_reset = TRUE; + udc_controller.ep0_state = WAIT_FOR_SETUP; + logf("ep0_state now WAIT_FOR_SETUP"); + udc_controller.ep0_dir = 0; + /* Reset all the queues, include XD, dTD, EP queue + * head and TR Queue */ + //reset_queues(udc); + } else { + logf("arcotg: Controller reset"); + /* initialize usb hw reg except for regs for EP, not + * touch usbintr reg */ + dr_controller_setup(); + /* Enable DR IRQ reg, Set Run bit, change udc state */ + /* setup ep0 */ + struct_ep_qh_setup(&udc_controller, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0); + struct_ep_qh_setup(&udc_controller, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0); + dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); + dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); + + dr_controller_run(); + udc_controller.usb_state = USB_STATE_ATTACHED; + udc_controller.ep0_state = WAIT_FOR_SETUP; + logf("ep0_state now WAIT_FOR_SETUP"); + udc_controller.ep0_dir = 0; + } +} + +static void port_change_irq(void) { + unsigned int speed; + + if (udc_controller.bus_reset) { + udc_controller.bus_reset = FALSE; + } + + /* Bus resetting is finished */ + if (!(UDC_PORTSC1 & PORTSCX_PORT_RESET)) { + /* Get the speed */ + speed = (UDC_PORTSC1 & PORTSCX_PORT_SPEED_MASK); + switch (speed) { + case PORTSCX_PORT_SPEED_HIGH: + udc_controller.gadget.speed = USB_SPEED_HIGH; + break; + case PORTSCX_PORT_SPEED_FULL: + udc_controller.gadget.speed = USB_SPEED_FULL; + break; + case PORTSCX_PORT_SPEED_LOW: + udc_controller.gadget.speed = USB_SPEED_LOW; + break; + default: + udc_controller.gadget.speed = USB_SPEED_UNKNOWN; + break; + } + } + + logf("arcotg: new speed %d", udc_controller.gadget.speed); + + /* Update USB state */ + if (!udc_controller.resume_state) { + udc_controller.usb_state = USB_STATE_DEFAULT; + } +} + + /* @qh_addr is the aligned virt addr of ep QH addr * it is used to set endpointlistaddr Reg */ /* was static int dr_controller_setup(void *qh_addr) */ int dr_controller_setup(void) { + int i; #if 0 struct arc_usb_config *config; @@ -51,6 +857,73 @@ return -EINVAL; #endif + /* setup udc_controller */ + /* Maybe we can find a better place for this... in the linux dirver + there is a probe function, which gets called when module gets load. */ + if (!initialized) { + logf("arcotg: intitialise"); + + /* set everything to 0 */ + memset(&udc_controller, 0, sizeof(struct arcotg_udc)); + + udc_controller.resume_state = USB_STATE_NOTATTACHED; + udc_controller.usb_state = USB_STATE_POWERED; + udc_controller.ep0_dir = 0; + spinlock_init(&udc_controller.lock); + + /* here comes the stand operations for probe + * set the arcotg_udc->gadget.xxx + */ + udc_controller.gadget.ops = &arcotg_gadget_ops; + udc_controller.gadget.is_dualspeed = 1; + +#if 0 + /* gadget.ep0 is a pointer */ + udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; + + INIT_LIST_HEAD(&udc_controller->gadget.ep_list); +#endif + udc_controller.gadget.speed = USB_SPEED_UNKNOWN; +#if 0 + /* name: Identifies the controller hardware type. */ + udc_controller->gadget.name = driver_name; + + device_initialize(&udc_controller->gadget.dev); + + strcpy(udc_controller->gadget.dev.bus_id, "gadget"); + + udc_controller->gadget.dev.release = arcotg_udc_release; + udc_controller->gadget.dev.parent = &pdev->dev; + + if (udc_controller->transceiver) { + udc_controller->gadget.is_otg = 1; + } +#endif + /* for an EP, the intialization includes: fields in QH, Regs, + * arcotg_ep struct */ + + /* setup ep0 */ + struct_ep_qh_setup(&udc_controller, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0); + struct_ep_qh_setup(&udc_controller, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD, 0, 0); + dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); + dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); + + for (i = 0; i < USB_MAX_PIPES; i++) { + /* because the ep type is not decide here so + * struct_ep_qh_setup() and dr_ep_setup() + * should be called in ep_enable() + */ + if (ep_name[i] != NULL) { + logf("usb: struct_ep_setup %d", i); + /* setup the arcotg_ep struct and link ep.ep.list + * into gadget.ep_list */ + struct_ep_setup(i); + } + } + + initialized = 1; + } + /* Stop and reset the usb controller */ UDC_USBCMD &= ~USB_CMD_RUN_STOP; @@ -58,12 +931,11 @@ /* Wait for reset to complete */ timeout = 10000000; - while ((UDC_USBCMD & USB_CMD_CTRL_RESET) && - --timeout) { + while ((UDC_USBCMD & USB_CMD_CTRL_RESET) && --timeout) { continue; } if (timeout == 0) { - logf("%s: TIMEOUT", __FUNCTION__); + logf("arcotg: %s: TIMEOUT", __FUNCTION__); return -ETIMEDOUT; } @@ -72,11 +944,10 @@ /* Clear the setup status */ UDC_USBSTS = 0; -#if 0 - UDC_ENDPOINTLISTADDR = (unsigned int)qh_addr & USB_EP_LIST_ADDRESS_MASK; - - VDBG("qh_addr=0x%x epla_reg=0x%8x", qh_addr, UOG_ASYNCLISTADDR); -#endif + + UDC_ENDPOINTLISTADDR = (unsigned int)udc_controller.ep_qh & USB_EP_LIST_ADDRESS_MASK; + logf("qh_addr=0x%x", udc_controller.ep_qh); + UDC_PORTSC1 = (UDC_PORTSC1 & ~PORTSCX_PHY_TYPE_SEL) | PORTSCX_PTS_UTMI; #if 0 if (config->set_vbus_power) @@ -90,14 +961,14 @@ /* was static void dr_controller_run(struct arcotg_udc *udc) */ void dr_controller_run(void) { - /*Enable DR irq reg */ + /* Enable DR irq reg */ UDC_USBINTR = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; -#if 0 + /* Clear stopped bit */ - udc->stopped = 0; -#endif + udc_controller.stopped = 0; + /* Set the controller as device mode */ UDC_USBMODE |= USB_MODE_CTRL_MODE_DEVICE; @@ -126,10 +997,10 @@ /* disable all INTR */ UDC_USBINTR = 0; -#if 0 + /* Set stopped bit */ - udc->stopped = 1; -#endif + udc_controller.stopped = 1; + /* Set controller to Stop */ UDC_USBCMD &= ~USB_CMD_RUN_STOP; }