From 798d5edc803a8bb0b6d2f8d37eaf2d8e8644d949 Mon Sep 17 00:00:00 2001 From: phk Date: Fri, 12 Jul 2019 09:02:12 +0000 Subject: [PATCH] Support multiple serial ports per device. Enable this for the NovAtel OEMv2 GPS receiver. Not fixed: The receiver shows up as "" in the device tree, because that is literally what the descriptor-string is. Reviewed by: hselasky@ --- sys/dev/usb/serial/ugensa.c | 109 +++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/sys/dev/usb/serial/ugensa.c b/sys/dev/usb/serial/ugensa.c index 19bcfca05b7..be9178f127e 100644 --- a/sys/dev/usb/serial/ugensa.c +++ b/sys/dev/usb/serial/ugensa.c @@ -70,6 +70,7 @@ #define UGENSA_CONFIG_INDEX 0 #define UGENSA_IFACE_INDEX 0 #define UGENSA_IFACE_MAX 8 /* exclusivly */ +#define UGENSA_PORT_MAX 8 /* exclusivly */ enum { UGENSA_BULK_DT_WR, @@ -84,11 +85,11 @@ struct ugensa_sub_softc { struct ugensa_softc { struct ucom_super_softc sc_super_ucom; - struct ucom_softc sc_ucom[UGENSA_IFACE_MAX]; - struct ugensa_sub_softc sc_sub[UGENSA_IFACE_MAX]; + struct ucom_softc sc_ucom[UGENSA_PORT_MAX]; + struct ugensa_sub_softc sc_sub[UGENSA_PORT_MAX]; struct mtx sc_mtx; - uint8_t sc_niface; + uint8_t sc_nports; }; /* prototypes */ @@ -154,12 +155,13 @@ static driver_t ugensa_driver = { .size = sizeof(struct ugensa_softc), }; +/* Driver-info is max number of serial ports per interface */ static const STRUCT_USB_HOST_ID ugensa_devs[] = { - {USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 0)}, - {USB_VPI(USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CDMA_MODEM1, 0)}, - {USB_VPI(USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_CDMA_MSM_K, 0)}, - {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_49GPLUS, 0)}, - {USB_VPI(USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_FLEXPACKGPS, 0)}, + {USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 1)}, + {USB_VPI(USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CDMA_MODEM1, 1)}, + {USB_VPI(USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_CDMA_MSM_K, 1)}, + {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_49GPLUS, 1)}, + {USB_VPI(USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_FLEXPACKGPS, 3)}, }; DRIVER_MODULE(ugensa, uhub, ugensa_driver, ugensa_devclass, NULL, 0); @@ -192,65 +194,68 @@ ugensa_attach(device_t dev) struct ugensa_softc *sc = device_get_softc(dev); struct ugensa_sub_softc *ssc; struct usb_interface *iface; + struct usb_config xfer_config[UGENSA_N_TRANSFER]; int32_t error; uint8_t iface_index; - int x, cnt; + int x, maxports; + maxports = USB_GET_DRIVER_INFO(uaa); device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "ugensa", NULL, MTX_DEF); ucom_ref(&sc->sc_super_ucom); - /* Figure out how many interfaces this device has got */ - for (cnt = 0; cnt < UGENSA_IFACE_MAX; cnt++) { - if ((usbd_get_endpoint(uaa->device, cnt, ugensa_xfer_config + 0) == NULL) || - (usbd_get_endpoint(uaa->device, cnt, ugensa_xfer_config + 1) == NULL)) { - /* we have reached the end */ - break; - } - } + for (iface_index = UGENSA_IFACE_INDEX; iface_index < UGENSA_IFACE_MAX; iface_index++) { - if (cnt == 0) { - device_printf(dev, "No interfaces\n"); - goto detach; - } - for (x = 0; x < cnt; x++) { - iface = usbd_get_iface(uaa->device, x); - if (iface->idesc->bInterfaceClass != UICLASS_VENDOR) + iface = usbd_get_iface(uaa->device, iface_index); + if (iface == NULL || iface->idesc->bInterfaceClass != UICLASS_VENDOR) /* Not a serial port, most likely a SD reader */ continue; - ssc = sc->sc_sub + sc->sc_niface; - ssc->sc_ucom_ptr = sc->sc_ucom + sc->sc_niface; - - iface_index = (UGENSA_IFACE_INDEX + x); - error = usbd_transfer_setup(uaa->device, - &iface_index, ssc->sc_xfer, ugensa_xfer_config, - UGENSA_N_TRANSFER, ssc, &sc->sc_mtx); - - if (error) { - device_printf(dev, "allocating USB " - "transfers failed\n"); - goto detach; + /* Loop over all endpoints pairwise */ + for (x = 0; x < maxports && sc->sc_nports < UGENSA_PORT_MAX; x++) { + + ssc = sc->sc_sub + sc->sc_nports; + ssc->sc_ucom_ptr = sc->sc_ucom + sc->sc_nports; + + memcpy(xfer_config, ugensa_xfer_config, sizeof ugensa_xfer_config); + xfer_config[UGENSA_BULK_DT_RD].ep_index = x; + xfer_config[UGENSA_BULK_DT_WR].ep_index = x; + + error = usbd_transfer_setup(uaa->device, + &iface_index, ssc->sc_xfer, xfer_config, + UGENSA_N_TRANSFER, ssc, &sc->sc_mtx); + + if (error) { + if (x == 0) { + device_printf(dev, "allocating USB " + "transfers failed (%d)\n", error); + goto detach; + } + break; + } + + /* clear stall at first run */ + mtx_lock(&sc->sc_mtx); + usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_WR]); + usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_RD]); + mtx_unlock(&sc->sc_mtx); + + /* initialize port number */ + ssc->sc_ucom_ptr->sc_portno = sc->sc_nports; + if (iface_index != uaa->info.bIfaceIndex) { + usbd_set_parent_iface(uaa->device, iface_index, + uaa->info.bIfaceIndex); + } + sc->sc_nports++; } - /* clear stall at first run */ - mtx_lock(&sc->sc_mtx); - usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_WR]); - usbd_xfer_set_stall(ssc->sc_xfer[UGENSA_BULK_DT_RD]); - mtx_unlock(&sc->sc_mtx); - - /* initialize port number */ - ssc->sc_ucom_ptr->sc_portno = sc->sc_niface; - sc->sc_niface++; - if (x != uaa->info.bIfaceIndex) - usbd_set_parent_iface(uaa->device, x, - uaa->info.bIfaceIndex); } - device_printf(dev, "Found %d interfaces.\n", sc->sc_niface); + device_printf(dev, "Found %d serial ports.\n", sc->sc_nports); - error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_niface, sc, + error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_nports, sc, &ugensa_callback, &sc->sc_mtx); + if (error) { - DPRINTF("attach failed\n"); + DPRINTF("ucom attach failed\n"); goto detach; } ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); @@ -270,7 +275,7 @@ ugensa_detach(device_t dev) ucom_detach(&sc->sc_super_ucom, sc->sc_ucom); - for (x = 0; x < sc->sc_niface; x++) { + for (x = 0; x < sc->sc_nports; x++) { usbd_transfer_unsetup(sc->sc_sub[x].sc_xfer, UGENSA_N_TRANSFER); } -- 2.45.0