Add uslcom(4) driver which provides support for USB devices based on
authorHasso Tepper <hasso@dragonflybsd.org>
Tue, 14 Aug 2007 08:53:59 +0000 (08:53 +0000)
committerHasso Tepper <hasso@dragonflybsd.org>
Tue, 14 Aug 2007 08:53:59 +0000 (08:53 +0000)
Silicon Laboratories CP120x USB-UART bridges.

Obtained-from: OpenBSD

share/man/man4/Makefile
share/man/man4/uslcom.4 [new file with mode: 0644]
sys/bus/usb/usbdevs.h
sys/bus/usb/usbdevs_data.h
sys/conf/files
sys/dev/usbmisc/Makefile
sys/dev/usbmisc/uslcom/Makefile [new file with mode: 0644]
sys/dev/usbmisc/uslcom/uslcom.c [new file with mode: 0644]

index 7e81dbd..fadb749 100644 (file)
@@ -1,6 +1,6 @@
 #      @(#)Makefile    8.1 (Berkeley) 6/18/93
 # $FreeBSD: src/share/man/man4/Makefile,v 1.83.2.66 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/share/man/man4/Makefile,v 1.58 2007/06/24 10:47:48 swildner Exp $
+# $DragonFly: src/share/man/man4/Makefile,v 1.59 2007/08/14 08:53:58 hasso Exp $
 
 MAN=   aac.4 \
        acpi.4 \
@@ -282,6 +282,7 @@ MAN=        aac.4 \
        urio.4 \
        usb.4 \
        uscanner.4 \
+       uslcom.4 \
        uvisor.4 \
        uvscom.4 \
        vga.4 \
diff --git a/share/man/man4/uslcom.4 b/share/man/man4/uslcom.4
new file mode 100644 (file)
index 0000000..78402de
--- /dev/null
@@ -0,0 +1,82 @@
+.\"    $DragonFly: src/share/man/man4/uslcom.4,v 1.1 2007/08/14 08:53:58 hasso Exp $
+.\"    $OpenBSD: uslcom.4,v 1.4 2007/02/17 01:47:47 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 $Mdocdate$
+.Dt USLCOM 4
+.Os
+.Sh NAME
+.Nm uslcom
+.Nd Silicon Laboratories CP2101/CP2102 based USB serial adapter
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device uslcom"
+.Cd "device ucom"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+uslcom_load="YES"
+.Ed
+.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
+Argussoft ISP
+Baltech card reader
+Burnside Telecom Desktop Mobile
+chip45.com Crumb128 module
+Jablotron PC-60B
+Lipowsky Baby-JTAG
+Lipowsky Baby-LIN
+Lipowsky HARP-1
+Pololu USB to Serial
+Silicon Laboratories CP2101
+Silicon Laboratories CP2102
+.Ed
+.Sh SEE ALSO
+.Xr tty 4 ,
+.Xr ucom 4 ,
+.Xr usb 4
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Ox 4.0
+and was imported into
+.Dx 1.11 .
+.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.
index 3c43590..e495d98 100644 (file)
@@ -1,10 +1,10 @@
-/*     $DragonFly: src/sys/bus/usb/Attic/usbdevs.h,v 1.19 2007/08/02 11:53:30 hasso Exp $      */
+/*     $DragonFly: src/sys/bus/usb/Attic/usbdevs.h,v 1.20 2007/08/14 08:53:58 hasso Exp $      */
 
 /*
  * THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT.
  *
  * generated from:
- *     DragonFly: src/sys/bus/usb/usbdevs,v 1.24 2007/08/02 11:37:24 hasso Exp 
+ *     DragonFly: src/sys/bus/usb/usbdevs,v 1.25 2007/08/14 08:42:34 hasso Exp 
  */
 /* $FreeBSD: src/sys/dev/usb/usbdevs,v 1.203 2004/09/20 04:56:13 sanpei Exp $ */
 /* $NetBSD: usbdevs,v 1.387 2004/10/27 07:02:47 augustss Exp $ */
 /* Avision products */
 #define        USB_PRODUCT_AVISION_1200U       0x0268          /* 1200U scanner */
 
+/* Baltech products */
+#define        USB_PRODUCT_BALTECH_CARDREADER  0x9999          /* Card reader */
+
 /* B&B Electronics products */
 #define        USB_PRODUCT_BBELECTRONICS_USOTL4        0xAC01          /* uLinks Isolated RS-422/485 to USB adapter */
 
 #define        USB_PRODUCT_DLINK2_DWLG122C1    0x3c03          /* DWL-G122 rev C1 */
 #define        USB_PRODUCT_DLINK2_WUA1340      0x3c04          /* WUA-1340 */
 
+/* Dynastream Innovations */
+#define        USB_PRODUCT_DYNASTREAM_ANTDEVBOARD      0x1003          /* ANT dev board */
+
 /* eGalax Products */
 #define        USB_PRODUCT_EGALAX_TPANEL       0x0001          /* Touch Panel */
 #define        USB_PRODUCT_EGALAX_TPANEL2      0x0002          /* Touch Panel */
 /* Ituner networks products */
 #define        USB_PRODUCT_ITUNERNET_USBLCD2X20        0x0002          /* USB-LCD 2x20 */
 
+/* Jablotron products */
+#define        USB_PRODUCT_JABLOTRON_PC60B     0x0001          /* PC-60B */
+
 /* Jaton products */
 #define        USB_PRODUCT_JATON_EDA   0x5704          /* Ethernet Device Adapter */
 
 #define        USB_PRODUCT_SIIG2_USBTOETHER    0x0109          /* USB TO Ethernet */
 #define        USB_PRODUCT_SIIG2_US2308        0x0421          /* Serial */
 
+/* Silicon Labs products */
+#define        USB_PRODUCT_SILABS_POLOLU       0x803b          /* Pololu Serial */
+#define        USB_PRODUCT_SILABS_ARGUSISP     0x8066          /* Argussoft ISP */
+#define        USB_PRODUCT_SILABS_CRUMB128     0x807a          /* Crumb128 */
+#define        USB_PRODUCT_SILABS_DEGREECONT   0x80ca          /* Degree Controls */
+#define        USB_PRODUCT_SILABS_SUNNTO       0x80f6          /* Suunto sports */
+#define        USB_PRODUCT_SILABS_DESKTOPMOBILE        0x813d          /* Burnside Desktop mobile */
+#define        USB_PRODUCT_SILABS_IPLINK1220   0x815e          /* IP-Link 1220 */
+#define        USB_PRODUCT_SILABS_LIPOWSKY_JTAG        0x81c8          /* Lipowsky Baby-JTAG */
+#define        USB_PRODUCT_SILABS_LIPOWSKY_LIN 0x81e2          /* Lipowsky Baby-LIN */
+#define        USB_PRODUCT_SILABS_LIPOWSKY_HARP        0x8218          /* Lipowsky HARP-1 */
+#define        USB_PRODUCT_SILABS_CP210X_1     0xea60          /* CP210x Serial */
+#define        USB_PRODUCT_SILABS_CP210X_2     0xea61          /* CP210x Serial */
+
+#define        USB_PRODUCT_SILABS2_DCU11CLONE  0xaa26          /* DCU-11 clone */
+
 /* Silicom products */
 #define        USB_PRODUCT_SILICOM_U2E 0x0001          /* U2E */
 #define        USB_PRODUCT_SILICOM_GPE 0x0002          /* Psion Gold Port Ethernet */
 /* Universal Access products */
 #define        USB_PRODUCT_UNIACCESS_PANACHE   0x0101          /* Panache Surf USB ISDN Adapter */
 
+/* USI products */
+#define        USB_PRODUCT_USI_MC60    0x10c5          /* MC60 Serial */
+
 /* U.S. Robotics products */
 #define        USB_PRODUCT_USR_USR1120 0x00eb          /* USR1120 WLAN */
 
index e0bdff4..c42b5e4 100644 (file)
@@ -1,10 +1,10 @@
-/*     $DragonFly: src/sys/bus/usb/Attic/usbdevs_data.h,v 1.19 2007/08/02 11:53:30 hasso Exp $ */
+/*     $DragonFly: src/sys/bus/usb/Attic/usbdevs_data.h,v 1.20 2007/08/14 08:53:58 hasso Exp $ */
 
 /*
  * THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT.
  *
  * generated from:
- *     DragonFly: src/sys/bus/usb/usbdevs,v 1.24 2007/08/02 11:37:24 hasso Exp 
+ *     DragonFly: src/sys/bus/usb/usbdevs,v 1.25 2007/08/14 08:42:34 hasso Exp 
  */
 /* $FreeBSD: src/sys/dev/usb/usbdevs,v 1.203 2004/09/20 04:56:13 sanpei Exp $ */
 /* $NetBSD: usbdevs,v 1.387 2004/10/27 07:02:47 augustss Exp $ */
@@ -1007,6 +1007,12 @@ const struct usb_knowndev usb_knowndevs[] = {
            "Avision",
            "1200U scanner",
        },
+       {
+           USB_VENDOR_BALTECH, USB_PRODUCT_BALTECH_CARDREADER,
+           0,
+           "Baltech",
+           "Card reader",
+       },
        {
            USB_VENDOR_BBELECTRONICS, USB_PRODUCT_BBELECTRONICS_USOTL4,
            0,
@@ -2015,6 +2021,12 @@ const struct usb_knowndev usb_knowndevs[] = {
            "D-Link",
            "WUA-1340",
        },
+       {
+           USB_VENDOR_DYNASTREAM, USB_PRODUCT_DYNASTREAM_ANTDEVBOARD,
+           0,
+           "Dynastream Innovations",
+           "ANT dev board",
+       },
        {
            USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL,
            0,
@@ -3545,6 +3557,12 @@ const struct usb_knowndev usb_knowndevs[] = {
            "I-Tuner Networks",
            "USB-LCD 2x20",
        },
+       {
+           USB_VENDOR_JABLOTRON, USB_PRODUCT_JABLOTRON_PC60B,
+           0,
+           "Jablotron",
+           "PC-60B",
+       },
        {
            USB_VENDOR_JATON, USB_PRODUCT_JATON_EDA,
            0,
@@ -6605,6 +6623,84 @@ const struct usb_knowndev usb_knowndevs[] = {
            "SIIG",
            "Serial",
        },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_POLOLU,
+           0,
+           "Silicon Labs",
+           "Pololu Serial",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_ARGUSISP,
+           0,
+           "Silicon Labs",
+           "Argussoft ISP",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CRUMB128,
+           0,
+           "Silicon Labs",
+           "Crumb128",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DEGREECONT,
+           0,
+           "Silicon Labs",
+           "Degree Controls",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_SUNNTO,
+           0,
+           "Silicon Labs",
+           "Suunto sports",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_DESKTOPMOBILE,
+           0,
+           "Silicon Labs",
+           "Burnside Desktop mobile",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_IPLINK1220,
+           0,
+           "Silicon Labs",
+           "IP-Link 1220",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_JTAG,
+           0,
+           "Silicon Labs",
+           "Lipowsky Baby-JTAG",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_LIN,
+           0,
+           "Silicon Labs",
+           "Lipowsky Baby-LIN",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_LIPOWSKY_HARP,
+           0,
+           "Silicon Labs",
+           "Lipowsky HARP-1",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP210X_1,
+           0,
+           "Silicon Labs",
+           "CP210x Serial",
+       },
+       {
+           USB_VENDOR_SILABS, USB_PRODUCT_SILABS_CP210X_2,
+           0,
+           "Silicon Labs",
+           "CP210x Serial",
+       },
+       {
+           USB_VENDOR_SILABS2, USB_PRODUCT_SILABS2_DCU11CLONE,
+           0,
+           "SILABS2",
+           "DCU-11 clone",
+       },
        {
            USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_U2E,
            0,
@@ -7313,6 +7409,12 @@ const struct usb_knowndev usb_knowndevs[] = {
            "Universal Access",
            "Panache Surf USB ISDN Adapter",
        },
+       {
+           USB_VENDOR_USI, USB_PRODUCT_USI_MC60,
+           0,
+           "USI",
+           "MC60 Serial",
+       },
        {
            USB_VENDOR_USR, USB_PRODUCT_USR_USR1120,
            0,
index bd33243..d126b84 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/sys/conf/files,v 1.340.2.137 2003/06/04 17:10:30 sam Exp $
-# $DragonFly: src/sys/conf/files,v 1.169 2007/08/13 17:49:14 dillon Exp $
+# $DragonFly: src/sys/conf/files,v 1.170 2007/08/14 08:53:58 hasso Exp $
 #
 # The long compile-with and dependency lines are required because of
 # limitations in config: backslash-newline doesn't work in strings, and
@@ -1192,6 +1192,7 @@ dev/usbmisc/umct/umct.c           optional umct ucom
 dev/usbmisc/ums/ums.c          optional ums
 dev/usbmisc/uplcom/uplcom.c    optional uplcom ucom
 dev/usbmisc/urio/urio.c                optional urio
+dev/usbmisc/uplcom/uslcom.c    optional uslcom ucom
 dev/usbmisc/ulpt/ulpt.c                optional ulpt
 dev/usbmisc/ukbd/ukbd.c                optional ukbd
 dev/usbmisc/umass/umass.c      optional umass
index a4386a1..811ab31 100644 (file)
@@ -1,7 +1,7 @@
-# $DragonFly: src/sys/dev/usbmisc/Makefile,v 1.2 2006/12/13 20:19:04 dillon Exp $
+# $DragonFly: src/sys/dev/usbmisc/Makefile,v 1.3 2007/08/14 08:53:58 hasso Exp $
 #
 
 SUBDIR= ubsa ucom ufm uftdi ugen uhid ukbd ulpt umass umodem ums \
-       uplcom uscanner uvisor uvscom umct
+       uplcom uscanner uslcom uvisor uvscom umct
 
 .include <bsd.subdir.mk>
diff --git a/sys/dev/usbmisc/uslcom/Makefile b/sys/dev/usbmisc/uslcom/Makefile
new file mode 100644 (file)
index 0000000..550e989
--- /dev/null
@@ -0,0 +1,10 @@
+# $DragonFly: src/sys/dev/usbmisc/uslcom/Makefile,v 1.1 2007/08/14 08:53:59 hasso Exp $
+
+.PATH: ${.CURDIR}/../ucom
+
+KMOD=  uslcom
+SRCS=  uslcom.c
+NOMAN=
+KMODDEPS= ucom
+
+.include <bsd.kmod.mk>
diff --git a/sys/dev/usbmisc/uslcom/uslcom.c b/sys/dev/usbmisc/uslcom/uslcom.c
new file mode 100644 (file)
index 0000000..4be9fc7
--- /dev/null
@@ -0,0 +1,464 @@
+/*     $DragonFly: src/sys/dev/usbmisc/uslcom/uslcom.c,v 1.1 2007/08/14 08:53:59 hasso Exp $   */
+/*     $OpenBSD: uslcom.c,v 1.12 2007/06/13 06:25:03 mbalmer 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 <sys/types.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+
+#include <bus/usb/usb.h>
+#include <bus/usb/usbdi.h>
+#include <bus/usb/usbdi_util.h>
+#include <bus/usb/usbdevs.h>
+
+#include <dev/usbmisc/ucom/ucomvar.h>
+
+#ifdef USLCOM_DEBUG
+#define DPRINTFN(n, x)  do { if (uslcomdebug > (n)) kprintf 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 {
+       struct ucom_softc       sc_ucom;
+       u_char                  sc_msr;
+       u_char                  sc_lsr;
+};
+
+void   uslcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
+void   uslcom_set(void *, int, int, int);
+int    uslcom_param(void *, int, struct termios *);
+int    uslcom_open(void *sc, int portno);
+void   uslcom_close(void *, int);
+void   uslcom_break(void *sc, int portno, int onoff);
+
+struct ucom_callback uslcom_callback = {
+       uslcom_get_status,
+       uslcom_set,
+       uslcom_param,
+       NULL,
+       uslcom_open,
+       uslcom_close,
+       NULL,
+       NULL,
+};
+
+static const struct usb_devno uslcom_devs[] = {
+       { USB_VENDOR_BALTECH,           USB_PRODUCT_BALTECH_CARDREADER },
+       { USB_VENDOR_DYNASTREAM,        USB_PRODUCT_DYNASTREAM_ANTDEVBOARD },
+       { USB_VENDOR_JABLOTRON,         USB_PRODUCT_JABLOTRON_PC60B },
+       { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_ARGUSISP },
+       { 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_LIPOWSKY_HARP },
+       { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_LIPOWSKY_JTAG },
+       { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_LIPOWSKY_LIN },
+       { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_POLOLU },
+       { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_CP210X_1 },
+       { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_CP210X_2 },
+       { USB_VENDOR_SILABS,            USB_PRODUCT_SILABS_SUNNTO },
+       { USB_VENDOR_SILABS2,           USB_PRODUCT_SILABS2_DCU11CLONE },
+       { USB_VENDOR_USI,               USB_PRODUCT_USI_MC60 }
+};
+
+static device_probe_t uslcom_match;
+static device_attach_t uslcom_attach;
+static device_detach_t uslcom_detach;
+
+static device_method_t uslcom_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe, uslcom_match),
+       DEVMETHOD(device_attach, uslcom_attach),
+       DEVMETHOD(device_detach, uslcom_detach),
+       { 0, 0 }
+};
+
+static driver_t uslcom_driver = {
+       "ucom",
+       uslcom_methods,
+       sizeof (struct uslcom_softc)
+};
+
+DRIVER_MODULE(uslcom, uhub, uslcom_driver, ucom_devclass, usbd_driver_load, 0);
+MODULE_DEPEND(uslcom, usb, 1, 1, 1);
+MODULE_DEPEND(uslcom, ucom, UCOM_MINVER, UCOM_PREFVER, UCOM_MAXVER);
+MODULE_VERSION(uslcom, 1);
+
+static int
+uslcom_match(device_t self)
+{
+       struct usb_attach_arg *uaa = device_get_ivars(self);
+
+       if (uaa->iface != NULL)
+               return UMATCH_NONE;
+
+       return (usb_lookup(uslcom_devs, uaa->vendor, uaa->product) != NULL) ?
+           UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
+}
+
+static int
+uslcom_attach(device_t self)
+{
+       struct uslcom_softc *sc = device_get_softc(self);
+       struct usb_attach_arg *uaa = device_get_ivars(self);
+       struct ucom_softc *ucom;
+       usb_interface_descriptor_t *id;
+       usb_endpoint_descriptor_t *ed;
+       usbd_status error;
+       char *devinfo;
+       const char *devname;
+       int i;
+
+       devinfo = kmalloc(1024, M_USBDEV, M_INTWAIT);
+       ucom = &sc->sc_ucom;
+
+       bzero(sc, sizeof (struct uslcom_softc));
+
+       usbd_devinfo(uaa->device, 0, devinfo);
+       ucom->sc_dev = self;
+       device_set_desc_copy(self, devinfo);
+
+       ucom->sc_udev = uaa->device;
+       ucom->sc_iface = uaa->iface;
+
+       devname = device_get_nameunit(ucom->sc_dev);
+       kprintf("%s: %s\n", devname, devinfo);
+       kfree(devinfo, M_USBDEV);
+
+       if (usbd_set_config_index(ucom->sc_udev, USLCOM_CONFIG_NO, 1) != 0) {
+               kprintf("%s: could not set configuration no\n", devname);
+               goto error;
+        }
+
+       /* get the first interface handle */
+       error = usbd_device2interface_handle(ucom->sc_udev, USLCOM_IFACE_NO,
+           &ucom->sc_iface);
+       if (error != 0) {
+               kprintf("%s: could not get interface handle\n", devname);
+               goto error;
+       }
+
+       id = usbd_get_interface_descriptor(ucom->sc_iface);
+
+       ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
+       for (i = 0; i < id->bNumEndpoints; i++) {
+               ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
+               if (ed == NULL) {
+                       kprintf("%s: no endpoint descriptor found for %d\n",
+                           devname, i);
+                       goto error;
+               }
+
+               if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
+                       ucom->sc_bulkin_no = ed->bEndpointAddress;
+               else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
+                       ucom->sc_bulkout_no = ed->bEndpointAddress;
+       }
+
+       if (ucom->sc_bulkin_no == -1 || ucom->sc_bulkout_no == -1) {
+               kprintf("%s: missing endpoint\n", devname);
+               goto error;
+       }
+
+       ucom->sc_parent = sc;
+       ucom->sc_portno = UCOM_UNK_PORTNO;
+       ucom->sc_ibufsize = USLCOMBUFSZ;
+       ucom->sc_obufsize = USLCOMBUFSZ;
+       ucom->sc_ibufsizepad = USLCOMBUFSZ;
+       ucom->sc_opkthdrlen = 0;
+       ucom->sc_callback = &uslcom_callback;
+
+       usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, ucom->sc_udev,
+           ucom->sc_dev);
+
+       DPRINTF(("uslcom: in = 0x%x, out = 0x%x, intr = 0x%x\n",
+                ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));
+
+       ucom_attach(&sc->sc_ucom);
+       return 0;
+
+error:
+        ucom->sc_dying = 1;
+        return ENXIO;
+}
+
+static int
+uslcom_detach(device_t self)
+{
+       struct uslcom_softc *sc = device_get_softc(self);
+       int rv = 0;
+
+       DPRINTF(("uslcom_detach: sc=%p\n", sc));
+       sc->sc_ucom.sc_dying = 1;
+       rv = ucom_detach(&sc->sc_ucom);
+       usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_ucom.sc_udev,
+                          sc->sc_ucom.sc_dev);
+
+       return (rv);
+}
+
+#if 0 /* not yet */
+int
+uslcom_activate(struct device *self, enum devact act)
+{
+       struct uslcom_softc *sc = (struct uslcom_softc *)self;
+       int rv = 0;
+
+       switch (act) {
+       case DVACT_ACTIVATE:
+               break;
+
+       case DVACT_DEACTIVATE:
+               if (sc->sc_subdev != NULL)
+                       rv = config_deactivate(sc->sc_subdev);
+               sc->sc_dying = 1;
+               break;
+       }
+       return (rv);
+}
+#endif
+
+int
+uslcom_open(void *vsc, int portno)
+{
+       struct uslcom_softc *sc = vsc;
+       usb_device_request_t req;
+       usbd_status err;
+
+       if (sc->sc_ucom.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_ucom.sc_udev, &req, NULL);
+       if (err)
+               return (EIO);
+
+       return (0);
+}
+
+void
+uslcom_close(void *vsc, int portno)
+{
+       struct uslcom_softc *sc = vsc;
+       usb_device_request_t req;
+
+       if (sc->sc_ucom.sc_dying)
+               return;
+
+       req.bmRequestType = USLCOM_WRITE;
+       req.bRequest = USLCOM_UART;
+       USETW(req.wValue, USLCOM_UART_DISABLE);
+       USETW(req.wIndex, portno);
+       USETW(req.wLength, 0);
+       usbd_do_request(sc->sc_ucom.sc_udev, &req, NULL);
+}
+
+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_ucom.sc_udev, &req, NULL);
+}
+
+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_ucom.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_ucom.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_ucom.sc_udev, &req, NULL);
+}