stdreq.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include "private.h"
00036 #include <usb/dev/request.h>
00037 #include <assert.h>
00038 #include <errno.h>
00039 
00051 void usbvirt_control_reply_helper(const usb_device_request_setup_packet_t *setup_packet,
00052     uint8_t *data, size_t *act_size,
00053     void *actual_data, size_t actual_data_size)
00054 {
00055         size_t expected_size = setup_packet->length;
00056         if (expected_size < actual_data_size) {
00057                 actual_data_size = expected_size;
00058         }
00059 
00060         memcpy(data, actual_data, actual_data_size);
00061 
00062         if (act_size != NULL) {
00063                 *act_size = actual_data_size;
00064         }
00065 }
00066 
00068 static int req_get_descriptor(usbvirt_device_t *device,
00069     const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
00070 {
00071         uint8_t type = setup_packet->value_high;
00072         uint8_t index = setup_packet->value_low;
00073 
00074         /*
00075          * Standard device descriptor.
00076          */
00077         if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
00078                 if (device->descriptors && device->descriptors->device) {
00079                         usbvirt_control_reply_helper(setup_packet, data, act_size,
00080                             device->descriptors->device,
00081                             device->descriptors->device->length);
00082                         return EOK;
00083                 } else {
00084                         return EFORWARD;
00085                 }
00086         }
00087 
00088         /*
00089          * Configuration descriptor together with interface, endpoint and
00090          * class-specific descriptors.
00091          */
00092         if (type == USB_DESCTYPE_CONFIGURATION) {
00093                 if (!device->descriptors) {
00094                         return EFORWARD;
00095                 }
00096                 if (index >= device->descriptors->configuration_count) {
00097                         return EFORWARD;
00098                 }
00099                 /* Copy the data. */
00100                 usbvirt_device_configuration_t *config = &device->descriptors
00101                     ->configuration[index];
00102                 uint8_t *all_data = malloc(config->descriptor->total_length);
00103                 if (all_data == NULL) {
00104                         return ENOMEM;
00105                 }
00106 
00107                 uint8_t *ptr = all_data;
00108                 memcpy(ptr, config->descriptor, config->descriptor->length);
00109                 ptr += config->descriptor->length;
00110                 size_t i;
00111                 for (i = 0; i < config->extra_count; i++) {
00112                         usbvirt_device_configuration_extras_t *extra
00113                             = &config->extra[i];
00114                         memcpy(ptr, extra->data, extra->length);
00115                         ptr += extra->length;
00116                 }
00117 
00118                 usbvirt_control_reply_helper(setup_packet, data, act_size,
00119                     all_data, config->descriptor->total_length);
00120 
00121                 free(all_data);
00122 
00123                 return EOK;
00124         }
00125 
00126         return EFORWARD;
00127 }
00128 
00129 static int req_set_address(usbvirt_device_t *device,
00130     const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
00131 {
00132         uint16_t new_address = setup_packet->value;
00133         uint16_t zero1 = setup_packet->index;
00134         uint16_t zero2 = setup_packet->length;
00135 
00136         if ((zero1 != 0) || (zero2 != 0)) {
00137                 return EINVAL;
00138         }
00139 
00140         if (new_address > 127) {
00141                 return EINVAL;
00142         }
00143 
00144         device->address = new_address;
00145 
00146         return EOK;
00147 }
00148 
00149 static int req_set_configuration(usbvirt_device_t *device,
00150     const usb_device_request_setup_packet_t *setup_packet, uint8_t *data, size_t *act_size)
00151 {
00152         uint16_t configuration_value = setup_packet->value;
00153         uint16_t zero1 = setup_packet->index;
00154         uint16_t zero2 = setup_packet->length;
00155 
00156         if ((zero1 != 0) || (zero2 != 0)) {
00157                 return EINVAL;
00158         }
00159 
00160         /*
00161          * Configuration value is 1 byte information.
00162          */
00163         if (configuration_value > 255) {
00164                 return EINVAL;
00165         }
00166 
00167         /*
00168          * Do nothing when in default state. According to specification,
00169          * this is not specified.
00170          */
00171         if (device->state == USBVIRT_STATE_DEFAULT) {
00172                 return EOK;
00173         }
00174 
00175         usbvirt_device_state_t new_state;
00176         if (configuration_value == 0) {
00177                 new_state = USBVIRT_STATE_ADDRESS;
00178         } else {
00179                 // FIXME: check that this configuration exists
00180                 new_state = USBVIRT_STATE_CONFIGURED;
00181         }
00182 
00183         if (device->ops && device->ops->state_changed) {
00184                 device->ops->state_changed(device, device->state, new_state);
00185         }
00186         device->state = new_state;
00187 
00188         return EOK;
00189 }
00190 
00192 usbvirt_control_request_handler_t library_handlers[] = {
00193         {
00194                 .req_direction = USB_DIRECTION_OUT,
00195                 .req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
00196                 .req_type = USB_REQUEST_TYPE_STANDARD,
00197                 .request = USB_DEVREQ_SET_ADDRESS,
00198                 .name = "SetAddress",
00199                 .callback = req_set_address
00200         },
00201         {
00202                 .req_direction = USB_DIRECTION_IN,
00203                 .req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
00204                 .req_type = USB_REQUEST_TYPE_STANDARD,
00205                 .request = USB_DEVREQ_GET_DESCRIPTOR,
00206                 .name = "GetDescriptor",
00207                 .callback = req_get_descriptor
00208         },
00209         {
00210                 .req_direction = USB_DIRECTION_OUT,
00211                 .req_recipient = USB_REQUEST_RECIPIENT_DEVICE,
00212                 .req_type = USB_REQUEST_TYPE_STANDARD,
00213                 .request = USB_DEVREQ_SET_CONFIGURATION,
00214                 .name = "SetConfiguration",
00215                 .callback = req_set_configuration
00216         },
00217 
00218         { .callback = NULL }
00219 };
00220 

Generated on Thu Jun 2 07:45:43 2011 for HelenOS/USB by  doxygen 1.4.7