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