diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2011-01-16 22:35:30 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2011-01-16 22:35:30 +0000 |
commit | bf7dd43b0ff651c5b7ba593bceb215dc29ad45d7 (patch) | |
tree | 45e6e943d25ebc8148bddd5d6a8250fbb43a6d85 /sys/dev/usb | |
parent | 3ea785dfac3b842c38d5b36eb3a32b8af8086460 (diff) |
* instead of NULLing pointers to interface descriptors in the uaa, mark
interfaces as being claimed in the usbd_device's copy of the interface
descriptors
* allow ugen(4) to be attached if there are unused interfaces in a
configuration that has had drivers attached
* make ugen(4) aware that it may be sharing a device with (an)other
driver(s), and if so:
* do not let ugen(4) change the configuration
* do not let ugen(4) access the already claimed interfaces
discussed with deraadt and miod
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/if_cdce.c | 6 | ||||
-rw-r--r-- | sys/dev/usb/if_urndis.c | 6 | ||||
-rw-r--r-- | sys/dev/usb/uaudio.c | 8 | ||||
-rw-r--r-- | sys/dev/usb/ugen.c | 42 | ||||
-rw-r--r-- | sys/dev/usb/umodem.c | 6 | ||||
-rw-r--r-- | sys/dev/usb/usb_subr.c | 57 | ||||
-rw-r--r-- | sys/dev/usb/usbdi.c | 20 | ||||
-rw-r--r-- | sys/dev/usb/usbdi.h | 6 | ||||
-rw-r--r-- | sys/dev/usb/usbdivar.h | 4 | ||||
-rw-r--r-- | sys/dev/usb/uvideo.c | 28 |
10 files changed, 122 insertions, 61 deletions
diff --git a/sys/dev/usb/if_cdce.c b/sys/dev/usb/if_cdce.c index cb91ba3e0b9..2e91ec8c0bb 100644 --- a/sys/dev/usb/if_cdce.c +++ b/sys/dev/usb/if_cdce.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_cdce.c,v 1.47 2010/10/27 17:51:11 jakemsr Exp $ */ +/* $OpenBSD: if_cdce.c,v 1.48 2011/01/16 22:35:29 jakemsr Exp $ */ /* * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com> @@ -224,12 +224,12 @@ cdce_attach(struct device *parent, struct device *self, void *aux) DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n", ctl_ifcno, data_ifcno)); for (i = 0; i < uaa->nifaces; i++) { - if (uaa->ifaces[i] == NULL) + if (usbd_iface_claimed(sc->cdce_udev, i)) continue; id = usbd_get_interface_descriptor(uaa->ifaces[i]); if (id != NULL && id->bInterfaceNumber == data_ifcno) { sc->cdce_data_iface = uaa->ifaces[i]; - uaa->ifaces[i] = NULL; + usbd_claim_iface(sc->cdce_udev, i); } } } diff --git a/sys/dev/usb/if_urndis.c b/sys/dev/usb/if_urndis.c index 29f9dd597b0..71a3a093593 100644 --- a/sys/dev/usb/if_urndis.c +++ b/sys/dev/usb/if_urndis.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_urndis.c,v 1.27 2010/10/27 17:51:11 jakemsr Exp $ */ +/* $OpenBSD: if_urndis.c,v 1.28 2011/01/16 22:35:29 jakemsr Exp $ */ /* * Copyright (c) 2010 Jonathan Armani <armani@openbsd.org> @@ -1389,12 +1389,12 @@ urndis_attach(struct device *parent, struct device *self, void *aux) DPRINTF(("urndis_attach: union interface: ctl %u, data %u\n", if_ctl, if_data)); for (i = 0; i < uaa->nifaces; i++) { - if (uaa->ifaces[i] == NULL) + if (usbd_iface_claimed(sc->sc_udev, i)) continue; id = usbd_get_interface_descriptor(uaa->ifaces[i]); if (id && id->bInterfaceNumber == if_data) { sc->sc_iface_data = uaa->ifaces[i]; - uaa->ifaces[i] = NULL; + usbd_claim_iface(sc->sc_udev, i); } } } diff --git a/sys/dev/usb/uaudio.c b/sys/dev/usb/uaudio.c index f91aaa1d57a..7a357bec7b0 100644 --- a/sys/dev/usb/uaudio.c +++ b/sys/dev/usb/uaudio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uaudio.c,v 1.89 2010/08/18 22:54:58 jakemsr Exp $ */ +/* $OpenBSD: uaudio.c,v 1.90 2011/01/16 22:35:29 jakemsr Exp $ */ /* $NetBSD: uaudio.c,v 1.90 2004/10/29 17:12:53 kent Exp $ */ /* @@ -210,7 +210,6 @@ struct uaudio_softc { struct device sc_dev; /* base device */ usbd_device_handle sc_udev; /* USB device */ int sc_ac_iface; /* Audio Control interface */ - usbd_interface_handle sc_ac_ifaceh; struct chan sc_playchan; /* play channel */ struct chan sc_recchan; /* record channel */ int sc_nullalt; @@ -520,10 +519,9 @@ uaudio_attach(struct device *parent, struct device *self, void *aux) return; } - sc->sc_ac_ifaceh = uaa->iface; /* Pick up the AS interface. */ for (i = 0; i < uaa->nifaces; i++) { - if (uaa->ifaces[i] == NULL) + if (usbd_iface_claimed(sc->sc_udev, i)) continue; id = usbd_get_interface_descriptor(uaa->ifaces[i]); if (id == NULL) @@ -537,7 +535,7 @@ uaudio_attach(struct device *parent, struct device *self, void *aux) } } if (found) - uaa->ifaces[i] = NULL; + usbd_claim_iface(sc->sc_udev, i); } for (j = 0; j < sc->sc_nalts; j++) { diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c index 457b77cd894..8261bbe9c2d 100644 --- a/sys/dev/usb/ugen.c +++ b/sys/dev/usb/ugen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ugen.c,v 1.62 2010/09/24 08:33:59 yuo Exp $ */ +/* $OpenBSD: ugen.c,v 1.63 2011/01/16 22:35:29 jakemsr Exp $ */ /* $NetBSD: ugen.c,v 1.63 2002/11/26 18:49:48 christos Exp $ */ /* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */ @@ -103,6 +103,7 @@ struct ugen_softc { int sc_refcnt; u_char sc_dying; + u_char sc_secondary; }; void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, @@ -166,13 +167,18 @@ ugen_attach(struct device *parent, struct device *self, void *aux) sc->sc_udev = udev = uaa->device; - /* First set configuration index 0, the default one for ugen. */ - err = usbd_set_config_index(udev, 0, 0); - if (err) { - printf("%s: setting configuration index 0 failed\n", - sc->sc_dev.dv_xname); - sc->sc_dying = 1; - return; + if (usbd_get_devcnt(udev) > 0) + sc->sc_secondary = 1; + + if (!sc->sc_secondary) { + /* First set configuration index 0, the default one for ugen. */ + err = usbd_set_config_index(udev, 0, 0); + if (err) { + printf("%s: setting configuration index 0 failed\n", + sc->sc_dev.dv_xname); + sc->sc_dying = 1; + return; + } } conf = usbd_get_config_descriptor(udev)->bConfigurationValue; @@ -220,9 +226,15 @@ ugen_set_config(struct ugen_softc *sc, int configno) /* Avoid setting the current value. */ cdesc = usbd_get_config_descriptor(dev); if (!cdesc || cdesc->bConfigurationValue != configno) { - err = usbd_set_config_no(dev, configno, 1); - if (err) - return (err); + if (sc->sc_secondary) { + printf("%s: secondary, not changing config to %d\n", + __func__, configno); + return (USBD_IN_USE); + } else { + err = usbd_set_config_no(dev, configno, 1); + if (err) + return (err); + } } err = usbd_interface_count(dev, &niface); @@ -231,6 +243,11 @@ ugen_set_config(struct ugen_softc *sc, int configno) memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints); for (ifaceno = 0; ifaceno < niface; ifaceno++) { DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno)); + if (usbd_iface_claimed(sc->sc_udev, ifaceno)) { + DPRINTF(("%s: iface %d not available\n", __func__, + ifaceno)); + continue; + } err = usbd_device2interface_handle(dev, ifaceno, &iface); if (err) return (err); @@ -897,7 +914,8 @@ ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno) err = usbd_interface_count(sc->sc_udev, &niface); if (err) return (err); - if (ifaceidx < 0 || ifaceidx >= niface) + if (ifaceidx < 0 || ifaceidx >= niface || + usbd_iface_claimed(sc->sc_udev, ifaceidx)) return (USBD_INVAL); err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface); diff --git a/sys/dev/usb/umodem.c b/sys/dev/usb/umodem.c index 4b55568eff1..cab12b62537 100644 --- a/sys/dev/usb/umodem.c +++ b/sys/dev/usb/umodem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: umodem.c,v 1.39 2010/12/02 01:37:45 jakemsr Exp $ */ +/* $OpenBSD: umodem.c,v 1.40 2011/01/16 22:35:29 jakemsr Exp $ */ /* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */ /* @@ -280,12 +280,12 @@ umodem_attach(struct device *parent, struct device *self, void *aux) /* Get the data interface too. */ for (i = 0; i < uaa->nifaces; i++) { - if (uaa->ifaces[i] != NULL) { + if (!usbd_iface_claimed(sc->sc_udev, i)) { id = usbd_get_interface_descriptor(uaa->ifaces[i]); if (id != NULL && id->bInterfaceNumber == data_iface_no) { sc->sc_data_iface = uaa->ifaces[i]; - uaa->ifaces[i] = NULL; + usbd_claim_iface(sc->sc_udev, i); } } } diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c index 498c579b4db..b46b0649a6a 100644 --- a/sys/dev/usb/usb_subr.c +++ b/sys/dev/usb/usb_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usb_subr.c,v 1.78 2011/01/15 23:58:43 jakemsr Exp $ */ +/* $OpenBSD: usb_subr.c,v 1.79 2011/01/16 22:35:29 jakemsr Exp $ */ /* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */ @@ -777,7 +777,7 @@ usbd_set_config_index(usbd_device_handle dev, int index, int msg) /* Allocate and fill interface data. */ nifc = cdp->bNumInterface; dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), - M_USB, M_NOWAIT); + M_USB, M_NOWAIT | M_ZERO); if (dev->ifaces == NULL) { err = USBD_NOMEM; goto bad; @@ -859,14 +859,13 @@ usbd_getnewaddr(usbd_bus_handle bus) return (-1); } - usbd_status usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port, int addr) { struct usb_attach_arg uaa; usb_device_descriptor_t *dd = &dev->ddesc; - int found, i, confi, nifaces, len; + int i, confi, nifaces, len; usbd_status err; struct device *dv; usbd_interface_handle *ifaces; @@ -895,8 +894,8 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port, err = USBD_NOMEM; goto fail; } - dev->subdevs[0] = dv; - dev->subdevs[1] = 0; + dev->subdevs[dev->ndevs++] = dv; + dev->subdevs[dev->ndevs] = 0; err = USBD_NORMAL_COMPLETION; goto fail; } @@ -934,7 +933,9 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port, ifaces[i] = &dev->ifaces[i]; uaa.ifaces = ifaces; uaa.nifaces = nifaces; - len = (nifaces+1) * sizeof dv; + + /* add 1 for possible ugen and 1 for NULL terminator */ + len = (nifaces + 2) * sizeof dv; dev->subdevs = malloc(len, M_USB, M_NOWAIT | M_ZERO); if (dev->subdevs == NULL) { free(ifaces, M_USB); @@ -942,25 +943,31 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port, goto fail; } - found = 0; for (i = 0; i < nifaces; i++) { - if (ifaces[i] == NULL) - continue; /* interface already claimed */ + if (usbd_iface_claimed(dev, i)) + continue; uaa.iface = ifaces[i]; uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber; dv = config_found_sm(parent, &uaa, usbd_print, usbd_submatch); - if (dv != NULL) { - dev->subdevs[found++] = dv; - ifaces[i] = NULL; /* consumed */ + dev->subdevs[dev->ndevs++] = dv; + usbd_claim_iface(dev, i); } } free(ifaces, M_USB); - if (found != 0) { - err = USBD_NORMAL_COMPLETION; - goto fail; + + if (dev->ndevs > 0) { + for (i = 0; i < nifaces; i++) { + if (!usbd_iface_claimed(dev, i)) + break; + } + if (i < nifaces) + goto generic; + else + goto fail; } + free(dev->subdevs, M_USB); dev->subdevs = 0; } @@ -971,20 +978,24 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port, DPRINTF(("usbd_probe_and_attach: no interface drivers found\n")); +generic: /* Finally try the generic driver. */ uaa.iface = NULL; uaa.usegeneric = 1; - uaa.configno = UHUB_UNK_CONFIGURATION; + uaa.configno = dev->ndevs == 0 ? UHUB_UNK_CONFIGURATION : + dev->cdesc->bConfigurationValue; uaa.ifaceno = UHUB_UNK_INTERFACE; dv = config_found_sm(parent, &uaa, usbd_print, usbd_submatch); if (dv != NULL) { - dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); - if (dev->subdevs == 0) { - err = USBD_NOMEM; - goto fail; + if (dev->ndevs == 0) { + dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT); + if (dev->subdevs == NULL) { + err = USBD_NOMEM; + goto fail; + } } - dev->subdevs[0] = dv; - dev->subdevs[1] = 0; + dev->subdevs[dev->ndevs++] = dv; + dev->subdevs[dev->ndevs] = 0; err = USBD_NORMAL_COMPLETION; goto fail; } diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c index 78e80e7c882..d0f90c25f9d 100644 --- a/sys/dev/usb/usbdi.c +++ b/sys/dev/usb/usbdi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdi.c,v 1.42 2010/12/30 05:10:35 jakemsr Exp $ */ +/* $OpenBSD: usbdi.c,v 1.43 2011/01/16 22:35:29 jakemsr Exp $ */ /* $NetBSD: usbdi.c,v 1.103 2002/09/27 15:37:38 provos Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */ @@ -117,6 +117,24 @@ usbd_ref_wait(usbd_device_handle dev) tsleep(&dev->ref_cnt, PWAIT, "usbref", hz * 60); } +int +usbd_get_devcnt(usbd_device_handle dev) +{ + return (dev->ndevs); +} + +void +usbd_claim_iface(usbd_device_handle dev, int ifaceidx) +{ + dev->ifaces[ifaceidx].claimed = 1; +} + +int +usbd_iface_claimed(usbd_device_handle dev, int ifaceidx) +{ + return (dev->ifaces[ifaceidx].claimed); +} + static __inline int usbd_xfer_isread(usbd_xfer_handle xfer) { diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index c7bc9a4c09e..0dd722f33ff 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdi.h,v 1.37 2010/12/30 05:10:35 jakemsr Exp $ */ +/* $OpenBSD: usbdi.h,v 1.38 2011/01/16 22:35:29 jakemsr Exp $ */ /* $NetBSD: usbdi.h,v 1.62 2002/07/11 21:14:35 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */ @@ -165,6 +165,10 @@ usbd_status usbd_reload_device_desc(usbd_device_handle); int usbd_ratecheck(struct timeval *last); +int usbd_get_devcnt(usbd_device_handle); +void usbd_claim_iface(usbd_device_handle, int); +int usbd_iface_claimed(usbd_device_handle, int); + int usbd_is_dying(usbd_device_handle); void usbd_deactivate(usbd_device_handle); diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h index f53369945ad..52d6ade7563 100644 --- a/sys/dev/usb/usbdivar.h +++ b/sys/dev/usb/usbdivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usbdivar.h,v 1.41 2010/12/30 05:10:35 jakemsr Exp $ */ +/* $OpenBSD: usbdivar.h,v 1.42 2011/01/16 22:35:29 jakemsr Exp $ */ /* $NetBSD: usbdivar.h,v 1.70 2002/07/11 21:14:36 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */ @@ -147,6 +147,7 @@ struct usbd_device { const struct usbd_quirks *quirks; /* device quirks, always set */ struct usbd_hub *hub; /* only if this is a hub */ struct device **subdevs; /* sub-devices, 0 terminated */ + int ndevs; /* # of subdevs */ }; struct usbd_interface { @@ -157,6 +158,7 @@ struct usbd_interface { struct usbd_endpoint *endpoints; void *priv; LIST_HEAD(, usbd_pipe) pipes; + u_int8_t claimed; }; struct usbd_pipe { diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c index 72a28548294..f0f85b5aba8 100644 --- a/sys/dev/usb/uvideo.c +++ b/sys/dev/usb/uvideo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvideo.c,v 1.147 2010/11/24 19:53:07 jakemsr Exp $ */ +/* $OpenBSD: uvideo.c,v 1.148 2011/01/16 22:35:29 jakemsr Exp $ */ /* * Copyright (c) 2008 Robert Nagy <robert@openbsd.org> @@ -468,13 +468,24 @@ uvideo_attach(struct device *parent, struct device *self, void *aux) { struct uvideo_softc *sc = (struct uvideo_softc *)self; struct usb_attach_arg *uaa = aux; + usb_interface_descriptor_t *id; + int i; sc->sc_udev = uaa->device; sc->sc_nifaces = uaa->nifaces; - sc->sc_ifaces = malloc(uaa->nifaces * sizeof(usbd_interface_handle), - M_USB, M_WAITOK); - bcopy(uaa->ifaces, sc->sc_ifaces, - uaa->nifaces * sizeof(usbd_interface_handle)); + /* + * Claim all video interfaces. Interfaces must be claimed during + * attach, during attach hooks is too late. + */ + for (i = 0; i < sc->sc_nifaces; i++) { + if (usbd_iface_claimed(sc->sc_udev, i)) + continue; + id = usbd_get_interface_descriptor(&sc->sc_udev->ifaces[i]); + if (id == NULL) + continue; + if (id->bInterfaceClass == UICLASS_VIDEO) + usbd_claim_iface(sc->sc_udev, i); + } /* maybe the device has quirks */ sc->sc_quirk = uvideo_lookup(uaa->vendor, uaa->product); @@ -557,8 +568,6 @@ uvideo_detach(struct device *self, int flags) struct uvideo_softc *sc = (struct uvideo_softc *)self; int rv = 0; - free(sc->sc_ifaces, M_USB); - /* Wait for outstanding requests to complete */ usbd_delay_ms(sc->sc_udev, UVIDEO_NFRAMES_MAX); @@ -837,12 +846,13 @@ uvideo_vs_parse_desc(struct uvideo_softc *sc, usb_config_descriptor_t *cdesc) for (i = 0; i < sc->sc_desc_vc_header.fix->bInCollection; i++) { iface = sc->sc_desc_vc_header.baInterfaceNr[i]; - id = usbd_get_interface_descriptor(sc->sc_ifaces[iface]); + id = usbd_get_interface_descriptor(&sc->sc_udev->ifaces[iface]); if (id == NULL) { printf("%s: can't get VS interface %d!\n", DEVNAME(sc), iface); return (USBD_INVAL); } + usbd_claim_iface(sc->sc_udev, iface); numalts = usbd_get_no_alts(cdesc, id->bInterfaceNumber); @@ -1197,7 +1207,7 @@ uvideo_vs_parse_desc_alt(struct uvideo_softc *sc, int vs_nr, int iface, int numa /* save endpoint with largest bandwidth */ if (UGETW(ed->wMaxPacketSize) > vs->psize) { - vs->ifaceh = sc->sc_ifaces[iface]; + vs->ifaceh = &sc->sc_udev->ifaces[iface]; vs->endpoint = ed->bEndpointAddress; vs->numalts = numalts; vs->curalt = id->bAlternateSetting; |