Line data Source code
1 : /* $OpenBSD: uhub.c,v 1.90 2017/04/08 02:57:25 deraadt Exp $ */
2 : /* $NetBSD: uhub.c,v 1.64 2003/02/08 03:32:51 ichiro Exp $ */
3 : /* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
4 :
5 : /*
6 : * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 : * All rights reserved.
8 : *
9 : * This code is derived from software contributed to The NetBSD Foundation
10 : * by Lennart Augustsson (lennart@augustsson.net) at
11 : * Carlstedt Research & Technology.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : *
22 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 : * POSSIBILITY OF SUCH DAMAGE.
33 : */
34 :
35 : #include <sys/param.h>
36 : #include <sys/systm.h>
37 : #include <sys/kernel.h>
38 : #include <sys/malloc.h>
39 : #include <sys/device.h>
40 :
41 : #include <machine/bus.h>
42 :
43 : #include <dev/usb/usb.h>
44 : #include <dev/usb/usbdi.h>
45 : #include <dev/usb/usbdi_util.h>
46 : #include <dev/usb/usbdivar.h>
47 :
48 : #define UHUB_INTR_INTERVAL 255 /* ms */
49 :
50 : #ifdef UHUB_DEBUG
51 : #define DPRINTF(x...) do { printf(x); } while (0)
52 : #else
53 : #define DPRINTF(x...)
54 : #endif
55 :
56 : #define DEVNAME(sc) ((sc)->sc_dev.dv_xname)
57 :
58 : struct uhub_softc {
59 : struct device sc_dev; /* base device */
60 : struct usbd_device *sc_hub; /* USB device */
61 : struct usbd_pipe *sc_ipipe; /* interrupt pipe */
62 :
63 : uint32_t sc_status; /* status from last interrupt */
64 : uint8_t *sc_statusbuf; /* per port status buffer */
65 : size_t sc_statuslen; /* status bufferlen */
66 :
67 : u_char sc_running;
68 : };
69 : #define UHUB_PROTO(sc) ((sc)->sc_hub->ddesc.bDeviceProtocol)
70 : #define UHUB_IS_HIGH_SPEED(sc) (UHUB_PROTO(sc) != UDPROTO_FSHUB)
71 : #define UHUB_IS_SINGLE_TT(sc) (UHUB_PROTO(sc) == UDPROTO_HSHUBSTT)
72 :
73 : int uhub_explore(struct usbd_device *hub);
74 : void uhub_intr(struct usbd_xfer *, void *, usbd_status);
75 : int uhub_port_connect(struct uhub_softc *, int, int, int);
76 :
77 : /*
78 : * We need two attachment points:
79 : * hub to usb and hub to hub
80 : * Every other driver only connects to hubs
81 : */
82 :
83 : int uhub_match(struct device *, void *, void *);
84 : void uhub_attach(struct device *, struct device *, void *);
85 : int uhub_detach(struct device *, int);
86 :
87 : struct cfdriver uhub_cd = {
88 : NULL, "uhub", DV_DULL
89 : };
90 :
91 : const struct cfattach uhub_ca = {
92 : sizeof(struct uhub_softc), uhub_match, uhub_attach, uhub_detach
93 : };
94 :
95 : const struct cfattach uhub_uhub_ca = {
96 : sizeof(struct uhub_softc), uhub_match, uhub_attach, uhub_detach
97 : };
98 :
99 : int
100 0 : uhub_match(struct device *parent, void *match, void *aux)
101 : {
102 0 : struct usb_attach_arg *uaa = aux;
103 0 : usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
104 :
105 0 : if (uaa->iface == NULL)
106 0 : return (UMATCH_NONE);
107 :
108 : /*
109 : * The subclass for hubs seems to be 0 for some and 1 for others,
110 : * so we just ignore the subclass.
111 : */
112 0 : if (dd->bDeviceClass == UDCLASS_HUB)
113 0 : return (UMATCH_DEVCLASS_DEVSUBCLASS);
114 0 : return (UMATCH_NONE);
115 0 : }
116 :
117 : void
118 0 : uhub_attach(struct device *parent, struct device *self, void *aux)
119 : {
120 0 : struct uhub_softc *sc = (struct uhub_softc *)self;
121 0 : struct usb_attach_arg *uaa = aux;
122 0 : struct usbd_device *dev = uaa->device;
123 : struct usbd_hub *hub = NULL;
124 0 : union {
125 : usb_hub_descriptor_t hs;
126 : usb_hub_ss_descriptor_t ss;
127 : } hd;
128 : int p, port, nports, powerdelay;
129 0 : struct usbd_interface *iface;
130 : usb_endpoint_descriptor_t *ed;
131 : struct usbd_tt *tts = NULL;
132 : uint8_t ttthink = 0;
133 : usbd_status err;
134 : #ifdef UHUB_DEBUG
135 : int nremov;
136 : #endif
137 :
138 0 : sc->sc_hub = dev;
139 :
140 0 : if (dev->depth > USB_HUB_MAX_DEPTH) {
141 0 : printf("%s: hub depth (%d) exceeded, hub ignored\n",
142 0 : sc->sc_dev.dv_xname, USB_HUB_MAX_DEPTH);
143 0 : return;
144 : }
145 :
146 : /*
147 : * Super-Speed hubs need to know their depth to be able to
148 : * parse the bits of the route-string that correspond to
149 : * their downstream port number.
150 : *
151 : * This does no apply to root hubs.
152 : */
153 0 : if (dev->depth != 0 && dev->speed == USB_SPEED_SUPER) {
154 0 : if (usbd_set_hub_depth(dev, dev->depth - 1)) {
155 0 : printf("%s: unable to set HUB depth\n",
156 0 : sc->sc_dev.dv_xname);
157 0 : return;
158 : }
159 : }
160 :
161 : /* Get hub descriptor. */
162 0 : if (dev->speed == USB_SPEED_SUPER) {
163 0 : err = usbd_get_hub_ss_descriptor(dev, &hd.ss, 1);
164 0 : nports = hd.ss.bNbrPorts;
165 0 : powerdelay = (hd.ss.bPwrOn2PwrGood * UHD_PWRON_FACTOR);
166 0 : if (!err && nports > 7)
167 0 : usbd_get_hub_ss_descriptor(dev, &hd.ss, nports);
168 : } else {
169 0 : err = usbd_get_hub_descriptor(dev, &hd.hs, 1);
170 0 : nports = hd.hs.bNbrPorts;
171 0 : powerdelay = (hd.hs.bPwrOn2PwrGood * UHD_PWRON_FACTOR);
172 0 : ttthink = UGETW(hd.hs.wHubCharacteristics) & UHD_TT_THINK;
173 0 : if (!err && nports > 7)
174 0 : usbd_get_hub_descriptor(dev, &hd.hs, nports);
175 : }
176 :
177 0 : if (err) {
178 : DPRINTF("%s: getting hub descriptor failed, error=%s\n",
179 : sc->sc_dev.dv_xname, usbd_errstr(err));
180 0 : return;
181 : }
182 :
183 : #ifdef UHUB_DEBUG
184 : for (nremov = 0, port = 1; port <= nports; port++) {
185 : if (dev->speed == USB_SPEED_SUPER) {
186 : if (!UHD_NOT_REMOV(&hd.ss, port))
187 : nremov++;
188 : } else {
189 : if (!UHD_NOT_REMOV(&hd.hs, port))
190 : nremov++;
191 : }
192 : }
193 :
194 : printf("%s: %d port%s with %d removable, %s powered",
195 : sc->sc_dev.dv_xname, nports, nports != 1 ? "s" : "",
196 : nremov, dev->self_powered ? "self" : "bus");
197 :
198 : if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
199 : printf(", %s transaction translator%s",
200 : UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
201 : UHUB_IS_SINGLE_TT(sc) ? "" : "s");
202 : }
203 :
204 : printf("\n");
205 : #endif
206 :
207 0 : if (nports == 0) {
208 0 : printf("%s: no ports, hub ignored\n", sc->sc_dev.dv_xname);
209 0 : goto bad;
210 : }
211 :
212 0 : hub = malloc(sizeof(*hub), M_USBDEV, M_NOWAIT);
213 0 : if (hub == NULL)
214 0 : return;
215 0 : hub->ports = mallocarray(nports, sizeof(struct usbd_port),
216 : M_USBDEV, M_NOWAIT);
217 0 : if (hub->ports == NULL) {
218 0 : free(hub, M_USBDEV, sizeof *hub);
219 0 : return;
220 : }
221 0 : dev->hub = hub;
222 0 : dev->hub->hubsoftc = sc;
223 0 : hub->explore = uhub_explore;
224 0 : hub->nports = nports;
225 0 : hub->powerdelay = powerdelay;
226 0 : hub->ttthink = ttthink >> 5;
227 :
228 0 : if (!dev->self_powered && dev->powersrc->parent != NULL &&
229 0 : !dev->powersrc->parent->self_powered) {
230 0 : printf("%s: bus powered hub connected to bus powered hub, "
231 0 : "ignored\n", sc->sc_dev.dv_xname);
232 0 : goto bad;
233 : }
234 :
235 : /* Set up interrupt pipe. */
236 0 : err = usbd_device2interface_handle(dev, 0, &iface);
237 0 : if (err) {
238 0 : printf("%s: no interface handle\n", sc->sc_dev.dv_xname);
239 0 : goto bad;
240 : }
241 0 : ed = usbd_interface2endpoint_descriptor(iface, 0);
242 0 : if (ed == NULL) {
243 0 : printf("%s: no endpoint descriptor\n", sc->sc_dev.dv_xname);
244 0 : goto bad;
245 : }
246 0 : if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
247 0 : printf("%s: bad interrupt endpoint\n", sc->sc_dev.dv_xname);
248 0 : goto bad;
249 : }
250 :
251 0 : sc->sc_statuslen = (nports + 1 + 7) / 8;
252 0 : sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
253 0 : if (!sc->sc_statusbuf)
254 : goto bad;
255 :
256 0 : err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
257 0 : USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf,
258 0 : sc->sc_statuslen, uhub_intr, UHUB_INTR_INTERVAL);
259 0 : if (err) {
260 0 : printf("%s: cannot open interrupt pipe\n",
261 0 : sc->sc_dev.dv_xname);
262 0 : goto bad;
263 : }
264 :
265 : /* Wait with power off for a while. */
266 0 : usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
267 :
268 : /*
269 : * To have the best chance of success we do things in the exact same
270 : * order as Windoze98. This should not be necessary, but some
271 : * devices do not follow the USB specs to the letter.
272 : *
273 : * These are the events on the bus when a hub is attached:
274 : * Get device and config descriptors (see attach code)
275 : * Get hub descriptor (see above)
276 : * For all ports
277 : * turn on power
278 : * wait for power to become stable
279 : * (all below happens in explore code)
280 : * For all ports
281 : * clear C_PORT_CONNECTION
282 : * For all ports
283 : * get port status
284 : * if device connected
285 : * wait 100 ms
286 : * turn on reset
287 : * wait
288 : * clear C_PORT_RESET
289 : * get port status
290 : * proceed with device attachment
291 : */
292 :
293 0 : if (UHUB_IS_HIGH_SPEED(sc)) {
294 0 : tts = mallocarray((UHUB_IS_SINGLE_TT(sc) ? 1 : nports),
295 : sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
296 0 : if (!tts)
297 : goto bad;
298 : }
299 : /* Set up data structures */
300 0 : for (p = 0; p < nports; p++) {
301 0 : struct usbd_port *up = &hub->ports[p];
302 0 : up->device = NULL;
303 0 : up->parent = dev;
304 0 : up->portno = p + 1;
305 0 : if (dev->self_powered)
306 : /* Self powered hub, give ports maximum current. */
307 0 : up->power = USB_MAX_POWER;
308 : else
309 0 : up->power = USB_MIN_POWER;
310 0 : up->restartcnt = 0;
311 0 : up->reattach = 0;
312 0 : if (UHUB_IS_HIGH_SPEED(sc)) {
313 0 : up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
314 0 : up->tt->hub = hub;
315 0 : } else {
316 0 : up->tt = NULL;
317 : }
318 : }
319 :
320 0 : for (port = 1; port <= nports; port++) {
321 : /* Turn the power on. */
322 0 : err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
323 0 : if (err)
324 0 : printf("%s: port %d power on failed, %s\n",
325 0 : sc->sc_dev.dv_xname, port,
326 0 : usbd_errstr(err));
327 : /* Make sure we check the port status at least once. */
328 0 : sc->sc_status |= (1 << port);
329 : }
330 :
331 : /* Wait for stable power. */
332 0 : if (dev->powersrc->parent != NULL)
333 0 : usbd_delay_ms(dev, powerdelay + USB_EXTRA_POWER_UP_TIME);
334 :
335 : /* The usual exploration will finish the setup. */
336 :
337 0 : sc->sc_running = 1;
338 :
339 0 : return;
340 :
341 : bad:
342 0 : if (sc->sc_statusbuf)
343 0 : free(sc->sc_statusbuf, M_USBDEV, sc->sc_statuslen);
344 0 : if (hub) {
345 0 : if (hub->ports)
346 0 : free(hub->ports, M_USBDEV, 0);
347 0 : free(hub, M_USBDEV, sizeof *hub);
348 0 : }
349 0 : dev->hub = NULL;
350 0 : }
351 :
352 : int
353 0 : uhub_explore(struct usbd_device *dev)
354 : {
355 0 : struct uhub_softc *sc = dev->hub->hubsoftc;
356 : struct usbd_port *up;
357 : int status, change;
358 : int port;
359 :
360 0 : if (usbd_is_dying(sc->sc_hub))
361 0 : return (EIO);
362 :
363 0 : if (!sc->sc_running)
364 0 : return (ENXIO);
365 :
366 : /* Ignore hubs that are too deep. */
367 0 : if (sc->sc_hub->depth > USB_HUB_MAX_DEPTH)
368 0 : return (EOPNOTSUPP);
369 :
370 0 : for (port = 1; port <= sc->sc_hub->hub->nports; port++) {
371 0 : up = &sc->sc_hub->hub->ports[port-1];
372 :
373 : change = 0;
374 : status = 0;
375 :
376 0 : if ((sc->sc_status & (1 << port)) || up->reattach) {
377 0 : sc->sc_status &= ~(1 << port);
378 :
379 0 : if (usbd_get_port_status(dev, port, &up->status))
380 : continue;
381 :
382 0 : status = UGETW(up->status.wPortStatus);
383 0 : change = UGETW(up->status.wPortChange);
384 : DPRINTF("%s: port %d status=0x%04x change=0x%04x\n",
385 : sc->sc_dev.dv_xname, port, status, change);
386 0 : }
387 :
388 0 : if (up->reattach) {
389 0 : change |= UPS_C_CONNECT_STATUS;
390 0 : up->reattach = 0;
391 0 : }
392 :
393 0 : if (change & UPS_C_PORT_ENABLED) {
394 0 : usbd_clear_port_feature(sc->sc_hub, port,
395 : UHF_C_PORT_ENABLE);
396 0 : if (change & UPS_C_CONNECT_STATUS) {
397 : /* Ignore the port error if the device
398 : vanished. */
399 0 : } else if (status & UPS_PORT_ENABLED) {
400 0 : printf("%s: illegal enable change, port %d\n",
401 0 : sc->sc_dev.dv_xname, port);
402 0 : } else {
403 : /* Port error condition. */
404 0 : if (up->restartcnt) /* no message first time */
405 0 : printf("%s: port error, restarting "
406 : "port %d\n",
407 0 : sc->sc_dev.dv_xname, port);
408 :
409 0 : if (up->restartcnt++ < USBD_RESTART_MAX)
410 0 : change |= UPS_C_CONNECT_STATUS;
411 : else
412 0 : printf("%s: port error, giving up "
413 : "port %d\n",
414 0 : sc->sc_dev.dv_xname, port);
415 : }
416 : }
417 :
418 0 : if (change & UPS_C_PORT_RESET) {
419 0 : usbd_clear_port_feature(sc->sc_hub, port,
420 : UHF_C_PORT_RESET);
421 0 : change |= UPS_C_CONNECT_STATUS;
422 0 : }
423 :
424 0 : if (change & UPS_C_BH_PORT_RESET &&
425 0 : sc->sc_hub->speed == USB_SPEED_SUPER) {
426 0 : usbd_clear_port_feature(sc->sc_hub, port,
427 : UHF_C_BH_PORT_RESET);
428 0 : }
429 :
430 0 : if (change & UPS_C_CONNECT_STATUS) {
431 0 : if (uhub_port_connect(sc, port, status, change))
432 : continue;
433 :
434 : /* The port set up succeeded, reset error count. */
435 0 : up->restartcnt = 0;
436 0 : }
437 :
438 0 : if (change & UPS_C_PORT_LINK_STATE) {
439 0 : usbd_clear_port_feature(sc->sc_hub, port,
440 : UHF_C_PORT_LINK_STATE);
441 0 : }
442 :
443 : /* Recursive explore. */
444 0 : if (up->device != NULL && up->device->hub != NULL)
445 0 : up->device->hub->explore(up->device);
446 : }
447 :
448 0 : return (0);
449 0 : }
450 :
451 : /*
452 : * Called from process context when the hub is gone.
453 : * Detach all devices on active ports.
454 : */
455 : int
456 0 : uhub_detach(struct device *self, int flags)
457 : {
458 0 : struct uhub_softc *sc = (struct uhub_softc *)self;
459 0 : struct usbd_hub *hub = sc->sc_hub->hub;
460 : struct usbd_port *rup;
461 : int port;
462 :
463 0 : if (hub == NULL) /* Must be partially working */
464 0 : return (0);
465 :
466 0 : usbd_abort_pipe(sc->sc_ipipe);
467 0 : usbd_close_pipe(sc->sc_ipipe);
468 :
469 0 : for (port = 0; port < hub->nports; port++) {
470 0 : rup = &hub->ports[port];
471 0 : if (rup->device != NULL) {
472 0 : usbd_detach(rup->device, self);
473 0 : rup->device = NULL;
474 0 : }
475 : }
476 :
477 0 : if (hub->ports[0].tt)
478 0 : free(hub->ports[0].tt, M_USBDEV, 0);
479 0 : if (sc->sc_statusbuf)
480 0 : free(sc->sc_statusbuf, M_USBDEV, sc->sc_statuslen);
481 0 : if (hub->ports)
482 0 : free(hub->ports, M_USBDEV, 0);
483 0 : free(hub, M_USBDEV, sizeof *hub);
484 0 : sc->sc_hub->hub = NULL;
485 :
486 0 : return (0);
487 0 : }
488 :
489 : /*
490 : * This is an indication that some port has changed status. Remember
491 : * the ports that need attention and notify the USB task thread that
492 : * we need to be explored again.
493 : */
494 : void
495 0 : uhub_intr(struct usbd_xfer *xfer, void *addr, usbd_status status)
496 : {
497 0 : struct uhub_softc *sc = addr;
498 : uint32_t stats = 0;
499 : int i;
500 :
501 0 : if (usbd_is_dying(sc->sc_hub))
502 0 : return;
503 :
504 : DPRINTF("%s: intr status=%d\n", sc->sc_dev.dv_xname, status);
505 :
506 0 : if (status == USBD_STALLED)
507 0 : usbd_clear_endpoint_stall_async(sc->sc_ipipe);
508 0 : else if (status == USBD_NORMAL_COMPLETION) {
509 0 : for (i = 0; i < xfer->actlen; i++)
510 0 : stats |= (uint32_t)(xfer->buffer[i]) << (i * 8);
511 0 : sc->sc_status |= stats;
512 :
513 0 : usb_needs_explore(sc->sc_hub, 0);
514 0 : }
515 0 : }
516 :
517 : int
518 0 : uhub_port_connect(struct uhub_softc *sc, int port, int status, int change)
519 : {
520 0 : struct usbd_port *up = &sc->sc_hub->hub->ports[port-1];
521 : int speed;
522 :
523 : /* We have a connect status change, handle it. */
524 0 : usbd_clear_port_feature(sc->sc_hub, port, UHF_C_PORT_CONNECTION);
525 :
526 : /*
527 : * If there is already a device on the port the change status
528 : * must mean that is has disconnected. Looking at the
529 : * current connect status is not enough to figure this out
530 : * since a new unit may have been connected before we handle
531 : * the disconnect.
532 : */
533 0 : if (up->device != NULL) {
534 : /* Disconnected */
535 0 : usbd_detach(up->device, &sc->sc_dev);
536 0 : up->device = NULL;
537 0 : }
538 :
539 : /* Nothing connected, just ignore it. */
540 0 : if ((status & UPS_CURRENT_CONNECT_STATUS) == 0)
541 0 : return (0);
542 :
543 : /* Connected */
544 0 : if ((status & (UPS_PORT_POWER|UPS_PORT_POWER_SS)) == 0) {
545 0 : printf("%s: connected port %d has no power\n", DEVNAME(sc),
546 : port);
547 0 : return (-1);
548 : }
549 :
550 : /* Wait for maximum device power up time. */
551 0 : usbd_delay_ms(sc->sc_hub, USB_PORT_POWERUP_DELAY);
552 :
553 : /* Reset port, which implies enabling it. */
554 0 : if (usbd_reset_port(sc->sc_hub, port)) {
555 0 : printf("%s: port %d reset failed\n", DEVNAME(sc), port);
556 0 : return (-1);
557 : }
558 : /* Get port status again, it might have changed during reset */
559 0 : if (usbd_get_port_status(sc->sc_hub, port, &up->status))
560 0 : return (-1);
561 :
562 0 : status = UGETW(up->status.wPortStatus);
563 0 : change = UGETW(up->status.wPortChange);
564 : DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", DEVNAME(sc),
565 : port, status, change);
566 :
567 : /* Nothing connected, just ignore it. */
568 0 : if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) {
569 : DPRINTF("%s: port %d, device disappeared after reset\n",
570 : DEVNAME(sc), port);
571 0 : return (-1);
572 : }
573 :
574 : /*
575 : * Figure out device speed. This is a bit tricky because
576 : * UPS_PORT_POWER_SS and UPS_LOW_SPEED share the same bit.
577 : */
578 0 : if ((status & UPS_PORT_POWER) == 0)
579 0 : status &= ~UPS_PORT_POWER_SS;
580 :
581 0 : if (status & UPS_HIGH_SPEED)
582 0 : speed = USB_SPEED_HIGH;
583 0 : else if (status & UPS_LOW_SPEED)
584 0 : speed = USB_SPEED_LOW;
585 : else {
586 : /*
587 : * If there is no power bit set, it is certainly
588 : * a Super Speed device, so use the speed of its
589 : * parent hub.
590 : */
591 0 : if (status & UPS_PORT_POWER)
592 0 : speed = USB_SPEED_FULL;
593 : else
594 0 : speed = sc->sc_hub->speed;
595 : }
596 :
597 : /*
598 : * Reduce the speed, otherwise we won't setup the proper
599 : * transfer methods.
600 : */
601 0 : if (speed > sc->sc_hub->speed)
602 0 : speed = sc->sc_hub->speed;
603 :
604 : /* Get device info and set its address. */
605 0 : if (usbd_new_device(&sc->sc_dev, sc->sc_hub->bus, sc->sc_hub->depth + 1,
606 : speed, port, up)) {
607 : /*
608 : * The unit refused to accept a new address, or had
609 : * some other serious problem. Since we cannot leave
610 : * at 0 we have to disable the port instead.
611 : */
612 0 : printf("%s: device problem, disabling port %d\n", DEVNAME(sc),
613 : port);
614 0 : usbd_clear_port_feature(sc->sc_hub, port, UHF_PORT_ENABLE);
615 :
616 0 : return (-1);
617 : }
618 :
619 0 : return (0);
620 0 : }
|