source: mainline/uspace/drv/bus/usb/vhc/hub/virthubops.c@ 0bb4738

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0bb4738 was 58563585, checked in by Martin Decky <martin@…>, 9 years ago

code review and cstyle cleanup (no change in functionality)

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