Annotation of src/sys/dev/usb/uhub.c, Revision 1.109.4.1
1.109.4.1! rmind 1: /* $NetBSD$ */
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.109.4.1! rmind 39: __KERNEL_RCSID(0, "$NetBSD$");
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.109.4.1! rmind 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.109.4.1! rmind 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 */
71: u_int8_t *sc_statusbuf;
1.84 drochner 72: u_int8_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);
190: DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
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.87 drochner 262: USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf,
263: sc->sc_statuslen, uhub_intr, USBD_DEFAULT_INTERVAL);
1.33 augustss 264: if (err) {
1.98 cube 265: aprint_error_dev(self, "cannot open interrupt pipe\n");
1.18 augustss 266: goto bad;
1.1 augustss 267: }
268:
1.11 augustss 269: /* Wait with power off for a while. */
1.13 augustss 270: usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
1.11 augustss 271:
1.105 dyoung 272: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, sc->sc_dev);
1.37 augustss 273:
1.42 augustss 274: /*
275: * To have the best chance of success we do things in the exact same
276: * order as Windoze98. This should not be necessary, but some
277: * devices do not follow the USB specs to the letter.
278: *
279: * These are the events on the bus when a hub is attached:
280: * Get device and config descriptors (see attach code)
281: * Get hub descriptor (see above)
282: * For all ports
283: * turn on power
284: * wait for power to become stable
285: * (all below happens in explore code)
286: * For all ports
287: * clear C_PORT_CONNECTION
288: * For all ports
289: * get port status
290: * if device connected
1.57 augustss 291: * wait 100 ms
1.42 augustss 292: * turn on reset
293: * wait
294: * clear C_PORT_RESET
295: * get port status
296: * proceed with device attachment
297: */
298:
1.83 drochner 299: #if 0
1.78 christos 300: if (UHUB_IS_HIGH_SPEED(sc) && nports > 0) {
1.70 augustss 301: tts = malloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
302: sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
303: if (!tts)
304: goto bad;
305: }
1.83 drochner 306: #endif
1.42 augustss 307: /* Set up data structures */
1.11 augustss 308: for (p = 0; p < nports; p++) {
309: struct usbd_port *up = &hub->ports[p];
1.70 augustss 310: up->device = NULL;
1.11 augustss 311: up->parent = dev;
312: up->portno = p+1;
1.42 augustss 313: if (dev->self_powered)
314: /* Self powered hub, give ports maximum current. */
315: up->power = USB_MAX_POWER;
316: else
317: up->power = USB_MIN_POWER;
1.67 petrov 318: up->restartcnt = 0;
1.72 joff 319: up->reattach = 0;
1.83 drochner 320: #if 0
1.70 augustss 321: if (UHUB_IS_HIGH_SPEED(sc)) {
322: up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
323: up->tt->hub = hub;
324: } else {
325: up->tt = NULL;
326: }
1.83 drochner 327: #endif
1.42 augustss 328: }
329:
330: /* XXX should check for none, individual, or ganged power? */
331:
332: pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
333: + USB_EXTRA_POWER_UP_TIME;
334: for (port = 1; port <= nports; port++) {
335: /* Turn the power on. */
336: err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
1.33 augustss 337: if (err)
1.98 cube 338: aprint_error_dev(self, "port %d power on failed, %s\n",
339: port, usbd_errstr(err));
1.42 augustss 340: DPRINTF(("usb_init_port: turn on port %d power\n", port));
1.94 jmcneill 341: }
342:
343: /* Wait for stable power if we are not a root hub */
344: if (dev->powersrc->parent != NULL)
1.42 augustss 345: usbd_delay_ms(dev, pwrdly);
346:
347: /* The usual exploration will finish the setup. */
348:
1.1 augustss 349: sc->sc_running = 1;
1.11 augustss 350:
1.92 jmcneill 351: if (!pmf_device_register(self, NULL, NULL))
352: aprint_error_dev(self, "couldn't establish power handler\n");
353:
1.107 dyoung 354: return;
1.11 augustss 355:
1.18 augustss 356: bad:
1.84 drochner 357: if (sc->sc_status)
358: free(sc->sc_status, M_USBDEV);
1.101 drochner 359: if (sc->sc_statusbuf)
360: free(sc->sc_statusbuf, M_USBDEV);
1.70 augustss 361: if (hub)
362: free(hub, M_USBDEV);
363: dev->hub = NULL;
1.107 dyoung 364: return;
1.11 augustss 365: }
366:
1.1 augustss 367: usbd_status
1.45 augustss 368: uhub_explore(usbd_device_handle dev)
1.1 augustss 369: {
370: usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
1.11 augustss 371: struct uhub_softc *sc = dev->hub->hubsoftc;
1.1 augustss 372: struct usbd_port *up;
1.33 augustss 373: usbd_status err;
1.56 augustss 374: int speed;
1.1 augustss 375: int port;
1.72 joff 376: int change, status, reconnect;
1.1 augustss 377:
1.11 augustss 378: DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
1.1 augustss 379:
380: if (!sc->sc_running)
381: return (USBD_NOT_STARTED);
382:
383: /* Ignore hubs that are too deep. */
384: if (dev->depth > USB_HUB_MAX_DEPTH)
385: return (USBD_TOO_DEEP);
386:
1.101 drochner 387: if (PORTSTAT_ISSET(sc, 0)) { /* hub status change */
388: usb_hub_status_t hs;
389:
390: err = usbd_get_hub_status(dev, &hs);
391: if (err) {
392: DPRINTF(("%s: get hub status failed, err=%d\n",
393: device_xname(sc->sc_dev), err));
394: } else {
395: /* just acknowledge */
396: status = UGETW(hs.wHubStatus);
397: change = UGETW(hs.wHubChange);
398: if (change & UHS_LOCAL_POWER)
399: usbd_clear_hub_feature(dev,
400: UHF_C_HUB_LOCAL_POWER);
401: if (change & UHS_OVER_CURRENT)
402: usbd_clear_hub_feature(dev,
403: UHF_C_HUB_OVER_CURRENT);
404: }
405: }
406:
1.84 drochner 407: for (port = 1; port <= hd->bNbrPorts; port++) {
1.1 augustss 408: up = &dev->hub->ports[port-1];
1.87 drochner 409:
410: /* reattach is needed after firmware upload */
411: reconnect = up->reattach;
412: up->reattach = 0;
413:
414: status = change = 0;
415:
416: /* don't check if no change summary notification */
417: if (PORTSTAT_ISSET(sc, port) || reconnect) {
418: err = usbd_get_port_status(dev, port, &up->status);
419: if (err) {
420: DPRINTF(("uhub_explore: get port stat failed, "
421: "error=%s\n", usbd_errstr(err)));
422: continue;
423: }
424: status = UGETW(up->status.wPortStatus);
425: change = UGETW(up->status.wPortChange);
1.101 drochner 426: #if 0
427: printf("%s port %d: s/c=%x/%x\n",
428: device_xname(sc->sc_dev), port, status, change);
429: #endif
1.87 drochner 430: }
431: if (!change && !reconnect) {
432: /* No status change, just do recursive explore. */
433: if (up->device != NULL && up->device->hub != NULL)
434: up->device->hub->explore(up->device);
1.1 augustss 435: continue;
436: }
1.87 drochner 437:
1.11 augustss 438: if (change & UPS_C_PORT_ENABLED) {
1.35 augustss 439: DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
1.11 augustss 440: usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
1.68 mycroft 441: if (change & UPS_C_CONNECT_STATUS) {
442: /* Ignore the port error if the device
443: vanished. */
444: } else if (status & UPS_PORT_ENABLED) {
1.98 cube 445: aprint_error_dev(sc->sc_dev,
446: "illegal enable change, port %d\n", port);
1.11 augustss 447: } else {
448: /* Port error condition. */
1.47 augustss 449: if (up->restartcnt) /* no message first time */
1.98 cube 450: aprint_error_dev(sc->sc_dev,
451: "port error, restarting port %d\n",
452: port);
1.47 augustss 453:
454: if (up->restartcnt++ < USBD_RESTART_MAX)
1.11 augustss 455: goto disco;
1.47 augustss 456: else
1.98 cube 457: aprint_error_dev(sc->sc_dev,
458: "port error, giving up port %d\n",
459: port);
1.11 augustss 460: }
461: }
1.87 drochner 462:
463: /* XXX handle overcurrent and resume events! */
464:
465: if (!(change & UPS_C_CONNECT_STATUS))
1.1 augustss 466: continue;
1.42 augustss 467:
468: /* We have a connect status change, handle it. */
469:
1.1 augustss 470: DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
471: dev->address, port));
472: usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
473: /*
474: * If there is already a device on the port the change status
475: * must mean that is has disconnected. Looking at the
476: * current connect status is not enough to figure this out
477: * since a new unit may have been connected before we handle
478: * the disconnect.
479: */
1.11 augustss 480: disco:
1.33 augustss 481: if (up->device != NULL) {
1.1 augustss 482: /* Disconnected */
1.35 augustss 483: DPRINTF(("uhub_explore: device addr=%d disappeared "
1.31 augustss 484: "on port %d\n", up->device->address, port));
1.108 dyoung 485: usb_disconnect_port(up, sc->sc_dev, DETACH_FORCE);
1.58 augustss 486: usbd_clear_port_feature(dev, port,
1.1 augustss 487: UHF_C_PORT_CONNECTION);
488: }
1.35 augustss 489: if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
1.42 augustss 490: /* Nothing connected, just ignore it. */
1.35 augustss 491: DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
492: "_STATUS\n", port));
1.1 augustss 493: continue;
1.35 augustss 494: }
1.1 augustss 495:
496: /* Connected */
1.42 augustss 497:
498: if (!(status & UPS_PORT_POWER))
1.98 cube 499: aprint_normal_dev(sc->sc_dev,
500: "strange, connected port %d has no power\n", port);
1.42 augustss 501:
1.1 augustss 502: /* Wait for maximum device power up time. */
1.13 augustss 503: usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
1.11 augustss 504:
1.1 augustss 505: /* Reset port, which implies enabling it. */
1.35 augustss 506: if (usbd_reset_port(dev, port, &up->status)) {
1.98 cube 507: aprint_error_dev(sc->sc_dev,
508: "port %d reset failed\n", port);
1.54 augustss 509: continue;
510: }
511: /* Get port status again, it might have changed during reset */
512: err = usbd_get_port_status(dev, port, &up->status);
513: if (err) {
514: DPRINTF(("uhub_explore: get port status failed, "
515: "error=%s\n", usbd_errstr(err)));
516: continue;
517: }
518: status = UGETW(up->status.wPortStatus);
519: change = UGETW(up->status.wPortChange);
520: if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
521: /* Nothing connected, just ignore it. */
522: #ifdef DIAGNOSTIC
1.98 cube 523: aprint_debug_dev(sc->sc_dev,
524: "port %d, device disappeared after reset\n", port);
1.54 augustss 525: #endif
1.1 augustss 526: continue;
1.35 augustss 527: }
1.109.4.1! rmind 528: if (!(status & UPS_PORT_ENABLED)) {
! 529: /* Not allowed send/receive packet. */
! 530: #ifdef DIAGNOSTIC
! 531: printf("%s: port %d, device not enable\n",
! 532: device_xname(sc->sc_dev), port);
! 533: #endif
! 534: continue;
! 535: }
1.1 augustss 536:
1.56 augustss 537: /* Figure out device speed */
538: if (status & UPS_HIGH_SPEED)
539: speed = USB_SPEED_HIGH;
540: else if (status & UPS_LOW_SPEED)
541: speed = USB_SPEED_LOW;
542: else
543: speed = USB_SPEED_FULL;
1.1 augustss 544: /* Get device info and set its address. */
1.105 dyoung 545: err = usbd_new_device(sc->sc_dev, dev->bus,
1.56 augustss 546: dev->depth + 1, speed, port, up);
1.1 augustss 547: /* XXX retry a few times? */
1.33 augustss 548: if (err) {
1.10 drochner 549: DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
1.33 augustss 550: "error=%s\n", usbd_errstr(err)));
1.1 augustss 551: /* Avoid addressing problems by disabling. */
552: /* usbd_reset_port(dev, port, &up->status); */
1.30 augustss 553:
1.58 augustss 554: /*
1.30 augustss 555: * The unit refused to accept a new address, or had
556: * some other serious problem. Since we cannot leave
557: * at 0 we have to disable the port instead.
558: */
1.98 cube 559: aprint_error_dev(sc->sc_dev,
560: "device problem, disabling port %d\n", port);
1.30 augustss 561: usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
1.1 augustss 562: } else {
1.47 augustss 563: /* The port set up succeeded, reset error count. */
564: up->restartcnt = 0;
565:
1.34 augustss 566: if (up->device->hub)
1.11 augustss 567: up->device->hub->explore(up->device);
1.1 augustss 568: }
569: }
1.87 drochner 570: /* enable status change notifications again */
1.101 drochner 571: if (!sc->sc_isehciroothub)
572: memset(sc->sc_status, 0, sc->sc_statuslen);
1.87 drochner 573: sc->sc_explorepending = 0;
1.1 augustss 574: return (USBD_NORMAL_COMPLETION);
575: }
576:
1.18 augustss 577: /*
578: * Called from process context when the hub is gone.
579: * Detach all devices on active ports.
580: */
1.105 dyoung 581: int
582: uhub_detach(device_t self, int flags)
1.18 augustss 583: {
1.107 dyoung 584: struct uhub_softc *sc = device_private(self);
1.39 augustss 585: struct usbd_hub *hub = sc->sc_hub->hub;
1.18 augustss 586: struct usbd_port *rup;
1.108 dyoung 587: int nports, port, rc;
1.18 augustss 588:
589: DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
590:
1.39 augustss 591: if (hub == NULL) /* Must be partially working */
1.18 augustss 592: return (0);
593:
1.39 augustss 594: nports = hub->hubdesc.bNbrPorts;
1.32 augustss 595: for(port = 0; port < nports; port++) {
1.39 augustss 596: rup = &hub->ports[port];
1.108 dyoung 597: if (rup->device == NULL)
598: continue;
599: if ((rc = usb_disconnect_port(rup, self, flags)) != 0)
600: return rc;
1.18 augustss 601: }
1.58 augustss 602:
1.108 dyoung 603: pmf_device_deregister(self);
604: usbd_abort_pipe(sc->sc_ipipe);
605: usbd_close_pipe(sc->sc_ipipe);
606:
1.105 dyoung 607: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub, sc->sc_dev);
1.37 augustss 608:
1.83 drochner 609: #if 0
1.70 augustss 610: if (hub->ports[0].tt)
611: free(hub->ports[0].tt, M_USBDEV);
1.83 drochner 612: #endif
1.71 augustss 613: free(hub, M_USBDEV);
1.39 augustss 614: sc->sc_hub->hub = NULL;
1.84 drochner 615: if (sc->sc_status)
616: free(sc->sc_status, M_USBDEV);
1.101 drochner 617: if (sc->sc_statusbuf)
618: free(sc->sc_statusbuf, M_USBDEV);
1.18 augustss 619:
620: return (0);
621: }
1.34 augustss 622:
1.103 kent 623: int
624: uhub_rescan(device_t self, const char *ifattr, const int *locators)
625: {
626: struct uhub_softc *sc = device_private(self);
627: struct usbd_hub *hub = sc->sc_hub->hub;
628: usbd_device_handle dev;
629: int port, err;
630:
631: for (port = 0; port < hub->hubdesc.bNbrPorts; port++) {
632: dev = hub->ports[port].device;
633: if (dev == NULL)
634: continue;
1.105 dyoung 635: err = usbd_reattach_device(sc->sc_dev, dev, port, locators);
1.103 kent 636: }
637: return 0;
638: }
639:
1.34 augustss 640: /* Called when a device has been detached from it */
1.95 dyoung 641: void
642: uhub_childdet(device_t self, device_t child)
1.34 augustss 643: {
1.95 dyoung 644: struct uhub_softc *sc = device_private(self);
645: usbd_device_handle devhub = sc->sc_hub;
646: usbd_device_handle dev;
647: int nports;
648: int port;
649: int i;
650:
651: if (!devhub->hub)
652: /* should never happen; children are only created after init */
653: panic("hub not fully initialised, but child deleted?");
654:
655: nports = devhub->hub->hubdesc.bNbrPorts;
656: for (port = 0; port < nports; port++) {
657: dev = devhub->hub->ports[port].device;
1.99 drochner 658: if (!dev)
1.95 dyoung 659: continue;
1.99 drochner 660: for (i = 0; i < dev->subdevlen; i++) {
1.95 dyoung 661: if (dev->subdevs[i] == child) {
662: dev->subdevs[i] = NULL;
1.102 drochner 663: dev->nifaces_claimed--;
1.95 dyoung 664: }
665: }
666: }
1.34 augustss 667: }
668:
1.18 augustss 669:
670: /*
671: * Hub interrupt.
672: * This an indication that some port has changed status.
673: * Notify the bus event handler thread that we need
674: * to be explored again.
675: */
1.1 augustss 676: void
1.105 dyoung 677: uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
1.1 augustss 678: {
679: struct uhub_softc *sc = addr;
680:
1.11 augustss 681: DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
1.87 drochner 682:
1.50 augustss 683: if (status == USBD_STALLED)
1.9 augustss 684: usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.87 drochner 685: else if (status == USBD_NORMAL_COMPLETION &&
686: !sc->sc_explorepending) {
687: /*
688: * Make sure the status is not overwritten in between.
689: * XXX we should suspend the pipe instead
690: */
691: memcpy(sc->sc_status, sc->sc_statusbuf, sc->sc_statuslen);
692: sc->sc_explorepending = 1;
1.50 augustss 693: usb_needs_explore(sc->sc_hub);
1.87 drochner 694: }
1.89 drochner 695: /*
696: * XXX workaround for broken implementation of the interrupt
697: * pipe in EHCI root hub emulation which doesn't resend
698: * status change notifications until handled: force a rescan
699: * of the ports we touched in the last run
700: */
701: if (status == USBD_NORMAL_COMPLETION && sc->sc_explorepending &&
1.101 drochner 702: sc->sc_isehciroothub)
1.89 drochner 703: usb_needs_explore(sc->sc_hub);
1.1 augustss 704: }
CVSweb <webmaster@jp.NetBSD.org>