summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_subr.c
diff options
context:
space:
mode:
authorn_hibma <n_hibma@FreeBSD.org>1999-11-17 22:33:51 +0000
committern_hibma <n_hibma@FreeBSD.org>1999-11-17 22:33:51 +0000
commitaeb2d2626b24c89dbb68adb9caebd10bbe02dd43 (patch)
tree4ffabed555c86f3e004db50f4d745f46d25b77c9 /sys/dev/usb/usb_subr.c
parenta586d3a066b64caa068a9a83440201f39e4d6677 (diff)
downloadFreeBSD-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.c316
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);
+}
+
OpenPOWER on IntegriCloud