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

Last change on this file was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

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