OK with me, but you'll also need a man page, and Xr that from usb.4

Mark Kettenis <mark.kette...@xs4all.nl> wrote:

> In principle this hardware implements the standard USB Communication
> Device Class interface which is supported by umodem(4).  However, the
> hardware enables hardware flow control bu default in CDC mode.  This
> means that if the flow control lines are not (properly) connected, the
> device isn't fully functional.  This is the case on the HiKey 970
> board, where serial output works fine, but no input is accepted.
> 
> Hardware flow control can be disabled by writing to a device-specific
> register.  It seems easiest to just implement a dedicated driver for
> this device rather than quirking umodem(4).  
> 
> ok?
> 
> 
> Index: dev/usb/files.usb
> ===================================================================
> RCS file: /cvs/src/sys/dev/usb/files.usb,v
> retrieving revision 1.136
> diff -u -p -r1.136 files.usb
> --- dev/usb/files.usb 25 Aug 2018 20:31:31 -0000      1.136
> +++ dev/usb/files.usb 24 Mar 2019 17:26:33 -0000
> @@ -342,6 +342,11 @@ device   uscom: ucombus
>  attach       uscom at uhub
>  file dev/usb/uscom.c                 uscom
>  
> +# Exar XR21V1410
> +device       uxrcom: ucombus
> +attach       uxrcom at uhub
> +file dev/usb/uxrcom.c                uxrcom
> +
>  # iPAQ PDAs
>  # Generic ipaq support
>  device       uipaq: ucombus
> Index: dev/usb/usbdevs
> ===================================================================
> RCS file: /cvs/src/sys/dev/usb/usbdevs,v
> retrieving revision 1.696
> diff -u -p -r1.696 usbdevs
> --- dev/usb/usbdevs   22 Mar 2019 12:02:38 -0000      1.696
> +++ dev/usb/usbdevs   24 Mar 2019 17:26:33 -0000
> @@ -143,6 +143,7 @@ vendor HOLTEK             0x04d9  Holtek
>  vendor PANASONIC     0x04da  Panasonic (Matsushita)
>  vendor SHARP         0x04dd  Sharp
>  vendor IIYAMA                0x04e1  Iiyama
> +vendor EXAR          0x04e2  Exar
>  vendor SHUTTLE               0x04e6  Shuttle Technology
>  vendor SAMSUNG2              0x04e8  Samsung Electronics
>  vendor ANNABOOKS     0x04ed  Annabooks
> @@ -1759,6 +1760,9 @@ product EVOLUTION RCM4_2        0x0303  RCM4 int
>  
>  /* Extended Systems products */
>  product EXTENDED XTNDACCESS  0x0100  XTNDAccess IrDA
> +
> +/* Exar products */
> +product EXAR XR21V1410               0x1410  XR21V1410
>  
>  /* Falcom Wireless Communications GmbH products */
>  product FALCOM TWIST         0x0001  Twist
> Index: dev/usb/uxrcom.c
> ===================================================================
> RCS file: dev/usb/uxrcom.c
> diff -N dev/usb/uxrcom.c
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ dev/usb/uxrcom.c  24 Mar 2019 17:26:33 -0000
> @@ -0,0 +1,436 @@
> +/*   $OpenBSD$       */
> +
> +/*
> + * Copyright (c) 2006 Jonathan Gray <j...@openbsd.org>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/kernel.h>
> +#include <sys/tty.h>
> +#include <sys/device.h>
> +
> +#include <dev/usb/usb.h>
> +#include <dev/usb/usbcdc.h>
> +#include <dev/usb/usbdi.h>
> +#include <dev/usb/usbdi_util.h>
> +#include <dev/usb/usbdevs.h>
> +
> +#include <dev/usb/ucomvar.h>
> +
> +#ifdef UXRCOM_DEBUG
> +#define DPRINTFN(n, x)  do { if (uxrcomdebug > (n)) printf x; } while (0)
> +int  uxrcomdebug = 0;
> +#else
> +#define DPRINTFN(n, x)
> +#endif
> +#define DPRINTF(x) DPRINTFN(0, x)
> +
> +#define UXRCOMBUFSZ          64
> +#define UXRCOM_INTR_IFACE_NO 0
> +#define UXRCOM_DATA_IFACE_NO 1
> +
> +#define XR_SET_REG           0
> +#define XR_GET_REGN          1
> +
> +#define XR_FLOW_CONTROL              0x000c
> +#define  XR_FLOW_CONTROL_ON  1
> +#define  XR_FLOW_CONTROL_OFF 0
> +#define XR_TX_BREAK          0x0014
> +#define  XR_TX_BREAK_ON              1
> +#define  XR_TX_BREAK_OFF     0
> +#define XR_GPIO_SET          0x001d
> +#define XR_GPIO_CLEAR                0x001e
> +#define  XR_GPIO3            (1 << 3)
> +#define  XR_GPIO5            (1 << 5)
> +
> +struct uxrcom_softc {
> +     struct device           sc_dev;
> +     struct usbd_device      *sc_udev;
> +     struct usbd_interface   *sc_intr_iface;
> +     struct usbd_interface   *sc_data_iface;
> +     struct device           *sc_subdev;
> +
> +     struct usb_cdc_line_state sc_line_state;
> +
> +     int                     sc_intr_number;
> +     struct usbd_pipe        *sc_intr_pipe;
> +     struct usb_cdc_notification sc_intr_buf;
> +     u_char                  sc_msr;
> +     u_char                  sc_lsr;
> +};
> +
> +void uxrcom_get_status(void *, int, u_char *, u_char *);
> +void uxrcom_set(void *, int, int, int);
> +int  uxrcom_param(void *, int, struct termios *);
> +int  uxrcom_open(void *, int);
> +void uxrcom_close(void *, int);
> +void uxrcom_break(void *, int, int);
> +void uxrcom_intr(struct usbd_xfer *, void *, usbd_status);
> +
> +struct ucom_methods uxrcom_methods = {
> +     uxrcom_get_status,
> +     uxrcom_set,
> +     uxrcom_param,
> +     NULL,
> +     uxrcom_open,
> +     uxrcom_close,
> +     NULL,
> +     NULL,
> +};
> +
> +static const struct usb_devno uxrcom_devs[] = {
> +     { USB_VENDOR_EXAR,              USB_PRODUCT_EXAR_XR21V1410 },
> +};
> +
> +int uxrcom_match(struct device *, void *, void *);
> +void uxrcom_attach(struct device *, struct device *, void *);
> +int uxrcom_detach(struct device *, int);
> +
> +struct cfdriver uxrcom_cd = {
> +     NULL, "uxrcom", DV_DULL
> +};
> +
> +const struct cfattach uxrcom_ca = {
> +     sizeof(struct uxrcom_softc), uxrcom_match, uxrcom_attach, uxrcom_detach
> +};
> +
> +int
> +uxrcom_match(struct device *parent, void *match, void *aux)
> +{
> +     struct usb_attach_arg *uaa = aux;
> +
> +     if (uaa->iface == NULL)
> +             return UMATCH_NONE;
> +     if (uaa->ifaceno != UXRCOM_INTR_IFACE_NO)
> +             return UMATCH_NONE;
> +
> +     return (usb_lookup(uxrcom_devs, uaa->vendor, uaa->product) != NULL) ?
> +         UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
> +}
> +
> +void
> +uxrcom_attach(struct device *parent, struct device *self, void *aux)
> +{
> +     struct uxrcom_softc *sc = (struct uxrcom_softc *)self;
> +     struct usb_attach_arg *uaa = aux;
> +     struct ucom_attach_args uca;
> +     usb_interface_descriptor_t *id;
> +     usb_endpoint_descriptor_t *ed;
> +     usbd_status error;
> +     int i;
> +
> +     memset(&uca, 0, sizeof(uca));
> +     sc->sc_udev = uaa->device;
> +     sc->sc_intr_iface = uaa->iface;
> +     sc->sc_intr_number = -1;
> +
> +     id = usbd_get_interface_descriptor(sc->sc_intr_iface);
> +     for (i = 0; i < id->bNumEndpoints; i++) {
> +             ed = usbd_interface2endpoint_descriptor(sc->sc_intr_iface, i);
> +             if (ed == NULL) {
> +                     printf("%s: no endpoint descriptor found for %d\n",
> +                         sc->sc_dev.dv_xname, i);
> +                     usbd_deactivate(sc->sc_udev);
> +                     return;
> +             }
> +
> +             if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
> +                 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT)
> +                     sc->sc_intr_number = ed->bEndpointAddress;
> +     }
> +
> +     error = usbd_device2interface_handle(sc->sc_udev, UXRCOM_DATA_IFACE_NO,
> +         &sc->sc_data_iface);
> +     if (error != 0) {
> +             printf("%s: could not get data interface handle\n",
> +                 sc->sc_dev.dv_xname);
> +             usbd_deactivate(sc->sc_udev);
> +             return;
> +     }
> +
> +     id = usbd_get_interface_descriptor(sc->sc_data_iface);
> +     uca.bulkin = uca.bulkout = -1;
> +     for (i = 0; i < id->bNumEndpoints; i++) {
> +             ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i);
> +             if (ed == NULL) {
> +                     printf("%s: no endpoint descriptor found for %d\n",
> +                         sc->sc_dev.dv_xname, i);
> +                     usbd_deactivate(sc->sc_udev);
> +                     return;
> +             }
> +
> +             if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
> +                 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
> +                     uca.bulkin = ed->bEndpointAddress;
> +             else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
> +                 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
> +                     uca.bulkout = ed->bEndpointAddress;
> +     }
> +
> +     if (uca.bulkin == -1 || uca.bulkout == -1) {
> +             printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
> +             usbd_deactivate(sc->sc_udev);
> +             return;
> +     }
> +
> +     usbd_claim_iface(sc->sc_udev, UXRCOM_DATA_IFACE_NO);
> +
> +     uca.ibufsize = UXRCOMBUFSZ;
> +     uca.obufsize = UXRCOMBUFSZ;
> +     uca.ibufsizepad = UXRCOMBUFSZ;
> +     uca.opkthdrlen = 0;
> +     uca.device = sc->sc_udev;
> +     uca.iface = sc->sc_data_iface;
> +     uca.methods = &uxrcom_methods;
> +     uca.arg = sc;
> +     uca.info = NULL;
> +
> +     sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
> +}
> +
> +int
> +uxrcom_detach(struct device *self, int flags)
> +{
> +     struct uxrcom_softc *sc = (struct uxrcom_softc *)self;
> +     int rv = 0;
> +
> +     if (sc->sc_intr_pipe != NULL) {
> +             usbd_abort_pipe(sc->sc_intr_pipe);
> +             usbd_close_pipe(sc->sc_intr_pipe);
> +             sc->sc_intr_pipe = NULL;
> +     }
> +
> +     if (sc->sc_subdev != NULL)
> +             rv = config_detach(sc->sc_subdev, flags);
> +
> +     return rv;
> +}
> +
> +int
> +uxrcom_open(void *vsc, int portno)
> +{
> +     struct uxrcom_softc *sc = vsc;
> +     int err;
> +
> +     if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
> +             err = usbd_open_pipe_intr(sc->sc_intr_iface,
> +                 sc->sc_intr_number, USBD_SHORT_XFER_OK, &sc->sc_intr_pipe,
> +                 sc, &sc->sc_intr_buf, sizeof(sc->sc_intr_buf),
> +                 uxrcom_intr, USBD_DEFAULT_INTERVAL);
> +             if (err)
> +                     return EIO;
> +     }
> +
> +     return 0;
> +}
> +
> +void
> +uxrcom_close(void *vsc, int portno)
> +{
> +     struct uxrcom_softc *sc = vsc;
> +     int err;
> +
> +     if (usbd_is_dying(sc->sc_udev))
> +             return;
> +
> +     if (sc->sc_intr_pipe != NULL) {
> +             usbd_abort_pipe(sc->sc_intr_pipe);
> +             err = usbd_close_pipe(sc->sc_intr_pipe);
> +             if (err)
> +                     printf("%s: close intr pipe failed: %s\n",
> +                         sc->sc_dev.dv_xname, usbd_errstr(err));
> +             sc->sc_intr_pipe = NULL;
> +     }
> +}
> +
> +void
> +uxrcom_set(void *vsc, int portno, int reg, int onoff)
> +{
> +     struct uxrcom_softc *sc = vsc;
> +     usb_device_request_t req;
> +     uint16_t index;
> +     uint8_t value;
> +
> +     index = onoff ? XR_GPIO_SET : XR_GPIO_CLEAR;
> +
> +     switch (reg) {
> +     case UCOM_SET_DTR:
> +             value = XR_GPIO3;
> +             break;
> +     case UCOM_SET_RTS:
> +             value = XR_GPIO5;
> +             break;
> +     case UCOM_SET_BREAK:
> +             uxrcom_break(sc, portno, onoff);
> +             return;
> +     default:
> +             return;
> +     }
> +     req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
> +     req.bRequest = XR_SET_REG;
> +     USETW(req.wValue, value);
> +     USETW(req.wIndex, index);
> +     USETW(req.wLength, 0);
> +     usbd_do_request(sc->sc_udev, &req, NULL);
> +}
> +
> +usbd_status
> +uxrcom_set_line_coding(struct uxrcom_softc *sc,
> +    struct usb_cdc_line_state *state)
> +{
> +     usb_device_request_t req;
> +     usbd_status err;
> +
> +     if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0)
> +             return USBD_NORMAL_COMPLETION;
> +
> +     req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
> +     req.bRequest = UCDC_SET_LINE_CODING;
> +     USETW(req.wValue, 0);
> +     USETW(req.wIndex, UXRCOM_INTR_IFACE_NO);
> +     USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
> +
> +     err = usbd_do_request(sc->sc_udev, &req, state);
> +     if (err)
> +             return err;
> +
> +     sc->sc_line_state = *state;
> +
> +     return USBD_NORMAL_COMPLETION;
> +}
> +
> +int
> +uxrcom_param(void *vsc, int portno, struct termios *t)
> +{
> +     struct uxrcom_softc *sc = (struct uxrcom_softc *)vsc;
> +     usb_device_request_t req;
> +     usbd_status err;
> +     struct usb_cdc_line_state ls;
> +     uint8_t flowctrl;
> +
> +     if (t->c_ospeed <= 0 || t->c_ospeed > 48000000)
> +             return (EINVAL);
> +
> +     USETDW(ls.dwDTERate, t->c_ospeed);
> +     if (ISSET(t->c_cflag, CSTOPB))
> +             ls.bCharFormat = UCDC_STOP_BIT_2;
> +     else
> +             ls.bCharFormat = UCDC_STOP_BIT_1;
> +     if (ISSET(t->c_cflag, PARENB)) {
> +             if (ISSET(t->c_cflag, PARODD))
> +                     ls.bParityType = UCDC_PARITY_ODD;
> +             else
> +                     ls.bParityType = UCDC_PARITY_EVEN;
> +     } else
> +             ls.bParityType = UCDC_PARITY_NONE;
> +     switch (ISSET(t->c_cflag, CSIZE)) {
> +     case CS5:
> +             ls.bDataBits = 5;
> +             break;
> +     case CS6:
> +             ls.bDataBits = 6;
> +             break;
> +     case CS7:
> +             ls.bDataBits = 7;
> +             break;
> +     case CS8:
> +             ls.bDataBits = 8;
> +             break;
> +     }
> +
> +     err = uxrcom_set_line_coding(sc, &ls);
> +     if (err)
> +             return (EIO);
> +
> +     if (ISSET(t->c_cflag, CRTSCTS)) {
> +             /*  rts/cts flow ctl */
> +             flowctrl = XR_FLOW_CONTROL_ON;
> +     } else {
> +             /* disable flow ctl */
> +             flowctrl = XR_FLOW_CONTROL_OFF;
> +     }
> +     req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
> +     req.bRequest = XR_SET_REG;
> +     USETW(req.wValue, flowctrl);
> +     USETW(req.wIndex, XR_FLOW_CONTROL);
> +     USETW(req.wLength, 0);
> +     usbd_do_request(sc->sc_udev, &req, NULL);
> +
> +     return (0);
> +}
> +
> +void
> +uxrcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
> +{
> +     struct uxrcom_softc *sc = priv;
> +     uint8_t mstatus;
> +
> +     if (usbd_is_dying(sc->sc_udev))
> +             return;
> +
> +     if (status != USBD_NORMAL_COMPLETION) {
> +             if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
> +                     return;
> +             usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
> +             return;
> +     }
> +
> +     if (sc->sc_intr_buf.bmRequestType != UCDC_NOTIFICATION)
> +             return;
> +
> +     switch (sc->sc_intr_buf.bNotification) {
> +     case UCDC_N_SERIAL_STATE:
> +             sc->sc_lsr = sc->sc_msr = 0;
> +             mstatus = sc->sc_intr_buf.data[0];
> +
> +             if (ISSET(mstatus, UCDC_N_SERIAL_RI))
> +                     sc->sc_msr |= UMSR_RI;
> +             if (ISSET(mstatus, UCDC_N_SERIAL_DSR))
> +                     sc->sc_msr |= UMSR_DSR;
> +             if (ISSET(mstatus, UCDC_N_SERIAL_DCD))
> +                     sc->sc_msr |= UMSR_DCD;
> +             ucom_status_change((struct ucom_softc *)sc->sc_subdev);
> +             break;
> +     default:
> +             break;
> +     }
> +}
> +
> +void
> +uxrcom_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
> +{
> +     struct uxrcom_softc *sc = vsc;
> +     
> +     if (msr != NULL)
> +             *msr = sc->sc_msr;
> +     if (lsr != NULL)
> +             *lsr = sc->sc_lsr;
> +}
> +
> +void
> +uxrcom_break(void *vsc, int portno, int onoff)
> +{
> +     struct uxrcom_softc *sc = vsc;
> +     usb_device_request_t req;
> +     uint8_t brk = onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF;
> +
> +     req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
> +     req.bRequest = XR_SET_REG;
> +     USETW(req.wValue, brk);
> +     USETW(req.wIndex, XR_TX_BREAK);
> +     USETW(req.wLength, 0);
> +     usbd_do_request(sc->sc_udev, &req, NULL);
> +}
> 

Reply via email to