svn commit: r202181 - in head: share/man/man4 sys/conf sys/dev/usb sys/dev/usb/net sys/modules/usb sys/modules/usb/uhso usr.sbin usr.sbin/uhsoctl

Andrew Thompson thompsa at FreeBSD.org
Wed Jan 13 03:16:31 UTC 2010


Author: thompsa
Date: Wed Jan 13 03:16:31 2010
New Revision: 202181
URL: http://svn.freebsd.org/changeset/base/202181

Log:
  Add a driver by Fredrik Lindberg for Option HSDPA USB devices. These differ
  from standard 3G wireless units by supplying a raw IP/IPv6 endpoint rather than
  using PPP over serial. uhsoctl(1) is used to initiate and close the WAN
  connection.
  
  Obtained from:	Fredrik Lindberg <fli at shapeshifter.se>

Added:
  head/share/man/man4/uhso.4   (contents, props changed)
  head/sys/dev/usb/net/uhso.c   (contents, props changed)
  head/sys/modules/usb/uhso/
  head/sys/modules/usb/uhso/Makefile   (contents, props changed)
  head/usr.sbin/uhsoctl/
  head/usr.sbin/uhsoctl/Makefile   (contents, props changed)
  head/usr.sbin/uhsoctl/uhsoctl.1   (contents, props changed)
  head/usr.sbin/uhsoctl/uhsoctl.c   (contents, props changed)
Modified:
  head/share/man/man4/Makefile
  head/sys/conf/NOTES
  head/sys/conf/files
  head/sys/dev/usb/usbdevs
  head/sys/modules/usb/Makefile
  head/usr.sbin/Makefile

Modified: head/share/man/man4/Makefile
==============================================================================
--- head/share/man/man4/Makefile	Tue Jan 12 23:33:14 2010	(r202180)
+++ head/share/man/man4/Makefile	Wed Jan 13 03:16:31 2010	(r202181)
@@ -424,6 +424,7 @@ MAN=	aac.4 \
 	ugen.4 \
 	uhci.4 \
 	uhid.4 \
+	uhso.4 \
 	uipaq.4 \
 	ukbd.4 \
 	ulpt.4 \

Added: head/share/man/man4/uhso.4
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/share/man/man4/uhso.4	Wed Jan 13 03:16:31 2010	(r202181)
@@ -0,0 +1,115 @@
+.\" Copyright (c) 2009 Fredrik Lindberg
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd Aug 12, 2009
+.Os
+.Dt UHSO 4
+.Sh NAME
+.Nm hso
+.Nd support for several HSxPA devices from Option N.V.
+.Sh SYNOPSIS
+The module can be loaded at boot time by placing the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+uhso_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for several HSxPA devices from Option N.V. that are
+based on their packet interface.
+Each device has a set of serial ports and a raw IP packet interface.
+The serial ports of the device are accessed through the
+.Xr ucom 4
+driver which makes them behave like a
+.Xr tty 4 .
+The packet interface is exposed as a network interface.
+.Pp
+To establish a connection on the packet interface the use of the proprietary
+AT commands
+.Dq Li AT_OWANCALL
+and
+.Dq Li AT_OWANDATA
+are required on any of the serial ports.
+.Pp
+The network interface must be configured manually using the data obtain from
+these calls.
+.Pp
+Each device usually have at least two or more serial ports, their individual purpose
+can be identified through
+.Xr sysctl 8 .
+.Sh HARDWARE
+The
+.Nm
+driver supports at least the following cards
+.Pp
+.Bl -bullet -compact
+.It
+Option GlobeSurfer iCON 7.2 (new firmware)
+.It
+Option iCON 225
+.El
+.Pp
+The device features a mass storage device referred to as
+.Dq Zero-CD
+which contains drivers for Microsoft Windows.
+The driver automatically switches the device to modem mode.
+.Sh EXAMPLES
+Establishing a packet interface connection
+.Bd -literal -offset indent
+AT+CGDCONT=1,,"apn.provider"
+AT_OWANCALL=1,1,1
+OK
+_OWANCALL=1,1
+
+AT_OWANDATA=1
+_OWANDATA: 1, 10.11.12.13, 0.0.0.0, 10.2.3.4, 10.2.3.5, \e
+	0.0.0.0, 0.0.0.0, 72000
+.Ed
+.Pp
+Configuring the interface
+.Bd -literal -offset indent
+ifconfig uhso0 10.11.12.13 up
+route add default -interface uhso0
+echo "nameserver 10.2.3.4" > /etc/resolv.conf
+echo "nameserver 10.2.3.5" >> /etc/resolv.conf
+.Ed
+.Pp
+The connection can be terminated with
+.Bd -literal -offset indent
+AT_OWANCALL=1,0,1
+.Ed
+.Sh FILES
+.Bl -tag -width "XXXXXX"
+.It Pa /dev/cuaU?.?
+.El
+.Sh SEE ALSO
+.Xr ucom 4 ,
+.Xr usb 4
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Fredrik Lindberg Aq fli at shapeshifter.se .

Modified: head/sys/conf/NOTES
==============================================================================
--- head/sys/conf/NOTES	Tue Jan 12 23:33:14 2010	(r202180)
+++ head/sys/conf/NOTES	Wed Jan 13 03:16:31 2010	(r202181)
@@ -2652,6 +2652,9 @@ device		rue
 #
 # Davicom DM9601E USB to fast ethernet. Supports the Corega FEther USB-TXC.
 device		udav
+#
+# HSxPA devices from Option N.V
+device		uhso
 
 #
 # Ralink Technology RT2501USB/RT2601USB wireless driver

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue Jan 12 23:33:14 2010	(r202180)
+++ head/sys/conf/files	Wed Jan 13 03:16:31 2010	(r202181)
@@ -1676,7 +1676,7 @@ dev/usb/usb_request.c		optional usb
 dev/usb/usb_transfer.c		optional usb
 dev/usb/usb_util.c		optional usb
 #
-# USB ethernet drivers
+# USB network drivers
 #
 dev/usb/net/if_aue.c		optional aue
 dev/usb/net/if_axe.c		optional axe
@@ -1687,6 +1687,7 @@ dev/usb/net/if_rue.c		optional rue
 dev/usb/net/if_udav.c		optional udav
 dev/usb/net/usb_ethernet.c	optional aue | axe | cdce | cue | kue | rue | \
 					 udav
+dev/usb/net/uhso.c		optional uhso
 #
 # USB WLAN drivers
 #

Added: head/sys/dev/usb/net/uhso.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/usb/net/uhso.c	Wed Jan 13 03:16:31 2010	(r202181)
@@ -0,0 +1,1754 @@
+/*-
+ * Copyright (c) 2009 Fredrik Lindberg
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/tty.h>
+#include <sys/sysctl.h>
+#include <sys/condvar.h>
+#include <sys/sx.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/bpf.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usb_cdc.h>
+#include "usbdevs.h"
+#define USB_DEBUG_VAR uhso_debug
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_device.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/serial/usb_serial.h>
+#include <dev/usb/usb_msctest.h>
+
+struct uhso_tty {
+	struct uhso_softc *ht_sc;
+	struct usb_xfer	*ht_xfer[3];
+	int		ht_muxport;
+	int		ht_open;
+	char		ht_name[32];
+};
+
+struct uhso_softc {
+	device_t		sc_dev;
+	struct usb_device	*sc_udev;
+	struct mtx		sc_mtx;
+	uint32_t		sc_type;
+
+	struct usb_xfer		*sc_xfer[3];
+	uint8_t			sc_iface_no;
+	uint8_t			sc_iface_index;
+
+	/* Control pipe */
+	struct usb_xfer	*	sc_ctrl_xfer[2];
+	uint8_t			sc_ctrl_iface_no;
+
+	/* Network */
+	struct usb_xfer		*sc_if_xfer[2];
+	struct ifnet		*sc_ifp;
+	struct mbuf		*sc_mwait;	/* partial packet */
+	size_t			sc_waitlen;	/* no. of outstanding bytes */
+	struct ifqueue		sc_rxq;
+	struct callout		sc_c;
+
+	/* TTY related structures */
+	struct ucom_super_softc sc_super_ucom;
+	int 			sc_ttys;
+	struct uhso_tty		*sc_tty;
+	struct ucom_softc	*sc_ucom;
+	int			sc_msr;
+	int			sc_lsr;
+	int			sc_line;
+};
+
+
+#define UHSO_MAX_MTU		2048
+
+/*
+ * There are mainly two type of cards floating around.
+ * The first one has 2,3 or 4 interfaces with a multiplexed serial port
+ * and packet interface on the first interface and bulk serial ports
+ * on the others.
+ * The second type of card has several other interfaces, their purpose
+ * can be detected during run-time.
+ */
+#define UHSO_IFACE_SPEC(usb_type, port, port_type) \
+	(((usb_type) << 24) | ((port) << 16) | (port_type))
+
+#define UHSO_IFACE_USB_TYPE(x) ((x >> 24) & 0xff)
+#define UHSO_IFACE_PORT(x) ((x >> 16) & 0xff)
+#define UHSO_IFACE_PORT_TYPE(x) (x & 0xff)
+
+/*
+ * USB interface types
+ */
+#define UHSO_IF_NET		0x01	/* Network packet interface */
+#define UHSO_IF_MUX		0x02	/* Multiplexed serial port */
+#define UHSO_IF_BULK		0x04	/* Bulk interface */
+
+/*
+ * Port types
+ */
+#define UHSO_PORT_UNKNOWN	0x00
+#define UHSO_PORT_SERIAL		0x01	/* Serial port */
+#define UHSO_PORT_NETWORK	0x02	/* Network packet interface */
+
+/*
+ * Multiplexed serial port destination sub-port names
+ */
+#define UHSO_MPORT_TYPE_CTL	0x00	/* Control port */
+#define UHSO_MPORT_TYPE_APP	0x01	/* Application */
+#define UHSO_MPORT_TYPE_PCSC	0x02
+#define UHSO_MPORT_TYPE_GPS	0x03
+#define UHSO_MPORT_TYPE_APP2	0x04
+#define UHSO_MPORT_TYPE_MAX	UHSO_MPORT_TYPE_APP2
+#define UHSO_MPORT_TYPE_NOMAX	8	/* Max number of mux ports */
+
+/*
+ * Port definitions
+ */
+#define UHSO_PORT_TYPE_CTL	0x01
+#define UHSO_PORT_TYPE_APP	0x02
+#define UHSO_PORT_TYPE_APP2	0x03
+#define UHSO_PORT_TYPE_MODEM	0x04
+#define UHSO_PORT_TYPE_NETWORK	0x05
+#define UHSO_PORT_TYPE_DIAG	0x06
+#define UHSO_PORT_TYPE_DIAG2	0x07
+#define UHSO_PORT_TYPE_GPS	0x08
+#define UHSO_PORT_TYPE_GPSCTL	0x09
+#define UHSO_PORT_TYPE_PCSC	0x0a
+#define UHSO_PORT_TYPE_MSD	0x0b
+#define UHSO_PORT_TYPE_VOICE	0x0c
+#define UHSO_PORT_TYPE_MAX	0x0c
+
+static eventhandler_tag uhso_etag;
+
+/* Overall port type */
+static char *uhso_port[] = {
+	"Unknown",
+	"Serial",
+	"Network",
+	"Network/Serial"
+};
+
+/* Map between interface port type read from device and description type */
+static char uhso_port_map[] = {
+	0,
+	UHSO_PORT_TYPE_DIAG,
+	UHSO_PORT_TYPE_GPS,
+	UHSO_PORT_TYPE_GPSCTL,
+	UHSO_PORT_TYPE_APP,
+	UHSO_PORT_TYPE_APP2,
+	UHSO_PORT_TYPE_CTL,
+	UHSO_PORT_TYPE_NETWORK,
+	UHSO_PORT_TYPE_MODEM,
+	UHSO_PORT_TYPE_MSD,
+	UHSO_PORT_TYPE_PCSC,
+	UHSO_PORT_TYPE_VOICE
+};
+static char uhso_port_map_max = sizeof(uhso_port_map) / sizeof(char);
+
+static char uhso_mux_port_map[] = {
+	UHSO_PORT_TYPE_CTL,
+	UHSO_PORT_TYPE_APP,
+	UHSO_PORT_TYPE_PCSC,
+	UHSO_PORT_TYPE_GPS,
+	UHSO_PORT_TYPE_APP2
+};
+
+static char *uhso_port_type[] = {
+	"Unknown",
+	"Control",
+	"Application",
+	"Application (Secondary)",
+	"Modem",
+	"Network",
+	"Diagnostic",
+	"Diagnostic (Secondary)",
+	"GPS",
+	"GPS Control",
+	"PC Smartcard",
+	"MSD",
+	"Voice",
+};
+
+static char *uhso_port_type_sysctl[] = {
+	"unknown",
+	"control",
+	"application",
+	"application",
+	"modem",
+	"network",
+	"diagnostic",
+	"diagnostic",
+	"gps",
+	"gps_control",
+	"pcsc",
+	"msd",
+	"voice",
+};
+
+
+#define UHSO_STATIC_IFACE	0x01
+#define UHSO_AUTO_IFACE		0x02
+
+static const struct usb_device_id uhso_devs[] = {
+#define	UHSO_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
+	/* Option GlobeSurfer iCON 7.2 */
+	UHSO_DEV(OPTION, GSICON72, UHSO_STATIC_IFACE),
+	/* Option iCON 225 */
+	UHSO_DEV(OPTION, GTHSDPA, UHSO_STATIC_IFACE),
+	/* Option GlobeSurfer iCON HSUPA */
+	UHSO_DEV(OPTION, GSICONHSUPA, UHSO_STATIC_IFACE),
+	/* Option GlobeTrotter HSUPA */
+	UHSO_DEV(OPTION, GTHSUPA, UHSO_STATIC_IFACE),
+	/* GE40x */
+	UHSO_DEV(OPTION, GE40X, UHSO_AUTO_IFACE),
+	UHSO_DEV(OPTION, GE40X_1, UHSO_AUTO_IFACE),
+	UHSO_DEV(OPTION, GE40X_2, UHSO_AUTO_IFACE),
+	UHSO_DEV(OPTION, GE40X_3, UHSO_AUTO_IFACE),
+	/* Option GlobeSurfer iCON 401 */
+	UHSO_DEV(OPTION, ICON401, UHSO_AUTO_IFACE),
+	/* Option GlobeTrotter Module 382 */
+	UHSO_DEV(OPTION, GMT382, UHSO_AUTO_IFACE),
+	/* Option iCON EDGE */
+	UHSO_DEV(OPTION, ICONEDGE, UHSO_STATIC_IFACE),
+	/* Option Module HSxPA */
+	UHSO_DEV(OPTION, MODHSXPA, UHSO_STATIC_IFACE),
+	/* Option iCON 321 */
+	UHSO_DEV(OPTION, ICON321, UHSO_STATIC_IFACE),
+	/* Option iCON 322 */
+	UHSO_DEV(OPTION, GTICON322, UHSO_STATIC_IFACE)
+#undef UHSO_DEV
+};
+
+SYSCTL_NODE(_hw_usb, OID_AUTO, uhso, CTLFLAG_RW, 0, "USB uhso");
+
+#ifdef USB_DEBUG
+#ifdef UHSO_DEBUG
+static int uhso_debug = UHSO_DEBUG;
+#else
+static int uhso_debug = -1;
+#endif
+
+SYSCTL_INT(_hw_usb_uhso, OID_AUTO, debug, CTLFLAG_RW,
+    &uhso_debug, 0, "Debug level");
+
+#define UHSO_DPRINTF(n, x, ...) {\
+	if (uhso_debug >= n) {\
+		printf("%s: " x, __func__, ##__VA_ARGS__);\
+	}\
+}
+#else
+#define UHSO_DPRINTF(n, x, ...)
+#endif
+
+#ifdef UHSO_DEBUG_HEXDUMP
+# define UHSO_HEXDUMP(_buf, _len) do { \
+  { \
+        size_t __tmp; \
+        const char *__buf = (const char *)_buf; \
+        for (__tmp = 0; __tmp < _len; __tmp++) \
+                printf("%02hhx ", *__buf++); \
+    printf("\n"); \
+  } \
+} while(0)
+#else
+# define UHSO_HEXDUMP(_buf, _len)
+#endif
+
+enum {
+	UHSO_MUX_ENDPT_INTR = 0,
+	UHSO_MUX_ENDPT_MAX
+};
+
+enum {
+	UHSO_CTRL_READ = 0,
+	UHSO_CTRL_WRITE,
+	UHSO_CTRL_MAX
+};
+
+enum {
+	UHSO_IFNET_READ = 0,
+	UHSO_IFNET_WRITE,
+	UHSO_IFNET_MAX
+};
+
+enum {
+	UHSO_BULK_ENDPT_READ = 0,
+	UHSO_BULK_ENDPT_WRITE,
+	UHSO_BULK_ENDPT_INTR,
+	UHSO_BULK_ENDPT_MAX
+};
+
+static usb_callback_t uhso_mux_intr_callback;
+static usb_callback_t uhso_mux_read_callback;
+static usb_callback_t uhso_mux_write_callback;
+static usb_callback_t uhso_bs_read_callback;
+static usb_callback_t uhso_bs_write_callback;
+static usb_callback_t uhso_bs_intr_callback;
+static usb_callback_t uhso_ifnet_read_callback;
+static usb_callback_t uhso_ifnet_write_callback;
+
+static const struct usb_config uhso_ctrl_config[UHSO_CTRL_MAX] = {
+	[UHSO_CTRL_READ] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,
+		.direction = UE_DIR_ANY,
+		.flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
+		.bufsize = sizeof(struct usb_device_request) + 1024,
+		.callback = &uhso_mux_read_callback
+	},
+
+	[UHSO_CTRL_WRITE] = {
+		.type = UE_CONTROL,
+		.endpoint = 0x00,
+		.direction = UE_DIR_ANY,
+		.flags = { .pipe_bof = 1, .force_short_xfer = 1 },
+		.bufsize = sizeof(struct usb_device_request) + 1024,
+		.timeout = 1000,
+		.callback = &uhso_mux_write_callback
+	}
+};
+
+static const struct usb_config uhso_mux_config[UHSO_MUX_ENDPT_MAX] = {
+	[UHSO_MUX_ENDPT_INTR] = {
+		.type = UE_INTERRUPT,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = { .short_xfer_ok = 1 },
+		.bufsize = 0,
+		.callback = &uhso_mux_intr_callback,
+	}
+};
+
+static const struct usb_config uhso_ifnet_config[UHSO_IFNET_MAX] = {
+	[UHSO_IFNET_READ] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
+		.bufsize = MCLBYTES,
+		.callback = &uhso_ifnet_read_callback
+	},
+	[UHSO_IFNET_WRITE] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.flags = { .pipe_bof = 1, .force_short_xfer = 1 },
+		.bufsize = MCLBYTES,
+		.timeout = 5 * USB_MS_HZ,
+		.callback = &uhso_ifnet_write_callback
+	}
+};
+
+static const struct usb_config uhso_bs_config[UHSO_BULK_ENDPT_MAX] = {
+	[UHSO_BULK_ENDPT_READ] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = { .pipe_bof = 1, .short_xfer_ok = 1 },
+		.bufsize = 4096,
+		.callback = &uhso_bs_read_callback
+	},
+
+	[UHSO_BULK_ENDPT_WRITE] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.flags = { .pipe_bof = 1, .force_short_xfer = 1 },
+		.bufsize = 8192,
+		.callback = &uhso_bs_write_callback
+	},
+
+	[UHSO_BULK_ENDPT_INTR] = {
+		.type = UE_INTERRUPT,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = { .short_xfer_ok = 1 },
+		.bufsize = 0,
+		.callback = &uhso_bs_intr_callback,
+	}
+};
+
+static int uhso_probe_iface(struct uhso_softc *, int,
+    int (*probe)(struct uhso_softc *, int));
+static int uhso_probe_iface_auto(struct uhso_softc *, int);
+static int uhso_probe_iface_static(struct uhso_softc *, int);
+
+static int uhso_attach_muxserial(struct uhso_softc *, struct usb_interface *,
+    int type);
+static int uhso_attach_bulkserial(struct uhso_softc *, struct usb_interface *,
+    int type);
+static int uhso_attach_ifnet(struct uhso_softc *, struct usb_interface *,
+    int type);
+static void uhso_test_autoinst(void *, struct usb_device *,
+		struct usb_attach_arg *);
+static int uhso_driver_loaded(struct module *, int, void *);
+
+static void uhso_ucom_start_read(struct ucom_softc *);
+static void uhso_ucom_stop_read(struct ucom_softc *);
+static void uhso_ucom_start_write(struct ucom_softc *);
+static void uhso_ucom_stop_write(struct ucom_softc *);
+static void uhso_ucom_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *);
+static void uhso_ucom_cfg_set_dtr(struct ucom_softc *, uint8_t);
+static void uhso_ucom_cfg_set_rts(struct ucom_softc *, uint8_t);
+
+static void uhso_if_init(void *);
+static void uhso_if_start(struct ifnet *);
+static void uhso_if_stop(struct uhso_softc *);
+static int uhso_if_ioctl(struct ifnet *, u_long, caddr_t);
+static int uhso_if_output(struct ifnet *, struct mbuf *, struct sockaddr *,
+    struct route *);
+static void uhso_if_rxflush(void *);
+
+static device_probe_t uhso_probe;
+static device_attach_t uhso_attach;
+static device_detach_t uhso_detach;
+
+static device_method_t uhso_methods[] = {
+	DEVMETHOD(device_probe,		uhso_probe),
+	DEVMETHOD(device_attach,	uhso_attach),
+	DEVMETHOD(device_detach,	uhso_detach),
+	{ 0, 0 }
+};
+
+static driver_t uhso_driver = {
+	"uhso",
+	uhso_methods,
+	sizeof(struct uhso_softc)
+};
+
+static devclass_t uhso_devclass;
+DRIVER_MODULE(uhso, uhub, uhso_driver, uhso_devclass, uhso_driver_loaded, 0);
+MODULE_DEPEND(uhso, ucom, 1, 1, 1);
+MODULE_DEPEND(uhso, usb, 1, 1, 1);
+MODULE_VERSION(uhso, 1);
+
+static struct ucom_callback uhso_ucom_callback = {
+	.ucom_cfg_get_status = &uhso_ucom_cfg_get_status,
+	.ucom_cfg_set_dtr = &uhso_ucom_cfg_set_dtr,
+	.ucom_cfg_set_rts = &uhso_ucom_cfg_set_rts,
+	.ucom_start_read = uhso_ucom_start_read,
+	.ucom_stop_read = uhso_ucom_stop_read,
+	.ucom_start_write = uhso_ucom_start_write,
+	.ucom_stop_write = uhso_ucom_stop_write
+};
+
+static int
+uhso_probe(device_t self)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(self);
+
+	if (uaa->usb_mode != USB_MODE_HOST)
+		return (ENXIO);
+	if (uaa->info.bConfigIndex != 0)
+		return (ENXIO);
+	if (uaa->device->ddesc.bDeviceClass != 0xff)
+		return (ENXIO);
+
+	return (usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa));
+}
+
+static int
+uhso_attach(device_t self)
+{
+	struct uhso_softc *sc = device_get_softc(self);
+	struct usb_attach_arg *uaa = device_get_ivars(self);
+	struct usb_config_descriptor *cd;
+	struct usb_interface_descriptor *id;
+	struct sysctl_ctx_list *sctx;
+	struct sysctl_oid *soid;
+	struct sysctl_oid *tree, *tty_node;
+	struct ucom_softc *ucom;
+	struct uhso_tty *ht;
+	int i, error, port;
+	void *probe_f;
+	usb_error_t uerr;
+	char *desc;
+
+	device_set_usb_desc(self);
+
+	UHSO_DPRINTF(0, "Device is in modem mode, devClass=%x\n",
+	    uaa->device->ddesc.bDeviceClass);
+
+	sc->sc_dev = self;
+	sc->sc_udev = uaa->device;
+	mtx_init(&sc->sc_mtx, "uhso", NULL, MTX_DEF);
+
+	sc->sc_ucom = NULL;
+	sc->sc_ttys = 0;
+
+	cd = usbd_get_config_descriptor(uaa->device);
+	id = usbd_get_interface_descriptor(uaa->iface);
+	sc->sc_ctrl_iface_no = id->bInterfaceNumber;
+
+	sc->sc_iface_no = uaa->info.bIfaceNum;
+	sc->sc_iface_index = uaa->info.bIfaceIndex;
+
+	/* Setup control pipe */
+	uerr = usbd_transfer_setup(uaa->device,
+	    &sc->sc_iface_index, sc->sc_ctrl_xfer,
+	    uhso_ctrl_config, UHSO_CTRL_MAX, sc, &sc->sc_mtx);
+	if (uerr) {
+		device_printf(self, "Failed to setup control pipe: %s\n",
+		    usbd_errstr(uerr));
+		goto out;
+	}
+
+	if (USB_GET_DRIVER_INFO(uaa) == UHSO_STATIC_IFACE)
+		probe_f = uhso_probe_iface_static;
+	else if (USB_GET_DRIVER_INFO(uaa) == UHSO_AUTO_IFACE)
+		probe_f = uhso_probe_iface_auto;
+	else
+		goto out;
+
+	error = uhso_probe_iface(sc, uaa->info.bIfaceNum, probe_f);
+	if (error != 0)
+		goto out;
+
+
+	sctx = device_get_sysctl_ctx(sc->sc_dev);
+	soid = device_get_sysctl_tree(sc->sc_dev);
+
+	SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "type",
+	    CTLFLAG_RD, uhso_port[UHSO_IFACE_PORT(sc->sc_type)], 0,
+	    "Port available at this interface");
+
+	if (sc->sc_ttys > 0) {
+		SYSCTL_ADD_INT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "ports",
+		    CTLFLAG_RD, &sc->sc_ttys, 0, "Number of attached serial ports");
+
+		tree = SYSCTL_ADD_NODE(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
+		    "port", CTLFLAG_RD, NULL, "Serial ports");
+	}
+
+	for (i = 0; i < sc->sc_ttys; i++) {
+		ht = &sc->sc_tty[i];
+		ucom = &sc->sc_ucom[i];
+
+
+		if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_MUX)
+			port = uhso_mux_port_map[ht->ht_muxport];
+		else
+			port = UHSO_IFACE_PORT_TYPE(sc->sc_type);
+
+		desc = uhso_port_type_sysctl[port];
+
+		tty_node = SYSCTL_ADD_NODE(sctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+		    desc, CTLFLAG_RD, NULL, "");
+
+		ht->ht_name[0] = 0;
+		if (sc->sc_ttys == 1)
+			snprintf(ht->ht_name, 32, "cuaU%d", ucom->sc_unit);
+		else {
+			snprintf(ht->ht_name, 32, "cuaU%d.%d",
+			    ucom->sc_unit - ucom->sc_local_unit,
+			    ucom->sc_local_unit);
+		}
+
+		desc = uhso_port_type[port];
+		SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(tty_node), OID_AUTO,
+		    "tty", CTLFLAG_RD, ht->ht_name, 0, "");
+		SYSCTL_ADD_STRING(sctx, SYSCTL_CHILDREN(tty_node), OID_AUTO,
+		    "desc", CTLFLAG_RD, desc, 0, "");
+
+		if (bootverbose)
+			device_printf(sc->sc_dev,
+			    "\"%s\" port at %s\n", desc, ht->ht_name);
+	}
+
+	return (0);
+out:
+	uhso_detach(sc->sc_dev);
+	return (ENXIO);
+
+}
+
+static int
+uhso_detach(device_t self)
+{
+	struct uhso_softc *sc = device_get_softc(self);
+	int i;
+
+	usbd_transfer_unsetup(sc->sc_xfer, 3);
+	usbd_transfer_unsetup(sc->sc_ctrl_xfer, UHSO_CTRL_MAX);
+	if (sc->sc_ttys > 0) {
+		ucom_detach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_ttys);
+
+		for (i = 0; i < sc->sc_ttys; i++) {
+			if (sc->sc_tty[i].ht_muxport != -1) {
+				usbd_transfer_unsetup(sc->sc_tty[i].ht_xfer,
+				    UHSO_CTRL_MAX);
+			}
+		}
+
+		free(sc->sc_tty, M_USBDEV);
+		free(sc->sc_ucom, M_USBDEV);
+	}
+
+	if (sc->sc_ifp != NULL) {
+
+		callout_drain(&sc->sc_c);
+
+		mtx_lock(&sc->sc_mtx);
+		uhso_if_stop(sc);
+		bpfdetach(sc->sc_ifp);
+		if_detach(sc->sc_ifp);
+		if_free(sc->sc_ifp);
+		mtx_unlock(&sc->sc_mtx);
+
+		usbd_transfer_unsetup(sc->sc_if_xfer, UHSO_IFNET_MAX);
+	}
+
+	mtx_destroy(&sc->sc_mtx);
+
+	return (0);
+}
+
+static void
+uhso_test_autoinst(void *arg, struct usb_device *udev,
+    struct usb_attach_arg *uaa)
+{
+	struct usb_interface *iface;
+	struct usb_interface_descriptor *id;
+
+	if (uaa->dev_state != UAA_DEV_READY)
+		return;
+
+	iface = usbd_get_iface(udev, 0);
+	if (iface == NULL)
+		return;
+	id = iface->idesc;
+	if (id == NULL || id->bInterfaceClass != UICLASS_MASS)
+		return;
+	if (usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa))
+		return;		/* no device match */
+
+	if (usb_msc_eject(udev, 0, MSC_EJECT_REZERO) == 0) {
+		/* success, mark the udev as disappearing */
+		uaa->dev_state = UAA_DEV_EJECTING;
+	}
+}
+
+static int
+uhso_driver_loaded(struct module *mod, int what, void *arg)
+{
+	switch (what) {
+	case MOD_LOAD:
+		/* register our autoinstall handler */
+		uhso_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
+		    uhso_test_autoinst, NULL, EVENTHANDLER_PRI_ANY);
+		break;
+	case MOD_UNLOAD:
+		EVENTHANDLER_DEREGISTER(usb_dev_configured, uhso_etag);
+		break;
+	default:
+		return (EOPNOTSUPP);
+	}
+	return (0);
+}
+
+static int uhso_probe_iface_auto(struct uhso_softc *sc, int index)
+{
+	struct usb_device_request req;
+	usb_error_t uerr;
+	uint16_t actlen = 0;
+	char port;
+	char buf[17] = {0};
+
+	req.bmRequestType = UT_READ_VENDOR_DEVICE;
+	req.bRequest = 0x86;
+	USETW(req.wValue, 0);
+	USETW(req.wIndex, 0);
+	USETW(req.wLength, 17);
+
+	uerr = usbd_do_request_flags(sc->sc_udev, NULL, &req, buf,
+	    0, &actlen, USB_MS_HZ);
+	if (uerr != 0) {
+		device_printf(sc->sc_dev, "usbd_do_request_flags failed: %s\n",
+		    usbd_errstr(uerr));
+		return (0);
+	}
+
+	UHSO_DPRINTF(3, "actlen=%d\n", actlen);
+	UHSO_HEXDUMP(buf, 17);
+
+	if (index < 0 || index > 16) {
+		UHSO_DPRINTF(0, "Index %d out of range\n", index);
+		return (0);
+	}
+
+	UHSO_DPRINTF(3, "index=%d, type=%x\n", index, buf[index]);
+
+	if (buf[index] >= uhso_port_map_max)
+		port = 0;
+	else
+		port = uhso_port_map[(int)buf[index]];
+
+	if (port == UHSO_PORT_TYPE_NETWORK)
+		return (UHSO_IFACE_SPEC(UHSO_IF_BULK,
+		    UHSO_PORT_NETWORK, port));
+	else if (port == UHSO_PORT_TYPE_VOICE)
+		return (0);
+	else
+		return (UHSO_IFACE_SPEC(UHSO_IF_BULK,
+		    UHSO_PORT_SERIAL, port));
+
+	return (0);
+}
+
+static int
+uhso_probe_iface_static(struct uhso_softc *sc, int index)
+{
+	struct usb_config_descriptor *cd;
+
+	cd = usbd_get_config_descriptor(sc->sc_udev);
+	if (cd->bNumInterface <= 3) {
+		switch (index) {
+		case 0:
+			return UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX,
+			    UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, 0);
+		case 1:
+			return UHSO_IFACE_SPEC(UHSO_IF_BULK,
+			    UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG);
+		case 2:
+			return UHSO_IFACE_SPEC(UHSO_IF_BULK,
+			    UHSO_PORT_SERIAL, UHSO_PORT_TYPE_MODEM);
+		}
+	}
+	else {
+		switch (index) {
+		case 0:
+			return UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX,
+			    UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, 0);
+		case 1:
+			return UHSO_IFACE_SPEC(UHSO_IF_BULK,
+			    UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG2);
+		case 2:
+			return UHSO_IFACE_SPEC(UHSO_IF_BULK,
+			    UHSO_PORT_SERIAL, UHSO_PORT_TYPE_MODEM);
+		case 3:
+			return UHSO_IFACE_SPEC(UHSO_IF_BULK,
+			    UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG);
+		}
+	}
+	return (0);
+}
+
+static int
+uhso_probe_iface(struct uhso_softc *sc, int index,
+    int (*probe)(struct uhso_softc *, int))
+{
+	struct usb_interface *iface;
+	int type, error, error0;
+
+	UHSO_DPRINTF(1, "Probing for interface %d, cb=%p\n", index, probe);
+
+	type = probe(sc, index);
+	UHSO_DPRINTF(1, "Probe result %x\n", type);
+	if (type <= 0)
+		return (ENXIO);
+
+	sc->sc_type = type;
+	iface = usbd_get_iface(sc->sc_udev, index);
+
+	if (UHSO_IFACE_USB_TYPE(type) & (UHSO_IF_MUX | UHSO_IF_NET)) {
+		error0 = uhso_attach_muxserial(sc, iface, type);
+		error = uhso_attach_ifnet(sc, iface, type);
+
+		if (error0 && error)
+			return (ENXIO);
+
+		if (sc->sc_ttys > 0) {
+			error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom,
+			    sc->sc_ttys, sc, &uhso_ucom_callback, &sc->sc_mtx);
+			if (error) {
+				device_printf(sc->sc_dev, "ucom_attach failed\n");
+				return (ENXIO);
+			}
+		}
+
+		mtx_lock(&sc->sc_mtx);
+		usbd_transfer_start(sc->sc_xfer[UHSO_MUX_ENDPT_INTR]);
+		mtx_unlock(&sc->sc_mtx);
+	}
+	else if ((UHSO_IFACE_USB_TYPE(type) & UHSO_IF_BULK) &&
+	    UHSO_IFACE_PORT(type) & UHSO_PORT_SERIAL) {
+
+		error = uhso_attach_bulkserial(sc, iface, type);
+		if (error)
+			return (ENXIO);
+
+		error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom,
+		    sc->sc_ttys, sc, &uhso_ucom_callback, &sc->sc_mtx);
+		if (error) {
+			device_printf(sc->sc_dev, "ucom_attach failed\n");
+			return (ENXIO);
+		}
+	}
+	else {
+		return (ENXIO);
+	}
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list