Annotation of src/sys/dev/usb/uhub.c, Revision 1.126.2.1
1.126.2.1! skrll 1: /* $NetBSD: uhub.c,v 1.126 2014/08/13 06:26:32 skrll Exp $ */
1.34 augustss 2: /* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
1.1 augustss 3:
4: /*
1.74 mycroft 5: * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
1.1 augustss 6: * All rights reserved.
7: *
1.6 augustss 8: * This code is derived from software contributed to The NetBSD Foundation
1.44 augustss 9: * by Lennart Augustsson (lennart@augustsson.net) at
1.6 augustss 10: * Carlstedt Research & Technology.
1.1 augustss 11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31: * POSSIBILITY OF SUCH DAMAGE.
1.15 augustss 32: */
33:
34: /*
1.64 ichiro 35: * USB spec: http://www.usb.org/developers/docs/usbspec.zip
1.1 augustss 36: */
1.53 lukem 37:
38: #include <sys/cdefs.h>
1.126.2.1! skrll 39: __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.126 2014/08/13 06:26:32 skrll Exp $");
1.1 augustss 40:
41: #include <sys/param.h>
42: #include <sys/systm.h>
43: #include <sys/kernel.h>
44: #include <sys/malloc.h>
45: #include <sys/device.h>
1.34 augustss 46: #include <sys/proc.h>
1.28 augustss 47:
1.90 ad 48: #include <sys/bus.h>
1.1 augustss 49:
50: #include <dev/usb/usb.h>
51: #include <dev/usb/usbdi.h>
52: #include <dev/usb/usbdi_util.h>
53: #include <dev/usb/usbdivar.h>
54:
1.32 augustss 55: #ifdef UHUB_DEBUG
1.111 dyoung 56: #define DPRINTF(x) if (uhubdebug) printf x
57: #define DPRINTFN(n,x) if (uhubdebug>(n)) printf x
1.63 dsainty 58: int uhubdebug = 0;
1.1 augustss 59: #else
60: #define DPRINTF(x)
61: #define DPRINTFN(n,x)
62: #endif
63:
64: struct uhub_softc {
1.111 dyoung 65: device_t sc_dev; /* base device */
1.11 augustss 66: usbd_device_handle sc_hub; /* USB device */
1.86 drochner 67: int sc_proto; /* device protocol */
1.11 augustss 68: usbd_pipe_handle sc_ipipe; /* interrupt pipe */
1.87 drochner 69:
70: /* XXX second buffer needed because we can't suspend pipes yet */
1.126.2.1! skrll 71: uint8_t *sc_statusbuf;
! 72: uint8_t *sc_status;
1.87 drochner 73: size_t sc_statuslen;
74: int sc_explorepending;
1.101 drochner 75: int sc_isehciroothub; /* see comment in uhub_intr() */
1.87 drochner 76:
1.11 augustss 77: u_char sc_running;
1.1 augustss 78: };
1.87 drochner 79:
1.86 drochner 80: #define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
81: #define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
1.1 augustss 82:
1.87 drochner 83: #define PORTSTAT_ISSET(sc, port) \
84: ((sc)->sc_status[(port) / 8] & (1 << ((port) % 8)))
85:
1.45 augustss 86: Static usbd_status uhub_explore(usbd_device_handle hub);
87: Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status);
1.1 augustss 88:
1.32 augustss 89:
1.58 augustss 90: /*
1.32 augustss 91: * We need two attachment points:
92: * hub to usb and hub to hub
93: * Every other driver only connects to hubs
94: */
1.1 augustss 95:
1.98 cube 96: int uhub_match(device_t, cfdata_t, void *);
1.95 dyoung 97: void uhub_attach(device_t, device_t, void *);
1.103 kent 98: int uhub_rescan(device_t, const char *, const int *);
1.95 dyoung 99: void uhub_childdet(device_t, device_t);
100: int uhub_detach(device_t, int);
101: extern struct cfdriver uhub_cd;
1.104 dyoung 102: CFATTACH_DECL3_NEW(uhub, sizeof(struct uhub_softc), uhub_match,
1.108 dyoung 103: uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet,
1.104 dyoung 104: DVF_DETACH_SHUTDOWN);
1.99 drochner 105: CFATTACH_DECL2_NEW(uroothub, sizeof(struct uhub_softc), uhub_match,
1.108 dyoung 106: uhub_attach, uhub_detach, NULL, uhub_rescan, uhub_childdet);
1.1 augustss 107:
1.109 pooka 108: /*
109: * Setting this to 1 makes sure than an uhub attaches even at higher
110: * priority than ugen when ugen_override is set to 1. This allows to
111: * probe the whole USB bus and attach functions with ugen.
112: */
113: int uhub_ubermatch = 0;
114:
1.105 dyoung 115: int
116: uhub_match(device_t parent, cfdata_t match, void *aux)
1.1 augustss 117: {
1.107 dyoung 118: struct usb_attach_arg *uaa = aux;
1.109 pooka 119: int matchvalue;
120:
121: if (uhub_ubermatch)
122: matchvalue = UMATCH_HIGHEST+1;
123: else
124: matchvalue = UMATCH_DEVCLASS_DEVSUBCLASS;
1.58 augustss 125:
1.88 drochner 126: DPRINTFN(5,("uhub_match, uaa=%p\n", uaa));
1.58 augustss 127: /*
1.1 augustss 128: * The subclass for hubs seems to be 0 for some and 1 for others,
129: * so we just ignore the subclass.
130: */
1.86 drochner 131: if (uaa->class == UDCLASS_HUB)
1.109 pooka 132: return (matchvalue);
1.1 augustss 133: return (UMATCH_NONE);
134: }
135:
1.105 dyoung 136: void
137: uhub_attach(device_t parent, device_t self, void *aux)
1.1 augustss 138: {
1.107 dyoung 139: struct uhub_softc *sc = device_private(self);
140: struct usb_attach_arg *uaa = aux;
1.1 augustss 141: usbd_device_handle dev = uaa->device;
1.76 augustss 142: char *devinfop;
1.33 augustss 143: usbd_status err;
1.70 augustss 144: struct usbd_hub *hub = NULL;
1.1 augustss 145: usb_device_request_t req;
146: usb_hub_descriptor_t hubdesc;
1.42 augustss 147: int p, port, nports, nremov, pwrdly;
1.1 augustss 148: usbd_interface_handle iface;
149: usb_endpoint_descriptor_t *ed;
1.83 drochner 150: #if 0 /* notyet */
1.70 augustss 151: struct usbd_tt *tts = NULL;
1.83 drochner 152: #endif
1.58 augustss 153:
1.1 augustss 154: DPRINTFN(1,("uhub_attach\n"));
1.98 cube 155: sc->sc_dev = self;
1.1 augustss 156: sc->sc_hub = dev;
1.86 drochner 157: sc->sc_proto = uaa->proto;
1.76 augustss 158:
159: devinfop = usbd_devinfo_alloc(dev, 1);
1.96 jmcneill 160: aprint_naive("\n");
161: aprint_normal(": %s\n", devinfop);
1.76 augustss 162: usbd_devinfo_free(devinfop);
1.1 augustss 163:
1.75 augustss 164: if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
1.98 cube 165: aprint_normal_dev(self, "%s transaction translator%s\n",
1.70 augustss 166: UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
167: UHUB_IS_SINGLE_TT(sc) ? "" : "s");
1.69 augustss 168: }
169:
1.33 augustss 170: err = usbd_set_config_index(dev, 0, 1);
171: if (err) {
1.21 augustss 172: DPRINTF(("%s: configuration failed, error=%s\n",
1.105 dyoung 173: device_xname(sc->sc_dev), usbd_errstr(err)));
1.107 dyoung 174: return;
1.1 augustss 175: }
176:
177: if (dev->depth > USB_HUB_MAX_DEPTH) {
1.98 cube 178: aprint_error_dev(self,
179: "hub depth (%d) exceeded, hub ignored\n",
180: USB_HUB_MAX_DEPTH);
1.107 dyoung 181: return;
1.1 augustss 182: }
183:
184: /* Get hub descriptor. */
185: req.bmRequestType = UT_READ_CLASS_DEVICE;
186: req.bRequest = UR_GET_DESCRIPTOR;
1.65 toshii 187: USETW2(req.wValue, UDESC_HUB, 0);
1.1 augustss 188: USETW(req.wIndex, 0);
189: USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
1.119 skrll 190: DPRINTFN(1,("%s: getting hub descriptor\n", __func__));
1.33 augustss 191: err = usbd_do_request(dev, &req, &hubdesc);
1.11 augustss 192: nports = hubdesc.bNbrPorts;
1.33 augustss 193: if (!err && nports > 7) {
1.11 augustss 194: USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
1.33 augustss 195: err = usbd_do_request(dev, &req, &hubdesc);
1.11 augustss 196: }
1.33 augustss 197: if (err) {
1.21 augustss 198: DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
1.105 dyoung 199: device_xname(sc->sc_dev), usbd_errstr(err)));
1.107 dyoung 200: return;
1.1 augustss 201: }
202:
1.11 augustss 203: for (nremov = 0, port = 1; port <= nports; port++)
204: if (!UHD_NOT_REMOV(&hubdesc, port))
205: nremov++;
1.98 cube 206: aprint_verbose_dev(self, "%d port%s with %d removable, %s powered\n",
207: nports, nports != 1 ? "s" : "", nremov,
208: dev->self_powered ? "self" : "bus");
1.11 augustss 209:
1.70 augustss 210: if (nports == 0) {
1.98 cube 211: aprint_debug_dev(self, "no ports, hub ignored\n");
1.70 augustss 212: goto bad;
213: }
214:
1.1 augustss 215: hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
1.18 augustss 216: M_USBDEV, M_NOWAIT);
1.33 augustss 217: if (hub == NULL)
1.107 dyoung 218: return;
1.1 augustss 219: dev->hub = hub;
1.11 augustss 220: dev->hub->hubsoftc = sc;
1.1 augustss 221: hub->explore = uhub_explore;
222: hub->hubdesc = hubdesc;
1.58 augustss 223:
1.1 augustss 224: /* Set up interrupt pipe. */
1.33 augustss 225: err = usbd_device2interface_handle(dev, 0, &iface);
226: if (err) {
1.98 cube 227: aprint_error_dev(self, "no interface handle\n");
1.18 augustss 228: goto bad;
1.1 augustss 229: }
1.83 drochner 230:
231: if (UHUB_IS_HIGH_SPEED(sc) && !UHUB_IS_SINGLE_TT(sc)) {
232: err = usbd_set_interface(iface, 1);
233: if (err)
1.98 cube 234: aprint_error_dev(self, "can't enable multiple TTs\n");
1.83 drochner 235: }
236:
1.1 augustss 237: ed = usbd_interface2endpoint_descriptor(iface, 0);
1.33 augustss 238: if (ed == NULL) {
1.98 cube 239: aprint_error_dev(self, "no endpoint descriptor\n");
1.18 augustss 240: goto bad;
1.1 augustss 241: }
242: if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
1.98 cube 243: aprint_error_dev(self, "bad interrupt endpoint\n");
1.18 augustss 244: goto bad;
1.1 augustss 245: }
246:
1.87 drochner 247: sc->sc_statuslen = (nports + 1 + 7) / 8;
248: sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
249: if (!sc->sc_statusbuf)
250: goto bad;
251: sc->sc_status = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
1.84 drochner 252: if (!sc->sc_status)
253: goto bad;
1.101 drochner 254: if (device_is_a(device_parent(device_parent(sc->sc_dev)), "ehci"))
255: sc->sc_isehciroothub = 1;
1.84 drochner 256:
1.87 drochner 257: /* force initial scan */
258: memset(sc->sc_status, 0xff, sc->sc_statuslen);
259: sc->sc_explorepending = 1;
260:
1.33 augustss 261: err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
1.122 jmcneill 262: USBD_SHORT_XFER_OK|USBD_MPSAFE, &sc->sc_ipipe, sc,
263: sc->sc_statusbuf, sc->sc_statuslen,
264: uhub_intr, USBD_DEFAULT_INTERVAL);
1.33 augustss 265: if (err) {
1.98 cube 266: aprint_error_dev(self, "cannot open interrupt pipe\n");
1.18 augustss 267: goto bad;
1.1 augustss 268: }
269:
1.11 augustss 270: /* Wait with power off for a while. */
1.13 augustss 271: usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
1.11 augustss 272:
1.105 dyoung 273: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, sc->sc_dev);
1.37 augustss 274:
1.42 augustss 275: /*
276: * To have the best chance of success we do things in the exact same
1.123 jakllsch 277: * order as Windows 98. This should not be necessary, but some
1.42 augustss 278: * devices do not follow the USB specs to the letter.
279: *
280: * These are the events on the bus when a hub is attached:
281: * Get device and config descriptors (see attach code)
282: * Get hub descriptor (see above)
283: * For all ports
284: * turn on power
285: * wait for power to become stable
286: * (all below happens in explore code)
287: * For all ports
288: * clear C_PORT_CONNECTION
289: * For all ports
290: * get port status
291: * if device connected
1.57 augustss 292: * wait 100 ms
1.42 augustss 293: * turn on reset
294: * wait
295: * clear C_PORT_RESET
296: * get port status
297: * proceed with device attachment
298: */
299:
1.83 drochner 300: #if 0
1.78 christos 301: if (UHUB_IS_HIGH_SPEED(sc) && nports > 0) {
1.70 augustss 302: tts = malloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
303: sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
304: if (!tts)
305: goto bad;
306: }
1.83 drochner 307: #endif
1.42 augustss 308: /* Set up data structures */
1.11 augustss 309: for (p = 0; p < nports; p++) {
310: struct usbd_port *up = &hub->ports[p];
1.70 augustss 311: up->device = NULL;
1.11 augustss 312: up->parent = dev;
313: up->portno = p+1;
1.42 augustss 314: if (dev->self_powered)
315: /* Self powered hub, give ports maximum current. */
316: up->power = USB_MAX_POWER;
317: else
318: up->power = USB_MIN_POWER;
1.67 petrov 319: up->restartcnt = 0;
1.72 joff 320: up->reattach = 0;
1.83 drochner 321: #if 0
1.70 augustss 322: if (UHUB_IS_HIGH_SPEED(sc)) {
323: up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
324: up->tt->hub = hub;
325: } else {
326: up->tt = NULL;
327: }
1.83 drochner 328: #endif
1.42 augustss 329: }
330:
331: /* XXX should check for none, individual, or ganged power? */
332:
333: pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
334: + USB_EXTRA_POWER_UP_TIME;
335: for (port = 1; port <= nports; port++) {
336: /* Turn the power on. */
337: err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
1.33 augustss 338: if (err)
1.98 cube 339: aprint_error_dev(self, "port %d power on failed, %s\n",
340: port, usbd_errstr(err));
1.42 augustss 341: DPRINTF(("usb_init_port: turn on port %d power\n", port));
1.94 jmcneill 342: }
343:
344: /* Wait for stable power if we are not a root hub */
345: if (dev->powersrc->parent != NULL)
1.42 augustss 346: usbd_delay_ms(dev, pwrdly);
347:
348: /* The usual exploration will finish the setup. */
349:
1.1 augustss 350: sc->sc_running = 1;
1.11 augustss 351:
1.92 jmcneill 352: if (!pmf_device_register(self, NULL, NULL))
353: aprint_error_dev(self, "couldn't establish power handler\n");
354:
1.107 dyoung 355: return;
1.11 augustss 356:
1.18 augustss 357: bad:
1.84 drochner 358: if (sc->sc_status)
359: free(sc->sc_status, M_USBDEV);
1.101 drochner 360: if (sc->sc_statusbuf)
361: free(sc->sc_statusbuf, M_USBDEV);
1.70 augustss 362: if (hub)
363: free(hub, M_USBDEV);
364: dev->hub = NULL;
1.107 dyoung 365: return;
1.11 augustss 366: }
367:
1.1 augustss 368: usbd_status
1.45 augustss 369: uhub_explore(usbd_device_handle dev)
1.1 augustss 370: {
371: usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
1.11 augustss 372: struct uhub_softc *sc = dev->hub->hubsoftc;
1.1 augustss 373: struct usbd_port *up;
1.33 augustss 374: usbd_status err;
1.56 augustss 375: int speed;
1.1 augustss 376: int port;
1.72 joff 377: int change, status, reconnect;
1.1 augustss 378:
1.11 augustss 379: DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
1.1 augustss 380:
381: if (!sc->sc_running)
382: return (USBD_NOT_STARTED);
383:
384: /* Ignore hubs that are too deep. */
385: if (dev->depth > USB_HUB_MAX_DEPTH)
386: return (USBD_TOO_DEEP);
387:
1.101 drochner 388: if (PORTSTAT_ISSET(sc, 0)) { /* hub status change */
389: usb_hub_status_t hs;
390:
391: err = usbd_get_hub_status(dev, &hs);
392: if (err) {
393: DPRINTF(("%s: get hub status failed, err=%d\n",
394: device_xname(sc->sc_dev), err));
395: } else {
396: /* just acknowledge */
397: status = UGETW(hs.wHubStatus);
398: change = UGETW(hs.wHubChange);
399: if (change & UHS_LOCAL_POWER)
400: usbd_clear_hub_feature(dev,
401: UHF_C_HUB_LOCAL_POWER);
402: if (change & UHS_OVER_CURRENT)
403: usbd_clear_hub_feature(dev,
404: UHF_C_HUB_OVER_CURRENT);
405: }
406: }
407:
1.84 drochner 408: for (port = 1; port <= hd->bNbrPorts; port++) {
1.1 augustss 409: up = &dev->hub->ports[port-1];
1.87 drochner 410:
411: /* reattach is needed after firmware upload */
412: reconnect = up->reattach;
413: up->reattach = 0;
414:
415: status = change = 0;
416:
417: /* don't check if no change summary notification */
418: if (PORTSTAT_ISSET(sc, port) || reconnect) {
419: err = usbd_get_port_status(dev, port, &up->status);
420: if (err) {
421: DPRINTF(("uhub_explore: get port stat failed, "
422: "error=%s\n", usbd_errstr(err)));
423: continue;
424: }
425: status = UGETW(up->status.wPortStatus);
426: change = UGETW(up->status.wPortChange);
1.101 drochner 427: #if 0
428: printf("%s port %d: s/c=%x/%x\n",
429: device_xname(sc->sc_dev), port, status, change);
430: #endif
1.87 drochner 431: }
432: if (!change && !reconnect) {
433: /* No status change, just do recursive explore. */
434: if (up->device != NULL && up->device->hub != NULL)
435: up->device->hub->explore(up->device);
1.1 augustss 436: continue;
437: }
1.87 drochner 438:
1.11 augustss 439: if (change & UPS_C_PORT_ENABLED) {
1.35 augustss 440: DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
1.11 augustss 441: usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
1.68 mycroft 442: if (change & UPS_C_CONNECT_STATUS) {
443: /* Ignore the port error if the device
444: vanished. */
445: } else if (status & UPS_PORT_ENABLED) {
1.98 cube 446: aprint_error_dev(sc->sc_dev,
447: "illegal enable change, port %d\n", port);
1.11 augustss 448: } else {
449: /* Port error condition. */
1.47 augustss 450: if (up->restartcnt) /* no message first time */
1.98 cube 451: aprint_error_dev(sc->sc_dev,
452: "port error, restarting port %d\n",
453: port);
1.47 augustss 454:
455: if (up->restartcnt++ < USBD_RESTART_MAX)
1.11 augustss 456: goto disco;
1.47 augustss 457: else
1.98 cube 458: aprint_error_dev(sc->sc_dev,
459: "port error, giving up port %d\n",
460: port);
1.11 augustss 461: }
462: }
1.87 drochner 463:
464: /* XXX handle overcurrent and resume events! */
465:
1.116 jakllsch 466: if (!reconnect && !(change & UPS_C_CONNECT_STATUS)) {
467: /* No status change, just do recursive explore. */
468: if (up->device != NULL && up->device->hub != NULL)
469: up->device->hub->explore(up->device);
1.1 augustss 470: continue;
1.116 jakllsch 471: }
1.42 augustss 472:
473: /* We have a connect status change, handle it. */
474:
1.1 augustss 475: DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
476: dev->address, port));
477: usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
478: /*
479: * If there is already a device on the port the change status
480: * must mean that is has disconnected. Looking at the
481: * current connect status is not enough to figure this out
482: * since a new unit may have been connected before we handle
483: * the disconnect.
484: */
1.11 augustss 485: disco:
1.33 augustss 486: if (up->device != NULL) {
1.1 augustss 487: /* Disconnected */
1.35 augustss 488: DPRINTF(("uhub_explore: device addr=%d disappeared "
1.31 augustss 489: "on port %d\n", up->device->address, port));
1.108 dyoung 490: usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
1.58 augustss 491: usbd_clear_port_feature(dev, port,
1.1 augustss 492: UHF_C_PORT_CONNECTION);
493: }
1.35 augustss 494: if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
1.42 augustss 495: /* Nothing connected, just ignore it. */
1.35 augustss 496: DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
497: "_STATUS\n", port));
1.1 augustss 498: continue;
1.35 augustss 499: }
1.1 augustss 500:
501: /* Connected */
1.42 augustss 502:
503: if (!(status & UPS_PORT_POWER))
1.98 cube 504: aprint_normal_dev(sc->sc_dev,
505: "strange, connected port %d has no power\n", port);
1.42 augustss 506:
1.1 augustss 507: /* Wait for maximum device power up time. */
1.13 augustss 508: usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
1.11 augustss 509:
1.1 augustss 510: /* Reset port, which implies enabling it. */
1.35 augustss 511: if (usbd_reset_port(dev, port, &up->status)) {
1.98 cube 512: aprint_error_dev(sc->sc_dev,
513: "port %d reset failed\n", port);
1.54 augustss 514: continue;
515: }
516: /* Get port status again, it might have changed during reset */
517: err = usbd_get_port_status(dev, port, &up->status);
518: if (err) {
519: DPRINTF(("uhub_explore: get port status failed, "
520: "error=%s\n", usbd_errstr(err)));
521: continue;
522: }
523: status = UGETW(up->status.wPortStatus);
524: change = UGETW(up->status.wPortChange);
525: if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
526: /* Nothing connected, just ignore it. */
527: #ifdef DIAGNOSTIC
1.98 cube 528: aprint_debug_dev(sc->sc_dev,
529: "port %d, device disappeared after reset\n", port);
1.54 augustss 530: #endif
1.1 augustss 531: continue;
1.35 augustss 532: }
1.110 kiyohara 533: if (!(status & UPS_PORT_ENABLED)) {
534: /* Not allowed send/receive packet. */
535: #ifdef DIAGNOSTIC
1.115 sborrill 536: printf("%s: port %d, device not enabled\n",
1.112 dyoung 537: device_xname(sc->sc_dev), port);
1.110 kiyohara 538: #endif
539: continue;
540: }
1.1 augustss 541:
1.56 augustss 542: /* Figure out device speed */
1.126 skrll 543: #if 0
1.125 skrll 544: if (status & UPS_SUPER_SPEED)
545: speed = USB_SPEED_SUPER;
1.126 skrll 546: else
547: #endif
548: if (status & UPS_HIGH_SPEED)
1.56 augustss 549: speed = USB_SPEED_HIGH;
550: else if (status & UPS_LOW_SPEED)
551: speed = USB_SPEED_LOW;
552: else
553: speed = USB_SPEED_FULL;
1.1 augustss 554: /* Get device info and set its address. */
1.105 dyoung 555: err = usbd_new_device(sc->sc_dev, dev->bus,
1.56 augustss 556: dev->depth + 1, speed, port, up);
1.1 augustss 557: /* XXX retry a few times? */
1.33 augustss 558: if (err) {
1.114 matt 559: DPRINTFN(-1,("uhub_explore: usbd_new_device failed, "
1.33 augustss 560: "error=%s\n", usbd_errstr(err)));
1.1 augustss 561: /* Avoid addressing problems by disabling. */
562: /* usbd_reset_port(dev, port, &up->status); */
1.30 augustss 563:
1.58 augustss 564: /*
1.30 augustss 565: * The unit refused to accept a new address, or had
566: * some other serious problem. Since we cannot leave
567: * at 0 we have to disable the port instead.
568: */
1.98 cube 569: aprint_error_dev(sc->sc_dev,
570: "device problem, disabling port %d\n", port);
1.30 augustss 571: usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
1.1 augustss 572: } else {
1.47 augustss 573: /* The port set up succeeded, reset error count. */
574: up->restartcnt = 0;
575:
1.34 augustss 576: if (up->device->hub)
1.11 augustss 577: up->device->hub->explore(up->device);
1.1 augustss 578: }
579: }
1.87 drochner 580: /* enable status change notifications again */
1.101 drochner 581: if (!sc->sc_isehciroothub)
582: memset(sc->sc_status, 0, sc->sc_statuslen);
1.87 drochner 583: sc->sc_explorepending = 0;
1.1 augustss 584: return (USBD_NORMAL_COMPLETION);
585: }
586:
1.18 augustss 587: /*
588: * Called from process context when the hub is gone.
589: * Detach all devices on active ports.
590: */
1.105 dyoung 591: int
592: uhub_detach(device_t self, int flags)
1.18 augustss 593: {
1.107 dyoung 594: struct uhub_softc *sc = device_private(self);
1.39 augustss 595: struct usbd_hub *hub = sc->sc_hub->hub;
1.18 augustss 596: struct usbd_port *rup;
1.108 dyoung 597: int nports, port, rc;
1.18 augustss 598:
599: DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
600:
1.39 augustss 601: if (hub == NULL) /* Must be partially working */
1.18 augustss 602: return (0);
603:
1.117 mrg 604: /* XXXSMP usb */
605: KERNEL_LOCK(1, curlwp);
606:
1.39 augustss 607: nports = hub->hubdesc.bNbrPorts;
1.32 augustss 608: for(port = 0; port < nports; port++) {
1.39 augustss 609: rup = &hub->ports[port];
1.108 dyoung 610: if (rup->device == NULL)
611: continue;
1.117 mrg 612: if ((rc = usb_disconnect_port(rup, self, flags)) != 0) {
613: /* XXXSMP usb */
614: KERNEL_UNLOCK_ONE(curlwp);
615:
1.108 dyoung 616: return rc;
1.117 mrg 617: }
1.18 augustss 618: }
1.58 augustss 619:
1.108 dyoung 620: pmf_device_deregister(self);
621: usbd_abort_pipe(sc->sc_ipipe);
622: usbd_close_pipe(sc->sc_ipipe);
623:
1.105 dyoung 624: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub, sc->sc_dev);
1.37 augustss 625:
1.83 drochner 626: #if 0
1.70 augustss 627: if (hub->ports[0].tt)
628: free(hub->ports[0].tt, M_USBDEV);
1.83 drochner 629: #endif
1.71 augustss 630: free(hub, M_USBDEV);
1.39 augustss 631: sc->sc_hub->hub = NULL;
1.84 drochner 632: if (sc->sc_status)
633: free(sc->sc_status, M_USBDEV);
1.101 drochner 634: if (sc->sc_statusbuf)
635: free(sc->sc_statusbuf, M_USBDEV);
1.18 augustss 636:
1.117 mrg 637: /* XXXSMP usb */
638: KERNEL_UNLOCK_ONE(curlwp);
639:
1.18 augustss 640: return (0);
641: }
1.34 augustss 642:
1.103 kent 643: int
644: uhub_rescan(device_t self, const char *ifattr, const int *locators)
645: {
646: struct uhub_softc *sc = device_private(self);
647: struct usbd_hub *hub = sc->sc_hub->hub;
648: usbd_device_handle dev;
1.124 martin 649: int port;
1.103 kent 650:
651: for (port = 0; port < hub->hubdesc.bNbrPorts; port++) {
652: dev = hub->ports[port].device;
653: if (dev == NULL)
654: continue;
1.124 martin 655: usbd_reattach_device(sc->sc_dev, dev, port, locators);
1.103 kent 656: }
657: return 0;
658: }
659:
1.34 augustss 660: /* Called when a device has been detached from it */
1.95 dyoung 661: void
662: uhub_childdet(device_t self, device_t child)
1.34 augustss 663: {
1.95 dyoung 664: struct uhub_softc *sc = device_private(self);
665: usbd_device_handle devhub = sc->sc_hub;
666: usbd_device_handle dev;
667: int nports;
668: int port;
669: int i;
670:
671: if (!devhub->hub)
672: /* should never happen; children are only created after init */
673: panic("hub not fully initialised, but child deleted?");
674:
675: nports = devhub->hub->hubdesc.bNbrPorts;
676: for (port = 0; port < nports; port++) {
677: dev = devhub->hub->ports[port].device;
1.118 gsutre 678: if (!dev || dev->subdevlen == 0)
1.95 dyoung 679: continue;
1.99 drochner 680: for (i = 0; i < dev->subdevlen; i++) {
1.95 dyoung 681: if (dev->subdevs[i] == child) {
682: dev->subdevs[i] = NULL;
1.102 drochner 683: dev->nifaces_claimed--;
1.95 dyoung 684: }
685: }
1.113 jmcneill 686: if (dev->nifaces_claimed == 0) {
687: free(dev->subdevs, M_USB);
688: dev->subdevs = NULL;
689: dev->subdevlen = 0;
690: }
1.95 dyoung 691: }
1.34 augustss 692: }
693:
1.18 augustss 694:
695: /*
696: * Hub interrupt.
697: * This an indication that some port has changed status.
698: * Notify the bus event handler thread that we need
699: * to be explored again.
700: */
1.1 augustss 701: void
1.105 dyoung 702: uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
1.1 augustss 703: {
704: struct uhub_softc *sc = addr;
705:
1.11 augustss 706: DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
1.87 drochner 707:
1.50 augustss 708: if (status == USBD_STALLED)
1.9 augustss 709: usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.87 drochner 710: else if (status == USBD_NORMAL_COMPLETION &&
711: !sc->sc_explorepending) {
712: /*
713: * Make sure the status is not overwritten in between.
714: * XXX we should suspend the pipe instead
715: */
716: memcpy(sc->sc_status, sc->sc_statusbuf, sc->sc_statuslen);
717: sc->sc_explorepending = 1;
1.50 augustss 718: usb_needs_explore(sc->sc_hub);
1.87 drochner 719: }
1.89 drochner 720: /*
721: * XXX workaround for broken implementation of the interrupt
722: * pipe in EHCI root hub emulation which doesn't resend
723: * status change notifications until handled: force a rescan
724: * of the ports we touched in the last run
725: */
726: if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
1.101 drochner 727: sc->sc_isehciroothub)
1.89 drochner 728: usb_needs_explore(sc->sc_hub);
1.1 augustss 729: }
CVSweb <webmaster@jp.NetBSD.org>