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 * (C) Copyright 2006 62731b9a8SJean-Christophe PLAGNIOL-VILLARD * Bryan O'Donoghue, deckard@CodeHermit.ie 72731b9a8SJean-Christophe PLAGNIOL-VILLARD * 82731b9a8SJean-Christophe PLAGNIOL-VILLARD * Based on 92731b9a8SJean-Christophe PLAGNIOL-VILLARD * linux/drivers/usbd/ep0.c 102731b9a8SJean-Christophe PLAGNIOL-VILLARD * 112731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copyright (c) 2000, 2001, 2002 Lineo 122731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copyright (c) 2001 Hewlett Packard 132731b9a8SJean-Christophe PLAGNIOL-VILLARD * 142731b9a8SJean-Christophe PLAGNIOL-VILLARD * By: 152731b9a8SJean-Christophe PLAGNIOL-VILLARD * Stuart Lynne <sl@lineo.com>, 162731b9a8SJean-Christophe PLAGNIOL-VILLARD * Tom Rushworth <tbr@lineo.com>, 172731b9a8SJean-Christophe PLAGNIOL-VILLARD * Bruce Balden <balden@lineo.com> 182731b9a8SJean-Christophe PLAGNIOL-VILLARD * 192731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or modify 202731b9a8SJean-Christophe PLAGNIOL-VILLARD * it under the terms of the GNU General Public License as published by 212731b9a8SJean-Christophe PLAGNIOL-VILLARD * the Free Software Foundation; either version 2 of the License, or 222731b9a8SJean-Christophe PLAGNIOL-VILLARD * (at your option) any later version. 232731b9a8SJean-Christophe PLAGNIOL-VILLARD * 242731b9a8SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 252731b9a8SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 262731b9a8SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 272731b9a8SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 282731b9a8SJean-Christophe PLAGNIOL-VILLARD * 292731b9a8SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 302731b9a8SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 312731b9a8SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 322731b9a8SJean-Christophe PLAGNIOL-VILLARD * 332731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 342731b9a8SJean-Christophe PLAGNIOL-VILLARD 352731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 362731b9a8SJean-Christophe PLAGNIOL-VILLARD * This is the builtin ep0 control function. It implements all required functionality 372731b9a8SJean-Christophe PLAGNIOL-VILLARD * for responding to control requests (SETUP packets). 382731b9a8SJean-Christophe PLAGNIOL-VILLARD * 392731b9a8SJean-Christophe PLAGNIOL-VILLARD * XXX 402731b9a8SJean-Christophe PLAGNIOL-VILLARD * 412731b9a8SJean-Christophe PLAGNIOL-VILLARD * Currently we do not pass any SETUP packets (or other) to the configured 422731b9a8SJean-Christophe PLAGNIOL-VILLARD * function driver. This may need to change. 432731b9a8SJean-Christophe PLAGNIOL-VILLARD * 442731b9a8SJean-Christophe PLAGNIOL-VILLARD * XXX 452731b9a8SJean-Christophe PLAGNIOL-VILLARD * 462731b9a8SJean-Christophe PLAGNIOL-VILLARD * As alluded to above, a simple callback cdc_recv_setup has been implemented 472731b9a8SJean-Christophe PLAGNIOL-VILLARD * in the usb_device data structure to facilicate passing 482731b9a8SJean-Christophe PLAGNIOL-VILLARD * Common Device Class packets to a function driver. 492731b9a8SJean-Christophe PLAGNIOL-VILLARD * 502731b9a8SJean-Christophe PLAGNIOL-VILLARD * XXX 512731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 522731b9a8SJean-Christophe PLAGNIOL-VILLARD 532731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 542731b9a8SJean-Christophe PLAGNIOL-VILLARD #include <usbdevice.h> 552731b9a8SJean-Christophe PLAGNIOL-VILLARD 562731b9a8SJean-Christophe PLAGNIOL-VILLARD #if 0 572731b9a8SJean-Christophe PLAGNIOL-VILLARD #define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args) 582731b9a8SJean-Christophe PLAGNIOL-VILLARD #else 592731b9a8SJean-Christophe PLAGNIOL-VILLARD #define dbg_ep0(lvl,fmt,args...) 602731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif 612731b9a8SJean-Christophe PLAGNIOL-VILLARD 622731b9a8SJean-Christophe PLAGNIOL-VILLARD /* EP0 Configuration Set ********************************************************************* */ 632731b9a8SJean-Christophe PLAGNIOL-VILLARD 642731b9a8SJean-Christophe PLAGNIOL-VILLARD 652731b9a8SJean-Christophe PLAGNIOL-VILLARD /** 662731b9a8SJean-Christophe PLAGNIOL-VILLARD * ep0_get_status - fill in URB data with appropriate status 672731b9a8SJean-Christophe PLAGNIOL-VILLARD * @device: 682731b9a8SJean-Christophe PLAGNIOL-VILLARD * @urb: 692731b9a8SJean-Christophe PLAGNIOL-VILLARD * @index: 702731b9a8SJean-Christophe PLAGNIOL-VILLARD * @requesttype: 712731b9a8SJean-Christophe PLAGNIOL-VILLARD * 722731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 732731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ep0_get_status (struct usb_device_instance *device, 742731b9a8SJean-Christophe PLAGNIOL-VILLARD struct urb *urb, int index, int requesttype) 752731b9a8SJean-Christophe PLAGNIOL-VILLARD { 762731b9a8SJean-Christophe PLAGNIOL-VILLARD char *cp; 772731b9a8SJean-Christophe PLAGNIOL-VILLARD 782731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->actual_length = 2; 792731b9a8SJean-Christophe PLAGNIOL-VILLARD cp = (char*)urb->buffer; 802731b9a8SJean-Christophe PLAGNIOL-VILLARD cp[0] = cp[1] = 0; 812731b9a8SJean-Christophe PLAGNIOL-VILLARD 822731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (requesttype) { 832731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_DEVICE: 842731b9a8SJean-Christophe PLAGNIOL-VILLARD cp[0] = USB_STATUS_SELFPOWERED; 852731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 862731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_INTERFACE: 872731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 882731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_ENDPOINT: 892731b9a8SJean-Christophe PLAGNIOL-VILLARD cp[0] = usbd_endpoint_halted (device, index); 902731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 912731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_OTHER: 922731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->actual_length = 0; 932731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 942731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 952731b9a8SJean-Christophe PLAGNIOL-VILLARD } 962731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (2, "%02x %02x", cp[0], cp[1]); 972731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 982731b9a8SJean-Christophe PLAGNIOL-VILLARD } 992731b9a8SJean-Christophe PLAGNIOL-VILLARD 1002731b9a8SJean-Christophe PLAGNIOL-VILLARD /** 1012731b9a8SJean-Christophe PLAGNIOL-VILLARD * ep0_get_one 1022731b9a8SJean-Christophe PLAGNIOL-VILLARD * @device: 1032731b9a8SJean-Christophe PLAGNIOL-VILLARD * @urb: 1042731b9a8SJean-Christophe PLAGNIOL-VILLARD * @result: 1052731b9a8SJean-Christophe PLAGNIOL-VILLARD * 1062731b9a8SJean-Christophe PLAGNIOL-VILLARD * Set a single byte value in the urb send buffer. Return non-zero to signal 1072731b9a8SJean-Christophe PLAGNIOL-VILLARD * a request error. 1082731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 1092731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ep0_get_one (struct usb_device_instance *device, struct urb *urb, 1102731b9a8SJean-Christophe PLAGNIOL-VILLARD __u8 result) 1112731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1122731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->actual_length = 1; /* XXX 2? */ 1132731b9a8SJean-Christophe PLAGNIOL-VILLARD ((char *) urb->buffer)[0] = result; 1142731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 1152731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1162731b9a8SJean-Christophe PLAGNIOL-VILLARD 1172731b9a8SJean-Christophe PLAGNIOL-VILLARD /** 1182731b9a8SJean-Christophe PLAGNIOL-VILLARD * copy_config 1192731b9a8SJean-Christophe PLAGNIOL-VILLARD * @urb: pointer to urb 1202731b9a8SJean-Christophe PLAGNIOL-VILLARD * @data: pointer to configuration data 1212731b9a8SJean-Christophe PLAGNIOL-VILLARD * @length: length of data 1222731b9a8SJean-Christophe PLAGNIOL-VILLARD * 1232731b9a8SJean-Christophe PLAGNIOL-VILLARD * Copy configuration data to urb transfer buffer if there is room for it. 1242731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 1252731b9a8SJean-Christophe PLAGNIOL-VILLARD void copy_config (struct urb *urb, void *data, int max_length, 1262731b9a8SJean-Christophe PLAGNIOL-VILLARD int max_buf) 1272731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1282731b9a8SJean-Christophe PLAGNIOL-VILLARD int available; 1292731b9a8SJean-Christophe PLAGNIOL-VILLARD int length; 1302731b9a8SJean-Christophe PLAGNIOL-VILLARD 1312731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */ 1322731b9a8SJean-Christophe PLAGNIOL-VILLARD /* urb->actual_length, urb->buffer_length, max_buf, max_length, data); */ 1332731b9a8SJean-Christophe PLAGNIOL-VILLARD 1342731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!data) { 1352731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "data is NULL"); 1362731b9a8SJean-Christophe PLAGNIOL-VILLARD return; 1372731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1382731b9a8SJean-Christophe PLAGNIOL-VILLARD length = max_length; 1392731b9a8SJean-Christophe PLAGNIOL-VILLARD 1402731b9a8SJean-Christophe PLAGNIOL-VILLARD if (length > max_length) { 1412731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "length: %d >= max_length: %d", length, 1422731b9a8SJean-Christophe PLAGNIOL-VILLARD max_length); 1432731b9a8SJean-Christophe PLAGNIOL-VILLARD return; 1442731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1452731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(1, " actual: %d buf: %d max_buf: %d max_length: %d length: %d", */ 1462731b9a8SJean-Christophe PLAGNIOL-VILLARD /* urb->actual_length, urb->buffer_length, max_buf, max_length, length); */ 1472731b9a8SJean-Christophe PLAGNIOL-VILLARD 1482731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((available = 1492731b9a8SJean-Christophe PLAGNIOL-VILLARD /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) { 1502731b9a8SJean-Christophe PLAGNIOL-VILLARD return; 1512731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1522731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ 1532731b9a8SJean-Christophe PLAGNIOL-VILLARD /* urb->actual_length, urb->buffer_length, max_buf, length, available); */ 1542731b9a8SJean-Christophe PLAGNIOL-VILLARD 1552731b9a8SJean-Christophe PLAGNIOL-VILLARD if (length > available) { 1562731b9a8SJean-Christophe PLAGNIOL-VILLARD length = available; 1572731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1582731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ 1592731b9a8SJean-Christophe PLAGNIOL-VILLARD /* urb->actual_length, urb->buffer_length, max_buf, length, available); */ 1602731b9a8SJean-Christophe PLAGNIOL-VILLARD 1612731b9a8SJean-Christophe PLAGNIOL-VILLARD memcpy (urb->buffer + urb->actual_length, data, length); 1622731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->actual_length += length; 1632731b9a8SJean-Christophe PLAGNIOL-VILLARD 1642731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (3, 1652731b9a8SJean-Christophe PLAGNIOL-VILLARD "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d", 1662731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->actual_length, urb->buffer_length, max_buf, max_length, 1672731b9a8SJean-Christophe PLAGNIOL-VILLARD available); 1682731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1692731b9a8SJean-Christophe PLAGNIOL-VILLARD 1702731b9a8SJean-Christophe PLAGNIOL-VILLARD /** 1712731b9a8SJean-Christophe PLAGNIOL-VILLARD * ep0_get_descriptor 1722731b9a8SJean-Christophe PLAGNIOL-VILLARD * @device: 1732731b9a8SJean-Christophe PLAGNIOL-VILLARD * @urb: 1742731b9a8SJean-Christophe PLAGNIOL-VILLARD * @max: 1752731b9a8SJean-Christophe PLAGNIOL-VILLARD * @descriptor_type: 1762731b9a8SJean-Christophe PLAGNIOL-VILLARD * @index: 1772731b9a8SJean-Christophe PLAGNIOL-VILLARD * 1782731b9a8SJean-Christophe PLAGNIOL-VILLARD * Called by ep0_rx_process for a get descriptor device command. Determine what 1792731b9a8SJean-Christophe PLAGNIOL-VILLARD * descriptor is being requested, copy to send buffer. Return zero if ok to send, 1802731b9a8SJean-Christophe PLAGNIOL-VILLARD * return non-zero to signal a request error. 1812731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 1822731b9a8SJean-Christophe PLAGNIOL-VILLARD static int ep0_get_descriptor (struct usb_device_instance *device, 1832731b9a8SJean-Christophe PLAGNIOL-VILLARD struct urb *urb, int max, int descriptor_type, 1842731b9a8SJean-Christophe PLAGNIOL-VILLARD int index) 1852731b9a8SJean-Christophe PLAGNIOL-VILLARD { 1862731b9a8SJean-Christophe PLAGNIOL-VILLARD int port = 0; /* XXX compound device */ 1872731b9a8SJean-Christophe PLAGNIOL-VILLARD 1882731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */ 1892731b9a8SJean-Christophe PLAGNIOL-VILLARD 1902731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!urb || !urb->buffer || !urb->buffer_length 1912731b9a8SJean-Christophe PLAGNIOL-VILLARD || (urb->buffer_length < 255)) { 1922731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (2, "invalid urb %p", urb); 1932731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1L; 1942731b9a8SJean-Christophe PLAGNIOL-VILLARD } 1952731b9a8SJean-Christophe PLAGNIOL-VILLARD 1962731b9a8SJean-Christophe PLAGNIOL-VILLARD /* setup tx urb */ 1972731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->actual_length = 0; 1982731b9a8SJean-Christophe PLAGNIOL-VILLARD 1992731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type)); 2002731b9a8SJean-Christophe PLAGNIOL-VILLARD 2012731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (descriptor_type) { 2022731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_DEVICE: 2032731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2042731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_device_descriptor *device_descriptor; 2052731b9a8SJean-Christophe PLAGNIOL-VILLARD if (! 2062731b9a8SJean-Christophe PLAGNIOL-VILLARD (device_descriptor = 2072731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_device_descriptor (device, port))) { 2082731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2092731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2102731b9a8SJean-Christophe PLAGNIOL-VILLARD /* copy descriptor for this device */ 2112731b9a8SJean-Christophe PLAGNIOL-VILLARD copy_config (urb, device_descriptor, 2122731b9a8SJean-Christophe PLAGNIOL-VILLARD sizeof (struct usb_device_descriptor), 2132731b9a8SJean-Christophe PLAGNIOL-VILLARD max); 2142731b9a8SJean-Christophe PLAGNIOL-VILLARD 2152731b9a8SJean-Christophe PLAGNIOL-VILLARD /* correct the correct control endpoint 0 max packet size into the descriptor */ 2162731b9a8SJean-Christophe PLAGNIOL-VILLARD device_descriptor = 2172731b9a8SJean-Christophe PLAGNIOL-VILLARD (struct usb_device_descriptor *) urb->buffer; 2182731b9a8SJean-Christophe PLAGNIOL-VILLARD 2192731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2202731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length); 2212731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 2222731b9a8SJean-Christophe PLAGNIOL-VILLARD 2232731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_CONFIGURATION: 2242731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2252731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_configuration_descriptor 2262731b9a8SJean-Christophe PLAGNIOL-VILLARD *configuration_descriptor; 2272731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_device_descriptor *device_descriptor; 2282731b9a8SJean-Christophe PLAGNIOL-VILLARD if (! 2292731b9a8SJean-Christophe PLAGNIOL-VILLARD (device_descriptor = 2302731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_device_descriptor (device, port))) { 2312731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2322731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2332731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */ 2342731b9a8SJean-Christophe PLAGNIOL-VILLARD if (index >= device_descriptor->bNumConfigurations) { 2352731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (0, "index too large: %d >= %d", index, 2362731b9a8SJean-Christophe PLAGNIOL-VILLARD device_descriptor-> 2372731b9a8SJean-Christophe PLAGNIOL-VILLARD bNumConfigurations); 2382731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2392731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2402731b9a8SJean-Christophe PLAGNIOL-VILLARD 2412731b9a8SJean-Christophe PLAGNIOL-VILLARD if (! 2422731b9a8SJean-Christophe PLAGNIOL-VILLARD (configuration_descriptor = 2432731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_configuration_descriptor (device, 2442731b9a8SJean-Christophe PLAGNIOL-VILLARD port, 2452731b9a8SJean-Christophe PLAGNIOL-VILLARD index))) { 2462731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (0, 2472731b9a8SJean-Christophe PLAGNIOL-VILLARD "usbd_device_configuration_descriptor failed: %d", 2482731b9a8SJean-Christophe PLAGNIOL-VILLARD index); 2492731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2502731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2512731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength)); 2522731b9a8SJean-Christophe PLAGNIOL-VILLARD copy_config (urb, configuration_descriptor, 2532731b9a8SJean-Christophe PLAGNIOL-VILLARD 2542731b9a8SJean-Christophe PLAGNIOL-VILLARD cpu_to_le16(configuration_descriptor->wTotalLength), 2552731b9a8SJean-Christophe PLAGNIOL-VILLARD max); 2562731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2572731b9a8SJean-Christophe PLAGNIOL-VILLARD 2582731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 2592731b9a8SJean-Christophe PLAGNIOL-VILLARD 2602731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_STRING: 2612731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2622731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_string_descriptor *string_descriptor; 2632731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(string_descriptor = usbd_get_string (index))) { 2642731b9a8SJean-Christophe PLAGNIOL-VILLARD serial_printf("Invalid string index %d\n", index); 2652731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2662731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2672731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength); 2682731b9a8SJean-Christophe PLAGNIOL-VILLARD copy_config (urb, string_descriptor, string_descriptor->bLength, max); 2692731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2702731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 2712731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_INTERFACE: 2722731b9a8SJean-Christophe PLAGNIOL-VILLARD serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n"); 2732731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2742731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_ENDPOINT: 2752731b9a8SJean-Christophe PLAGNIOL-VILLARD serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n"); 2762731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2772731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_HID: 2782731b9a8SJean-Christophe PLAGNIOL-VILLARD { 2792731b9a8SJean-Christophe PLAGNIOL-VILLARD serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n"); 2802731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; /* unsupported at this time */ 2812731b9a8SJean-Christophe PLAGNIOL-VILLARD #if 0 2822731b9a8SJean-Christophe PLAGNIOL-VILLARD int bNumInterface = 2832731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (urb->device_request.wIndex); 2842731b9a8SJean-Christophe PLAGNIOL-VILLARD int bAlternateSetting = 0; 2852731b9a8SJean-Christophe PLAGNIOL-VILLARD int class = 0; 2862731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_class_descriptor *class_descriptor; 2872731b9a8SJean-Christophe PLAGNIOL-VILLARD 2882731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(class_descriptor = 2892731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_class_descriptor_index (device, 2902731b9a8SJean-Christophe PLAGNIOL-VILLARD port, 0, 2912731b9a8SJean-Christophe PLAGNIOL-VILLARD bNumInterface, 2922731b9a8SJean-Christophe PLAGNIOL-VILLARD bAlternateSetting, 2932731b9a8SJean-Christophe PLAGNIOL-VILLARD class)) 2942731b9a8SJean-Christophe PLAGNIOL-VILLARD || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) { 2952731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (3, "[%d] interface is not HID", 2962731b9a8SJean-Christophe PLAGNIOL-VILLARD bNumInterface); 2972731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 2982731b9a8SJean-Christophe PLAGNIOL-VILLARD } 2992731b9a8SJean-Christophe PLAGNIOL-VILLARD /* copy descriptor for this class */ 3002731b9a8SJean-Christophe PLAGNIOL-VILLARD copy_config (urb, class_descriptor, 3012731b9a8SJean-Christophe PLAGNIOL-VILLARD class_descriptor->descriptor.hid.bLength, 3022731b9a8SJean-Christophe PLAGNIOL-VILLARD max); 3032731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif 3042731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3052731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 3062731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_REPORT: 3072731b9a8SJean-Christophe PLAGNIOL-VILLARD { 3082731b9a8SJean-Christophe PLAGNIOL-VILLARD serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n"); 3092731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; /* unsupported at this time */ 3102731b9a8SJean-Christophe PLAGNIOL-VILLARD #if 0 3112731b9a8SJean-Christophe PLAGNIOL-VILLARD int bNumInterface = 3122731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (urb->device_request.wIndex); 3132731b9a8SJean-Christophe PLAGNIOL-VILLARD int bAlternateSetting = 0; 3142731b9a8SJean-Christophe PLAGNIOL-VILLARD int class = 0; 3152731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_class_report_descriptor *report_descriptor; 3162731b9a8SJean-Christophe PLAGNIOL-VILLARD 3172731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!(report_descriptor = 3182731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_class_report_descriptor_index 3192731b9a8SJean-Christophe PLAGNIOL-VILLARD (device, port, 0, bNumInterface, 3202731b9a8SJean-Christophe PLAGNIOL-VILLARD bAlternateSetting, class)) 3212731b9a8SJean-Christophe PLAGNIOL-VILLARD || report_descriptor->bDescriptorType != 3222731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_DT_REPORT) { 3232731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (3, "[%d] descriptor is not REPORT", 3242731b9a8SJean-Christophe PLAGNIOL-VILLARD bNumInterface); 3252731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 3262731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3272731b9a8SJean-Christophe PLAGNIOL-VILLARD /* copy report descriptor for this class */ 3282731b9a8SJean-Christophe PLAGNIOL-VILLARD /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */ 3292731b9a8SJean-Christophe PLAGNIOL-VILLARD if (max - urb->actual_length > 0) { 3302731b9a8SJean-Christophe PLAGNIOL-VILLARD int length = 3312731b9a8SJean-Christophe PLAGNIOL-VILLARD MIN (report_descriptor->wLength, 3322731b9a8SJean-Christophe PLAGNIOL-VILLARD max - urb->actual_length); 3332731b9a8SJean-Christophe PLAGNIOL-VILLARD memcpy (urb->buffer + urb->actual_length, 3342731b9a8SJean-Christophe PLAGNIOL-VILLARD &report_descriptor->bData[0], length); 3352731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->actual_length += length; 3362731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3372731b9a8SJean-Christophe PLAGNIOL-VILLARD #endif 3382731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3392731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 3402731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: 341*f9da0f89SVipin KUMAR #if defined(CONFIG_USBD_HS) 3422731b9a8SJean-Christophe PLAGNIOL-VILLARD { 343*f9da0f89SVipin KUMAR struct usb_qualifier_descriptor *qualifier_descriptor = 344*f9da0f89SVipin KUMAR device->qualifier_descriptor; 345*f9da0f89SVipin KUMAR 346*f9da0f89SVipin KUMAR if (!qualifier_descriptor) 3472731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 348*f9da0f89SVipin KUMAR 349*f9da0f89SVipin KUMAR /* copy descriptor for this device */ 350*f9da0f89SVipin KUMAR copy_config(urb, qualifier_descriptor, 351*f9da0f89SVipin KUMAR sizeof(struct usb_qualifier_descriptor), 352*f9da0f89SVipin KUMAR max); 353*f9da0f89SVipin KUMAR 3542731b9a8SJean-Christophe PLAGNIOL-VILLARD } 355*f9da0f89SVipin KUMAR dbg_ep0(3, "copied qualifier descriptor, actual_length: 0x%x", 356*f9da0f89SVipin KUMAR urb->actual_length); 357*f9da0f89SVipin KUMAR #else 358*f9da0f89SVipin KUMAR return -1; 359*f9da0f89SVipin KUMAR #endif 360*f9da0f89SVipin KUMAR break; 361*f9da0f89SVipin KUMAR 3622731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 3632731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 3642731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3652731b9a8SJean-Christophe PLAGNIOL-VILLARD 3662731b9a8SJean-Christophe PLAGNIOL-VILLARD 3672731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d", 3682731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->buffer, urb->buffer_length, urb->actual_length, 3692731b9a8SJean-Christophe PLAGNIOL-VILLARD device->bus->endpoint_array[0].tx_packetSize); 3702731b9a8SJean-Christophe PLAGNIOL-VILLARD /* 3712731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) { 3722731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0(0, "adding null byte"); 3732731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->buffer[urb->actual_length++] = 0; 3742731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d", 3752731b9a8SJean-Christophe PLAGNIOL-VILLARD urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize); 3762731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3772731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 3782731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 3792731b9a8SJean-Christophe PLAGNIOL-VILLARD 3802731b9a8SJean-Christophe PLAGNIOL-VILLARD } 3812731b9a8SJean-Christophe PLAGNIOL-VILLARD 3822731b9a8SJean-Christophe PLAGNIOL-VILLARD /** 3832731b9a8SJean-Christophe PLAGNIOL-VILLARD * ep0_recv_setup - called to indicate URB has been received 3842731b9a8SJean-Christophe PLAGNIOL-VILLARD * @urb: pointer to struct urb 3852731b9a8SJean-Christophe PLAGNIOL-VILLARD * 3862731b9a8SJean-Christophe PLAGNIOL-VILLARD * Check if this is a setup packet, process the device request, put results 3872731b9a8SJean-Christophe PLAGNIOL-VILLARD * back into the urb and return zero or non-zero to indicate success (DATA) 3882731b9a8SJean-Christophe PLAGNIOL-VILLARD * or failure (STALL). 3892731b9a8SJean-Christophe PLAGNIOL-VILLARD * 3902731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 3912731b9a8SJean-Christophe PLAGNIOL-VILLARD int ep0_recv_setup (struct urb *urb) 3922731b9a8SJean-Christophe PLAGNIOL-VILLARD { 3932731b9a8SJean-Christophe PLAGNIOL-VILLARD /*struct usb_device_request *request = urb->buffer; */ 3942731b9a8SJean-Christophe PLAGNIOL-VILLARD /*struct usb_device_instance *device = urb->device; */ 3952731b9a8SJean-Christophe PLAGNIOL-VILLARD 3962731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_device_request *request; 3972731b9a8SJean-Christophe PLAGNIOL-VILLARD struct usb_device_instance *device; 3982731b9a8SJean-Christophe PLAGNIOL-VILLARD int address; 3992731b9a8SJean-Christophe PLAGNIOL-VILLARD 4002731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (0, "entering ep0_recv_setup()"); 4012731b9a8SJean-Christophe PLAGNIOL-VILLARD if (!urb || !urb->device) { 4022731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (3, "invalid URB %p", urb); 4032731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 4042731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4052731b9a8SJean-Christophe PLAGNIOL-VILLARD 4062731b9a8SJean-Christophe PLAGNIOL-VILLARD request = &urb->device_request; 4072731b9a8SJean-Christophe PLAGNIOL-VILLARD device = urb->device; 4082731b9a8SJean-Christophe PLAGNIOL-VILLARD 4092731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (3, "urb: %p device: %p", urb, urb->device); 4102731b9a8SJean-Christophe PLAGNIOL-VILLARD 4112731b9a8SJean-Christophe PLAGNIOL-VILLARD 4122731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(2, "- - - - - - - - - -"); */ 4132731b9a8SJean-Christophe PLAGNIOL-VILLARD 4142731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (2, 4152731b9a8SJean-Christophe PLAGNIOL-VILLARD "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s", 4162731b9a8SJean-Christophe PLAGNIOL-VILLARD request->bmRequestType, request->bRequest, 4172731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex), 4182731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (request->wLength), 4192731b9a8SJean-Christophe PLAGNIOL-VILLARD USBD_DEVICE_REQUESTS (request->bRequest)); 4202731b9a8SJean-Christophe PLAGNIOL-VILLARD 4212731b9a8SJean-Christophe PLAGNIOL-VILLARD /* handle USB Standard Request (c.f. USB Spec table 9-2) */ 4222731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) { 4232731b9a8SJean-Christophe PLAGNIOL-VILLARD if(device->device_state <= STATE_CONFIGURED){ 4242731b9a8SJean-Christophe PLAGNIOL-VILLARD /* Attempt to handle a CDC specific request if we are 4252731b9a8SJean-Christophe PLAGNIOL-VILLARD * in the configured state. 4262731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4272731b9a8SJean-Christophe PLAGNIOL-VILLARD return device->cdc_recv_setup(request,urb); 4282731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4292731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "non standard request: %x", 4302731b9a8SJean-Christophe PLAGNIOL-VILLARD request->bmRequestType & USB_REQ_TYPE_MASK); 4312731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; /* Stall here */ 4322731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4332731b9a8SJean-Christophe PLAGNIOL-VILLARD 4342731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (device->device_state) { 4352731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_CREATED: 4362731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_ATTACHED: 4372731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_POWERED: 4382731b9a8SJean-Christophe PLAGNIOL-VILLARD /* It actually is important to allow requests in these states, 4392731b9a8SJean-Christophe PLAGNIOL-VILLARD * Windows will request descriptors before assigning an 4402731b9a8SJean-Christophe PLAGNIOL-VILLARD * address to the client. 4412731b9a8SJean-Christophe PLAGNIOL-VILLARD */ 4422731b9a8SJean-Christophe PLAGNIOL-VILLARD 4432731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0 (1, "request %s not allowed in this state: %s", */ 4442731b9a8SJean-Christophe PLAGNIOL-VILLARD /* USBD_DEVICE_REQUESTS(request->bRequest), */ 4452731b9a8SJean-Christophe PLAGNIOL-VILLARD /* usbd_device_states[device->device_state]); */ 4462731b9a8SJean-Christophe PLAGNIOL-VILLARD /*return -1; */ 4472731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 4482731b9a8SJean-Christophe PLAGNIOL-VILLARD 4492731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_INIT: 4502731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_DEFAULT: 4512731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (request->bRequest) { 4522731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_STATUS: 4532731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_INTERFACE: 4542731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ 4552731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_CLEAR_FEATURE: 4562731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_FEATURE: 4572731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_DESCRIPTOR: 4582731b9a8SJean-Christophe PLAGNIOL-VILLARD /* case USB_REQ_SET_CONFIGURATION: */ 4592731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_INTERFACE: 4602731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, 4612731b9a8SJean-Christophe PLAGNIOL-VILLARD "request %s not allowed in DEFAULT state: %s", 4622731b9a8SJean-Christophe PLAGNIOL-VILLARD USBD_DEVICE_REQUESTS (request->bRequest), 4632731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_states[device->device_state]); 4642731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 4652731b9a8SJean-Christophe PLAGNIOL-VILLARD 4662731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_CONFIGURATION: 4672731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_ADDRESS: 4682731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_DESCRIPTOR: 4692731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_CONFIGURATION: 4702731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 4712731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4722731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_ADDRESSED: 4732731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_CONFIGURED: 4742731b9a8SJean-Christophe PLAGNIOL-VILLARD break; 4752731b9a8SJean-Christophe PLAGNIOL-VILLARD case STATE_UNKNOWN: 4762731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s", 4772731b9a8SJean-Christophe PLAGNIOL-VILLARD USBD_DEVICE_REQUESTS (request->bRequest), 4782731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_states[device->device_state]); 4792731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 4802731b9a8SJean-Christophe PLAGNIOL-VILLARD } 4812731b9a8SJean-Christophe PLAGNIOL-VILLARD 4822731b9a8SJean-Christophe PLAGNIOL-VILLARD /* handle all requests that return data (direction bit set on bm RequestType) */ 4832731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) { 4842731b9a8SJean-Christophe PLAGNIOL-VILLARD 4852731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (3, "Device-to-Host"); 4862731b9a8SJean-Christophe PLAGNIOL-VILLARD 4872731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (request->bRequest) { 4882731b9a8SJean-Christophe PLAGNIOL-VILLARD 4892731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_STATUS: 4902731b9a8SJean-Christophe PLAGNIOL-VILLARD return ep0_get_status (device, urb, request->wIndex, 4912731b9a8SJean-Christophe PLAGNIOL-VILLARD request->bmRequestType & 4922731b9a8SJean-Christophe PLAGNIOL-VILLARD USB_REQ_RECIPIENT_MASK); 4932731b9a8SJean-Christophe PLAGNIOL-VILLARD 4942731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_DESCRIPTOR: 4952731b9a8SJean-Christophe PLAGNIOL-VILLARD return ep0_get_descriptor (device, urb, 4962731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (request->wLength), 4972731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (request->wValue) >> 8, 4982731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (request->wValue) & 0xff); 4992731b9a8SJean-Christophe PLAGNIOL-VILLARD 5002731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_CONFIGURATION: 5012731b9a8SJean-Christophe PLAGNIOL-VILLARD serial_printf("get config %d\n", device->configuration); 5022731b9a8SJean-Christophe PLAGNIOL-VILLARD return ep0_get_one (device, urb, 5032731b9a8SJean-Christophe PLAGNIOL-VILLARD device->configuration); 5042731b9a8SJean-Christophe PLAGNIOL-VILLARD 5052731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_INTERFACE: 5062731b9a8SJean-Christophe PLAGNIOL-VILLARD return ep0_get_one (device, urb, device->alternate); 5072731b9a8SJean-Christophe PLAGNIOL-VILLARD 5082731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ 5092731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5102731b9a8SJean-Christophe PLAGNIOL-VILLARD 5112731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_CLEAR_FEATURE: 5122731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_FEATURE: 5132731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_ADDRESS: 5142731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_DESCRIPTOR: 5152731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_CONFIGURATION: 5162731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_INTERFACE: 5172731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5182731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5192731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5202731b9a8SJean-Christophe PLAGNIOL-VILLARD /* handle the requests that do not return data */ 5212731b9a8SJean-Christophe PLAGNIOL-VILLARD else { 5222731b9a8SJean-Christophe PLAGNIOL-VILLARD 5232731b9a8SJean-Christophe PLAGNIOL-VILLARD 5242731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(3, "Host-to-Device"); */ 5252731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (request->bRequest) { 5262731b9a8SJean-Christophe PLAGNIOL-VILLARD 5272731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_CLEAR_FEATURE: 5282731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_FEATURE: 5292731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (0, "Host-to-Device"); 5302731b9a8SJean-Christophe PLAGNIOL-VILLARD switch (request-> 5312731b9a8SJean-Christophe PLAGNIOL-VILLARD bmRequestType & USB_REQ_RECIPIENT_MASK) { 5322731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_DEVICE: 5332731b9a8SJean-Christophe PLAGNIOL-VILLARD /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */ 5342731b9a8SJean-Christophe PLAGNIOL-VILLARD /* XXX fall through for now as we do not support either */ 5352731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_INTERFACE: 5362731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_OTHER: 5372731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (0, "request %s not", 5382731b9a8SJean-Christophe PLAGNIOL-VILLARD USBD_DEVICE_REQUESTS (request->bRequest)); 5392731b9a8SJean-Christophe PLAGNIOL-VILLARD default: 5402731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5412731b9a8SJean-Christophe PLAGNIOL-VILLARD 5422731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_RECIPIENT_ENDPOINT: 5432731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue)); 5442731b9a8SJean-Christophe PLAGNIOL-VILLARD if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) { 5452731b9a8SJean-Christophe PLAGNIOL-VILLARD /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */ 5462731b9a8SJean-Christophe PLAGNIOL-VILLARD /* request->bRequest == USB_REQ_SET_FEATURE); */ 5472731b9a8SJean-Christophe PLAGNIOL-VILLARD /* NEED TO IMPLEMENT THIS!!! */ 5482731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5492731b9a8SJean-Christophe PLAGNIOL-VILLARD } else { 5502731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "request %s bad wValue: %04x", 5512731b9a8SJean-Christophe PLAGNIOL-VILLARD USBD_DEVICE_REQUESTS 5522731b9a8SJean-Christophe PLAGNIOL-VILLARD (request->bRequest), 5532731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (request->wValue)); 5542731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5552731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5562731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5572731b9a8SJean-Christophe PLAGNIOL-VILLARD 5582731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_ADDRESS: 5592731b9a8SJean-Christophe PLAGNIOL-VILLARD /* check if this is a re-address, reset first if it is (this shouldn't be possible) */ 5602731b9a8SJean-Christophe PLAGNIOL-VILLARD if (device->device_state != STATE_DEFAULT) { 5612731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "set_address: %02x state: %s", 5622731b9a8SJean-Christophe PLAGNIOL-VILLARD le16_to_cpu (request->wValue), 5632731b9a8SJean-Christophe PLAGNIOL-VILLARD usbd_device_states[device->device_state]); 5642731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5652731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5662731b9a8SJean-Christophe PLAGNIOL-VILLARD address = le16_to_cpu (request->wValue); 5672731b9a8SJean-Christophe PLAGNIOL-VILLARD if ((address & 0x7f) != address) { 5682731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (1, "invalid address %04x %04x", 5692731b9a8SJean-Christophe PLAGNIOL-VILLARD address, address & 0x7f); 5702731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5712731b9a8SJean-Christophe PLAGNIOL-VILLARD } 5722731b9a8SJean-Christophe PLAGNIOL-VILLARD device->address = address; 5732731b9a8SJean-Christophe PLAGNIOL-VILLARD 5742731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(2, "address: %d %d %d", */ 5752731b9a8SJean-Christophe PLAGNIOL-VILLARD /* request->wValue, le16_to_cpu(request->wValue), device->address); */ 5762731b9a8SJean-Christophe PLAGNIOL-VILLARD 5772731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 5782731b9a8SJean-Christophe PLAGNIOL-VILLARD 5792731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */ 5802731b9a8SJean-Christophe PLAGNIOL-VILLARD dbg_ep0 (0, "set descriptor: NOT SUPPORTED"); 5812731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 5822731b9a8SJean-Christophe PLAGNIOL-VILLARD 5832731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_CONFIGURATION: 5842731b9a8SJean-Christophe PLAGNIOL-VILLARD /* c.f. 9.4.7 - the top half of wValue is reserved */ 5852731b9a8SJean-Christophe PLAGNIOL-VILLARD device->configuration = le16_to_cpu(request->wValue) & 0xff; 5862731b9a8SJean-Christophe PLAGNIOL-VILLARD 5872731b9a8SJean-Christophe PLAGNIOL-VILLARD /* reset interface and alternate settings */ 5882731b9a8SJean-Christophe PLAGNIOL-VILLARD device->interface = device->alternate = 0; 5892731b9a8SJean-Christophe PLAGNIOL-VILLARD 5902731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(2, "set configuration: %d", device->configuration); */ 5912731b9a8SJean-Christophe PLAGNIOL-VILLARD /*serial_printf("DEVICE_CONFIGURED.. event?\n"); */ 5922731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 5932731b9a8SJean-Christophe PLAGNIOL-VILLARD 5942731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SET_INTERFACE: 5952731b9a8SJean-Christophe PLAGNIOL-VILLARD device->interface = le16_to_cpu (request->wIndex); 5962731b9a8SJean-Christophe PLAGNIOL-VILLARD device->alternate = le16_to_cpu (request->wValue); 5972731b9a8SJean-Christophe PLAGNIOL-VILLARD /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */ 5982731b9a8SJean-Christophe PLAGNIOL-VILLARD serial_printf ("DEVICE_SET_INTERFACE.. event?\n"); 5992731b9a8SJean-Christophe PLAGNIOL-VILLARD return 0; 6002731b9a8SJean-Christophe PLAGNIOL-VILLARD 6012731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_STATUS: 6022731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_DESCRIPTOR: 6032731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_CONFIGURATION: 6042731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_GET_INTERFACE: 6052731b9a8SJean-Christophe PLAGNIOL-VILLARD case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ 6062731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 6072731b9a8SJean-Christophe PLAGNIOL-VILLARD } 6082731b9a8SJean-Christophe PLAGNIOL-VILLARD } 6092731b9a8SJean-Christophe PLAGNIOL-VILLARD return -1; 6102731b9a8SJean-Christophe PLAGNIOL-VILLARD } 611