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