source: mainline/uspace/drv/vhc/hub/virthubops.c@ 70e5ad5

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

More doxygen comments

  • Property mode set to 100644
File size: 11.2 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 <errno.h>
36#include <usb/classes/hub.h>
37#include "virthub.h"
38#include "hub.h"
39
40/** Callback when device changes states. */
41static void on_state_change(struct usbvirt_device *dev,
42 usbvirt_device_state_t old_state, usbvirt_device_state_t new_state)
43{
44 hub_t *hub = (hub_t *)dev->device_data;
45
46 hub_acquire(hub);
47
48 switch (new_state) {
49 case USBVIRT_STATE_CONFIGURED:
50 hub_set_port_state_all(hub, HUB_PORT_STATE_POWERED_OFF);
51 break;
52 case USBVIRT_STATE_ADDRESS:
53 hub_set_port_state_all(hub, HUB_PORT_STATE_NOT_CONFIGURED);
54 break;
55 default:
56 break;
57 }
58
59 hub_release(hub);
60}
61
62/** Callback for data request. */
63static int req_on_data(struct usbvirt_device *dev,
64 usb_endpoint_t endpoint,
65 void *buffer, size_t size, size_t *actual_size)
66{
67 if (endpoint != HUB_STATUS_CHANGE_PIPE) {
68 return EINVAL;
69 }
70
71 hub_t *hub = (hub_t *)dev->device_data;
72
73 hub_acquire(hub);
74
75 uint8_t change_map = hub_get_status_change_bitmap(hub);
76
77 uint8_t *b = (uint8_t *) buffer;
78 if (size > 0) {
79 *b = change_map;
80 *actual_size = 1;
81 }
82
83 hub_release(hub);
84
85 return EOK;
86}
87
88/** Handle ClearHubFeature request.
89 *
90 * @param dev Virtual device representing the hub.
91 * @param request The SETUP packet of the control request.
92 * @param data Extra data (when DATA stage present).
93 * @return Error code.
94 */
95static int req_clear_hub_feature(usbvirt_device_t *dev,
96 usb_device_request_setup_packet_t *request,
97 uint8_t *data)
98{
99 return ENOTSUP;
100}
101
102/** Handle ClearPortFeature request.
103 *
104 * @param dev Virtual device representing the hub.
105 * @param request The SETUP packet of the control request.
106 * @param data Extra data (when DATA stage present).
107 * @return Error code.
108 */
109static int req_clear_port_feature(usbvirt_device_t *dev,
110 usb_device_request_setup_packet_t *request,
111 uint8_t *data)
112{
113 int rc;
114 size_t port = request->index - 1;
115 usb_hub_class_feature_t feature = request->value;
116 hub_t *hub = (hub_t *) dev->device_data;
117
118 hub_acquire(hub);
119
120 hub_port_state_t port_state = hub_get_port_state(hub, port);
121
122 switch (feature) {
123 case USB_HUB_FEATURE_PORT_ENABLE:
124 if ((port_state != HUB_PORT_STATE_NOT_CONFIGURED)
125 && (port_state != HUB_PORT_STATE_POWERED_OFF)) {
126 hub_set_port_state(hub, port, HUB_PORT_STATE_DISABLED);
127 }
128 rc = EOK;
129 break;
130
131 case USB_HUB_FEATURE_PORT_SUSPEND:
132 if (port_state != HUB_PORT_STATE_SUSPENDED) {
133 rc = EOK;
134 break;
135 }
136 hub_set_port_state(hub, port, HUB_PORT_STATE_RESUMING);
137 rc = EOK;
138 break;
139
140 case USB_HUB_FEATURE_PORT_POWER:
141 if (port_state != HUB_PORT_STATE_NOT_CONFIGURED) {
142 hub_set_port_state(hub, port, HUB_PORT_STATE_POWERED_OFF);
143 }
144 rc = EOK;
145 break;
146
147 case USB_HUB_FEATURE_C_PORT_CONNECTION:
148 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_CONNECTION);
149 rc = EOK;
150 break;
151
152 case USB_HUB_FEATURE_C_PORT_ENABLE:
153 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_ENABLE);
154 rc = EOK;
155 break;
156
157 case USB_HUB_FEATURE_C_PORT_SUSPEND:
158 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_SUSPEND);
159 rc = EOK;
160 break;
161
162 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
163 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_OVER_CURRENT);
164 rc = EOK;
165 break;
166
167 case USB_HUB_FEATURE_C_PORT_RESET:
168 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_RESET);
169 rc = EOK;
170 break;
171
172 default:
173 rc = ENOTSUP;
174 break;
175 }
176
177 hub_release(hub);
178
179 return rc;
180}
181
182/** Handle GetBusState request.
183 *
184 * @param dev Virtual device representing the hub.
185 * @param request The SETUP packet of the control request.
186 * @param data Extra data (when DATA stage present).
187 * @return Error code.
188 */
189static int req_get_bus_state(usbvirt_device_t *dev,
190 usb_device_request_setup_packet_t *request,
191 uint8_t *data)
192{
193 return ENOTSUP;
194}
195
196/** Handle GetDescriptor request.
197 *
198 * @param dev Virtual device representing the hub.
199 * @param request The SETUP packet of the control request.
200 * @param data Extra data (when DATA stage present).
201 * @return Error code.
202 */
203static int req_get_descriptor(usbvirt_device_t *dev,
204 usb_device_request_setup_packet_t *request,
205 uint8_t *data)
206{
207 if (request->value_high == USB_DESCTYPE_HUB) {
208 int rc = dev->control_transfer_reply(dev, 0,
209 &hub_descriptor, hub_descriptor.length);
210
211 return rc;
212 }
213 /* Let the framework handle all the rest. */
214 return EFORWARD;
215}
216
217/** Handle GetHubStatus request.
218 *
219 * @param dev Virtual device representing the hub.
220 * @param request The SETUP packet of the control request.
221 * @param data Extra data (when DATA stage present).
222 * @return Error code.
223 */
224static int req_get_hub_status(usbvirt_device_t *dev,
225 usb_device_request_setup_packet_t *request,
226 uint8_t *data)
227{
228 uint32_t hub_status = 0;
229
230 return dev->control_transfer_reply(dev, 0,
231 &hub_status, sizeof(hub_status));
232}
233
234/** Handle GetPortStatus request.
235 *
236 * @param dev Virtual device representing the hub.
237 * @param request The SETUP packet of the control request.
238 * @param data Extra data (when DATA stage present).
239 * @return Error code.
240 */
241static int req_get_port_status(usbvirt_device_t *dev,
242 usb_device_request_setup_packet_t *request,
243 uint8_t *data)
244{
245 hub_t *hub = (hub_t *) dev->device_data;
246
247 hub_acquire(hub);
248
249 uint32_t status = hub_get_port_status(hub, request->index - 1);
250
251 hub_release(hub);
252
253 return dev->control_transfer_reply(dev, 0, &status, 4);
254}
255
256/** Handle SetHubFeature request.
257 *
258 * @param dev Virtual device representing the hub.
259 * @param request The SETUP packet of the control request.
260 * @param data Extra data (when DATA stage present).
261 * @return Error code.
262 */
263static int req_set_hub_feature(usbvirt_device_t *dev,
264 usb_device_request_setup_packet_t *request,
265 uint8_t *data)
266{
267 return ENOTSUP;
268}
269
270/** Handle SetPortFeature request.
271 *
272 * @param dev Virtual device representing the hub.
273 * @param request The SETUP packet of the control request.
274 * @param data Extra data (when DATA stage present).
275 * @return Error code.
276 */
277static int req_set_port_feature(usbvirt_device_t *dev,
278 usb_device_request_setup_packet_t *request,
279 uint8_t *data)
280{
281 int rc;
282 size_t port = request->index - 1;
283 usb_hub_class_feature_t feature = request->value;
284 hub_t *hub = (hub_t *) dev->device_data;
285
286 hub_acquire(hub);
287
288 hub_port_state_t port_state = hub_get_port_state(hub, port);
289
290 switch (feature) {
291 case USB_HUB_FEATURE_PORT_RESET:
292 if (port_state != HUB_PORT_STATE_POWERED_OFF) {
293 hub_set_port_state(hub, port, HUB_PORT_STATE_RESETTING);
294 }
295 rc = EOK;
296 break;
297
298 case USB_HUB_FEATURE_PORT_SUSPEND:
299 if (port_state == HUB_PORT_STATE_ENABLED) {
300 hub_set_port_state(hub, port, HUB_PORT_STATE_SUSPENDED);
301 }
302 rc = EOK;
303 break;
304
305 case USB_HUB_FEATURE_PORT_POWER:
306 if (port_state == HUB_PORT_STATE_POWERED_OFF) {
307 hub_set_port_state(hub, port, HUB_PORT_STATE_DISCONNECTED);
308 }
309 rc = EOK;
310 break;
311
312 default:
313 break;
314 }
315
316 hub_release(hub);
317
318 return rc;
319}
320
321
322/** IN class request. */
323#define CLASS_REQ_IN(recipient) \
324 USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_IN, \
325 USBVIRT_REQUEST_TYPE_CLASS, recipient)
326/** OUT class request. */
327#define CLASS_REQ_OUT(recipient) \
328 USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_OUT, \
329 USBVIRT_REQUEST_TYPE_CLASS, recipient)
330
331/** Recipient: other. */
332#define REC_OTHER USBVIRT_REQUEST_RECIPIENT_OTHER
333/** Recipient: device. */
334#define REC_DEVICE USBVIRT_REQUEST_RECIPIENT_DEVICE
335/** Direction: in. */
336#define DIR_IN USB_DIRECTION_IN
337/** Direction: out. */
338#define DIR_OUT USB_DIRECTION_OUT
339
340/** Create a class request.
341 *
342 * @param direction Request direction.
343 * @param recipient Request recipient.
344 * @param req Request code.
345 */
346#define CLASS_REQ(direction, recipient, req) \
347 .request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
348 USBVIRT_REQUEST_TYPE_CLASS, recipient), \
349 .request = req
350
351/** Create a standard request.
352 *
353 * @param direction Request direction.
354 * @param recipient Request recipient.
355 * @param req Request code.
356 */
357#define STD_REQ(direction, recipient, req) \
358 .request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
359 USBVIRT_REQUEST_TYPE_STANDARD, recipient), \
360 .request = req
361
362/** Hub operations on control endpoint zero. */
363static usbvirt_control_transfer_handler_t endpoint_zero_handlers[] = {
364 {
365 STD_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
366 .name = "GetDescriptor",
367 .callback = req_get_descriptor
368 },
369 {
370 CLASS_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
371 .name = "GetDescriptor",
372 .callback = req_get_descriptor
373 },
374 {
375 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
376 .name = "GetPortStatus",
377 .callback = req_get_port_status
378 },
379 {
380 CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
381 .name = "ClearHubFeature",
382 .callback = req_clear_hub_feature
383 },
384 {
385 CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
386 .name = "ClearPortFeature",
387 .callback = req_clear_port_feature
388 },
389 {
390 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATE),
391 .name = "GetBusState",
392 .callback = req_get_bus_state
393 },
394 {
395 CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
396 .name = "GetHubDescriptor",
397 .callback = req_get_descriptor
398 },
399 {
400 CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_STATUS),
401 .name = "GetHubStatus",
402 .callback = req_get_hub_status
403 },
404 {
405 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
406 .name = "GetPortStatus",
407 .callback = req_get_port_status
408 },
409 {
410 CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
411 .name = "SetHubFeature",
412 .callback = req_set_hub_feature
413 },
414 {
415 CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_SET_FEATURE),
416 .name = "SetPortFeature",
417 .callback = req_set_port_feature
418 },
419 USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
420};
421
422
423/** Hub operations. */
424usbvirt_device_ops_t hub_ops = {
425 .control_transfer_handlers = endpoint_zero_handlers,
426 .on_data = NULL,
427 .on_data_request = req_on_data,
428 .on_state_change = on_state_change,
429};
430
431/**
432 * @}
433 */
Note: See TracBrowser for help on using the repository browser.