123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683 |
- /*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- * Stuart Lynne <sl@lineo.com>,
- * Tom Rushworth <tbr@lineo.com>,
- * Bruce Balden <balden@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
- #include <malloc.h>
- #include <usbdevice.h>
- #define MAX_INTERFACES 2
- int maxstrings = 20;
- /* Global variables ************************************************************************** */
- struct usb_string_descriptor **usb_strings;
- int usb_devices;
- extern struct usb_function_driver ep0_driver;
- int registered_functions;
- int registered_devices;
- char *usbd_device_events[] = {
- "DEVICE_UNKNOWN",
- "DEVICE_INIT",
- "DEVICE_CREATE",
- "DEVICE_HUB_CONFIGURED",
- "DEVICE_RESET",
- "DEVICE_ADDRESS_ASSIGNED",
- "DEVICE_CONFIGURED",
- "DEVICE_SET_INTERFACE",
- "DEVICE_SET_FEATURE",
- "DEVICE_CLEAR_FEATURE",
- "DEVICE_DE_CONFIGURED",
- "DEVICE_BUS_INACTIVE",
- "DEVICE_BUS_ACTIVITY",
- "DEVICE_POWER_INTERRUPTION",
- "DEVICE_HUB_RESET",
- "DEVICE_DESTROY",
- "DEVICE_FUNCTION_PRIVATE",
- };
- char *usbd_device_states[] = {
- "STATE_INIT",
- "STATE_CREATED",
- "STATE_ATTACHED",
- "STATE_POWERED",
- "STATE_DEFAULT",
- "STATE_ADDRESSED",
- "STATE_CONFIGURED",
- "STATE_UNKNOWN",
- };
- char *usbd_device_requests[] = {
- "GET STATUS", /* 0 */
- "CLEAR FEATURE", /* 1 */
- "RESERVED", /* 2 */
- "SET FEATURE", /* 3 */
- "RESERVED", /* 4 */
- "SET ADDRESS", /* 5 */
- "GET DESCRIPTOR", /* 6 */
- "SET DESCRIPTOR", /* 7 */
- "GET CONFIGURATION", /* 8 */
- "SET CONFIGURATION", /* 9 */
- "GET INTERFACE", /* 10 */
- "SET INTERFACE", /* 11 */
- "SYNC FRAME", /* 12 */
- };
- char *usbd_device_descriptors[] = {
- "UNKNOWN", /* 0 */
- "DEVICE", /* 1 */
- "CONFIG", /* 2 */
- "STRING", /* 3 */
- "INTERFACE", /* 4 */
- "ENDPOINT", /* 5 */
- "DEVICE QUALIFIER", /* 6 */
- "OTHER SPEED", /* 7 */
- "INTERFACE POWER", /* 8 */
- };
- char *usbd_device_status[] = {
- "USBD_OPENING",
- "USBD_OK",
- "USBD_SUSPENDED",
- "USBD_CLOSING",
- };
- /* Descriptor support functions ************************************************************** */
- /**
- * usbd_get_string - find and return a string descriptor
- * @index: string index to return
- *
- * Find an indexed string and return a pointer to a it.
- */
- struct usb_string_descriptor *usbd_get_string (__u8 index)
- {
- if (index >= maxstrings) {
- return NULL;
- }
- return usb_strings[index];
- }
- /* Access to device descriptor functions ***************************************************** */
- /* *
- * usbd_device_configuration_instance - find a configuration instance for this device
- * @device:
- * @configuration: index to configuration, 0 - N-1
- *
- * Get specifed device configuration. Index should be bConfigurationValue-1.
- */
- static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
- unsigned int port, unsigned int configuration)
- {
- if (configuration >= device->configurations)
- return NULL;
- return device->configuration_instance_array + configuration;
- }
- /* *
- * usbd_device_interface_instance
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- *
- * Return the specified interface descriptor for the specified device.
- */
- struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
- {
- struct usb_configuration_instance *configuration_instance;
- if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
- return NULL;
- }
- if (interface >= configuration_instance->interfaces) {
- return NULL;
- }
- return configuration_instance->interface_instance_array + interface;
- }
- /* *
- * usbd_device_alternate_descriptor_list
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified alternate descriptor for the specified device.
- */
- struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
- {
- struct usb_interface_instance *interface_instance;
- if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
- return NULL;
- }
- if (alternate >= interface_instance->alternates) {
- return NULL;
- }
- return interface_instance->alternates_instance_array + alternate;
- }
- /* *
- * usbd_device_device_descriptor
- * @device: which device
- * @configuration: index to configuration, 0 - N-1
- * @port: which port
- *
- * Return the specified configuration descriptor for the specified device.
- */
- struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
- {
- return (device->device_descriptor);
- }
- /**
- * usbd_device_configuration_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- *
- * Return the specified configuration descriptor for the specified device.
- */
- struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
- usb_device_instance
- *device, int port, int configuration)
- {
- struct usb_configuration_instance *configuration_instance;
- if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
- return NULL;
- }
- return (configuration_instance->configuration_descriptor);
- }
- /**
- * usbd_device_interface_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified interface descriptor for the specified device.
- */
- struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
- *device, int port, int configuration, int interface, int alternate)
- {
- struct usb_interface_instance *interface_instance;
- if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
- return NULL;
- }
- if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
- return NULL;
- }
- return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
- }
- /**
- * usbd_device_endpoint_descriptor_index
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: index setting
- * @index: which index
- *
- * Return the specified endpoint descriptor for the specified device.
- */
- struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
- *device, int port, int configuration, int interface, int alternate, int index)
- {
- struct usb_alternate_instance *alternate_instance;
- if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
- return NULL;
- }
- if (index >= alternate_instance->endpoints) {
- return NULL;
- }
- return *(alternate_instance->endpoints_descriptor_array + index);
- }
- /**
- * usbd_device_endpoint_transfersize
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @index: which index
- *
- * Return the specified endpoint transfer size;
- */
- int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
- {
- struct usb_alternate_instance *alternate_instance;
- if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
- return 0;
- }
- if (index >= alternate_instance->endpoints) {
- return 0;
- }
- return *(alternate_instance->endpoint_transfersize_array + index);
- }
- /**
- * usbd_device_endpoint_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- * @endpoint: which endpoint
- *
- * Return the specified endpoint descriptor for the specified device.
- */
- struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
- {
- struct usb_endpoint_descriptor *endpoint_descriptor;
- int i;
- for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
- if (endpoint_descriptor->bEndpointAddress == endpoint) {
- return endpoint_descriptor;
- }
- }
- return NULL;
- }
- /**
- * usbd_endpoint_halted
- * @device: point to struct usb_device_instance
- * @endpoint: endpoint to check
- *
- * Return non-zero if endpoint is halted.
- */
- int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
- {
- return (device->status == USB_STATUS_HALT);
- }
- /**
- * usbd_rcv_complete - complete a receive
- * @endpoint:
- * @len:
- * @urb_bad:
- *
- * Called from rcv interrupt to complete.
- */
- void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
- {
- if (endpoint) {
- struct urb *rcv_urb;
- /*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
- /* if we had an urb then update actual_length, dispatch if neccessary */
- if ((rcv_urb = endpoint->rcv_urb)) {
- /*usbdbg("actual: %d buffer: %d\n", */
- /*rcv_urb->actual_length, rcv_urb->buffer_length); */
- /* check the urb is ok, are we adding data less than the packetsize */
- if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
- /*usbdbg("updating actual_length by %d\n",len); */
- /* increment the received data size */
- rcv_urb->actual_length += len;
- } else {
- usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
- rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
- rcv_urb->actual_length = 0;
- rcv_urb->status = RECV_ERROR;
- }
- } else {
- usberr("no rcv_urb!");
- }
- } else {
- usberr("no endpoint!");
- }
- }
- /**
- * usbd_tx_complete - complete a transmit
- * @endpoint:
- * @resetart:
- *
- * Called from tx interrupt to complete.
- */
- void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
- {
- if (endpoint) {
- struct urb *tx_urb;
- /* if we have a tx_urb advance or reset, finish if complete */
- if ((tx_urb = endpoint->tx_urb)) {
- int sent = endpoint->last;
- endpoint->sent += sent;
- endpoint->last -= sent;
- if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
- tx_urb->actual_length = 0;
- endpoint->sent = 0;
- endpoint->last = 0;
- /* Remove from active, save for re-use */
- urb_detach(tx_urb);
- urb_append(&endpoint->done, tx_urb);
- /*usbdbg("done->next %p, tx_urb %p, done %p", */
- /* endpoint->done.next, tx_urb, &endpoint->done); */
- endpoint->tx_urb = first_urb_detached(&endpoint->tx);
- if( endpoint->tx_urb ) {
- endpoint->tx_queue--;
- usbdbg("got urb from tx list");
- }
- if( !endpoint->tx_urb ) {
- /*usbdbg("taking urb from done list"); */
- endpoint->tx_urb = first_urb_detached(&endpoint->done);
- }
- if( !endpoint->tx_urb ) {
- usbdbg("allocating new urb for tx_urb");
- endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
- }
- }
- }
- }
- }
- /* URB linked list functions ***************************************************** */
- /*
- * Initialize an urb_link to be a single element list.
- * If the urb_link is being used as a distinguished list head
- * the list is empty when the head is the only link in the list.
- */
- void urb_link_init (urb_link * ul)
- {
- if (ul) {
- ul->prev = ul->next = ul;
- }
- }
- /*
- * Detach an urb_link from a list, and set it
- * up as a single element list, so no dangling
- * pointers can be followed, and so it can be
- * joined to another list if so desired.
- */
- void urb_detach (struct urb *urb)
- {
- if (urb) {
- urb_link *ul = &urb->link;
- ul->next->prev = ul->prev;
- ul->prev->next = ul->next;
- urb_link_init (ul);
- }
- }
- /*
- * Return the first urb_link in a list with a distinguished
- * head "hd", or NULL if the list is empty. This will also
- * work as a predicate, returning NULL if empty, and non-NULL
- * otherwise.
- */
- urb_link *first_urb_link (urb_link * hd)
- {
- urb_link *nx;
- if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
- /* There is at least one element in the list */
- /* (besides the distinguished head). */
- return (nx);
- }
- /* The list is empty */
- return (NULL);
- }
- /*
- * Return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- */
- struct urb *first_urb (urb_link * hd)
- {
- urb_link *nx;
- if (NULL == (nx = first_urb_link (hd))) {
- /* The list is empty */
- return (NULL);
- }
- return (p2surround (struct urb, link, nx));
- }
- /*
- * Detach and return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- *
- */
- struct urb *first_urb_detached (urb_link * hd)
- {
- struct urb *urb;
- if ((urb = first_urb (hd))) {
- urb_detach (urb);
- }
- return urb;
- }
- /*
- * Append an urb_link (or a whole list of
- * urb_links) to the tail of another list
- * of urb_links.
- */
- void urb_append (urb_link * hd, struct urb *urb)
- {
- if (hd && urb) {
- urb_link *new = &urb->link;
- /* This allows the new urb to be a list of urbs, */
- /* with new pointing at the first, but the link */
- /* must be initialized. */
- /* Order is important here... */
- urb_link *pul = hd->prev;
- new->prev->next = hd;
- hd->prev = new->prev;
- new->prev = pul;
- pul->next = new;
- }
- }
- /* URB create/destroy functions ***************************************************** */
- /**
- * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
- * @device: device instance
- * @endpoint: endpoint
- *
- * Allocate an urb structure. The usb device urb structure is used to
- * contain all data associated with a transfer, including a setup packet for
- * control transfers.
- *
- * NOTE: endpoint_address MUST contain a direction flag.
- */
- struct urb *usbd_alloc_urb (struct usb_device_instance *device,
- struct usb_endpoint_instance *endpoint)
- {
- struct urb *urb;
- if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
- usberr (" F A T A L: malloc(%zu) FAILED!!!!",
- sizeof (struct urb));
- return NULL;
- }
- /* Fill in known fields */
- memset (urb, 0, sizeof (struct urb));
- urb->endpoint = endpoint;
- urb->device = device;
- urb->buffer = (u8 *) urb->buffer_data;
- urb->buffer_length = sizeof (urb->buffer_data);
- urb_link_init (&urb->link);
- return urb;
- }
- /**
- * usbd_dealloc_urb - deallocate an URB and associated buffer
- * @urb: pointer to an urb structure
- *
- * Deallocate an urb structure and associated data.
- */
- void usbd_dealloc_urb (struct urb *urb)
- {
- if (urb) {
- free (urb);
- }
- }
- /* Event signaling functions ***************************************************** */
- /**
- * usbd_device_event - called to respond to various usb events
- * @device: pointer to struct device
- * @event: event to respond to
- *
- * Used by a Bus driver to indicate an event.
- */
- void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
- {
- usb_device_state_t state;
- if (!device || !device->bus) {
- usberr("(%p,%d) NULL device or device->bus", device, event);
- return;
- }
- state = device->device_state;
- usbinfo("%s", usbd_device_events[event]);
- switch (event) {
- case DEVICE_UNKNOWN:
- break;
- case DEVICE_INIT:
- device->device_state = STATE_INIT;
- break;
- case DEVICE_CREATE:
- device->device_state = STATE_ATTACHED;
- break;
- case DEVICE_HUB_CONFIGURED:
- device->device_state = STATE_POWERED;
- break;
- case DEVICE_RESET:
- device->device_state = STATE_DEFAULT;
- device->address = 0;
- break;
- case DEVICE_ADDRESS_ASSIGNED:
- device->device_state = STATE_ADDRESSED;
- break;
- case DEVICE_CONFIGURED:
- device->device_state = STATE_CONFIGURED;
- break;
- case DEVICE_DE_CONFIGURED:
- device->device_state = STATE_ADDRESSED;
- break;
- case DEVICE_BUS_INACTIVE:
- if (device->status != USBD_CLOSING) {
- device->status = USBD_SUSPENDED;
- }
- break;
- case DEVICE_BUS_ACTIVITY:
- if (device->status != USBD_CLOSING) {
- device->status = USBD_OK;
- }
- break;
- case DEVICE_SET_INTERFACE:
- break;
- case DEVICE_SET_FEATURE:
- break;
- case DEVICE_CLEAR_FEATURE:
- break;
- case DEVICE_POWER_INTERRUPTION:
- device->device_state = STATE_POWERED;
- break;
- case DEVICE_HUB_RESET:
- device->device_state = STATE_ATTACHED;
- break;
- case DEVICE_DESTROY:
- device->device_state = STATE_UNKNOWN;
- break;
- case DEVICE_FUNCTION_PRIVATE:
- break;
- default:
- usbdbg("event %d - not handled",event);
- break;
- }
- /*usbdbg("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
- device->name, event, state,
- device->device_state, device->status, device->address); */
- /* tell the bus interface driver */
- if( device->event ) {
- /* usbdbg("calling device->event"); */
- device->event(device, event, data);
- }
- }
|