/* * Copyright (c) 2010 Vojtech Horky * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup libusbvirt usb * @{ */ /** @file * @brief Preprocessing of standard device requests. */ #include #include #include #include #include "private.h" /* * All sub handlers must return EFORWARD to inform the caller that * they were not able to process the request (yes, it is abuse of * this error code but such error code shall not collide with anything * else in this context). */ /** GET_DESCRIPTOR handler. */ static int handle_get_descriptor(usbvirt_device_t *device, uint8_t type, uint8_t index, uint16_t language, uint16_t length) { /* * Standard device descriptor. */ if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) { if (device->descriptors && device->descriptors->device) { return device->control_transfer_reply(device, 0, device->descriptors->device, device->descriptors->device->length); } else { return EFORWARD; } } /* * Configuration descriptor together with interface, endpoint and * class-specific descriptors. */ if (type == USB_DESCTYPE_CONFIGURATION) { if (!device->descriptors) { return EFORWARD; } if (index >= device->descriptors->configuration_count) { return EFORWARD; } /* Copy the data. */ usbvirt_device_configuration_t *config = &device->descriptors ->configuration[index]; uint8_t *all_data = malloc(config->descriptor->total_length); if (all_data == NULL) { return ENOMEM; } uint8_t *ptr = all_data; memcpy(ptr, config->descriptor, config->descriptor->length); ptr += config->descriptor->length; size_t i; for (i = 0; i < config->extra_count; i++) { usbvirt_device_configuration_extras_t *extra = &config->extra[i]; memcpy(ptr, extra->data, extra->length); ptr += extra->length; } int rc = device->control_transfer_reply(device, 0, all_data, config->descriptor->total_length); free(all_data); return rc; } return EFORWARD; } /** SET_ADDRESS handler. */ static int handle_set_address(usbvirt_device_t *device, uint16_t new_address, uint16_t zero1, uint16_t zero2) { if ((zero1 != 0) || (zero2 != 0)) { return EINVAL; } if (new_address > 127) { return EINVAL; } device->new_address = new_address; return EOK; } /** SET_CONFIGURATION handler. */ static int handle_set_configuration(usbvirt_device_t *device, uint16_t configuration_value, uint16_t zero1, uint16_t zero2) { if ((zero1 != 0) || (zero2 != 0)) { return EINVAL; } /* * Configuration value is 1 byte information. */ if (configuration_value > 255) { return EINVAL; } /* * Do nothing when in default state. According to specification, * this is not specified. */ if (device->state == USBVIRT_STATE_DEFAULT) { return EOK; } if (configuration_value == 0) { device->state = USBVIRT_STATE_ADDRESS; } else { /* * TODO: browse provided configurations and verify that * user selected existing configuration. */ device->state = USBVIRT_STATE_CONFIGURED; if (device->descriptors) { device->descriptors->current_configuration = configuration_value; } } return EOK; } #define HANDLE_REQUEST(request, data, type, dev, user_callback, default_handler) \ do { \ if ((request)->request == (type)) { \ int _rc = EFORWARD; \ if (((dev)->ops) && ((dev)->ops->standard_request_ops) \ && ((dev)->ops->standard_request_ops->user_callback)) { \ _rc = (dev)->ops->standard_request_ops->\ user_callback(dev, request, data); \ } \ if (_rc == EFORWARD) { \ default_handler; \ } \ return _rc; \ } \ } while (false) /** Handle standard device request. */ int handle_std_request(usbvirt_device_t *device, usb_device_request_setup_packet_t *request, uint8_t *data) { device->lib_debug(device, 3, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO, "handling standard request %d", request->request); HANDLE_REQUEST(request, data, USB_DEVREQ_GET_DESCRIPTOR, device, on_get_descriptor, handle_get_descriptor(device, request->value_high, request->value_low, request->index, request->length)); HANDLE_REQUEST(request, data, USB_DEVREQ_SET_ADDRESS, device, on_set_address, handle_set_address(device, request->value, request->index, request->length)); HANDLE_REQUEST(request, data, USB_DEVREQ_SET_CONFIGURATION, device, on_set_configuration, handle_set_configuration(device, request->value, request->index, request->length)); return ENOTSUP; } /** * @} */