source: mainline/uspace/lib/usbvirt/src/stdreq.c@ 84439d7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 84439d7 was 56b962d, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Standard request callbacks use array in libusbvirt

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libusbvirt usb
30 * @{
31 */
32/** @file
33 * @brief Preprocessing of standard device requests.
34 */
35#include <errno.h>
36#include <stdlib.h>
37#include <mem.h>
38#include <usb/devreq.h>
39
40#include "private.h"
41
42
43typedef int (*usbvirt_stdreq_handler_t)(usbvirt_device_t *,
44usb_device_request_setup_packet_t *, uint8_t *);
45
46/*
47 * All sub handlers must return EFORWARD to inform the caller that
48 * they were not able to process the request (yes, it is abuse of
49 * this error code but such error code shall not collide with anything
50 * else in this context).
51 */
52
53/** GET_DESCRIPTOR handler. */
54static int handle_get_descriptor(usbvirt_device_t *device,
55 usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
56{
57 uint8_t type = setup_packet->value_high;
58 uint8_t index = setup_packet->value_low;
59
60 /*
61 * Standard device descriptor.
62 */
63 if ((type == USB_DESCTYPE_DEVICE) && (index == 0)) {
64 if (device->descriptors && device->descriptors->device) {
65 return device->control_transfer_reply(device, 0,
66 device->descriptors->device,
67 device->descriptors->device->length);
68 } else {
69 return EFORWARD;
70 }
71 }
72
73 /*
74 * Configuration descriptor together with interface, endpoint and
75 * class-specific descriptors.
76 */
77 if (type == USB_DESCTYPE_CONFIGURATION) {
78 if (!device->descriptors) {
79 return EFORWARD;
80 }
81 if (index >= device->descriptors->configuration_count) {
82 return EFORWARD;
83 }
84 /* Copy the data. */
85 usbvirt_device_configuration_t *config = &device->descriptors
86 ->configuration[index];
87 uint8_t *all_data = malloc(config->descriptor->total_length);
88 if (all_data == NULL) {
89 return ENOMEM;
90 }
91
92 uint8_t *ptr = all_data;
93 memcpy(ptr, config->descriptor, config->descriptor->length);
94 ptr += config->descriptor->length;
95 size_t i;
96 for (i = 0; i < config->extra_count; i++) {
97 usbvirt_device_configuration_extras_t *extra
98 = &config->extra[i];
99 memcpy(ptr, extra->data, extra->length);
100 ptr += extra->length;
101 }
102
103 int rc = device->control_transfer_reply(device, 0,
104 all_data, config->descriptor->total_length);
105
106 free(all_data);
107
108 return rc;
109 }
110
111 return EFORWARD;
112}
113
114/** SET_ADDRESS handler. */
115static int handle_set_address(usbvirt_device_t *device,
116 usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
117{
118 uint16_t new_address = setup_packet->value;
119 uint16_t zero1 = setup_packet->index;
120 uint16_t zero2 = setup_packet->length;
121
122 if ((zero1 != 0) || (zero2 != 0)) {
123 return EINVAL;
124 }
125
126 if (new_address > 127) {
127 return EINVAL;
128 }
129
130 device->new_address = new_address;
131
132 return EOK;
133}
134
135/** SET_CONFIGURATION handler. */
136static int handle_set_configuration(usbvirt_device_t *device,
137 usb_device_request_setup_packet_t *setup_packet, uint8_t *extra_data)
138{
139 uint16_t configuration_value = setup_packet->value;
140 uint16_t zero1 = setup_packet->index;
141 uint16_t zero2 = setup_packet->length;
142
143 if ((zero1 != 0) || (zero2 != 0)) {
144 return EINVAL;
145 }
146
147 /*
148 * Configuration value is 1 byte information.
149 */
150 if (configuration_value > 255) {
151 return EINVAL;
152 }
153
154 /*
155 * Do nothing when in default state. According to specification,
156 * this is not specified.
157 */
158 if (device->state == USBVIRT_STATE_DEFAULT) {
159 return EOK;
160 }
161
162 if (configuration_value == 0) {
163 device->state = USBVIRT_STATE_ADDRESS;
164 } else {
165 /*
166 * TODO: browse provided configurations and verify that
167 * user selected existing configuration.
168 */
169 device->state = USBVIRT_STATE_CONFIGURED;
170 if (device->descriptors) {
171 device->descriptors->current_configuration
172 = configuration_value;
173 }
174 }
175
176 return EOK;
177}
178
179static usbvirt_stdreq_handler_t local_handlers[USB_DEVREQ_LAST_STD] = {
180 [USB_DEVREQ_GET_DESCRIPTOR] = handle_get_descriptor,
181 [USB_DEVREQ_SET_ADDRESS] = handle_set_address,
182 [USB_DEVREQ_SET_CONFIGURATION] = handle_set_configuration
183};
184
185/** Handle standard device request. */
186int handle_std_request(usbvirt_device_t *device,
187 usb_device_request_setup_packet_t *request_packet, uint8_t *data)
188{
189 int request = request_packet->request;
190
191 device->lib_debug(device, 3, USBVIRT_DEBUGTAG_CONTROL_PIPE_ZERO,
192 "handling standard request %d", request);
193
194 if (request >= USB_DEVREQ_LAST_STD) {
195 return ENOTSUP;
196 }
197
198 int rc = EFORWARD;
199 if ((device->ops)
200 && (device->ops->on_standard_request[request])) {
201 rc = device->ops->on_standard_request[request](device,
202 request_packet, data);
203 }
204
205 if (rc == EFORWARD) {
206 if (local_handlers[request]) {
207 rc = local_handlers[request](device,
208 request_packet, data);
209 } else {
210 rc = ENOTSUP;
211 }
212 }
213
214 assert(rc != EFORWARD);
215 return rc;
216}
217
218/**
219 * @}
220 */
Note: See TracBrowser for help on using the repository browser.