source: rtems-libbsd/freebsd/sys/dev/usb/usb_hub.c @ 165dd8e

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 165dd8e was 165dd8e, checked in by Sebastian Huber <sebastian.huber@…>, on 04/08/15 at 13:37:49

Update to FreeBSD Stable/9 2015-04-08

  • Property mode set to 100644
File size: 68.8 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/* $FreeBSD$ */
4/*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.
6 * Copyright (c) 1998 Lennart Augustsson. All rights reserved.
7 * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*
32 * USB spec: http://www.usb.org/developers/docs/usbspec.zip
33 */
34
35#include <sys/stdint.h>
36#include <sys/stddef.h>
37#include <rtems/bsd/sys/param.h>
38#include <sys/queue.h>
39#include <rtems/bsd/sys/types.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/bus.h>
43#include <sys/module.h>
44#include <rtems/bsd/sys/lock.h>
45#include <sys/mutex.h>
46#include <sys/condvar.h>
47#include <sys/sysctl.h>
48#include <sys/sx.h>
49#include <rtems/bsd/sys/unistd.h>
50#include <sys/callout.h>
51#include <sys/malloc.h>
52#include <sys/priv.h>
53
54#include <dev/usb/usb.h>
55#include <dev/usb/usbdi.h>
56#include <dev/usb/usbdi_util.h>
57
58#define USB_DEBUG_VAR uhub_debug
59
60#include <dev/usb/usb_core.h>
61#include <dev/usb/usb_process.h>
62#include <dev/usb/usb_device.h>
63#include <dev/usb/usb_request.h>
64#include <dev/usb/usb_debug.h>
65#include <dev/usb/usb_hub.h>
66#include <dev/usb/usb_util.h>
67#include <dev/usb/usb_busdma.h>
68#include <dev/usb/usb_transfer.h>
69#include <dev/usb/usb_dynamic.h>
70
71#include <dev/usb/usb_controller.h>
72#include <dev/usb/usb_bus.h>
73
74#define UHUB_INTR_INTERVAL 250          /* ms */
75enum {
76        UHUB_INTR_TRANSFER,
77#if USB_HAVE_TT_SUPPORT
78        UHUB_RESET_TT_TRANSFER,
79#endif
80        UHUB_N_TRANSFER,
81};
82
83#ifdef USB_DEBUG
84static int uhub_debug = 0;
85
86static SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB");
87SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &uhub_debug, 0,
88    "Debug level");
89TUNABLE_INT("hw.usb.uhub.debug", &uhub_debug);
90#endif
91
92#if USB_HAVE_POWERD
93static int usb_power_timeout = 30;      /* seconds */
94
95SYSCTL_INT(_hw_usb, OID_AUTO, power_timeout, CTLFLAG_RW,
96    &usb_power_timeout, 0, "USB power timeout");
97#endif
98
99struct uhub_current_state {
100        uint16_t port_change;
101        uint16_t port_status;
102};
103
104struct uhub_softc {
105        struct uhub_current_state sc_st;/* current state */
106        device_t sc_dev;                /* base device */
107        struct mtx sc_mtx;              /* our mutex */
108        struct usb_device *sc_udev;     /* USB device */
109        struct usb_xfer *sc_xfer[UHUB_N_TRANSFER];      /* interrupt xfer */
110        uint8_t sc_flags;
111#define UHUB_FLAG_DID_EXPLORE 0x01
112        char    sc_name[32];
113};
114
115#define UHUB_PROTO(sc) ((sc)->sc_udev->ddesc.bDeviceProtocol)
116#define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB)
117#define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT)
118#define UHUB_IS_MULTI_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBMTT)
119#define UHUB_IS_SUPER_SPEED(sc) (UHUB_PROTO(sc) == UDPROTO_SSHUB)
120
121/* prototypes for type checking: */
122
123static device_probe_t uhub_probe;
124static device_attach_t uhub_attach;
125static device_detach_t uhub_detach;
126static device_suspend_t uhub_suspend;
127static device_resume_t uhub_resume;
128
129static bus_driver_added_t uhub_driver_added;
130static bus_child_location_str_t uhub_child_location_string;
131static bus_child_pnpinfo_str_t uhub_child_pnpinfo_string;
132
133static usb_callback_t uhub_intr_callback;
134#if USB_HAVE_TT_SUPPORT
135static usb_callback_t uhub_reset_tt_callback;
136#endif
137
138static void usb_dev_resume_peer(struct usb_device *udev);
139static void usb_dev_suspend_peer(struct usb_device *udev);
140static uint8_t usb_peer_should_wakeup(struct usb_device *udev);
141
142static const struct usb_config uhub_config[UHUB_N_TRANSFER] = {
143
144        [UHUB_INTR_TRANSFER] = {
145                .type = UE_INTERRUPT,
146                .endpoint = UE_ADDR_ANY,
147                .direction = UE_DIR_ANY,
148                .timeout = 0,
149                .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
150                .bufsize = 0,   /* use wMaxPacketSize */
151                .callback = &uhub_intr_callback,
152                .interval = UHUB_INTR_INTERVAL,
153        },
154#if USB_HAVE_TT_SUPPORT
155        [UHUB_RESET_TT_TRANSFER] = {
156                .type = UE_CONTROL,
157                .endpoint = 0x00,       /* Control pipe */
158                .direction = UE_DIR_ANY,
159                .bufsize = sizeof(struct usb_device_request),
160                .callback = &uhub_reset_tt_callback,
161                .timeout = 1000,        /* 1 second */
162                .usb_mode = USB_MODE_HOST,
163        },
164#endif
165};
166
167/*
168 * driver instance for "hub" connected to "usb"
169 * and "hub" connected to "hub"
170 */
171static devclass_t uhub_devclass;
172
173static device_method_t uhub_methods[] = {
174        DEVMETHOD(device_probe, uhub_probe),
175        DEVMETHOD(device_attach, uhub_attach),
176        DEVMETHOD(device_detach, uhub_detach),
177
178        DEVMETHOD(device_suspend, uhub_suspend),
179        DEVMETHOD(device_resume, uhub_resume),
180
181        DEVMETHOD(bus_child_location_str, uhub_child_location_string),
182        DEVMETHOD(bus_child_pnpinfo_str, uhub_child_pnpinfo_string),
183        DEVMETHOD(bus_driver_added, uhub_driver_added),
184        {0, 0}
185};
186
187static driver_t uhub_driver = {
188        .name = "uhub",
189        .methods = uhub_methods,
190        .size = sizeof(struct uhub_softc)
191};
192
193DRIVER_MODULE(uhub, usbus, uhub_driver, uhub_devclass, 0, 0);
194DRIVER_MODULE(uhub, uhub, uhub_driver, uhub_devclass, NULL, 0);
195MODULE_VERSION(uhub, 1);
196
197static void
198uhub_intr_callback(struct usb_xfer *xfer, usb_error_t error)
199{
200        struct uhub_softc *sc = usbd_xfer_softc(xfer);
201
202        switch (USB_GET_STATE(xfer)) {
203        case USB_ST_TRANSFERRED:
204                DPRINTFN(2, "\n");
205                /*
206                 * This is an indication that some port
207                 * has changed status. Notify the bus
208                 * event handler thread that we need
209                 * to be explored again:
210                 */
211                usb_needs_explore(sc->sc_udev->bus, 0);
212
213        case USB_ST_SETUP:
214                usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
215                usbd_transfer_submit(xfer);
216                break;
217
218        default:                        /* Error */
219                if (xfer->error != USB_ERR_CANCELLED) {
220                        /*
221                         * Do a clear-stall. The "stall_pipe" flag
222                         * will get cleared before next callback by
223                         * the USB stack.
224                         */
225                        usbd_xfer_set_stall(xfer);
226                        usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
227                        usbd_transfer_submit(xfer);
228                }
229                break;
230        }
231}
232
233/*------------------------------------------------------------------------*
234 *      uhub_reset_tt_proc
235 *
236 * This function starts the TT reset USB request
237 *------------------------------------------------------------------------*/
238#if USB_HAVE_TT_SUPPORT
239static void
240uhub_reset_tt_proc(struct usb_proc_msg *_pm)
241{
242        struct usb_udev_msg *pm = (void *)_pm;
243        struct usb_device *udev = pm->udev;
244        struct usb_hub *hub;
245        struct uhub_softc *sc;
246
247        hub = udev->hub;
248        if (hub == NULL)
249                return;
250        sc = hub->hubsoftc;
251        if (sc == NULL)
252                return;
253
254        /* Change lock */
255        USB_BUS_UNLOCK(udev->bus);
256        mtx_lock(&sc->sc_mtx);
257        /* Start transfer */
258        usbd_transfer_start(sc->sc_xfer[UHUB_RESET_TT_TRANSFER]);
259        /* Change lock */
260        mtx_unlock(&sc->sc_mtx);
261        USB_BUS_LOCK(udev->bus);
262}
263#endif
264
265/*------------------------------------------------------------------------*
266 *      uhub_tt_buffer_reset_async_locked
267 *
268 * This function queues a TT reset for the given USB device and endpoint.
269 *------------------------------------------------------------------------*/
270#if USB_HAVE_TT_SUPPORT
271void
272uhub_tt_buffer_reset_async_locked(struct usb_device *child, struct usb_endpoint *ep)
273{
274        struct usb_device_request req;
275        struct usb_device *udev;
276        struct usb_hub *hub;
277        struct usb_port *up;
278        uint16_t wValue;
279        uint8_t port;
280
281        if (child == NULL || ep == NULL)
282                return;
283
284        udev = child->parent_hs_hub;
285        port = child->hs_port_no;
286
287        if (udev == NULL)
288                return;
289
290        hub = udev->hub;
291        if ((hub == NULL) ||
292            (udev->speed != USB_SPEED_HIGH) ||
293            (child->speed != USB_SPEED_LOW &&
294             child->speed != USB_SPEED_FULL) ||
295            (child->flags.usb_mode != USB_MODE_HOST) ||
296            (port == 0) || (ep->edesc == NULL)) {
297                /* not applicable */
298                return;
299        }
300
301        USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
302
303        up = hub->ports + port - 1;
304
305        if (udev->ddesc.bDeviceClass == UDCLASS_HUB &&
306            udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT)
307                port = 1;
308
309        /* if we already received a clear buffer request, reset the whole TT */
310        if (up->req_reset_tt.bRequest != 0) {
311                req.bmRequestType = UT_WRITE_CLASS_OTHER;
312                req.bRequest = UR_RESET_TT;
313                USETW(req.wValue, 0);
314                req.wIndex[0] = port;
315                req.wIndex[1] = 0;
316                USETW(req.wLength, 0);
317        } else {
318                wValue = (ep->edesc->bEndpointAddress & 0xF) |
319                      ((child->address & 0x7F) << 4) |
320                      ((ep->edesc->bEndpointAddress & 0x80) << 8) |
321                      ((ep->edesc->bmAttributes & 3) << 12);
322
323                req.bmRequestType = UT_WRITE_CLASS_OTHER;
324                req.bRequest = UR_CLEAR_TT_BUFFER;
325                USETW(req.wValue, wValue);
326                req.wIndex[0] = port;
327                req.wIndex[1] = 0;
328                USETW(req.wLength, 0);
329        }
330        up->req_reset_tt = req;
331        /* get reset transfer started */
332        usb_proc_msignal(&udev->bus->non_giant_callback_proc,
333            &hub->tt_msg[0], &hub->tt_msg[1]);
334}
335#endif
336
337#if USB_HAVE_TT_SUPPORT
338static void
339uhub_reset_tt_callback(struct usb_xfer *xfer, usb_error_t error)
340{
341        struct uhub_softc *sc;
342        struct usb_device *udev;
343        struct usb_port *up;
344        uint8_t x;
345
346        DPRINTF("TT buffer reset\n");
347
348        sc = usbd_xfer_softc(xfer);
349        udev = sc->sc_udev;
350
351        switch (USB_GET_STATE(xfer)) {
352        case USB_ST_TRANSFERRED:
353        case USB_ST_SETUP:
354tr_setup:
355                USB_BUS_LOCK(udev->bus);
356                /* find first port which needs a TT reset */
357                for (x = 0; x != udev->hub->nports; x++) {
358                        up = udev->hub->ports + x;
359
360                        if (up->req_reset_tt.bRequest == 0)
361                                continue;
362
363                        /* copy in the transfer */
364                        usbd_copy_in(xfer->frbuffers, 0, &up->req_reset_tt,
365                            sizeof(up->req_reset_tt));
366                        /* reset buffer */
367                        memset(&up->req_reset_tt, 0, sizeof(up->req_reset_tt));
368
369                        /* set length */
370                        usbd_xfer_set_frame_len(xfer, 0, sizeof(up->req_reset_tt));
371                        xfer->nframes = 1;
372                        USB_BUS_UNLOCK(udev->bus);
373
374                        usbd_transfer_submit(xfer);
375                        return;
376                }
377                USB_BUS_UNLOCK(udev->bus);
378                break;
379
380        default:
381                if (error == USB_ERR_CANCELLED)
382                        break;
383
384                DPRINTF("TT buffer reset failed (%s)\n", usbd_errstr(error));
385                goto tr_setup;
386        }
387}
388#endif
389
390/*------------------------------------------------------------------------*
391 *      uhub_count_active_host_ports
392 *
393 * This function counts the number of active ports at the given speed.
394 *------------------------------------------------------------------------*/
395uint8_t
396uhub_count_active_host_ports(struct usb_device *udev, enum usb_dev_speed speed)
397{
398        struct uhub_softc *sc;
399        struct usb_device *child;
400        struct usb_hub *hub;
401        struct usb_port *up;
402        uint8_t retval = 0;
403        uint8_t x;
404
405        if (udev == NULL)
406                goto done;
407        hub = udev->hub;
408        if (hub == NULL)
409                goto done;
410        sc = hub->hubsoftc;
411        if (sc == NULL)
412                goto done;
413
414        for (x = 0; x != hub->nports; x++) {
415                up = hub->ports + x;
416                child = usb_bus_port_get_device(udev->bus, up);
417                if (child != NULL &&
418                    child->flags.usb_mode == USB_MODE_HOST &&
419                    child->speed == speed)
420                        retval++;
421        }
422done:
423        return (retval);
424}
425
426void
427uhub_explore_handle_re_enumerate(struct usb_device *child)
428{
429        uint8_t do_unlock;
430        usb_error_t err;
431
432        /* check if device should be re-enumerated */
433        if (child->flags.usb_mode != USB_MODE_HOST)
434                return;
435
436        do_unlock = usbd_enum_lock(child);
437        switch (child->re_enumerate_wait) {
438        case USB_RE_ENUM_START:
439                err = usbd_set_config_index(child,
440                    USB_UNCONFIG_INDEX);
441                if (err != 0) {
442                        DPRINTF("Unconfigure failed: %s: Ignored.\n",
443                            usbd_errstr(err));
444                }
445                if (child->parent_hub == NULL) {
446                        /* the root HUB cannot be re-enumerated */
447                        DPRINTFN(6, "cannot reset root HUB\n");
448                        err = 0;
449                } else {
450                        err = usbd_req_re_enumerate(child, NULL);
451                }
452                if (err == 0)
453                        err = usbd_set_config_index(child, 0);
454                if (err == 0) {
455                        err = usb_probe_and_attach(child,
456                            USB_IFACE_INDEX_ANY);
457                }
458                child->re_enumerate_wait = USB_RE_ENUM_DONE;
459                break;
460
461        case USB_RE_ENUM_PWR_OFF:
462                /* get the device unconfigured */
463                err = usbd_set_config_index(child,
464                    USB_UNCONFIG_INDEX);
465                if (err) {
466                        DPRINTFN(0, "Could not unconfigure "
467                            "device (ignored)\n");
468                }
469                if (child->parent_hub == NULL) {
470                        /* the root HUB cannot be re-enumerated */
471                        DPRINTFN(6, "cannot set port feature\n");
472                        err = 0;
473                } else {
474                        /* clear port enable */
475                        err = usbd_req_clear_port_feature(child->parent_hub,
476                            NULL, child->port_no, UHF_PORT_ENABLE);
477                        if (err) {
478                                DPRINTFN(0, "Could not disable port "
479                                    "(ignored)\n");
480                        }
481                }
482                child->re_enumerate_wait = USB_RE_ENUM_DONE;
483                break;
484
485        case USB_RE_ENUM_SET_CONFIG:
486                err = usbd_set_config_index(child,
487                    child->next_config_index);
488                if (err != 0) {
489                        DPRINTF("Configure failed: %s: Ignored.\n",
490                            usbd_errstr(err));
491                } else {
492                        err = usb_probe_and_attach(child,
493                            USB_IFACE_INDEX_ANY);
494                }
495                child->re_enumerate_wait = USB_RE_ENUM_DONE;
496                break;
497
498        default:
499                child->re_enumerate_wait = USB_RE_ENUM_DONE;
500                break;
501        }
502        if (do_unlock)
503                usbd_enum_unlock(child);
504}
505
506/*------------------------------------------------------------------------*
507 *      uhub_explore_sub - subroutine
508 *
509 * Return values:
510 *    0: Success
511 * Else: A control transaction failed
512 *------------------------------------------------------------------------*/
513static usb_error_t
514uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up)
515{
516        struct usb_bus *bus;
517        struct usb_device *child;
518        uint8_t refcount;
519        usb_error_t err;
520
521        bus = sc->sc_udev->bus;
522        err = 0;
523
524        /* get driver added refcount from USB bus */
525        refcount = bus->driver_added_refcount;
526
527        /* get device assosiated with the given port */
528        child = usb_bus_port_get_device(bus, up);
529        if (child == NULL) {
530                /* nothing to do */
531                goto done;
532        }
533
534        uhub_explore_handle_re_enumerate(child);
535
536        /* check if probe and attach should be done */
537
538        if (child->driver_added_refcount != refcount) {
539                child->driver_added_refcount = refcount;
540                err = usb_probe_and_attach(child,
541                    USB_IFACE_INDEX_ANY);
542                if (err) {
543                        goto done;
544                }
545        }
546        /* start control transfer, if device mode */
547
548        if (child->flags.usb_mode == USB_MODE_DEVICE)
549                usbd_ctrl_transfer_setup(child);
550
551        /* if a HUB becomes present, do a recursive HUB explore */
552
553        if (child->hub)
554                err = (child->hub->explore) (child);
555
556done:
557        return (err);
558}
559
560/*------------------------------------------------------------------------*
561 *      uhub_read_port_status - factored out code
562 *------------------------------------------------------------------------*/
563static usb_error_t
564uhub_read_port_status(struct uhub_softc *sc, uint8_t portno)
565{
566        struct usb_port_status ps;
567        usb_error_t err;
568
569        err = usbd_req_get_port_status(
570            sc->sc_udev, NULL, &ps, portno);
571
572        /* update status regardless of error */
573
574        sc->sc_st.port_status = UGETW(ps.wPortStatus);
575        sc->sc_st.port_change = UGETW(ps.wPortChange);
576
577        /* debugging print */
578
579        DPRINTFN(4, "port %d, wPortStatus=0x%04x, "
580            "wPortChange=0x%04x, err=%s\n",
581            portno, sc->sc_st.port_status,
582            sc->sc_st.port_change, usbd_errstr(err));
583        return (err);
584}
585
586/*------------------------------------------------------------------------*
587 *      uhub_reattach_port
588 *
589 * Returns:
590 *    0: Success
591 * Else: A control transaction failed
592 *------------------------------------------------------------------------*/
593static usb_error_t
594uhub_reattach_port(struct uhub_softc *sc, uint8_t portno)
595{
596        struct usb_device *child;
597        struct usb_device *udev;
598        enum usb_dev_speed speed;
599        enum usb_hc_mode mode;
600        usb_error_t err;
601        uint16_t power_mask;
602        uint8_t timeout;
603
604        DPRINTF("reattaching port %d\n", portno);
605
606        timeout = 0;
607        udev = sc->sc_udev;
608        child = usb_bus_port_get_device(udev->bus,
609            udev->hub->ports + portno - 1);
610
611repeat:
612
613        /* first clear the port connection change bit */
614
615        err = usbd_req_clear_port_feature(udev, NULL,
616            portno, UHF_C_PORT_CONNECTION);
617
618        if (err) {
619                goto error;
620        }
621        /* check if there is a child */
622
623        if (child != NULL) {
624                /*
625                 * Free USB device and all subdevices, if any.
626                 */
627                usb_free_device(child, 0);
628                child = NULL;
629        }
630        /* get fresh status */
631
632        err = uhub_read_port_status(sc, portno);
633        if (err) {
634                goto error;
635        }
636        /* check if nothing is connected to the port */
637
638        if (!(sc->sc_st.port_status & UPS_CURRENT_CONNECT_STATUS)) {
639                goto error;
640        }
641        /* check if there is no power on the port and print a warning */
642
643        switch (udev->speed) {
644        case USB_SPEED_HIGH:
645        case USB_SPEED_FULL:
646        case USB_SPEED_LOW:
647                power_mask = UPS_PORT_POWER;
648                break;
649        case USB_SPEED_SUPER:
650                if (udev->parent_hub == NULL)
651                        power_mask = UPS_PORT_POWER;
652                else
653                        power_mask = UPS_PORT_POWER_SS;
654                break;
655        default:
656                power_mask = 0;
657                break;
658        }
659        if (!(sc->sc_st.port_status & power_mask)) {
660                DPRINTF("WARNING: strange, connected port %d "
661                    "has no power\n", portno);
662        }
663
664        /* check if the device is in Host Mode */
665
666        if (!(sc->sc_st.port_status & UPS_PORT_MODE_DEVICE)) {
667
668                DPRINTF("Port %d is in Host Mode\n", portno);
669
670                if (sc->sc_st.port_status & UPS_SUSPEND) {
671                        /*
672                         * NOTE: Should not get here in SuperSpeed
673                         * mode, because the HUB should report this
674                         * bit as zero.
675                         */
676                        DPRINTF("Port %d was still "
677                            "suspended, clearing.\n", portno);
678                        err = usbd_req_clear_port_feature(udev,
679                            NULL, portno, UHF_PORT_SUSPEND);
680                }
681
682                /* USB Host Mode */
683
684                /* wait for maximum device power up time */
685
686                usb_pause_mtx(NULL,
687                    USB_MS_TO_TICKS(usb_port_powerup_delay));
688
689                /* reset port, which implies enabling it */
690
691                err = usbd_req_reset_port(udev, NULL, portno);
692
693                if (err) {
694                        DPRINTFN(0, "port %d reset "
695                            "failed, error=%s\n",
696                            portno, usbd_errstr(err));
697                        goto error;
698                }
699                /* get port status again, it might have changed during reset */
700
701                err = uhub_read_port_status(sc, portno);
702                if (err) {
703                        goto error;
704                }
705                /* check if something changed during port reset */
706
707                if ((sc->sc_st.port_change & UPS_C_CONNECT_STATUS) ||
708                    (!(sc->sc_st.port_status & UPS_CURRENT_CONNECT_STATUS))) {
709                        if (timeout) {
710                                DPRINTFN(0, "giving up port reset "
711                                    "- device vanished\n");
712                                goto error;
713                        }
714                        timeout = 1;
715                        goto repeat;
716                }
717        } else {
718                DPRINTF("Port %d is in Device Mode\n", portno);
719        }
720
721        /*
722         * Figure out the device speed
723         */
724        switch (udev->speed) {
725        case USB_SPEED_HIGH:
726                if (sc->sc_st.port_status & UPS_HIGH_SPEED)
727                        speed = USB_SPEED_HIGH;
728                else if (sc->sc_st.port_status & UPS_LOW_SPEED)
729                        speed = USB_SPEED_LOW;
730                else
731                        speed = USB_SPEED_FULL;
732                break;
733        case USB_SPEED_FULL:
734                if (sc->sc_st.port_status & UPS_LOW_SPEED)
735                        speed = USB_SPEED_LOW;
736                else
737                        speed = USB_SPEED_FULL;
738                break;
739        case USB_SPEED_LOW:
740                speed = USB_SPEED_LOW;
741                break;
742        case USB_SPEED_SUPER:
743                if (udev->parent_hub == NULL) {
744                        /* Root HUB - special case */
745                        switch (sc->sc_st.port_status & UPS_OTHER_SPEED) {
746                        case 0:
747                                speed = USB_SPEED_FULL;
748                                break;
749                        case UPS_LOW_SPEED:
750                                speed = USB_SPEED_LOW;
751                                break;
752                        case UPS_HIGH_SPEED:
753                                speed = USB_SPEED_HIGH;
754                                break;
755                        default:
756                                speed = USB_SPEED_SUPER;
757                                break;
758                        }
759                } else {
760                        speed = USB_SPEED_SUPER;
761                }
762                break;
763        default:
764                /* same speed like parent */
765                speed = udev->speed;
766                break;
767        }
768        if (speed == USB_SPEED_SUPER) {
769                err = usbd_req_set_hub_u1_timeout(udev, NULL,
770                    portno, 128 - (2 * udev->depth));
771                if (err) {
772                        DPRINTFN(0, "port %d U1 timeout "
773                            "failed, error=%s\n",
774                            portno, usbd_errstr(err));
775                }
776                err = usbd_req_set_hub_u2_timeout(udev, NULL,
777                    portno, 128 - (2 * udev->depth));
778                if (err) {
779                        DPRINTFN(0, "port %d U2 timeout "
780                            "failed, error=%s\n",
781                            portno, usbd_errstr(err));
782                }
783        }
784
785        /*
786         * Figure out the device mode
787         *
788         * NOTE: This part is currently FreeBSD specific.
789         */
790        if (udev->parent_hub != NULL) {
791                /* inherit mode from the parent HUB */
792                mode = udev->parent_hub->flags.usb_mode;
793        } else if (sc->sc_st.port_status & UPS_PORT_MODE_DEVICE)
794                mode = USB_MODE_DEVICE;
795        else
796                mode = USB_MODE_HOST;
797
798        /* need to create a new child */
799        child = usb_alloc_device(sc->sc_dev, udev->bus, udev,
800            udev->depth + 1, portno - 1, portno, speed, mode);
801        if (child == NULL) {
802                DPRINTFN(0, "could not allocate new device\n");
803                goto error;
804        }
805        return (0);                     /* success */
806
807error:
808        if (child != NULL) {
809                /*
810                 * Free USB device and all subdevices, if any.
811                 */
812                usb_free_device(child, 0);
813                child = NULL;
814        }
815        if (err == 0) {
816                if (sc->sc_st.port_status & UPS_PORT_ENABLED) {
817                        err = usbd_req_clear_port_feature(
818                            sc->sc_udev, NULL,
819                            portno, UHF_PORT_ENABLE);
820                }
821        }
822        if (err) {
823                DPRINTFN(0, "device problem (%s), "
824                    "disabling port %d\n", usbd_errstr(err), portno);
825        }
826        return (err);
827}
828
829/*------------------------------------------------------------------------*
830 *      usb_device_20_compatible
831 *
832 * Returns:
833 *    0: HUB does not support suspend and resume
834 * Else: HUB supports suspend and resume
835 *------------------------------------------------------------------------*/
836static uint8_t
837usb_device_20_compatible(struct usb_device *udev)
838{
839        if (udev == NULL)
840                return (0);
841        switch (udev->speed) {
842        case USB_SPEED_LOW:
843        case USB_SPEED_FULL:
844        case USB_SPEED_HIGH:
845                return (1);
846        default:
847                return (0);
848        }
849}
850
851/*------------------------------------------------------------------------*
852 *      uhub_suspend_resume_port
853 *
854 * Returns:
855 *    0: Success
856 * Else: A control transaction failed
857 *------------------------------------------------------------------------*/
858static usb_error_t
859uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno)
860{
861        struct usb_device *child;
862        struct usb_device *udev;
863        uint8_t is_suspend;
864        usb_error_t err;
865
866        DPRINTF("port %d\n", portno);
867
868        udev = sc->sc_udev;
869        child = usb_bus_port_get_device(udev->bus,
870            udev->hub->ports + portno - 1);
871
872        /* first clear the port suspend change bit */
873
874        if (usb_device_20_compatible(udev)) {
875                err = usbd_req_clear_port_feature(udev, NULL,
876                    portno, UHF_C_PORT_SUSPEND);
877        } else {
878                err = usbd_req_clear_port_feature(udev, NULL,
879                    portno, UHF_C_PORT_LINK_STATE);
880        }
881
882        if (err) {
883                DPRINTF("clearing suspend failed.\n");
884                goto done;
885        }
886        /* get fresh status */
887
888        err = uhub_read_port_status(sc, portno);
889        if (err) {
890                DPRINTF("reading port status failed.\n");
891                goto done;
892        }
893        /* convert current state */
894
895        if (usb_device_20_compatible(udev)) {
896                if (sc->sc_st.port_status & UPS_SUSPEND) {
897                        is_suspend = 1;
898                } else {
899                        is_suspend = 0;
900                }
901        } else {
902                switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) {
903                case UPS_PORT_LS_U3:
904                        is_suspend = 1;
905                        break;
906                case UPS_PORT_LS_SS_INA:
907                        usbd_req_warm_reset_port(udev, NULL, portno);
908                        is_suspend = 0;
909                        break;
910                default:
911                        is_suspend = 0;
912                        break;
913                }
914        }
915
916        DPRINTF("suspended=%u\n", is_suspend);
917
918        /* do the suspend or resume */
919
920        if (child) {
921                /*
922                 * This code handle two cases: 1) Host Mode - we can only
923                 * receive resume here 2) Device Mode - we can receive
924                 * suspend and resume here
925                 */
926                if (is_suspend == 0)
927                        usb_dev_resume_peer(child);
928                else if (child->flags.usb_mode == USB_MODE_DEVICE)
929                        usb_dev_suspend_peer(child);
930        }
931done:
932        return (err);
933}
934
935/*------------------------------------------------------------------------*
936 *      uhub_root_interrupt
937 *
938 * This function is called when a Root HUB interrupt has
939 * happened. "ptr" and "len" makes up the Root HUB interrupt
940 * packet. This function is called having the "bus_mtx" locked.
941 *------------------------------------------------------------------------*/
942void
943uhub_root_intr(struct usb_bus *bus, const uint8_t *ptr, uint8_t len)
944{
945        USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
946
947        usb_needs_explore(bus, 0);
948}
949
950static uint8_t
951uhub_is_too_deep(struct usb_device *udev)
952{
953        switch (udev->speed) {
954        case USB_SPEED_FULL:
955        case USB_SPEED_LOW:
956        case USB_SPEED_HIGH:
957                if (udev->depth > USB_HUB_MAX_DEPTH)
958                        return (1);
959                break;
960        case USB_SPEED_SUPER:
961                if (udev->depth > USB_SS_HUB_DEPTH_MAX)
962                        return (1);
963                break;
964        default:
965                break;
966        }
967        return (0);
968}
969
970/*------------------------------------------------------------------------*
971 *      uhub_explore
972 *
973 * Returns:
974 *     0: Success
975 *  Else: Failure
976 *------------------------------------------------------------------------*/
977static usb_error_t
978uhub_explore(struct usb_device *udev)
979{
980        struct usb_hub *hub;
981        struct uhub_softc *sc;
982        struct usb_port *up;
983        usb_error_t err;
984        uint8_t portno;
985        uint8_t x;
986        uint8_t do_unlock;
987
988        hub = udev->hub;
989        sc = hub->hubsoftc;
990
991        DPRINTFN(11, "udev=%p addr=%d\n", udev, udev->address);
992
993        /* ignore devices that are too deep */
994        if (uhub_is_too_deep(udev))
995                return (USB_ERR_TOO_DEEP);
996
997        /* check if device is suspended */
998        if (udev->flags.self_suspended) {
999                /* need to wait until the child signals resume */
1000                DPRINTF("Device is suspended!\n");
1001                return (0);
1002        }
1003
1004        /*
1005         * Make sure we don't race against user-space applications
1006         * like LibUSB:
1007         */
1008        do_unlock = usbd_enum_lock(udev);
1009
1010        for (x = 0; x != hub->nports; x++) {
1011                up = hub->ports + x;
1012                portno = x + 1;
1013
1014                err = uhub_read_port_status(sc, portno);
1015                if (err) {
1016                        /* most likely the HUB is gone */
1017                        break;
1018                }
1019                if (sc->sc_st.port_change & UPS_C_OVERCURRENT_INDICATOR) {
1020                        DPRINTF("Overcurrent on port %u.\n", portno);
1021                        err = usbd_req_clear_port_feature(
1022                            udev, NULL, portno, UHF_C_PORT_OVER_CURRENT);
1023                        if (err) {
1024                                /* most likely the HUB is gone */
1025                                break;
1026                        }
1027                }
1028                if (!(sc->sc_flags & UHUB_FLAG_DID_EXPLORE)) {
1029                        /*
1030                         * Fake a connect status change so that the
1031                         * status gets checked initially!
1032                         */
1033                        sc->sc_st.port_change |=
1034                            UPS_C_CONNECT_STATUS;
1035                }
1036                if (sc->sc_st.port_change & UPS_C_PORT_ENABLED) {
1037                        err = usbd_req_clear_port_feature(
1038                            udev, NULL, portno, UHF_C_PORT_ENABLE);
1039                        if (err) {
1040                                /* most likely the HUB is gone */
1041                                break;
1042                        }
1043                        if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) {
1044                                /*
1045                                 * Ignore the port error if the device
1046                                 * has vanished !
1047                                 */
1048                        } else if (sc->sc_st.port_status & UPS_PORT_ENABLED) {
1049                                DPRINTFN(0, "illegal enable change, "
1050                                    "port %d\n", portno);
1051                        } else {
1052
1053                                if (up->restartcnt == USB_RESTART_MAX) {
1054                                        /* XXX could try another speed ? */
1055                                        DPRINTFN(0, "port error, giving up "
1056                                            "port %d\n", portno);
1057                                } else {
1058                                        sc->sc_st.port_change |=
1059                                            UPS_C_CONNECT_STATUS;
1060                                        up->restartcnt++;
1061                                }
1062                        }
1063                }
1064                if (sc->sc_st.port_change & UPS_C_CONNECT_STATUS) {
1065                        err = uhub_reattach_port(sc, portno);
1066                        if (err) {
1067                                /* most likely the HUB is gone */
1068                                break;
1069                        }
1070                }
1071                if (sc->sc_st.port_change & (UPS_C_SUSPEND |
1072                    UPS_C_PORT_LINK_STATE)) {
1073                        err = uhub_suspend_resume_port(sc, portno);
1074                        if (err) {
1075                                /* most likely the HUB is gone */
1076                                break;
1077                        }
1078                }
1079                err = uhub_explore_sub(sc, up);
1080                if (err) {
1081                        /* no device(s) present */
1082                        continue;
1083                }
1084                /* explore succeeded - reset restart counter */
1085                up->restartcnt = 0;
1086        }
1087
1088        if (do_unlock)
1089                usbd_enum_unlock(udev);
1090
1091        /* initial status checked */
1092        sc->sc_flags |= UHUB_FLAG_DID_EXPLORE;
1093
1094        /* return success */
1095        return (USB_ERR_NORMAL_COMPLETION);
1096}
1097
1098static int
1099uhub_probe(device_t dev)
1100{
1101        struct usb_attach_arg *uaa = device_get_ivars(dev);
1102
1103        if (uaa->usb_mode != USB_MODE_HOST)
1104                return (ENXIO);
1105
1106        /*
1107         * The subclass for USB HUBs is currently ignored because it
1108         * is 0 for some and 1 for others.
1109         */
1110        if (uaa->info.bConfigIndex == 0 &&
1111            uaa->info.bDeviceClass == UDCLASS_HUB)
1112                return (0);
1113
1114        return (ENXIO);
1115}
1116
1117/* NOTE: The information returned by this function can be wrong. */
1118usb_error_t
1119uhub_query_info(struct usb_device *udev, uint8_t *pnports, uint8_t *ptt)
1120{
1121        struct usb_hub_descriptor hubdesc20;
1122        struct usb_hub_ss_descriptor hubdesc30;
1123        usb_error_t err;
1124        uint8_t nports;
1125        uint8_t tt;
1126
1127        if (udev->ddesc.bDeviceClass != UDCLASS_HUB)
1128                return (USB_ERR_INVAL);
1129
1130        nports = 0;
1131        tt = 0;
1132
1133        switch (udev->speed) {
1134        case USB_SPEED_LOW:
1135        case USB_SPEED_FULL:
1136        case USB_SPEED_HIGH:
1137                /* assuming that there is one port */
1138                err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1);
1139                if (err) {
1140                        DPRINTFN(0, "getting USB 2.0 HUB descriptor failed,"
1141                            "error=%s\n", usbd_errstr(err));
1142                        break;
1143                }
1144                nports = hubdesc20.bNbrPorts;
1145                if (nports > 127)
1146                        nports = 127;
1147
1148                if (udev->speed == USB_SPEED_HIGH)
1149                        tt = (UGETW(hubdesc20.wHubCharacteristics) >> 5) & 3;
1150                break;
1151
1152        case USB_SPEED_SUPER:
1153                err = usbd_req_get_ss_hub_descriptor(udev, NULL, &hubdesc30, 1);
1154                if (err) {
1155                        DPRINTFN(0, "Getting USB 3.0 HUB descriptor failed,"
1156                            "error=%s\n", usbd_errstr(err));
1157                        break;
1158                }
1159                nports = hubdesc30.bNbrPorts;
1160                if (nports > 16)
1161                        nports = 16;
1162                break;
1163
1164        default:
1165                err = USB_ERR_INVAL;
1166                break;
1167        }
1168
1169        if (pnports != NULL)
1170                *pnports = nports;
1171
1172        if (ptt != NULL)
1173                *ptt = tt;
1174
1175        return (err);
1176}
1177
1178static int
1179uhub_attach(device_t dev)
1180{
1181        struct uhub_softc *sc = device_get_softc(dev);
1182        struct usb_attach_arg *uaa = device_get_ivars(dev);
1183        struct usb_device *udev = uaa->device;
1184        struct usb_device *parent_hub = udev->parent_hub;
1185        struct usb_hub *hub;
1186        struct usb_hub_descriptor hubdesc20;
1187        struct usb_hub_ss_descriptor hubdesc30;
1188        uint16_t pwrdly;
1189        uint8_t x;
1190        uint8_t nports;
1191        uint8_t portno;
1192        uint8_t removable;
1193        uint8_t iface_index;
1194        usb_error_t err;
1195
1196        sc->sc_udev = udev;
1197        sc->sc_dev = dev;
1198
1199        mtx_init(&sc->sc_mtx, "USB HUB mutex", NULL, MTX_DEF);
1200
1201        snprintf(sc->sc_name, sizeof(sc->sc_name), "%s",
1202            device_get_nameunit(dev));
1203
1204        device_set_usb_desc(dev);
1205
1206        DPRINTFN(2, "depth=%d selfpowered=%d, parent=%p, "
1207            "parent->selfpowered=%d\n",
1208            udev->depth,
1209            udev->flags.self_powered,
1210            parent_hub,
1211            parent_hub ?
1212            parent_hub->flags.self_powered : 0);
1213
1214        if (uhub_is_too_deep(udev)) {
1215                DPRINTFN(0, "HUB at depth %d, "
1216                    "exceeds maximum. HUB ignored\n", (int)udev->depth);
1217                goto error;
1218        }
1219
1220        if (!udev->flags.self_powered && parent_hub &&
1221            !parent_hub->flags.self_powered) {
1222                DPRINTFN(0, "Bus powered HUB connected to "
1223                    "bus powered HUB. HUB ignored\n");
1224                goto error;
1225        }
1226
1227        if (UHUB_IS_MULTI_TT(sc)) {
1228                err = usbd_set_alt_interface_index(udev, 0, 1);
1229                if (err) {
1230                        device_printf(dev, "MTT could not be enabled\n");
1231                        goto error;
1232                }
1233                device_printf(dev, "MTT enabled\n");
1234        }
1235
1236        /* get HUB descriptor */
1237
1238        DPRINTFN(2, "Getting HUB descriptor\n");
1239
1240        switch (udev->speed) {
1241        case USB_SPEED_LOW:
1242        case USB_SPEED_FULL:
1243        case USB_SPEED_HIGH:
1244                /* assuming that there is one port */
1245                err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, 1);
1246                if (err) {
1247                        DPRINTFN(0, "getting USB 2.0 HUB descriptor failed,"
1248                            "error=%s\n", usbd_errstr(err));
1249                        goto error;
1250                }
1251                /* get number of ports */
1252                nports = hubdesc20.bNbrPorts;
1253
1254                /* get power delay */
1255                pwrdly = ((hubdesc20.bPwrOn2PwrGood * UHD_PWRON_FACTOR) +
1256                    usb_extra_power_up_time);
1257
1258                /* get complete HUB descriptor */
1259                if (nports >= 8) {
1260                        /* check number of ports */
1261                        if (nports > 127) {
1262                                DPRINTFN(0, "Invalid number of USB 2.0 ports,"
1263                                    "error=%s\n", usbd_errstr(err));
1264                                goto error;
1265                        }
1266                        /* get complete HUB descriptor */
1267                        err = usbd_req_get_hub_descriptor(udev, NULL, &hubdesc20, nports);
1268
1269                        if (err) {
1270                                DPRINTFN(0, "Getting USB 2.0 HUB descriptor failed,"
1271                                    "error=%s\n", usbd_errstr(err));
1272                                goto error;
1273                        }
1274                        if (hubdesc20.bNbrPorts != nports) {
1275                                DPRINTFN(0, "Number of ports changed\n");
1276                                goto error;
1277                        }
1278                }
1279                break;
1280        case USB_SPEED_SUPER:
1281                if (udev->parent_hub != NULL) {
1282                        err = usbd_req_set_hub_depth(udev, NULL,
1283                            udev->depth - 1);
1284                        if (err) {
1285                                DPRINTFN(0, "Setting USB 3.0 HUB depth failed,"
1286                                    "error=%s\n", usbd_errstr(err));
1287                                goto error;
1288                        }
1289                }
1290                err = usbd_req_get_ss_hub_descriptor(udev, NULL, &hubdesc30, 1);
1291                if (err) {
1292                        DPRINTFN(0, "Getting USB 3.0 HUB descriptor failed,"
1293                            "error=%s\n", usbd_errstr(err));
1294                        goto error;
1295                }
1296                /* get number of ports */
1297                nports = hubdesc30.bNbrPorts;
1298
1299                /* get power delay */
1300                pwrdly = ((hubdesc30.bPwrOn2PwrGood * UHD_PWRON_FACTOR) +
1301                    usb_extra_power_up_time);
1302
1303                /* get complete HUB descriptor */
1304                if (nports >= 8) {
1305                        /* check number of ports */
1306                        if (nports > ((udev->parent_hub != NULL) ? 15 : 127)) {
1307                                DPRINTFN(0, "Invalid number of USB 3.0 ports,"
1308                                    "error=%s\n", usbd_errstr(err));
1309                                goto error;
1310                        }
1311                        /* get complete HUB descriptor */
1312                        err = usbd_req_get_ss_hub_descriptor(udev, NULL, &hubdesc30, nports);
1313
1314                        if (err) {
1315                                DPRINTFN(0, "Getting USB 2.0 HUB descriptor failed,"
1316                                    "error=%s\n", usbd_errstr(err));
1317                                goto error;
1318                        }
1319                        if (hubdesc30.bNbrPorts != nports) {
1320                                DPRINTFN(0, "Number of ports changed\n");
1321                                goto error;
1322                        }
1323                }
1324                break;
1325        default:
1326                DPRINTF("Assuming HUB has only one port\n");
1327                /* default number of ports */
1328                nports = 1;
1329                /* default power delay */
1330                pwrdly = ((10 * UHD_PWRON_FACTOR) + usb_extra_power_up_time);
1331                break;
1332        }
1333        if (nports == 0) {
1334                DPRINTFN(0, "portless HUB\n");
1335                goto error;
1336        }
1337        hub = malloc(sizeof(hub[0]) + (sizeof(hub->ports[0]) * nports),
1338            M_USBDEV, M_WAITOK | M_ZERO);
1339
1340        if (hub == NULL) {
1341                goto error;
1342        }
1343        udev->hub = hub;
1344
1345        /* initialize HUB structure */
1346        hub->hubsoftc = sc;
1347        hub->explore = &uhub_explore;
1348        hub->nports = nports;
1349        hub->hubudev = udev;
1350#if USB_HAVE_TT_SUPPORT
1351        hub->tt_msg[0].hdr.pm_callback = &uhub_reset_tt_proc;
1352        hub->tt_msg[0].udev = udev;
1353        hub->tt_msg[1].hdr.pm_callback = &uhub_reset_tt_proc;
1354        hub->tt_msg[1].udev = udev;
1355#endif
1356        /* if self powered hub, give ports maximum current */
1357        if (udev->flags.self_powered) {
1358                hub->portpower = USB_MAX_POWER;
1359        } else {
1360                hub->portpower = USB_MIN_POWER;
1361        }
1362
1363        /* set up interrupt pipe */
1364        iface_index = 0;
1365        if (udev->parent_hub == NULL) {
1366                /* root HUB is special */
1367                err = 0;
1368        } else {
1369                /* normal HUB */
1370                err = usbd_transfer_setup(udev, &iface_index, sc->sc_xfer,
1371                    uhub_config, UHUB_N_TRANSFER, sc, &sc->sc_mtx);
1372        }
1373        if (err) {
1374                DPRINTFN(0, "cannot setup interrupt transfer, "
1375                    "errstr=%s\n", usbd_errstr(err));
1376                goto error;
1377        }
1378        /* wait with power off for a while */
1379        usb_pause_mtx(NULL, USB_MS_TO_TICKS(USB_POWER_DOWN_TIME));
1380
1381        /*
1382         * To have the best chance of success we do things in the exact same
1383         * order as Windoze98.  This should not be necessary, but some
1384         * devices do not follow the USB specs to the letter.
1385         *
1386         * These are the events on the bus when a hub is attached:
1387         *  Get device and config descriptors (see attach code)
1388         *  Get hub descriptor (see above)
1389         *  For all ports
1390         *     turn on power
1391         *     wait for power to become stable
1392         * (all below happens in explore code)
1393         *  For all ports
1394         *     clear C_PORT_CONNECTION
1395         *  For all ports
1396         *     get port status
1397         *     if device connected
1398         *        wait 100 ms
1399         *        turn on reset
1400         *        wait
1401         *        clear C_PORT_RESET
1402         *        get port status
1403         *        proceed with device attachment
1404         */
1405
1406        /* XXX should check for none, individual, or ganged power? */
1407
1408        removable = 0;
1409
1410        for (x = 0; x != nports; x++) {
1411                /* set up data structures */
1412                struct usb_port *up = hub->ports + x;
1413
1414                up->device_index = 0;
1415                up->restartcnt = 0;
1416                portno = x + 1;
1417
1418                /* check if port is removable */
1419                switch (udev->speed) {
1420                case USB_SPEED_LOW:
1421                case USB_SPEED_FULL:
1422                case USB_SPEED_HIGH:
1423                        if (!UHD_NOT_REMOV(&hubdesc20, portno))
1424                                removable++;
1425                        break;
1426                case USB_SPEED_SUPER:
1427                        if (!UHD_NOT_REMOV(&hubdesc30, portno))
1428                                removable++;
1429                        break;
1430                default:
1431                        DPRINTF("Assuming removable port\n");
1432                        removable++;
1433                        break;
1434                }
1435                if (!err) {
1436                        /* turn the power on */
1437                        err = usbd_req_set_port_feature(udev, NULL,
1438                            portno, UHF_PORT_POWER);
1439                }
1440                if (err) {
1441                        DPRINTFN(0, "port %d power on failed, %s\n",
1442                            portno, usbd_errstr(err));
1443                }
1444                DPRINTF("turn on port %d power\n",
1445                    portno);
1446
1447                /* wait for stable power */
1448                usb_pause_mtx(NULL, USB_MS_TO_TICKS(pwrdly));
1449        }
1450
1451        device_printf(dev, "%d port%s with %d "
1452            "removable, %s powered\n", nports, (nports != 1) ? "s" : "",
1453            removable, udev->flags.self_powered ? "self" : "bus");
1454
1455        /* Start the interrupt endpoint, if any */
1456
1457        mtx_lock(&sc->sc_mtx);
1458        usbd_transfer_start(sc->sc_xfer[UHUB_INTR_TRANSFER]);
1459        mtx_unlock(&sc->sc_mtx);
1460
1461        /* Enable automatic power save on all USB HUBs */
1462
1463        usbd_set_power_mode(udev, USB_POWER_MODE_SAVE);
1464
1465        return (0);
1466
1467error:
1468        usbd_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER);
1469
1470        if (udev->hub) {
1471                free(udev->hub, M_USBDEV);
1472                udev->hub = NULL;
1473        }
1474
1475        mtx_destroy(&sc->sc_mtx);
1476
1477        return (ENXIO);
1478}
1479
1480/*
1481 * Called from process context when the hub is gone.
1482 * Detach all devices on active ports.
1483 */
1484static int
1485uhub_detach(device_t dev)
1486{
1487        struct uhub_softc *sc = device_get_softc(dev);
1488        struct usb_hub *hub = sc->sc_udev->hub;
1489        struct usb_bus *bus = sc->sc_udev->bus;
1490        struct usb_device *child;
1491        uint8_t x;
1492
1493        if (hub == NULL)                /* must be partially working */
1494                return (0);
1495
1496        /* Make sure interrupt transfer is gone. */
1497        usbd_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER);
1498
1499        /* Detach all ports */
1500        for (x = 0; x != hub->nports; x++) {
1501
1502                child = usb_bus_port_get_device(bus, hub->ports + x);
1503
1504                if (child == NULL) {
1505                        continue;
1506                }
1507
1508                /*
1509                 * Free USB device and all subdevices, if any.
1510                 */
1511                usb_free_device(child, 0);
1512        }
1513
1514#if USB_HAVE_TT_SUPPORT
1515        /* Make sure our TT messages are not queued anywhere */
1516        USB_BUS_LOCK(bus);
1517        usb_proc_mwait(&bus->non_giant_callback_proc,
1518            &hub->tt_msg[0], &hub->tt_msg[1]);
1519        USB_BUS_UNLOCK(bus);
1520#endif
1521        free(hub, M_USBDEV);
1522        sc->sc_udev->hub = NULL;
1523
1524        mtx_destroy(&sc->sc_mtx);
1525
1526        return (0);
1527}
1528
1529static int
1530uhub_suspend(device_t dev)
1531{
1532        DPRINTF("\n");
1533        /* Sub-devices are not suspended here! */
1534        return (0);
1535}
1536
1537static int
1538uhub_resume(device_t dev)
1539{
1540        DPRINTF("\n");
1541        /* Sub-devices are not resumed here! */
1542        return (0);
1543}
1544
1545static void
1546uhub_driver_added(device_t dev, driver_t *driver)
1547{
1548        usb_needs_explore_all();
1549}
1550
1551struct hub_result {
1552        struct usb_device *udev;
1553        uint8_t portno;
1554        uint8_t iface_index;
1555};
1556
1557static void
1558uhub_find_iface_index(struct usb_hub *hub, device_t child,
1559    struct hub_result *res)
1560{
1561        struct usb_interface *iface;
1562        struct usb_device *udev;
1563        uint8_t nports;
1564        uint8_t x;
1565        uint8_t i;
1566
1567        nports = hub->nports;
1568        for (x = 0; x != nports; x++) {
1569                udev = usb_bus_port_get_device(hub->hubudev->bus,
1570                    hub->ports + x);
1571                if (!udev) {
1572                        continue;
1573                }
1574                for (i = 0; i != USB_IFACE_MAX; i++) {
1575                        iface = usbd_get_iface(udev, i);
1576                        if (iface &&
1577                            (iface->subdev == child)) {
1578                                res->iface_index = i;
1579                                res->udev = udev;
1580                                res->portno = x + 1;
1581                                return;
1582                        }
1583                }
1584        }
1585        res->iface_index = 0;
1586        res->udev = NULL;
1587        res->portno = 0;
1588}
1589
1590static int
1591uhub_child_location_string(device_t parent, device_t child,
1592    char *buf, size_t buflen)
1593{
1594        struct uhub_softc *sc;
1595        struct usb_hub *hub;
1596        struct hub_result res;
1597        char *ugen_name;
1598
1599        if (!device_is_attached(parent)) {
1600                if (buflen)
1601                        buf[0] = 0;
1602                return (0);
1603        }
1604
1605        sc = device_get_softc(parent);
1606        hub = sc->sc_udev->hub;
1607
1608        mtx_lock(&Giant);
1609        uhub_find_iface_index(hub, child, &res);
1610        if (!res.udev) {
1611                DPRINTF("device not on hub\n");
1612                if (buflen) {
1613                        buf[0] = '\0';
1614                }
1615                goto done;
1616        }
1617#if USB_HAVE_UGEN
1618        ugen_name = res.udev->ugen_name;
1619#else
1620        ugen_name = "?";
1621#endif
1622        snprintf(buf, buflen, "bus=%u hubaddr=%u port=%u devaddr=%u interface=%u"
1623            " ugen=%s",
1624            (res.udev->parent_hub != NULL) ? res.udev->parent_hub->device_index : 0,
1625            res.portno, device_get_unit(res.udev->bus->bdev),
1626            res.udev->device_index, res.iface_index, ugen_name);
1627done:
1628        mtx_unlock(&Giant);
1629
1630        return (0);
1631}
1632
1633static int
1634uhub_child_pnpinfo_string(device_t parent, device_t child,
1635    char *buf, size_t buflen)
1636{
1637        struct uhub_softc *sc;
1638        struct usb_hub *hub;
1639        struct usb_interface *iface;
1640        struct hub_result res;
1641
1642        if (!device_is_attached(parent)) {
1643                if (buflen)
1644                        buf[0] = 0;
1645                return (0);
1646        }
1647
1648        sc = device_get_softc(parent);
1649        hub = sc->sc_udev->hub;
1650
1651        mtx_lock(&Giant);
1652        uhub_find_iface_index(hub, child, &res);
1653        if (!res.udev) {
1654                DPRINTF("device not on hub\n");
1655                if (buflen) {
1656                        buf[0] = '\0';
1657                }
1658                goto done;
1659        }
1660        iface = usbd_get_iface(res.udev, res.iface_index);
1661        if (iface && iface->idesc) {
1662                snprintf(buf, buflen, "vendor=0x%04x product=0x%04x "
1663                    "devclass=0x%02x devsubclass=0x%02x "
1664                    "sernum=\"%s\" "
1665                    "release=0x%04x "
1666                    "mode=%s "
1667                    "intclass=0x%02x intsubclass=0x%02x "
1668                    "intprotocol=0x%02x" "%s%s",
1669                    UGETW(res.udev->ddesc.idVendor),
1670                    UGETW(res.udev->ddesc.idProduct),
1671                    res.udev->ddesc.bDeviceClass,
1672                    res.udev->ddesc.bDeviceSubClass,
1673                    usb_get_serial(res.udev),
1674                    UGETW(res.udev->ddesc.bcdDevice),
1675                    (res.udev->flags.usb_mode == USB_MODE_HOST) ? "host" : "device",
1676                    iface->idesc->bInterfaceClass,
1677                    iface->idesc->bInterfaceSubClass,
1678                    iface->idesc->bInterfaceProtocol,
1679                    iface->pnpinfo ? " " : "",
1680                    iface->pnpinfo ? iface->pnpinfo : "");
1681        } else {
1682                if (buflen) {
1683                        buf[0] = '\0';
1684                }
1685                goto done;
1686        }
1687done:
1688        mtx_unlock(&Giant);
1689
1690        return (0);
1691}
1692
1693/*
1694 * The USB Transaction Translator:
1695 * ===============================
1696 *
1697 * When doing LOW- and FULL-speed USB transfers accross a HIGH-speed
1698 * USB HUB, bandwidth must be allocated for ISOCHRONOUS and INTERRUPT
1699 * USB transfers. To utilize bandwidth dynamically the "scatter and
1700 * gather" principle must be applied. This means that bandwidth must
1701 * be divided into equal parts of bandwidth. With regard to USB all
1702 * data is transferred in smaller packets with length
1703 * "wMaxPacketSize". The problem however is that "wMaxPacketSize" is
1704 * not a constant!
1705 *
1706 * The bandwidth scheduler which I have implemented will simply pack
1707 * the USB transfers back to back until there is no more space in the
1708 * schedule. Out of the 8 microframes which the USB 2.0 standard
1709 * provides, only 6 are available for non-HIGH-speed devices. I have
1710 * reserved the first 4 microframes for ISOCHRONOUS transfers. The
1711 * last 2 microframes I have reserved for INTERRUPT transfers. Without
1712 * this division, it is very difficult to allocate and free bandwidth
1713 * dynamically.
1714 *
1715 * NOTE about the Transaction Translator in USB HUBs:
1716 *
1717 * USB HUBs have a very simple Transaction Translator, that will
1718 * simply pipeline all the SPLIT transactions. That means that the
1719 * transactions will be executed in the order they are queued!
1720 *
1721 */
1722
1723/*------------------------------------------------------------------------*
1724 *      usb_intr_find_best_slot
1725 *
1726 * Return value:
1727 *   The best Transaction Translation slot for an interrupt endpoint.
1728 *------------------------------------------------------------------------*/
1729static uint8_t
1730usb_intr_find_best_slot(usb_size_t *ptr, uint8_t start,
1731    uint8_t end, uint8_t mask)
1732{
1733        usb_size_t min = (usb_size_t)-1;
1734        usb_size_t sum;
1735        uint8_t x;
1736        uint8_t y;
1737        uint8_t z;
1738
1739        y = 0;
1740
1741        /* find the last slot with lesser used bandwidth */
1742
1743        for (x = start; x < end; x++) {
1744
1745                sum = 0;
1746
1747                /* compute sum of bandwidth */
1748                for (z = x; z < end; z++) {
1749                        if (mask & (1U << (z - x)))
1750                                sum += ptr[z];
1751                }
1752
1753                /* check if the current multi-slot is more optimal */
1754                if (min >= sum) {
1755                        min = sum;
1756                        y = x;
1757                }
1758
1759                /* check if the mask is about to be shifted out */
1760                if (mask & (1U << (end - 1 - x)))
1761                        break;
1762        }
1763        return (y);
1764}
1765
1766/*------------------------------------------------------------------------*
1767 *      usb_hs_bandwidth_adjust
1768 *
1769 * This function will update the bandwith usage for the microframe
1770 * having index "slot" by "len" bytes. "len" can be negative.  If the
1771 * "slot" argument is greater or equal to "USB_HS_MICRO_FRAMES_MAX"
1772 * the "slot" argument will be replaced by the slot having least used
1773 * bandwidth. The "mask" argument is used for multi-slot allocations.
1774 *
1775 * Returns:
1776 *    The slot in which the bandwidth update was done: 0..7
1777 *------------------------------------------------------------------------*/
1778static uint8_t
1779usb_hs_bandwidth_adjust(struct usb_device *udev, int16_t len,
1780    uint8_t slot, uint8_t mask)
1781{
1782        struct usb_bus *bus = udev->bus;
1783        struct usb_hub *hub;
1784        enum usb_dev_speed speed;
1785        uint8_t x;
1786
1787        USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
1788
1789        speed = usbd_get_speed(udev);
1790
1791        switch (speed) {
1792        case USB_SPEED_LOW:
1793        case USB_SPEED_FULL:
1794                if (speed == USB_SPEED_LOW) {
1795                        len *= 8;
1796                }
1797                /*
1798                 * The Host Controller Driver should have
1799                 * performed checks so that the lookup
1800                 * below does not result in a NULL pointer
1801                 * access.
1802                 */
1803
1804                hub = udev->parent_hs_hub->hub;
1805                if (slot >= USB_HS_MICRO_FRAMES_MAX) {
1806                        slot = usb_intr_find_best_slot(hub->uframe_usage,
1807                            USB_FS_ISOC_UFRAME_MAX, 6, mask);
1808                }
1809                for (x = slot; x < 8; x++) {
1810                        if (mask & (1U << (x - slot))) {
1811                                hub->uframe_usage[x] += len;
1812                                bus->uframe_usage[x] += len;
1813                        }
1814                }
1815                break;
1816        default:
1817                if (slot >= USB_HS_MICRO_FRAMES_MAX) {
1818                        slot = usb_intr_find_best_slot(bus->uframe_usage, 0,
1819                            USB_HS_MICRO_FRAMES_MAX, mask);
1820                }
1821                for (x = slot; x < 8; x++) {
1822                        if (mask & (1U << (x - slot))) {
1823                                bus->uframe_usage[x] += len;
1824                        }
1825                }
1826                break;
1827        }
1828        return (slot);
1829}
1830
1831/*------------------------------------------------------------------------*
1832 *      usb_hs_bandwidth_alloc
1833 *
1834 * This function is a wrapper function for "usb_hs_bandwidth_adjust()".
1835 *------------------------------------------------------------------------*/
1836void
1837usb_hs_bandwidth_alloc(struct usb_xfer *xfer)
1838{
1839        struct usb_device *udev;
1840        uint8_t slot;
1841        uint8_t mask;
1842        uint8_t speed;
1843
1844        udev = xfer->xroot->udev;
1845
1846        if (udev->flags.usb_mode != USB_MODE_HOST)
1847                return;         /* not supported */
1848
1849        xfer->endpoint->refcount_bw++;
1850        if (xfer->endpoint->refcount_bw != 1)
1851                return;         /* already allocated */
1852
1853        speed = usbd_get_speed(udev);
1854
1855        switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
1856        case UE_INTERRUPT:
1857                /* allocate a microframe slot */
1858
1859                mask = 0x01;
1860                slot = usb_hs_bandwidth_adjust(udev,
1861                    xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, mask);
1862
1863                xfer->endpoint->usb_uframe = slot;
1864                xfer->endpoint->usb_smask = mask << slot;
1865
1866                if ((speed != USB_SPEED_FULL) &&
1867                    (speed != USB_SPEED_LOW)) {
1868                        xfer->endpoint->usb_cmask = 0x00 ;
1869                } else {
1870                        xfer->endpoint->usb_cmask = (-(0x04 << slot)) & 0xFE;
1871                }
1872                break;
1873
1874        case UE_ISOCHRONOUS:
1875                switch (usbd_xfer_get_fps_shift(xfer)) {
1876                case 0:
1877                        mask = 0xFF;
1878                        break;
1879                case 1:
1880                        mask = 0x55;
1881                        break;
1882                case 2:
1883                        mask = 0x11;
1884                        break;
1885                default:
1886                        mask = 0x01;
1887                        break;
1888                }
1889
1890                /* allocate a microframe multi-slot */
1891
1892                slot = usb_hs_bandwidth_adjust(udev,
1893                    xfer->max_frame_size, USB_HS_MICRO_FRAMES_MAX, mask);
1894
1895                xfer->endpoint->usb_uframe = slot;
1896                xfer->endpoint->usb_cmask = 0;
1897                xfer->endpoint->usb_smask = mask << slot;
1898                break;
1899
1900        default:
1901                xfer->endpoint->usb_uframe = 0;
1902                xfer->endpoint->usb_cmask = 0;
1903                xfer->endpoint->usb_smask = 0;
1904                break;
1905        }
1906
1907        DPRINTFN(11, "slot=%d, mask=0x%02x\n",
1908            xfer->endpoint->usb_uframe,
1909            xfer->endpoint->usb_smask >> xfer->endpoint->usb_uframe);
1910}
1911
1912/*------------------------------------------------------------------------*
1913 *      usb_hs_bandwidth_free
1914 *
1915 * This function is a wrapper function for "usb_hs_bandwidth_adjust()".
1916 *------------------------------------------------------------------------*/
1917void
1918usb_hs_bandwidth_free(struct usb_xfer *xfer)
1919{
1920        struct usb_device *udev;
1921        uint8_t slot;
1922        uint8_t mask;
1923
1924        udev = xfer->xroot->udev;
1925
1926        if (udev->flags.usb_mode != USB_MODE_HOST)
1927                return;         /* not supported */
1928
1929        xfer->endpoint->refcount_bw--;
1930        if (xfer->endpoint->refcount_bw != 0)
1931                return;         /* still allocated */
1932
1933        switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) {
1934        case UE_INTERRUPT:
1935        case UE_ISOCHRONOUS:
1936
1937                slot = xfer->endpoint->usb_uframe;
1938                mask = xfer->endpoint->usb_smask;
1939
1940                /* free microframe slot(s): */   
1941                usb_hs_bandwidth_adjust(udev,
1942                    -xfer->max_frame_size, slot, mask >> slot);
1943
1944                DPRINTFN(11, "slot=%d, mask=0x%02x\n",
1945                    slot, mask >> slot);
1946
1947                xfer->endpoint->usb_uframe = 0;
1948                xfer->endpoint->usb_cmask = 0;
1949                xfer->endpoint->usb_smask = 0;
1950                break;
1951
1952        default:
1953                break;
1954        }
1955}
1956
1957/*------------------------------------------------------------------------*
1958 *      usb_isoc_time_expand
1959 *
1960 * This function will expand the time counter from 7-bit to 16-bit.
1961 *
1962 * Returns:
1963 *   16-bit isochronous time counter.
1964 *------------------------------------------------------------------------*/
1965uint16_t
1966usb_isoc_time_expand(struct usb_bus *bus, uint16_t isoc_time_curr)
1967{
1968        uint16_t rem;
1969
1970        USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
1971
1972        rem = bus->isoc_time_last & (USB_ISOC_TIME_MAX - 1);
1973
1974        isoc_time_curr &= (USB_ISOC_TIME_MAX - 1);
1975
1976        if (isoc_time_curr < rem) {
1977                /* the time counter wrapped around */
1978                bus->isoc_time_last += USB_ISOC_TIME_MAX;
1979        }
1980        /* update the remainder */
1981
1982        bus->isoc_time_last &= ~(USB_ISOC_TIME_MAX - 1);
1983        bus->isoc_time_last |= isoc_time_curr;
1984
1985        return (bus->isoc_time_last);
1986}
1987
1988/*------------------------------------------------------------------------*
1989 *      usbd_fs_isoc_schedule_alloc_slot
1990 *
1991 * This function will allocate bandwidth for an isochronous FULL speed
1992 * transaction in the FULL speed schedule.
1993 *
1994 * Returns:
1995 *    <8: Success
1996 * Else: Error
1997 *------------------------------------------------------------------------*/
1998#if USB_HAVE_TT_SUPPORT
1999uint8_t
2000usbd_fs_isoc_schedule_alloc_slot(struct usb_xfer *isoc_xfer, uint16_t isoc_time)
2001{
2002        struct usb_xfer *xfer;
2003        struct usb_xfer *pipe_xfer;
2004        struct usb_bus *bus;
2005        usb_frlength_t len;
2006        usb_frlength_t data_len;
2007        uint16_t delta;
2008        uint16_t slot;
2009        uint8_t retval;
2010
2011        data_len = 0;
2012        slot = 0;
2013
2014        bus = isoc_xfer->xroot->bus;
2015
2016        TAILQ_FOREACH(xfer, &bus->intr_q.head, wait_entry) {
2017
2018                /* skip self, if any */
2019
2020                if (xfer == isoc_xfer)
2021                        continue;
2022
2023                /* check if this USB transfer is going through the same TT */
2024
2025                if (xfer->xroot->udev->parent_hs_hub !=
2026                    isoc_xfer->xroot->udev->parent_hs_hub) {
2027                        continue;
2028                }
2029                if ((isoc_xfer->xroot->udev->parent_hs_hub->
2030                    ddesc.bDeviceProtocol == UDPROTO_HSHUBMTT) &&
2031                    (xfer->xroot->udev->hs_port_no !=
2032                    isoc_xfer->xroot->udev->hs_port_no)) {
2033                        continue;
2034                }
2035                if (xfer->endpoint->methods != isoc_xfer->endpoint->methods)
2036                        continue;
2037
2038                /* check if isoc_time is part of this transfer */
2039
2040                delta = xfer->isoc_time_complete - isoc_time;
2041                if (delta > 0 && delta <= xfer->nframes) {
2042                        delta = xfer->nframes - delta;
2043
2044                        len = xfer->frlengths[delta];
2045                        len += 8;
2046                        len *= 7;
2047                        len /= 6;
2048
2049                        data_len += len;
2050                }
2051
2052                /* check double buffered transfers */
2053
2054                TAILQ_FOREACH(pipe_xfer, &xfer->endpoint->endpoint_q.head,
2055                    wait_entry) {
2056
2057                        /* skip self, if any */
2058
2059                        if (pipe_xfer == isoc_xfer)
2060                                continue;
2061
2062                        /* check if isoc_time is part of this transfer */
2063
2064                        delta = pipe_xfer->isoc_time_complete - isoc_time;
2065                        if (delta > 0 && delta <= pipe_xfer->nframes) {
2066                                delta = pipe_xfer->nframes - delta;
2067
2068                                len = pipe_xfer->frlengths[delta];
2069                                len += 8;
2070                                len *= 7;
2071                                len /= 6;
2072
2073                                data_len += len;
2074                        }
2075                }
2076        }
2077
2078        while (data_len >= USB_FS_BYTES_PER_HS_UFRAME) {
2079                data_len -= USB_FS_BYTES_PER_HS_UFRAME;
2080                slot++;
2081        }
2082
2083        /* check for overflow */
2084
2085        if (slot >= USB_FS_ISOC_UFRAME_MAX)
2086                return (255);
2087
2088        retval = slot;
2089
2090        delta = isoc_xfer->isoc_time_complete - isoc_time;
2091        if (delta > 0 && delta <= isoc_xfer->nframes) {
2092                delta = isoc_xfer->nframes - delta;
2093
2094                len = isoc_xfer->frlengths[delta];
2095                len += 8;
2096                len *= 7;
2097                len /= 6;
2098
2099                data_len += len;
2100        }
2101
2102        while (data_len >= USB_FS_BYTES_PER_HS_UFRAME) {
2103                data_len -= USB_FS_BYTES_PER_HS_UFRAME;
2104                slot++;
2105        }
2106
2107        /* check for overflow */
2108
2109        if (slot >= USB_FS_ISOC_UFRAME_MAX)
2110                return (255);
2111
2112        return (retval);
2113}
2114#endif
2115
2116/*------------------------------------------------------------------------*
2117 *      usb_bus_port_get_device
2118 *
2119 * This function is NULL safe.
2120 *------------------------------------------------------------------------*/
2121struct usb_device *
2122usb_bus_port_get_device(struct usb_bus *bus, struct usb_port *up)
2123{
2124        if ((bus == NULL) || (up == NULL)) {
2125                /* be NULL safe */
2126                return (NULL);
2127        }
2128        if (up->device_index == 0) {
2129                /* nothing to do */
2130                return (NULL);
2131        }
2132        return (bus->devices[up->device_index]);
2133}
2134
2135/*------------------------------------------------------------------------*
2136 *      usb_bus_port_set_device
2137 *
2138 * This function is NULL safe.
2139 *------------------------------------------------------------------------*/
2140void
2141usb_bus_port_set_device(struct usb_bus *bus, struct usb_port *up,
2142    struct usb_device *udev, uint8_t device_index)
2143{
2144        if (bus == NULL) {
2145                /* be NULL safe */
2146                return;
2147        }
2148        /*
2149         * There is only one case where we don't
2150         * have an USB port, and that is the Root Hub!
2151         */
2152        if (up) {
2153                if (udev) {
2154                        up->device_index = device_index;
2155                } else {
2156                        device_index = up->device_index;
2157                        up->device_index = 0;
2158                }
2159        }
2160        /*
2161         * Make relationships to our new device
2162         */
2163        if (device_index != 0) {
2164#if USB_HAVE_UGEN
2165                mtx_lock(&usb_ref_lock);
2166#endif
2167                bus->devices[device_index] = udev;
2168#if USB_HAVE_UGEN
2169                mtx_unlock(&usb_ref_lock);
2170#endif
2171        }
2172        /*
2173         * Debug print
2174         */
2175        DPRINTFN(2, "bus %p devices[%u] = %p\n", bus, device_index, udev);
2176}
2177
2178/*------------------------------------------------------------------------*
2179 *      usb_needs_explore
2180 *
2181 * This functions is called when the USB event thread needs to run.
2182 *------------------------------------------------------------------------*/
2183void
2184usb_needs_explore(struct usb_bus *bus, uint8_t do_probe)
2185{
2186        uint8_t do_unlock;
2187
2188        DPRINTF("\n");
2189
2190        if (bus == NULL) {
2191                DPRINTF("No bus pointer!\n");
2192                return;
2193        }
2194        if ((bus->devices == NULL) ||
2195            (bus->devices[USB_ROOT_HUB_ADDR] == NULL)) {
2196                DPRINTF("No root HUB\n");
2197                return;
2198        }
2199        if (mtx_owned(&bus->bus_mtx)) {
2200                do_unlock = 0;
2201        } else {
2202                USB_BUS_LOCK(bus);
2203                do_unlock = 1;
2204        }
2205        if (do_probe) {
2206                bus->do_probe = 1;
2207        }
2208        if (usb_proc_msignal(&bus->explore_proc,
2209            &bus->explore_msg[0], &bus->explore_msg[1])) {
2210                /* ignore */
2211        }
2212        if (do_unlock) {
2213                USB_BUS_UNLOCK(bus);
2214        }
2215}
2216
2217/*------------------------------------------------------------------------*
2218 *      usb_needs_explore_all
2219 *
2220 * This function is called whenever a new driver is loaded and will
2221 * cause that all USB busses are re-explored.
2222 *------------------------------------------------------------------------*/
2223void
2224usb_needs_explore_all(void)
2225{
2226        struct usb_bus *bus;
2227        devclass_t dc;
2228        device_t dev;
2229        int max;
2230
2231        DPRINTFN(3, "\n");
2232
2233        dc = usb_devclass_ptr;
2234        if (dc == NULL) {
2235                DPRINTFN(0, "no devclass\n");
2236                return;
2237        }
2238        /*
2239         * Explore all USB busses in parallell.
2240         */
2241        max = devclass_get_maxunit(dc);
2242        while (max >= 0) {
2243                dev = devclass_get_device(dc, max);
2244                if (dev) {
2245                        bus = device_get_softc(dev);
2246                        if (bus) {
2247                                usb_needs_explore(bus, 1);
2248                        }
2249                }
2250                max--;
2251        }
2252}
2253
2254/*------------------------------------------------------------------------*
2255 *      usb_bus_power_update
2256 *
2257 * This function will ensure that all USB devices on the given bus are
2258 * properly suspended or resumed according to the device transfer
2259 * state.
2260 *------------------------------------------------------------------------*/
2261#if USB_HAVE_POWERD
2262void
2263usb_bus_power_update(struct usb_bus *bus)
2264{
2265        usb_needs_explore(bus, 0 /* no probe */ );
2266}
2267#endif
2268
2269/*------------------------------------------------------------------------*
2270 *      usbd_transfer_power_ref
2271 *
2272 * This function will modify the power save reference counts and
2273 * wakeup the USB device associated with the given USB transfer, if
2274 * needed.
2275 *------------------------------------------------------------------------*/
2276#if USB_HAVE_POWERD
2277void
2278usbd_transfer_power_ref(struct usb_xfer *xfer, int val)
2279{
2280        static const usb_power_mask_t power_mask[4] = {
2281                [UE_CONTROL] = USB_HW_POWER_CONTROL,
2282                [UE_BULK] = USB_HW_POWER_BULK,
2283                [UE_INTERRUPT] = USB_HW_POWER_INTERRUPT,
2284                [UE_ISOCHRONOUS] = USB_HW_POWER_ISOC,
2285        };
2286        struct usb_device *udev;
2287        uint8_t needs_explore;
2288        uint8_t needs_hw_power;
2289        uint8_t xfer_type;
2290
2291        udev = xfer->xroot->udev;
2292
2293        if (udev->device_index == USB_ROOT_HUB_ADDR) {
2294                /* no power save for root HUB */
2295                return;
2296        }
2297        USB_BUS_LOCK(udev->bus);
2298
2299        xfer_type = xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE;
2300
2301        udev->pwr_save.last_xfer_time = ticks;
2302        udev->pwr_save.type_refs[xfer_type] += val;
2303
2304        if (xfer->flags_int.control_xfr) {
2305                udev->pwr_save.read_refs += val;
2306                if (xfer->flags_int.usb_mode == USB_MODE_HOST) {
2307                        /*
2308                         * It is not allowed to suspend during a
2309                         * control transfer:
2310                         */
2311                        udev->pwr_save.write_refs += val;
2312                }
2313        } else if (USB_GET_DATA_ISREAD(xfer)) {
2314                udev->pwr_save.read_refs += val;
2315        } else {
2316                udev->pwr_save.write_refs += val;
2317        }
2318
2319        if (val > 0) {
2320                if (udev->flags.self_suspended)
2321                        needs_explore = usb_peer_should_wakeup(udev);
2322                else
2323                        needs_explore = 0;
2324
2325                if (!(udev->bus->hw_power_state & power_mask[xfer_type])) {
2326                        DPRINTF("Adding type %u to power state\n", xfer_type);
2327                        udev->bus->hw_power_state |= power_mask[xfer_type];
2328                        needs_hw_power = 1;
2329                } else {
2330                        needs_hw_power = 0;
2331                }
2332        } else {
2333                needs_explore = 0;
2334                needs_hw_power = 0;
2335        }
2336
2337        USB_BUS_UNLOCK(udev->bus);
2338
2339        if (needs_explore) {
2340                DPRINTF("update\n");
2341                usb_bus_power_update(udev->bus);
2342        } else if (needs_hw_power) {
2343                DPRINTF("needs power\n");
2344                if (udev->bus->methods->set_hw_power != NULL) {
2345                        (udev->bus->methods->set_hw_power) (udev->bus);
2346                }
2347        }
2348}
2349#endif
2350
2351/*------------------------------------------------------------------------*
2352 *      usb_peer_should_wakeup
2353 *
2354 * This function returns non-zero if the current device should wake up.
2355 *------------------------------------------------------------------------*/
2356static uint8_t
2357usb_peer_should_wakeup(struct usb_device *udev)
2358{
2359        return (((udev->power_mode == USB_POWER_MODE_ON) &&
2360            (udev->flags.usb_mode == USB_MODE_HOST)) ||
2361            (udev->driver_added_refcount != udev->bus->driver_added_refcount) ||
2362            (udev->re_enumerate_wait != USB_RE_ENUM_DONE) ||
2363            (udev->pwr_save.type_refs[UE_ISOCHRONOUS] != 0) ||
2364            (udev->pwr_save.write_refs != 0) ||
2365            ((udev->pwr_save.read_refs != 0) &&
2366            (udev->flags.usb_mode == USB_MODE_HOST) &&
2367            (usb_peer_can_wakeup(udev) == 0)));
2368}
2369
2370/*------------------------------------------------------------------------*
2371 *      usb_bus_powerd
2372 *
2373 * This function implements the USB power daemon and is called
2374 * regularly from the USB explore thread.
2375 *------------------------------------------------------------------------*/
2376#if USB_HAVE_POWERD
2377void
2378usb_bus_powerd(struct usb_bus *bus)
2379{
2380        struct usb_device *udev;
2381        usb_ticks_t temp;
2382        usb_ticks_t limit;
2383        usb_ticks_t mintime;
2384        usb_size_t type_refs[5];
2385        uint8_t x;
2386
2387        limit = usb_power_timeout;
2388        if (limit == 0)
2389                limit = hz;
2390        else if (limit > 255)
2391                limit = 255 * hz;
2392        else
2393                limit = limit * hz;
2394
2395        DPRINTF("bus=%p\n", bus);
2396
2397        USB_BUS_LOCK(bus);
2398
2399        /*
2400         * The root HUB device is never suspended
2401         * and we simply skip it.
2402         */
2403        for (x = USB_ROOT_HUB_ADDR + 1;
2404            x != bus->devices_max; x++) {
2405
2406                udev = bus->devices[x];
2407                if (udev == NULL)
2408                        continue;
2409
2410                temp = ticks - udev->pwr_save.last_xfer_time;
2411
2412                if (usb_peer_should_wakeup(udev)) {
2413                        /* check if we are suspended */
2414                        if (udev->flags.self_suspended != 0) {
2415                                USB_BUS_UNLOCK(bus);
2416                                usb_dev_resume_peer(udev);
2417                                USB_BUS_LOCK(bus);
2418                        }
2419                } else if ((temp >= limit) &&
2420                    (udev->flags.usb_mode == USB_MODE_HOST) &&
2421                    (udev->flags.self_suspended == 0)) {
2422                        /* try to do suspend */
2423
2424                        USB_BUS_UNLOCK(bus);
2425                        usb_dev_suspend_peer(udev);
2426                        USB_BUS_LOCK(bus);
2427                }
2428        }
2429
2430        /* reset counters */
2431
2432        mintime = (usb_ticks_t)-1;
2433        type_refs[0] = 0;
2434        type_refs[1] = 0;
2435        type_refs[2] = 0;
2436        type_refs[3] = 0;
2437        type_refs[4] = 0;
2438
2439        /* Re-loop all the devices to get the actual state */
2440
2441        for (x = USB_ROOT_HUB_ADDR + 1;
2442            x != bus->devices_max; x++) {
2443
2444                udev = bus->devices[x];
2445                if (udev == NULL)
2446                        continue;
2447
2448                /* we found a non-Root-Hub USB device */
2449                type_refs[4] += 1;
2450
2451                /* "last_xfer_time" can be updated by a resume */
2452                temp = ticks - udev->pwr_save.last_xfer_time;
2453
2454                /*
2455                 * Compute minimum time since last transfer for the complete
2456                 * bus:
2457                 */
2458                if (temp < mintime)
2459                        mintime = temp;
2460
2461                if (udev->flags.self_suspended == 0) {
2462                        type_refs[0] += udev->pwr_save.type_refs[0];
2463                        type_refs[1] += udev->pwr_save.type_refs[1];
2464                        type_refs[2] += udev->pwr_save.type_refs[2];
2465                        type_refs[3] += udev->pwr_save.type_refs[3];
2466                }
2467        }
2468
2469        if (mintime >= (usb_ticks_t)(1 * hz)) {
2470                /* recompute power masks */
2471                DPRINTF("Recomputing power masks\n");
2472                bus->hw_power_state = 0;
2473                if (type_refs[UE_CONTROL] != 0)
2474                        bus->hw_power_state |= USB_HW_POWER_CONTROL;
2475                if (type_refs[UE_BULK] != 0)
2476                        bus->hw_power_state |= USB_HW_POWER_BULK;
2477                if (type_refs[UE_INTERRUPT] != 0)
2478                        bus->hw_power_state |= USB_HW_POWER_INTERRUPT;
2479                if (type_refs[UE_ISOCHRONOUS] != 0)
2480                        bus->hw_power_state |= USB_HW_POWER_ISOC;
2481                if (type_refs[4] != 0)
2482                        bus->hw_power_state |= USB_HW_POWER_NON_ROOT_HUB;
2483        }
2484        USB_BUS_UNLOCK(bus);
2485
2486        if (bus->methods->set_hw_power != NULL) {
2487                /* always update hardware power! */
2488                (bus->methods->set_hw_power) (bus);
2489        }
2490        return;
2491}
2492#endif
2493
2494/*------------------------------------------------------------------------*
2495 *      usb_dev_resume_peer
2496 *
2497 * This function will resume an USB peer and do the required USB
2498 * signalling to get an USB device out of the suspended state.
2499 *------------------------------------------------------------------------*/
2500static void
2501usb_dev_resume_peer(struct usb_device *udev)
2502{
2503        struct usb_bus *bus;
2504        int err;
2505
2506        /* be NULL safe */
2507        if (udev == NULL)
2508                return;
2509
2510        /* check if already resumed */
2511        if (udev->flags.self_suspended == 0)
2512                return;
2513
2514        /* we need a parent HUB to do resume */
2515        if (udev->parent_hub == NULL)
2516                return;
2517
2518        DPRINTF("udev=%p\n", udev);
2519
2520        if ((udev->flags.usb_mode == USB_MODE_DEVICE) &&
2521            (udev->flags.remote_wakeup == 0)) {
2522                /*
2523                 * If the host did not set the remote wakeup feature, we can
2524                 * not wake it up either!
2525                 */
2526                DPRINTF("remote wakeup is not set!\n");
2527                return;
2528        }
2529        /* get bus pointer */
2530        bus = udev->bus;
2531
2532        /* resume parent hub first */
2533        usb_dev_resume_peer(udev->parent_hub);
2534
2535        /* reduce chance of instant resume failure by waiting a little bit */
2536        usb_pause_mtx(NULL, USB_MS_TO_TICKS(20));
2537
2538        if (usb_device_20_compatible(udev)) {
2539                /* resume current port (Valid in Host and Device Mode) */
2540                err = usbd_req_clear_port_feature(udev->parent_hub,
2541                    NULL, udev->port_no, UHF_PORT_SUSPEND);
2542                if (err) {
2543                        DPRINTFN(0, "Resuming port failed\n");
2544                        return;
2545                }
2546        } else {
2547                /* resume current port (Valid in Host and Device Mode) */
2548                err = usbd_req_set_port_link_state(udev->parent_hub,
2549                    NULL, udev->port_no, UPS_PORT_LS_U0);
2550                if (err) {
2551                        DPRINTFN(0, "Resuming port failed\n");
2552                        return;
2553                }
2554        }
2555
2556        /* resume settle time */
2557        usb_pause_mtx(NULL, USB_MS_TO_TICKS(usb_port_resume_delay));
2558
2559        if (bus->methods->device_resume != NULL) {
2560                /* resume USB device on the USB controller */
2561                (bus->methods->device_resume) (udev);
2562        }
2563        USB_BUS_LOCK(bus);
2564        /* set that this device is now resumed */
2565        udev->flags.self_suspended = 0;
2566#if USB_HAVE_POWERD
2567        /* make sure that we don't go into suspend right away */
2568        udev->pwr_save.last_xfer_time = ticks;
2569
2570        /* make sure the needed power masks are on */
2571        if (udev->pwr_save.type_refs[UE_CONTROL] != 0)
2572                bus->hw_power_state |= USB_HW_POWER_CONTROL;
2573        if (udev->pwr_save.type_refs[UE_BULK] != 0)
2574                bus->hw_power_state |= USB_HW_POWER_BULK;
2575        if (udev->pwr_save.type_refs[UE_INTERRUPT] != 0)
2576                bus->hw_power_state |= USB_HW_POWER_INTERRUPT;
2577        if (udev->pwr_save.type_refs[UE_ISOCHRONOUS] != 0)
2578                bus->hw_power_state |= USB_HW_POWER_ISOC;
2579#endif
2580        USB_BUS_UNLOCK(bus);
2581
2582        if (bus->methods->set_hw_power != NULL) {
2583                /* always update hardware power! */
2584                (bus->methods->set_hw_power) (bus);
2585        }
2586
2587        usbd_sr_lock(udev);
2588
2589        /* notify all sub-devices about resume */
2590        err = usb_suspend_resume(udev, 0);
2591
2592        usbd_sr_unlock(udev);
2593
2594        /* check if peer has wakeup capability */
2595        if (usb_peer_can_wakeup(udev)) {
2596                /* clear remote wakeup */
2597                err = usbd_req_clear_device_feature(udev,
2598                    NULL, UF_DEVICE_REMOTE_WAKEUP);
2599                if (err) {
2600                        DPRINTFN(0, "Clearing device "
2601                            "remote wakeup failed: %s\n",
2602                            usbd_errstr(err));
2603                }
2604        }
2605}
2606
2607/*------------------------------------------------------------------------*
2608 *      usb_dev_suspend_peer
2609 *
2610 * This function will suspend an USB peer and do the required USB
2611 * signalling to get an USB device into the suspended state.
2612 *------------------------------------------------------------------------*/
2613static void
2614usb_dev_suspend_peer(struct usb_device *udev)
2615{
2616        struct usb_device *child;
2617        int err;
2618        uint8_t x;
2619        uint8_t nports;
2620
2621repeat:
2622        /* be NULL safe */
2623        if (udev == NULL)
2624                return;
2625
2626        /* check if already suspended */
2627        if (udev->flags.self_suspended)
2628                return;
2629
2630        /* we need a parent HUB to do suspend */
2631        if (udev->parent_hub == NULL)
2632                return;
2633
2634        DPRINTF("udev=%p\n", udev);
2635
2636        /* check if the current device is a HUB */
2637        if (udev->hub != NULL) {
2638                nports = udev->hub->nports;
2639
2640                /* check if all devices on the HUB are suspended */
2641                for (x = 0; x != nports; x++) {
2642                        child = usb_bus_port_get_device(udev->bus,
2643                            udev->hub->ports + x);
2644
2645                        if (child == NULL)
2646                                continue;
2647
2648                        if (child->flags.self_suspended)
2649                                continue;
2650
2651                        DPRINTFN(1, "Port %u is busy on the HUB!\n", x + 1);
2652                        return;
2653                }
2654        }
2655
2656        if (usb_peer_can_wakeup(udev)) {
2657                /*
2658                 * This request needs to be done before we set
2659                 * "udev->flags.self_suspended":
2660                 */
2661
2662                /* allow device to do remote wakeup */
2663                err = usbd_req_set_device_feature(udev,
2664                    NULL, UF_DEVICE_REMOTE_WAKEUP);
2665                if (err) {
2666                        DPRINTFN(0, "Setting device "
2667                            "remote wakeup failed\n");
2668                }
2669        }
2670
2671        USB_BUS_LOCK(udev->bus);
2672        /*
2673         * Checking for suspend condition and setting suspended bit
2674         * must be atomic!
2675         */
2676        err = usb_peer_should_wakeup(udev);
2677        if (err == 0) {
2678                /*
2679                 * Set that this device is suspended. This variable
2680                 * must be set before calling USB controller suspend
2681                 * callbacks.
2682                 */
2683                udev->flags.self_suspended = 1;
2684        }
2685        USB_BUS_UNLOCK(udev->bus);
2686
2687        if (err != 0) {
2688                if (usb_peer_can_wakeup(udev)) {
2689                        /* allow device to do remote wakeup */
2690                        err = usbd_req_clear_device_feature(udev,
2691                            NULL, UF_DEVICE_REMOTE_WAKEUP);
2692                        if (err) {
2693                                DPRINTFN(0, "Setting device "
2694                                    "remote wakeup failed\n");
2695                        }
2696                }
2697
2698                if (udev->flags.usb_mode == USB_MODE_DEVICE) {
2699                        /* resume parent HUB first */
2700                        usb_dev_resume_peer(udev->parent_hub);
2701
2702                        /* reduce chance of instant resume failure by waiting a little bit */
2703                        usb_pause_mtx(NULL, USB_MS_TO_TICKS(20));
2704
2705                        /* resume current port (Valid in Host and Device Mode) */
2706                        err = usbd_req_clear_port_feature(udev->parent_hub,
2707                            NULL, udev->port_no, UHF_PORT_SUSPEND);
2708
2709                        /* resume settle time */
2710                        usb_pause_mtx(NULL, USB_MS_TO_TICKS(usb_port_resume_delay));
2711                }
2712                DPRINTF("Suspend was cancelled!\n");
2713                return;
2714        }
2715
2716        usbd_sr_lock(udev);
2717
2718        /* notify all sub-devices about suspend */
2719        err = usb_suspend_resume(udev, 1);
2720
2721        usbd_sr_unlock(udev);
2722
2723        if (udev->bus->methods->device_suspend != NULL) {
2724                usb_timeout_t temp;
2725
2726                /* suspend device on the USB controller */
2727                (udev->bus->methods->device_suspend) (udev);
2728
2729                /* do DMA delay */
2730                temp = usbd_get_dma_delay(udev);
2731                if (temp != 0)
2732                        usb_pause_mtx(NULL, USB_MS_TO_TICKS(temp));
2733
2734        }
2735
2736        if (usb_device_20_compatible(udev)) {
2737                /* suspend current port */
2738                err = usbd_req_set_port_feature(udev->parent_hub,
2739                    NULL, udev->port_no, UHF_PORT_SUSPEND);
2740                if (err) {
2741                        DPRINTFN(0, "Suspending port failed\n");
2742                        return;
2743                }
2744        } else {
2745                /* suspend current port */
2746                err = usbd_req_set_port_link_state(udev->parent_hub,
2747                    NULL, udev->port_no, UPS_PORT_LS_U3);
2748                if (err) {
2749                        DPRINTFN(0, "Suspending port failed\n");
2750                        return;
2751                }
2752        }
2753
2754        udev = udev->parent_hub;
2755        goto repeat;
2756}
2757
2758/*------------------------------------------------------------------------*
2759 *      usbd_set_power_mode
2760 *
2761 * This function will set the power mode, see USB_POWER_MODE_XXX for a
2762 * USB device.
2763 *------------------------------------------------------------------------*/
2764void
2765usbd_set_power_mode(struct usb_device *udev, uint8_t power_mode)
2766{
2767        /* filter input argument */
2768        if ((power_mode != USB_POWER_MODE_ON) &&
2769            (power_mode != USB_POWER_MODE_OFF))
2770                power_mode = USB_POWER_MODE_SAVE;
2771
2772        power_mode = usbd_filter_power_mode(udev, power_mode); 
2773
2774        udev->power_mode = power_mode;  /* update copy of power mode */
2775
2776#if USB_HAVE_POWERD
2777        usb_bus_power_update(udev->bus);
2778#else
2779        usb_needs_explore(udev->bus, 0 /* no probe */ );
2780#endif
2781}
2782
2783/*------------------------------------------------------------------------*
2784 *      usbd_filter_power_mode
2785 *
2786 * This function filters the power mode based on hardware requirements.
2787 *------------------------------------------------------------------------*/
2788uint8_t
2789usbd_filter_power_mode(struct usb_device *udev, uint8_t power_mode)
2790{
2791        struct usb_bus_methods *mtod;
2792        int8_t temp;
2793
2794        mtod = udev->bus->methods;
2795        temp = -1;
2796
2797        if (mtod->get_power_mode != NULL)
2798                (mtod->get_power_mode) (udev, &temp);
2799
2800        /* check if we should not filter */
2801        if (temp < 0)
2802                return (power_mode);
2803
2804        /* use fixed power mode given by hardware driver */
2805        return (temp);
2806}
2807
2808/*------------------------------------------------------------------------*
2809 *      usbd_start_re_enumerate
2810 *
2811 * This function starts re-enumeration of the given USB device. This
2812 * function does not need to be called BUS-locked. This function does
2813 * not wait until the re-enumeration is completed.
2814 *------------------------------------------------------------------------*/
2815void
2816usbd_start_re_enumerate(struct usb_device *udev)
2817{
2818        if (udev->re_enumerate_wait == USB_RE_ENUM_DONE) {
2819                udev->re_enumerate_wait = USB_RE_ENUM_START;
2820                usb_needs_explore(udev->bus, 0);
2821        }
2822}
2823
2824/*-----------------------------------------------------------------------*
2825 *      usbd_start_set_config
2826 *
2827 * This function starts setting a USB configuration. This function
2828 * does not need to be called BUS-locked. This function does not wait
2829 * until the set USB configuratino is completed.
2830 *------------------------------------------------------------------------*/
2831usb_error_t
2832usbd_start_set_config(struct usb_device *udev, uint8_t index)
2833{
2834        if (udev->re_enumerate_wait == USB_RE_ENUM_DONE) {
2835                if (udev->curr_config_index == index) {
2836                        /* no change needed */
2837                        return (0);
2838                }
2839                udev->next_config_index = index;
2840                udev->re_enumerate_wait = USB_RE_ENUM_SET_CONFIG;
2841                usb_needs_explore(udev->bus, 0);
2842                return (0);
2843        } else if (udev->re_enumerate_wait == USB_RE_ENUM_SET_CONFIG) {
2844                if (udev->next_config_index == index) {
2845                        /* no change needed */
2846                        return (0);
2847                }
2848        }
2849        return (USB_ERR_PENDING_REQUESTS);
2850}
Note: See TracBrowser for help on using the repository browser.