On Mon, Jun 03, 2019 at 11:44:37PM -0400, Cody Cutler wrote:
> Hi jcs and tech, the following is a patch which implements jcs's feedback and
> adds a man page.
>
> Note that one must execute `make -C sys/dev/usb' after applying to build.
>
> Thanks!
>
> diff --git share/man/man4/Makefile share/man/man4/Makefile
> index 7d470b6ca47..999621c7889 100644
> --- share/man/man4/Makefile
> +++ share/man/man4/Makefile
> @@ -71,7 +71,7 @@ MAN= aac.4 abcrtc.4 ac97.4 acphy.4 acrtc.4 \
> tlphy.4 thmc.4 tpm.4 tqphy.4 trm.4 trunk.4 tsl.4 tty.4 tun.4 tap.4 \
> twe.4 \
> txp.4 txphy.4 uaudio.4 uark.4 uath.4 ubcmtp.4 uberry.4 ubsa.4 \
> - ubsec.4 ucom.4 uchcom.4 ucrcom.4 ucycom.4 uslhcom.4 \
> + ubsec.4 ucom.4 uchcom.4 ucrcom.4 ucycom.4 ukspan.4 uslhcom.4 \
> udav.4 udcf.4 udl.4 udp.4 udsbr.4 \
> uftdi.4 ugen.4 ugl.4 ugold.4 uguru.4 uhci.4 uhid.4 uhidev.4 uipaq.4 \
> uk.4 ukbd.4 \
> diff --git share/man/man4/ucom.4 share/man/man4/ucom.4
> index e14df75675b..bde53a2c5e1 100644
> --- share/man/man4/ucom.4
> +++ share/man/man4/ucom.4
> @@ -42,6 +42,7 @@
> .Cd "ucom* at ucycom?" # Cypress
> .Cd "ucom* at uftdi?" # FTDI
> .Cd "ucom* at uipaq?" # iPAQ
> +.Cd "ucom* at ukspan?" # Keyspan
> .Cd "ucom* at umcs?" # MosChip Semiconductor multiport
> .Cd "ucom* at umct?" # MCT
> .Cd "ucom* at umodem?" # Standardized umodem
> diff --git share/man/man4/ukspan.4 share/man/man4/ukspan.4
> new file mode 100644
> index 00000000000..2b98f1efcb5
> --- /dev/null
> +++ share/man/man4/ukspan.4
> @@ -0,0 +1,39 @@
> +.\" Copyright (c) 2019 Cody Cutler <[email protected]>
> +.\"
> +.\" 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.
> +.\"
> +.Dd $Mdocdate$
> +.Dt UKSPAN 4
> +.Os
> +.Sh NAME
> +.Nm ukspan
> +.Nd Keyspan USB serial adapter
> +.Sh SYNOPSIS
> +.Cd "ukspan* at uhub?"
> +.Cd "ucom* at ukspan?"
> +.Sh DESCRIPTION
> +The
> +.Nm
> +driver supports the TrippLite Keyspan USA-19HS serial adapter, which is made
> +accessible through
> +.Xr ucom 4 .
> +.Sh SEE ALSO
> +.Xr tty 4 ,
> +.Xr ucom 4 ,
> +.Xr uhub 4 ,
> +.Xr usb 4
> +.Sh AUTHORS
> +The
> +.Nm
> +driver was written by
> +.An Cody Cutler Aq Mt [email protected] .
> diff --git share/man/man4/usb.4 share/man/man4/usb.4
> index 520d513f5b1..81a4abd8c70 100644
> --- share/man/man4/usb.4
> +++ share/man/man4/usb.4
> @@ -188,6 +188,8 @@ FTDI USB serial adapter
> iPAQ USB units
> .It Xr ulpt 4
> USB printer support
> +.It Xr ukspan 4
> +Keyspan serial adapter
> .It Xr umcs 4
> MosChip Semiconductor based USB multiport serial adapter
> .It Xr umct 4
> diff --git sys/arch/amd64/conf/GENERIC sys/arch/amd64/conf/GENERIC
> index ad192f4ea1d..5b5d37c24e2 100644
> --- sys/arch/amd64/conf/GENERIC
> +++ sys/arch/amd64/conf/GENERIC
> @@ -224,6 +224,8 @@ uvscom* at uhub? # SUNTAC Slipper U
> VS-10U serial
> ucom* at uvscom?
> ubsa* at uhub? # Belkin serial adapter
> ucom* at ubsa?
> +ukspan* at uhub? # Keyspan USA19HS serial adapter
> +ucom* at ukspan?
> uftdi* at uhub? # FTDI FT8U100AX serial adapter
> ucom* at uftdi?
> uplcom* at uhub? # I/O DATA USB-RSAQ2 serial adapter
> diff --git sys/dev/usb/files.usb sys/dev/usb/files.usb
> index 1036cf36232..29bc1205540 100644
> --- sys/dev/usb/files.usb
> +++ sys/dev/usb/files.usb
> @@ -317,6 +317,11 @@ device ubsa: ucombus
> attach ubsa at uhub
> file dev/usb/ubsa.c ubsa
>
> +# Keyspan USA19HS serial
> +device ukspan: ucombus
> +attach ukspan at uhub
> +file dev/usb/ukspan.c ukspan
> +
> # Silicon Laboratories CP210x serial
> device uslcom: ucombus
> attach uslcom at uhub
> diff --git sys/dev/usb/ukspan.c sys/dev/usb/ukspan.c
> new file mode 100644
> index 00000000000..5f5e9583641
> --- /dev/null
> +++ sys/dev/usb/ukspan.c
> @@ -0,0 +1,594 @@
> +/*
> + * Copyright (c) 2019 Cody Cutler <[email protected]>
> + *
> + * 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.
> + */
> +
> +/*
> + * I don't know of any technical documentation for the Keyspan USA-19HS. I
> + * inspected the Linux driver (drivers/usb/serial/keyspan_usa90msg.h) to
> learn
> + * the device message format and the procedure for setting the baud rate.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/tty.h>
> +
> +#include <dev/usb/usb.h>
> +#include <dev/usb/usbdevs.h>
> +#include <dev/usb/usbdi.h>
> +#include <dev/usb/usbdi_util.h>
> +
> +#include <dev/usb/ucomvar.h>
> +
> +/*#define UKSPAN_DEBUG */
> +
> +#ifdef UKSPAN_DEBUG
> + #define DPRINTF(x...) do { printf(x); } while (0)
> +#else
> + #define DPRINTF(x...) do { ; } while (0)
> +#endif
> +
> +#define UKSPAN_PARITY_NONE 0x0
> +#define UKSPAN_PARITY_ODD 0x08
> +#define UKSPAN_PARITY_EVEN 0x18
> +
> +#define UKSPAN_DATA_5 0x0
> +#define UKSPAN_DATA_6 0x1
> +#define UKSPAN_DATA_7 0x2
> +#define UKSPAN_DATA_8 0x3
> +
> +#define UKSPAN_STOP_1 0x0
> +#define UKSPAN_STOP_2 0x4
> +
> +#define UKSPAN_MAGIC 0x2
> +
> +#define UKSPAN_CLOCK 14769231
> +
> +/*
> + * The following USB indexes and endpoint addresses may be specific to the
> + * Keyspan USA19HS device
> + */
> +#define UKSPAN_CONFIG_IDX 1
> +#define UKSPAN_IFACE_IDX 0
> +
> +#define UKSPAN_EA_BULKIN (UE_DIR_IN | 1)
> +#define UKSPAN_EA_BULKOUT (UE_DIR_OUT | 1)
> +#define UKSPAN_EA_CONFIGIN (UE_DIR_IN | 2)
> +#define UKSPAN_EA_CONFIGOUT (UE_DIR_OUT | 2)
> +
> +/* Sent to device on control out endpoint */
> +struct ukspan_cmsg {
> + uint8_t setclock;
> + uint8_t baudlo;
> + uint8_t baudhi;
> + uint8_t setlcr;
> + uint8_t lcr;
> + uint8_t setrxmode;
> + uint8_t rxmode;
> + uint8_t settxmode;
> + uint8_t txmode;
> + uint8_t settxflowcontrol;
> + uint8_t txflowcontrol;
> + uint8_t setrxflowcontrol;
> + uint8_t rxflowcontrol;
> + uint8_t sendxoff;
> + uint8_t sendxon;
> + uint8_t xonchar;
> + uint8_t xoffchar;
> + uint8_t sendchar;
> + uint8_t txchar;
> + uint8_t setrts;
> + uint8_t rts;
> + uint8_t setdtr;
> + uint8_t dtr;
> +
> + uint8_t rxforwardingchars;
> + uint8_t rxforwardingtimeoutms;
> + uint8_t txacksetting;
> +
> + uint8_t portenabled;
> + uint8_t txflush;
> + uint8_t txbreak;
> + uint8_t loopbackmode;
> +
> + uint8_t rxflush;
> + uint8_t rxforward;
> + uint8_t cancelrxoff;
> + uint8_t returnstatus;
> +} __packed;
> +
> +/* Received from device on control in endpoint */
> +struct ukspan_smsg {
> + uint8_t msr;
> + uint8_t cts;
> + uint8_t dcd;
> + uint8_t dsr;
> + uint8_t ri;
> + uint8_t txxoff;
> + uint8_t rxbreak;
> + uint8_t rxoverrun;
> + uint8_t rxparity;
> + uint8_t rxframe;
> + uint8_t portstate;
> + uint8_t messageack;
> + uint8_t charack;
> + uint8_t controlresp;
> +} __packed;
> +
> +struct ukspan_softc {
> + struct device sc_dev;
> + struct usbd_device *udev;
> + struct usbd_interface *iface;
> + struct usbd_pipe *cout_pipe;
> + struct usbd_pipe *cin_pipe;
> + struct usbd_xfer *ixfer;
> + struct usbd_xfer *oxfer;
> + struct device *ucom_dev;
> + struct ukspan_smsg smsg;
> + struct ukspan_cmsg cmsg;
> + u_char lsr;
> + u_char msr;
> +};
> +
> +int ukspan_match(struct device *, void *, void *);
> +void ukspan_attach(struct device *, struct device *, void *);
> +int ukspan_detach(struct device *, int);
> +
> +void ukspan_close(void *, int);
> +int ukspan_open(void *, int);
> +int ukspan_param(void *, int, struct termios *);
> +void ukspan_set(void *, int, int, int);
> +void ukspan_get_status(void *, int, u_char *, u_char *);
> +
> +void ukspan_cmsg_init(bool, struct ukspan_cmsg *);
> +int ukspan_cmsg_send(struct ukspan_softc *);
> +void ukspan_incb(struct usbd_xfer *, void *, usbd_status);
> +void ukspan_outcb(struct usbd_xfer *, void *, usbd_status);
> +void ukspan_destroy(struct ukspan_softc *);
> +
> +struct cfdriver ukspan_cd = {
> + NULL, "ukspan", DV_DULL
> +};
> +
> +const struct cfattach ukspan_ca = {
> + sizeof(struct ukspan_softc), ukspan_match, ukspan_attach,
> + ukspan_detach
> +};
> +
> +static const struct usb_devno ukspan_devs[] = {
> + { USB_VENDOR_KEYSPAN, USB_PRODUCT_KEYSPAN_USA19HS },
> +};
> +
> +static struct ucom_methods ukspan_methods = {
> + .ucom_get_status = ukspan_get_status,
> + .ucom_set = ukspan_set,
> + .ucom_param = ukspan_param,
> + .ucom_ioctl = NULL,
> + .ucom_open = ukspan_open,
> + .ucom_close = ukspan_close,
> + .ucom_read = NULL,
> + .ucom_write = NULL,
> +};
> +
> +int
> +ukspan_match(struct device *parent, void *match, void *aux)
> +{
> + struct usb_attach_arg *uaa = aux;
> +
> + if (uaa->iface != NULL)
> + return UMATCH_NONE;
> +
> + int found = usb_lookup(ukspan_devs, uaa->vendor, uaa->product) != NULL;
> + return found ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
> +}
> +
> +void
> +ukspan_attach(struct device *parent, struct device *self, void *aux)
> +{
> + struct ukspan_softc *sc = (struct ukspan_softc *)self;
> + struct usb_attach_arg *uaa = aux;
> + struct usbd_device *dev = uaa->device;
> + struct ucom_attach_args uca = {0};
> + usb_endpoint_descriptor_t *ed;
> + const char *devname = sc->sc_dev.dv_xname;
> + usbd_status err;
> + int t1, t2, t3, t4;
> +
> + DPRINTF("attach\n");
> +
> + sc->udev = dev;
> + sc->cin_pipe = sc->cout_pipe = NULL;
> + sc->ixfer = sc->oxfer = NULL;
> + sc->ucom_dev = NULL;
> +
> + /*
> + * Switch to configuration 1 where the transfer mode of the input
> + * endpoints is bulk instead of interrupt, as ucom expects
> + */
> + err = usbd_set_config_index(sc->udev, UKSPAN_CONFIG_IDX, 1);
> + if (err) {
> + printf("%s: set config failed\n", devname);
> + goto fail;
> + }
> +
> + err = usbd_device2interface_handle(sc->udev, UKSPAN_IFACE_IDX,
> + &sc->iface);
> + if (err) {
> + printf("%s: get interface failed\n", devname);
> + goto fail;
> + }
> +
> + ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_BULKIN);
> + t1 = UE_GET_XFERTYPE(ed->bmAttributes);
> + uca.ibufsize = UGETW(ed->wMaxPacketSize);
> + uca.bulkin = UKSPAN_EA_BULKIN;
> +
> + ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_BULKOUT);
> + t2 = UE_GET_XFERTYPE(ed->bmAttributes);
> + uca.obufsize = UGETW(ed->wMaxPacketSize);
> + uca.bulkout = UKSPAN_EA_BULKOUT;
> +
> + ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_CONFIGIN);
> + t3 = UE_GET_XFERTYPE(ed->bmAttributes);
> + if (UGETW(ed->wMaxPacketSize) < sizeof(struct ukspan_smsg)) {
> + printf("%s: in config packet size too small\n", devname);
> + goto fail;
> + }
> +
> + ed = usbd_get_endpoint_descriptor(sc->iface, UKSPAN_EA_CONFIGOUT);
> + t4 = UE_GET_XFERTYPE(ed->bmAttributes);
> + if (UGETW(ed->wMaxPacketSize) < sizeof(struct ukspan_cmsg)) {
> + printf("%s: out config packet size too small\n", devname);
> + goto fail;
> + }
> +
> + if (t1 != UE_BULK || t2 != UE_BULK || t3 != UE_BULK || t4 != UE_BULK) {
> + printf("%s: unexpected xfertypes %x %x %x %x != %x\n", devname,
> + t1, t2, t3, t4, UE_BULK);
> + goto fail;
> + }
> +
> + /* Resource acquisition starts here */
> + err = usbd_open_pipe(sc->iface, UKSPAN_EA_CONFIGOUT, USBD_EXCLUSIVE_USE,
> + &sc->cout_pipe);
> + if (err) {
> + printf("%s: failed to create control out pipe\n", devname);
> + goto fail;
> + }
> +
> + err = usbd_open_pipe(sc->iface, UKSPAN_EA_CONFIGIN, USBD_EXCLUSIVE_USE,
> + &sc->cin_pipe);
> + if (err) {
> + printf("%s: failed to create control out pipe\n", devname);
> + goto fail;
> + }
> +
> + sc->ixfer = usbd_alloc_xfer(sc->udev);
> + sc->oxfer = usbd_alloc_xfer(sc->udev);
> + if (!sc->ixfer || !sc->oxfer) {
> + printf("%s: failed to allocate xfers\n", devname);
> + goto fail;
> + }
> +
> + usbd_setup_xfer(sc->ixfer, sc->cin_pipe, sc, &sc->smsg,
> + sizeof(sc->smsg), 0, USBD_NO_TIMEOUT, ukspan_incb);
> + err = usbd_transfer(sc->ixfer);
> + if (err && err != USBD_IN_PROGRESS) {
> + printf("%s: failed to start ixfer\n", devname);
> + goto fail;
> + }
> +
> + uca.portno = UCOM_UNK_PORTNO;
> + uca.ibufsizepad = uca.ibufsize;
> + uca.opkthdrlen = 0;
> + uca.device = dev;
> + uca.iface = sc->iface;
> + uca.methods = &ukspan_methods;
> + uca.arg = sc;
> + uca.info = NULL;
> +
> + sc->ucom_dev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
> +
> + DPRINTF("attach done\n");
> +
> + return;
> +fail:
> + ukspan_destroy(sc);
> + usbd_deactivate(sc->udev);
> +}
> +
> +int
> +ukspan_detach(struct device *self, int flags)
> +{
> + struct ukspan_softc *sc = (struct ukspan_softc *)self;
> + DPRINTF("detach\n");
> +
> + ukspan_destroy(sc);
> +
> + if (sc->ucom_dev) {
> + config_detach(sc->ucom_dev, flags);
> + sc->ucom_dev = NULL;
> + }
> + return 0;
> +}
> +
> +void
> +ukspan_outcb(struct usbd_xfer *xfer, void *priv, usbd_status status)
> +{
> + struct ukspan_softc *sc = priv;
> + const char *devname = sc->sc_dev.dv_xname;
> +
> + DPRINTF("outcb\n");
> +
> + if (usbd_is_dying(sc->udev)) {
> + DPRINTF("usb dying\n");
> + return;
> + }
> + if (status != USBD_NORMAL_COMPLETION) {
> + printf("%s: oxfer failed\n", devname);
> + return;
> + }
> +}
> +
> +void
> +ukspan_incb(struct usbd_xfer *xfer, void *priv, usbd_status status)
> +{
> + struct ukspan_softc *sc = priv;
> + const char *devname = sc->sc_dev.dv_xname;
> + const struct ukspan_smsg *smsg = &sc->smsg;
> + usbd_status err;
> + u_int32_t len;
> +
> + DPRINTF("incb\n");
> +
> + if (usbd_is_dying(sc->udev)) {
> + printf("%s: usb dying\n", devname);
> + return;
> + }
> + if (!sc->cin_pipe || !sc->ixfer) {
> + printf("%s: no cin_pipe, but not dying?\n", devname);
> + return;
> + }
> + if (status != USBD_NORMAL_COMPLETION) {
> + if (status != USBD_NOT_STARTED && status != USBD_CANCELLED)
> + printf("%s: ixfer failed\n", devname);
> + return;
> + }
> +
> + usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
> + if (len < sizeof(struct ukspan_smsg)) {
> + printf("%s: short read\n", devname);
> + return;
> + }
> +
> + /* The device provides the actual MSR register */
> + sc->msr = smsg->msr;
> + /* But not LSR... */
> + sc->lsr = (smsg->rxoverrun ? ULSR_OE : 0) |
> + (smsg->rxparity ? ULSR_PE : 0) |
> + (smsg->rxframe ? ULSR_FE : 0) |
> + (smsg->rxbreak ? ULSR_BI : 0);
> + ucom_status_change((struct ucom_softc *)sc->ucom_dev);
> +
> + usbd_setup_xfer(sc->ixfer, sc->cin_pipe, sc, &sc->smsg,
> + sizeof(sc->smsg), USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT,
> + ukspan_incb);
> + err = usbd_transfer(sc->ixfer);
> + if (err && err != USBD_IN_PROGRESS)
> + printf("%s: usbd transfer failed\n", devname);
> +}
> +
> +void
> +ukspan_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
> +{
> + struct ukspan_softc *sc = addr;
> + DPRINTF("get status\n");
> + if (lsr)
> + *lsr = sc->lsr;
> + if (msr)
> + *msr = sc->msr;
> +}
> +
> +void
> +ukspan_cmsg_init(bool opening, struct ukspan_cmsg *omsg)
> +{
> + bzero(omsg, sizeof(*omsg));
> +
> + omsg->xonchar = 17;
> + omsg->xoffchar = 19;
> +
> + omsg->rxforwardingchars = 16;
> + omsg->rxforwardingtimeoutms = 16;
> + omsg->txacksetting = 0;
> + omsg->txbreak = 0;
> + if (opening) {
> + omsg->portenabled = 1;
> + omsg->rxflush = 1;
> + }
> +}
> +
> +int
> +ukspan_cmsg_send(struct ukspan_softc *sc)
> +{
> + const char *devname = sc->sc_dev.dv_xname;
> + usbd_status err;
> +
> + usbd_setup_xfer(sc->oxfer, sc->cout_pipe, sc, &sc->cmsg,
> + sizeof(sc->cmsg), USBD_SYNCHRONOUS, USBD_NO_TIMEOUT, ukspan_outcb);
> + err = usbd_transfer(sc->oxfer);
> + if (err != USBD_NORMAL_COMPLETION) {
> + printf("%s: control xfer failed\n", devname);
> + return EIO;
> + }
> + return 0;
> +}
> +
> +void
> +ukspan_set(void *addr, int portno, int reg, int onoff)
> +{
> + struct ukspan_softc *sc = addr;
> + const char *devname = sc->sc_dev.dv_xname;
> + DPRINTF("set %#x = %#x\n", reg, onoff);
> + int flag = !!onoff;
> + switch (reg) {
> + case UCOM_SET_DTR:
> + sc->cmsg.setdtr = 1;
> + sc->cmsg.dtr = flag;
> + break;
> + case UCOM_SET_RTS:
> + sc->cmsg.setrts = 1;
> + sc->cmsg.rts = flag;
> + break;
> + case UCOM_SET_BREAK:
> + sc->cmsg.txbreak = flag;
> + break;
> + default:
> + printf("%s: unhandled reg %#x\n", devname, reg);
> + return;
> + }
> + ukspan_cmsg_send(sc);
> +}
> +
> +int
> +ukspan_param(void *addr, int portno, struct termios *ti)
> +{
> + struct ukspan_softc *sc = addr;
> + const char *devname = sc->sc_dev.dv_xname;
> + struct ukspan_cmsg *cmsg = &sc->cmsg;
> + speed_t baud;
> + tcflag_t cflag;
> + u_int32_t div;
> + u_int8_t lcr;
> +
> + DPRINTF("param: %#x %#x %#x\n", ti->c_ospeed, ti->c_cflag, ti->c_iflag);
> +
> + /* Set baud */
> + div = 1;
> + baud = ti->c_ospeed;
> + switch (baud) {
> + case B300:
> + case B600:
> + case B1200:
> + case B2400:
> + case B4800:
> + case B9600:
> + case B19200:
> + case B38400:
> + case B57600:
> + case B115200:
> + case B230400:
> + div = UKSPAN_CLOCK / (baud * 16);
> + break;
> + default:
> + printf("%s: unexpected baud: %d\n", devname, baud);
> + return EINVAL;
> + }
> +
> + cmsg->setclock = 1;
> + cmsg->baudlo = div & 0xff;
> + cmsg->baudhi = div >> 8;
> +
> + cmsg->setrxmode = 1;
> + cmsg->settxmode = 1;
> + if (baud > 57600)
> + cmsg->rxmode = cmsg->txmode = UKSPAN_MAGIC;
> + else
> + cmsg->rxmode = cmsg->txmode = 0;
> +
> + /* Set parity, data, and stop bits */
> + if ((cflag & CIGNORE) == 0) {
> + cflag = ti->c_cflag;
> + if (cflag & PARENB)
> + lcr = (cflag & PARODD) ? UKSPAN_PARITY_ODD :
> + UKSPAN_PARITY_EVEN;
> + else
> + lcr = UKSPAN_PARITY_NONE;
> + switch (cflag & CSIZE) {
> + case CS5:
> + lcr |= UKSPAN_DATA_5;
> + break;
> + case CS6:
> + lcr |= UKSPAN_DATA_6;
> + break;
> + case CS7:
> + lcr |= UKSPAN_DATA_7;
> + break;
> + case CS8:
> + lcr |= UKSPAN_DATA_8;
> + break;
> + }
> +
> + lcr |= (cflag & CSTOPB) ? UKSPAN_STOP_2 : UKSPAN_STOP_1;
> +
> + cmsg->setlcr = 1;
> + cmsg->lcr = lcr;
> + }
> +
> + /* XXX flow control? */
> +
> + ukspan_cmsg_send(sc);
> + return 0;
> +}
> +
> +int
> +ukspan_open(void *addr, int portno)
> +{
> + struct ukspan_softc *sc = addr;
> + int ret;
> +
> + DPRINTF("open\n");
> + if (usbd_is_dying(sc->udev)) {
> + DPRINTF("usb dying\n");
> + return ENXIO;
> + }
> +
> + ukspan_cmsg_init(true, &sc->cmsg);
> + ret = ukspan_cmsg_send(sc);
> + return ret;
> +}
> +
> +void
> +ukspan_close(void *addr, int portno)
> +{
> + struct ukspan_softc *sc = addr;
> + DPRINTF("close\n");
> + if (usbd_is_dying(sc->udev)) {
> + DPRINTF("usb dying\n");
> + return;
> + }
> + ukspan_cmsg_init(false, &sc->cmsg);
> + ukspan_cmsg_send(sc);
> +}
> +
> +void
> +ukspan_destroy(struct ukspan_softc *sc)
> +{
> + DPRINTF("destroy\n");
> + if (sc->cin_pipe) {
> + usbd_close_pipe(sc->cin_pipe);
> + sc->cin_pipe = NULL;
> + }
> + if (sc->cout_pipe) {
> + usbd_close_pipe(sc->cout_pipe);
> + sc->cout_pipe = NULL;
> + }
> + if (sc->oxfer) {
> + usbd_free_xfer(sc->oxfer);
> + sc->oxfer = NULL;
> + }
> + if (sc->ixfer) {
> + usbd_free_xfer(sc->ixfer);
> + sc->ixfer = NULL;
> + }
> +}
> diff --git sys/dev/usb/usbdevs sys/dev/usb/usbdevs
> index e8247513ee1..fc994337042 100644
> --- sys/dev/usb/usbdevs
> +++ sys/dev/usb/usbdevs
> @@ -2454,6 +2454,7 @@ product KEYSPAN USA18XA_NF 0x0116 USA-18XA serial
> product KEYSPAN USA18XA 0x0117 USA-18XA serial
> product KEYSPAN USA19QW_NF 0x0118 USA-19WQ serial
> product KEYSPAN USA19QW 0x0119 USA-19WQ serial
> +product KEYSPAN USA19HS 0x0121 USA-19HS serial
> product KEYSPAN UIA10 0x0201 UIA-10 remote control
> product KEYSPAN UIA11 0x0202 UIA-11 remote control
>
The diff applies cleanly and the device works fine. Tested using minicom
to an apu device.
The only thing I noticed was a failure when disconnecting the keyspan:
ikspan0: ixfer failed
Thanks! I now have another working serial-to-usb!
Hope this helps,
Tracey
---------
Jun 4 08:13:35 stef /bsd: ukspan0 at uhub0 port 4 "Keyspan, a division of
InnoSys Inc. Keyspan USA-19H" rev 1.10/1.00 addr 2
Jun 4 08:13:35 stef /bsd: ucom0 at ukspan0
Jun 4 08:13:49 stef /bsd: ukspan0: ixfer failed
Jun 4 08:13:49 stef /bsd: ucom0 detached
Jun 4 08:13:49 stef /bsd: ukspan0 detached