summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_subr.c
diff options
context:
space:
mode:
authorn_hibma <n_hibma@FreeBSD.org>1999-10-07 19:26:38 +0000
committern_hibma <n_hibma@FreeBSD.org>1999-10-07 19:26:38 +0000
commitb6c58860ab2b8db1457a6a3ff967066e30992908 (patch)
tree89a9b4bc579522b90571350c7580f2a0b06a069a /sys/dev/usb/usb_subr.c
parent2417a471092d1b5e990dad00d605bde4819e26f9 (diff)
downloadFreeBSD-src-b6c58860ab2b8db1457a6a3ff967066e30992908.zip
FreeBSD-src-b6c58860ab2b8db1457a6a3ff967066e30992908.tar.gz
Major synchronisation with the NetBSD USB stack:
- Some cleanup and improvements in the uhci and ohci drivers - Support for plugging and unplugging devices improved - Now available is bulk transport over OHCI controllers - Resume and suspend have been temporarily been disabled again. Proper support for it is available in the uhci.c and ohci.c files but I have not yet spent the brain cycles to use it. - OpenBSD now uses the USB stack as well - Add FreeBSD tags
Diffstat (limited to 'sys/dev/usb/usb_subr.c')
-rw-r--r--sys/dev/usb/usb_subr.c601
1 files changed, 335 insertions, 266 deletions
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 5279c8b..9730939 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.29 1999/03/18 12:08:43 augustss Exp $ */
+/* $NetBSD: usb_subr.c,v 1.45 1999/09/09 12:26:47 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -42,7 +42,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/device.h>
#elif defined(__FreeBSD__)
#include <sys/module.h>
@@ -73,6 +73,22 @@ extern int usbdebug;
#define DPRINTFN(n,x)
#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));
+#if defined(__NetBSD__)
+int usbd_submatch __P((device_ptr_t, struct cfdata *cf, void *));
+#elif defined(__OpenBSD__)
+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
+ __P((device_ptr_t parent, usbd_device_handle dev, int port, int addr));
+
+
+#ifdef USBVERBOSE
typedef u_int16_t usb_vendor_id_t;
typedef u_int16_t usb_product_id_t;
@@ -80,28 +96,52 @@ typedef u_int16_t usb_product_id_t;
* Descriptions of of known vendors and devices ("products").
*/
struct usb_knowndev {
- usb_vendor_id_t vendor;
- usb_product_id_t product;
- int flags;
- char *vendorname, *productname;
+ usb_vendor_id_t vendor;
+ usb_product_id_t product;
+ int flags;
+ char *vendorname, *productname;
};
-#define USB_KNOWNDEV_NOPROD 0x01 /* match on vendor only */
+#define USB_KNOWNDEV_NOPROD 0x01 /* match on vendor only */
#include <dev/usb/usbdevs_data.h>
+#endif
+const char *usbd_error_strs[] = {
+ "NORMAL_COMPLETION",
+ "IN_PROGRESS",
+ "PENDING_REQUESTS",
+ "NOT_STARTED",
+ "INVAL",
+ "NOMEM",
+ "CANCELLED",
+ "BAD_ADDRESS",
+ "IN_USE",
+ "NO_ADDR",
+ "SET_ADDR_FAILED",
+ "NO_POWER",
+ "TOO_DEEP",
+ "IOERROR",
+ "NOT_CONFIGURED",
+ "TIMEOUT",
+ "SHORT_XFER",
+ "STALLED",
+ "INTERRUPTED",
+ "XXX",
+};
-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));
-#if defined(__NetBSD__)
-int usbd_print __P((void *aux, const char *pnp));
-int usbd_submatch __P((bdevice *, struct cfdata *cf, 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
- __P((bdevice *parent, usbd_device_handle dev, int port, int addr));
+const char *
+usbd_errstr(err)
+ usbd_status err;
+{
+ static char buffer[5];
+ if (err < USBD_ERROR_MAX) {
+ return usbd_error_strs[err];
+ } else {
+ snprintf(buffer, sizeof buffer, "%d", err);
+ return buffer;
+ }
+}
usbd_status
usbd_get_string_desc(dev, sindex, langid, sdesc)
@@ -111,16 +151,16 @@ usbd_get_string_desc(dev, sindex, langid, sdesc)
usb_string_descriptor_t *sdesc;
{
usb_device_request_t req;
- usbd_status err;
+ usbd_status r;
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 */
- err = usbd_do_request(dev, &req, sdesc);
- if (err)
- return (err);
+ r = usbd_do_request(dev, &req, sdesc);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
USETW(req.wLength, sdesc->bLength); /* the whole string */
return (usbd_do_request(dev, &req, sdesc));
}
@@ -133,10 +173,10 @@ usbd_get_string(dev, si, buf)
{
int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE;
usb_string_descriptor_t us;
- char *string;
+ char *s;
int i, n;
u_int16_t c;
- usbd_status err;
+ usbd_status r;
if (si == 0)
return (0);
@@ -144,30 +184,30 @@ usbd_get_string(dev, si, buf)
return (0);
if (dev->langid == USBD_NOLANG) {
/* Set up default language */
- err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us);
- if (err) {
+ r = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us);
+ if (r != USBD_NORMAL_COMPLETION || 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]);
}
}
- err = usbd_get_string_desc(dev, si, dev->langid, &us);
- if (err)
+ r = usbd_get_string_desc(dev, si, dev->langid, &us);
+ if (r != USBD_NORMAL_COMPLETION)
return (0);
- string = buf;
+ s = buf;
n = us.bLength / 2 - 1;
for (i = 0; i < n; i++) {
c = UGETW(us.bString[i]);
/* Convert from Unicode, handle buggy strings. */
if ((c & 0xff00) == 0)
- *string++ = c;
+ *s++ = c;
else if ((c & 0x00ff) == 0 && swap)
- *string++ = c >> 8;
+ *s++ = c >> 8;
else
- *string++ = '?';
+ *s++ = '?';
}
- *string++ = 0;
+ *s++ = 0;
return buf;
}
@@ -177,30 +217,37 @@ usbd_devinfo_vp(dev, v, p)
char *v, *p;
{
usb_device_descriptor_t *udd = &dev->ddesc;
- char *vendor, *product;
+ char *vendor = 0, *product = 0;
+#ifdef USBVERBOSE
struct usb_knowndev *kdp;
+#endif
+
+ if (!dev) {
+ v[0] = p[0] = '\0';
+ return;
+ }
vendor = usbd_get_string(dev, udd->iManufacturer, v);
product = usbd_get_string(dev, udd->iProduct, p);
-
+#ifdef USBVERBOSE
if (!vendor) {
for(kdp = usb_knowndevs;
kdp->vendorname != NULL;
kdp++) {
if (kdp->vendor == UGETW(udd->idVendor) &&
(kdp->product == UGETW(udd->idProduct) ||
- (kdp->flags & USB_KNOWNDEV_NOPROD) != 0))
+ (kdp->flags & USB_KNOWNDEV_NOPROD) != 0))
break;
}
- if (kdp->vendorname == NULL) {
+ if (kdp->vendorname == NULL)
vendor = product = NULL;
- } else {
+ else {
vendor = kdp->vendorname;
product = (kdp->flags & USB_KNOWNDEV_NOPROD) == 0 ?
- kdp->productname : NULL;
+ kdp->productname : NULL;
}
}
-
+#endif
if (vendor)
strcpy(v, vendor);
@@ -275,7 +322,7 @@ usbd_reset_port(dev, port, ps)
usb_port_status_t *ps;
{
usb_device_request_t req;
- usbd_status err;
+ usbd_status r;
int n;
req.bmRequestType = UT_WRITE_CLASS_OTHER;
@@ -283,38 +330,34 @@ usbd_reset_port(dev, port, ps)
USETW(req.wValue, UHF_PORT_RESET);
USETW(req.wIndex, port);
USETW(req.wLength, 0);
- err = usbd_do_request(dev, &req, 0);
- DPRINTFN(1,("usbd_reset_port: port %d reset done, %s\n",
- port, usbd_errstr(err)));
- if (err)
- return(err);
-
+ r = 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);
n = 10;
do {
/* Wait for device to recover from reset. */
usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
- err = usbd_get_port_status(dev, port, ps);
- if (err) {
- DPRINTF(("usbd_reset_port: get port %d status failed %s\n",
- port, usbd_errstr(err)));
- return (err);
+ 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);
}
} while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
-
if (n == 0) {
printf("usbd_reset_port: timeout\n");
return (USBD_IOERROR);
}
- err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
+ r = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
#ifdef USB_DEBUG
- if (err)
- DPRINTF(("usbd_reset_port: clear port %d feature failed %d\n",
- port, err));
+ if (r != USBD_NORMAL_COMPLETION)
+ DPRINTF(("usbd_reset_port: clear port feature failed %d\n",r));
#endif
/* Wait for the device to recover from reset. */
usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
- return (err);
+ return (r);
}
usb_interface_descriptor_t *
@@ -436,14 +479,11 @@ usbd_fill_iface_data(dev, ifaceidx, altidx)
goto bad;
found:
ifc->endpoints[endpt].edesc = ed;
- ifc->endpoints[endpt].state = USBD_ENDPOINT_ACTIVE;
ifc->endpoints[endpt].refcnt = 0;
- ifc->endpoints[endpt].toggle = 0;
p += ed->bLength;
}
#undef ed
LIST_INIT(&ifc->pipes);
- ifc->state = USBD_INTERFACE_ACTIVE;
return (USBD_NORMAL_COMPLETION);
bad:
@@ -484,14 +524,14 @@ usbd_set_config_no(dev, no, msg)
{
int index;
usb_config_descriptor_t cd;
- usbd_status err;
+ usbd_status r;
DPRINTFN(5,("usbd_set_config_no: %d\n", no));
/* Figure out what config index to use. */
for (index = 0; index < dev->ddesc.bNumConfigurations; index++) {
- err = usbd_get_config_desc(dev, index, &cd);
- if (err)
- return (err);
+ r = usbd_get_config_desc(dev, index, &cd);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
if (cd.bConfigurationValue == no)
return (usbd_set_config_index(dev, index, msg));
}
@@ -505,9 +545,8 @@ usbd_set_config_index(dev, index, msg)
int msg;
{
usb_status_t ds;
- usb_hub_status_t hs;
usb_config_descriptor_t cd, *cdp;
- usbd_status err;
+ usbd_status r;
int ifcidx, nifc, len, selfpowered, power;
DPRINTFN(5,("usbd_set_config_index: dev=%p index=%d\n", dev, index));
@@ -524,24 +563,23 @@ usbd_set_config_index(dev, index, msg)
dev->ifaces = 0;
dev->cdesc = 0;
dev->config = 0;
- dev->state = USBD_DEVICE_ADDRESSED;
}
/* Figure out what config number to use. */
- err = usbd_get_config_desc(dev, index, &cd);
- if (err)
- return (err);
+ r = usbd_get_config_desc(dev, index, &cd);
+ if (r != USBD_NORMAL_COMPLETION)
+ return (r);
len = UGETW(cd.wTotalLength);
cdp = malloc(len, M_USB, M_NOWAIT);
if (cdp == 0)
return (USBD_NOMEM);
- err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
- if (err)
+ r = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
+ if (r != USBD_NORMAL_COMPLETION)
goto bad;
if (cdp->bDescriptorType != UDESC_CONFIG) {
DPRINTFN(-1,("usbd_set_config_index: bad desc %d\n",
cdp->bDescriptorType));
- err = USBD_INVAL;
+ r = USBD_INVAL;
goto bad;
}
selfpowered = 0;
@@ -549,31 +587,23 @@ usbd_set_config_index(dev, index, msg)
/* May be self powered. */
if (cdp->bmAttributes & UC_BUS_POWERED) {
/* Must ask device. */
- if (dev->quirks->uq_flags & UQ_HUB_POWER) {
- /* Buggy hub, use hub descriptor. */
- err = usbd_get_hub_status(dev, &hs);
- if (err == USBD_NORMAL_COMPLETION &&
- !(UGETW(hs.wHubStatus) & UHS_LOCAL_POWER))
- selfpowered = 1;
- } else {
- err = usbd_get_device_status(dev, &ds);
- if (err == USBD_NORMAL_COMPLETION &&
- (UGETW(ds.wStatus) & UDS_SELF_POWERED))
- selfpowered = 1;
- }
- DPRINTF(("usbd_set_config_index: status=0x%04x, %s\n",
- UGETW(ds.wStatus), usbd_errstr(err)));
+ r = usbd_get_device_status(dev, &ds);
+ if (r == USBD_NORMAL_COMPLETION &&
+ (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)));
} else
selfpowered = 1;
}
DPRINTF(("usbd_set_config_index: (addr %d) attr=0x%02x, "
- "selfpowered=%d, power=%d, powerquirk=%x\n",
+ "selfpowered=%d, power=%d\n",
dev->address, cdp->bmAttributes,
- selfpowered, cdp->bMaxPower * 2,
- dev->quirks->uq_flags & UQ_HUB_POWER));
+ selfpowered, cdp->bMaxPower * 2));
#ifdef USB_DEBUG
if (!dev->powersrc) {
- printf("usbd_set_config_index: No power source?\n");
+ DPRINTF(("usbd_set_config_index: No power source?\n"));
return (USBD_IOERROR);
}
#endif
@@ -586,7 +616,7 @@ usbd_set_config_index(dev, index, msg)
USBDEVNAME(dev->bus->bdev), dev->address,
cdp->bConfigurationValue,
power, dev->powersrc->power);
- err = USBD_NO_POWER;
+ r = USBD_NO_POWER;
goto bad;
}
dev->power = power;
@@ -594,10 +624,11 @@ usbd_set_config_index(dev, index, msg)
DPRINTF(("usbd_set_config_index: set config %d\n",
cdp->bConfigurationValue));
- err = usbd_set_config(dev, cdp->bConfigurationValue);
- if (err) {
- DPRINTF(("usbd_set_config_index: setting config=%d failed, %s\n",
- cdp->bConfigurationValue, usbd_errstr(err)));
+ r = usbd_set_config(dev, cdp->bConfigurationValue);
+ if (r != USBD_NORMAL_COMPLETION) {
+ DPRINTF(("usbd_set_config_index: setting config=%d failed, "
+ "error=%s\n",
+ cdp->bConfigurationValue, usbd_errstr(r)));
goto bad;
}
DPRINTF(("usbd_set_config_index: setting new config %d\n",
@@ -606,16 +637,15 @@ usbd_set_config_index(dev, index, msg)
dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),
M_USB, M_NOWAIT);
if (dev->ifaces == 0) {
- err = USBD_NOMEM;
+ r = USBD_NOMEM;
goto bad;
}
DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp));
dev->cdesc = cdp;
dev->config = cdp->bConfigurationValue;
- dev->state = USBD_DEVICE_CONFIGURED;
for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
- err = usbd_fill_iface_data(dev, ifcidx, 0);
- if (err) {
+ r = usbd_fill_iface_data(dev, ifcidx, 0);
+ if (r != USBD_NORMAL_COMPLETION) {
while (--ifcidx >= 0)
usbd_free_iface_data(dev, ifcidx);
goto bad;
@@ -626,48 +656,47 @@ usbd_set_config_index(dev, index, msg)
bad:
free(cdp, M_USB);
- return (err);
+ return (r);
}
/* XXX add function for alternate settings */
usbd_status
-usbd_setup_pipe(dev, iface, ep, rpipe)
+usbd_setup_pipe(dev, iface, ep, pipe)
usbd_device_handle dev;
usbd_interface_handle iface;
struct usbd_endpoint *ep;
- usbd_pipe_handle *rpipe;
+ usbd_pipe_handle *pipe;
{
- usbd_pipe_handle pipe;
- usbd_status err;
+ usbd_pipe_handle p;
+ usbd_status r;
DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n",
- dev, iface, ep, rpipe));
- pipe = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
- if (!pipe)
+ dev, iface, ep, pipe));
+ p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);
+ if (p == 0)
return (USBD_NOMEM);
-
- pipe->device = dev;
- pipe->iface = iface;
- pipe->state = USBD_PIPE_ACTIVE;
- pipe->endpoint = ep;
+ p->device = dev;
+ p->iface = iface;
+ p->endpoint = ep;
ep->refcnt++;
- pipe->refcnt = 1;
- pipe->intrreqh = 0;
- pipe->running = 0;
- pipe->disco = 0;
- pipe->discoarg = 0;
- SIMPLEQ_INIT(&pipe->queue);
-
- err = dev->bus->open_pipe(pipe);
- if (err) {
- DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, %s\n",
- ep->edesc->bEndpointAddress, usbd_errstr(err)));
- free(pipe, M_USB);
- return (err);
+ p->refcnt = 1;
+ p->intrreqh = 0;
+ p->running = 0;
+ p->repeat = 0;
+ SIMPLEQ_INIT(&p->queue);
+ r = dev->bus->methods->open_pipe(p);
+ if (r != USBD_NORMAL_COMPLETION) {
+ DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, error="
+ "%s\n",
+ ep->edesc->bEndpointAddress, usbd_errstr(r)));
+ free(p, M_USB);
+ return (r);
}
-
- *rpipe = pipe;
+ /* Clear any stall and make sure DATA0 toggle will be used next. */
+ if (UE_GET_ADDR(ep->edesc->bEndpointAddress) != USB_CONTROL_ENDPOINT)
+ usbd_clear_endpoint_stall(p);
+ *pipe = p;
return (USBD_NORMAL_COMPLETION);
}
@@ -690,29 +719,30 @@ usbd_getnewaddr(bus)
for (addr = 1; addr < USB_MAX_DEVICES; addr++)
if (bus->devices[addr] == 0)
return (addr);
-
return (-1);
}
+
usbd_status
usbd_probe_and_attach(parent, dev, port, addr)
- bdevice *parent;
+ device_ptr_t parent;
usbd_device_handle dev;
int port;
int addr;
{
struct usb_attach_arg uaa;
usb_device_descriptor_t *dd = &dev->ddesc;
- int found = 0;
- int err, i, confi, nifaces;
+ int r, found, i, confi, nifaces;
+ device_ptr_t dv;
usbd_interface_handle ifaces[256]; /* 256 is the absolute max */
#if defined(__FreeBSD__)
-/* XXX uaa is a static var. Not a problem as it _should_ be used only
- * during probe and attach. Should be changed however
- */
- bdevice bdev;
- bdev = device_add_child(*parent, NULL, -1, &uaa);
+ /*
+ * XXX uaa is a static var. Not a problem as it _should_ be used only
+ * during probe and attach. Should be changed however.
+ */
+ device_t bdev;
+ bdev = device_add_child(parent, NULL, -1, &uaa);
if (!bdev) {
printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev));
return (USBD_INVAL);
@@ -728,10 +758,20 @@ usbd_probe_and_attach(parent, dev, port, addr)
uaa.port = port;
uaa.configno = UHUB_UNK_CONFIGURATION;
uaa.ifaceno = UHUB_UNK_INTERFACE;
+ uaa.vendor = UGETW(dd->idVendor);
+ uaa.product = UGETW(dd->idProduct);
+ uaa.release = UGETW(dd->bcdDevice);
/* First try with device specific drivers. */
- if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch))
+ dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
+ if (dv) {
+ dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
+ if (dev->subdevs == 0)
+ return (USBD_NOMEM);
+ dev->subdevs[0] = dv;
+ dev->subdevs[1] = 0;
return (USBD_NORMAL_COMPLETION);
+ }
DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));
@@ -739,11 +779,21 @@ 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));
- err = usbd_set_config_index(dev, confi, 1);
- if (err) {
- printf("%s: port %d, set config at addr %d failed, %s\n",
- USBDEVNAME(*parent), port, addr, usbd_errstr(err));
- return (err);
+ r = usbd_set_config_index(dev, confi, 1);
+ if (r != USBD_NORMAL_COMPLETION) {
+#ifdef USB_DEBUG
+ DPRINTF(("%s: port %d, set config at addr %d failed, "
+ "error=%s\n", USBDEVPTRNAME(parent), port,
+ addr, usbd_errstr(r)));
+#else
+ printf("%s: port %d, set config at addr %d failed\n",
+ USBDEVPTRNAME(parent), port, addr);
+#endif
+#if defined(__FreeBSD__)
+ device_delete_child(parent, bdev);
+#endif
+
+ return (r);
}
nifaces = dev->cdesc->bNumInterface;
uaa.configno = dev->cdesc->bConfigurationValue;
@@ -751,38 +801,56 @@ 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__)
+ device_delete_child(parent, bdev);
+#endif
+ return (USBD_NOMEM);
+ }
+
+ found = 0;
for (i = 0; i < nifaces; i++) {
if (!ifaces[i])
continue; /* interface already claimed */
+
uaa.iface = ifaces[i];
uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
- if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print,
- usbd_submatch)) {
- found++;
+ dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print,
+ usbd_submatch);
+ if (dv) {
+ dev->subdevs[found++] = dv;
+ dev->subdevs[found] = 0;
ifaces[i] = 0; /* consumed */
#if defined(__FreeBSD__)
- /* create another device for the next iface */
- bdev = device_add_child(*parent, NULL, -1, &uaa);
+ /* create another child for the next iface */
+ bdev = device_add_child(parent, NULL, -1, &uaa);
if (!bdev) {
printf("%s: Device creation failed\n",
- USBDEVNAME(dev->bus->bdev));
+ USBDEVNAME(dev->bus->bdev));
return (USBD_NORMAL_COMPLETION);
}
device_quiet(bdev);
#endif
}
}
+
if (found != 0) {
#if defined(__FreeBSD__)
- /* remove the last created child again, it is unused */
- device_delete_child(*parent, bdev);
+ /* remove the last created child again; it is unused */
+ device_delete_child(parent, bdev);
#endif
return (USBD_NORMAL_COMPLETION);
}
+
+ free(dev->subdevs, M_USB);
+ dev->subdevs = 0;
}
/* No interfaces were attached in any of the configurations. */
- if (dd->bNumConfigurations > 1)/* don't change if only 1 config */
+
+ if (dd->bNumConfigurations > 1) /* don't change if only 1 config */
usbd_set_config_index(dev, 0, 0);
DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));
@@ -792,8 +860,18 @@ usbd_probe_and_attach(parent, dev, port, addr)
uaa.usegeneric = 1;
uaa.configno = UHUB_UNK_CONFIGURATION;
uaa.ifaceno = UHUB_UNK_INTERFACE;
- if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch))
+ uaa.vendor = UHUB_UNK_VENDOR;
+ uaa.product = UHUB_UNK_PRODUCT;
+ uaa.release = UHUB_UNK_RELEASE;
+ dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
+ if (dv) {
+ dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
+ if (dev->subdevs == 0)
+ return (USBD_NOMEM);
+ dev->subdevs[0] = dv;
+ dev->subdevs[1] = 0;
return (USBD_NORMAL_COMPLETION);
+ }
/*
* The generic attach failed, but leave the device as it is.
@@ -802,13 +880,9 @@ usbd_probe_and_attach(parent, dev, port, addr)
*/
DPRINTF(("usbd_probe_and_attach: generic attach failed\n"));
#if defined(__FreeBSD__)
-/*
- * XXX should we delete the child again? Left for now to avoid dangling
- * references.
- device_delete_child(*parent, bdev);
-*/
+ device_delete_child(parent, bdev);
#endif
- return (USBD_NORMAL_COMPLETION);
+ return (USBD_NORMAL_COMPLETION);
}
@@ -821,7 +895,7 @@ usbd_probe_and_attach(parent, dev, port, addr)
*/
usbd_status
usbd_new_device(parent, bus, depth, lowspeed, port, up)
- bdevice *parent;
+ device_ptr_t parent;
usbd_bus_handle bus;
int depth;
int lowspeed;
@@ -830,7 +904,7 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
{
usbd_device_handle dev;
usb_device_descriptor_t *dd;
- usbd_status err;
+ usbd_status r;
int addr;
int i;
@@ -852,7 +926,6 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
/* Set up default endpoint handle. */
dev->def_ep.edesc = &dev->def_ep_desc;
- dev->def_ep.state = USBD_ENDPOINT_ACTIVE;
/* Set up default endpoint descriptor. */
dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
@@ -862,7 +935,6 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);
dev->def_ep_desc.bInterval = 0;
- dev->state = USBD_DEVICE_DEFAULT;
dev->quirks = &usbd_no_quirk;
dev->address = USB_START_ADDR;
dev->ddesc.bMaxPacketSize = 0;
@@ -872,10 +944,10 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
dev->langid = USBD_NOLANG;
/* Establish the the default pipe. */
- err = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe);
- if (err) {
+ r = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe);
+ if (r != USBD_NORMAL_COMPLETION) {
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
up->device = dev;
@@ -883,18 +955,25 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
/* Try a few times in case the device is slow (i.e. outside specs.) */
for (i = 0; i < 5; i++) {
/* Get the first 8 bytes of the device descriptor. */
- err = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
- if (err == USBD_NORMAL_COMPLETION)
+ r = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);
+ if (r == USBD_NORMAL_COMPLETION)
break;
usbd_delay_ms(dev, 200);
}
- if (err) {
+ if (r != USBD_NORMAL_COMPLETION) {
DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "
- "failed\n", addr));
+ "failed\n",
+ addr));
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
+ DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
+ "subclass=%d, protocol=%d, maxpacket=%d, len=%d, ls=%d\n",
+ addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
+ dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength,
+ dev->lowspeed));
+
if (dd->bDescriptorType != UDESC_DEVICE) {
/* Illegal device descriptor */
DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n",
@@ -903,38 +982,38 @@ usbd_new_device(parent, bus, depth, lowspeed, port, up)
return (USBD_INVAL);
}
- DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "
- "subclass=%d, protocol=%d, maxpacket=%d, ls=%d\n",
- addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,
- dd->bDeviceProtocol, dd->bMaxPacketSize, dev->lowspeed));
+ if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
+ DPRINTFN(-1,("usbd_new_device: bad length %d\n", dd->bLength));
+ usbd_remove_device(dev, up);
+ return (USBD_INVAL);
+ }
USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);
/* Get the full device descriptor. */
- err = usbd_get_device_desc(dev, dd);
- if (err) {
+ r = usbd_get_device_desc(dev, dd);
+ if (r != USBD_NORMAL_COMPLETION) {
DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc "
"failed\n", addr));
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
/* Figure out what's wrong with this device. */
dev->quirks = usbd_find_quirk(dd);
/* Set the address */
- err = usbd_set_address(dev, addr);
- if (err) {
- DPRINTFN(-1,("usbd_new_device: set address %d failed\n",addr));
- err = USBD_SET_ADDR_FAILED;
+ r = usbd_set_address(dev, addr);
+ if (r != USBD_NORMAL_COMPLETION) {
+ DPRINTFN(-1,("usb_new_device: set address %d failed\n",addr));
+ r = USBD_SET_ADDR_FAILED;
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
/* Allow device time to set new address */
usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
dev->address = addr; /* New device address now */
- dev->state = USBD_DEVICE_ADDRESSED;
bus->devices[addr] = dev;
/* Assume 100mA bus powered for now. Changed when configured. */
@@ -944,12 +1023,12 @@ 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));
- err = usbd_probe_and_attach(parent, dev, port, addr);
- if (err) {
+ r = usbd_probe_and_attach(parent, dev, port, addr);
+ if (r != USBD_NORMAL_COMPLETION) {
usbd_remove_device(dev, up);
- return (err);
+ return (r);
}
-
+
return (USBD_NORMAL_COMPLETION);
}
@@ -962,14 +1041,13 @@ usbd_remove_device(dev, up)
if (dev->default_pipe)
usbd_kill_pipe(dev->default_pipe);
-
up->device = 0;
dev->bus->devices[dev->address] = 0;
free(dev, M_USB);
}
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(__OpenBSD__)
int
usbd_print(aux, pnp)
void *aux;
@@ -991,15 +1069,38 @@ usbd_print(aux, pnp)
printf(" configuration %d", uaa->configno);
if (uaa->ifaceno != UHUB_UNK_INTERFACE)
printf(" interface %d", uaa->ifaceno);
+#if 0
+ /*
+ * It gets very crowded with these locators on the attach line.
+ * They are not really needed since they are printed in the clear
+ * by each driver.
+ */
+ if (uaa->vendor != UHUB_UNK_VENDOR)
+ printf(" vendor 0x%04x", uaa->vendor);
+ if (uaa->product != UHUB_UNK_PRODUCT)
+ printf(" product 0x%04x", uaa->product);
+ if (uaa->release != UHUB_UNK_RELEASE)
+ printf(" release 0x%04x", uaa->release);
+#endif
return (UNCONF);
}
+#if defined(__NetBSD__)
int
usbd_submatch(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
+#elif defined(__OpenBSD__)
+int
+usbd_submatch(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ struct cfdata *cf = match;
+#endif
struct usb_attach_arg *uaa = aux;
if ((uaa->port != 0 &&
@@ -1010,86 +1111,34 @@ usbd_submatch(parent, cf, aux)
cf->uhubcf_configuration != uaa->configno) ||
(uaa->ifaceno != UHUB_UNK_INTERFACE &&
cf->uhubcf_interface != UHUB_UNK_INTERFACE &&
- cf->uhubcf_interface != uaa->ifaceno))
+ cf->uhubcf_interface != uaa->ifaceno) ||
+ (uaa->vendor != UHUB_UNK_VENDOR &&
+ cf->uhubcf_vendor != UHUB_UNK_VENDOR &&
+ cf->uhubcf_vendor != uaa->vendor) ||
+ (uaa->product != UHUB_UNK_PRODUCT &&
+ cf->uhubcf_product != UHUB_UNK_PRODUCT &&
+ cf->uhubcf_product != uaa->product) ||
+ (uaa->release != UHUB_UNK_RELEASE &&
+ cf->uhubcf_release != UHUB_UNK_RELEASE &&
+ cf->uhubcf_release != uaa->release)
+ )
return 0;
return ((*cf->cf_attach->ca_match)(parent, cf, aux));
}
-#endif
-
-
-/*
- * Maintain a list of control transfers per pipe. As soon as the
- * previous one for the queue is done the next one is submitted
- */
-usbd_status
-usb_insert_transfer(reqh)
- usbd_request_handle reqh;
-{
- usbd_pipe_handle pipe = reqh->pipe;
- usbd_interface_handle iface = pipe->iface;
-
- if (pipe->state == USBD_PIPE_IDLE ||
- (iface && iface->state == USBD_INTERFACE_IDLE))
- return (USBD_IS_IDLE);
- SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);
- if (pipe->state != USBD_PIPE_ACTIVE ||
- (iface && iface->state != USBD_INTERFACE_ACTIVE))
- return (USBD_NOT_STARTED);
- if (pipe->running)
- return (USBD_IN_PROGRESS);
- pipe->running = 1;
- return (USBD_NORMAL_COMPLETION);
-}
-void
-usb_start_next(pipe)
- usbd_pipe_handle pipe;
-{
- usbd_request_handle reqh;
- usbd_status err;
-
-#ifdef DIAGNOSTIC
- if (SIMPLEQ_FIRST(&pipe->queue) == 0) {
- printf("usb_start_next: empty\n");
- return;
- }
#endif
- /* First remove finished transfer */
-#if defined(__NetBSD__)
- SIMPLEQ_REMOVE_HEAD(&pipe->queue, SIMPLEQ_FIRST(&pipe->queue), next);
-#elif defined(__FreeBSD__)
- SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);
-#endif
- if (pipe->state != USBD_PIPE_ACTIVE) {
- pipe->running = 0;
- return;
- }
- reqh = SIMPLEQ_FIRST(&pipe->queue);
- DPRINTFN(5, ("usb_start_next: start reqh=%p\n", reqh));
- if (!reqh)
- pipe->running = 0;
- else {
- err = pipe->methods->start(reqh);
- if (err != USBD_IN_PROGRESS) {
- printf("usb_start_next: error=%d\n", err);
- pipe->running = 0;
- /* XXX do what? */
- }
- }
-}
-
void
usbd_fill_deviceinfo(dev, di)
usbd_device_handle dev;
struct usb_device_info *di;
{
- struct usbd_port *port;
- int i, err, s;
+ struct usbd_port *p;
+ int i, r, s;
di->config = dev->config;
usbd_devinfo_vp(dev, di->vendor, di->product);
- usbd_printBCD(di->revision, UGETW(dev->ddesc.bcdDevice));
+ usbd_printBCD(di->release, UGETW(dev->ddesc.bcdDevice));
di->vendorNo = UGETW(dev->ddesc.idVendor);
di->productNo = UGETW(dev->ddesc.idProduct);
di->class = dev->ddesc.bDeviceClass;
@@ -1101,24 +1150,44 @@ usbd_fill_deviceinfo(dev, di)
i < sizeof(di->ports) / sizeof(di->ports[0]) &&
i < dev->hub->hubdesc.bNbrPorts;
i++) {
- port = &dev->hub->ports[i];
- if (port->device)
- err = port->device->address;
+ p = &dev->hub->ports[i];
+ if (p->device)
+ r = p->device->address;
else {
- s = UGETW(port->status.wPortStatus);
+ s = UGETW(p->status.wPortStatus);
if (s & UPS_PORT_ENABLED)
- err = USB_PORT_ENABLED;
+ r = USB_PORT_ENABLED;
else if (s & UPS_SUSPEND)
- err = USB_PORT_SUSPENDED;
+ r = USB_PORT_SUSPENDED;
else if (s & UPS_PORT_POWER)
- err = USB_PORT_POWERED;
+ r = USB_PORT_POWERED;
else
- err = USB_PORT_DISABLED;
+ r = USB_PORT_DISABLED;
}
- di->ports[i] = err;
+ di->ports[i] = r;
}
di->nports = dev->hub->hubdesc.bNbrPorts;
} else
di->nports = 0;
}
+void
+usb_free_device(dev)
+ usbd_device_handle dev;
+{
+ int ifcidx, nifc;
+
+ if (dev->default_pipe)
+ usbd_kill_pipe(dev->default_pipe);
+ if (dev->ifaces) {
+ nifc = dev->cdesc->bNumInterface;
+ for (ifcidx = 0; ifcidx < nifc; ifcidx++)
+ usbd_free_iface_data(dev, ifcidx);
+ free(dev->ifaces, M_USB);
+ }
+ if (dev->cdesc)
+ free(dev->cdesc, M_USB);
+ if (dev->subdevs)
+ free(dev->subdevs, M_USB);
+ free(dev, M_USB);
+}
OpenPOWER on IntegriCloud