1/*
2 * Copyright (c) 2007-2013 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10/*
11 * Copyright (c) 2007-2013 ETH Zurich.
12 * All rights reserved.
13 *
14 * This file is distributed under the terms in the attached LICENSE file.
15 * If you do not find this file, copies can be found by writing to:
16 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
17 */
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <barrelfish/barrelfish.h>
22
23#include <usb/usb.h>
24#include <usb/usb_descriptor.h>
25
26#include <usb_controller.h>
27#include <usb_hub.h>
28#include <usb_device.h>
29#include <usb_transfer.h>
30#include <usb_driver.h>
31
32static void usb_hub_intr_cb(struct usb_xfer *xfer, usb_error_t err);
33
34static const struct usb_xfer_config hub_config[USB_HUB_NUM_TRANSFERS] = {
35    [0] = {
36        .type = USB_ENDPOINT_TYPE_INTR,
37        .direction = USB_ENDPOINT_DIRECTION_ANY,
38        .endpoint = USB_ENDPOINT_ADDRESS_ANY,
39        .timeout = 0,
40        .flags = {
41            .short_xfer_ok = 1,
42            .pipe_on_falure = 1,
43        },
44        .bufsize = 0,
45        .interval = USB_HUB_INTR_INTERVAL,
46        .usb_type = USB_TYPE_INTR,
47        .xfer_done_cb = &usb_hub_intr_cb
48    },
49};
50
51static uint8_t usb_hub_xplore_done = 1;
52
53static void usb_hub_intr_cb(struct usb_xfer *xfer, usb_error_t err)
54{
55    if (err != USB_ERR_OK) {
56        USB_DEBUG("WARNING: hub intr transfer failed...\n");
57        usb_transfer_start(xfer);
58    }
59
60    if (usb_hub_xplore_done) {
61        usb_hub_explore((xfer->device));
62    }
63    usb_transfer_start(xfer);
64}
65
66struct usb_device *usb_hub_get_device(struct usb_hub *hub,
67        struct usb_hub_port *port)
68{
69    return (hub->device->controller->devices[port->device_index]);
70}
71
72/**
73 * \brief   checks if the hub device lies within an acceptable depdth, such that
74 *          the attached USB devices have a specification conform depth
75 *
76 * \param   device: device we want to check
77 *
78 * \return  0: the depth of the device in the tree lies withing the range
79 *          1: the depth of the device is too deep
80 */
81static uint8_t usb_hub_too_deep(struct usb_device *device)
82{
83    switch (device->speed) {
84        case USB_SPEED_FULL:
85        case USB_SPEED_LOW:
86        case USB_SPEED_HIGH:
87            /* revision 2.0 */
88            if (device->depth > USB_HUB_MAX_DEPTH) {
89                return (1);
90            }
91            break;
92        case USB_SPEED_SUPER:
93            /* revision 3.0 */
94            assert(!"Super Speed not supported");
95            break;
96        default:
97            break;
98    }
99    return (0);
100}
101
102/**
103 * \brief this function reattaches the device on this port and reads out the
104 *        device information and does the basic initialization such as
105 *        assigning an address
106 *
107 * \param hub       the hub to attach the device
108 * \param portno    the number of the port to attach the device
109 *
110 * \return USB_ERR_OK on success
111 *         USB_ERR_XX on failure
112 */
113static usb_error_t usb_hub_reattach_port(struct usb_hub *hub, uint8_t portno)
114{
115    USB_DEBUG_TR_ENTER;
116    usb_error_t err = USB_ERR_OK;
117    uint8_t timeout = 0;
118
119    struct usb_device *child = usb_hub_get_device(hub,
120            hub->ports + (portno - 1));
121    struct usb_hub_port_status ps;
122    while (1) {
123
124        err = usb_hub_clear_port_feature(hub->device,
125                USB_HUB_FEATURE_C_PORT_CONNECTION, portno);
126        if (err) {
127            break;
128        }
129
130        err = usb_hub_get_port_status(hub->device, portno, &ps);
131        if (err) {
132            USB_DEBUG("ERROR: could not get port status. Port=%u", portno);
133            break;
134        }
135
136        if (!ps.wPortStatus.connection) {
137            debug_printf("Device detached from [Hub: %u, Port: %u].\n",
138                    hub->device->device_address, portno);
139            if (child != NULL) {
140                /* free up the device to restart fresh */
141                usb_device_free(child, 0);
142                child = NULL;
143            }
144            break;
145        }
146
147        /* check for the power on the port */
148        if (!ps.wPortStatus.power_state) {
149            USB_DEBUG("WARNING: Connected port %u has no power!\n", portno);
150        }
151
152        if (!ps.wPortStatus.device_mode) {
153            if (ps.wPortStatus.suspend) {
154                USB_DEBUG("Port %u is suspended. Wake up.\n", portno);
155                err = usb_hub_clear_port_feature(hub->device,
156                        USB_HUB_FEATURE_PORT_SUSPEND, portno);
157                lib_usb_wait(USB_DELAY_PORT_POWERUP);
158            }
159
160            err = usb_hub_reset_port(hub->device, portno);
161            if (err != USB_ERR_OK) {
162                USB_DEBUG("WARNING: port reset failed.\n");
163                break;
164            }
165
166            err = usb_hub_get_port_status(hub->device, portno, &ps);
167            if (err != USB_ERR_OK) {
168                USB_DEBUG("ERROR: Could not read port status (%u)\n", portno);
169                break;
170            }
171
172            if (ps.wPortChange.connect || !ps.wPortStatus.connection) {
173                if (timeout) {
174                    USB_DEBUG("WARTNING: timed out. "
175                    "Giving up port reset...\n");
176                    break;
177                }
178                timeout = 1;
179                continue;
180            }
181        }
182
183        /*
184         * figuring out the device speed, this depends on the hub speed
185         * and the port status fields
186         */
187        usb_speed_t speed = hub->device->speed;
188        switch (hub->device->speed) {
189            case USB_SPEED_HIGH:
190                if (ps.wPortStatus.is_hs) {
191                    speed = USB_SPEED_HIGH;
192                    USB_DEBUG_DEV("device speed is HS -> HIGH SPEED\n");
193                } else if (ps.wPortStatus.is_ls) {
194                    USB_DEBUG_DEV("device speed is HS -> LOW SPEED\n");
195                    speed = USB_SPEED_LOW;
196                } else {
197                    USB_DEBUG_DEV("device speed is HS -> FULL SPEED\n");
198                    speed = USB_SPEED_FULL;
199                }
200                break;
201
202            case USB_SPEED_FULL:
203                if (ps.wPortStatus.is_ls) {
204                    speed = USB_SPEED_LOW;
205                    USB_DEBUG_DEV("device speed is FS -> LOW SPEED\n");
206                } else {
207                    speed = USB_SPEED_FULL;
208                    USB_DEBUG_DEV("device speed is FS -> FULL SPEED\n");
209                }
210                break;
211            case USB_SPEED_LOW:
212                USB_DEBUG_DEV("device speed is LS -> LOW SPEED\n");
213                speed = USB_SPEED_LOW;
214                break;
215            case USB_SPEED_SUPER:
216                assert(!"NYI: SUPER SPEED DEVICES");
217                break;
218            default:
219                /* same speed as parent */
220                break;
221        }
222
223        if (speed == USB_SPEED_SUPER) {
224            /* here goes some special handling for super speeds */
225            assert(!"NYI: super speed timeout handling\n");
226        }
227
228        usb_mode_t mode = USB_MODE_HOST;
229        if (ps.wPortStatus.device_mode) {
230            USB_DEBUG_DEV("new device in DEVICE_MODE\n");
231            mode = USB_MODE_DEVICE;
232        }
233        debug_printf("New device attached on [Hub: %u, Port: %u]\n",
234                hub->device->device_address, portno);
235        child = usb_device_alloc(hub->device->controller, hub->device,
236                hub->device->depth + 1, portno - 1, portno, speed, mode);
237        if (child == NULL) {
238            USB_DEBUG("ERROR: Could not allocate a new device!\n");
239            return (USB_ERR_NOMEM);
240        }
241
242        usb_driver_start(child);
243
244        return (USB_ERR_OK);
245    }
246
247    if (child != NULL) {
248        usb_device_free(child, 0);
249        child = NULL;
250    }
251
252    if (err == USB_ERR_OK) {
253        if (ps.wPortStatus.enabled) {
254            err = usb_hub_clear_port_feature(hub->device,
255                    USB_HUB_FEATURE_PORT_ENABLE, portno);
256        }
257    }
258    if (err) {
259        USB_DEBUG("WARNING: Device problem, disabling port\n");
260    }
261    return (err);
262}
263
264static usb_error_t usb_hub_suspend_resume_port(struct usb_hub *hub,
265        uint8_t portno)
266{
267    assert(!"NYI: don't support suspend / resume at the moment.\n");
268    return (USB_ERR_OK);
269}
270
271/**
272 * \brief initializes a new USB hub device and checks for attached devices
273 *
274 * \param hub_device the USB device which is a hub
275 *
276 * \return USB_ERR_OK on success
277 *         USB_ERR_XX on failure
278 */
279usb_error_t usb_hub_init(struct usb_device *hub_device)
280{
281    USB_DEBUG_TR_ENTER;
282
283    struct usb_device *parent_hub = hub_device->parent_hub;
284    usb_error_t err;
285
286    USB_DEBUG_DEV("initializing hub device...\n");
287
288    /* check if the hub has an appropriate depth */
289    if (usb_hub_too_deep(hub_device)) {
290        USB_DEBUG("Hub is too deep!. Ignored. \n");
291        /* TODO: err */
292        return (USB_ERR_TOO_DEEP);
293    }
294
295    if (!(hub_device->flags.self_powered) && parent_hub
296            && (!parent_hub->flags.self_powered)) {
297        /*
298         * note: bus powered hubs cannot be connected to other
299         * bus powered hubs.
300         */
301        USB_DEBUG("WARNING: insufficient power.\n");
302        /* TODO: ERR */
303        return (USB_ERR_INVAL);
304    }
305
306    struct usb_hub_descriptor desc;
307
308    uint8_t nports = 0;
309    uint16_t powerdelay = 0;
310
311    switch (hub_device->speed) {
312        case USB_SPEED_LOW:
313        case USB_SPEED_FULL:
314        case USB_SPEED_HIGH:
315            err = usb_hub_get_hub_descriptor(hub_device, 1, &desc);
316            if (err != USB_ERR_OK) {
317                USB_DEBUG("ERROR: could not get hub descriptor \n");
318                return (err);
319            }
320            /* get the number of ports */
321            nports = desc.bNbrPorts;
322
323            if (nports > 127) {
324                USB_DEBUG("WARNING: invalid port count\n");
325                return (USB_ERR_INVAL);
326            }
327
328            /* get the power delay */
329            powerdelay = USB_HUB_POWER_ON_DELAY(&desc);
330
331            /*
332             * we just got the first byte of data for the ports, so we
333             * have to get more data if the port count is bigger than
334             * the first byte i.e. 8
335             */
336            if (nports >= 8) {
337                err = usb_hub_get_hub_descriptor(hub_device, nports, &desc);
338
339                if (err != USB_ERR_OK) {
340                    debug_printf("ERROR: could not get hub descriptor \n");
341                    return (err);
342                }
343
344                if (desc.bNbrPorts != nports) {
345                    debug_printf("ERROR: Volatile port count?? \n");
346                    return (USB_ERR_INVAL);
347                }
348            }
349            break;
350
351        case USB_SPEED_SUPER:
352            assert(!"NYI: super speed not supported\n");
353            break;
354        default:
355            debug_printf("ERROR: Invalid device speed!\n");
356            return (USB_ERR_INVAL);
357            break;
358    }
359
360    USB_DEBUG_DEV("Found hub device: Num ports = %u\n", desc.bNbrPorts);
361
362    if (nports == 0) {
363        debug_printf("ERROR: hub has no ports\n");
364        return (USB_ERR_IOERROR);
365        /* TODO: ERROR */
366    }
367
368    struct usb_hub *hub = malloc(
369            sizeof(struct usb_hub) + (sizeof(usb_hub_port_t) * nports));
370
371    if (hub == NULL) {
372        debug_printf("ERROR: Could not allocate memory for hub struct\n");
373        return (USB_ERR_NOMEM);
374    }
375
376    /* do the binding */
377    hub_device->hub = hub;
378    hub->device = hub_device;
379
380    hub->num_ports = nports;
381
382    if (hub_device->flags.self_powered) {
383        hub->portpower = USB_POWER_MAX;
384    } else {
385        hub->portpower = USB_POWER_MIN;
386    }
387
388    /* setup the interrupt pipe */
389    if (USB_DEVICE_IS_ROOTHUB(hub_device)) {
390        /*
391         * the root hub is special, it needs no interrupt transfer
392         */
393        USB_DEBUG_DEV("device was the root hub \n");
394        err = USB_ERR_OK;
395    } else {
396        USB_DEBUG_DEV("device was an attached hub \n");
397        err = usb_transfer_setup(hub_device, 0, &hub->xfers[0], hub_config);
398    }
399    if (err != USB_ERR_OK) {
400        debug_printf("Could not setup the interrupt transfer\n");
401        free(hub);
402        return (err);
403    }
404
405    lib_usb_wait(USB_DELAY_PORT_POWERUP);
406
407    uint8_t portno = 0;
408    uint8_t removable = 0;
409
410    /* enumerate the devices and setup the data structures */
411    for (uint8_t portindex = 0; portindex < nports; portindex++) {
412        struct usb_hub_port *port = hub->ports + portindex;
413
414        port->device_index = 0;
415        port->restarts = 0;
416
417        /* the port number (1 based) is the port index (0 based) + 1 */
418        portno = portindex + 1;
419
420        switch (hub_device->speed) {
421            case USB_SPEED_LOW:
422            case USB_SPEED_FULL:
423            case USB_SPEED_HIGH:
424                if (USB_HUB_DEVICE_REMOVABLE(&desc, portno)) {
425                    removable++;
426                }
427                break;
428            case USB_SPEED_SUPER:
429                assert(!"NYI: super speed\n");
430                break;
431            default:
432                debug_printf("WARNING: unknown speed, "
433                        "assuming device removable\n");
434                removable++;
435                break;
436        }
437
438        if (err == USB_ERR_OK) {
439            /* all fine we can turn on the power on that port */
440            err = usb_hub_set_port_feature(hub_device,
441                    USB_HUB_FEATURE_PORT_POWER, portno);
442        }
443
444        if (err != USB_ERR_OK) {
445            debug_printf("WARNING: could not power on the port\n");
446        }
447
448        /* wait for powerdelay ms till the power power is good  */
449        lib_usb_wait(powerdelay);
450    }
451
452    /* start the interrupt transfer */
453    if (hub->xfers[0] != NULL) {
454        USB_DEBUG_DEV("starting hub interrupt transfer\n");
455        usb_transfer_start(hub->xfers[0]);
456    }
457
458    return (USB_ERR_OK);
459}
460
461/**
462 * \brief this function is called upon removal of the USB hub device.
463 *        All the child devices need to be removed
464 *
465 * \brief hub_device the USB device (hub) which is removed
466 *
467 * \return USB_ERR_OK on success
468 *         USB_ERR_XX on failure
469 */
470usb_error_t usb_hub_deinit(struct usb_device *hub_device)
471{
472    return (USB_ERR_OK);
473}
474
475/**
476 * \brief this function is called when a port hub change event is detected.
477 *        all the ports are explored and the devices are identified
478 *
479 * \param usb_device the hub to explore
480 *
481 * \return USB_ERR_OK on success
482 *         USB_ERR_XX on failure
483 */
484usb_error_t usb_hub_explore(struct usb_device *hub_device)
485{
486    usb_error_t err;
487
488    struct usb_hub *hub = hub_device->hub;
489
490    usb_hub_xplore_done = 0;
491
492    if (hub == NULL) {
493        USB_DEBUG("ERROR: hub_explore() - bad context.\n");
494        return (USB_ERR_BAD_CONTEXT);
495    }
496
497    /*
498     * if the USB hub is too deep in the USB device tree, then the attached
499     * USB devices have a depth which would not be USB specification conform,
500     * so if this is the case, skip the exploration process at this stage.
501     */
502    if (usb_hub_too_deep(hub_device)) {
503        USB_DEBUG("WARNING: hub_explore() - too deep.\n");
504        return (USB_ERR_TOO_DEEP);
505    }
506
507    /* start exploring the ports by loop over the ports */
508
509    usb_hub_port_t *port = NULL;
510    uint8_t portno = 0;
511    struct usb_hub_port_status ps;
512
513    USB_DEBUG_DEV(
514            "exploring ports of hub [%03u]...\n", hub_device->device_address);
515
516    for (uint32_t i = 0; i < hub->num_ports; i++) {
517        port = hub->ports + i;
518        portno = i + 1;
519
520        err = usb_hub_get_port_status(hub->device, portno, &ps);
521        if (err != USB_ERR_OK) {
522            USB_DEBUG(
523                    "WARNING: Could not read port status. Hub gone?%s\n", usb_get_error_string(err));
524            break;
525        }
526
527        /* check if we have a port over current condition */
528        if (ps.wPortChange.over_current) {
529            USB_DEBUG_DEV(
530                    "NOTICE: Over current condition on port %u.\n", portno);
531            err = usb_hub_clear_port_feature(hub->device,
532                    USB_HUB_FEATURE_C_PORT_OVER_CURRENT, portno);
533            if (err != USB_ERR_OK) {
534                USB_DEBUG(
535                        "WARNING: Could not clear port feature. Hub gone?\n");
536                break;
537            }
538        }
539
540        /*
541         * check if the port got disabled, this indicates an error condition
542         * on the port
543         */
544        if (ps.wPortChange.disabled) {
545            USB_DEBUG_DEV("WARNING: Port %i got disabled.\n", i);
546            err = usb_hub_clear_port_feature(hub->device,
547                    USB_HUB_FEATURE_C_PORT_ENABLE, portno);
548            if (err != USB_ERR_OK) {
549                debug_printf(
550                        "WARNING: Could not clear port feature. Hub gone?\n");
551                break;
552            }
553
554            if (ps.wPortChange.connect) {
555                USB_DEBUG_DEV("NOTICE: Device on ort %u is gone.\n", i);
556                /* the device is gone, ignore the port error */
557
558            } else if (ps.wPortStatus.enabled) {
559                USB_DEBUG(
560                        "WARNING: illegal enable change on port %u\n", portno);
561            } else {
562                if (port->restarts == USB_HUB_MAX_RESTARTS) {
563                    USB_DEBUG("WARNING: too many restarts on port %"PRIu32".\n ", i);
564                } else {
565                    ps.wPortChange.connect = 1;
566                    port->restarts++;
567                }
568            }
569        }
570
571        if (ps.wPortChange.connect) {
572            err = usb_hub_reattach_port(hub, portno);
573            if (err != USB_ERR_OK) {
574                debug_printf("WARNING: Could not reattach port. Hub gone?\n");
575                break;
576            }
577        }
578
579        if (ps.wPortChange.resumed || ps.wPortChange.linkstate) {
580            USB_DEBUG_DEV("NOTICE: suspend/resume device on port %i.\n", i);
581            err = usb_hub_suspend_resume_port(hub, portno);
582            if (err != USB_ERR_OK) {
583                debug_printf("WARNING: Could not resume the port. Hub gone?\n");
584                break;
585            }
586        }
587
588        struct usb_host_controller *hc = hub_device->controller;
589        struct usb_device *child = hc->devices[port->device_index];
590
591        if (child != NULL && child->hub != NULL) {
592            USB_DEBUG_DEV("Device on port %u is a hub. Exploring...\n", portno);
593            err = usb_hub_explore(child);
594            usb_hub_xplore_done = 0;
595        }
596
597        if (err != USB_ERR_OK) {
598            /* no device is present, just continue */
599            continue;
600        }
601
602        port->restarts = 0;
603
604    }
605
606    usb_hub_xplore_done = 1;
607
608    return (USB_ERR_OK);
609}
610
611static uint8_t usb_hub_find_slot(uint16_t *ptr, uint8_t start, uint8_t end,
612        uint8_t mask)
613{
614    uint16_t min = (uint16_t)-1;
615    uint8_t slot = 0;
616    for (uint8_t cs = start; cs < end; cs++) {
617        uint16_t sum = 0;
618
619        for (uint8_t bw = cs; bw < end; bw++) {
620            if (mask & (1U << (bw - cs))) {
621                sum += ptr[bw];
622            }
623        }
624
625        if (min >= sum) {
626            min = sum;
627            slot = cs;
628        }
629
630        if (mask & (1U << (end - 1 - cs))) {
631            break;
632        }
633    }
634    return (slot);
635}
636
637uint8_t usb_hub_bandwidth_adjust(struct usb_device *dev, uint16_t length,
638        uint8_t slot, uint8_t mask)
639{
640    struct usb_host_controller *hc = dev->controller;
641    struct usb_hub *hub = dev->parent_hs_hub->hub;
642    assert(hub != NULL);
643
644    switch (dev->speed) {
645        case USB_SPEED_LOW:
646        case USB_SPEED_FULL:
647            if (dev->speed == USB_SPEED_LOW) {
648                length *=  8;
649            }
650            assert(dev->parent_hs_hub != NULL);
651
652            if (slot >= 8) {
653                slot = usb_hub_find_slot(hub->uframe_usage, 4, 6, mask);
654            }
655
656            for (uint32_t cs = slot; cs < 8; cs++) {
657                if (mask & (1U << (cs - slot))) {
658                    hub->uframe_usage[cs] += length;
659                    hc->uframe_usage[cs] += length;
660                }
661            }
662            break;
663        default:
664            if (slot >= 8) {
665                slot = usb_hub_find_slot(hub->uframe_usage, 8, 6, mask);
666            }
667            for (uint32_t cs = slot; cs < 8; cs++) {
668                if (mask & (1U << (cs - slot))) {
669                    hc->uframe_usage[cs] += length;
670                }
671            }
672            break;
673    }
674    return (slot);
675}
676
677void usb_hub_bandwidth_alloc(struct usb_xfer *xfer)
678{
679    struct usb_device *dev = xfer->device;
680
681    xfer->endpoint->ref_bandwidth++;
682    if (xfer->endpoint->ref_bandwidth != 1) {
683        /* the bandwidth for this transfer is already allocated... */
684        return;
685    }
686
687    uint8_t slot, mask;
688
689    switch (xfer->type) {
690        case USB_TYPE_INTR:
691            mask = 0x01;
692            slot = usb_hub_bandwidth_adjust(dev, xfer->max_frame_size, 8, mask);
693            xfer->endpoint->hs_uframe = slot;
694            xfer->endpoint->hs_smask = mask << slot;
695
696            switch (xfer->device->speed) {
697                case USB_SPEED_LOW:
698                case USB_SPEED_FULL:
699                    xfer->endpoint->hs_cmask = (-(0x04 << slot)) & 0xFE;
700                    break;
701                default:
702                    xfer->endpoint->hs_cmask = 0x00;
703                    break;
704            }
705
706            break;
707        case USB_TYPE_ISOC:
708            switch (xfer->frame_shift) {
709                case 0:
710                    mask = 0xFF;
711                    break;
712                case 1:
713                    mask = 0x55;
714                    break;
715                case 2:
716                    mask = 0x11;
717                    break;
718                default:
719                    mask = 0x01;
720                    break;
721
722            }
723            slot = usb_hub_bandwidth_adjust(dev, xfer->max_frame_size, 8, mask);
724            xfer->endpoint->hs_uframe = slot;
725            xfer->endpoint->hs_smask = mask << slot;
726            xfer->endpoint->hs_cmask = 0;
727            break;
728        default:
729            xfer->endpoint->hs_uframe = 0;
730            xfer->endpoint->hs_smask = 0;
731            xfer->endpoint->hs_cmask = 0;
732            break;
733    }
734}
735
736void usb_hub_bandwidth_free(struct usb_xfer *xfer)
737{
738
739    struct usb_device *dev;
740    uint8_t slot;
741    uint8_t mask;
742
743    dev = xfer->device;
744
745    xfer->endpoint->ref_bandwidth--;
746    if (xfer->endpoint->ref_bandwidth != 0) {
747        /* the allocated bandwidth is still needed.. */
748        return;
749    }
750
751    switch (xfer->type) {
752        case USB_TYPE_INTR:
753        case USB_TYPE_ISOC:
754
755            slot = xfer->endpoint->hs_uframe;
756            mask = xfer->endpoint->hs_smask;
757
758
759            usb_hub_bandwidth_adjust(dev, -(xfer->max_frame_size), slot,
760                    mask >> slot);
761
762            xfer->endpoint->hs_uframe = 0;
763            xfer->endpoint->hs_cmask = 0;
764            xfer->endpoint->hs_smask = 0;
765            break;
766
767        default:
768            break;
769    }
770}
771
772/**
773 *
774 */
775usb_error_t usb_hub_query_info(struct usb_hub *hub, uint8_t *ret_nports,
776        uint8_t *ret_tt)
777{
778    struct usb_hub_descriptor desc;
779    usb_error_t err = USB_ERR_OK;
780
781    uint8_t nports = 0;
782    uint8_t tt = 0;
783
784    switch (hub->device->speed) {
785        case USB_SPEED_LOW:
786        case USB_SPEED_HIGH:
787        case USB_SPEED_FULL:
788            err = usb_hub_get_hub_descriptor(hub->device, 1, &desc);
789            if (err) {
790                debug_printf("ERROR: Failed to get hub descriptor\n");
791                break;
792            }
793            nports = desc.bNbrPorts;
794            if (nports > 127) {
795                nports = 127;
796            }
797            if (hub->device->speed == USB_SPEED_HIGH) {
798                tt = desc.wHubCharacteristics.tt_think_time;
799            }
800            break;
801        case USB_SPEED_SUPER:
802            assert(!"NYI: super speed hub\n");
803            break;
804        default:
805            break;
806    }
807
808    if (ret_nports != NULL) {
809        *ret_nports = nports;
810    }
811
812    if (ret_tt != NULL) {
813        *ret_tt = tt;
814    }
815
816    return (err);
817}
818
819void usb_hub_root_interrupt(struct usb_host_controller *hc)
820{
821    USB_DEBUG_TR("usb_hub_root_interrupt()\n");
822    if (hc == NULL) {
823        debug_printf("WARNING: No host controller\n");
824        return;
825    }
826    if ((hc->devices == NULL) || (hc->root_hub == NULL)) {
827        debug_printf("WARNING: No root hub\n");
828        return;
829    }
830    if (usb_hub_explore(hc->root_hub) != USB_ERR_OK) {
831        debug_printf("WARNING: explore failed\n");
832    }
833}
834