Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/usb Add a driver for ArkMicroChips 3116 serial devic...



details:   https://anonhg.NetBSD.org/src/rev/ac8b569fdc05
branches:  trunk
changeset: 755238:ac8b569fdc05
user:      martin <martin%NetBSD.org@localhost>
date:      Sat May 29 17:39:41 2010 +0000

description:
Add a driver for ArkMicroChips 3116 serial devices, used in some Nokia
phone cables and in cheap stand alone usb<->serial devices. From OpenBSD.

The hardware is crap, avoid it if possible. There is no documentation and
even the vendor supllied win32 driver gets it wrong.

This driver mostly works, but you can't send a break.

diffstat:

 sys/dev/usb/files.usb |    7 +-
 sys/dev/usb/uark.c    |  355 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 361 insertions(+), 1 deletions(-)

diffs (truncated from 380 to 300 lines):

diff -r 7fd2de33befe -r ac8b569fdc05 sys/dev/usb/files.usb
--- a/sys/dev/usb/files.usb     Sat May 29 17:33:57 2010 +0000
+++ b/sys/dev/usb/files.usb     Sat May 29 17:39:41 2010 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.usb,v 1.98 2010/05/29 01:14:29 pgoyette Exp $
+#      $NetBSD: files.usb,v 1.99 2010/05/29 17:39:41 martin Exp $
 #
 # Config file and device description for machine-independent USB code.
 # Included by ports that need it.  Ports that use it must provide
@@ -289,6 +289,11 @@
 attach ukyopon at usbifif
 file   dev/usb/ukyopon.c               ukyopon
 
+# ArkMicroChips 3116 based serial (used with some Nokia USB cables too)
+device uark: ucombus
+attach uark at usbdevif
+file   dev/usb/uark.c          uark
+
 # Silicon Labs CP210x serial driver
 device uslsa: ucombus
 attach uslsa at usbdevif
diff -r 7fd2de33befe -r ac8b569fdc05 sys/dev/usb/uark.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/usb/uark.c        Sat May 29 17:39:41 2010 +0000
@@ -0,0 +1,355 @@
+/*     $NetBSD: uark.c,v 1.1 2010/05/29 17:39:41 martin Exp $  */
+/*     $OpenBSD: uark.c,v 1.13 2009/10/13 19:33:17 pirofti Exp $       */
+
+/*
+ * Copyright (c) 2006 Jonathan Gray <jsg%openbsd.org@localhost>
+ *
+ * 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 UARK_DEBUG
+#define DPRINTFN(n, x)  do { if (uarkdebug > (n)) printf x; } while (0)
+int    uarkebug = 0;
+#else
+#define DPRINTFN(n, x)
+#endif
+#define DPRINTF(x) DPRINTFN(0, x)
+
+#define UARKBUFSZ              256
+#define UARK_CONFIG_NO 0
+#define UARK_IFACE_NO          0
+
+#define UARK_SET_DATA_BITS(x)  (x - 5)
+
+#define UARK_PARITY_NONE       0x00
+#define UARK_PARITY_ODD                0x08
+#define UARK_PARITY_EVEN       0x18
+
+#define UARK_STOP_BITS_1       0x00
+#define UARK_STOP_BITS_2       0x04
+
+#define UARK_BAUD_REF          3000000
+
+#define UARK_WRITE             0x40
+#define UARK_READ              0xc0
+
+#define UARK_REQUEST           0xfe
+
+struct uark_softc {
+       struct device           *sc_dev;
+       usbd_device_handle       sc_udev;
+       usbd_interface_handle    sc_iface;
+       struct device           *sc_subdev;
+
+       u_char                   sc_msr;
+       u_char                   sc_lsr;
+
+       u_char                   sc_dying;
+};
+
+void   uark_get_status(void *, int portno, u_char *lsr, u_char *msr);
+void   uark_set(void *, int, int, int);
+int    uark_param(void *, int, struct termios *);
+void   uark_break(void *, int, int);
+int    uark_cmd(struct uark_softc *, uint16_t, uint16_t);
+
+struct ucom_methods uark_methods = {
+       uark_get_status,
+       uark_set,
+       uark_param,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+};
+
+static const struct usb_devno uark_devs[] = {
+       { USB_VENDOR_ARKMICROCHIPS, USB_PRODUCT_ARKMICROCHIPS_USBSERIAL },
+};
+
+USB_DECLARE_DRIVER(uark);
+
+USB_MATCH(uark)
+{
+       USB_MATCH_START(uarkcom, uaa);
+
+       return (usb_lookup(uark_devs, uaa->vendor, uaa->product) != NULL) ?
+           UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
+}
+
+USB_ATTACH(uark)
+{
+       USB_ATTACH_START(uark, sc, uaa);
+       usbd_device_handle dev = uaa->device;
+       char *devinfop;
+       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_dev = self;
+
+       devinfop = usbd_devinfo_alloc(dev, 0);
+       USB_ATTACH_SETUP;
+       aprint_normal_dev(self, "%s\n", devinfop);
+       usbd_devinfo_free(devinfop);
+
+       sc->sc_udev = dev;
+
+       if (usbd_set_config_index(sc->sc_udev, UARK_CONFIG_NO, 1) != 0) {
+               aprint_error_dev(self, "could not set configuration no\n");
+               sc->sc_dying = 1;
+               return;
+       }
+
+       /* get the first interface handle */
+       error = usbd_device2interface_handle(sc->sc_udev, UARK_IFACE_NO,
+           &sc->sc_iface);
+       if (error != 0) {
+               aprint_error_dev(self, "could not get interface handle\n");
+               sc->sc_dying = 1;
+               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) {
+                       aprint_error_dev(self, "no endpoint descriptor found for %d\n",
+                           i);
+                       sc->sc_dying = 1;
+                       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) {
+               aprint_error_dev(self, "missing endpoint\n");
+               sc->sc_dying = 1;
+               return;
+       }
+
+       uca.ibufsize = UARKBUFSZ;
+       uca.obufsize = UARKBUFSZ;
+       uca.ibufsizepad = UARKBUFSZ;
+       uca.opkthdrlen = 0;
+       uca.device = sc->sc_udev;
+       uca.iface = sc->sc_iface;
+       uca.methods = &uark_methods;
+       uca.arg = sc;
+       uca.info = NULL;
+
+       usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
+           sc->sc_dev);
+       
+       sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca,
+                                           ucomprint, ucomsubmatch);
+
+       USB_ATTACH_SUCCESS_RETURN;
+}
+
+int
+uark_detach(struct device *self, int flags)
+{
+       struct uark_softc *sc = device_private(self);
+       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,
+                          sc->sc_dev);
+
+       return rv;
+}
+
+int
+uark_activate(struct device* self, enum devact act)
+{
+       struct uark_softc *sc = device_private(self);
+       int rv = 0;
+
+       switch (act) {
+       case DVACT_DEACTIVATE:
+               if (sc->sc_subdev != NULL)
+                       rv = config_deactivate(sc->sc_subdev);
+               sc->sc_dying = 1;
+               break;
+       }
+       return (rv);
+}
+
+void
+uark_set(void *vsc, int portno, int reg, int onoff)
+{
+       struct uark_softc *sc = vsc;
+
+       switch (reg) {
+       case UCOM_SET_BREAK:
+               uark_break(sc, portno, onoff);
+               return;
+       case UCOM_SET_DTR:
+       case UCOM_SET_RTS:
+       default:
+               return;
+       }
+}
+
+int
+uark_param(void *vsc, int portno, struct termios *t)
+{
+       struct uark_softc *sc = (struct uark_softc *)vsc;
+       int data;
+
+       switch (t->c_ospeed) {
+       case 300:
+       case 600:
+       case 1200:
+       case 1800:
+       case 2400:
+       case 4800:
+       case 9600:
+       case 19200:
+       case 38400:
+       case 57600:
+       case 115200:
+               uark_cmd(sc, 3, 0x83);
+               uark_cmd(sc, 0, (UARK_BAUD_REF / t->c_ospeed) & 0xFF);
+               uark_cmd(sc, 1, (UARK_BAUD_REF / t->c_ospeed) >> 8);
+               uark_cmd(sc, 3, 0x03);
+               break;
+       default:
+               return (EINVAL);
+       }
+
+       if (ISSET(t->c_cflag, CSTOPB))
+               data = UARK_STOP_BITS_2;
+       else
+               data = UARK_STOP_BITS_1;
+
+       if (ISSET(t->c_cflag, PARENB)) {
+               if (ISSET(t->c_cflag, PARODD))
+                       data |= UARK_PARITY_ODD;
+               else
+                       data |= UARK_PARITY_EVEN;
+       } else
+               data |= UARK_PARITY_NONE;



Home | Main Index | Thread Index | Old Index