source: mainline/uspace/drv/bus/usb/uhci/uhci_rh.c

Last change on this file was bd41ac52, checked in by Jakub Jermar <jakub@…>, 7 years ago

Get rid of sys/time.h

This commit moves the POSIX-like time functionality from libc's
sys/time.h to libposix and introduces C11-like or HelenOS-specific
interfaces to libc.

Specifically, use of sys/time.h, struct timeval, suseconds_t and
gettimeofday is replaced by time.h (C11), struct timespec (C11), usec_t
(HelenOS) and getuptime / getrealtime (HelenOS).

Also attempt to fix the implementation of clock() to return microseconds
(clocks) rather than processor cycles and move it to libc.

  • Property mode set to 100644
File size: 16.5 KB
RevLine 
[c95c00e]1/*
2 * Copyright (c) 2013 Jan Vesely
[e0a5d4c]3 * Copyright (c) 2018 Ondrej Hlavaty
[c95c00e]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <assert.h>
[8064c2f6]31#include <async.h>
32#include <ddi.h>
33#include <errno.h>
[c95c00e]34#include <macros.h>
[8064c2f6]35#include <mem.h>
[bd41ac52]36#include <time.h>
[8064c2f6]37
[c95c00e]38#include <usb/debug.h>
[8064c2f6]39#include <usb/descriptor.h>
[49f2f29]40#include <usb/classes/hub.h>
[8064c2f6]41#include <usb/request.h>
[5fd9c30]42#include <usb/host/endpoint.h>
[8064c2f6]43#include <usb/usb.h>
[c95c00e]44
45#include "uhci_rh.h"
46
47enum {
48 UHCI_RH_PORT_COUNT = 2,
[49f2f29]49 UHCI_PORT_BYTES = STATUS_BYTES(UHCI_RH_PORT_COUNT),
[c95c00e]50};
51
52/** Hub descriptor. */
53static const struct {
[af4e464e]54 /** Common hub descriptor header */
[c95c00e]55 usb_hub_descriptor_header_t header;
[af4e464e]56 /** Port removable status bits */
[c95c00e]57 uint8_t removable[UHCI_PORT_BYTES];
[af4e464e]58 /** Port powered status bits */
[c95c00e]59 uint8_t powered[UHCI_PORT_BYTES];
60} __attribute__((packed)) hub_descriptor = {
61 .header = {
62 .length = sizeof(hub_descriptor),
63 .descriptor_type = USB_DESCTYPE_HUB,
64 .port_count = UHCI_RH_PORT_COUNT,
65 .characteristics =
66 HUB_CHAR_NO_POWER_SWITCH_FLAG | HUB_CHAR_NO_OC_FLAG,
67 .power_good_time = 50,
68 .max_current = 0,
69 },
70 .removable = { 0 },
71 .powered = { 0xFF },
72};
73
74static usbvirt_device_ops_t ops;
75
[af4e464e]76/** Initialize uhci rh structure.
77 * @param instance Memory place to initialize.
78 * @param ports Pointer to TWO UHCI RH port registers.
79 * @param name device name, passed to virthub init
80 * @return Error code, EOK on success.
81 */
[5a6cc679]82errno_t uhci_rh_init(uhci_rh_t *instance, ioport16_t *ports, const char *name)
[c95c00e]83{
84 assert(instance);
85 instance->ports[0] = ports;
86 instance->ports[1] = ports + 1;
87 instance->reset_changed[0] = false;
88 instance->reset_changed[1] = false;
[e646c61]89 return virthub_base_init(&instance->base, name, &ops, instance,
[49f2f29]90 NULL, &hub_descriptor.header, HUB_STATUS_CHANGE_PIPE);
[c95c00e]91}
92
[af4e464e]93/** Schedule USB batch for the root hub.
94 *
95 * @param instance UHCI rh instance
96 * @param batch USB communication batch
97 * @return EOK.
98 *
99 * The result of scheduling is always EOK. The result of communication does
100 * not have to be.
101 */
[5a6cc679]102errno_t uhci_rh_schedule(uhci_rh_t *instance, usb_transfer_batch_t *batch)
[c95c00e]103{
104 assert(instance);
105 assert(batch);
106
[58d4880]107 do {
[a5b3de6]108 batch->error = virthub_base_request(&instance->base, batch->target,
[3bacee1]109 batch->dir, (void *) batch->setup.buffer,
[1d758fc]110 batch->dma_buffer.virt, batch->size, &batch->transferred_size);
[58d4880]111 if (batch->error == ENAK)
[5f97ef44]112 fibril_usleep(instance->base.endpoint_descriptor.poll_interval * 1000);
[58d4880]113 //TODO This is flimsy, but we can't exit early because
114 //ENAK is technically an error condition
115 } while (batch->error == ENAK);
[5fd9c30]116 usb_transfer_batch_finish(batch);
[c95c00e]117 return EOK;
118}
[af4e464e]119
120/** UHCI port register bits */
[c95c00e]121enum {
122 STATUS_CONNECTED = (1 << 0),
123 STATUS_CONNECTED_CHANGED = (1 << 1),
124 STATUS_ENABLED = (1 << 2),
125 STATUS_ENABLED_CHANGED = (1 << 3),
126 STATUS_LINE_D_PLUS = (1 << 4),
127 STATUS_LINE_D_MINUS = (1 << 5),
128 STATUS_RESUME = (1 << 6),
129 STATUS_ALWAYS_ONE = (1 << 7),
130
131 STATUS_LOW_SPEED = (1 << 8),
132 STATUS_IN_RESET = (1 << 9),
133 STATUS_SUSPEND = (1 << 12),
134
135 STATUS_CHANGE_BITS = STATUS_CONNECTED_CHANGED | STATUS_ENABLED_CHANGED,
136 STATUS_WC_BITS = STATUS_CHANGE_BITS,
137};
[af4e464e]138
[c95c00e]139/* HUB ROUTINES IMPLEMENTATION */
[af4e464e]140
[c95c00e]141static void uhci_port_reset_enable(ioport16_t *port)
142{
143 assert(port);
144 uint16_t port_status = pio_read_16(port);
145 /* We don't wan to remove changes, that's hub drivers work */
146 port_status &= ~STATUS_WC_BITS;
147 port_status |= STATUS_IN_RESET;
148 pio_write_16(port, port_status);
[5f97ef44]149 fibril_usleep(50000);
[c95c00e]150 port_status = pio_read_16(port);
151 port_status &= ~STATUS_IN_RESET;
152 pio_write_16(port, port_status);
[3bacee1]153 while ((port_status = pio_read_16(port)) & STATUS_IN_RESET)
154 ;
[7c3fb9b]155 /*
156 * PIO delay, should not be longer than 3ms as the device might
157 * enter suspend state.
158 */
[c95c00e]159 udelay(10);
[7c3fb9b]160 /*
161 * Drop ConnectionChange as some UHCI hw
162 * sets this bit after reset, that is incorrect
163 */
[c95c00e]164 port_status &= ~STATUS_WC_BITS;
[be554d9]165 pio_write_16(port, port_status | STATUS_ENABLED | STATUS_CONNECTED_CHANGED);
[c95c00e]166}
167#define TEST_SIZE_INIT(size, port, hub) \
168do { \
169 if (uint16_usb2host(setup_packet->length) != size) \
170 return ESTALL; \
171 port = uint16_usb2host(setup_packet->index) - 1; \
172 if (port != 0 && port != 1) \
173 return EINVAL; \
174 hub = virthub_get_data(device); \
175 assert(hub);\
176} while (0)
177
[9e9d018e]178#define RH_DEBUG(hub, port, msg, ...) \
[bc8bc6e]179do { \
[e646c61]180 if ((int)port >= 0) \
[9e9d018e]181 usb_log_debug("RH(%p-%d): " msg, hub, port, ##__VA_ARGS__); \
[e646c61]182 else \
[bc8bc6e]183 usb_log_debug("RH(%p):" msg, hub, ##__VA_ARGS__); \
184} while (0)
[e646c61]185
[af4e464e]186/** USB HUB port state request handler.
187 * @param device Virtual hub device
188 * @param setup_packet USB setup stage data.
189 * @param[out] data destination data buffer, size must be at least
190 * setup_packet->length bytes
191 * @param[out] act_size Sized of the valid response part of the buffer.
192 * @return Error code.
193 *
194 * Do not confuse with port status. Port state reports data line states,
195 * it is usefull for debuging purposes only.
196 */
[5a6cc679]197static errno_t req_get_port_state(usbvirt_device_t *device,
[c95c00e]198 const usb_device_request_setup_packet_t *setup_packet,
199 uint8_t *data, size_t *act_size)
200{
201 uhci_rh_t *hub;
202 unsigned port;
203 TEST_SIZE_INIT(1, port, hub);
204 if (setup_packet->value != 0)
205 return EINVAL;
206
207 const uint16_t value = pio_read_16(hub->ports[port]);
[3bacee1]208 data[0] = ((value & STATUS_LINE_D_MINUS) ? 1 : 0) |
209 ((value & STATUS_LINE_D_PLUS) ? 2 : 0);
210 RH_DEBUG(hub, port, "Bus state %" PRIx8 "(source %" PRIx16 ")",
[e646c61]211 data[0], value);
[c95c00e]212 *act_size = 1;
213 return EOK;
214}
215
216#define BIT_VAL(val, bit) \
217 ((val & bit) ? 1 : 0)
[cd3fa47]218#define UHCI2USB(val, bit, mask) \
219 (BIT_VAL(val, bit) ? (mask) : 0)
[c95c00e]220
[af4e464e]221/** Port status request handler.
222 * @param device Virtual hub device
223 * @param setup_packet USB setup stage data.
224 * @param[out] data destination data buffer, size must be at least
225 * setup_packet->length bytes
226 * @param[out] act_size Sized of the valid response part of the buffer.
227 * @return Error code.
228 *
229 * Converts status reported via ioport to USB format.
230 * @note: reset change status needs to be handled in sw.
231 */
[5a6cc679]232static errno_t req_get_port_status(usbvirt_device_t *device,
[c95c00e]233 const usb_device_request_setup_packet_t *setup_packet,
234 uint8_t *data, size_t *act_size)
235{
236 uhci_rh_t *hub;
237 unsigned port;
238 TEST_SIZE_INIT(4, port, hub);
239 if (setup_packet->value != 0)
240 return EINVAL;
241
242 const uint16_t val = pio_read_16(hub->ports[port]);
[44d518b]243 const uint32_t status = uint32_host2usb(
[cd3fa47]244 UHCI2USB(val, STATUS_CONNECTED, USB_HUB_PORT_STATUS_CONNECTION) |
245 UHCI2USB(val, STATUS_ENABLED, USB_HUB_PORT_STATUS_ENABLE) |
246 UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_SUSPEND) |
247 UHCI2USB(val, STATUS_IN_RESET, USB_HUB_PORT_STATUS_RESET) |
248 UHCI2USB(val, STATUS_ALWAYS_ONE, USB2_HUB_PORT_STATUS_POWER) |
249 UHCI2USB(val, STATUS_LOW_SPEED, USB2_HUB_PORT_STATUS_LOW_SPEED) |
250 UHCI2USB(val, STATUS_CONNECTED_CHANGED, USB_HUB_PORT_STATUS_C_CONNECTION) |
251 UHCI2USB(val, STATUS_ENABLED_CHANGED, USB2_HUB_PORT_STATUS_C_ENABLE) |
[3fafe5e0]252#if 0
253 UHCI2USB(val, STATUS_SUSPEND, USB2_HUB_PORT_STATUS_C_SUSPEND) |
254#endif
[3bacee1]255 (hub->reset_changed[port] ? USB_HUB_PORT_STATUS_C_RESET : 0));
[9e9d018e]256 RH_DEBUG(hub, port, "Port status %" PRIx32 " (source %" PRIx16
[a1732929]257 "%s)", uint32_usb2host(status), val,
[e646c61]258 hub->reset_changed[port] ? "-reset" : "");
[c95c00e]259 memcpy(data, &status, sizeof(status));
[84239b1]260 *act_size = sizeof(status);
[c95c00e]261 return EOK;
262}
263
[af4e464e]264/** Port clear feature request handler.
265 * @param device Virtual hub device
266 * @param setup_packet USB setup stage data.
267 * @param[out] data destination data buffer, size must be at least
268 * setup_packet->length bytes
269 * @param[out] act_size Sized of the valid response part of the buffer.
270 * @return Error code.
271 */
[5a6cc679]272static errno_t req_clear_port_feature(usbvirt_device_t *device,
[c95c00e]273 const usb_device_request_setup_packet_t *setup_packet,
274 uint8_t *data, size_t *act_size)
275{
276 uhci_rh_t *hub;
277 unsigned port;
278 TEST_SIZE_INIT(0, port, hub);
279 const unsigned feature = uint16_usb2host(setup_packet->value);
[e646c61]280 const uint16_t status = pio_read_16(hub->ports[port]);
281 const uint16_t val = status & (~STATUS_WC_BITS);
[c95c00e]282 switch (feature) {
[cd3fa47]283 case USB2_HUB_FEATURE_PORT_ENABLE:
[9e9d018e]284 RH_DEBUG(hub, port, "Clear port enable (status %"
[a1732929]285 PRIx16 ")", status);
[e646c61]286 pio_write_16(hub->ports[port], val & ~STATUS_ENABLED);
[c95c00e]287 break;
[cd3fa47]288 case USB2_HUB_FEATURE_PORT_SUSPEND:
[9e9d018e]289 RH_DEBUG(hub, port, "Clear port suspend (status %"
[a1732929]290 PRIx16 ")", status);
[e646c61]291 pio_write_16(hub->ports[port], val & ~STATUS_SUSPEND);
[c95c00e]292 // TODO we should do resume magic
[a1732929]293 usb_log_warning("Resume is not implemented on port %u", port);
[c95c00e]294 break;
295 case USB_HUB_FEATURE_PORT_POWER:
[a1732929]296 RH_DEBUG(hub, port, "Clear port power (status %" PRIx16 ")",
[e646c61]297 status);
[c95c00e]298 /* We are always powered */
[a1732929]299 usb_log_warning("Tried to power off port %u", port);
[c95c00e]300 break;
301 case USB_HUB_FEATURE_C_PORT_CONNECTION:
[9e9d018e]302 RH_DEBUG(hub, port, "Clear port conn change (status %"
[a1732929]303 PRIx16 ")", status);
[e646c61]304 pio_write_16(hub->ports[port], val | STATUS_CONNECTED_CHANGED);
[c95c00e]305 break;
306 case USB_HUB_FEATURE_C_PORT_RESET:
[9e9d018e]307 RH_DEBUG(hub, port, "Clear port reset change (status %"
[a1732929]308 PRIx16 ")", status);
[e646c61]309 hub->reset_changed[port] = false;
[c95c00e]310 break;
[cd3fa47]311 case USB2_HUB_FEATURE_C_PORT_ENABLE:
[9e9d018e]312 RH_DEBUG(hub, port, "Clear port enable change (status %"
[a1732929]313 PRIx16 ")", status);
[c95c00e]314 pio_write_16(hub->ports[port], status | STATUS_ENABLED_CHANGED);
315 break;
[cd3fa47]316 case USB2_HUB_FEATURE_C_PORT_SUSPEND:
[9e9d018e]317 RH_DEBUG(hub, port, "Clear port suspend change (status %"
[a1732929]318 PRIx16 ")", status);
[c95c00e]319 //TODO
320 return ENOTSUP;
321 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
[9e9d018e]322 RH_DEBUG(hub, port, "Clear port OC change (status %"
[a1732929]323 PRIx16 ")", status);
[c95c00e]324 /* UHCI Does not report over current */
[9e9d018e]325 //TODO: newer chips do, but some have broken wiring
[c95c00e]326 break;
327 default:
[9e9d018e]328 RH_DEBUG(hub, port, "Clear unknown feature %d (status %"
[a1732929]329 PRIx16 ")", feature, status);
330 usb_log_warning("Clearing feature %d is unsupported",
[e646c61]331 feature);
[c95c00e]332 return ESTALL;
333 }
334 return EOK;
335}
336
[af4e464e]337/** Port set feature request handler.
338 * @param device Virtual hub device
339 * @param setup_packet USB setup stage data.
340 * @param[out] data destination data buffer, size must be at least
341 * setup_packet->length bytes
342 * @param[out] act_size Sized of the valid response part of the buffer.
343 * @return Error code.
344 */
[5a6cc679]345static errno_t req_set_port_feature(usbvirt_device_t *device,
[c95c00e]346 const usb_device_request_setup_packet_t *setup_packet,
347 uint8_t *data, size_t *act_size)
348{
349 uhci_rh_t *hub;
350 unsigned port;
351 TEST_SIZE_INIT(0, port, hub);
352 const unsigned feature = uint16_usb2host(setup_packet->value);
353 const uint16_t status = pio_read_16(hub->ports[port]);
354 switch (feature) {
355 case USB_HUB_FEATURE_PORT_RESET:
[9e9d018e]356 RH_DEBUG(hub, port, "Set port reset before (status %" PRIx16
[a1732929]357 ")", status);
[c95c00e]358 uhci_port_reset_enable(hub->ports[port]);
359 hub->reset_changed[port] = true;
[9e9d018e]360 RH_DEBUG(hub, port, "Set port reset after (status %" PRIx16
[a1732929]361 ")", pio_read_16(hub->ports[port]));
[c95c00e]362 break;
[cd3fa47]363 case USB2_HUB_FEATURE_PORT_SUSPEND:
[9e9d018e]364 RH_DEBUG(hub, port, "Set port suspend (status %" PRIx16
[a1732929]365 ")", status);
[c95c00e]366 pio_write_16(hub->ports[port],
367 (status & ~STATUS_WC_BITS) | STATUS_SUSPEND);
[a1732929]368 usb_log_warning("Suspend is not implemented on port %u", port);
[c95c00e]369 break;
370 case USB_HUB_FEATURE_PORT_POWER:
[9e9d018e]371 RH_DEBUG(hub, port, "Set port power (status %" PRIx16
[a1732929]372 ")", status);
[c95c00e]373 /* We are always powered */
[a1732929]374 usb_log_warning("Tried to power port %u", port);
[af4e464e]375 break;
[c95c00e]376 case USB_HUB_FEATURE_C_PORT_CONNECTION:
[cd3fa47]377 case USB2_HUB_FEATURE_C_PORT_ENABLE:
378 case USB2_HUB_FEATURE_C_PORT_SUSPEND:
[c95c00e]379 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT:
[9e9d018e]380 RH_DEBUG(hub, port, "Set port change flag (status %" PRIx16
[a1732929]381 ")", status);
[7c3fb9b]382 /*
383 * These are voluntary and don't have to be set
384 * there is no way we could do it on UHCI anyway
385 */
[c95c00e]386 break;
387 default:
[9e9d018e]388 RH_DEBUG(hub, port, "Set unknown feature %d (status %" PRIx16
[a1732929]389 ")", feature, status);
390 usb_log_warning("Setting feature %d is unsupported",
[e646c61]391 feature);
[c95c00e]392 return ESTALL;
393 }
394 return EOK;
395}
396
[a5c2eb5f]397/** Status change handler.
398 * @param device Virtual hub device
399 * @param endpoint Endpoint number
400 * @param tr_type Transfer type
401 * @param buffer Response destination
402 * @param buffer_size Bytes available in buffer
403 * @param actual_size Size us the used part of the dest buffer.
404 *
405 * Produces status mask. Bit 0 indicates hub status change the other bits
406 * represent port status change. Endian does not matter as UHCI root hubs
407 * only need 1 byte.
408 */
[5a6cc679]409static errno_t req_status_change_handler(usbvirt_device_t *device,
[a5c2eb5f]410 usb_endpoint_t endpoint, usb_transfer_type_t tr_type,
411 void *buffer, size_t buffer_size, size_t *actual_size)
412{
413 uhci_rh_t *hub = virthub_get_data(device);
414 assert(hub);
415
416 if (buffer_size < 1)
417 return ESTALL;
418
419 const uint16_t status_a = pio_read_16(hub->ports[0]);
420 const uint16_t status_b = pio_read_16(hub->ports[1]);
421 const uint8_t status =
422 ((((status_a & STATUS_CHANGE_BITS) != 0) || hub->reset_changed[0]) ?
[3bacee1]423 0x2 : 0) |
[a5c2eb5f]424 ((((status_b & STATUS_CHANGE_BITS) != 0) || hub->reset_changed[1]) ?
[3bacee1]425 0x4 : 0);
[bc8bc6e]426 if (status)
427 RH_DEBUG(hub, -1, "Event mask %" PRIx8
428 " (status_a %" PRIx16 "%s),"
[a1732929]429 " (status_b %" PRIx16 "%s)", status,
[bc8bc6e]430 status_a, hub->reset_changed[0] ? "-reset" : "",
[3bacee1]431 status_b, hub->reset_changed[1] ? "-reset" : "");
[a5c2eb5f]432 ((uint8_t *)buffer)[0] = status;
433 *actual_size = 1;
[58d4880]434 return (status != 0 ? EOK : ENAK);
[a5c2eb5f]435}
436
[af4e464e]437/** UHCI root hub request handlers */
[2a5a7711]438static const usbvirt_control_request_handler_t control_transfer_handlers[] = {
[c95c00e]439 {
440 STD_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
441 .name = "GetDescriptor",
442 .callback = virthub_base_get_hub_descriptor,
443 },
444 {
445 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_DESCRIPTOR),
446 .name = "GetDescriptor",
447 .callback = virthub_base_get_hub_descriptor,
448 },
449 {
450 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_GET_DESCRIPTOR),
451 .name = "GetHubDescriptor",
452 .callback = virthub_base_get_hub_descriptor,
453 },
454 {
455 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_GET_STATE),
456 .name = "GetBusState",
457 .callback = req_get_port_state,
458 },
459 {
460 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_GET_STATUS),
461 .name = "GetPortStatus",
462 .callback = req_get_port_status
463 },
464 {
465 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_CLEAR_FEATURE),
466 .name = "ClearHubFeature",
[7c3fb9b]467 /*
468 * Hub features are overcurrent and supply good,
469 * this request may only clear changes that we never report
470 */
[c95c00e]471 .callback = req_nop,
472 },
473 {
474 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_CLEAR_FEATURE),
475 .name = "ClearPortFeature",
476 .callback = req_clear_port_feature
477 },
478 {
479 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_GET_STATUS),
480 .name = "GetHubStatus",
[7c3fb9b]481 /*
482 * UHCI can't report OC condition or,
483 * lose power source
484 */
[c95c00e]485 .callback = virthub_base_get_null_status,
486 },
487 {
488 CLASS_REQ_IN(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_GET_STATUS),
489 .name = "GetPortStatus",
490 .callback = req_get_port_status
491 },
492 {
493 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_DEVICE, USB_HUB_REQUEST_SET_FEATURE),
494 .name = "SetHubFeature",
[7c3fb9b]495 /*
496 * Hub features are overcurrent and supply good,
497 * this request may only set changes that we never report
498 */
[c95c00e]499 .callback = req_nop,
500 },
501 {
502 CLASS_REQ_OUT(USB_REQUEST_RECIPIENT_OTHER, USB_HUB_REQUEST_SET_FEATURE),
503 .name = "SetPortFeature",
504 .callback = req_set_port_feature
505 },
506 {
507 .callback = NULL
508 }
509};
510
511static usbvirt_device_ops_t ops = {
[3bacee1]512 .control = control_transfer_handlers,
513 .data_in[HUB_STATUS_CHANGE_PIPE] = req_status_change_handler,
[c95c00e]514};
Note: See TracBrowser for help on using the repository browser.