source: mainline/uspace/drv/vhc/hub/virthubops.c@ 774afaae

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

Refactoring of virtual hub

The hub is now divided into two layers (one as a hub and the other
one as a virtual USB device) and separated into more files for better
readability.

  • Property mode set to 100644
File size: 9.0 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
89static int req_clear_hub_feature(usbvirt_device_t *dev,
90 usb_device_request_setup_packet_t *request,
91 uint8_t *data)
92{
93 return ENOTSUP;
94}
95
96static int req_clear_port_feature(usbvirt_device_t *dev,
97 usb_device_request_setup_packet_t *request,
98 uint8_t *data)
99{
100 int rc;
101 size_t port = request->index - 1;
102 usb_hub_class_feature_t feature = request->value;
103 hub_t *hub = (hub_t *) dev->device_data;
104
105 hub_acquire(hub);
106
107 hub_port_state_t port_state = hub_get_port_state(hub, port);
108
109 switch (feature) {
110 case USB_HUB_FEATURE_PORT_ENABLE:
111 if ((port_state != HUB_PORT_STATE_NOT_CONFIGURED)
112 && (port_state != HUB_PORT_STATE_POWERED_OFF)) {
113 hub_set_port_state(hub, port, HUB_PORT_STATE_DISABLED);
114 }
115 rc = EOK;
116 break;
117
118 case USB_HUB_FEATURE_PORT_SUSPEND:
119 if (port_state != HUB_PORT_STATE_SUSPENDED) {
120 rc = EOK;
121 break;
122 }
123 hub_set_port_state(hub, port, HUB_PORT_STATE_RESUMING);
124 rc = EOK;
125 break;
126
127 case USB_HUB_FEATURE_PORT_POWER:
128 if (port_state != HUB_PORT_STATE_NOT_CONFIGURED) {
129 hub_set_port_state(hub, port, HUB_PORT_STATE_POWERED_OFF);
130 }
131 rc = EOK;
132 break;
133
134 case USB_HUB_FEATURE_C_PORT_CONNECTION:
135 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_CONNECTION);
136 rc = EOK;
137 break;
138
139 case USB_HUB_FEATURE_C_PORT_ENABLE:
140 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_ENABLE);
141 rc = EOK;
142 break;
143
144 case USB_HUB_FEATURE_C_PORT_SUSPEND:
145 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_SUSPEND);
146 rc = EOK;
147 break;
148
149 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
150 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_OVER_CURRENT);
151 rc = EOK;
152 break;
153
154 case USB_HUB_FEATURE_C_PORT_RESET:
155 hub_clear_port_status_change(hub, port, HUB_STATUS_C_PORT_RESET);
156 rc = EOK;
157 break;
158
159 default:
160 rc = ENOTSUP;
161 break;
162 }
163
164 hub_release(hub);
165
166 return rc;
167}
168
169static int req_get_bus_state(usbvirt_device_t *dev,
170 usb_device_request_setup_packet_t *request,
171 uint8_t *data)
172{
173 return ENOTSUP;
174}
175
176static int req_get_descriptor(usbvirt_device_t *dev,
177 usb_device_request_setup_packet_t *request,
178 uint8_t *data)
179{
180 if (request->value_high == USB_DESCTYPE_HUB) {
181 int rc = dev->control_transfer_reply(dev, 0,
182 &hub_descriptor, hub_descriptor.length);
183
184 return rc;
185 }
186 /* Let the framework handle all the rest. */
187 return EFORWARD;
188}
189
190static int req_get_hub_status(usbvirt_device_t *dev,
191 usb_device_request_setup_packet_t *request,
192 uint8_t *data)
193{
194 uint32_t hub_status = 0;
195
196 return dev->control_transfer_reply(dev, 0,
197 &hub_status, sizeof(hub_status));
198}
199
200static int req_get_port_status(usbvirt_device_t *dev,
201 usb_device_request_setup_packet_t *request,
202 uint8_t *data)
203{
204 hub_t *hub = (hub_t *) dev->device_data;
205
206 hub_acquire(hub);
207
208 uint32_t status = hub_get_port_status(hub, request->index - 1);
209
210 hub_release(hub);
211
212 return dev->control_transfer_reply(dev, 0, &status, 4);
213}
214
215static int req_set_hub_feature(usbvirt_device_t *dev,
216 usb_device_request_setup_packet_t *request,
217 uint8_t *data)
218{
219 return ENOTSUP;
220}
221
222static int req_set_port_feature(usbvirt_device_t *dev,
223 usb_device_request_setup_packet_t *request,
224 uint8_t *data)
225{
226 int rc;
227 size_t port = request->index - 1;
228 usb_hub_class_feature_t feature = request->value;
229 hub_t *hub = (hub_t *) dev->device_data;
230
231 hub_acquire(hub);
232
233 hub_port_state_t port_state = hub_get_port_state(hub, port);
234
235 switch (feature) {
236 case USB_HUB_FEATURE_PORT_RESET:
237 if (port_state != HUB_PORT_STATE_POWERED_OFF) {
238 hub_set_port_state(hub, port, HUB_PORT_STATE_RESETTING);
239 }
240 rc = EOK;
241 break;
242
243 case USB_HUB_FEATURE_PORT_SUSPEND:
244 if (port_state == HUB_PORT_STATE_ENABLED) {
245 hub_set_port_state(hub, port, HUB_PORT_STATE_SUSPENDED);
246 }
247 rc = EOK;
248 break;
249
250 case USB_HUB_FEATURE_PORT_POWER:
251 if (port_state == HUB_PORT_STATE_POWERED_OFF) {
252 hub_set_port_state(hub, port, HUB_PORT_STATE_DISCONNECTED);
253 }
254 rc = EOK;
255 break;
256
257 default:
258 break;
259 }
260
261 hub_release(hub);
262
263 return rc;
264}
265
266
267
268#define CLASS_REQ_IN(recipient) \
269 USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_IN, \
270 USBVIRT_REQUEST_TYPE_CLASS, recipient)
271#define CLASS_REQ_OUT(recipient) \
272 USBVIRT_MAKE_CONTROL_REQUEST_TYPE(USB_DIRECTION_OUT, \
273 USBVIRT_REQUEST_TYPE_CLASS, recipient)
274
275#define REC_OTHER USBVIRT_REQUEST_RECIPIENT_OTHER
276#define REC_DEVICE USBVIRT_REQUEST_RECIPIENT_DEVICE
277#define DIR_IN USB_DIRECTION_IN
278#define DIR_OUT USB_DIRECTION_OUT
279
280#define CLASS_REQ(direction, recipient, req) \
281 .request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
282 USBVIRT_REQUEST_TYPE_CLASS, recipient), \
283 .request = req
284
285#define STD_REQ(direction, recipient, req) \
286 .request_type = USBVIRT_MAKE_CONTROL_REQUEST_TYPE(direction, \
287 USBVIRT_REQUEST_TYPE_STANDARD, recipient), \
288 .request = req
289
290/** Hub operations on control endpoint zero. */
291static usbvirt_control_transfer_handler_t endpoint_zero_handlers[] = {
292 {
293 STD_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
294 .name = "GetDescriptor",
295 .callback = req_get_descriptor
296 },
297 {
298 CLASS_REQ(DIR_IN, REC_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
299 .name = "GetDescriptor",
300 .callback = req_get_descriptor
301 },
302 {
303 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
304 .name = "GetPortStatus",
305 .callback = req_get_port_status
306 },
307 {
308 CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
309 .name = "ClearHubFeature",
310 .callback = req_clear_hub_feature
311 },
312 {
313 CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
314 .name = "ClearPortFeature",
315 .callback = req_clear_port_feature
316 },
317 {
318 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATE),
319 .name = "GetBusState",
320 .callback = req_get_bus_state
321 },
322 {
323 CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
324 .name = "GetHubDescriptor",
325 .callback = req_get_descriptor
326 },
327 {
328 CLASS_REQ(DIR_IN, REC_DEVICE, USB_HUB_REQUEST_GET_STATUS),
329 .name = "GetHubStatus",
330 .callback = req_get_hub_status
331 },
332 {
333 CLASS_REQ(DIR_IN, REC_OTHER, USB_HUB_REQUEST_GET_STATUS),
334 .name = "GetPortStatus",
335 .callback = req_get_port_status
336 },
337 {
338 CLASS_REQ(DIR_OUT, REC_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
339 .name = "SetHubFeature",
340 .callback = req_set_hub_feature
341 },
342 {
343 CLASS_REQ(DIR_OUT, REC_OTHER, USB_HUB_REQUEST_SET_FEATURE),
344 .name = "SetPortFeature",
345 .callback = req_set_port_feature
346 },
347 USBVIRT_CONTROL_TRANSFER_HANDLER_LAST
348};
349
350
351/** Hub operations. */
352usbvirt_device_ops_t hub_ops = {
353 .control_transfer_handlers = endpoint_zero_handlers,
354 .on_data = NULL,
355 .on_data_request = req_on_data,
356 .on_state_change = on_state_change,
357};
358
359/**
360 * @}
361 */
Note: See TracBrowser for help on using the repository browser.