|  | /* | 
|  | * (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 "usbdcore.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) | 
|  | { | 
|  | /* XXX */ | 
|  | configuration = configuration ? configuration - 1 : 0; | 
|  |  | 
|  | 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(%u) 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); | 
|  | } | 
|  | } |