source: mainline/uspace/drv/bus/usb/ehci/ehci_rh.c@ c3d926f3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c3d926f3 was 5fd9c30, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

usbhost refactoring: let transfer_batch be initialized by bus

Currently makes older HCs fail, work in progress.

  • Property mode set to 100644
File size: 19.9 KB
Line 
1/*
2 * Copyright (c) 2013 Jan Vesely
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/** @addtogroup drvusbehci
29 * @{
30 */
31/** @file
32 * @brief EHCI driver
33 */
34
35#include <assert.h>
36#include <errno.h>
37#include <mem.h>
38#include <str_error.h>
39#include <stdint.h>
40#include <stddef.h>
41
42#include <usb/classes/hub.h>
43#include <usb/debug.h>
44#include <usb/descriptor.h>
45#include <usb/request.h>
46#include <usb/usb.h>
47
48#include <usb/host/endpoint.h>
49#include <usbvirt/device.h>
50
51#include "ehci_rh.h"
52
53enum {
54 HUB_STATUS_CHANGE_PIPE = 1,
55};
56
57static usbvirt_device_ops_t ops;
58
59/** Initialize internal USB HUB class descriptor.
60 * @param instance EHCI root hub.
61 * Use register based info to create accurate descriptor.
62 */
63static void ehci_rh_hub_desc_init(ehci_rh_t *instance, unsigned hcs)
64{
65 assert(instance);
66 const unsigned dsize = sizeof(usb_hub_descriptor_header_t) +
67 STATUS_BYTES(instance->port_count) * 2;
68 assert(dsize <= sizeof(instance->hub_descriptor));
69
70 instance->hub_descriptor.header.length = dsize;
71 instance->hub_descriptor.header.descriptor_type = USB_DESCTYPE_HUB;
72 instance->hub_descriptor.header.port_count = instance->port_count;
73 /* Bits 0,1 indicate power switching mode
74 * Bit 2 indicates device type (compound device)
75 * Bits 3,4 indicate over-current protection mode */
76 instance->hub_descriptor.header.characteristics = 0 |
77 ((hcs & EHCI_CAPS_HCS_PPC_FLAG) ? 0x09 : 0x12) |
78 ((hcs & EHCI_CAPS_HCS_INDICATORS_FLAG) ? 0x80 : 0) |
79 (0x3 << 5); /* Need 32 FS bit times */ // TODO Implement
80 instance->hub_descriptor.header.characteristics_reserved = 0;
81 instance->hub_descriptor.header.power_good_time = 50;
82 /* bHubContrCurrent, root hubs don't need no power. */
83 instance->hub_descriptor.header.max_current = 0;
84
85 /* Device removable and some legacy 1.0 stuff*/
86 instance->hub_descriptor.rempow[0] = 0xff;
87 instance->hub_descriptor.rempow[1] = 0xff;
88 instance->hub_descriptor.rempow[2] = 0xff;
89 instance->hub_descriptor.rempow[3] = 0xff;
90
91}
92/** Initialize EHCI root hub.
93 * @param instance Place to initialize.
94 * @param regs EHCI device registers.
95 * @param name Device name.
96 * return Error code, EOK on success.
97 *
98 * Selects preconfigured port powering mode, sets up descriptor, and
99 * initializes internal virtual hub.
100 */
101int ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps, ehci_regs_t *regs,
102 const char *name)
103{
104 assert(instance);
105 instance->registers = regs;
106 instance->port_count =
107 (EHCI_RD(caps->hcsparams) >> EHCI_CAPS_HCS_N_PORTS_SHIFT) &
108 EHCI_CAPS_HCS_N_PORTS_MASK;
109 usb_log_debug2("RH(%p): hcsparams: %x.\n", instance,
110 EHCI_RD(caps->hcsparams));
111 usb_log_info("RH(%p): Found %u ports.\n", instance,
112 instance->port_count);
113
114 if (EHCI_RD(caps->hcsparams) & EHCI_CAPS_HCS_PPC_FLAG) {
115 usb_log_info("RH(%p): Per-port power switching.", instance);
116 } else {
117 usb_log_info("RH(%p): No power switching.", instance);
118 }
119 for (unsigned i = 0; i < instance->port_count; ++i)
120 usb_log_debug2("RH(%p-%u): status: %"PRIx32, instance, i,
121 EHCI_RD(regs->portsc[i]));
122
123 for (unsigned i = 0; i < EHCI_MAX_PORTS; ++i) {
124 instance->reset_flag[i] = false;
125 instance->resume_flag[i] = false;
126 }
127
128 ehci_rh_hub_desc_init(instance, EHCI_RD(caps->hcsparams));
129 instance->unfinished_interrupt_transfer = NULL;
130
131 return virthub_base_init(&instance->base, name, &ops, instance,
132 NULL, &instance->hub_descriptor.header, HUB_STATUS_CHANGE_PIPE);
133}
134
135/** Schedule USB request.
136 * @param instance OCHI root hub instance.
137 * @param batch USB requst batch to schedule.
138 * @return Always EOK.
139 * Most requests complete even before this function returns,
140 * status change requests might be postponed until there is something to report.
141 */
142int ehci_rh_schedule(ehci_rh_t *instance, usb_transfer_batch_t *batch)
143{
144 assert(instance);
145 assert(batch);
146 const usb_target_t target = batch->ep->target;
147 batch->error = virthub_base_request(&instance->base, target,
148 batch->dir, (void*) batch->setup.buffer,
149 batch->buffer, batch->buffer_size, &batch->transfered_size);
150 if (batch->error == ENAK) {
151 usb_log_debug("RH(%p): BATCH(%p) adding as unfinished",
152 instance, batch);
153 /* This is safe because only status change interrupt transfers
154 * return NAK. The assertion holds true because the batch
155 * existence prevents communication with that ep */
156 assert(instance->unfinished_interrupt_transfer == NULL);
157 instance->unfinished_interrupt_transfer = batch;
158 } else {
159 usb_log_debug("RH(%p): BATCH(%p) virtual request complete: %s",
160 instance, batch, str_error(batch->error));
161 usb_transfer_batch_finish(batch);
162 }
163 return EOK;
164}
165
166/** Handle EHCI RHSC interrupt.
167 * @param instance EHCI root hub isntance.
168 * @return Always EOK.
169 *
170 * Interrupt means there is a change of status to report. It may trigger
171 * processing of a postponed request.
172 */
173int ehci_rh_interrupt(ehci_rh_t *instance)
174{
175 //TODO atomic swap needed
176 usb_transfer_batch_t *batch = instance->unfinished_interrupt_transfer;
177 instance->unfinished_interrupt_transfer = NULL;
178 usb_log_debug2("RH(%p): Interrupt. Processing batch: %p",
179 instance, batch);
180 if (batch) {
181 const usb_target_t target = batch->ep->target;
182 batch->error = virthub_base_request(&instance->base, target,
183 batch->dir, (void*) batch->setup.buffer,
184 batch->buffer, batch->buffer_size, &batch->transfered_size);
185 usb_transfer_batch_finish(batch);
186 }
187 return EOK;
188}
189
190/* HUB ROUTINES IMPLEMENTATION */
191#define TEST_SIZE_INIT(size, port, hub) \
192do { \
193 hub = virthub_get_data(device); \
194 assert(hub);\
195 if (uint16_usb2host(setup_packet->length) != size) \
196 return ESTALL; \
197 port = uint16_usb2host(setup_packet->index) - 1; \
198 if (port > hub->port_count) \
199 return EINVAL; \
200} while (0)
201
202/** Hub status request handler.
203 * @param device Virtual hub device
204 * @param setup_packet USB setup stage data.
205 * @param[out] data destination data buffer, size must be at least
206 * setup_packet->length bytes
207 * @param[out] act_size Sized of the valid response part of the buffer.
208 * @return Error code.
209 */
210static int req_get_status(usbvirt_device_t *device,
211 const usb_device_request_setup_packet_t *setup_packet,
212 uint8_t *data, size_t *act_size)
213{
214 ehci_rh_t *hub = virthub_get_data(device);
215 assert(hub);
216 if (uint16_usb2host(setup_packet->length) != 4)
217 return ESTALL;
218 /* ECHI RH does not report global OC, and local power is always good */
219 const uint32_t val = 0;
220 memcpy(data, &val, sizeof(val));
221 *act_size = sizeof(val);
222 return EOK;
223}
224
225/** Hub set feature request handler.
226 * @param device Virtual hub device
227 * @param setup_packet USB setup stage data.
228 * @param[out] data destination data buffer, size must be at least
229 * setup_packet->length bytes
230 * @param[out] act_size Sized of the valid response part of the buffer.
231 * @return Error code.
232 */
233static int req_clear_hub_feature(usbvirt_device_t *device,
234 const usb_device_request_setup_packet_t *setup_packet,
235 uint8_t *data, size_t *act_size)
236{
237 ehci_rh_t *hub = virthub_get_data(device);
238 assert(hub);
239
240 /*
241 * Chapter 11.16.2 specifies that only C_HUB_LOCAL_POWER and
242 * C_HUB_OVER_CURRENT are supported.
243 * C_HUB_LOCAL_POWER is not supported because root hubs do not support
244 * local power status feature.
245 * EHCI RH does not report global OC condition either
246 */
247 return ESTALL;
248}
249
250#define BIT_VAL(val, bit) ((val & bit) ? 1 : 0)
251#define EHCI2USB(val, bit, feat) (BIT_VAL(val, bit) << feat)
252
253/** Port status request handler.
254 * @param device Virtual hub device
255 * @param setup_packet USB setup stage data.
256 * @param[out] data destination data buffer, size must be at least
257 * setup_packet->length bytes
258 * @param[out] act_size Sized of the valid response part of the buffer.
259 * @return Error code.
260 */
261static int req_get_port_status(usbvirt_device_t *device,
262 const usb_device_request_setup_packet_t *setup_packet,
263 uint8_t *data, size_t *act_size)
264{
265 ehci_rh_t *hub;
266 unsigned port;
267 TEST_SIZE_INIT(4, port, hub);
268 if (setup_packet->value != 0)
269 return EINVAL;
270
271 const uint32_t reg = EHCI_RD(hub->registers->portsc[port]);
272 const uint32_t status = uint32_host2usb(
273 EHCI2USB(reg, USB_PORTSC_CONNECT_FLAG, USB_HUB_FEATURE_PORT_CONNECTION) |
274 EHCI2USB(reg, USB_PORTSC_ENABLED_FLAG, USB_HUB_FEATURE_PORT_ENABLE) |
275 EHCI2USB(reg, USB_PORTSC_SUSPEND_FLAG, USB_HUB_FEATURE_PORT_SUSPEND) |
276 EHCI2USB(reg, USB_PORTSC_OC_ACTIVE_FLAG, USB_HUB_FEATURE_PORT_OVER_CURRENT) |
277 EHCI2USB(reg, USB_PORTSC_PORT_RESET_FLAG, USB_HUB_FEATURE_PORT_RESET) |
278 EHCI2USB(reg, USB_PORTSC_PORT_POWER_FLAG, USB_HUB_FEATURE_PORT_POWER) |
279 (((reg & USB_PORTSC_LINE_STATUS_MASK) == USB_PORTSC_LINE_STATUS_K) ?
280 (1 << USB_HUB_FEATURE_PORT_LOW_SPEED) : 0) |
281 ((reg & USB_PORTSC_PORT_OWNER_FLAG) ? 0 : (1 << USB_HUB_FEATURE_PORT_HIGH_SPEED)) |
282 EHCI2USB(reg, USB_PORTSC_PORT_TEST_MASK, 11) |
283 EHCI2USB(reg, USB_PORTSC_INDICATOR_MASK, 12) |
284 EHCI2USB(reg, USB_PORTSC_CONNECT_CH_FLAG, USB_HUB_FEATURE_C_PORT_CONNECTION) |
285 EHCI2USB(reg, USB_PORTSC_EN_CHANGE_FLAG, USB_HUB_FEATURE_C_PORT_ENABLE) |
286 (hub->resume_flag[port] ? (1 << USB_HUB_FEATURE_C_PORT_SUSPEND) : 0) |
287 EHCI2USB(reg, USB_PORTSC_OC_CHANGE_FLAG, USB_HUB_FEATURE_C_PORT_OVER_CURRENT) |
288 (hub->reset_flag[port] ? (1 << USB_HUB_FEATURE_C_PORT_RESET): 0)
289 );
290 /* Note feature numbers for test and indicator feature do not
291 * correspond to the port status bit locations */
292 usb_log_debug2("RH(%p-%u) port status: %"PRIx32"(%"PRIx32")", hub, port,
293 status, reg);
294 memcpy(data, &status, sizeof(status));
295 *act_size = sizeof(status);
296 return EOK;
297}
298
299typedef struct {
300 ehci_rh_t *hub;
301 unsigned port;
302} ehci_rh_job_t;
303
304static int stop_reset(void *arg)
305{
306 ehci_rh_job_t *job = arg;
307 async_usleep(50000);
308 usb_log_debug("RH(%p-%u): Clearing reset", job->hub, job->port);
309 EHCI_CLR(job->hub->registers->portsc[job->port],
310 USB_PORTSC_PORT_RESET_FLAG);
311 /* wait for reset to complete */
312 while (EHCI_RD(job->hub->registers->portsc[job->port]) &
313 USB_PORTSC_PORT_RESET_FLAG) {
314 async_usleep(1);
315 };
316 usb_log_debug("RH(%p-%u): Reset complete", job->hub, job->port);
317 /* Handle port ownership, if the port is not enabled
318 * after reset it's a full speed device */
319 if (!(EHCI_RD(job->hub->registers->portsc[job->port]) &
320 USB_PORTSC_ENABLED_FLAG)) {
321 usb_log_info("RH(%p-%u): Port not enabled after reset (%"PRIX32
322 "), giving up ownership", job->hub, job->port,
323 EHCI_RD(job->hub->registers->portsc[job->port]));
324 EHCI_SET(job->hub->registers->portsc[job->port],
325 USB_PORTSC_PORT_OWNER_FLAG);
326 }
327 job->hub->reset_flag[job->port] = true;
328 ehci_rh_interrupt(job->hub);
329 free(job);
330 return 0;
331}
332
333static int stop_resume(void *arg)
334{
335 ehci_rh_job_t *job = arg;
336 async_usleep(20000);
337 usb_log_debug("RH(%p-%u): Stopping resume", job->hub, job->port);
338 EHCI_CLR(job->hub->registers->portsc[job->port],
339 USB_PORTSC_RESUME_FLAG);
340 job->hub->resume_flag[job->port] = true;
341 ehci_rh_interrupt(job->hub);
342 free(job);
343 return 0;
344}
345
346static int delayed_job(int (*func)(void*), ehci_rh_t *rh, unsigned port)
347{
348 ehci_rh_job_t *job = malloc(sizeof(*job));
349 if (!job)
350 return ENOMEM;
351 job->hub = rh;
352 job->port = port;
353 fid_t fib = fibril_create(func, job);
354 if (!fib) {
355 free(job);
356 return ENOMEM;
357 }
358 fibril_add_ready(fib);
359 usb_log_debug2("RH(%p-%u): Scheduled delayed stop job.", rh, port);
360 return EOK;
361}
362
363
364/** Port clear feature request handler.
365 * @param device Virtual hub device
366 * @param setup_packet USB setup stage data.
367 * @param[out] data destination data buffer, size must be at least
368 * setup_packet->length bytes
369 * @param[out] act_size Sized of the valid response part of the buffer.
370 * @return Error code.
371 */
372static int req_clear_port_feature(usbvirt_device_t *device,
373 const usb_device_request_setup_packet_t *setup_packet,
374 uint8_t *data, size_t *act_size)
375{
376 ehci_rh_t *hub;
377 unsigned port;
378 TEST_SIZE_INIT(0, port, hub);
379 const unsigned feature = uint16_usb2host(setup_packet->value);
380 /* Enabled features to clear: see page 269 of USB specs */
381 switch (feature)
382 {
383 case USB_HUB_FEATURE_PORT_POWER: /*8*/
384 usb_log_debug2("RH(%p-%u): Clear port power.", hub, port);
385 EHCI_CLR(hub->registers->portsc[port],
386 USB_PORTSC_PORT_POWER_FLAG);
387 return EOK;
388
389 case USB_HUB_FEATURE_PORT_ENABLE: /*1*/
390 usb_log_debug2("RH(%p-%u): Clear port enable.", hub, port);
391 EHCI_CLR(hub->registers->portsc[port],
392 USB_PORTSC_ENABLED_FLAG);
393 return EOK;
394
395 case USB_HUB_FEATURE_PORT_SUSPEND: /*2*/
396 usb_log_debug2("RH(%p-%u): Clear port suspend.", hub, port);
397 /* If not in suspend it's noop */
398 if ((EHCI_RD(hub->registers->portsc[port]) &
399 USB_PORTSC_SUSPEND_FLAG) == 0)
400 return EOK;
401 /* Host driven resume */
402 EHCI_SET(hub->registers->portsc[port],
403 USB_PORTSC_RESUME_FLAG);
404 //TODO: What if creating the delayed job fails?
405 return delayed_job(stop_resume, hub, port);
406
407 case USB_HUB_FEATURE_C_PORT_CONNECTION: /*16*/
408 usb_log_debug2("RH(%p-%u): Clear port connection change.",
409 hub, port);
410 EHCI_SET(hub->registers->portsc[port],
411 USB_PORTSC_CONNECT_CH_FLAG);
412 return EOK;
413 case USB_HUB_FEATURE_C_PORT_ENABLE: /*17*/
414 usb_log_debug2("RH(%p-%u): Clear port enable change.",
415 hub, port);
416 EHCI_SET(hub->registers->portsc[port],
417 USB_PORTSC_CONNECT_CH_FLAG);
418 return EOK;
419 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: /*19*/
420 usb_log_debug2("RH(%p-%u): Clear port OC change.",
421 hub, port);
422 EHCI_SET(hub->registers->portsc[port],
423 USB_PORTSC_OC_CHANGE_FLAG);
424 return EOK;
425 case USB_HUB_FEATURE_C_PORT_SUSPEND: /*18*/
426 usb_log_debug2("RH(%p-%u): Clear port suspend change.",
427 hub, port);
428 hub->resume_flag[port] = false;
429 return EOK;
430 case USB_HUB_FEATURE_C_PORT_RESET: /*20*/
431 usb_log_debug2("RH(%p-%u): Clear port reset change.",
432 hub, port);
433 hub->reset_flag[port] = false;
434 return EOK;
435
436 default:
437 usb_log_warning("RH(%p-%u): Clear unknown feature: %u",
438 hub, port, feature);
439 return ENOTSUP;
440 }
441}
442
443/** Port set feature request handler.
444 * @param device Virtual hub device
445 * @param setup_packet USB setup stage data.
446 * @param[out] data destination data buffer, size must be at least
447 * setup_packet->length bytes
448 * @param[out] act_size Sized of the valid response part of the buffer.
449 * @return Error code.
450 */
451static int req_set_port_feature(usbvirt_device_t *device,
452 const usb_device_request_setup_packet_t *setup_packet,
453 uint8_t *data, size_t *act_size)
454{
455 ehci_rh_t *hub;
456 unsigned port;
457 TEST_SIZE_INIT(0, port, hub);
458 const unsigned feature = uint16_usb2host(setup_packet->value);
459 switch (feature) {
460 case USB_HUB_FEATURE_PORT_ENABLE: /*1*/
461 usb_log_debug2("RH(%p-%u): Set port enable.", hub, port);
462 EHCI_SET(hub->registers->portsc[port],
463 USB_PORTSC_ENABLED_FLAG);
464 return EOK;
465 case USB_HUB_FEATURE_PORT_SUSPEND: /*2*/
466 usb_log_debug2("RH(%p-%u): Set port suspend.", hub, port);
467 EHCI_SET(hub->registers->portsc[port],
468 USB_PORTSC_SUSPEND_FLAG);
469 return EOK;
470 case USB_HUB_FEATURE_PORT_RESET: /*4*/
471 usb_log_debug2("RH(%p-%u): Set port reset.", hub, port);
472 EHCI_SET(hub->registers->portsc[port],
473 USB_PORTSC_PORT_RESET_FLAG);
474 //TODO: What if creating the delayed job fails?
475 return delayed_job(stop_reset, hub, port);
476 case USB_HUB_FEATURE_PORT_POWER: /*8*/
477 usb_log_debug2("RH(%p-%u): Set port power.", hub, port);
478 EHCI_SET(hub->registers->portsc[port],
479 USB_PORTSC_PORT_POWER_FLAG);
480 return EOK;
481 default:
482 usb_log_warning("RH(%p-%u): Set unknown feature: %u",
483 hub, port, feature);
484 return ENOTSUP;
485 }
486}
487
488/** Status change handler.
489 * @param device Virtual hub device
490 * @param endpoint Endpoint number
491 * @param tr_type Transfer type
492 * @param buffer Response destination
493 * @param buffer_size Bytes available in buffer
494 * @param actual_size Size us the used part of the dest buffer.
495 *
496 * Produces status mask. Bit 0 indicates hub status change the other bits
497 * represent port status change. Endian does not matter as UHCI root hubs
498 * only need 1 byte.
499 */
500static int req_status_change_handler(usbvirt_device_t *device,
501 usb_endpoint_t endpoint, usb_transfer_type_t tr_type,
502 void *buffer, size_t buffer_size, size_t *actual_size)
503{
504 ehci_rh_t *hub = virthub_get_data(device);
505 assert(hub);
506
507 if (buffer_size < STATUS_BYTES(hub->port_count))
508 return ESTALL;
509
510 uint16_t mask = 0;
511 for (unsigned port = 0; port < hub->port_count; ++port) {
512 /* Write-clean bits are those that indicate change */
513 uint32_t status = EHCI_RD(hub->registers->portsc[port]);
514 if ((status & USB_PORTSC_WC_MASK) || hub->reset_flag[port]) {
515 /* Ignore new LS device */
516 if ((status & USB_PORTSC_CONNECT_CH_FLAG) &&
517 (status & USB_PORTSC_LINE_STATUS_MASK) ==
518 USB_PORTSC_LINE_STATUS_K)
519 EHCI_SET(hub->registers->portsc[port],
520 USB_PORTSC_PORT_OWNER_FLAG);
521 else
522 mask |= (2 << port);
523 }
524 }
525
526 usb_log_debug2("RH(%p): root hub interrupt mask: %"PRIx16, hub, mask);
527
528 if (mask == 0)
529 return ENAK;
530 mask = uint16_host2usb(mask);
531 memcpy(buffer, &mask, STATUS_BYTES(hub->port_count));
532 *actual_size = STATUS_BYTES(hub->port_count);
533 return EOK;
534}
535
536/** EHCI root hub request handlers */
537static const usbvirt_control_request_handler_t control_transfer_handlers[] = {
538 {
539 STD_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
540 .name = "GetDescriptor",
541 .callback = virthub_base_get_hub_descriptor,
542 },
543 {
544 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
545 .name = "GetDescriptor",
546 .callback = virthub_base_get_hub_descriptor,
547 },
548 {
549 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
550 .name = "GetHubDescriptor",
551 .callback = virthub_base_get_hub_descriptor,
552 },
553 {
554 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_GET_STATUS),
555 .name = "GetPortStatus",
556 .callback = req_get_port_status,
557 },
558 {
559 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
560 .name = "ClearHubFeature",
561 .callback = req_clear_hub_feature,
562 },
563 {
564 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
565 .name = "ClearPortFeature",
566 .callback = req_clear_port_feature,
567 },
568 {
569 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_GET_STATUS),
570 .name = "GetHubStatus",
571 .callback = req_get_status,
572 },
573 {
574 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_GET_STATUS),
575 .name = "GetPortStatus",
576 .callback = req_get_port_status,
577 },
578 {
579 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
580 .name = "SetHubFeature",
581 .callback = req_nop,
582 },
583 {
584 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_SET_FEATURE),
585 .name = "SetPortFeature",
586 .callback = req_set_port_feature,
587 },
588 {
589 .callback = NULL
590 }
591};
592
593/** Virtual EHCI root hub ops */
594static usbvirt_device_ops_t ops = {
595 .control = control_transfer_handlers,
596 .data_in[HUB_STATUS_CHANGE_PIPE] = req_status_change_handler,
597};
Note: See TracBrowser for help on using the repository browser.