| /* | 
 |  * (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) | 
 | { | 
 | 	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); | 
 | 	} | 
 | } |