Module Name: src Committed By: ws Date: Tue Feb 20 15:48:37 UTC 2018
Modified Files: src/sys/dev/usb: files.usb uftdi.c ugen.c Log Message: Attach uftdi to each interface found in the device separately. This allows for other drivers (e.g. ugen) to attach to some of the other interfaces. Allow ugen to attach only to some of the interfaces found in a device. To generate a diff of this commit: cvs rdiff -u -r1.148 -r1.149 src/sys/dev/usb/files.usb cvs rdiff -u -r1.66 -r1.67 src/sys/dev/usb/uftdi.c cvs rdiff -u -r1.137 -r1.138 src/sys/dev/usb/ugen.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/files.usb diff -u src/sys/dev/usb/files.usb:1.148 src/sys/dev/usb/files.usb:1.149 --- src/sys/dev/usb/files.usb:1.148 Sun Dec 10 17:03:07 2017 +++ src/sys/dev/usb/files.usb Tue Feb 20 15:48:37 2018 @@ -1,4 +1,4 @@ -# $NetBSD: files.usb,v 1.148 2017/12/10 17:03:07 bouyer Exp $ +# $NetBSD: files.usb,v 1.149 2018/02/20 15:48:37 ws Exp $ # # Config file and device description for machine-independent USB code. # Included by ports that need it. Ports that use it must provide @@ -138,6 +138,7 @@ file dev/usb/ucom.c ucom | ucombus ne # Generic devices device ugen attach ugen at usbdevif +attach ugen at usbifif with ugenif file dev/usb/ugen.c ugen needs-flag @@ -387,7 +388,7 @@ file dev/usb/umodem.c umodem # FTDI serial driver device uftdi: ucombus -attach uftdi at usbdevif +attach uftdi at usbifif file dev/usb/uftdi.c uftdi # Prolific PL2303 serial driver Index: src/sys/dev/usb/uftdi.c diff -u src/sys/dev/usb/uftdi.c:1.66 src/sys/dev/usb/uftdi.c:1.67 --- src/sys/dev/usb/uftdi.c:1.66 Fri Dec 22 14:18:29 2017 +++ src/sys/dev/usb/uftdi.c Tue Feb 20 15:48:37 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: uftdi.c,v 1.66 2017/12/22 14:18:29 jakllsch Exp $ */ +/* $NetBSD: uftdi.c,v 1.67 2018/02/20 15:48:37 ws Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uftdi.c,v 1.66 2017/12/22 14:18:29 jakllsch Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uftdi.c,v 1.67 2018/02/20 15:48:37 ws Exp $"); #ifdef _KERNEL_OPT #include "opt_usb.h" @@ -62,9 +62,7 @@ int uftdidebug = 0; #define DPRINTFN(n,x) #endif -#define UFTDI_CONFIG_INDEX 0 -#define UFTDI_IFACE_INDEX 0 -#define UFTDI_MAX_PORTS 4 +#define UFTDI_CONFIG_NO 1 /* * These are the default number of bytes transferred per frame if the @@ -83,17 +81,17 @@ int uftdidebug = 0; struct uftdi_softc { device_t sc_dev; /* base device */ struct usbd_device * sc_udev; /* device */ - struct usbd_interface * sc_iface[UFTDI_MAX_PORTS]; /* interface */ + struct usbd_interface * sc_iface; /* interface */ + int sc_iface_no; enum uftdi_type sc_type; u_int sc_hdrlen; - u_int sc_numports; u_int sc_chiptype; u_char sc_msr; u_char sc_lsr; - device_t sc_subdev[UFTDI_MAX_PORTS]; + device_t sc_subdev; u_char sc_dying; @@ -190,29 +188,30 @@ CFATTACH_DECL2_NEW(uftdi, sizeof(struct int uftdi_match(device_t parent, cfdata_t match, void *aux) { - struct usb_attach_arg *uaa = aux; + struct usbif_attach_arg *uiaa = aux; DPRINTFN(20,("uftdi: vendor=0x%x, product=0x%x\n", - uaa->uaa_vendor, uaa->uaa_product)); + uiaa->uiaa_vendor, uiaa->uiaa_product)); - return uftdi_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? - UMATCH_VENDOR_PRODUCT : UMATCH_NONE; + if (uiaa->uiaa_configno != UFTDI_CONFIG_NO) + return UMATCH_NONE; + + return uftdi_lookup(uiaa->uiaa_vendor, uiaa->uiaa_product) != NULL ? + UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE; } void uftdi_attach(device_t parent, device_t self, void *aux) { struct uftdi_softc *sc = device_private(self); - struct usb_attach_arg *uaa = aux; - struct usbd_device *dev = uaa->uaa_device; - struct usbd_interface *iface; + struct usbif_attach_arg *uiaa = aux; + struct usbd_device *dev = uiaa->uiaa_device; + struct usbd_interface *iface = uiaa->uiaa_iface; usb_device_descriptor_t *ddesc; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; char *devinfop; - const char *devname = device_xname(self); - int i,idx; - usbd_status err; + int i; struct ucom_attach_args ucaa; DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc)); @@ -224,122 +223,86 @@ uftdi_attach(device_t parent, device_t s aprint_normal_dev(self, "%s\n", devinfop); usbd_devinfo_free(devinfop); - /* Move the device into the configured state. */ - err = usbd_set_config_index(dev, UFTDI_CONFIG_INDEX, 1); - if (err) { - aprint_error("\n%s: failed to set configuration, err=%s\n", - devname, usbd_errstr(err)); - goto bad; - } - sc->sc_dev = self; sc->sc_udev = dev; - sc->sc_numports = 1; + sc->sc_iface_no = uiaa->uiaa_ifaceno; sc->sc_type = UFTDI_TYPE_8U232AM; /* most devices are post-8U232AM */ sc->sc_hdrlen = 0; - if (uaa->uaa_vendor == USB_VENDOR_FTDI - && uaa->uaa_product == USB_PRODUCT_FTDI_SERIAL_8U100AX) { + if (uiaa->uiaa_vendor == USB_VENDOR_FTDI + && uiaa->uiaa_product == USB_PRODUCT_FTDI_SERIAL_8U100AX) { sc->sc_type = UFTDI_TYPE_SIO; sc->sc_hdrlen = 1; } ddesc = usbd_get_device_descriptor(dev); sc->sc_chiptype = UGETW(ddesc->bcdDevice); - switch (sc->sc_chiptype) { - case 0x500: /* 2232D */ - case 0x700: /* 2232H */ - sc->sc_numports = 2; - break; - case 0x800: /* 4232H */ - sc->sc_numports = 4; - break; - case 0x200: /* 232/245AM */ - case 0x400: /* 232/245BL */ - case 0x600: /* 232/245R */ - default: - break; - } - - for (idx = UFTDI_IFACE_INDEX; idx < sc->sc_numports; idx++) { - err = usbd_device2interface_handle(dev, idx, &iface); - if (err) { - aprint_error( - "\n%s: failed to get interface idx=%d, err=%s\n", - devname, idx, usbd_errstr(err)); - goto bad; - } - id = usbd_get_interface_descriptor(iface); + id = usbd_get_interface_descriptor(iface); - sc->sc_iface[idx] = iface; + sc->sc_iface = iface; - ucaa.ucaa_bulkin = ucaa.ucaa_bulkout = -1; - ucaa.ucaa_ibufsize = ucaa.ucaa_obufsize = 0; - for (i = 0; i < id->bNumEndpoints; i++) { - int addr, dir, attr; - ed = usbd_interface2endpoint_descriptor(iface, i); - if (ed == NULL) { - aprint_error_dev(self, - "could not read endpoint descriptor: %s\n", - usbd_errstr(err)); - goto bad; - } - - addr = ed->bEndpointAddress; - dir = UE_GET_DIR(ed->bEndpointAddress); - attr = ed->bmAttributes & UE_XFERTYPE; - if (dir == UE_DIR_IN && attr == UE_BULK) { - ucaa.ucaa_bulkin = addr; - ucaa.ucaa_ibufsize = UGETW(ed->wMaxPacketSize); - if (ucaa.ucaa_ibufsize >= UFTDI_MAX_IBUFSIZE) - ucaa.ucaa_ibufsize = UFTDI_MAX_IBUFSIZE; - } else if (dir == UE_DIR_OUT && attr == UE_BULK) { - ucaa.ucaa_bulkout = addr; - ucaa.ucaa_obufsize = UGETW(ed->wMaxPacketSize) - - sc->sc_hdrlen; - if (ucaa.ucaa_obufsize >= UFTDI_MAX_OBUFSIZE) - ucaa.ucaa_obufsize = UFTDI_MAX_OBUFSIZE; - /* Limit length if we have a 6-bit header. */ - if ((sc->sc_hdrlen > 0) && - (ucaa.ucaa_obufsize > UFTDIOBUFSIZE)) - ucaa.ucaa_obufsize = UFTDIOBUFSIZE; - } else { - aprint_error_dev(self, - "unexpected endpoint\n"); - goto bad; - } - } - if (ucaa.ucaa_bulkin == -1) { + ucaa.ucaa_bulkin = ucaa.ucaa_bulkout = -1; + ucaa.ucaa_ibufsize = ucaa.ucaa_obufsize = 0; + for (i = 0; i < id->bNumEndpoints; i++) { + int addr, dir, attr; + ed = usbd_interface2endpoint_descriptor(iface, i); + if (ed == NULL) { aprint_error_dev(self, - "Could not find data bulk in\n"); + "could not read endpoint descriptor\n"); goto bad; } - if (ucaa.ucaa_bulkout == -1) { - aprint_error_dev(self, - "Could not find data bulk out\n"); + + addr = ed->bEndpointAddress; + dir = UE_GET_DIR(ed->bEndpointAddress); + attr = ed->bmAttributes & UE_XFERTYPE; + if (dir == UE_DIR_IN && attr == UE_BULK) { + ucaa.ucaa_bulkin = addr; + ucaa.ucaa_ibufsize = UGETW(ed->wMaxPacketSize); + if (ucaa.ucaa_ibufsize >= UFTDI_MAX_IBUFSIZE) + ucaa.ucaa_ibufsize = UFTDI_MAX_IBUFSIZE; + } else if (dir == UE_DIR_OUT && attr == UE_BULK) { + ucaa.ucaa_bulkout = addr; + ucaa.ucaa_obufsize = UGETW(ed->wMaxPacketSize) + - sc->sc_hdrlen; + if (ucaa.ucaa_obufsize >= UFTDI_MAX_OBUFSIZE) + ucaa.ucaa_obufsize = UFTDI_MAX_OBUFSIZE; + /* Limit length if we have a 6-bit header. */ + if ((sc->sc_hdrlen > 0) && + (ucaa.ucaa_obufsize > UFTDIOBUFSIZE)) + ucaa.ucaa_obufsize = UFTDIOBUFSIZE; + } else { + aprint_error_dev(self, "unexpected endpoint\n"); goto bad; } - - ucaa.ucaa_portno = FTDI_PIT_SIOA + idx; - /* ucaa_bulkin, ucaa_bulkout set above */ - if (ucaa.ucaa_ibufsize == 0) - ucaa.ucaa_ibufsize = UFTDIIBUFSIZE; - ucaa.ucaa_ibufsizepad = ucaa.ucaa_ibufsize; - if (ucaa.ucaa_obufsize == 0) - ucaa.ucaa_obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen; - ucaa.ucaa_opkthdrlen = sc->sc_hdrlen; - ucaa.ucaa_device = dev; - ucaa.ucaa_iface = iface; - ucaa.ucaa_methods = &uftdi_methods; - ucaa.ucaa_arg = sc; - ucaa.ucaa_info = NULL; - - DPRINTF(("uftdi: in=0x%x out=0x%x isize=0x%x osize=0x%x\n", - ucaa.ucaa_bulkin, ucaa.ucaa_bulkout, - ucaa.ucaa_ibufsize, ucaa.ucaa_obufsize)); - sc->sc_subdev[idx] = config_found_sm_loc(self, "ucombus", NULL, - &ucaa, ucomprint, ucomsubmatch); } + if (ucaa.ucaa_bulkin == -1) { + aprint_error_dev(self, "Could not find data bulk in\n"); + goto bad; + } + if (ucaa.ucaa_bulkout == -1) { + aprint_error_dev(self, "Could not find data bulk out\n"); + goto bad; + } + + ucaa.ucaa_portno = FTDI_PIT_SIOA + sc->sc_iface_no; + /* ucaa_bulkin, ucaa_bulkout set above */ + if (ucaa.ucaa_ibufsize == 0) + ucaa.ucaa_ibufsize = UFTDIIBUFSIZE; + ucaa.ucaa_ibufsizepad = ucaa.ucaa_ibufsize; + if (ucaa.ucaa_obufsize == 0) + ucaa.ucaa_obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen; + ucaa.ucaa_opkthdrlen = sc->sc_hdrlen; + ucaa.ucaa_device = dev; + ucaa.ucaa_iface = iface; + ucaa.ucaa_methods = &uftdi_methods; + ucaa.ucaa_arg = sc; + ucaa.ucaa_info = NULL; + + DPRINTF(("uftdi: in=0x%x out=0x%x isize=0x%x osize=0x%x\n", + ucaa.ucaa_bulkin, ucaa.ucaa_bulkout, + ucaa.ucaa_ibufsize, ucaa.ucaa_obufsize)); + sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, + &ucaa, ucomprint, ucomsubmatch); usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); @@ -371,29 +334,21 @@ uftdi_activate(device_t self, enum devac void uftdi_childdet(device_t self, device_t child) { - int i; struct uftdi_softc *sc = device_private(self); - for (i = 0; i < sc->sc_numports; i++) { - if (sc->sc_subdev[i] == child) - break; - } - KASSERT(i < sc->sc_numports); - sc->sc_subdev[i] = NULL; + KASSERT(child == sc->sc_subdev); + sc->sc_subdev = NULL; } int uftdi_detach(device_t self, int flags) { struct uftdi_softc *sc = device_private(self); - int i; DPRINTF(("uftdi_detach: sc=%p flags=%d\n", sc, flags)); sc->sc_dying = 1; - for (i=0; i < sc->sc_numports; i++) { - if (sc->sc_subdev[i] != NULL) - config_detach(sc->sc_subdev[i], flags); - } + if (sc->sc_subdev != NULL) + config_detach(sc->sc_subdev, flags); usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev); @@ -466,7 +421,7 @@ uftdi_read(void *vsc, int portno, u_char lsr, sc->sc_lsr)); sc->sc_msr = msr; sc->sc_lsr = lsr; - ucom_status_change(device_private(sc->sc_subdev[portno-1])); + ucom_status_change(device_private(sc->sc_subdev)); } /* Adjust buffer pointer to skip status prefix */ Index: src/sys/dev/usb/ugen.c diff -u src/sys/dev/usb/ugen.c:1.137 src/sys/dev/usb/ugen.c:1.138 --- src/sys/dev/usb/ugen.c:1.137 Sun Jan 21 13:57:12 2018 +++ src/sys/dev/usb/ugen.c Tue Feb 20 15:48:37 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ugen.c,v 1.137 2018/01/21 13:57:12 skrll Exp $ */ +/* $NetBSD: ugen.c,v 1.138 2018/02/20 15:48:37 ws Exp $ */ /* * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.137 2018/01/21 13:57:12 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.138 2018/02/20 15:48:37 ws Exp $"); #ifdef _KERNEL_OPT #include "opt_compat_netbsd.h" @@ -170,7 +170,7 @@ Static int ugen_do_read(struct ugen_soft Static int ugen_do_write(struct ugen_softc *, int, struct uio *, int); Static int ugen_do_ioctl(struct ugen_softc *, int, u_long, void *, int, struct lwp *); -Static int ugen_set_config(struct ugen_softc *, int); +Static int ugen_set_config(struct ugen_softc *, int, int); Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *, int, int *); Static usbd_status ugen_set_interface(struct ugen_softc *, int, int); @@ -181,13 +181,17 @@ Static void ugen_clear_endpoints(struct #define UGENENDPOINT(n) (minor(n) & 0xf) #define UGENDEV(u, e) (makedev(0, ((u) << 4) | (e))) +int ugenif_match(device_t, cfdata_t, void *); +void ugenif_attach(device_t, device_t, void *); int ugen_match(device_t, cfdata_t, void *); void ugen_attach(device_t, device_t, void *); int ugen_detach(device_t, int); int ugen_activate(device_t, enum devact); extern struct cfdriver ugen_cd; -CFATTACH_DECL_NEW(ugen, sizeof(struct ugen_softc), ugen_match, ugen_attach, - ugen_detach, ugen_activate); +CFATTACH_DECL_NEW(ugen, sizeof(struct ugen_softc), ugen_match, + ugen_attach, ugen_detach, ugen_activate); +CFATTACH_DECL_NEW(ugenif, sizeof(struct ugen_softc), ugenif_match, + ugenif_attach, ugen_detach, ugen_activate); /* toggle to control attach priority. -1 means "let autoconf decide" */ int ugen_override = -1; @@ -211,11 +215,38 @@ ugen_match(device_t parent, cfdata_t mat return UMATCH_NONE; } +int +ugenif_match(device_t parent, cfdata_t match, void *aux) +{ + if (match->cf_flags & 1) + return UMATCH_HIGHEST; + else + return UMATCH_NONE; +} + void ugen_attach(device_t parent, device_t self, void *aux) { - struct ugen_softc *sc = device_private(self); struct usb_attach_arg *uaa = aux; + struct usbif_attach_arg uiaa; + + memset(&uiaa, 0, sizeof uiaa); + uiaa.uiaa_port = uaa->uaa_port; + uiaa.uiaa_vendor = uaa->uaa_vendor; + uiaa.uiaa_product = uaa->uaa_product; + uiaa.uiaa_release = uaa->uaa_release; + uiaa.uiaa_device = uaa->uaa_device; + uiaa.uiaa_configno = -1; + uiaa.uiaa_ifaceno = -1; + + ugenif_attach(parent, self, &uiaa); +} + +void +ugenif_attach(device_t parent, device_t self, void *aux) +{ + struct ugen_softc *sc = device_private(self); + struct usbif_attach_arg *uiaa = aux; struct usbd_device *udev; char *devinfop; usbd_status err; @@ -227,12 +258,12 @@ ugen_attach(device_t parent, device_t se mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); cv_init(&sc->sc_detach_cv, "ugendet"); - devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); + devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); aprint_normal_dev(self, "%s\n", devinfop); usbd_devinfo_free(devinfop); sc->sc_dev = self; - sc->sc_udev = udev = uaa->uaa_device; + sc->sc_udev = udev = uiaa->uiaa_device; for (i = 0; i < USB_MAX_ENDPOINTS; i++) { for (dir = OUT; dir <= IN; dir++) { @@ -244,18 +275,25 @@ ugen_attach(device_t parent, device_t se } } - /* First set configuration index 0, the default one for ugen. */ - err = usbd_set_config_index(udev, 0, 0); - if (err) { - aprint_error_dev(self, - "setting configuration index 0 failed\n"); - sc->sc_dying = 1; - return; + if (uiaa->uiaa_ifaceno < 0) { + /* + * If we attach the whole device, + * set configuration index 0, the default one. + */ + err = usbd_set_config_index(udev, 0, 0); + if (err) { + aprint_error_dev(self, + "setting configuration index 0 failed\n"); + sc->sc_dying = 1; + return; + } } + + /* Get current configuration */ conf = usbd_get_config_descriptor(udev)->bConfigurationValue; /* Set up all the local state for this configuration. */ - err = ugen_set_config(sc, conf); + err = ugen_set_config(sc, conf, uiaa->uiaa_ifaceno < 0); if (err) { aprint_error_dev(self, "setting configuration %d failed\n", conf); @@ -268,7 +306,6 @@ ugen_attach(device_t parent, device_t se if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); - return; } Static void @@ -285,7 +322,7 @@ ugen_clear_endpoints(struct ugen_softc * } Static int -ugen_set_config(struct ugen_softc *sc, int configno) +ugen_set_config(struct ugen_softc *sc, int configno, int chkopen) { struct usbd_device *dev = sc->sc_udev; usb_config_descriptor_t *cdesc; @@ -300,17 +337,19 @@ ugen_set_config(struct ugen_softc *sc, i DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n", device_xname(sc->sc_dev), configno, sc)); - /* - * We start at 1, not 0, because we don't care whether the - * control endpoint is open or not. It is always present. - */ - for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) - if (sc->sc_is_open[endptno]) { - DPRINTFN(1, - ("ugen_set_config: %s - endpoint %d is open\n", - device_xname(sc->sc_dev), endptno)); - return USBD_IN_USE; - } + if (chkopen) { + /* + * We start at 1, not 0, because we don't care whether the + * control endpoint is open or not. It is always present. + */ + for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) + if (sc->sc_is_open[endptno]) { + DPRINTFN(1, + ("ugen_set_config: %s - endpoint %d is open\n", + device_xname(sc->sc_dev), endptno)); + return USBD_IN_USE; + } + } /* Avoid setting the current value. */ cdesc = usbd_get_config_descriptor(dev); @@ -320,12 +359,12 @@ ugen_set_config(struct ugen_softc *sc, i return err; } + ugen_clear_endpoints(sc); + err = usbd_interface_count(dev, &niface); if (err) return err; - ugen_clear_endpoints(sc); - for (ifaceno = 0; ifaceno < niface; ifaceno++) { DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno)); err = usbd_device2interface_handle(dev, ifaceno, &iface); @@ -1601,7 +1640,7 @@ ugen_do_ioctl(struct ugen_softc *sc, int case USB_SET_CONFIG: if (!(flag & FWRITE)) return EPERM; - err = ugen_set_config(sc, *(int *)addr); + err = ugen_set_config(sc, *(int *)addr, 1); switch (err) { case USBD_NORMAL_COMPLETION: break;