Annotation of src/sys/dev/usb/uhub.c, Revision 1.36
1.36 ! augustss 1: /* $NetBSD: uhub.c,v 1.35 1999/11/24 23:13:19 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: /*
42: * USB spec: http://www.usb.org/cgi-usb/mailmerge.cgi/home/usb/docs/developers/cgiform.tpl
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.32 augustss 65: #ifdef UHUB_DEBUG
1.35 augustss 66: #define DPRINTF(x) if (uhubdebug) logprintf x
67: #define DPRINTFN(n,x) if (uhubdebug>(n)) logprintf x
68: int uhubdebug;
1.1 augustss 69: #else
70: #define DPRINTF(x)
71: #define DPRINTFN(n,x)
72: #endif
73:
74: struct uhub_softc {
1.26 augustss 75: USBBASEDEVICE sc_dev; /* base device */
1.11 augustss 76: usbd_device_handle sc_hub; /* USB device */
77: usbd_pipe_handle sc_ipipe; /* interrupt pipe */
78: u_int8_t sc_status[1]; /* XXX more ports */
79: u_char sc_running;
1.1 augustss 80: };
81:
1.33 augustss 82: static usbd_status uhub_init_port __P((struct usbd_port *));
83: static usbd_status uhub_explore __P((usbd_device_handle hub));
1.34 augustss 84: static void uhub_intr __P((usbd_xfer_handle, usbd_private_handle,usbd_status));
1.1 augustss 85:
1.32 augustss 86: #if defined(__FreeBSD__)
87: static bus_child_detached_t uhub_child_detached;
88: #endif
89:
90:
91: /*
92: * We need two attachment points:
93: * hub to usb and hub to hub
94: * Every other driver only connects to hubs
95: */
1.1 augustss 96:
1.20 augustss 97: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.34 augustss 98: USB_DECLARE_DRIVER(uhub);
99:
1.32 augustss 100: /* Create the driver instance for the hub connected to hub case */
1.1 augustss 101: struct cfattach uhub_uhub_ca = {
1.18 augustss 102: sizeof(struct uhub_softc), uhub_match, uhub_attach,
103: uhub_detach, uhub_activate
1.1 augustss 104: };
1.32 augustss 105: #elif defined(__FreeBSD__)
1.34 augustss 106: USB_DECLARE_DRIVER_INIT(uhub,
107: DEVMETHOD(bus_child_detached, uhub_child_detached));
108:
1.32 augustss 109: /* Create the driver instance for the hub connected to usb case. */
110: devclass_t uhubroot_devclass;
111:
112: static device_method_t uhubroot_methods[] = {
113: DEVMETHOD(device_probe, uhub_match),
114: DEVMETHOD(device_attach, uhub_attach),
115:
116: /* detach is not allowed for a root hub */
117: {0,0}
118: };
119:
120: static driver_t uhubroot_driver = {
121: "uhub",
122: uhubroot_methods,
123: sizeof(struct uhub_softc)
124: };
1.11 augustss 125: #endif
1.1 augustss 126:
1.11 augustss 127: USB_MATCH(uhub)
1.1 augustss 128: {
1.11 augustss 129: USB_MATCH_START(uhub, uaa);
1.1 augustss 130: usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
131:
1.11 augustss 132: DPRINTFN(5,("uhub_match, dd=%p\n", dd));
1.1 augustss 133: /*
134: * The subclass for hubs seems to be 0 for some and 1 for others,
135: * so we just ignore the subclass.
136: */
1.33 augustss 137: if (uaa->iface == NULL && dd->bDeviceClass == UCLASS_HUB)
1.1 augustss 138: return (UMATCH_DEVCLASS_DEVSUBCLASS);
139: return (UMATCH_NONE);
140: }
141:
1.11 augustss 142: USB_ATTACH(uhub)
1.1 augustss 143: {
1.11 augustss 144: USB_ATTACH_START(uhub, sc, uaa);
1.1 augustss 145: usbd_device_handle dev = uaa->device;
146: char devinfo[1024];
1.33 augustss 147: usbd_status err;
1.1 augustss 148: struct usbd_hub *hub;
149: usb_device_request_t req;
150: usb_hub_descriptor_t hubdesc;
1.11 augustss 151: int p, port, nports, nremov;
1.1 augustss 152: usbd_interface_handle iface;
153: usb_endpoint_descriptor_t *ed;
154:
155: DPRINTFN(1,("uhub_attach\n"));
156: sc->sc_hub = dev;
157: usbd_devinfo(dev, 1, devinfo);
1.11 augustss 158: USB_ATTACH_SETUP;
159: printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
1.1 augustss 160:
1.33 augustss 161: err = usbd_set_config_index(dev, 0, 1);
162: if (err) {
1.21 augustss 163: DPRINTF(("%s: configuration failed, error=%s\n",
1.33 augustss 164: USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
1.11 augustss 165: USB_ATTACH_ERROR_RETURN;
1.1 augustss 166: }
167:
168: if (dev->depth > USB_HUB_MAX_DEPTH) {
169: printf("%s: hub depth (%d) exceeded, hub ignored\n",
1.11 augustss 170: USBDEVNAME(sc->sc_dev), USB_HUB_MAX_DEPTH);
171: USB_ATTACH_ERROR_RETURN;
1.1 augustss 172: }
173:
174: /* Get hub descriptor. */
175: req.bmRequestType = UT_READ_CLASS_DEVICE;
176: req.bRequest = UR_GET_DESCRIPTOR;
177: USETW(req.wValue, 0);
178: USETW(req.wIndex, 0);
179: USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
180: DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
1.33 augustss 181: err = usbd_do_request(dev, &req, &hubdesc);
1.11 augustss 182: nports = hubdesc.bNbrPorts;
1.33 augustss 183: if (!err && nports > 7) {
1.11 augustss 184: USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
1.33 augustss 185: err = usbd_do_request(dev, &req, &hubdesc);
1.11 augustss 186: }
1.33 augustss 187: if (err) {
1.21 augustss 188: DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
1.33 augustss 189: USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
1.11 augustss 190: USB_ATTACH_ERROR_RETURN;
1.1 augustss 191: }
192:
1.11 augustss 193: for (nremov = 0, port = 1; port <= nports; port++)
194: if (!UHD_NOT_REMOV(&hubdesc, port))
195: nremov++;
196: printf("%s: %d port%s with %d removable, %s powered\n",
197: USBDEVNAME(sc->sc_dev), nports, nports != 1 ? "s" : "",
198: nremov, dev->self_powered ? "self" : "bus");
199:
1.1 augustss 200: hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
1.18 augustss 201: M_USBDEV, M_NOWAIT);
1.33 augustss 202: if (hub == NULL)
1.11 augustss 203: USB_ATTACH_ERROR_RETURN;
1.1 augustss 204: dev->hub = hub;
1.11 augustss 205: dev->hub->hubsoftc = sc;
1.1 augustss 206: hub->explore = uhub_explore;
207: hub->hubdesc = hubdesc;
208:
1.10 drochner 209: DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, "
210: "parent->selfpowered=%d\n",
1.1 augustss 211: dev->self_powered, dev->powersrc->parent,
212: dev->powersrc->parent ?
213: dev->powersrc->parent->self_powered : 0));
1.32 augustss 214:
1.33 augustss 215: if (!dev->self_powered && dev->powersrc->parent != NULL &&
1.1 augustss 216: !dev->powersrc->parent->self_powered) {
1.10 drochner 217: printf("%s: bus powered hub connected to bus powered hub, "
1.26 augustss 218: "ignored\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 219: goto bad;
1.1 augustss 220: }
221:
222: /* Set up interrupt pipe. */
1.33 augustss 223: err = usbd_device2interface_handle(dev, 0, &iface);
224: if (err) {
1.11 augustss 225: printf("%s: no interface handle\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 226: goto bad;
1.1 augustss 227: }
228: ed = usbd_interface2endpoint_descriptor(iface, 0);
1.33 augustss 229: if (ed == NULL) {
1.11 augustss 230: printf("%s: no endpoint descriptor\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 231: goto bad;
1.1 augustss 232: }
233: if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
1.11 augustss 234: printf("%s: bad interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
1.18 augustss 235: goto bad;
1.1 augustss 236: }
237:
1.33 augustss 238: err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
239: USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_status,
1.36 ! augustss 240: sizeof(sc->sc_status), uhub_intr, USBD_DEFAULT_INTERVAL);
1.33 augustss 241: if (err) {
1.11 augustss 242: printf("%s: cannot open interrupt pipe\n",
243: USBDEVNAME(sc->sc_dev));
1.18 augustss 244: goto bad;
1.1 augustss 245: }
246:
1.11 augustss 247: /* Wait with power off for a while. */
1.13 augustss 248: usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
1.11 augustss 249:
250: for (p = 0; p < nports; p++) {
251: struct usbd_port *up = &hub->ports[p];
252: up->device = 0;
253: up->parent = dev;
254: up->portno = p+1;
1.33 augustss 255: err = uhub_init_port(up);
256: if (err)
1.1 augustss 257: printf("%s: init of port %d failed\n",
1.33 augustss 258: USBDEVNAME(sc->sc_dev), up->portno);
1.1 augustss 259: }
260: sc->sc_running = 1;
1.11 augustss 261:
262: USB_ATTACH_SUCCESS_RETURN;
263:
1.18 augustss 264: bad:
265: free(hub, M_USBDEV);
266: dev->hub = 0;
267: USB_ATTACH_ERROR_RETURN;
1.11 augustss 268: }
269:
1.1 augustss 270: usbd_status
1.11 augustss 271: uhub_init_port(up)
272: struct usbd_port *up;
1.1 augustss 273: {
1.11 augustss 274: int port = up->portno;
275: usbd_device_handle dev = up->parent;
1.33 augustss 276: usbd_status err;
1.1 augustss 277: u_int16_t pstatus;
278:
1.33 augustss 279: err = usbd_get_port_status(dev, port, &up->status);
280: if (err)
281: return (err);
1.11 augustss 282: pstatus = UGETW(up->status.wPortStatus);
1.10 drochner 283: DPRINTF(("usbd_init_port: adding hub port=%d status=0x%04x "
284: "change=0x%04x\n",
1.11 augustss 285: port, pstatus, UGETW(up->status.wPortChange)));
1.1 augustss 286: if ((pstatus & UPS_PORT_POWER) == 0) {
287: /* Port lacks power, turn it on */
1.12 augustss 288:
1.8 augustss 289: /* First let the device go through a good power cycle, */
1.13 augustss 290: usbd_delay_ms(dev, USB_PORT_POWER_DOWN_TIME);
1.12 augustss 291:
1.19 augustss 292: #if 0
293: usbd_clear_hub_feature(dev, UHF_C_HUB_OVER_CURRENT);
294: usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT);
295: #endif
296:
1.8 augustss 297: /* then turn the power on. */
1.33 augustss 298: err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
299: if (err)
300: return (err);
1.10 drochner 301: DPRINTF(("usb_init_port: turn on port %d power status=0x%04x "
302: "change=0x%04x\n",
1.11 augustss 303: port, UGETW(up->status.wPortStatus),
304: UGETW(up->status.wPortChange)));
1.1 augustss 305: /* Wait for stable power. */
1.13 augustss 306: usbd_delay_ms(dev, dev->hub->hubdesc.bPwrOn2PwrGood *
307: UHD_PWRON_FACTOR);
1.17 augustss 308: /* Get the port status again. */
1.33 augustss 309: err = usbd_get_port_status(dev, port, &up->status);
310: if (err)
311: return (err);
1.19 augustss 312: DPRINTF(("usb_init_port: after power on status=0x%04x "
313: "change=0x%04x\n",
314: UGETW(up->status.wPortStatus),
315: UGETW(up->status.wPortChange)));
316:
317: #if 0
318: usbd_clear_hub_feature(dev, UHF_C_HUB_OVER_CURRENT);
319: usbd_clear_port_feature(dev, port, UHF_C_PORT_OVER_CURRENT);
320: usbd_get_port_status(dev, port, &up->status);
321: #endif
322:
1.17 augustss 323: pstatus = UGETW(up->status.wPortStatus);
324: if ((pstatus & UPS_PORT_POWER) == 0)
325: printf("%s: port %d did not power up\n",
326: USBDEVNAME(((struct uhub_softc *)dev->hub->hubsoftc)->sc_dev), port);
327:
1.1 augustss 328: }
329: if (dev->self_powered)
330: /* Self powered hub, give ports maximum current. */
1.11 augustss 331: up->power = USB_MAX_POWER;
1.1 augustss 332: else
1.11 augustss 333: up->power = USB_MIN_POWER;
1.1 augustss 334: return (USBD_NORMAL_COMPLETION);
335: }
336:
337: usbd_status
1.11 augustss 338: uhub_explore(dev)
1.1 augustss 339: usbd_device_handle dev;
340: {
341: usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
1.11 augustss 342: struct uhub_softc *sc = dev->hub->hubsoftc;
1.1 augustss 343: struct usbd_port *up;
1.33 augustss 344: usbd_status err;
1.1 augustss 345: int port;
346: int change, status;
347:
1.11 augustss 348: DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
1.1 augustss 349:
350: if (!sc->sc_running)
351: return (USBD_NOT_STARTED);
352:
353: /* Ignore hubs that are too deep. */
354: if (dev->depth > USB_HUB_MAX_DEPTH)
355: return (USBD_TOO_DEEP);
356:
357: for(port = 1; port <= hd->bNbrPorts; port++) {
358: up = &dev->hub->ports[port-1];
1.33 augustss 359: err = usbd_get_port_status(dev, port, &up->status);
360: if (err) {
1.10 drochner 361: DPRINTF(("uhub_explore: get port status failed, "
1.33 augustss 362: "error=%s\n", usbd_errstr(err)));
1.1 augustss 363: continue;
364: }
365: status = UGETW(up->status.wPortStatus);
366: change = UGETW(up->status.wPortChange);
1.35 augustss 367: DPRINTFN(3,("uhub_explore: port %d status 0x%04x 0x%04x\n",
368: port, status, change));
1.11 augustss 369: if (change & UPS_C_PORT_ENABLED) {
1.35 augustss 370: DPRINTF(("uhub_explore: C_PORT_ENABLED\n"));
1.11 augustss 371: usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
372: if (status & UPS_PORT_ENABLED) {
373: printf("%s: illegal enable change, port %d\n",
374: USBDEVNAME(sc->sc_dev), port);
375: } else {
376: /* Port error condition. */
377: if (up->restartcnt++ < USBD_RESTART_MAX) {
378: printf("%s: port error, restarting "
379: "port %d\n",
380: USBDEVNAME(sc->sc_dev), port);
381: goto disco;
382: } else {
383: printf("%s: port error, giving up "
384: "port %d\n",
385: USBDEVNAME(sc->sc_dev), port);
386: }
387: }
388: }
389: if (!(change & UPS_C_CONNECT_STATUS)) {
1.35 augustss 390: DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_"
391: "STATUS\n", port));
1.1 augustss 392: /* No status change, just do recursive explore. */
393: if (up->device && up->device->hub)
1.11 augustss 394: up->device->hub->explore(up->device);
1.1 augustss 395: continue;
396: }
397: DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
398: dev->address, port));
399: usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
400: usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
401: /*
402: * If there is already a device on the port the change status
403: * must mean that is has disconnected. Looking at the
404: * current connect status is not enough to figure this out
405: * since a new unit may have been connected before we handle
406: * the disconnect.
407: */
1.11 augustss 408: disco:
1.33 augustss 409: if (up->device != NULL) {
1.1 augustss 410: /* Disconnected */
1.35 augustss 411: DPRINTF(("uhub_explore: device addr=%d disappeared "
1.31 augustss 412: "on port %d\n", up->device->address, port));
413: usb_disconnect_port(up, USBDEV(sc->sc_dev));
1.1 augustss 414: usbd_clear_port_feature(dev, port,
415: UHF_C_PORT_CONNECTION);
416: }
1.35 augustss 417: if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
418: DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
419: "_STATUS\n", port));
1.1 augustss 420: continue;
1.35 augustss 421: }
1.1 augustss 422:
423: /* Connected */
1.11 augustss 424: up->restartcnt = 0;
425:
1.1 augustss 426: /* Wait for maximum device power up time. */
1.13 augustss 427: usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
1.11 augustss 428:
1.1 augustss 429: /* Reset port, which implies enabling it. */
1.35 augustss 430: if (usbd_reset_port(dev, port, &up->status)) {
431: DPRINTF(("uhub_explore: port=%d reset failed\n",
432: port));
1.1 augustss 433: continue;
1.35 augustss 434: }
1.1 augustss 435:
436: /* Get device info and set its address. */
1.33 augustss 437: err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus,
438: dev->depth + 1, status & UPS_LOW_SPEED,
439: port, up);
1.1 augustss 440: /* XXX retry a few times? */
1.33 augustss 441: if (err) {
1.10 drochner 442: DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
1.33 augustss 443: "error=%s\n", usbd_errstr(err)));
1.1 augustss 444: /* Avoid addressing problems by disabling. */
445: /* usbd_reset_port(dev, port, &up->status); */
1.30 augustss 446:
447: /*
448: * The unit refused to accept a new address, or had
449: * some other serious problem. Since we cannot leave
450: * at 0 we have to disable the port instead.
451: */
452: printf("%s: device problem, disabling port %d\n",
453: USBDEVNAME(sc->sc_dev), port);
454: usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
455: /* Make sure we don't try to restart it infinitely. */
456: up->restartcnt = USBD_RESTART_MAX;
1.1 augustss 457: } else {
1.34 augustss 458: if (up->device->hub)
1.11 augustss 459: up->device->hub->explore(up->device);
1.1 augustss 460: }
461: }
462: return (USBD_NORMAL_COMPLETION);
463: }
464:
1.32 augustss 465: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.18 augustss 466: int
467: uhub_activate(self, act)
1.26 augustss 468: device_ptr_t self;
1.18 augustss 469: enum devact act;
470: {
1.27 augustss 471: struct uhub_softc *sc = (struct uhub_softc *)self;
472: usbd_device_handle devhub = sc->sc_hub;
1.34 augustss 473: usbd_device_handle dev;
474: int nports, port, i;
1.27 augustss 475:
1.23 augustss 476: switch (act) {
477: case DVACT_ACTIVATE:
478: return (EOPNOTSUPP);
479: break;
480:
481: case DVACT_DEACTIVATE:
1.27 augustss 482: nports = devhub->hub->hubdesc.bNbrPorts;
1.34 augustss 483: for(port = 0; port < nports; port++) {
484: dev = devhub->hub->ports[port].device;
1.33 augustss 485: if (dev != NULL) {
1.27 augustss 486: for (i = 0; dev->subdevs[i]; i++)
487: config_deactivate(dev->subdevs[i]);
488: }
489: }
1.23 augustss 490: break;
491: }
1.18 augustss 492: return (0);
493: }
1.32 augustss 494: #endif
1.18 augustss 495:
496: /*
497: * Called from process context when the hub is gone.
498: * Detach all devices on active ports.
499: */
1.32 augustss 500: USB_DETACH(uhub)
1.18 augustss 501: {
1.32 augustss 502: USB_DETACH_START(uhub, sc);
1.18 augustss 503: usbd_device_handle dev = sc->sc_hub;
504: struct usbd_port *rup;
1.32 augustss 505: int port, nports;
1.18 augustss 506:
1.32 augustss 507: #if defined(__NetBSD__) || defined(__OpenBSD__)
1.18 augustss 508: DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
1.32 augustss 509: #elif defined(__FreeBSD__)
510: DPRINTF(("uhub_detach: sc=%port\n", sc));
511: #endif
1.18 augustss 512:
1.33 augustss 513: if (dev->hub == NULL) /* Must be partially working */
1.18 augustss 514: return (0);
515:
516: usbd_abort_pipe(sc->sc_ipipe);
517: usbd_close_pipe(sc->sc_ipipe);
518:
519: nports = dev->hub->hubdesc.bNbrPorts;
1.32 augustss 520: for(port = 0; port < nports; port++) {
521: rup = &dev->hub->ports[port];
1.18 augustss 522: if (rup->device)
1.31 augustss 523: usb_disconnect_port(rup, self);
1.18 augustss 524: }
525:
526: free(dev->hub, M_USBDEV);
1.33 augustss 527: dev->hub = NULL;
1.18 augustss 528:
529: return (0);
530: }
1.34 augustss 531:
532: #if defined(__FreeBSD__)
533: /* Called when a device has been detached from it */
534: static void
535: uhub_child_detached(self, child)
536: device_t self;
537: device_t child;
538: {
539: struct uhub_softc *sc = device_get_softc(self);
540: usbd_device_handle devhub = sc->sc_hub;
541: usbd_device_handle dev;
542: int nports;
543: int port;
544: int i;
545:
546: if (!devhub->hub)
547: /* should never happen; children are only created after init */
548: panic("hub not fully initialised, but child deleted?");
549:
550: nports = devhub->hub->hubdesc.bNbrPorts;
551: for (port = 0; port < nports; port++) {
552: dev = devhub->hub->ports[port].device;
553: if (dev && dev->subdevs) {
554: for (i = 0; dev->subdevs[i]; i++) {
555: if (dev->subdevs[i] == child) {
556: dev->subdevs[i] = NULL;
557: return;
558: }
559: }
560: }
561: }
562: }
563: #endif
564:
1.18 augustss 565:
566: /*
567: * Hub interrupt.
568: * This an indication that some port has changed status.
569: * Notify the bus event handler thread that we need
570: * to be explored again.
571: */
1.1 augustss 572: void
1.33 augustss 573: uhub_intr(xfer, addr, status)
574: usbd_xfer_handle xfer;
1.1 augustss 575: usbd_private_handle addr;
576: usbd_status status;
577: {
578: struct uhub_softc *sc = addr;
579:
1.11 augustss 580: DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
1.1 augustss 581: if (status != USBD_NORMAL_COMPLETION)
1.9 augustss 582: usbd_clear_endpoint_stall_async(sc->sc_ipipe);
1.18 augustss 583:
584: usb_needs_explore(sc->sc_hub->bus);
1.1 augustss 585: }
1.11 augustss 586:
587: #if defined(__FreeBSD__)
1.19 augustss 588: DRIVER_MODULE(uhub, usb, uhubroot_driver, uhubroot_devclass, 0, 0);
589: DRIVER_MODULE(uhub, uhub, uhub_driver, uhub_devclass, usbd_driver_load, 0);
1.11 augustss 590: #endif
CVSweb <webmaster@jp.NetBSD.org>