source: mainline/uspace/srv/hw/bus/usb/hcd/virtual/hubops.c@ 7a7bfeb3

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

Virtual USB overhaul almost complete

The virtual HC, hub and keyboard are rewritten after changes to HCD API.
Comments will be added later.

  • Property mode set to 100644
File size: 9.3 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 usb
30 * @{
31 */
32/** @file
33 * @brief Virtual USB hub operations.
34 */
35#include <usb/classes.h>
36#include <usb/hub.h>
37#include <usbvirt/hub.h>
38#include <usbvirt/device.h>
39#include <errno.h>
40
41#include "vhcd.h"
42#include "hub.h"
43#include "hubintern.h"
44
45#define MAKE_BYTE(b0, b1, b2, b3, b4, b5, b6, b7) \
46 (( \
47 ((b0) << 0) \
48 | ((b1) << 1) \
49 | ((b2) << 2) \
50 | ((b3) << 3) \
51 | ((b4) << 4) \
52 | ((b5) << 5) \
53 | ((b6) << 6) \
54 | ((b7) << 7) \
55 ))
56
57static int on_get_descriptor(struct usbvirt_device *dev,
58 usb_device_request_setup_packet_t *request, uint8_t *data);
59static int on_class_request(struct usbvirt_device *dev,
60 usb_device_request_setup_packet_t *request, uint8_t *data);
61static int on_data_request(struct usbvirt_device *dev,
62 usb_endpoint_t endpoint,
63 void *buffer, size_t size, size_t *actual_size);
64
65
66static usbvirt_standard_device_request_ops_t standard_request_ops = {
67 .on_get_status = NULL,
68 .on_clear_feature = NULL,
69 .on_set_feature = NULL,
70 .on_set_address = NULL,
71 .on_get_descriptor = on_get_descriptor,
72 .on_set_descriptor = NULL,
73 .on_get_configuration = NULL,
74 .on_set_configuration = NULL,
75 .on_get_interface = NULL,
76 .on_set_interface = NULL,
77 .on_synch_frame = NULL
78};
79
80
81usbvirt_device_ops_t hub_ops = {
82 .standard_request_ops = &standard_request_ops,
83 .on_class_device_request = on_class_request,
84 .on_data = NULL,
85 .on_data_request = on_data_request
86};
87
88static int on_get_descriptor(struct usbvirt_device *dev,
89 usb_device_request_setup_packet_t *request, uint8_t *data)
90{
91 if (request->value_high == USB_DESCTYPE_HUB) {
92 int rc = dev->control_transfer_reply(dev, 0,
93 &hub_descriptor, hub_descriptor.length);
94
95 return rc;
96 }
97 /* Let the framework handle all the rest. */
98 return EFORWARD;
99}
100
101/** Change port status and updates status change status fields.
102 */
103static void set_port_state(hub_port_t *port, hub_port_state_t state)
104{
105 port->state = state;
106 if (state == HUB_PORT_STATE_POWERED_OFF) {
107 clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
108 clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
109 clear_port_status_change(port, HUB_STATUS_C_PORT_RESET);
110 }
111 if (state == HUB_PORT_STATE_RESUMING) {
112 async_usleep(10*1000);
113 if (port->state == state) {
114 set_port_state(port, HUB_PORT_STATE_ENABLED);
115 }
116 }
117 if (state == HUB_PORT_STATE_RESETTING) {
118 async_usleep(10*1000);
119 if (port->state == state) {
120 set_port_status_change(port, HUB_STATUS_C_PORT_RESET);
121 set_port_state(port, HUB_PORT_STATE_ENABLED);
122 }
123 }
124}
125
126#define _GET_PORT(portvar, index) \
127 do { \
128 if (virthub_dev.state != USBVIRT_STATE_CONFIGURED) { \
129 return EINVAL; \
130 } \
131 if (((index) == 0) || ((index) > HUB_PORT_COUNT)) { \
132 return EINVAL; \
133 } \
134 } while (false); \
135 hub_port_t *portvar = &hub_dev.ports[index]
136
137
138static int clear_hub_feature(uint16_t feature)
139{
140 return ENOTSUP;
141}
142
143static int clear_port_feature(uint16_t feature, uint16_t portindex)
144{
145 _GET_PORT(port, portindex);
146
147 switch (feature) {
148 case USB_HUB_FEATURE_PORT_ENABLE:
149 if ((port->state != HUB_PORT_STATE_NOT_CONFIGURED)
150 && (port->state != HUB_PORT_STATE_POWERED_OFF)) {
151 set_port_state(port, HUB_PORT_STATE_DISABLED);
152 }
153 return EOK;
154
155 case USB_HUB_FEATURE_PORT_SUSPEND:
156 if (port->state != HUB_PORT_STATE_SUSPENDED) {
157 return EOK;
158 }
159 set_port_state(port, HUB_PORT_STATE_RESUMING);
160 return EOK;
161
162 case USB_HUB_FEATURE_PORT_POWER:
163 if (port->state != HUB_PORT_STATE_NOT_CONFIGURED) {
164 set_port_state(port, HUB_PORT_STATE_POWERED_OFF);
165 }
166 return EOK;
167
168 case USB_HUB_FEATURE_C_PORT_CONNECTION:
169 clear_port_status_change(port, HUB_STATUS_C_PORT_CONNECTION);
170 return EOK;
171
172 case USB_HUB_FEATURE_C_PORT_ENABLE:
173 clear_port_status_change(port, HUB_STATUS_C_PORT_ENABLE);
174 return EOK;
175
176 case USB_HUB_FEATURE_C_PORT_SUSPEND:
177 clear_port_status_change(port, HUB_STATUS_C_PORT_SUSPEND);
178 return EOK;
179
180 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
181 clear_port_status_change(port, HUB_STATUS_C_PORT_OVER_CURRENT);
182 return EOK;
183 }
184
185 return ENOTSUP;
186}
187
188static int get_bus_state(uint16_t portindex)
189{
190 return ENOTSUP;
191}
192
193static int get_hub_descriptor(uint8_t descriptor_type,
194 uint8_t descriptor_index, uint16_t length)
195{
196 return ENOTSUP;
197}
198
199static int get_hub_status(void)
200{
201 uint32_t hub_status = 0;
202
203 return virthub_dev.control_transfer_reply(&virthub_dev, 0,
204 &hub_status, 4);
205}
206
207static int get_port_status(uint16_t portindex)
208{
209 _GET_PORT(port, portindex);
210
211 uint32_t status;
212 status = MAKE_BYTE(
213 /* Current connect status. */
214 port->device == NULL ? 0 : 1,
215 /* Port enabled/disabled. */
216 port->state == HUB_PORT_STATE_ENABLED ? 1 : 0,
217 /* Suspend. */
218 (port->state == HUB_PORT_STATE_SUSPENDED)
219 || (port->state == HUB_PORT_STATE_RESUMING) ? 1 : 0,
220 /* Over-current. */
221 0,
222 /* Reset. */
223 port->state == HUB_PORT_STATE_RESETTING ? 1 : 0,
224 /* Reserved. */
225 0, 0, 0)
226
227 | (MAKE_BYTE(
228 /* Port power. */
229 port->state == HUB_PORT_STATE_POWERED_OFF ? 0 : 1,
230 /* Full-speed device. */
231 0,
232 /* Reserved. */
233 0, 0, 0, 0, 0, 0
234 )) << 8;
235
236 status |= (port->status_change << 16);
237
238 return virthub_dev.control_transfer_reply(&virthub_dev, 0, &status, 4);
239}
240
241
242static int set_hub_feature(uint16_t feature)
243{
244 return ENOTSUP;
245}
246
247static int set_port_feature(uint16_t feature, uint16_t portindex)
248{
249 _GET_PORT(port, portindex);
250
251 switch (feature) {
252 case USB_HUB_FEATURE_PORT_RESET:
253 if (port->state != HUB_PORT_STATE_POWERED_OFF) {
254 set_port_state(port, HUB_PORT_STATE_RESETTING);
255 }
256 return EOK;
257
258 case USB_HUB_FEATURE_PORT_SUSPEND:
259 if (port->state == HUB_PORT_STATE_ENABLED) {
260 set_port_state(port, HUB_PORT_STATE_SUSPENDED);
261 }
262 return EOK;
263
264 case USB_HUB_FEATURE_PORT_POWER:
265 if (port->state == HUB_PORT_STATE_POWERED_OFF) {
266 set_port_state(port, HUB_PORT_STATE_DISCONNECTED);
267 }
268 return EOK;
269 }
270 return ENOTSUP;
271}
272
273#undef _GET_PORT
274
275
276
277
278static int on_class_request(struct usbvirt_device *dev,
279 usb_device_request_setup_packet_t *request, uint8_t *data)
280{
281 printf("%s: hub class request (%d)\n", NAME, (int) request->request);
282
283 uint8_t recipient = request->request_type & 31;
284 uint8_t direction = request->request_type >> 7;
285
286#define _VERIFY(cond) \
287 do { \
288 if (!(cond)) { \
289 printf("%s: WARN: invalid class request (%s not met).\n", \
290 NAME, #cond); \
291 return EINVAL; \
292 } \
293 } while (0)
294
295 switch (request->request) {
296 case USB_HUB_REQUEST_CLEAR_FEATURE:
297 _VERIFY(direction == 0);
298 _VERIFY(request->length == 0);
299 if (recipient == 0) {
300 _VERIFY(request->index == 0);
301 return clear_hub_feature(request->value);
302 } else {
303 _VERIFY(recipient == 3);
304 return clear_port_feature(request->value,
305 request->index);
306 }
307
308 case USB_HUB_REQUEST_GET_STATE:
309 return get_bus_state(request->index);
310
311 case USB_HUB_REQUEST_GET_DESCRIPTOR:
312 return get_hub_descriptor(request->value_low,
313 request->value_high, request->length);
314
315 case USB_HUB_REQUEST_GET_STATUS:
316 if (recipient == 0) {
317 return get_hub_status();
318 } else {
319 return get_port_status(request->index);
320 }
321
322 case USB_HUB_REQUEST_SET_FEATURE:
323 if (recipient == 0) {
324 return set_hub_feature(request->value);
325 } else {
326 return set_port_feature(request->value, request->index);
327 }
328
329 default:
330 break;
331 }
332
333#undef _VERIFY
334
335
336 return EOK;
337}
338
339void clear_port_status_change(hub_port_t *port, uint16_t change)
340{
341 port->status_change &= (~change);
342}
343
344void set_port_status_change(hub_port_t *port, uint16_t change)
345{
346 port->status_change |= change;
347}
348
349static int on_data_request(struct usbvirt_device *dev,
350 usb_endpoint_t endpoint,
351 void *buffer, size_t size, size_t *actual_size)
352{
353 uint8_t change_map = 0;
354
355 size_t i;
356 for (i = 0; i < HUB_PORT_COUNT; i++) {
357 hub_port_t *port = &hub_dev.ports[i];
358
359 if (port->status_change != 0) {
360 change_map |= (1 << (i + 1));
361 }
362 }
363
364 uint8_t *b = (uint8_t *) buffer;
365 if (size > 0) {
366 *b = change_map;
367 *actual_size = 1;
368 }
369
370 return EOK;
371}
372
373
374/**
375 * @}
376 */
Note: See TracBrowser for help on using the repository browser.