diff options
author | n_hibma <n_hibma@FreeBSD.org> | 1999-11-17 22:33:51 +0000 |
---|---|---|
committer | n_hibma <n_hibma@FreeBSD.org> | 1999-11-17 22:33:51 +0000 |
commit | aeb2d2626b24c89dbb68adb9caebd10bbe02dd43 (patch) | |
tree | 4ffabed555c86f3e004db50f4d745f46d25b77c9 /sys/dev/usb/usb_subr.c | |
parent | a586d3a066b64caa068a9a83440201f39e4d6677 (diff) | |
download | FreeBSD-src-aeb2d2626b24c89dbb68adb9caebd10bbe02dd43.zip FreeBSD-src-aeb2d2626b24c89dbb68adb9caebd10bbe02dd43.tar.gz |
Synchronisation with NetBSD as of 1999/11/16:
Cleaning up the code:
- Declare many functions static
- Change variable names to make them more self explanatory
- Change usbd_request_handle -> usbd_xfer_handle
- Syntactical changes
- Remove some unused code
- Other KNF changes
Interrupt context handling
- Change delay to usbd_delay_ms were possible (takes polling mode into
account)
- Change detection mechanism for interrupt context
Add support for pre-allocation DMA-able memory by device driver
Add preliminary support for isochronous to the UHCI driver (not for OHCI
yet).
usb.c, uhci.c, ohci.c
- Initial attempt at detachable USB host controllers
- Handle the use_polling flag with a lttle more care and only set it if
we are cold booting.
usb.c, uhci.c ohci.c, usbdi.c usbdi_util.c usb_subr.c
- Make sure an aborted pipe is marked as not running.
- Start queued request in the right order.
- Insert some more DIAGNOSTIC sanity checks.
- Remove (almost) unused definitions USBD_XFER_OUT and USBD_XFER_IN.
usb.c, usb_subr.c
- Add an event mechanism so that a userland process can watch devices
come and go.
ohci.c
- Handle the case when a USB transfer is so long that it crosses two
page (4K) boundaries. OHCI cannot do that with a single TD so we make
a chain.
ulpt.c
- Use a bigger buffer when transferring data.
- Pre-allocate the DMA buffer. This makes the driver slightly more
efficient.
- Comment out the GET_DEVICE_ID code, because for some unknown reason it
causes printing to fail sometimes.
usb.h
- Add a macro to extract the isoc type.
- Add a macro to check whether the routine has been entered after splusb
and if not, complain.
usbdi.c
- Fix a glitch in dequeueing and aborting requests on interrupt pipes.
- Add a flag in the request to determine if the data copying is done by
the driver or the usbdi layer.
Diffstat (limited to 'sys/dev/usb/usb_subr.c')
-rw-r--r-- | sys/dev/usb/usb_subr.c | 316 |
1 files changed, 194 insertions, 122 deletions
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c index fb4ef4b..b985a5e 100644 --- a/sys/dev/usb/usb_subr.c +++ b/sys/dev/usb/usb_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: usb_subr.c,v 1.45 1999/09/09 12:26:47 augustss Exp $ */ +/* $NetBSD: usb_subr.c,v 1.52 1999/10/13 08:10:58 augustss Exp $ */ /* $FreeBSD$ */ /* @@ -51,6 +51,8 @@ #endif #include <sys/proc.h> +#include <machine/bus.h> + #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> @@ -74,19 +76,20 @@ extern int usbdebug; #endif static usbd_status usbd_set_config __P((usbd_device_handle, int)); -char *usbd_get_string __P((usbd_device_handle, int, char *)); -int usbd_getnewaddr __P((usbd_bus_handle bus)); -int usbd_print __P((void *aux, const char *pnp)); +static char *usbd_get_string __P((usbd_device_handle, int, char *)); +static int usbd_getnewaddr __P((usbd_bus_handle bus)); #if defined(__NetBSD__) -int usbd_submatch __P((device_ptr_t, struct cfdata *cf, void *)); +static int usbd_print __P((void *aux, const char *pnp)); +static int usbd_submatch __P((device_ptr_t, struct cfdata *cf, void *)); #elif defined(__OpenBSD__) -int usbd_submatch __P((device_ptr_t, void *, void *)); +static int usbd_submatch __P((device_ptr_t, void *, void *)); #endif -void usbd_free_iface_data __P((usbd_device_handle dev, int ifcno)); -void usbd_kill_pipe __P((usbd_pipe_handle)); -usbd_status usbd_probe_and_attach +static void usbd_free_iface_data __P((usbd_device_handle dev, int ifcno)); +static void usbd_kill_pipe __P((usbd_pipe_handle)); +static usbd_status usbd_probe_and_attach __P((device_ptr_t parent, usbd_device_handle dev, int port, int addr)); +static u_int32_t usb_cookie_no = 0; #ifdef USBVERBOSE typedef u_int16_t usb_vendor_id_t; @@ -104,9 +107,9 @@ struct usb_knowndev { #define USB_KNOWNDEV_NOPROD 0x01 /* match on vendor only */ #include <dev/usb/usbdevs_data.h> -#endif +#endif /* USBVERBOSE */ -const char *usbd_error_strs[] = { +static const char *usbd_error_strs[] = { "NORMAL_COMPLETION", "IN_PROGRESS", "PENDING_REQUESTS", @@ -151,16 +154,16 @@ usbd_get_string_desc(dev, sindex, langid, sdesc) usb_string_descriptor_t *sdesc; { usb_device_request_t req; - usbd_status r; + usbd_status err; req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, UDESC_STRING, sindex); USETW(req.wIndex, langid); USETW(req.wLength, 1); /* only size byte first */ - r = usbd_do_request(dev, &req, sdesc); - if (r != USBD_NORMAL_COMPLETION) - return (r); + err = usbd_do_request(dev, &req, sdesc); + if (err) + return (err); USETW(req.wLength, sdesc->bLength); /* the whole string */ return (usbd_do_request(dev, &req, sdesc)); } @@ -176,7 +179,7 @@ usbd_get_string(dev, si, buf) char *s; int i, n; u_int16_t c; - usbd_status r; + usbd_status err; if (si == 0) return (0); @@ -184,16 +187,16 @@ usbd_get_string(dev, si, buf) return (0); if (dev->langid == USBD_NOLANG) { /* Set up default language */ - r = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us); - if (r != USBD_NORMAL_COMPLETION || us.bLength < 4) { + err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us); + if (err || us.bLength < 4) { dev->langid = 0; /* Well, just pick English then */ } else { /* Pick the first language as the default. */ dev->langid = UGETW(us.bString[0]); } } - r = usbd_get_string_desc(dev, si, dev->langid, &us); - if (r != USBD_NORMAL_COMPLETION) + err = usbd_get_string_desc(dev, si, dev->langid, &us); + if (err) return (0); s = buf; n = us.bLength / 2 - 1; @@ -208,7 +211,7 @@ usbd_get_string(dev, si, buf) *s++ = '?'; } *s++ = 0; - return buf; + return (buf); } void @@ -222,7 +225,7 @@ usbd_devinfo_vp(dev, v, p) struct usb_knowndev *kdp; #endif - if (!dev) { + if (dev == NULL) { v[0] = p[0] = '\0'; return; } @@ -230,7 +233,7 @@ usbd_devinfo_vp(dev, v, p) vendor = usbd_get_string(dev, udd->iManufacturer, v); product = usbd_get_string(dev, udd->iProduct, p); #ifdef USBVERBOSE - if (!vendor) { + if (vendor == NULL) { for(kdp = usb_knowndevs; kdp->vendorname != NULL; kdp++) { @@ -248,12 +251,11 @@ usbd_devinfo_vp(dev, v, p) } } #endif - - if (vendor) + if (vendor != NULL) strcpy(v, vendor); else sprintf(v, "vendor 0x%04x", UGETW(udd->idVendor)); - if (product) + if (product != NULL) strcpy(p, product); else sprintf(p, "product 0x%04x", UGETW(udd->idProduct)); @@ -322,7 +324,7 @@ usbd_reset_port(dev, port, ps) usb_port_status_t *ps; { usb_device_request_t req; - usbd_status r; + usbd_status err; int n; req.bmRequestType = UT_WRITE_CLASS_OTHER; @@ -330,34 +332,36 @@ usbd_reset_port(dev, port, ps) USETW(req.wValue, UHF_PORT_RESET); USETW(req.wIndex, port); USETW(req.wLength, 0); - r = usbd_do_request(dev, &req, 0); + err = usbd_do_request(dev, &req, 0); DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n", - port, usbd_errstr(r))); - if (r != USBD_NORMAL_COMPLETION) - return (r); + port, usbd_errstr(err))); + if (err) + return (err); n = 10; do { /* Wait for device to recover from reset. */ usbd_delay_ms(dev, USB_PORT_RESET_DELAY); - r = usbd_get_port_status(dev, port, ps); - if (r != USBD_NORMAL_COMPLETION) { - DPRINTF(("usbd_reset_port: get status failed %d\n",r)); - return (r); + err = usbd_get_port_status(dev, port, ps); + if (err) { + DPRINTF(("usbd_reset_port: get status failed %d\n", + err)); + return (err); } } while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0); if (n == 0) { printf("usbd_reset_port: timeout\n"); return (USBD_IOERROR); } - r = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET); + err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET); #ifdef USB_DEBUG - if (r != USBD_NORMAL_COMPLETION) - DPRINTF(("usbd_reset_port: clear port feature failed %d\n",r)); + if (err) + DPRINTF(("usbd_reset_port: clear port feature failed %d\n", + err)); #endif /* Wait for the device to recover from reset. */ usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY); - return (r); + return (err); } usb_interface_descriptor_t * @@ -408,7 +412,7 @@ usbd_find_edesc(cd, ifaceidx, altidx, endptidx) int curidx; d = usbd_find_idesc(cd, ifaceidx, altidx); - if (!d) + if (d == NULL) return (0); if (endptidx >= d->bNumEndpoints) /* quick exit */ return (0); @@ -524,14 +528,14 @@ usbd_set_config_no(dev, no, msg) { int index; usb_config_descriptor_t cd; - usbd_status r; + usbd_status err; DPRINTFN(5,("usbd_set_config_no: %d\n", no)); /* Figure out what config index to use. */ for (index = 0; index < dev->ddesc.bNumConfigurations; index++) { - r = usbd_get_config_desc(dev, index, &cd); - if (r != USBD_NORMAL_COMPLETION) - return (r); + err = usbd_get_config_desc(dev, index, &cd); + if (err) + return (err); if (cd.bConfigurationValue == no) return (usbd_set_config_index(dev, index, msg)); } @@ -546,7 +550,7 @@ usbd_set_config_index(dev, index, msg) { usb_status_t ds; usb_config_descriptor_t cd, *cdp; - usbd_status r; + usbd_status err; int ifcidx, nifc, len, selfpowered, power; DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index)); @@ -566,34 +570,34 @@ usbd_set_config_index(dev, index, msg) } /* Figure out what config number to use. */ - r = usbd_get_config_desc(dev, index, &cd); - if (r != USBD_NORMAL_COMPLETION) - return (r); + err = usbd_get_config_desc(dev, index, &cd); + if (err) + return (err); len = UGETW(cd.wTotalLength); cdp = malloc(len, M_USB, M_NOWAIT); - if (cdp == 0) + if (cdp == NULL) return (USBD_NOMEM); - r = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp); - if (r != USBD_NORMAL_COMPLETION) + err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp); + if (err) goto bad; if (cdp->bDescriptorType != UDESC_CONFIG) { DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n", cdp->bDescriptorType)); - r = USBD_INVAL; + err = USBD_INVAL; goto bad; } selfpowered = 0; - if (cdp->bmAttributes & UC_SELF_POWERED) { + if (!(dev->quirks->uq_flags & UQ_BUS_POWERED) && + cdp->bmAttributes & UC_SELF_POWERED) { /* May be self powered. */ if (cdp->bmAttributes & UC_BUS_POWERED) { /* Must ask device. */ - r = usbd_get_device_status(dev, &ds); - if (r == USBD_NORMAL_COMPLETION && - (UGETW(ds.wStatus) & UDS_SELF_POWERED)) + err = usbd_get_device_status(dev, &ds); + if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED)) selfpowered = 1; DPRINTF(("usbd_set_config_index: status=0x%04x, " "error=%s\n", - UGETW(ds.wStatus), usbd_errstr(r))); + UGETW(ds.wStatus), usbd_errstr(err))); } else selfpowered = 1; } @@ -602,7 +606,7 @@ usbd_set_config_index(dev, index, msg) dev->address, cdp->bmAttributes, selfpowered, cdp->bMaxPower * 2)); #ifdef USB_DEBUG - if (!dev->powersrc) { + if (dev->powersrc == NULL) { DPRINTF(("usbd_set_config_index: No power source?\n")); return (USBD_IOERROR); } @@ -616,7 +620,7 @@ usbd_set_config_index(dev, index, msg) USBDEVNAME(dev->bus->bdev), dev->address, cdp->bConfigurationValue, power, dev->powersrc->power); - r = USBD_NO_POWER; + err = USBD_NO_POWER; goto bad; } dev->power = power; @@ -624,11 +628,11 @@ usbd_set_config_index(dev, index, msg) DPRINTF(("usbd_set_config_index: set config %d\n", cdp->bConfigurationValue)); - r = usbd_set_config(dev, cdp->bConfigurationValue); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_set_config(dev, cdp->bConfigurationValue); + if (err) { DPRINTF(("usbd_set_config_index: setting config=%d failed, " "error=%s\n", - cdp->bConfigurationValue, usbd_errstr(r))); + cdp->bConfigurationValue, usbd_errstr(err))); goto bad; } DPRINTF(("usbd_set_config_index: setting new config %d\n", @@ -637,15 +641,15 @@ usbd_set_config_index(dev, index, msg) dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), M_USB, M_NOWAIT); if (dev->ifaces == 0) { - r = USBD_NOMEM; + err = USBD_NOMEM; goto bad; } DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp)); dev->cdesc = cdp; dev->config = cdp->bConfigurationValue; for (ifcidx = 0; ifcidx < nifc; ifcidx++) { - r = usbd_fill_iface_data(dev, ifcidx, 0); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_fill_iface_data(dev, ifcidx, 0); + if (err) { while (--ifcidx >= 0) usbd_free_iface_data(dev, ifcidx); goto bad; @@ -656,7 +660,7 @@ usbd_set_config_index(dev, index, msg) bad: free(cdp, M_USB); - return (r); + return (err); } /* XXX add function for alternate settings */ @@ -669,29 +673,29 @@ usbd_setup_pipe(dev, iface, ep, pipe) usbd_pipe_handle *pipe; { usbd_pipe_handle p; - usbd_status r; + usbd_status err; DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n", dev, iface, ep, pipe)); p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT); - if (p == 0) + if (p == NULL) return (USBD_NOMEM); p->device = dev; p->iface = iface; p->endpoint = ep; ep->refcnt++; p->refcnt = 1; - p->intrreqh = 0; + p->intrxfer = 0; p->running = 0; p->repeat = 0; SIMPLEQ_INIT(&p->queue); - r = dev->bus->methods->open_pipe(p); - if (r != USBD_NORMAL_COMPLETION) { + err = dev->bus->methods->open_pipe(p); + if (err) { DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error=" "%s\n", - ep->edesc->bEndpointAddress, usbd_errstr(r))); + ep->edesc->bEndpointAddress, usbd_errstr(err))); free(p, M_USB); - return (r); + return (err); } /* Clear any stall and make sure DATA0 toggle will be used next. */ if (UE_GET_ADDR(ep->edesc->bEndpointAddress) != USB_CONTROL_ENDPOINT) @@ -732,7 +736,8 @@ usbd_probe_and_attach(parent, dev, port, addr) { struct usb_attach_arg uaa; usb_device_descriptor_t *dd = &dev->ddesc; - int r, found, i, confi, nifaces; + int found, i, confi, nifaces; + usbd_status err; device_ptr_t dv; usbd_interface_handle ifaces[256]; /* 256 is the absolute max */ @@ -779,12 +784,12 @@ usbd_probe_and_attach(parent, dev, port, addr) for (confi = 0; confi < dd->bNumConfigurations; confi++) { DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n", confi)); - r = usbd_set_config_index(dev, confi, 1); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_set_config_index(dev, confi, 1); + if (err) { #ifdef USB_DEBUG DPRINTF(("%s: port %d, set config at addr %d failed, " "error=%s\n", USBDEVPTRNAME(parent), port, - addr, usbd_errstr(r))); + addr, usbd_errstr(err))); #else printf("%s: port %d, set config at addr %d failed\n", USBDEVPTRNAME(parent), port, addr); @@ -792,8 +797,8 @@ usbd_probe_and_attach(parent, dev, port, addr) #if defined(__FreeBSD__) device_delete_child(parent, bdev); #endif - - return (r); + + return (err); } nifaces = dev->cdesc->bNumInterface; uaa.configno = dev->cdesc->bConfigurationValue; @@ -801,7 +806,6 @@ usbd_probe_and_attach(parent, dev, port, addr) ifaces[i] = &dev->ifaces[i]; uaa.ifaces = ifaces; uaa.nifaces = nifaces; - dev->subdevs = malloc((nifaces+1) * sizeof dv, M_USB,M_NOWAIT); if (dev->subdevs == 0) { #if defined(__FreeBSD__) @@ -812,21 +816,20 @@ usbd_probe_and_attach(parent, dev, port, addr) found = 0; for (i = 0; i < nifaces; i++) { - if (!ifaces[i]) + if (ifaces[i] == NULL) continue; /* interface already claimed */ - uaa.iface = ifaces[i]; uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch); - if (dv) { + if (dv != NULL) { dev->subdevs[found++] = dv; dev->subdevs[found] = 0; ifaces[i] = 0; /* consumed */ #if defined(__FreeBSD__) /* create another child for the next iface */ - bdev = device_add_child(parent, NULL, -1, &uaa); + bdev = device_add_child(parent, NULL, -1,&uaa); if (!bdev) { printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev)); @@ -836,7 +839,6 @@ usbd_probe_and_attach(parent, dev, port, addr) #endif } } - if (found != 0) { #if defined(__FreeBSD__) /* remove the last created child again; it is unused */ @@ -844,7 +846,6 @@ usbd_probe_and_attach(parent, dev, port, addr) #endif return (USBD_NORMAL_COMPLETION); } - free(dev->subdevs, M_USB); dev->subdevs = 0; } @@ -864,7 +865,7 @@ usbd_probe_and_attach(parent, dev, port, addr) uaa.product = UHUB_UNK_PRODUCT; uaa.release = UHUB_UNK_RELEASE; dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch); - if (dv) { + if (dv != NULL) { dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); if (dev->subdevs == 0) return (USBD_NOMEM); @@ -886,7 +887,6 @@ usbd_probe_and_attach(parent, dev, port, addr) } - /* * Called when a new device has been put in the powered state, * but not yet in the addressed state. @@ -904,7 +904,7 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up) { usbd_device_handle dev; usb_device_descriptor_t *dd; - usbd_status r; + usbd_status err; int addr; int i; @@ -918,7 +918,7 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up) } dev = malloc(sizeof *dev, M_USB, M_NOWAIT); - if (dev == 0) + if (dev == NULL) return (USBD_NOMEM); memset(dev, 0, sizeof(*dev)); @@ -942,30 +942,31 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up) dev->depth = depth; dev->powersrc = up; dev->langid = USBD_NOLANG; + dev->cookie.cookie = ++usb_cookie_no; /* Establish the the default pipe. */ - r = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe); + if (err) { usbd_remove_device(dev, up); - return (r); + return (err); } up->device = dev; dd = &dev->ddesc; /* Try a few times in case the device is slow (i.e. outside specs.) */ - for (i = 0; i < 5; i++) { + /* for (i = 0; i < 5; i++) { */ + for (i = 0; i < 3; i++) { /* Get the first 8 bytes of the device descriptor. */ - r = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd); - if (r == USBD_NORMAL_COMPLETION) + err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd); + if (!err) break; usbd_delay_ms(dev, 200); } - if (r != USBD_NORMAL_COMPLETION) { + if (err) { DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc " - "failed\n", - addr)); + "failed\n", addr)); usbd_remove_device(dev, up); - return (r); + return (err); } DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, " @@ -991,24 +992,24 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up) USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize); /* Get the full device descriptor. */ - r = usbd_get_device_desc(dev, dd); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_get_device_desc(dev, dd); + if (err) { DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc " "failed\n", addr)); usbd_remove_device(dev, up); - return (r); + return (err); } /* Figure out what's wrong with this device. */ dev->quirks = usbd_find_quirk(dd); /* Set the address */ - r = usbd_set_address(dev, addr); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_set_address(dev, addr); + if (err) { DPRINTFN(-1,("usb_new_device: set address %d failed\n",addr)); - r = USBD_SET_ADDR_FAILED; + err = USBD_SET_ADDR_FAILED; usbd_remove_device(dev, up); - return (r); + return (err); } /* Allow device time to set new address */ usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE); @@ -1023,12 +1024,13 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up) DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n", addr, dev, parent)); - r = usbd_probe_and_attach(parent, dev, port, addr); - if (r != USBD_NORMAL_COMPLETION) { + err = usbd_probe_and_attach(parent, dev, port, addr); + if (err) { usbd_remove_device(dev, up); - return (r); + return (err); } + usbd_add_event(USB_EVENT_ATTACH, dev); return (USBD_NORMAL_COMPLETION); } @@ -1039,7 +1041,7 @@ usbd_remove_device(dev, up) { DPRINTF(("usbd_remove_device: %p\n", dev)); - if (dev->default_pipe) + if (dev->default_pipe != NULL) usbd_kill_pipe(dev->default_pipe); up->device = 0; dev->bus->devices[dev->address] = 0; @@ -1134,7 +1136,7 @@ usbd_fill_deviceinfo(dev, di) struct usb_device_info *di; { struct usbd_port *p; - int i, r, s; + int i, err, s; di->config = dev->config; usbd_devinfo_vp(dev, di->vendor, di->product); @@ -1152,19 +1154,19 @@ usbd_fill_deviceinfo(dev, di) i++) { p = &dev->hub->ports[i]; if (p->device) - r = p->device->address; + err = p->device->address; else { s = UGETW(p->status.wPortStatus); if (s & UPS_PORT_ENABLED) - r = USB_PORT_ENABLED; + err = USB_PORT_ENABLED; else if (s & UPS_SUSPEND) - r = USB_PORT_SUSPENDED; + err = USB_PORT_SUSPENDED; else if (s & UPS_PORT_POWER) - r = USB_PORT_POWERED; + err = USB_PORT_POWERED; else - r = USB_PORT_DISABLED; + err = USB_PORT_DISABLED; } - di->ports[i] = r; + di->ports[i] = err; } di->nports = dev->hub->hubdesc.bNbrPorts; } else @@ -1177,17 +1179,87 @@ usb_free_device(dev) { int ifcidx, nifc; - if (dev->default_pipe) + if (dev->default_pipe != NULL) usbd_kill_pipe(dev->default_pipe); - if (dev->ifaces) { + if (dev->ifaces != NULL) { nifc = dev->cdesc->bNumInterface; for (ifcidx = 0; ifcidx < nifc; ifcidx++) usbd_free_iface_data(dev, ifcidx); free(dev->ifaces, M_USB); } - if (dev->cdesc) + if (dev->cdesc != NULL) free(dev->cdesc, M_USB); - if (dev->subdevs) + if (dev->subdevs != NULL) free(dev->subdevs, M_USB); free(dev, M_USB); } + +/* + * The general mechanism for detaching drivers works as follows: Each + * driver is responsible for maintaining a reference count on the + * number of outstanding references to its softc (e.g. from + * processing hanging in a read or write). The detach method of the + * driver decrements this counter and flags in the softc that the + * driver is dying and then wakes any sleepers. It then sleeps on the + * softc. Each place that can sleep must maintain the reference + * count. When the reference count drops to -1 (0 is the normal value + * of the reference count) the a wakeup on the softc is performed + * signaling to the detach waiter that all references are gone. + */ + +/* + * Called from process context when we discover that a port has + * been disconnected. + */ +void +usb_disconnect_port(up, parent) + struct usbd_port *up; + device_ptr_t parent; +{ + usbd_device_handle dev = up->device; + char *hubname = USBDEVPTRNAME(parent); + int i; + + DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n", + up, dev, up->portno)); + +#ifdef DIAGNOSTIC + if (!dev) { + printf("usb_disconnect_port: no device\n"); + return; + } +#endif + + if (!dev->cdesc) { + /* Partially attached device, just drop it. */ + dev->bus->devices[dev->address] = 0; + up->device = 0; + return; + } + + if (dev->subdevs != NULL) { + for (i = 0; dev->subdevs[i]; i++) { + if (!dev->subdevs[i]) /* skip empty elements */ + continue; + + printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]), + hubname); + if (up->portno != 0) + printf(" port %d", up->portno); + printf(" (addr %d) disconnected\n", dev->address); +#if defined(__NetBSD__) || defined(__OpenBSD__) + config_detach(dev->subdevs[i], DETACH_FORCE); +#elif defined(__FreeBSD__) + device_delete_child(device_get_parent(dev->subdevs[i]), + dev->subdevs[i]); +#endif + + } + } + + usbd_add_event(USB_EVENT_DETACH, dev); + dev->bus->devices[dev->address] = 0; + up->device = 0; + usb_free_device(dev); +} + |