diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2006-04-29 02:15:07 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2006-04-29 02:15:07 +0000 |
commit | a17cdfa53888fa71338ff9bc367f3c28cc7dfdad (patch) | |
tree | e14423d24eb7a76d4408b953f47cd837a23e2c41 | |
parent | aa6f2f0294a3341c26228320ee21081167a5cc06 (diff) |
Driver for Silicon Laboratories CP2101/CP2102 based serial adapters.
ok dlg@
-rw-r--r-- | share/man/man4/Makefile | 6 | ||||
-rw-r--r-- | share/man/man4/usb.4 | 4 | ||||
-rw-r--r-- | share/man/man4/uslcom.4 | 64 | ||||
-rw-r--r-- | sys/arch/amd64/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/arch/i386/conf/GENERIC | 4 | ||||
-rw-r--r-- | sys/dev/usb/files.usb | 7 | ||||
-rw-r--r-- | sys/dev/usb/uslcom.c | 411 |
7 files changed, 493 insertions, 7 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 52a073553ab..16b2b4060eb 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.354 2006/04/26 15:59:26 jason Exp $ +# $OpenBSD: Makefile,v 1.355 2006/04/29 02:15:06 jsg Exp $ MAN= aac.4 ac97.4 acphy.4 acpi.4 acpihpet.4 acpitimer.4 \ adc.4 addcom.4 admcts.4 admlc.4 admtemp.4 \ @@ -42,8 +42,8 @@ MAN= aac.4 ac97.4 acphy.4 acpi.4 acpihpet.4 acpitimer.4 \ udcf.4 udp.4 udsbr.4 \ ueagle.4 uftdi.4 ugen.4 uhci.4 uhid.4 uhidev.4 uipaq.4 uk.4 ukbd.4 \ ukphy.4 ulpt.4 umass.4 umct.4 umidi.4 umodem.4 ums.4 umsm.4 \ - unix.4 upl.4 uplcom.4 urio.4 url.4 urlphy.4 usb.4 \ - uscanner.4 usscanner.4 uvisor.4 uvscom.4 uyap.4 vga.4 vgafb.4 vge.4 \ + unix.4 upl.4 uplcom.4 urio.4 url.4 urlphy.4 usb.4 uscanner.4 + uslcom.4 usscanner.4 uvisor.4 uvscom.4 uyap.4 vga.4 vgafb.4 vge.4 \ viaenv.4 viapm.4 viasio.4 vic.4 vlan.4 vnd.4 vr.4 watchdog.4 wb.4 \ wbenv.4 wd.4 wdc.4 we.4 wi.4tbl wscons.4 wsdisplay.4 wskbd.4 \ wsmouse.4 wsmux.4 xe.4 xf86.4 xl.4 xmphy.4 yds.4 ym.4 zero.4 diff --git a/share/man/man4/usb.4 b/share/man/man4/usb.4 index 3c9a0314d24..df36a75220b 100644 --- a/share/man/man4/usb.4 +++ b/share/man/man4/usb.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: usb.4,v 1.57 2006/04/20 08:09:31 jmc Exp $ +.\" $OpenBSD: usb.4,v 1.58 2006/04/29 02:15:06 jsg Exp $ .\" $NetBSD: usb.4,v 1.15 1999/07/29 14:20:32 augustss Exp $ .\" .\" Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -173,6 +173,8 @@ Modems. Qualcomm MSM EVDO modems. .It Xr uplcom 4 Prolific PL-2303 serial adapters. +.It Xr uslcom 4 +Silicon Laboratories CP2101/CP2102 serial adapters. .It Xr uvscom 4 SUNTAC Slipper U VS-10U serial adapters. .El diff --git a/share/man/man4/uslcom.4 b/share/man/man4/uslcom.4 new file mode 100644 index 00000000000..efef356d123 --- /dev/null +++ b/share/man/man4/uslcom.4 @@ -0,0 +1,64 @@ +.\" $OpenBSD: uslcom.4,v 1.1 2006/04/29 02:15:06 jsg Exp $ +.\" +.\" Copyright (c) 2006 Jonathan Gray <jsg@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. +.\" +.Dd April 29, 2006 +.Dt USLCOM 4 +.Os +.Sh NAME +.Nm uslcom +.Nd Silicon Laboratories CP2101/CP2102 based serial adapters driver +.Sh SYNOPSIS +.Cd "uslcom* at uhub?" +.Cd "ucom* at uslcom?" +.Sh DESCRIPTION +The +.Nm +driver supports Silicon Laboratories CP2101/CP2102 based serial adapters. +.Pp +The following devices should work with the +.Nm +driver: +.Bd -literal -offset indent +Burnside Telecom Desktop Mobile +chip45.com Crumb128 module +Jablotron PC-60B +Pololu USB to Serial +Silicon Laboratories CP2101 +Silicon Laboratories CP2102 +.Ed +.Pp +.Sh SEE ALSO +.Xr tty 4 , +.Xr ucom 4 , +.Xr uhub 4 , +.Xr usb 4 , +.Sh HISTORY +The +.Nm +device driver first appeared in +.Ox 4.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Jonathan Gray +.Aq jsg@openbsd.org . +.Sh CAVEATS +Setting hardware flow control is not currently supported. +.Pp +Silicon Laboratories don't release any programming information +on their products. diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index d6dacc6e921..5a384319bd7 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.122 2006/03/30 21:12:50 wilfried Exp $ +# $OpenBSD: GENERIC,v 1.123 2006/04/29 02:15:06 jsg Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -147,6 +147,8 @@ uplcom* at uhub? # I/O DATA USB-RSAQ2 serial adapter ucom* at uplcom? umct* at uhub? # MCT USB-RS232 serial adapter ucom* at umct? +uslcom* at uhub? # Silicon Laboratories CP210x serial +ucom* at uslcom? uipaq* at uhub? # iPAQ serial adapter ucom* at uipaq? umsm* at uhub? # Qualcomm MSM EVDO diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 9a2401c3c0b..c29e733965e 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.485 2006/04/25 16:27:46 deraadt Exp $ +# $OpenBSD: GENERIC,v 1.486 2006/04/29 02:15:06 jsg Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -195,6 +195,8 @@ uplcom* at uhub? # I/O DATA USB-RSAQ2 serial adapter ucom* at uplcom? umct* at uhub? # MCT USB-RS232 serial adapter ucom* at umct? +uslcom* at uhub? # Silicon Laboratories CP210x serial +ucom* at uslcom? uipaq* at uhub? # iPAQ serial adapter ucom* at uipaq? umsm* at uhub? # Qualcomm MSM EVDO diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 9102a1a11ab..2391dce449c 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $OpenBSD: files.usb,v 1.56 2006/04/24 02:35:26 deraadt Exp $ +# $OpenBSD: files.usb,v 1.57 2006/04/29 02:15:06 jsg Exp $ # $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $ # # Config file and device description for machine-independent USB code. @@ -196,6 +196,11 @@ device ubsa: ucombus attach ubsa at uhub file dev/usb/ubsa.c ubsa +# Silicon Laboratories CP210x serial +device uslcom: ucombus +attach uslcom at uhub +file dev/usb/uslcom.c uslcom + # iPAQ PDAs # Generic ipaq support device uipaq: ucombus diff --git a/sys/dev/usb/uslcom.c b/sys/dev/usb/uslcom.c new file mode 100644 index 00000000000..c7e65679db6 --- /dev/null +++ b/sys/dev/usb/uslcom.c @@ -0,0 +1,411 @@ +/* $OpenBSD: uslcom.c,v 1.1 2006/04/29 02:15:06 jsg Exp $ */ + +/* + * Copyright (c) 2006 Jonathan Gray <jsg@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/conf.h> +#include <sys/tty.h> +#include <sys/device.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/usbdevs.h> + +#include <dev/usb/usbdevs.h> +#include <dev/usb/ucomvar.h> + +#ifdef USLCOM_DEBUG +#define DPRINTFN(n, x) do { if (uslcomdebug > (n)) logprintf x; } while (0) +int uslcomdebug = 0; +#else +#define DPRINTFN(n, x) +#endif +#define DPRINTF(x) DPRINTFN(0, x) + +#define USLCOMBUFSZ 256 +#define USLCOM_CONFIG_NO 0 +#define USLCOM_IFACE_NO 0 + +#define USLCOM_SET_DATA_BITS(x) (x << 8) + +#define USLCOM_WRITE 0x41 +#define USLCOM_READ 0xc1 + +#define USLCOM_UART 0x00 +#define USLCOM_BAUD_RATE 0x01 +#define USLCOM_DATA 0x03 +#define USLCOM_BREAK 0x05 +#define USLCOM_CTRL 0x07 + +#define USLCOM_UART_DISABLE 0x00 +#define USLCOM_UART_ENABLE 0x01 + +#define USLCOM_CTRL_DTR_ON 0x0001 +#define USLCOM_CTRL_DTR_SET 0x0100 +#define USLCOM_CTRL_RTS_ON 0x0002 +#define USLCOM_CTRL_RTS_SET 0x0200 +#define USLCOM_CTRL_CTS 0x0010 +#define USLCOM_CTRL_DSR 0x0020 +#define USLCOM_CTRL_DCD 0x0080 + + +#define USLCOM_BAUD_REF 0x384000 + +#define USLCOM_STOP_BITS_1 0x00 +#define USLCOM_STOP_BITS_2 0x02 + +#define USLCOM_PARITY_NONE 0x00 +#define USLCOM_PARITY_ODD 0x10 +#define USLCOM_PARITY_EVEN 0x20 + +#define USLCOM_BREAK_OFF 0x00 +#define USLCOM_BREAK_ON 0x01 + + +struct uslcom_softc { + USBBASEDEVICE sc_dev; + usbd_device_handle sc_udev; + usbd_interface_handle sc_iface; + device_ptr_t sc_subdev; + + u_char sc_msr; + u_char sc_lsr; + + u_char sc_dying; +}; + +Static void uslcom_get_status(void *, int portno, u_char *lsr, u_char *msr); +Static void uslcom_set(void *, int, int, int); +Static int uslcom_param(void *, int, struct termios *); +Static int uslcom_open(void *sc, int portno); +Static void uslcom_break(void *sc, int portno, int onoff); + +struct ucom_methods uslcom_methods = { + uslcom_get_status, + uslcom_set, + uslcom_param, + NULL, + uslcom_open, + NULL, + NULL, + NULL, +}; + +static const struct usb_devno uslcom_devs[] = { + { USB_VENDOR_DYNASTREAM, USB_PRODUCT_DYNASTREAM_ANTDEVBOARD }, + { USB_VENDOR_JABLOTRON, USB_PRODUCT_JABLOTRON_PC60B }, + { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CRUMB128 }, + { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DEGREECONT }, + { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DESKTOPMOBILE }, + { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_IPLINK1220 }, + { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_POLOLU }, + { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP210X }, + { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_SUNNTO }, + { USB_VENDOR_SILABS2, USB_PRODUCT_SILABS2_DCU11CLONE }, + { USB_VENDOR_USI, USB_PRODUCT_USI_MC60 } +}; + +USB_DECLARE_DRIVER(uslcom); + +USB_MATCH(uslcom) +{ + USB_MATCH_START(uslcom, uaa); + + if (uaa->iface != NULL) + return UMATCH_NONE; + + return (usb_lookup(uslcom_devs, uaa->vendor, uaa->product) != NULL) ? + UMATCH_VENDOR_PRODUCT : UMATCH_NONE; +} + +USB_ATTACH(uslcom) +{ + USB_ATTACH_START(uslcom, sc, uaa); + struct ucom_attach_args uca; + usb_interface_descriptor_t *id; + usb_endpoint_descriptor_t *ed; + usbd_status error; + char *devinfop; + int i; + + bzero(&uca, sizeof(uca)); + sc->sc_udev = uaa->device; + devinfop = usbd_devinfo_alloc(uaa->device, 0); + USB_ATTACH_SETUP; + printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop); + usbd_devinfo_free(devinfop); + + if (usbd_set_config_index(sc->sc_udev, USLCOM_CONFIG_NO, 1) != 0) { + printf("%s: could not set configuration no\n", + USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + /* get the first interface handle */ + error = usbd_device2interface_handle(sc->sc_udev, USLCOM_IFACE_NO, + &sc->sc_iface); + if (error != 0) { + printf("%s: could not get interface handle\n", + USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + id = usbd_get_interface_descriptor(sc->sc_iface); + + uca.bulkin = uca.bulkout = -1; + for (i = 0; i < id->bNumEndpoints; i++) { + ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); + if (ed == NULL) { + printf("%s: no endpoint descriptor found for %d\n", + USBDEVNAME(sc->sc_dev), i); + sc->sc_dying = 1; + USB_ATTACH_ERROR_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", USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + uca.ibufsize = USLCOMBUFSZ; + uca.obufsize = USLCOMBUFSZ; + uca.ibufsizepad = USLCOMBUFSZ; + uca.opkthdrlen = 0; + uca.device = sc->sc_udev; + uca.iface = sc->sc_iface; + uca.methods = &uslcom_methods; + uca.arg = sc; + uca.info = NULL; + + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); + + USB_ATTACH_SUCCESS_RETURN; +} + +USB_DETACH(uslcom) +{ + USB_DETACH_START(uslcom, sc); + int rv = 0; + + sc->sc_dying = 1; + if (sc->sc_subdev != NULL) { + rv = config_detach(sc->sc_subdev, flags); + sc->sc_subdev = NULL; + } + + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + return (rv); +} + +int +uslcom_activate(device_ptr_t self, enum devact act) +{ + struct uslcom_softc *sc = (struct uslcom_softc *)self; + int rv = 0; + + switch (act) { + case DVACT_ACTIVATE: + return (EOPNOTSUPP); + + case DVACT_DEACTIVATE: + if (sc->sc_subdev != NULL) + rv = config_deactivate(sc->sc_subdev); + sc->sc_dying = 1; + break; + } + return (rv); +} + +Static int +uslcom_open(void *vsc, int portno) +{ + struct uslcom_softc *sc = vsc; + usb_device_request_t req; + usbd_status err; + + if (sc->sc_dying) + return (EIO); + + req.bmRequestType = USLCOM_WRITE; + req.bRequest = USLCOM_UART; + USETW(req.wValue, USLCOM_UART_ENABLE); + USETW(req.wIndex, portno); + USETW(req.wLength, 0); + err = usbd_do_request(sc->sc_udev, &req, NULL); + if (err) + return (EIO); + + return (0); +} + +Static void +uslcom_set(void *vsc, int portno, int reg, int onoff) +{ + struct uslcom_softc *sc = vsc; + usb_device_request_t req; + int ctl; + + switch (reg) { + case UCOM_SET_DTR: + ctl = onoff ? USLCOM_CTRL_DTR_ON : 0; + ctl |= USLCOM_CTRL_DTR_SET; + break; + case UCOM_SET_RTS: + ctl = onoff ? USLCOM_CTRL_RTS_ON : 0; + ctl |= USLCOM_CTRL_RTS_SET; + break; + case UCOM_SET_BREAK: + uslcom_break(sc, portno, onoff); + return; + default: + return; + } + req.bmRequestType = USLCOM_WRITE; + req.bRequest = USLCOM_CTRL; + USETW(req.wValue, ctl); + USETW(req.wIndex, portno); + USETW(req.wLength, 0); + usbd_do_request(sc->sc_udev, &req, NULL); +} + +Static int +uslcom_param(void *vsc, int portno, struct termios *t) +{ + struct uslcom_softc *sc = (struct uslcom_softc *)vsc; + usbd_status err; + usb_device_request_t req; + int data; + + switch (t->c_ospeed) { + case 600: + case 1200: + case 1800: + case 2400: + case 4800: + case 9600: + case 19200: + case 38400: + case 57600: + case 115200: + case 460800: + case 921600: + req.bmRequestType = USLCOM_WRITE; + req.bRequest = USLCOM_BAUD_RATE; + USETW(req.wValue, USLCOM_BAUD_REF / t->c_ospeed); + USETW(req.wIndex, portno); + USETW(req.wLength, 0); + err = usbd_do_request(sc->sc_udev, &req, NULL); + if (err) + return (EIO); + break; + default: + return (EINVAL); + } + + if (ISSET(t->c_cflag, CSTOPB)) + data = USLCOM_STOP_BITS_2; + else + data = USLCOM_STOP_BITS_1; + if (ISSET(t->c_cflag, PARENB)) { + if (ISSET(t->c_cflag, PARODD)) + data |= USLCOM_PARITY_ODD; + else + data |= USLCOM_PARITY_EVEN; + } else + data |= USLCOM_PARITY_NONE; + switch (ISSET(t->c_cflag, CSIZE)) { + case CS5: + data |= USLCOM_SET_DATA_BITS(5); + break; + case CS6: + data |= USLCOM_SET_DATA_BITS(6); + break; + case CS7: + data |= USLCOM_SET_DATA_BITS(7); + break; + case CS8: + data |= USLCOM_SET_DATA_BITS(8); + break; + } + + req.bmRequestType = USLCOM_WRITE; + req.bRequest = USLCOM_DATA; + USETW(req.wValue, data); + USETW(req.wIndex, portno); + USETW(req.wLength, 0); + err = usbd_do_request(sc->sc_udev, &req, NULL); + if (err) + return (EIO); + +#if 0 + /* XXX flow control */ + if (ISSET(t->c_cflag, CRTSCTS)) + /* rts/cts flow ctl */ + } else if (ISSET(t->c_iflag, IXON|IXOFF)) { + /* xon/xoff flow ctl */ + } else { + /* disable flow ctl */ + } +#endif + + return (0); +} + +void +uslcom_get_status(void *vsc, int portno, u_char *lsr, u_char *msr) +{ + struct uslcom_softc *sc = vsc; + + if (msr != NULL) + *msr = sc->sc_msr; + if (lsr != NULL) + *lsr = sc->sc_lsr; +} + +void +uslcom_break(void *vsc, int portno, int onoff) +{ + struct uslcom_softc *sc = vsc; + usb_device_request_t req; + int brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF; + + req.bmRequestType = USLCOM_WRITE; + req.bRequest = USLCOM_BREAK; + USETW(req.wValue, brk); + USETW(req.wIndex, portno); + USETW(req.wLength, 0); + usbd_do_request(sc->sc_udev, &req, NULL); +} |