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