xref: /rk3399_rockchip-uboot/drivers/usb/gadget/core.c (revision 326ea986ac150acdc7656d57fca647db80b50158)
12731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
22731b9a8SJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2003
32731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Gerry Hamel, geh@ti.com, Texas Instruments
42731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
52731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Based on
62731b9a8SJean-Christophe PLAGNIOL-VILLARD  * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
72731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
82731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Copyright (c) 2000, 2001, 2002 Lineo
92731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Copyright (c) 2001 Hewlett Packard
102731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
112731b9a8SJean-Christophe PLAGNIOL-VILLARD  * By:
122731b9a8SJean-Christophe PLAGNIOL-VILLARD  *	Stuart Lynne <sl@lineo.com>,
132731b9a8SJean-Christophe PLAGNIOL-VILLARD  *	Tom Rushworth <tbr@lineo.com>,
142731b9a8SJean-Christophe PLAGNIOL-VILLARD  *	Bruce Balden <balden@lineo.com>
152731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
16*1a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
172731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
182731b9a8SJean-Christophe PLAGNIOL-VILLARD 
192731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <malloc.h>
202731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <usbdevice.h>
212731b9a8SJean-Christophe PLAGNIOL-VILLARD 
222731b9a8SJean-Christophe PLAGNIOL-VILLARD #define MAX_INTERFACES 2
232731b9a8SJean-Christophe PLAGNIOL-VILLARD 
242731b9a8SJean-Christophe PLAGNIOL-VILLARD 
252731b9a8SJean-Christophe PLAGNIOL-VILLARD int maxstrings = 20;
262731b9a8SJean-Christophe PLAGNIOL-VILLARD 
272731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Global variables ************************************************************************** */
282731b9a8SJean-Christophe PLAGNIOL-VILLARD 
292731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_string_descriptor **usb_strings;
302731b9a8SJean-Christophe PLAGNIOL-VILLARD 
312731b9a8SJean-Christophe PLAGNIOL-VILLARD int usb_devices;
322731b9a8SJean-Christophe PLAGNIOL-VILLARD 
332731b9a8SJean-Christophe PLAGNIOL-VILLARD extern struct usb_function_driver ep0_driver;
342731b9a8SJean-Christophe PLAGNIOL-VILLARD 
352731b9a8SJean-Christophe PLAGNIOL-VILLARD int registered_functions;
362731b9a8SJean-Christophe PLAGNIOL-VILLARD int registered_devices;
372731b9a8SJean-Christophe PLAGNIOL-VILLARD 
382731b9a8SJean-Christophe PLAGNIOL-VILLARD char *usbd_device_events[] = {
392731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_UNKNOWN",
402731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_INIT",
412731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_CREATE",
422731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_HUB_CONFIGURED",
432731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_RESET",
442731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_ADDRESS_ASSIGNED",
452731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_CONFIGURED",
462731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_SET_INTERFACE",
472731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_SET_FEATURE",
482731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_CLEAR_FEATURE",
492731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_DE_CONFIGURED",
502731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_BUS_INACTIVE",
512731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_BUS_ACTIVITY",
522731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_POWER_INTERRUPTION",
532731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_HUB_RESET",
542731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_DESTROY",
552731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE_FUNCTION_PRIVATE",
562731b9a8SJean-Christophe PLAGNIOL-VILLARD };
572731b9a8SJean-Christophe PLAGNIOL-VILLARD 
582731b9a8SJean-Christophe PLAGNIOL-VILLARD char *usbd_device_states[] = {
592731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_INIT",
602731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_CREATED",
612731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_ATTACHED",
622731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_POWERED",
632731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_DEFAULT",
642731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_ADDRESSED",
652731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_CONFIGURED",
662731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STATE_UNKNOWN",
672731b9a8SJean-Christophe PLAGNIOL-VILLARD };
682731b9a8SJean-Christophe PLAGNIOL-VILLARD 
692731b9a8SJean-Christophe PLAGNIOL-VILLARD char *usbd_device_requests[] = {
702731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"GET STATUS",		/* 0 */
712731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"CLEAR FEATURE",	/* 1 */
722731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"RESERVED",		/* 2 */
732731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"SET FEATURE",		/* 3 */
742731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"RESERVED",		/* 4 */
752731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"SET ADDRESS",		/* 5 */
762731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"GET DESCRIPTOR",	/* 6 */
772731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"SET DESCRIPTOR",	/* 7 */
782731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"GET CONFIGURATION",	/* 8 */
792731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"SET CONFIGURATION",	/* 9 */
802731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"GET INTERFACE",	/* 10 */
812731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"SET INTERFACE",	/* 11 */
822731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"SYNC FRAME",		/* 12 */
832731b9a8SJean-Christophe PLAGNIOL-VILLARD };
842731b9a8SJean-Christophe PLAGNIOL-VILLARD 
852731b9a8SJean-Christophe PLAGNIOL-VILLARD char *usbd_device_descriptors[] = {
862731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"UNKNOWN",		/* 0 */
872731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE",		/* 1 */
882731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"CONFIG",		/* 2 */
892731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"STRING",		/* 3 */
902731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"INTERFACE",		/* 4 */
912731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"ENDPOINT",		/* 5 */
922731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"DEVICE QUALIFIER",	/* 6 */
932731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"OTHER SPEED",		/* 7 */
942731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"INTERFACE POWER",	/* 8 */
952731b9a8SJean-Christophe PLAGNIOL-VILLARD };
962731b9a8SJean-Christophe PLAGNIOL-VILLARD 
972731b9a8SJean-Christophe PLAGNIOL-VILLARD char *usbd_device_status[] = {
982731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"USBD_OPENING",
992731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"USBD_OK",
1002731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"USBD_SUSPENDED",
1012731b9a8SJean-Christophe PLAGNIOL-VILLARD 	"USBD_CLOSING",
1022731b9a8SJean-Christophe PLAGNIOL-VILLARD };
1032731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1042731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1052731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Descriptor support functions ************************************************************** */
1062731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1072731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1082731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
1092731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_get_string - find and return a string descriptor
1102731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @index: string index to return
1112731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
1122731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Find an indexed string and return a pointer to a it.
1132731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_get_string(__u8 index)1142731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_string_descriptor *usbd_get_string (__u8 index)
1152731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1162731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (index >= maxstrings) {
1172731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
1182731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
1192731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return usb_strings[index];
1202731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1212731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1222731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1232731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Access to device descriptor functions ***************************************************** */
1242731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1252731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1262731b9a8SJean-Christophe PLAGNIOL-VILLARD /* *
1272731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_configuration_instance - find a configuration instance for this device
1282731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device:
1292731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
1302731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
1312731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Get specifed device configuration. Index should be bConfigurationValue-1.
1322731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_configuration_instance(struct usb_device_instance * device,unsigned int port,unsigned int configuration)1332731b9a8SJean-Christophe PLAGNIOL-VILLARD static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
1342731b9a8SJean-Christophe PLAGNIOL-VILLARD 		unsigned int port, unsigned int configuration)
1352731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1362731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (configuration >= device->configurations)
1372731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
1382731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1392731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return device->configuration_instance_array + configuration;
1402731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1412731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1422731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1432731b9a8SJean-Christophe PLAGNIOL-VILLARD /* *
1442731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_interface_instance
1452731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device:
1462731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
1472731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @interface: index to interface
1482731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
1492731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified interface descriptor for the specified device.
1502731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_interface_instance(struct usb_device_instance * device,int port,int configuration,int interface)1512731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
1522731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1532731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct usb_configuration_instance *configuration_instance;
1542731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1552731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
1562731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
1572731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
1582731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (interface >= configuration_instance->interfaces) {
1592731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
1602731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
1612731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return configuration_instance->interface_instance_array + interface;
1622731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1632731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1642731b9a8SJean-Christophe PLAGNIOL-VILLARD /* *
1652731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_alternate_descriptor_list
1662731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device:
1672731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
1682731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @interface: index to interface
1692731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @alternate: alternate setting
1702731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
1712731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified alternate descriptor for the specified device.
1722731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_alternate_instance(struct usb_device_instance * device,int port,int configuration,int interface,int alternate)1732731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
1742731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1752731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct usb_interface_instance *interface_instance;
1762731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1772731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
1782731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
1792731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
1802731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1812731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (alternate >= interface_instance->alternates) {
1822731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
1832731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
1842731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1852731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return interface_instance->alternates_instance_array + alternate;
1862731b9a8SJean-Christophe PLAGNIOL-VILLARD }
1872731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1882731b9a8SJean-Christophe PLAGNIOL-VILLARD 
1892731b9a8SJean-Christophe PLAGNIOL-VILLARD /* *
1902731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_device_descriptor
1912731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: which device
1922731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
1932731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @port: which port
1942731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
1952731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified configuration descriptor for the specified device.
1962731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_device_descriptor(struct usb_device_instance * device,int port)1972731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
1982731b9a8SJean-Christophe PLAGNIOL-VILLARD {
1992731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return (device->device_descriptor);
2002731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2012731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2022731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
2032731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_configuration_descriptor
2042731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: which device
2052731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @port: which port
2062731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
2072731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
2082731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified configuration descriptor for the specified device.
2092731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_configuration_descriptor(struct usb_device_instance * device,int port,int configuration)2102731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
2112731b9a8SJean-Christophe PLAGNIOL-VILLARD 									   usb_device_instance
2122731b9a8SJean-Christophe PLAGNIOL-VILLARD 									   *device, int port, int configuration)
2132731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2142731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct usb_configuration_instance *configuration_instance;
2152731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
2162731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
2172731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
2182731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return (configuration_instance->configuration_descriptor);
2192731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2202731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2212731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2222731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
2232731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_interface_descriptor
2242731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: which device
2252731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @port: which port
2262731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
2272731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @interface: index to interface
2282731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @alternate: alternate setting
2292731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
2302731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified interface descriptor for the specified device.
2312731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_interface_descriptor(struct usb_device_instance * device,int port,int configuration,int interface,int alternate)2322731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
2332731b9a8SJean-Christophe PLAGNIOL-VILLARD 								   *device, int port, int configuration, int interface, int alternate)
2342731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2352731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct usb_interface_instance *interface_instance;
2362731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
2372731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
2382731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
2392731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
2402731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
2412731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
2422731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
2432731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2442731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2452731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
2462731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_endpoint_descriptor_index
2472731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: which device
2482731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @port: which port
2492731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
2502731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @interface: index to interface
2512731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @alternate: index setting
2522731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @index: which index
2532731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
2542731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified endpoint descriptor for the specified device.
2552731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_endpoint_descriptor_index(struct usb_device_instance * device,int port,int configuration,int interface,int alternate,int index)2562731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
2572731b9a8SJean-Christophe PLAGNIOL-VILLARD 								       *device, int port, int configuration, int interface, int alternate, int index)
2582731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2592731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct usb_alternate_instance *alternate_instance;
2602731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2612731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
2622731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
2632731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
2642731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (index >= alternate_instance->endpoints) {
2652731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
2662731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
2672731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return *(alternate_instance->endpoints_descriptor_array + index);
2682731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2692731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2702731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2712731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
2722731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_endpoint_transfersize
2732731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: which device
2742731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @port: which port
2752731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
2762731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @interface: index to interface
2772731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @index: which index
2782731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
2792731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified endpoint transfer size;
2802731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_endpoint_transfersize(struct usb_device_instance * device,int port,int configuration,int interface,int alternate,int index)2812731b9a8SJean-Christophe PLAGNIOL-VILLARD int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
2822731b9a8SJean-Christophe PLAGNIOL-VILLARD {
2832731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct usb_alternate_instance *alternate_instance;
2842731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2852731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
2862731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return 0;
2872731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
2882731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (index >= alternate_instance->endpoints) {
2892731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return 0;
2902731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
2912731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return *(alternate_instance->endpoint_transfersize_array + index);
2922731b9a8SJean-Christophe PLAGNIOL-VILLARD }
2932731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2942731b9a8SJean-Christophe PLAGNIOL-VILLARD 
2952731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
2962731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_endpoint_descriptor
2972731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: which device
2982731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @port: which port
2992731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @configuration: index to configuration, 0 - N-1
3002731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @interface: index to interface
3012731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @alternate: alternate setting
3022731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @endpoint: which endpoint
3032731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
3042731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the specified endpoint descriptor for the specified device.
3052731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_endpoint_descriptor(struct usb_device_instance * device,int port,int configuration,int interface,int alternate,int endpoint)3062731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
3072731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3082731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct usb_endpoint_descriptor *endpoint_descriptor;
3092731b9a8SJean-Christophe PLAGNIOL-VILLARD 	int i;
3102731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3112731b9a8SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
3122731b9a8SJean-Christophe PLAGNIOL-VILLARD 		if (endpoint_descriptor->bEndpointAddress == endpoint) {
3132731b9a8SJean-Christophe PLAGNIOL-VILLARD 			return endpoint_descriptor;
3142731b9a8SJean-Christophe PLAGNIOL-VILLARD 		}
3152731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
3162731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return NULL;
3172731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3182731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3192731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
3202731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_endpoint_halted
3212731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: point to struct usb_device_instance
3222731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @endpoint: endpoint to check
3232731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
3242731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return non-zero if endpoint is halted.
3252731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_endpoint_halted(struct usb_device_instance * device,int endpoint)3262731b9a8SJean-Christophe PLAGNIOL-VILLARD int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
3272731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3282731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return (device->status == USB_STATUS_HALT);
3292731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3302731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3312731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3322731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
3332731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_rcv_complete - complete a receive
3342731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @endpoint:
3352731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @len:
3362731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @urb_bad:
3372731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
3382731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Called from rcv interrupt to complete.
3392731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_rcv_complete(struct usb_endpoint_instance * endpoint,int len,int urb_bad)3402731b9a8SJean-Christophe PLAGNIOL-VILLARD void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
3412731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3422731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (endpoint) {
3432731b9a8SJean-Christophe PLAGNIOL-VILLARD 		struct urb *rcv_urb;
3442731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3452731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
3462731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3472731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* if we had an urb then update actual_length, dispatch if neccessary */
3482731b9a8SJean-Christophe PLAGNIOL-VILLARD 		if ((rcv_urb = endpoint->rcv_urb)) {
3492731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3502731b9a8SJean-Christophe PLAGNIOL-VILLARD 			/*usbdbg("actual: %d buffer: %d\n", */
3512731b9a8SJean-Christophe PLAGNIOL-VILLARD 			/*rcv_urb->actual_length, rcv_urb->buffer_length); */
3522731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3532731b9a8SJean-Christophe PLAGNIOL-VILLARD 			/* check the urb is ok, are we adding data less than the packetsize */
3542731b9a8SJean-Christophe PLAGNIOL-VILLARD 			if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
3552731b9a8SJean-Christophe PLAGNIOL-VILLARD 			  /*usbdbg("updating actual_length by %d\n",len); */
3562731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3572731b9a8SJean-Christophe PLAGNIOL-VILLARD 				/* increment the received data size */
3582731b9a8SJean-Christophe PLAGNIOL-VILLARD 				rcv_urb->actual_length += len;
3592731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3602731b9a8SJean-Christophe PLAGNIOL-VILLARD 			} else {
3612731b9a8SJean-Christophe PLAGNIOL-VILLARD 				usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
3622731b9a8SJean-Christophe PLAGNIOL-VILLARD 				       rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
3632731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3642731b9a8SJean-Christophe PLAGNIOL-VILLARD 				rcv_urb->actual_length = 0;
3652731b9a8SJean-Christophe PLAGNIOL-VILLARD 				rcv_urb->status = RECV_ERROR;
3662731b9a8SJean-Christophe PLAGNIOL-VILLARD 			}
3672731b9a8SJean-Christophe PLAGNIOL-VILLARD 		} else {
3682731b9a8SJean-Christophe PLAGNIOL-VILLARD 			usberr("no rcv_urb!");
3692731b9a8SJean-Christophe PLAGNIOL-VILLARD 		}
3702731b9a8SJean-Christophe PLAGNIOL-VILLARD 	} else {
3712731b9a8SJean-Christophe PLAGNIOL-VILLARD 		usberr("no endpoint!");
3722731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
3732731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3742731b9a8SJean-Christophe PLAGNIOL-VILLARD }
3752731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3762731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
3772731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_tx_complete - complete a transmit
3782731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @endpoint:
3792731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @resetart:
3802731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
3812731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Called from tx interrupt to complete.
3822731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_tx_complete(struct usb_endpoint_instance * endpoint)3832731b9a8SJean-Christophe PLAGNIOL-VILLARD void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
3842731b9a8SJean-Christophe PLAGNIOL-VILLARD {
3852731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (endpoint) {
3862731b9a8SJean-Christophe PLAGNIOL-VILLARD 		struct urb *tx_urb;
3872731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3882731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* if we have a tx_urb advance or reset, finish if complete */
3892731b9a8SJean-Christophe PLAGNIOL-VILLARD 		if ((tx_urb = endpoint->tx_urb)) {
3902731b9a8SJean-Christophe PLAGNIOL-VILLARD 			int sent = endpoint->last;
3912731b9a8SJean-Christophe PLAGNIOL-VILLARD 			endpoint->sent += sent;
3922731b9a8SJean-Christophe PLAGNIOL-VILLARD 			endpoint->last -= sent;
3932731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3942731b9a8SJean-Christophe PLAGNIOL-VILLARD 			if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
3952731b9a8SJean-Christophe PLAGNIOL-VILLARD 				tx_urb->actual_length = 0;
3962731b9a8SJean-Christophe PLAGNIOL-VILLARD 				endpoint->sent = 0;
3972731b9a8SJean-Christophe PLAGNIOL-VILLARD 				endpoint->last = 0;
3982731b9a8SJean-Christophe PLAGNIOL-VILLARD 
3992731b9a8SJean-Christophe PLAGNIOL-VILLARD 				/* Remove from active, save for re-use */
4002731b9a8SJean-Christophe PLAGNIOL-VILLARD 				urb_detach(tx_urb);
4012731b9a8SJean-Christophe PLAGNIOL-VILLARD 				urb_append(&endpoint->done, tx_urb);
4022731b9a8SJean-Christophe PLAGNIOL-VILLARD 				/*usbdbg("done->next %p, tx_urb %p, done %p", */
4032731b9a8SJean-Christophe PLAGNIOL-VILLARD 				/*	 endpoint->done.next, tx_urb, &endpoint->done); */
4042731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4052731b9a8SJean-Christophe PLAGNIOL-VILLARD 				endpoint->tx_urb = first_urb_detached(&endpoint->tx);
4062731b9a8SJean-Christophe PLAGNIOL-VILLARD 				if( endpoint->tx_urb ) {
4072731b9a8SJean-Christophe PLAGNIOL-VILLARD 					endpoint->tx_queue--;
4082731b9a8SJean-Christophe PLAGNIOL-VILLARD 					usbdbg("got urb from tx list");
4092731b9a8SJean-Christophe PLAGNIOL-VILLARD 				}
4102731b9a8SJean-Christophe PLAGNIOL-VILLARD 				if( !endpoint->tx_urb ) {
4112731b9a8SJean-Christophe PLAGNIOL-VILLARD 					/*usbdbg("taking urb from done list"); */
4122731b9a8SJean-Christophe PLAGNIOL-VILLARD 					endpoint->tx_urb = first_urb_detached(&endpoint->done);
4132731b9a8SJean-Christophe PLAGNIOL-VILLARD 				}
4142731b9a8SJean-Christophe PLAGNIOL-VILLARD 				if( !endpoint->tx_urb ) {
4152731b9a8SJean-Christophe PLAGNIOL-VILLARD 					usbdbg("allocating new urb for tx_urb");
4162731b9a8SJean-Christophe PLAGNIOL-VILLARD 					endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
4172731b9a8SJean-Christophe PLAGNIOL-VILLARD 				}
4182731b9a8SJean-Christophe PLAGNIOL-VILLARD 			}
4192731b9a8SJean-Christophe PLAGNIOL-VILLARD 		}
4202731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
4212731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4222731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4232731b9a8SJean-Christophe PLAGNIOL-VILLARD /* URB linked list functions ***************************************************** */
4242731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4252731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4262731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Initialize an urb_link to be a single element list.
4272731b9a8SJean-Christophe PLAGNIOL-VILLARD  * If the urb_link is being used as a distinguished list head
4282731b9a8SJean-Christophe PLAGNIOL-VILLARD  * the list is empty when the head is the only link in the list.
4292731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
urb_link_init(urb_link * ul)4302731b9a8SJean-Christophe PLAGNIOL-VILLARD void urb_link_init (urb_link * ul)
4312731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4322731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (ul) {
4332731b9a8SJean-Christophe PLAGNIOL-VILLARD 		ul->prev = ul->next = ul;
4342731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
4352731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4362731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4372731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4382731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Detach an urb_link from a list, and set it
4392731b9a8SJean-Christophe PLAGNIOL-VILLARD  * up as a single element list, so no dangling
4402731b9a8SJean-Christophe PLAGNIOL-VILLARD  * pointers can be followed, and so it can be
4412731b9a8SJean-Christophe PLAGNIOL-VILLARD  * joined to another list if so desired.
4422731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
urb_detach(struct urb * urb)4432731b9a8SJean-Christophe PLAGNIOL-VILLARD void urb_detach (struct urb *urb)
4442731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4452731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (urb) {
4462731b9a8SJean-Christophe PLAGNIOL-VILLARD 		urb_link *ul = &urb->link;
4472731b9a8SJean-Christophe PLAGNIOL-VILLARD 		ul->next->prev = ul->prev;
4482731b9a8SJean-Christophe PLAGNIOL-VILLARD 		ul->prev->next = ul->next;
4492731b9a8SJean-Christophe PLAGNIOL-VILLARD 		urb_link_init (ul);
4502731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
4512731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4522731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4532731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4542731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the first urb_link in a list with a distinguished
4552731b9a8SJean-Christophe PLAGNIOL-VILLARD  * head "hd", or NULL if the list is empty.  This will also
4562731b9a8SJean-Christophe PLAGNIOL-VILLARD  * work as a predicate, returning NULL if empty, and non-NULL
4572731b9a8SJean-Christophe PLAGNIOL-VILLARD  * otherwise.
4582731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
first_urb_link(urb_link * hd)4592731b9a8SJean-Christophe PLAGNIOL-VILLARD urb_link *first_urb_link (urb_link * hd)
4602731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4612731b9a8SJean-Christophe PLAGNIOL-VILLARD 	urb_link *nx;
4622731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
4632731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* There is at least one element in the list */
4642731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* (besides the distinguished head). */
4652731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return (nx);
4662731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
4672731b9a8SJean-Christophe PLAGNIOL-VILLARD 	/* The list is empty */
4682731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return (NULL);
4692731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4702731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4712731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4722731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Return the first urb in a list with a distinguished
4732731b9a8SJean-Christophe PLAGNIOL-VILLARD  * head "hd", or NULL if the list is empty.
4742731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
first_urb(urb_link * hd)4752731b9a8SJean-Christophe PLAGNIOL-VILLARD struct urb *first_urb (urb_link * hd)
4762731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4772731b9a8SJean-Christophe PLAGNIOL-VILLARD 	urb_link *nx;
4782731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (NULL == (nx = first_urb_link (hd))) {
4792731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* The list is empty */
4802731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return (NULL);
4812731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
4822731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return (p2surround (struct urb, link, nx));
4832731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4842731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4852731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
4862731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Detach and return the first urb in a list with a distinguished
4872731b9a8SJean-Christophe PLAGNIOL-VILLARD  * head "hd", or NULL if the list is empty.
4882731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
4892731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
first_urb_detached(urb_link * hd)4902731b9a8SJean-Christophe PLAGNIOL-VILLARD struct urb *first_urb_detached (urb_link * hd)
4912731b9a8SJean-Christophe PLAGNIOL-VILLARD {
4922731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct urb *urb;
4932731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if ((urb = first_urb (hd))) {
4942731b9a8SJean-Christophe PLAGNIOL-VILLARD 		urb_detach (urb);
4952731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
4962731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return urb;
4972731b9a8SJean-Christophe PLAGNIOL-VILLARD }
4982731b9a8SJean-Christophe PLAGNIOL-VILLARD 
4992731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5002731b9a8SJean-Christophe PLAGNIOL-VILLARD /*
5012731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Append an urb_link (or a whole list of
5022731b9a8SJean-Christophe PLAGNIOL-VILLARD  * urb_links) to the tail of another list
5032731b9a8SJean-Christophe PLAGNIOL-VILLARD  * of urb_links.
5042731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
urb_append(urb_link * hd,struct urb * urb)5052731b9a8SJean-Christophe PLAGNIOL-VILLARD void urb_append (urb_link * hd, struct urb *urb)
5062731b9a8SJean-Christophe PLAGNIOL-VILLARD {
5072731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (hd && urb) {
5082731b9a8SJean-Christophe PLAGNIOL-VILLARD 		urb_link *new = &urb->link;
5092731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5102731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* This allows the new urb to be a list of urbs, */
5112731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* with new pointing at the first, but the link */
5122731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* must be initialized. */
5132731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* Order is important here... */
5142731b9a8SJean-Christophe PLAGNIOL-VILLARD 		urb_link *pul = hd->prev;
5152731b9a8SJean-Christophe PLAGNIOL-VILLARD 		new->prev->next = hd;
5162731b9a8SJean-Christophe PLAGNIOL-VILLARD 		hd->prev = new->prev;
5172731b9a8SJean-Christophe PLAGNIOL-VILLARD 		new->prev = pul;
5182731b9a8SJean-Christophe PLAGNIOL-VILLARD 		pul->next = new;
5192731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
5202731b9a8SJean-Christophe PLAGNIOL-VILLARD }
5212731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5222731b9a8SJean-Christophe PLAGNIOL-VILLARD /* URB create/destroy functions ***************************************************** */
5232731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5242731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
5252731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
5262731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: device instance
5272731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @endpoint: endpoint
5282731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
5292731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Allocate an urb structure. The usb device urb structure is used to
5302731b9a8SJean-Christophe PLAGNIOL-VILLARD  * contain all data associated with a transfer, including a setup packet for
5312731b9a8SJean-Christophe PLAGNIOL-VILLARD  * control transfers.
5322731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
5332731b9a8SJean-Christophe PLAGNIOL-VILLARD  * NOTE: endpoint_address MUST contain a direction flag.
5342731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_alloc_urb(struct usb_device_instance * device,struct usb_endpoint_instance * endpoint)5352731b9a8SJean-Christophe PLAGNIOL-VILLARD struct urb *usbd_alloc_urb (struct usb_device_instance *device,
5362731b9a8SJean-Christophe PLAGNIOL-VILLARD 			    struct usb_endpoint_instance *endpoint)
5372731b9a8SJean-Christophe PLAGNIOL-VILLARD {
5382731b9a8SJean-Christophe PLAGNIOL-VILLARD 	struct urb *urb;
5392731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5402731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
5412731b9a8SJean-Christophe PLAGNIOL-VILLARD 		usberr (" F A T A L:  malloc(%zu) FAILED!!!!",
5422731b9a8SJean-Christophe PLAGNIOL-VILLARD 			sizeof (struct urb));
5432731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return NULL;
5442731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
5452731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5462731b9a8SJean-Christophe PLAGNIOL-VILLARD 	/* Fill in known fields */
5472731b9a8SJean-Christophe PLAGNIOL-VILLARD 	memset (urb, 0, sizeof (struct urb));
5482731b9a8SJean-Christophe PLAGNIOL-VILLARD 	urb->endpoint = endpoint;
5492731b9a8SJean-Christophe PLAGNIOL-VILLARD 	urb->device = device;
5502731b9a8SJean-Christophe PLAGNIOL-VILLARD 	urb->buffer = (u8 *) urb->buffer_data;
5512731b9a8SJean-Christophe PLAGNIOL-VILLARD 	urb->buffer_length = sizeof (urb->buffer_data);
5522731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5532731b9a8SJean-Christophe PLAGNIOL-VILLARD 	urb_link_init (&urb->link);
5542731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5552731b9a8SJean-Christophe PLAGNIOL-VILLARD 	return urb;
5562731b9a8SJean-Christophe PLAGNIOL-VILLARD }
5572731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5582731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
5592731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_dealloc_urb - deallocate an URB and associated buffer
5602731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @urb: pointer to an urb structure
5612731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
5622731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Deallocate an urb structure and associated data.
5632731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_dealloc_urb(struct urb * urb)5642731b9a8SJean-Christophe PLAGNIOL-VILLARD void usbd_dealloc_urb (struct urb *urb)
5652731b9a8SJean-Christophe PLAGNIOL-VILLARD {
5662731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (urb) {
5672731b9a8SJean-Christophe PLAGNIOL-VILLARD 		free (urb);
5682731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
5692731b9a8SJean-Christophe PLAGNIOL-VILLARD }
5702731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5712731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Event signaling functions ***************************************************** */
5722731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5732731b9a8SJean-Christophe PLAGNIOL-VILLARD /**
5742731b9a8SJean-Christophe PLAGNIOL-VILLARD  * usbd_device_event - called to respond to various usb events
5752731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @device: pointer to struct device
5762731b9a8SJean-Christophe PLAGNIOL-VILLARD  * @event: event to respond to
5772731b9a8SJean-Christophe PLAGNIOL-VILLARD  *
5782731b9a8SJean-Christophe PLAGNIOL-VILLARD  * Used by a Bus driver to indicate an event.
5792731b9a8SJean-Christophe PLAGNIOL-VILLARD  */
usbd_device_event_irq(struct usb_device_instance * device,usb_device_event_t event,int data)5802731b9a8SJean-Christophe PLAGNIOL-VILLARD void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
5812731b9a8SJean-Christophe PLAGNIOL-VILLARD {
5822731b9a8SJean-Christophe PLAGNIOL-VILLARD 	usb_device_state_t state;
5832731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5842731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if (!device || !device->bus) {
5852731b9a8SJean-Christophe PLAGNIOL-VILLARD 		usberr("(%p,%d) NULL device or device->bus", device, event);
5862731b9a8SJean-Christophe PLAGNIOL-VILLARD 		return;
5872731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
5882731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5892731b9a8SJean-Christophe PLAGNIOL-VILLARD 	state = device->device_state;
5902731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5912731b9a8SJean-Christophe PLAGNIOL-VILLARD 	usbinfo("%s", usbd_device_events[event]);
5922731b9a8SJean-Christophe PLAGNIOL-VILLARD 
5932731b9a8SJean-Christophe PLAGNIOL-VILLARD 	switch (event) {
5942731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_UNKNOWN:
5952731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
5962731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_INIT:
5972731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_INIT;
5982731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
5992731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6002731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_CREATE:
6012731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_ATTACHED;
6022731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6032731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6042731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_HUB_CONFIGURED:
6052731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_POWERED;
6062731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6072731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6082731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_RESET:
6092731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_DEFAULT;
6102731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->address = 0;
6112731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6122731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6132731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_ADDRESS_ASSIGNED:
6142731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_ADDRESSED;
6152731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6162731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6172731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_CONFIGURED:
6182731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_CONFIGURED;
6192731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6202731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6212731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_DE_CONFIGURED:
6222731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_ADDRESSED;
6232731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6242731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6252731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_BUS_INACTIVE:
6262731b9a8SJean-Christophe PLAGNIOL-VILLARD 		if (device->status != USBD_CLOSING) {
6272731b9a8SJean-Christophe PLAGNIOL-VILLARD 			device->status = USBD_SUSPENDED;
6282731b9a8SJean-Christophe PLAGNIOL-VILLARD 		}
6292731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6302731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_BUS_ACTIVITY:
6312731b9a8SJean-Christophe PLAGNIOL-VILLARD 		if (device->status != USBD_CLOSING) {
6322731b9a8SJean-Christophe PLAGNIOL-VILLARD 			device->status = USBD_OK;
6332731b9a8SJean-Christophe PLAGNIOL-VILLARD 		}
6342731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6352731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6362731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_SET_INTERFACE:
6372731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6382731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_SET_FEATURE:
6392731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6402731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_CLEAR_FEATURE:
6412731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6422731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6432731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_POWER_INTERRUPTION:
6442731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_POWERED;
6452731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6462731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_HUB_RESET:
6472731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_ATTACHED;
6482731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6492731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_DESTROY:
6502731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->device_state = STATE_UNKNOWN;
6512731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6522731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6532731b9a8SJean-Christophe PLAGNIOL-VILLARD 	case DEVICE_FUNCTION_PRIVATE:
6542731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6552731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6562731b9a8SJean-Christophe PLAGNIOL-VILLARD 	default:
6572731b9a8SJean-Christophe PLAGNIOL-VILLARD 		usbdbg("event %d - not handled",event);
6582731b9a8SJean-Christophe PLAGNIOL-VILLARD 		break;
6592731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
6605fea7756SAnatolij Gustschin 	debug("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
6612731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->name, event, state,
6625fea7756SAnatolij Gustschin 		device->device_state, device->status, device->address);
6632731b9a8SJean-Christophe PLAGNIOL-VILLARD 
6642731b9a8SJean-Christophe PLAGNIOL-VILLARD 	/* tell the bus interface driver */
6652731b9a8SJean-Christophe PLAGNIOL-VILLARD 	if( device->event ) {
6662731b9a8SJean-Christophe PLAGNIOL-VILLARD 		/* usbdbg("calling device->event"); */
6672731b9a8SJean-Christophe PLAGNIOL-VILLARD 		device->event(device, event, data);
6682731b9a8SJean-Christophe PLAGNIOL-VILLARD 	}
6692731b9a8SJean-Christophe PLAGNIOL-VILLARD }
670