Module Name: src
Committed By: jakllsch
Date: Sat Jan 14 21:06:01 UTC 2012
Modified Files:
src/sys/dev/usb: files.usb uslsa.c
Added Files:
src/sys/dev/usb: uslsareg.h
Log Message:
Rework uslsa(4) based on publicly-available Silicon Labs AN571 document.
To generate a diff of this commit:
cvs rdiff -u -r1.117 -r1.118 src/sys/dev/usb/files.usb
cvs rdiff -u -r1.16 -r1.17 src/sys/dev/usb/uslsa.c
cvs rdiff -u -r0 -r1.1 src/sys/dev/usb/uslsareg.h
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.117 src/sys/dev/usb/files.usb:1.118
--- src/sys/dev/usb/files.usb:1.117 Sat Dec 31 00:08:48 2011
+++ src/sys/dev/usb/files.usb Sat Jan 14 21:06:01 2012
@@ -1,4 +1,4 @@
-# $NetBSD: files.usb,v 1.117 2011/12/31 00:08:48 christos Exp $
+# $NetBSD: files.usb,v 1.118 2012/01/14 21:06:01 jakllsch Exp $
#
# Config file and device description for machine-independent USB code.
# Included by ports that need it. Ports that use it must provide
@@ -339,7 +339,7 @@ file dev/usb/uark.c uark
# Silicon Labs CP210x serial driver
device uslsa: ucombus
-attach uslsa at usbdevif
+attach uslsa at usbifif
file dev/usb/uslsa.c uslsa
# WinChipHead CH341/340 serial driver
Index: src/sys/dev/usb/uslsa.c
diff -u src/sys/dev/usb/uslsa.c:1.16 src/sys/dev/usb/uslsa.c:1.17
--- src/sys/dev/usb/uslsa.c:1.16 Fri Dec 23 00:51:49 2011
+++ src/sys/dev/usb/uslsa.c Sat Jan 14 21:06:01 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: uslsa.c,v 1.16 2011/12/23 00:51:49 jakllsch Exp $ */
+/* $NetBSD: uslsa.c,v 1.17 2012/01/14 21:06:01 jakllsch Exp $ */
/* from ugensa.c */
@@ -57,12 +57,8 @@
*
*/
-/*
- * Craig Shelley's Linux driver was used for documentation.
- */
-
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uslsa.c,v 1.16 2011/12/23 00:51:49 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uslsa.c,v 1.17 2012/01/14 21:06:01 jakllsch Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -79,102 +75,45 @@ __KERNEL_RCSID(0, "$NetBSD: uslsa.c,v 1.
#include <dev/usb/ucomvar.h>
-#ifdef DEBUG
-#define USLSA_DEBUG
-#endif
+#include <dev/usb/uslsareg.h>
+
+#include <fs/unicode.h>
#ifdef USLSA_DEBUG
-#define DPRINTF(x) if (uslsadebug) printf x
-#define DPRINTFN(n,x) if (uslsadebug>(n)) printf x
+#define DPRINTF(x) if (uslsadebug) device_printf x
int uslsadebug = 0;
#else
#define DPRINTF(x)
-#define DPRINTFN(n,x)
#endif
-#define USLSA_REQ_SET_STATE 0x00
-
-#define USLSA_REQ_SET_BPS 0x01
-#define USLSA_REQ_GET_BPS 0x02
-
-#define USLSA_REQ_SET_DPS 0x03
-#define USLSA_REQ_GET_DPS 0x04
-
-#define USLSA_REQ_SET_BREAK 0x05
-
-#define USLSA_REQ_SET_FLOW 0x07
-#define USLSA_REQ_GET_FLOW 0x08
-
-#define USLSA_REQ_SET_MODEM 0x13
-#define USLSA_REQ_GET_MODEM 0x14
-
-#define USLSA_REQ_SET_MISC 0x19
-#define USLSA_REQ_GET_MISC 0x20
-
-#define USLSA_STATE_DISABLE 0x0000
-#define USLSA_STATE_ENABLE 0x0001
-
-#define USLSA_BPS(b) (3686400/b)
-
-#define USLSA_DPS_DATA_MASK 0x0f00
-#define USLSA_DPS_DATA_FIVE 0x0500
-#define USLSA_DPS_DATA_SIX 0x0600
-#define USLSA_DPS_DATA_SEVEN 0x0700
-#define USLSA_DPS_DATA_EIGHT 0x0800
-#define USLSA_DPS_DATA_NINE 0x0900
-
-#define USLSA_DPS_PARITY_MASK 0x00f0
-#define USLSA_DPS_PARITY_SPACE 0x0040
-#define USLSA_DPS_PARITY_MARK 0x0030
-#define USLSA_DPS_PARITY_EVEN 0x0020
-#define USLSA_DPS_PARITY_ODD 0x0010
-#define USLSA_DPS_PARITY_NONE 0x0000
-
-#define USLSA_DPS_STOP_MASK 0x000f
-#define USLSA_DPS_STOP_TWO 0x0002
-#define USLSA_DPS_STOP_ONE_FIVE 0x0001
-#define USLSA_DPS_STOP_ONE 0x0000
-
-#define USLSA_BREAK_DISABLE 0x0000
-#define USLSA_BREAK_ENABLE 0x0001
-
-#define USLSA_FLOW_SET_RTS 0x0200
-#define USLSA_FLOW_SET_DTR 0x0100
-#define USLSA_FLOW_MSR_MASK 0x00f0
-#define USLSA_FLOW_MSR_DCD 0x0080
-#define USLSA_FLOW_MSR_RI 0x0040
-#define USLSA_FLOW_MSR_DSR 0x0020
-#define USLSA_FLOW_MSR_CTS 0x0010
-#define USLSA_FLOW_RTS 0x0002
-#define USLSA_FLOW_DTR 0x0001
-
struct uslsa_softc {
device_t sc_dev; /* base device */
- usbd_device_handle sc_udev; /* device */
- usbd_interface_handle sc_iface; /* interface */
-
device_t sc_subdev; /* ucom device */
-
- u_char sc_dying; /* disconnecting */
-
- u_char sc_lsr; /* local status register */
- u_char sc_msr; /* uslsa status register */
+ usbd_device_handle sc_udev; /* usb device */
+ usbd_interface_handle sc_iface; /* interface */
+ uint8_t sc_ifnum; /* interface number */
+ bool sc_dying; /* disconnecting */
};
static void uslsa_get_status(void *sc, int, u_char *, u_char *);
static void uslsa_set(void *, int, int, int);
static int uslsa_param(void *, int, struct termios *);
+static int uslsa_ioctl(void *, int, u_long, void *, int, proc_t *);
+
static int uslsa_open(void *, int);
static void uslsa_close(void *, int);
+static int uslsa_usbd_errno(usbd_status);
static int uslsa_request_set(struct uslsa_softc *, uint8_t, uint16_t);
-static void uslsa_set_flow(struct uslsa_softc *, tcflag_t, tcflag_t);
+static int uslsa_set_flow(struct uslsa_softc *, tcflag_t, tcflag_t);
+
+static void uslsa_props(struct uslsa_softc *);
static const struct ucom_methods uslsa_methods = {
uslsa_get_status,
uslsa_set,
uslsa_param,
- NULL,
+ uslsa_ioctl,
uslsa_open,
uslsa_close,
NULL,
@@ -204,7 +143,6 @@ static const struct usb_devno uslsa_devs
{ USB_VENDOR_SILABS2, USB_PRODUCT_SILABS2_DCU11CLONE },
{ USB_VENDOR_USI, USB_PRODUCT_USI_MC60 }
};
-#define uslsa_lookup(v, p) usb_lookup(uslsa_devs, v, p)
static int uslsa_match(device_t, cfdata_t, void *);
static void uslsa_attach(device_t, device_t, void *);
@@ -215,59 +153,48 @@ static int uslsa_activate(device_t, enum
CFATTACH_DECL2_NEW(uslsa, sizeof(struct uslsa_softc), uslsa_match,
uslsa_attach, uslsa_detach, uslsa_activate, NULL, uslsa_childdet);
-static int
+static int
uslsa_match(device_t parent, cfdata_t match, void *aux)
{
- struct usb_attach_arg *uaa = aux;
+ const struct usbif_attach_arg *uaa;
+
+ uaa = aux;
- return (uslsa_lookup(uaa->vendor, uaa->product) != NULL ?
- UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
+ if (usb_lookup(uslsa_devs, uaa->vendor, uaa->product) != NULL) {
+ return UMATCH_VENDOR_PRODUCT;
+ } else {
+ return UMATCH_NONE;
+ }
}
-static void
+static void
uslsa_attach(device_t parent, device_t self, void *aux)
{
- struct uslsa_softc *sc = device_private(self);
- struct usb_attach_arg *uaa = aux;
- usbd_device_handle dev = uaa->device;
- usbd_interface_handle iface;
- usb_interface_descriptor_t *id;
- usb_endpoint_descriptor_t *ed;
+ struct uslsa_softc *sc;
+ const struct usbif_attach_arg *uaa;
+ const usb_interface_descriptor_t *id;
+ const usb_endpoint_descriptor_t *ed;
char *devinfop;
- usbd_status err;
struct ucom_attach_args uca;
int i;
- sc->sc_dev = self;
+ sc = device_private(self);
+ uaa = aux;
- DPRINTFN(10, ("\nuslsa_attach: sc=%p\n", sc));
+ sc->sc_dev = self;
+ sc->sc_udev = uaa->device;
+ sc->sc_iface = uaa->iface;
aprint_naive("\n");
aprint_normal("\n");
- devinfop = usbd_devinfo_alloc(dev, 0);
+ devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
aprint_normal_dev(self, "%s\n", devinfop);
usbd_devinfo_free(devinfop);
- /* Move the device into the configured state. */
- err = usbd_set_config_index(dev, USLSA_CONFIG_INDEX, 1);
- if (err) {
- aprint_error_dev(self, "failed to set configuration, err=%s\n",
- usbd_errstr(err));
- goto bad;
- }
-
- err = usbd_device2interface_handle(dev, USLSA_IFACE_INDEX, &iface);
- if (err) {
- aprint_error_dev(self, "failed to get interface, err=%s\n",
- usbd_errstr(err));
- goto bad;
- }
-
- id = usbd_get_interface_descriptor(iface);
+ id = usbd_get_interface_descriptor(sc->sc_iface);
- sc->sc_udev = dev;
- sc->sc_iface = iface;
+ sc->sc_ifnum = id->bInterfaceNumber;
uca.info = "Silicon Labs CP210x";
uca.portno = UCOM_UNK_PORTNO;
@@ -275,8 +202,8 @@ uslsa_attach(device_t parent, device_t s
uca.obufsize = USLSA_BUFSIZE;
uca.ibufsizepad = USLSA_BUFSIZE;
uca.opkthdrlen = 0;
- uca.device = dev;
- uca.iface = iface;
+ uca.device = sc->sc_udev;
+ uca.iface = sc->sc_iface;
uca.methods = &uslsa_methods;
uca.arg = sc;
@@ -287,42 +214,36 @@ uslsa_attach(device_t parent, device_t s
for (i = 0; i < id->bNumEndpoints; i++) {
int addr, dir, attr;
- ed = usbd_interface2endpoint_descriptor(iface, i);
+ ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
if (ed == NULL) {
aprint_error_dev(self,
- "could not read endpoint descriptor: %s\n",
- usbd_errstr(err));
- goto bad;
+ "could not read endpoint descriptor\n");
+ sc->sc_dying = true;
+ return;
}
addr = ed->bEndpointAddress;
dir = UE_GET_DIR(ed->bEndpointAddress);
attr = ed->bmAttributes & UE_XFERTYPE;
- if (dir == UE_DIR_IN && attr == UE_BULK)
+ if (dir == UE_DIR_IN && attr == UE_BULK) {
uca.bulkin = addr;
- else if (dir == UE_DIR_OUT && attr == UE_BULK)
+ } else if (dir == UE_DIR_OUT && attr == UE_BULK) {
uca.bulkout = addr;
- else
+ } else {
aprint_error_dev(self, "unexpected endpoint\n");
+ }
}
- if (uca.bulkin == -1) {
- aprint_error_dev(self, "Could not find data bulk in\n");
- goto bad;
- }
- if (uca.bulkout == -1) {
- aprint_error_dev(self, "Could not find data bulk out\n");
- goto bad;
+ aprint_debug_dev(sc->sc_dev, "EPs: in=%#x out=%#x\n",
+ uca.bulkin, uca.bulkout);
+ if ((uca.bulkin == -1) || (uca.bulkout == -1)) {
+ aprint_error_dev(self, "could not find endpoints\n");
+ sc->sc_dying = true;
+ return;
}
- DPRINTF(("uslsa: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca,
ucomprint, ucomsubmatch);
return;
-
-bad:
- DPRINTF(("uslsa_attach: ATTACH ERROR\n"));
- sc->sc_dying = 1;
- return;
}
static int
@@ -332,7 +253,7 @@ uslsa_activate(device_t self, enum devac
switch (act) {
case DVACT_DEACTIVATE:
- sc->sc_dying = 1;
+ sc->sc_dying = true;
return 0;
default:
return EOPNOTSUPP;
@@ -348,18 +269,19 @@ uslsa_childdet(device_t self, device_t c
sc->sc_subdev = NULL;
}
-static int
+static int
uslsa_detach(device_t self, int flags)
{
struct uslsa_softc *sc = device_private(self);
int rv = 0;
- DPRINTF(("uslsa_detach: sc=%p flags=%d\n", sc, flags));
+ DPRINTF((self, "%s(%p, %#x)\n", __func__, self, flags));
- sc->sc_dying = 1;
+ sc->sc_dying = true;
- if (sc->sc_subdev != NULL)
+ if (sc->sc_subdev != NULL) {
rv = config_detach(sc->sc_subdev, flags);
+ }
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
sc->sc_dev);
@@ -367,39 +289,61 @@ uslsa_detach(device_t self, int flags)
return (rv);
}
+static int
+uslsa_usbd_errno(usbd_status status)
+{
+ switch (status) {
+ case USBD_NORMAL_COMPLETION:
+ return 0;
+ case USBD_STALLED:
+ return EINVAL;
+ default:
+ return EIO;
+ }
+}
+
static void
uslsa_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
{
struct uslsa_softc *sc;
usb_device_request_t req;
- usbd_status err;
- int actlen;
- uint16_t flowreg;
+ usbd_status status;
+ uint8_t mdmsts;
sc = vsc;
- DPRINTF(("uslsa_get_status:\n"));
+ DPRINTF((sc->sc_dev, "%s(%p, %d, ....)\n", __func__, vsc, portno));
+
+ if (sc->sc_dying) {
+ return;
+ }
req.bmRequestType = UT_READ_VENDOR_INTERFACE;
- req.bRequest = USLSA_REQ_GET_FLOW;
+ req.bRequest = SLSA_R_GET_MDMSTS;
USETW(req.wValue, 0);
- USETW(req.wIndex, 0);
- USETW(req.wLength, sizeof(flowreg));
+ USETW(req.wIndex, sc->sc_ifnum);
+ USETW(req.wLength, SLSA_RL_GET_MDMSTS);
+
+ status = usbd_do_request(sc->sc_udev, &req, &mdmsts);
+ if (status != USBD_NORMAL_COMPLETION) {
+ device_printf(sc->sc_dev, "%s: GET_MDMSTS %s\n",
+ __func__, usbd_errstr(status));
+ return;
+ }
+
+ DPRINTF((sc->sc_dev, "%s: GET_MDMSTS %#x\n", __func__, mdmsts));
+
+ if (lsr != NULL) {
+ *lsr = 0;
+ }
- err = usbd_do_request_flags(sc->sc_udev, &req, &flowreg,
- USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT);
- if (err)
- printf("%s: uslsa_get_status: %s\n",
- device_xname(sc->sc_dev), usbd_errstr(err));
-
- DPRINTF(("uslsa_get_status: flowreg=0x%x\n", flowreg));
-
- sc->sc_msr = (u_char)(USLSA_FLOW_MSR_MASK & flowreg);
-
- if (lsr != NULL)
- *lsr = sc->sc_lsr;
- if (msr != NULL)
- *msr = sc->sc_msr;
+ if (msr != NULL) {
+ *msr = 0;
+ *msr |= ISSET(mdmsts, SLSA_MDMSTS_CTS) ? UMSR_CTS : 0;
+ *msr |= ISSET(mdmsts, SLSA_MDMSTS_DSR) ? UMSR_DSR : 0;
+ *msr |= ISSET(mdmsts, SLSA_MDMSTS_RI) ? UMSR_RI : 0;
+ *msr |= ISSET(mdmsts, SLSA_MDMSTS_DCD) ? UMSR_DCD : 0;
+ }
}
static void
@@ -409,30 +353,33 @@ uslsa_set(void *vsc, int portno, int reg
sc = vsc;
- DPRINTF(("uslsa_set: sc=%p, port=%d reg=%d onoff=%d\n", sc, portno,
- reg, onoff));
+ DPRINTF((sc->sc_dev, "%s(%p, %d, %d, %d)\n", __func__, vsc, portno, reg, onoff));
+
+ if (sc->sc_dying) {
+ return;
+ }
switch (reg) {
case UCOM_SET_DTR:
- if (uslsa_request_set(sc, USLSA_REQ_SET_FLOW,
- (onoff ? (USLSA_FLOW_DTR | USLSA_FLOW_SET_DTR) :
- USLSA_FLOW_SET_DTR)))
- printf("%s: uslsa_set_dtr failed\n",
- device_xname(sc->sc_dev));
+ if (uslsa_request_set(sc, SLSA_R_SET_MHS,
+ SLSA_RV_SET_MHS_DTR_MASK |
+ (onoff ? SLSA_RV_SET_MHS_DTR : 0))) {
+ device_printf(sc->sc_dev, "SET_MHS/DTR failed\n");
+ }
break;
case UCOM_SET_RTS:
- if (uslsa_request_set(sc, USLSA_REQ_SET_FLOW,
- (onoff ? (USLSA_FLOW_RTS | USLSA_FLOW_SET_RTS) :
- USLSA_FLOW_SET_RTS)))
- printf("%s: uslsa_set_rts failed\n",
- device_xname(sc->sc_dev));
+ if (uslsa_request_set(sc, SLSA_R_SET_MHS,
+ SLSA_RV_SET_MHS_RTS_MASK |
+ (onoff ? SLSA_RV_SET_MHS_RTS : 0))) {
+ device_printf(sc->sc_dev, "SET_MHS/RTS failed\n");
+ }
break;
case UCOM_SET_BREAK:
- if (uslsa_request_set(sc, USLSA_REQ_SET_BREAK,
- (onoff ? USLSA_BREAK_ENABLE :
- USLSA_BREAK_DISABLE)))
- printf("%s: uslsa_set_break failed\n",
- device_xname(sc->sc_dev));
+ if (uslsa_request_set(sc, SLSA_R_SET_BREAK,
+ (onoff ? SLSA_RV_SET_BREAK_ENABLE :
+ SLSA_RV_SET_BREAK_DISABLE))) {
+ device_printf(sc->sc_dev, "SET_BREAK failed\n");
+ }
break;
default:
break;
@@ -440,81 +387,92 @@ uslsa_set(void *vsc, int portno, int reg
}
static int
-uslsa_param(void *vsc, int portno, struct termios * t)
+uslsa_param(void *vsc, int portno, struct termios *t)
{
struct uslsa_softc *sc;
- uint16_t data;
+ int ret;
+ uint16_t value;
sc = vsc;
- DPRINTF(("uslsa_param: sc=%p\n", sc));
+ DPRINTF((sc->sc_dev, "%s(%p, %d, %p)\n", __func__, vsc, portno, t));
- switch (t->c_ospeed) {
- case B600:
- case B1200:
- case B2400:
- case B4800:
- case B9600:
- case B19200:
- case B38400:
- case B57600:
- case B115200:
- case B230400:
- case B460800:
- case B921600:
- data = USLSA_BPS(t->c_ospeed);
- break;
- default:
- printf("%s: uslsa_param: unsupported data rate, "
- "forcing default of 115200bps\n",
- device_xname(sc->sc_dev));
- data = USLSA_BPS(B115200);
- };
-
- if (uslsa_request_set(sc, USLSA_REQ_SET_BPS, data))
- printf("%s: uslsa_param: setting data rate failed\n",
- device_xname(sc->sc_dev));
-
- data = 0;
-
- if (ISSET(t->c_cflag, CSTOPB))
- data |= USLSA_DPS_STOP_TWO;
- else
- data |= USLSA_DPS_STOP_ONE;
+ if (sc->sc_dying) {
+ return EIO;
+ }
+
+ value = SLSA_RV_BAUDDIV(t->c_ospeed);
+
+ if ((ret = uslsa_request_set(sc, SLSA_R_SET_BAUDDIV, value)) != 0) {
+ device_printf(sc->sc_dev, "%s: SET_BAUDDIV failed\n",
+ __func__);
+ return ret;
+ }
+
+ value = 0;
+
+ if (ISSET(t->c_cflag, CSTOPB)) {
+ value |= SLSA_RV_LINE_CTL_STOP_2;
+ } else {
+ value |= SLSA_RV_LINE_CTL_STOP_1;
+ }
if (ISSET(t->c_cflag, PARENB)) {
- if (ISSET(t->c_cflag, PARODD))
- data |= USLSA_DPS_PARITY_ODD;
- else
- data |= USLSA_DPS_PARITY_EVEN;
- } else
- data |= USLSA_DPS_PARITY_NONE;
+ if (ISSET(t->c_cflag, PARODD)) {
+ value |= SLSA_RV_LINE_CTL_PARITY_ODD;
+ } else {
+ value |= SLSA_RV_LINE_CTL_PARITY_EVEN;
+ }
+ } else {
+ value |= SLSA_RV_LINE_CTL_PARITY_NONE;
+ }
switch (ISSET(t->c_cflag, CSIZE)) {
case CS5:
- data |= USLSA_DPS_DATA_FIVE;
+ value |= SLSA_RV_LINE_CTL_LEN_5;
break;
case CS6:
- data |= USLSA_DPS_DATA_SIX;
+ value |= SLSA_RV_LINE_CTL_LEN_6;
break;
case CS7:
- data |= USLSA_DPS_DATA_SEVEN;
+ value |= SLSA_RV_LINE_CTL_LEN_7;
break;
case CS8:
- data |= USLSA_DPS_DATA_EIGHT;
+ value |= SLSA_RV_LINE_CTL_LEN_8;
break;
}
- DPRINTF(("uslsa_param: setting DPS register to 0x%x\n", data));
- if (uslsa_request_set(sc, USLSA_REQ_SET_DPS, data))
- printf("%s: setting DPS register failed: invalid argument\n",
- device_xname(sc->sc_dev));
+ DPRINTF((sc->sc_dev, "%s: setting LINE_CTL to 0x%x\n",
+ __func__, value));
+ if ((ret = uslsa_request_set(sc, SLSA_R_SET_LINE_CTL, value)) != 0) {
+ device_printf(sc->sc_dev, "SET_LINE_CTL failed\n");
+ return ret;
+ }
- uslsa_set_flow(sc, t->c_cflag, t->c_iflag);
+ if ((ret = uslsa_set_flow(sc, t->c_cflag, t->c_iflag)) != 0) {
+ device_printf(sc->sc_dev, "SET_LINE_CTL failed\n");
+ }
- return 0;
+ return ret;
}
+static int
+uslsa_ioctl(void *vsc, int portno, u_long cmd, void *data, int flag, proc_t *p)
+{
+ struct uslsa_softc *sc;
+
+ sc = vsc;
+
+ switch (cmd) {
+ case TIOCMGET:
+ ucom_status_change(device_private(sc->sc_subdev));
+ return EPASSTHROUGH;
+ default:
+ return EPASSTHROUGH;
+ }
+
+ return 0;
+}
static int
uslsa_open(void *vsc, int portno)
@@ -523,15 +481,14 @@ uslsa_open(void *vsc, int portno)
sc = vsc;
- DPRINTF(("uslsa_open: sc=%p\n", sc));
-
- if (sc->sc_dying)
- return (EIO);
+ DPRINTF((sc->sc_dev, "%s(%p, %d)\n", __func__, vsc, portno));
- if (uslsa_request_set(sc, USLSA_REQ_SET_STATE, USLSA_STATE_ENABLE))
- return (EIO);
+ if (sc->sc_dying) {
+ return EIO;
+ }
- return 0;
+ return uslsa_request_set(sc, SLSA_R_IFC_ENABLE,
+ SLSA_RV_IFC_ENABLE_ENABLE);
}
static void
@@ -541,81 +498,79 @@ uslsa_close(void *vsc, int portno)
sc = vsc;
- if (sc->sc_dying)
- return;
+ DPRINTF((sc->sc_dev, "%s(%p, %d)\n", __func__, vsc, portno));
- DPRINTF(("uslsa_close: sc=%p\n", sc));
+ if (sc->sc_dying) {
+ return;
+ }
- if (uslsa_request_set(sc, USLSA_REQ_SET_STATE,
- USLSA_STATE_DISABLE))
- printf("%s: disable-on-close failed\n",
- device_xname(sc->sc_dev));
+ (void)uslsa_request_set(sc, SLSA_R_IFC_ENABLE,
+ SLSA_RV_IFC_ENABLE_DISABLE);
}
-/*
- * uslsa_request_set(), wrapper for doing sets with usbd_do_request()
- */
static int
uslsa_request_set(struct uslsa_softc * sc, uint8_t request, uint16_t value)
{
usb_device_request_t req;
- usbd_status err;
+ usbd_status status;
req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
req.bRequest = request;
USETW(req.wValue, value);
- USETW(req.wIndex, 0);
+ USETW(req.wIndex, sc->sc_ifnum);
USETW(req.wLength, 0);
- err = usbd_do_request(sc->sc_udev, &req, 0);
- if (err)
- printf("%s: uslsa_request: %s\n",
- device_xname(sc->sc_dev), usbd_errstr(err));
- return err;
+ status = usbd_do_request(sc->sc_udev, &req, NULL);
+
+ return uslsa_usbd_errno(status);
}
-/*
- * uslsa_set_flow() does some magic to set up hardware flow control
- */
-static void
+static int
uslsa_set_flow(struct uslsa_softc *sc, tcflag_t cflag, tcflag_t iflag)
{
- uint8_t mysterydata[16];
+ struct slsa_fcs fcs;
usb_device_request_t req;
- usbd_status err;
+ uint32_t ulControlHandshake;
+ uint32_t ulFlowReplace;
+ usbd_status status;
- DPRINTF(("uslsa_set_flow: cflag = 0x%x, iflag = 0x%x\n",
- cflag, iflag));
+ DPRINTF((sc->sc_dev, "%s(%p, %#x, %#x)\n", __func__, sc, cflag, iflag));
req.bmRequestType = UT_READ_VENDOR_INTERFACE;
- req.bRequest = USLSA_REQ_GET_MODEM;
+ req.bRequest = SLSA_R_GET_FLOW;
USETW(req.wValue, 0);
- USETW(req.wIndex, 0);
- USETW(req.wLength, 16);
+ USETW(req.wIndex, sc->sc_ifnum);
+ USETW(req.wLength, SLSA_RL_GET_FLOW);
+
+ status = usbd_do_request(sc->sc_udev, &req, &fcs);
+ if (status != USBD_NORMAL_COMPLETION) {
+ device_printf(sc->sc_dev, "%s: GET_FLOW %s\n",
+ __func__, usbd_errstr(status));
+ return uslsa_usbd_errno(status);
+ }
- err = usbd_do_request(sc->sc_udev, &req, mysterydata);
- if (err)
- printf("%s: uslsa_set_flow: %s\n",
- device_xname(sc->sc_dev), usbd_errstr(err));
+ ulControlHandshake = le32toh(fcs.ulControlHandshake);
+ ulFlowReplace = le32toh(fcs.ulFlowReplace);
if (ISSET(cflag, CRTSCTS)) {
- mysterydata[0] &= ~0x7b;
- mysterydata[0] |= 0x09;
- mysterydata[4] = 0x80;
+ ulControlHandshake =
+ SERIAL_CTS_HANDSHAKE | __SHIFTIN(1, SERIAL_DTR_MASK);
+ ulFlowReplace = __SHIFTIN(2, SERIAL_RTS_MASK);
} else {
- mysterydata[0] &= ~0x7b;
- mysterydata[0] |= 0x01;
- mysterydata[4] = 0x40;
+ ulControlHandshake = __SHIFTIN(1, SERIAL_DTR_MASK);
+ ulFlowReplace = __SHIFTIN(1, SERIAL_RTS_MASK);
}
+ fcs.ulControlHandshake = htole32(ulControlHandshake);
+ fcs.ulFlowReplace = htole32(ulFlowReplace);
+
req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
- req.bRequest = USLSA_REQ_SET_MODEM;
+ req.bRequest = SLSA_R_SET_FLOW;
USETW(req.wValue, 0);
- USETW(req.wIndex, 0);
- USETW(req.wLength, 16);
+ USETW(req.wIndex, sc->sc_ifnum);
+ USETW(req.wLength, SLSA_RL_SET_FLOW);
+
+ status = usbd_do_request(sc->sc_udev, &req, &fcs);
- err = usbd_do_request(sc->sc_udev, &req, mysterydata);
- if (err)
- printf("%s: uslsa_set_flow: %s\n",
- device_xname(sc->sc_dev), usbd_errstr(err));
+ return uslsa_usbd_errno(status);
}
Added files:
Index: src/sys/dev/usb/uslsareg.h
diff -u /dev/null src/sys/dev/usb/uslsareg.h:1.1
--- /dev/null Sat Jan 14 21:06:01 2012
+++ src/sys/dev/usb/uslsareg.h Sat Jan 14 21:06:01 2012
@@ -0,0 +1,240 @@
+/* $NetBSD: uslsareg.h,v 1.1 2012/01/14 21:06:01 jakllsch Exp $ */
+
+/*
+ * Copyright (c) 2011 Jonathan A. Kollasch.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _SLSAREG_H_
+#define _SLSAREG_H_
+
+#include <lib/libkern/libkern.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+
+/* From Silicon Laboratories Application Note AN571 */
+
+#define SLSA_FREQ 3686400
+
+/* USB Control Requests */
+#define SLSA_R_IFC_ENABLE 0x00
+#define SLSA_R_SET_BAUDDIV 0x01
+#define SLSA_R_GET_BAUDDIV 0x02
+#define SLSA_R_SET_LINE_CTL 0x03
+#define SLSA_R_GET_LINE_CTL 0x04
+#define SLSA_R_SET_BREAK 0x05
+#define SLSA_R_IMM_CHAR 0x06
+#define SLSA_R_SET_MHS 0x07
+#define SLSA_R_GET_MDMSTS 0x08
+#define SLSA_R_SET_XON 0x09
+#define SLSA_R_SET_XOFF 0x0a
+#define SLSA_R_SET_EVENTMASK 0x0b
+#define SLSA_R_GET_EVENTMASK 0x0c
+#define SLSA_R_SET_CHAR 0x0d
+#define SLSA_R_GET_CHARS 0x0e
+#define SLSA_R_GET_PROPS 0x0f
+#define SLSA_R_GET_COMM_STATUS 0x10
+#define SLSA_R_RESET 0x11
+#define SLSA_R_PURGE 0x12
+#define SLSA_R_SET_FLOW 0x13
+#define SLSA_R_GET_FLOW 0x14
+#define SLSA_R_EMBED_EVENTS 0x15
+#define SLSA_R_SET_CHARS 0x19
+#define SLSA_R_GET_BAUDRATE 0x1d
+#define SLSA_R_SET_BAUDRATE 0x1e
+#define SLSA_R_VENDOR_SPECIFIC 0xff
+
+
+#define SLSA_RV_IFC_ENABLE_DISABLE 0x0000
+#define SLSA_RV_IFC_ENABLE_ENABLE 0x0001
+
+
+#define SLSA_RV_BAUDDIV(b) (SLSA_FREQ/(b))
+
+
+#define SLSA_RV_LINE_CTL_STOP __BITS(3,0)
+#define SLSA_RV_LINE_CTL_PARITY __BITS(7,4)
+#define SLSA_RV_LINE_CTL_LEN __BITS(15,8)
+
+#define SLSA_RV_LINE_CTL_STOP_1 __SHIFTIN(0, SLSA_RV_LINE_CTL_STOP)
+#define SLSA_RV_LINE_CTL_STOP_1_5 __SHIFTIN(1, SLSA_RV_LINE_CTL_STOP)
+#define SLSA_RV_LINE_CTL_STOP_2 __SHIFTIN(2, SLSA_RV_LINE_CTL_STOP)
+
+#define SLSA_RV_LINE_CTL_PARITY_NONE __SHIFTIN(0, SLSA_RV_LINE_CTL_PARITY)
+#define SLSA_RV_LINE_CTL_PARITY_ODD __SHIFTIN(1, SLSA_RV_LINE_CTL_PARITY)
+#define SLSA_RV_LINE_CTL_PARITY_EVEN __SHIFTIN(2, SLSA_RV_LINE_CTL_PARITY)
+#define SLSA_RV_LINE_CTL_PARITY_MARK __SHIFTIN(3, SLSA_RV_LINE_CTL_PARITY)
+#define SLSA_RV_LINE_CTL_PARITY_SPACE __SHIFTIN(4, SLSA_RV_LINE_CTL_PARITY)
+
+#define SLSA_RV_LINE_CTL_LEN_5 __SHIFTIN(5, SLSA_RV_LINE_CTL_LEN)
+#define SLSA_RV_LINE_CTL_LEN_6 __SHIFTIN(6, SLSA_RV_LINE_CTL_LEN)
+#define SLSA_RV_LINE_CTL_LEN_7 __SHIFTIN(7, SLSA_RV_LINE_CTL_LEN)
+#define SLSA_RV_LINE_CTL_LEN_8 __SHIFTIN(8, SLSA_RV_LINE_CTL_LEN)
+
+
+#define SLSA_RV_SET_BREAK_DISABLE 0x0000
+#define SLSA_RV_SET_BREAK_ENABLE 0x0001
+
+
+#define SLSA_RV_SET_MHS_DTR __BIT(0)
+#define SLSA_RV_SET_MHS_RTS __BIT(1)
+/* AN571 calls these next two masks, they're more like change-enables */
+#define SLSA_RV_SET_MHS_DTR_MASK __BIT(8)
+#define SLSA_RV_SET_MHS_RTS_MASK __BIT(9)
+
+
+#define SLSA_RL_GET_MDMSTS 1
+/* data in uint8_t returned from GET_MDMSTS */
+#define SLSA_MDMSTS_DTR __BIT(0)
+#define SLSA_MDMSTS_RTS __BIT(1)
+#define SLSA_MDMSTS_CTS __BIT(4)
+#define SLSA_MDMSTS_DSR __BIT(5)
+#define SLSA_MDMSTS_RI __BIT(6)
+#define SLSA_MDMSTS_DCD __BIT(7)
+
+
+#define SLSA_RL_SET_EVENTMASK 0
+#define SLSA_RL_GET_EVENTMASK 2
+#define SLSA_RL_GET_EVENTSTATE 2
+#define SLSA_EVENT_TERI __BIT(0) /* RI trailing edge */
+#define SLSA_EVENT_RB80 __BIT(2) /* Rx buf 80% full */
+#define SLSA_EVENT_CR __BIT(8) /* char received */
+#define SLSA_EVENT_SCR __BIT(9) /* special char received */
+#define SLSA_EVENT_TQE __BIT(10) /* Tx queue empty */
+#define SLSA_EVENT_DCTS __BIT(11) /* CTS changed */
+#define SLSA_EVENT_DDSR __BIT(12) /* DSR changed */
+#define SLSA_EVENT_DDCD __BIT(13) /* DCD changed */
+#define SLSA_EVENT_BI __BIT(14) /* line break received */
+#define SLSA_EVENT_LSE __BIT(15) /* line status error */
+
+
+/* USETW2(wValue, char, index) */
+#define SLSA_RV_SET_CHAR_EofChar 0
+#define SLSA_RV_SET_CHAR_ErrorChar 1
+#define SLSA_RV_SET_CHAR_BreakChar 2
+#define SLSA_RV_SET_CHAR_EventChar 3
+#define SLSA_RV_SET_CHAR_XonChar 4
+#define SLSA_RV_SET_CHAR_XoffChar 5
+
+
+#define SLSA_RV_PURGE_TX __BIT(0)
+#define SLSA_RV_PURGE_RX __BIT(1)
+#define SLSA_RV_PURGE_TX1 __BIT(2) /* what's the second set for? */
+#define SLSA_RV_PURGE_RX1 __BIT(3)
+
+
+/* Communication Properties Response Table 7. */
+struct slsa_cpr {
+ uint16_t wLength;
+ uint16_t bcdVersion;
+ uint32_t ulServiceMask;
+ uint32_t _reserved8;
+ uint32_t ulMaxTxQueue;
+ uint32_t ulMaxRxQueue;
+ uint32_t ulMaxBaud;
+ uint32_t ulProvSubType;
+ uint32_t ulProvCapabilities;
+ uint32_t ulSettableParams;
+ uint32_t ulSettableBaud;
+ uint16_t wSettableData;
+ uint16_t _reserved42;
+ uint32_t ulCurrentTxQueue;
+ uint32_t ulCurrentRxQueue;
+ uint32_t _reserved52;
+ uint32_t _reserved56;
+ uint16_t uniProvName[0];
+};
+CTASSERT(offsetof(struct slsa_cpr, _reserved8) == 8);
+CTASSERT(offsetof(struct slsa_cpr, _reserved42) == 42);
+CTASSERT(offsetof(struct slsa_cpr, uniProvName[0]) == 60);
+#define SLSA_CPR_MINLEN 60
+
+#define SLSA_RL_GET_COMM_STATUS 19
+/* Serial Status Response Table 8. */
+struct slsa_ssr {
+ uint32_t ulErrors;
+ uint32_t ulHoldReasons;
+ uint32_t ulAmountInInQueue;
+ uint32_t ulAmountInOutQueue;
+ uint8_t bEofReceived;
+ uint8_t bWaitForImmediate;
+ uint8_t bReserved;
+};
+CTASSERT(offsetof(struct slsa_ssr, bReserved) == 18);
+CTASSERT(sizeof(struct slsa_ssr) >= SLSA_RL_GET_COMM_STATUS);
+
+#define SLSA_RL_SET_FLOW 16
+#define SLSA_RL_GET_FLOW 16
+/* Flow Control State Setting/Response Table 9. */
+struct slsa_fcs {
+ uint32_t ulControlHandshake;
+#define SERIAL_DTR_MASK __BITS(0, 1)
+#define SERIAL_CTS_HANDSHAKE __BIT(3)
+#define SERIAL_DSR_HANDSHAKE __BIT(4)
+#define SERIAL_DCD_HANDSHAKE __BIT(5)
+#define SERIAL_DSR_SENSITIVITY __BIT(6)
+ uint32_t ulFlowReplace;
+#define SERIAL_AUTO_TRANSMIT __BIT(0)
+#define SERIAL_AUTO_RECEIVE __BIT(1)
+#define SERIAL_ERROR_CHAR __BIT(2)
+#define SERIAL_NULL_STRIPPING __BIT(3)
+#define SERIAL_BREAK_CHAR __BIT(4)
+#define SERIAL_RTS_MASK __BITS(6, 7)
+#define SERIAL_XOFF_CONTINUE __BIT(31)
+ uint32_t ulXonLimit;
+ uint32_t ulXoffLimit;
+};
+CTASSERT(sizeof(struct slsa_fcs) == SLSA_RL_SET_FLOW);
+CTASSERT(sizeof(struct slsa_fcs) == SLSA_RL_GET_FLOW);
+
+#define SLSA_RL_SET_CHARS 6
+#define SLSA_RL_GET_CHARS 6
+/* Special Characters Response Table 12. */
+struct slsa_scr {
+ uint8_t bEofChar;
+ uint8_t bErrorChar;
+ uint8_t bBreakChar;
+ uint8_t bEventChar;
+ uint8_t bXonChar;
+ uint8_t bXoffChar;
+};
+CTASSERT(sizeof(struct slsa_scr) == SLSA_RL_SET_CHARS);
+CTASSERT(sizeof(struct slsa_scr) == SLSA_RL_GET_CHARS);
+
+
+#define SLSA_RV_VENDOR_SPECIFIC_READ_LATCH 0x00c2
+#define SLSA_RL_VENDOR_SPECIFIC_READ_LATCH 1
+
+#define SLSA_RV_VENDOR_SPECIFIC_WRITE_LATCH 0x37e1
+/*
+ * on CP2103/CP2104 the latch state and latch mask are
+ * written in the high and low bytes of wIndex respectively
+ *
+ * on CP2105, wIndex is the interface number, and the same
+ * latch/mask is written as data instead.
+ */
+#define SLSA_RL_VENDOR_SPECIFIC_WRITE_LATCH_CP2103 0
+#define SLSA_RL_VENDOR_SPECIFIC_WRITE_LATCH_CP2105 2
+
+#endif /* _SLSAREG_H_ */