Annotation of src/sys/dev/usb/uhub.c, Revision 1.43
1.43 ! augustss 1: /* $NetBSD: uhub.c,v 1.42 2000/04/21 16:05:50 augustss 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: /*
5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
1.6 augustss 8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Lennart Augustsson (augustss@carlstedt.se) at
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: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
1.15 augustss 39: */
40:
41: /*
1.42 augustss 42: * USB spec: http://www.usb.org/developers/docs.htm
1.1 augustss 43: */
44:
45: #include <sys/param.h>
46: #include <sys/systm.h>
47: #include <sys/kernel.h>
48: #include <sys/malloc.h>
1.20 augustss 49: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.1 augustss 50: #include <sys/device.h>
1.34 augustss 51: #include <sys/proc.h>
1.11 augustss 52: #elif defined(__FreeBSD__)
53: #include <sys/module.h>
54: #include <sys/bus.h>
1.32 augustss 55: #include "bus_if.h"
1.11 augustss 56: #endif
1.28 augustss 57:
58: #include <machine/bus.h>
1.1 augustss 59:
60: #include <dev/usb/usb.h>
61: #include <dev/usb/usbdi.h>
62: #include <dev/usb/usbdi_util.h>
63: #include <dev/usb/usbdivar.h>
64:
1.43 ! augustss 65: #define UHUB_INTR_INTERVAL 255 /* ms */
! 66:
1.32 augustss 67: #ifdef UHUB_DEBUG
1.35 augustss 68: #define DPRINTF(x) if (uhubdebug) logprintf x
69: #define DPRINTFN(n,x) if (uhubdebug>(n)) logprintf x
70: int uhubdebug;
1.1 augustss 71: #else
72: #define DPRINTF(x)
73: #define DPRINTFN(n,x)
74: #endif
75:
76: struct uhub_softc {
1.26 augustss 77: USBBASEDEVICE sc_dev; /* base device */
1.11 augustss 78: usbd_device_handle sc_hub; /* USB device */
79: usbd_pipe_handle sc_ipipe; /* interrupt pipe */
80: u_int8_t sc_status[1]; /* XXX more ports */
81: u_char sc_running;
1.1 augustss 82: };
83:
1.41 augustss 84: Static usbd_status uhub_explore __P((usbd_device_handle hub));
85: Static void uhub_intr __P((usbd_xfer_handle, usbd_private_handle,usbd_status));
1.1 augustss 86:
1.32 augustss 87: #if defined(__FreeBSD__)
1.41 augustss 88: Static bus_child_detached_t uhub_child_detached;
1.32 augustss 89: #endif
90:
91:
92: /*
93: * We need two attachment points:
94: * hub to usb and hub to hub
95: * Every other driver only connects to hubs
96: */
1.1 augustss 97:
1.20 augustss 98: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.34 augustss 99: USB_DECLARE_DRIVER(uhub);
100:
1.32 augustss 101: /* Create the driver instance for the hub connected to hub case */
1.1 augustss 102: struct cfattach uhub_uhub_ca = {
1.18 augustss 103: sizeof(struct uhub_softc), uhub_match, uhub_attach,
104: uhub_detach, uhub_activate
1.1 augustss 105: };
1.32 augustss 106: #elif defined(__FreeBSD__)
1.34 augustss 107: USB_DECLARE_DRIVER_INIT(uhub,
108: DEVMETHOD(bus_child_detached, uhub_child_detached));
109:
1.32 augustss 110: /* Create the driver instance for the hub connected to usb case. */
111: devclass_t uhubroot_devclass;
112:
1.41 augustss 113: Static device_method_t uhubroot_methods[] = {
1.32 augustss 114: DEVMETHOD(device_probe, uhub_match),
115: DEVMETHOD(device_attach, uhub_attach),
116:
117: /* detach is not allowed for a root hub */
118: {0,0}
119: };
120:
1.41 augustss 121: Static driver_t uhubroot_driver = {
1.32 augustss 122: "uhub",
123: uhubroot_methods,
124: sizeof(struct uhub_softc)
125: };
1.11 augustss 126: #endif
1.1 augustss 127:
1.11 augustss 128: USB_MATCH(uhub)
1.1 augustss 129: {
1.11 augustss 130: USB_MATCH_START(uhub, uaa);
1.1 augustss 131: usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
132:
1.11 augustss 133: DPRINTFN(5,("uhub_match, dd=%p\n", dd));
1.1 augustss 134: /*
135: * The subclass for hubs seems to be 0 for some and 1 for others,
136: * so we just ignore the subclass.
137: */
1.40 augustss 138: if (uaa->iface == NULL && dd->bDeviceClass == UDCLASS_HUB)
1.1 augustss 139: return (UMATCH_DEVCLASS_DEVSUBCLASS);
140: return (UMATCH_NONE);
141: }
142:
1.11 augustss 143: USB_ATTACH(uhub)
1.1 augustss 144: {
1.11 augustss 145: USB_ATTACH_START(uhub, sc, uaa);
1.1 augustss 146: usbd_device_handle dev = uaa->device;
147: char devinfo[1024];
1.33 augustss 148: usbd_status err;
1.1 augustss 149: struct usbd_hub *hub;
150: usb_device_request_t req;
151: usb_hub_descriptor_t hubdesc;
1.42 augustss 152: int p, port, nports, nremov, pwrdly;
1.1 augustss 153: usbd_interface_handle iface;
154: usb_endpoint_descriptor_t *ed;
155:
156: DPRINTFN(1,("uhub_attach\n"));
157: sc->sc_hub = dev;
158: usbd_devinfo(dev, 1, devinfo);
1.11 augustss 159: USB_ATTACH_SETUP;
160: printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
1.1 augustss 161:
1.33 augustss 162: err = usbd_set_config_index(dev, 0, 1);
163: if (err) {
1.21 augustss 164: DPRINTF(("%s: configuration failed, error=%s\n",
1.33 augustss 165: USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
1.11 augustss 166: USB_ATTACH_ERROR_RETURN;
1.1 augustss 167: }
168:
169: if (dev->depth > USB_HUB_MAX_DEPTH) {
170: printf("%s: hub depth (%d) exceeded, hub ignored\n",
1.11 augustss 171: USBDEVNAME(sc->sc_dev), USB_HUB_MAX_DEPTH);
172: USB_ATTACH_ERROR_RETURN;
1.1 augustss 173: }
174:
175: /* Get hub descriptor. */
176: req.bmRequestType = UT_READ_CLASS_DEVICE;
177: req.bRequest = UR_GET_DESCRIPTOR;
178: USETW(req.wValue, 0);
179: USETW(req.wIndex, 0);
180: USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
181: DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
1.33 augustss 182: err = usbd_do_request(dev, &req, &hubdesc);
1.11 augustss 183: nports = hubdesc.bNbrPorts;
1.33 augustss 184: if (!err && nports > 7) {
1.11 augustss 185: USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
1.33 augustss 186: err = usbd_do_request(dev, &req, &hubdesc);
1.11 augustss 187: }
1.33 augustss 188: if (err) {
1.21 augustss 189: DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
1.33 augustss 190: USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
1.11 augustss 191: USB_ATTACH_ERROR_RETURN;
1.1 augustss 192: }
193:
1.11 augustss 194: for (nremov = 0, port = 1; port <= nports; port++)
195: if (!UHD_NOT_REMOV(&hubdesc, port))
196: nremov++;
197: printf("%s: %d port%s with %d removable, %s powered\n",
198: USBDEVNAME(sc->sc_dev), nports, nports != 1 ? "s" : "",
199: nremov, dev->self_powered ? "self" : "bus");
200:
1.1 augustss 201: hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
1.18 augustss 202: M_USBDEV, M_NOWAIT);
1.33 augustss 203: if (hub == NULL)
1.11 augustss 204: USB_ATTACH_ERROR_RETURN;
1.1 augustss 205: dev->hub = hub;
1.11 augustss 206: dev->hub->hubsoftc = sc;
1.1 augustss 207: hub->explore = uhub_explore;
208: hub->hubdesc = hubdesc;
209:
1.10 drochner 210: DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, "
211: "parent->selfpowered=%d\n",
1.1 augustss 212: dev->self_powered, dev->powersrc->parent,
213: dev->powersrc->parent ?
214: dev->powersrc->parent->self_powered : 0));
1.32 augustss 215:
1.33 augustss 216: if (!dev->self_powered && dev->powersrc->parent != NULL &&
1.1 augustss 217: !dev->powersrc->parent->self_powered) {
1.10 drochner 218: printf("%s: bus powered hub connected to bus powered hub, "
1.26 augustss 219: "ignored\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 220: goto bad;
1.1 augustss 221: }
222:
223: /* Set up interrupt pipe. */
1.33 augustss 224: err = usbd_device2interface_handle(dev, 0, &iface);
225: if (err) {
1.11 augustss 226: printf("%s: no interface handle\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 227: goto bad;
1.1 augustss 228: }
229: ed = usbd_interface2endpoint_descriptor(iface, 0);
1.33 augustss 230: if (ed == NULL) {
1.11 augustss 231: printf("%s: no endpoint descriptor\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 232: goto bad;
1.1 augustss 233: }
234: if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
1.11 augustss 235: printf("%s: bad interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 236: goto bad;
1.1 augustss 237: }
238:
1.33 augustss 239: err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
240: USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status,
1.43 ! augustss 241: sizeof(sc->sc_status), uhub_intr, UHUB_INTR_INTERVAL);
1.33 augustss 242: if (err) {
1.11 augustss 243: printf("%s: cannot open interrupt pipe\n",
244: USBDEVNAME(sc->sc_dev));
1.18 augustss 245: goto bad;
1.1 augustss 246: }
247:
1.11 augustss 248: /* Wait with power off for a while. */
1.13 augustss 249: usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
1.11 augustss 250:
1.37 augustss 251: usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, USBDEV(sc->sc_dev));
252:
1.42 augustss 253: /*
254: * To have the best chance of success we do things in the exact same
255: * order as Windoze98. This should not be necessary, but some
256: * devices do not follow the USB specs to the letter.
257: *
258: * These are the events on the bus when a hub is attached:
259: * Get device and config descriptors (see attach code)
260: * Get hub descriptor (see above)
261: * For all ports
262: * turn on power
263: * wait for power to become stable
264: * (all below happens in explore code)
265: * For all ports
266: * clear C_PORT_CONNECTION
267: * For all ports
268: * get port status
269: * if device connected
270: * turn on reset
271: * wait
272: * clear C_PORT_RESET
273: * get port status
274: * proceed with device attachment
275: */
276:
277: /* Set up data structures */
1.11 augustss 278: for (p = 0; p < nports; p++) {
279: struct usbd_port *up = &hub->ports[p];
280: up->device = 0;
281: up->parent = dev;
282: up->portno = p+1;
1.42 augustss 283: if (dev->self_powered)
284: /* Self powered hub, give ports maximum current. */
285: up->power = USB_MAX_POWER;
286: else
287: up->power = USB_MIN_POWER;
288: }
289:
290: /* XXX should check for none, individual, or ganged power? */
291:
292: pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
293: + USB_EXTRA_POWER_UP_TIME;
294: for (port = 1; port <= nports; port++) {
295: /* Turn the power on. */
296: err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
1.33 augustss 297: if (err)
1.42 augustss 298: printf("%s: port %d power on failed, %s\n",
299: USBDEVNAME(sc->sc_dev), port,
300: usbd_errstr(err));
301: DPRINTF(("usb_init_port: turn on port %d power\n", port));
302: /* Wait for stable power. */
303: usbd_delay_ms(dev, pwrdly);
1.1 augustss 304: }
1.42 augustss 305:
306: /* The usual exploration will finish the setup. */
307:
1.1 augustss 308: sc->sc_running = 1;
1.11 augustss 309:
310: USB_ATTACH_SUCCESS_RETURN;
311:
1.18 augustss 312: bad:
313: free(hub, M_USBDEV);
314: dev->hub = 0;
315: USB_ATTACH_ERROR_RETURN;
1.11 augustss 316: }
317:
1.1 augustss 318: usbd_status
1.11 augustss 319: uhub_explore(dev)
1.1 augustss 320: usbd_device_handle dev;
321: {
322: usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
1.11 augustss 323: struct uhub_softc *sc = dev->hub->hubsoftc;
1.1 augustss 324: struct usbd_port *up;
1.33 augustss 325: usbd_status err;
1.1 augustss 326: int port;
327: int change, status;
328:
1.11 augustss 329: DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
1.1 augustss 330:
331: if (!sc->sc_running)
332: return (USBD_NOT_STARTED);
333:
334: /* Ignore hubs that are too deep. */
335: if (dev->depth > USB_HUB_MAX_DEPTH)
336: return (USBD_TOO_DEEP);
337:
338: for(port = 1; port <= hd->bNbrPorts; port++) {
339: up = &dev->hub->ports[port-1];
1.33 augustss 340: err = usbd_get_port_status(dev, port, &up->status);
341: if (err) {
1.10 drochner 342: DPRINTF(("uhub_explore: get port status failed, "
1.33 augustss 343: "error=%s\n", usbd_errstr(err)));
1.1 augustss 344: continue;
345: }
346: status = UGETW(up->status.wPortStatus);
347: change = UGETW(up->status.wPortChange);
1.35 augustss 348: DPRINTFN(3,("uhub_explore: port %d status 0x%04x 0x%04x\n",
349: port, status, change));
1.11 augustss 350: if (change & UPS_C_PORT_ENABLED) {
1.35 augustss 351: DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
1.11 augustss 352: usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
353: if (status & UPS_PORT_ENABLED) {
354: printf("%s: illegal enable change, port %d\n",
355: USBDEVNAME(sc->sc_dev), port);
356: } else {
357: /* Port error condition. */
358: if (up->restartcnt++ < USBD_RESTART_MAX) {
359: printf("%s: port error, restarting "
360: "port %d\n",
361: USBDEVNAME(sc->sc_dev), port);
362: goto disco;
363: } else {
364: printf("%s: port error, giving up "
365: "port %d\n",
366: USBDEVNAME(sc->sc_dev), port);
367: }
368: }
369: }
370: if (!(change & UPS_C_CONNECT_STATUS)) {
1.35 augustss 371: DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_"
372: "STATUS\n", port));
1.1 augustss 373: /* No status change, just do recursive explore. */
374: if (up->device && up->device->hub)
1.11 augustss 375: up->device->hub->explore(up->device);
1.1 augustss 376: continue;
377: }
1.42 augustss 378:
379: /* We have a connect status change, handle it. */
380:
1.1 augustss 381: DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
382: dev->address, port));
383: usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
1.42 augustss 384: /*usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);*/
1.1 augustss 385: /*
386: * If there is already a device on the port the change status
387: * must mean that is has disconnected. Looking at the
388: * current connect status is not enough to figure this out
389: * since a new unit may have been connected before we handle
390: * the disconnect.
391: */
1.11 augustss 392: disco:
1.33 augustss 393: if (up->device != NULL) {
1.1 augustss 394: /* Disconnected */
1.35 augustss 395: DPRINTF(("uhub_explore: device addr=%d disappeared "
1.31 augustss 396: "on port %d\n", up->device->address, port));
397: usb_disconnect_port(up, USBDEV(sc->sc_dev));
1.1 augustss 398: usbd_clear_port_feature(dev, port,
399: UHF_C_PORT_CONNECTION);
400: }
1.35 augustss 401: if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
1.42 augustss 402: /* Nothing connected, just ignore it. */
1.35 augustss 403: DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
404: "_STATUS\n", port));
1.1 augustss 405: continue;
1.35 augustss 406: }
1.1 augustss 407:
408: /* Connected */
1.42 augustss 409:
410: if (!(status & UPS_PORT_POWER))
411: printf("%s: strange, connected port %d has no power\n",
412: USBDEVNAME(sc->sc_dev), port);
413:
1.11 augustss 414: up->restartcnt = 0;
415:
1.1 augustss 416: /* Wait for maximum device power up time. */
1.13 augustss 417: usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
1.11 augustss 418:
1.1 augustss 419: /* Reset port, which implies enabling it. */
1.35 augustss 420: if (usbd_reset_port(dev, port, &up->status)) {
1.42 augustss 421: printf("uhub_explore: port=%d reset failed\n",
422: port);
1.1 augustss 423: continue;
1.35 augustss 424: }
1.1 augustss 425:
426: /* Get device info and set its address. */
1.33 augustss 427: err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus,
428: dev->depth + 1, status & UPS_LOW_SPEED,
429: port, up);
1.1 augustss 430: /* XXX retry a few times? */
1.33 augustss 431: if (err) {
1.10 drochner 432: DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
1.33 augustss 433: "error=%s\n", usbd_errstr(err)));
1.1 augustss 434: /* Avoid addressing problems by disabling. */
435: /* usbd_reset_port(dev, port, &up->status); */
1.30 augustss 436:
437: /*
438: * The unit refused to accept a new address, or had
439: * some other serious problem. Since we cannot leave
440: * at 0 we have to disable the port instead.
441: */
442: printf("%s: device problem, disabling port %d\n",
443: USBDEVNAME(sc->sc_dev), port);
444: usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
445: /* Make sure we don't try to restart it infinitely. */
446: up->restartcnt = USBD_RESTART_MAX;
1.1 augustss 447: } else {
1.34 augustss 448: if (up->device->hub)
1.11 augustss 449: up->device->hub->explore(up->device);
1.1 augustss 450: }
451: }
452: return (USBD_NORMAL_COMPLETION);
453: }
454:
1.32 augustss 455: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.18 augustss 456: int
457: uhub_activate(self, act)
1.26 augustss 458: device_ptr_t self;
1.18 augustss 459: enum devact act;
460: {
1.27 augustss 461: struct uhub_softc *sc = (struct uhub_softc *)self;
1.39 augustss 462: struct usbd_hub *hub = sc->sc_hub->hub;
1.34 augustss 463: usbd_device_handle dev;
464: int nports, port, i;
1.27 augustss 465:
1.23 augustss 466: switch (act) {
467: case DVACT_ACTIVATE:
468: return (EOPNOTSUPP);
469: break;
470:
471: case DVACT_DEACTIVATE:
1.39 augustss 472: if (hub == NULL) /* malfunctioning hub */
473: break;
474: nports = hub->hubdesc.bNbrPorts;
1.34 augustss 475: for(port = 0; port < nports; port++) {
1.39 augustss 476: dev = hub->ports[port].device;
1.33 augustss 477: if (dev != NULL) {
1.27 augustss 478: for (i = 0; dev->subdevs[i]; i++)
479: config_deactivate(dev->subdevs[i]);
480: }
481: }
1.23 augustss 482: break;
483: }
1.18 augustss 484: return (0);
485: }
1.32 augustss 486: #endif
1.18 augustss 487:
488: /*
489: * Called from process context when the hub is gone.
490: * Detach all devices on active ports.
491: */
1.32 augustss 492: USB_DETACH(uhub)
1.18 augustss 493: {
1.32 augustss 494: USB_DETACH_START(uhub, sc);
1.39 augustss 495: struct usbd_hub *hub = sc->sc_hub->hub;
1.18 augustss 496: struct usbd_port *rup;
1.32 augustss 497: int port, nports;
1.18 augustss 498:
1.32 augustss 499: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.18 augustss 500: DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
1.32 augustss 501: #elif defined(__FreeBSD__)
502: DPRINTF(("uhub_detach: sc=%port\n", sc));
503: #endif
1.18 augustss 504:
1.39 augustss 505: if (hub == NULL) /* Must be partially working */
1.18 augustss 506: return (0);
507:
508: usbd_abort_pipe(sc->sc_ipipe);
509: usbd_close_pipe(sc->sc_ipipe);
510:
1.39 augustss 511: nports = hub->hubdesc.bNbrPorts;
1.32 augustss 512: for(port = 0; port < nports; port++) {
1.39 augustss 513: rup = &hub->ports[port];
1.18 augustss 514: if (rup->device)
1.31 augustss 515: usb_disconnect_port(rup, self);
1.18 augustss 516: }
517:
1.39 augustss 518: usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub,
519: USBDEV(sc->sc_dev));
1.37 augustss 520:
1.39 augustss 521: free(hub, M_USBDEV);
522: sc->sc_hub->hub = NULL;
1.18 augustss 523:
524: return (0);
525: }
1.34 augustss 526:
527: #if defined(__FreeBSD__)
528: /* Called when a device has been detached from it */
1.41 augustss 529: Static void
1.34 augustss 530: uhub_child_detached(self, child)
531: device_t self;
532: device_t child;
533: {
534: struct uhub_softc *sc = device_get_softc(self);
535: usbd_device_handle devhub = sc->sc_hub;
536: usbd_device_handle dev;
537: int nports;
538: int port;
539: int i;
540:
541: if (!devhub->hub)
542: /* should never happen; children are only created after init */
543: panic("hub not fully initialised, but child deleted?");
544:
545: nports = devhub->hub->hubdesc.bNbrPorts;
546: for (port = 0; port < nports; port++) {
547: dev = devhub->hub->ports[port].device;
548: if (dev && dev->subdevs) {
549: for (i = 0; dev->subdevs[i]; i++) {
550: if (dev->subdevs[i] == child) {
551: dev->subdevs[i] = NULL;
552: return;
553: }
554: }
555: }
556: }
557: }
558: #endif
559:
1.18 augustss 560:
561: /*
562: * Hub interrupt.
563: * This an indication that some port has changed status.
564: * Notify the bus event handler thread that we need
565: * to be explored again.
566: */
1.1 augustss 567: void
1.33 augustss 568: uhub_intr(xfer, addr, status)
569: usbd_xfer_handle xfer;
1.1 augustss 570: usbd_private_handle addr;
571: usbd_status status;
572: {
573: struct uhub_softc *sc = addr;
574:
1.11 augustss 575: DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
1.1 augustss 576: if (status != USBD_NORMAL_COMPLETION)
1.9 augustss 577: usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.18 augustss 578:
579: usb_needs_explore(sc->sc_hub->bus);
1.1 augustss 580: }
1.11 augustss 581:
582: #if defined(__FreeBSD__)
1.19 augustss 583: DRIVER_MODULE(uhub, usb, uhubroot_driver, uhubroot_devclass, 0, 0);
584: DRIVER_MODULE(uhub, uhub, uhub_driver, uhub_devclass, usbd_driver_load, 0);
1.11 augustss 585: #endif
CVSweb <webmaster@jp.NetBSD.org>