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