mirror of
https://github.com/opnsense/src.git
synced 2026-06-04 22:32:43 -04:00
Update to Fredrik's latest uhso driver. This changes port detection, adds
comments and other code nits. Submitted by: Fredrik Lindberg <fli@shapeshifter.se>
This commit is contained in:
parent
9567147bea
commit
9b6ffc1f49
3 changed files with 169 additions and 97 deletions
|
|
@ -23,11 +23,11 @@
|
|||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd Aug 12, 2009
|
||||
.Dd January 14, 2010
|
||||
.Os
|
||||
.Dt UHSO 4
|
||||
.Sh NAME
|
||||
.Nm hso
|
||||
.Nm uhso
|
||||
.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
|
||||
|
|
@ -47,12 +47,12 @@ 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
|
||||
Connection of the packet interface is achieved by using the proprietary
|
||||
AT commands
|
||||
.Dq Li AT_OWANCALL
|
||||
and
|
||||
.Dq Li AT_OWANDATA
|
||||
are required on any of the serial ports.
|
||||
on any of the available serial ports.
|
||||
.Pp
|
||||
The network interface must be configured manually using the data obtain from
|
||||
these calls.
|
||||
|
|
@ -70,12 +70,23 @@ driver supports at least the following cards
|
|||
Option GlobeSurfer iCON 7.2 (new firmware)
|
||||
.It
|
||||
Option iCON 225
|
||||
.It
|
||||
Option iCON 505
|
||||
.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.
|
||||
which contains drivers for Microsoft Windows, this is the default
|
||||
mode for the device.
|
||||
The
|
||||
.Nm
|
||||
driver automatically switches the device from
|
||||
.Dq Zero-CD
|
||||
mode to modem mode.
|
||||
This behavior can be disabled by setting
|
||||
.Va hw.usb.uhso.auto_switch
|
||||
to 0 using
|
||||
.Xr sysctl 8
|
||||
.Sh EXAMPLES
|
||||
Establishing a packet interface connection
|
||||
.Bd -literal -offset indent
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*-
|
||||
* Copyright (c) 2009 Fredrik Lindberg
|
||||
* Copyright (c) 2009 Fredrik Lindberg <fli@shapeshifter.se>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
|
@ -63,13 +63,15 @@ __FBSDID("$FreeBSD$");
|
|||
#include <dev/usb/usb_process.h>
|
||||
#include <dev/usb/usb_device.h>
|
||||
#include <dev/usb/usb_busdma.h>
|
||||
#include <dev/usb/usb_controller.h>
|
||||
#include <dev/usb/usb_bus.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_muxport; /* Mux. port no */
|
||||
int ht_open;
|
||||
char ht_name[32];
|
||||
};
|
||||
|
|
@ -78,7 +80,7 @@ struct uhso_softc {
|
|||
device_t sc_dev;
|
||||
struct usb_device *sc_udev;
|
||||
struct mtx sc_mtx;
|
||||
uint32_t sc_type;
|
||||
uint32_t sc_type; /* Interface definition */
|
||||
|
||||
struct usb_xfer *sc_xfer[3];
|
||||
uint8_t sc_iface_no;
|
||||
|
|
@ -91,14 +93,14 @@ struct uhso_softc {
|
|||
/* 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 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;
|
||||
int sc_ttys;
|
||||
struct uhso_tty *sc_tty;
|
||||
struct ucom_softc *sc_ucom;
|
||||
int sc_msr;
|
||||
|
|
@ -106,7 +108,6 @@ struct uhso_softc {
|
|||
int sc_line;
|
||||
};
|
||||
|
||||
|
||||
#define UHSO_MAX_MTU 2048
|
||||
|
||||
/*
|
||||
|
|
@ -135,7 +136,7 @@ struct uhso_softc {
|
|||
* Port types
|
||||
*/
|
||||
#define UHSO_PORT_UNKNOWN 0x00
|
||||
#define UHSO_PORT_SERIAL 0x01 /* Serial port */
|
||||
#define UHSO_PORT_SERIAL 0x01 /* Serial port */
|
||||
#define UHSO_PORT_NETWORK 0x02 /* Network packet interface */
|
||||
|
||||
/*
|
||||
|
|
@ -145,12 +146,14 @@ struct uhso_softc {
|
|||
#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_APP2 0x04 /* Secondary application */
|
||||
#define UHSO_MPORT_TYPE_MAX UHSO_MPORT_TYPE_APP2
|
||||
#define UHSO_MPORT_TYPE_NOMAX 8 /* Max number of mux ports */
|
||||
|
||||
/*
|
||||
* Port definitions
|
||||
* Note that these definitions are arbitray and doesn't match
|
||||
* values returned by the auto config descriptor.
|
||||
*/
|
||||
#define UHSO_PORT_TYPE_CTL 0x01
|
||||
#define UHSO_PORT_TYPE_APP 0x02
|
||||
|
|
@ -176,8 +179,12 @@ static char *uhso_port[] = {
|
|||
"Network/Serial"
|
||||
};
|
||||
|
||||
/* Map between interface port type read from device and description type */
|
||||
static char uhso_port_map[] = {
|
||||
/*
|
||||
* Map between interface port type read from device and description type.
|
||||
* The position in this array is a direct map to the auto config
|
||||
* descriptor values.
|
||||
*/
|
||||
static unsigned char uhso_port_map[] = {
|
||||
0,
|
||||
UHSO_PORT_TYPE_DIAG,
|
||||
UHSO_PORT_TYPE_GPS,
|
||||
|
|
@ -193,7 +200,7 @@ static char uhso_port_map[] = {
|
|||
};
|
||||
static char uhso_port_map_max = sizeof(uhso_port_map) / sizeof(char);
|
||||
|
||||
static char uhso_mux_port_map[] = {
|
||||
static unsigned char uhso_mux_port_map[] = {
|
||||
UHSO_PORT_TYPE_CTL,
|
||||
UHSO_PORT_TYPE_APP,
|
||||
UHSO_PORT_TYPE_PCSC,
|
||||
|
|
@ -202,7 +209,7 @@ static char uhso_mux_port_map[] = {
|
|||
};
|
||||
|
||||
static char *uhso_port_type[] = {
|
||||
"Unknown",
|
||||
"Unknown", /* Not a valid port */
|
||||
"Control",
|
||||
"Application",
|
||||
"Application (Secondary)",
|
||||
|
|
@ -233,7 +240,6 @@ static char *uhso_port_type_sysctl[] = {
|
|||
"voice",
|
||||
};
|
||||
|
||||
|
||||
#define UHSO_STATIC_IFACE 0x01
|
||||
#define UHSO_AUTO_IFACE 0x02
|
||||
|
||||
|
|
@ -263,11 +269,16 @@ static const struct usb_device_id uhso_devs[] = {
|
|||
/* Option iCON 321 */
|
||||
UHSO_DEV(OPTION, ICON321, UHSO_STATIC_IFACE),
|
||||
/* Option iCON 322 */
|
||||
UHSO_DEV(OPTION, GTICON322, UHSO_STATIC_IFACE)
|
||||
UHSO_DEV(OPTION, GTICON322, UHSO_STATIC_IFACE),
|
||||
/* Option iCON 505 */
|
||||
UHSO_DEV(OPTION, ICON505, UHSO_AUTO_IFACE),
|
||||
#undef UHSO_DEV
|
||||
};
|
||||
|
||||
SYSCTL_NODE(_hw_usb, OID_AUTO, uhso, CTLFLAG_RW, 0, "USB uhso");
|
||||
static int uhso_autoswitch = 1;
|
||||
SYSCTL_INT(_hw_usb_uhso, OID_AUTO, auto_switch, CTLFLAG_RW,
|
||||
&uhso_autoswitch, 0, "Automatically switch to modem mode");
|
||||
|
||||
#ifdef USB_DEBUG
|
||||
#ifdef UHSO_DEBUG
|
||||
|
|
@ -335,6 +346,7 @@ static usb_callback_t uhso_bs_intr_callback;
|
|||
static usb_callback_t uhso_ifnet_read_callback;
|
||||
static usb_callback_t uhso_ifnet_write_callback;
|
||||
|
||||
/* Config used for the default control pipes */
|
||||
static const struct usb_config uhso_ctrl_config[UHSO_CTRL_MAX] = {
|
||||
[UHSO_CTRL_READ] = {
|
||||
.type = UE_CONTROL,
|
||||
|
|
@ -356,6 +368,7 @@ static const struct usb_config uhso_ctrl_config[UHSO_CTRL_MAX] = {
|
|||
}
|
||||
};
|
||||
|
||||
/* Config for the multiplexed serial ports */
|
||||
static const struct usb_config uhso_mux_config[UHSO_MUX_ENDPT_MAX] = {
|
||||
[UHSO_MUX_ENDPT_INTR] = {
|
||||
.type = UE_INTERRUPT,
|
||||
|
|
@ -367,6 +380,7 @@ static const struct usb_config uhso_mux_config[UHSO_MUX_ENDPT_MAX] = {
|
|||
}
|
||||
};
|
||||
|
||||
/* Config for the raw IP-packet interface */
|
||||
static const struct usb_config uhso_ifnet_config[UHSO_IFNET_MAX] = {
|
||||
[UHSO_IFNET_READ] = {
|
||||
.type = UE_BULK,
|
||||
|
|
@ -387,6 +401,7 @@ static const struct usb_config uhso_ifnet_config[UHSO_IFNET_MAX] = {
|
|||
}
|
||||
};
|
||||
|
||||
/* Config for interfaces with normal bulk serial ports */
|
||||
static const struct usb_config uhso_bs_config[UHSO_BULK_ENDPT_MAX] = {
|
||||
[UHSO_BULK_ENDPT_READ] = {
|
||||
.type = UE_BULK,
|
||||
|
|
@ -416,20 +431,19 @@ static const struct usb_config uhso_bs_config[UHSO_BULK_ENDPT_MAX] = {
|
|||
}
|
||||
};
|
||||
|
||||
static int uhso_probe_iface(struct uhso_softc *, int,
|
||||
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 *,
|
||||
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 *,
|
||||
static int uhso_attach_bulkserial(struct uhso_softc *, struct usb_interface *,
|
||||
int type);
|
||||
static int uhso_attach_ifnet(struct uhso_softc *, struct usb_interface *,
|
||||
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 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 *);
|
||||
|
|
@ -438,12 +452,11 @@ 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 *,
|
||||
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 *);
|
||||
|
||||
|
|
@ -512,11 +525,6 @@ uhso_attach(device_t self)
|
|||
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);
|
||||
|
|
@ -552,7 +560,6 @@ uhso_attach(device_t self)
|
|||
if (error != 0)
|
||||
goto out;
|
||||
|
||||
|
||||
sctx = device_get_sysctl_ctx(sc->sc_dev);
|
||||
soid = device_get_sysctl_tree(sc->sc_dev);
|
||||
|
||||
|
|
@ -560,6 +567,18 @@ uhso_attach(device_t self)
|
|||
CTLFLAG_RD, uhso_port[UHSO_IFACE_PORT(sc->sc_type)], 0,
|
||||
"Port available at this interface");
|
||||
|
||||
/*
|
||||
* The default interface description on most Option devices aren't
|
||||
* very helpful. So we skip device_set_usb_desc and set the
|
||||
* device description manually.
|
||||
*/
|
||||
device_set_desc_copy(self, uhso_port_type[UHSO_IFACE_PORT_TYPE(sc->sc_type)]);
|
||||
/* Announce device */
|
||||
device_printf(self, "<%s port> at <%s %s> on %s\n",
|
||||
uhso_port_type[UHSO_IFACE_PORT_TYPE(sc->sc_type)],
|
||||
uaa->device->manufacturer, uaa->device->product,
|
||||
device_get_nameunit(uaa->device->bus->bdev));
|
||||
|
||||
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");
|
||||
|
|
@ -568,11 +587,14 @@ uhso_attach(device_t self)
|
|||
"port", CTLFLAG_RD, NULL, "Serial ports");
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through the number of found TTYs and create sysctl
|
||||
* nodes for them.
|
||||
*/
|
||||
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
|
||||
|
|
@ -607,7 +629,6 @@ uhso_attach(device_t self)
|
|||
out:
|
||||
uhso_detach(sc->sc_dev);
|
||||
return (ENXIO);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -633,21 +654,17 @@ uhso_detach(device_t self)
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -658,7 +675,7 @@ uhso_test_autoinst(void *arg, struct usb_device *udev,
|
|||
struct usb_interface *iface;
|
||||
struct usb_interface_descriptor *id;
|
||||
|
||||
if (uaa->dev_state != UAA_DEV_READY)
|
||||
if (uaa->dev_state != UAA_DEV_READY || !uhso_autoswitch)
|
||||
return;
|
||||
|
||||
iface = usbd_get_iface(udev, 0);
|
||||
|
|
@ -694,7 +711,13 @@ uhso_driver_loaded(struct module *mod, int what, void *arg)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static int uhso_probe_iface_auto(struct uhso_softc *sc, int index)
|
||||
/*
|
||||
* Probe the interface type by querying the device. The elements
|
||||
* of an array indicates the capabilities of a particular interface.
|
||||
* Returns a bit mask with the interface capabilities.
|
||||
*/
|
||||
static int
|
||||
uhso_probe_iface_auto(struct uhso_softc *sc, int index)
|
||||
{
|
||||
struct usb_device_request req;
|
||||
usb_error_t uerr;
|
||||
|
|
@ -716,7 +739,7 @@ static int uhso_probe_iface_auto(struct uhso_softc *sc, int index)
|
|||
return (0);
|
||||
}
|
||||
|
||||
UHSO_DPRINTF(3, "actlen=%d\n", actlen);
|
||||
UHSO_DPRINTF(1, "actlen=%d\n", actlen);
|
||||
UHSO_HEXDUMP(buf, 17);
|
||||
|
||||
if (index < 0 || index > 16) {
|
||||
|
|
@ -724,21 +747,25 @@ static int uhso_probe_iface_auto(struct uhso_softc *sc, int index)
|
|||
return (0);
|
||||
}
|
||||
|
||||
UHSO_DPRINTF(3, "index=%d, type=%x\n", index, buf[index]);
|
||||
UHSO_DPRINTF(1, "index=%d, type=%x[%s]\n", index, buf[index],
|
||||
uhso_port_type[(int)uhso_port_map[(int)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)
|
||||
switch (port) {
|
||||
case UHSO_PORT_TYPE_NETWORK:
|
||||
return (UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX,
|
||||
UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, port));
|
||||
case UHSO_PORT_TYPE_VOICE:
|
||||
/* Don't claim 'voice' ports */
|
||||
return (0);
|
||||
else
|
||||
default:
|
||||
return (UHSO_IFACE_SPEC(UHSO_IF_BULK,
|
||||
UHSO_PORT_SERIAL, port));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -750,10 +777,12 @@ uhso_probe_iface_static(struct uhso_softc *sc, int index)
|
|||
|
||||
cd = usbd_get_config_descriptor(sc->sc_udev);
|
||||
if (cd->bNumInterface <= 3) {
|
||||
/* Cards with 3 or less interfaces */
|
||||
switch (index) {
|
||||
case 0:
|
||||
return UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX,
|
||||
UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, 0);
|
||||
UHSO_PORT_SERIAL | UHSO_PORT_NETWORK,
|
||||
UHSO_PORT_TYPE_NETWORK);
|
||||
case 1:
|
||||
return UHSO_IFACE_SPEC(UHSO_IF_BULK,
|
||||
UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG);
|
||||
|
|
@ -761,12 +790,13 @@ uhso_probe_iface_static(struct uhso_softc *sc, int index)
|
|||
return UHSO_IFACE_SPEC(UHSO_IF_BULK,
|
||||
UHSO_PORT_SERIAL, UHSO_PORT_TYPE_MODEM);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* Cards with 4 interfaces */
|
||||
switch (index) {
|
||||
case 0:
|
||||
return UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX,
|
||||
UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, 0);
|
||||
UHSO_PORT_SERIAL | UHSO_PORT_NETWORK,
|
||||
UHSO_PORT_TYPE_NETWORK);
|
||||
case 1:
|
||||
return UHSO_IFACE_SPEC(UHSO_IF_BULK,
|
||||
UHSO_PORT_SERIAL, UHSO_PORT_TYPE_DIAG2);
|
||||
|
|
@ -781,14 +811,18 @@ uhso_probe_iface_static(struct uhso_softc *sc, int index)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Probes an interface for its particular capabilities and attaches if
|
||||
* it's a supported interface.
|
||||
*/
|
||||
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;
|
||||
int type, error;
|
||||
|
||||
UHSO_DPRINTF(1, "Probing for interface %d, cb=%p\n", index, probe);
|
||||
UHSO_DPRINTF(1, "Probing for interface %d, probe_func=%p\n", index, probe);
|
||||
|
||||
type = probe(sc, index);
|
||||
UHSO_DPRINTF(1, "Probe result %x\n", type);
|
||||
|
|
@ -798,27 +832,41 @@ uhso_probe_iface(struct uhso_softc *sc, int index,
|
|||
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);
|
||||
if (UHSO_IFACE_PORT_TYPE(type) == UHSO_PORT_TYPE_NETWORK) {
|
||||
error = uhso_attach_ifnet(sc, iface, type);
|
||||
|
||||
if (error0 && error)
|
||||
if (error) {
|
||||
UHSO_DPRINTF(1, "uhso_attach_ifnet failed");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (sc->sc_ttys > 0) {
|
||||
/*
|
||||
* If there is an additional interrupt endpoint on this
|
||||
* interface we most likley have a multiplexed serial port
|
||||
* available.
|
||||
*/
|
||||
if (iface->idesc->bNumEndpoints < 3) {
|
||||
sc->sc_type = UHSO_IFACE_SPEC(
|
||||
UHSO_IFACE_USB_TYPE(type) & ~UHSO_IF_MUX,
|
||||
UHSO_IFACE_PORT(type) & ~UHSO_PORT_SERIAL,
|
||||
UHSO_IFACE_PORT_TYPE(type));
|
||||
return (0);
|
||||
}
|
||||
|
||||
UHSO_DPRINTF(1, "Trying to attach mux. serial\n");
|
||||
error = uhso_attach_muxserial(sc, iface, type);
|
||||
if (error == 0 && 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) &&
|
||||
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);
|
||||
|
|
@ -833,12 +881,18 @@ uhso_probe_iface(struct uhso_softc *sc, int index,
|
|||
}
|
||||
}
|
||||
else {
|
||||
UHSO_DPRINTF(0, "Unknown type %x\n", type);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expands allocated memory to fit an additional TTY.
|
||||
* Two arrays are kept with matching indexes, one for ucom and one
|
||||
* for our private data.
|
||||
*/
|
||||
static int
|
||||
uhso_alloc_tty(struct uhso_softc *sc)
|
||||
{
|
||||
|
|
@ -856,11 +910,15 @@ uhso_alloc_tty(struct uhso_softc *sc)
|
|||
|
||||
sc->sc_tty[sc->sc_ttys - 1].ht_sc = sc;
|
||||
|
||||
UHSO_DPRINTF(2, "Allocated TTY %d\n", sc->sc_ttys - 1);
|
||||
UHSO_DPRINTF(1, "Allocated TTY %d\n", sc->sc_ttys - 1);
|
||||
return (sc->sc_ttys - 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Attach a multiplexed serial port
|
||||
* Data is read/written with requests on the default control pipe. An interrupt
|
||||
* endpoint returns when there is new data to be read.
|
||||
*/
|
||||
static int
|
||||
uhso_attach_muxserial(struct uhso_softc *sc, struct usb_interface *iface,
|
||||
int type)
|
||||
|
|
@ -885,6 +943,10 @@ uhso_attach_muxserial(struct uhso_softc *sc, struct usb_interface *iface,
|
|||
if (desc->bDescriptorSubtype == 0)
|
||||
return (ENXIO);
|
||||
|
||||
/*
|
||||
* The bitmask is one octet, loop through the number of
|
||||
* bits that are set and create a TTY for each.
|
||||
*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
port = (1 << i);
|
||||
if ((port & desc->bDescriptorSubtype) == port) {
|
||||
|
|
@ -905,6 +967,7 @@ uhso_attach_muxserial(struct uhso_softc *sc, struct usb_interface *iface,
|
|||
}
|
||||
}
|
||||
|
||||
/* Setup the intr. endpoint */
|
||||
uerr = usbd_transfer_setup(sc->sc_udev,
|
||||
&iface->idesc->bInterfaceNumber, sc->sc_xfer,
|
||||
uhso_mux_config, 1, sc, &sc->sc_mtx);
|
||||
|
|
@ -914,6 +977,10 @@ uhso_attach_muxserial(struct uhso_softc *sc, struct usb_interface *iface,
|
|||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt callback for the multiplexed serial port. Indicates
|
||||
* which serial port that has data waiting.
|
||||
*/
|
||||
static void
|
||||
uhso_mux_intr_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
{
|
||||
|
|
@ -943,6 +1010,7 @@ uhso_mux_intr_callback(struct usb_xfer *xfer, usb_error_t error)
|
|||
if (mux > UHSO_MPORT_TYPE_NOMAX)
|
||||
break;
|
||||
|
||||
/* Issue a read for this serial port */
|
||||
usbd_xfer_set_priv(
|
||||
sc->sc_tty[mux].ht_xfer[UHSO_CTRL_READ],
|
||||
&sc->sc_tty[mux]);
|
||||
|
|
@ -962,7 +1030,6 @@ tr_setup:
|
|||
usbd_xfer_set_stall(xfer);
|
||||
goto tr_setup;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1079,7 +1146,6 @@ uhso_mux_write_callback(struct usb_xfer *xfer, usb_error_t error)
|
|||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1089,9 +1155,7 @@ uhso_attach_bulkserial(struct uhso_softc *sc, struct usb_interface *iface,
|
|||
usb_error_t uerr;
|
||||
int tty;
|
||||
|
||||
/*
|
||||
* Try attaching RD/WR/INTR first
|
||||
*/
|
||||
/* Try attaching RD/WR/INTR first */
|
||||
uerr = usbd_transfer_setup(sc->sc_udev,
|
||||
&iface->idesc->bInterfaceNumber, sc->sc_xfer,
|
||||
uhso_bs_config, UHSO_BULK_ENDPT_MAX, sc, &sc->sc_mtx);
|
||||
|
|
@ -1146,7 +1210,6 @@ tr_setup:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
uhso_bs_write_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
{
|
||||
|
|
@ -1208,9 +1271,7 @@ uhso_bs_intr_callback(struct usb_xfer *xfer, usb_error_t error)
|
|||
int actlen;
|
||||
struct usb_cdc_notification cdc;
|
||||
|
||||
|
||||
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
|
||||
|
||||
UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen);
|
||||
|
||||
switch (USB_GET_STATE(xfer)) {
|
||||
|
|
@ -1228,14 +1289,14 @@ uhso_bs_intr_callback(struct usb_xfer *xfer, usb_error_t error)
|
|||
usbd_copy_out(pc, 0, &cdc, actlen);
|
||||
|
||||
if (UGETW(cdc.wIndex) != sc->sc_iface_no) {
|
||||
UHSO_DPRINTF(0, "Interface missmatch, got %d expected %d\n",
|
||||
UHSO_DPRINTF(0, "Interface mismatch, got %d expected %d\n",
|
||||
UGETW(cdc.wIndex), sc->sc_iface_no);
|
||||
goto tr_setup;
|
||||
}
|
||||
|
||||
if (cdc.bmRequestType == UCDC_NOTIFICATION &&
|
||||
cdc.bNotification == UCDC_N_SERIAL_STATE) {
|
||||
UHSO_DPRINTF(1, "notify = 0x%02x\n", cdc.data[0]);
|
||||
UHSO_DPRINTF(2, "notify = 0x%02x\n", cdc.data[0]);
|
||||
|
||||
sc->sc_msr = 0;
|
||||
sc->sc_lsr = 0;
|
||||
|
|
@ -1299,7 +1360,6 @@ uhso_ucom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
|
|||
uhso_bs_cfg(sc);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
uhso_ucom_start_read(struct ucom_softc *ucom)
|
||||
{
|
||||
|
|
@ -1373,7 +1433,6 @@ uhso_ucom_stop_write(struct ucom_softc *ucom)
|
|||
else if (UHSO_IFACE_USB_TYPE(sc->sc_type) & UHSO_IF_BULK) {
|
||||
usbd_transfer_stop(sc->sc_xfer[UHSO_BULK_ENDPT_WRITE]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface,
|
||||
|
|
@ -1393,7 +1452,7 @@ static int uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface,
|
|||
return (-1);
|
||||
}
|
||||
|
||||
sc->sc_ifp = ifp = if_alloc(IFT_PPP);
|
||||
sc->sc_ifp = ifp = if_alloc(IFT_OTHER);
|
||||
if (sc->sc_ifp == NULL) {
|
||||
device_printf(sc->sc_dev, "if_alloc() failed\n");
|
||||
return (-1);
|
||||
|
|
@ -1406,7 +1465,6 @@ static int uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface,
|
|||
|
||||
if_initname(ifp, device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev));
|
||||
ifp->if_mtu = UHSO_MAX_MTU;
|
||||
|
||||
ifp->if_ioctl = uhso_if_ioctl;
|
||||
ifp->if_init = uhso_if_init;
|
||||
ifp->if_start = uhso_if_start;
|
||||
|
|
@ -1448,6 +1506,7 @@ uhso_ifnet_read_callback(struct usb_xfer *xfer, usb_error_t error)
|
|||
m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
|
||||
usbd_copy_out(pc, 0, mtod(m, uint8_t *), actlen);
|
||||
m->m_pkthdr.len = m->m_len = actlen;
|
||||
/* Enqueue frame for further processing */
|
||||
_IF_ENQUEUE(&sc->sc_rxq, m);
|
||||
if (!callout_pending(&sc->sc_c) ||
|
||||
!callout_active(&sc->sc_c)) {
|
||||
|
|
@ -1470,7 +1529,11 @@ tr_setup:
|
|||
}
|
||||
|
||||
/*
|
||||
* Defered RX processing, called with mutex locked.
|
||||
* Deferred RX processing, called with mutex locked.
|
||||
*
|
||||
* Each frame we receive might contain several small ip-packets aswell
|
||||
* as partial ip-packets. We need to separate/assemble them into individual
|
||||
* packets before sending them to the ip-layer.
|
||||
*/
|
||||
static void
|
||||
uhso_if_rxflush(void *arg)
|
||||
|
|
@ -1493,7 +1556,7 @@ uhso_if_rxflush(void *arg)
|
|||
_IF_DEQUEUE(&sc->sc_rxq, m);
|
||||
if (m == NULL)
|
||||
break;
|
||||
UHSO_DPRINTF(2, "dequeue m=%p, len=%d\n", m, m->m_len);
|
||||
UHSO_DPRINTF(3, "dequeue m=%p, len=%d\n", m, m->m_len);
|
||||
}
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
|
|
@ -1502,7 +1565,7 @@ uhso_if_rxflush(void *arg)
|
|||
m0 = mwait;
|
||||
mwait = NULL;
|
||||
|
||||
UHSO_DPRINTF(1, "partial m0=%p(%d), concat w/ m=%p(%d)\n",
|
||||
UHSO_DPRINTF(3, "partial m0=%p(%d), concat w/ m=%p(%d)\n",
|
||||
m0, m0->m_len, m, m->m_len);
|
||||
len = m->m_len + m0->m_len;
|
||||
|
||||
|
|
@ -1518,7 +1581,7 @@ uhso_if_rxflush(void *arg)
|
|||
mtx_lock(&sc->sc_mtx);
|
||||
continue;
|
||||
}
|
||||
UHSO_DPRINTF(2, "Constructed mbuf=%p, len=%d\n",
|
||||
UHSO_DPRINTF(3, "Constructed mbuf=%p, len=%d\n",
|
||||
m, m->m_pkthdr.len);
|
||||
}
|
||||
|
||||
|
|
@ -1560,7 +1623,7 @@ uhso_if_rxflush(void *arg)
|
|||
continue;
|
||||
}
|
||||
|
||||
UHSO_DPRINTF(1, "m=%p, len=%d, cp=%p, iplen=%d\n",
|
||||
UHSO_DPRINTF(3, "m=%p, len=%d, cp=%p, iplen=%d\n",
|
||||
m, m->m_pkthdr.len, cp, iplen);
|
||||
|
||||
m0 = NULL;
|
||||
|
|
@ -1581,12 +1644,12 @@ uhso_if_rxflush(void *arg)
|
|||
m_adj(m0, iplen);
|
||||
m0 = m_defrag(m0, M_WAIT);
|
||||
|
||||
UHSO_DPRINTF(1, "New mbuf=%p, len=%d/%d, m0=%p, "
|
||||
UHSO_DPRINTF(3, "New mbuf=%p, len=%d/%d, m0=%p, "
|
||||
"m0_len=%d/%d\n", m, m->m_pkthdr.len, m->m_len,
|
||||
m0, m0->m_pkthdr.len, m0->m_len);
|
||||
}
|
||||
else if (iplen > m->m_pkthdr.len) {
|
||||
UHSO_DPRINTF(1, "Defered mbuf=%p, len=%d\n",
|
||||
UHSO_DPRINTF(3, "Deferred mbuf=%p, len=%d\n",
|
||||
m, m->m_pkthdr.len);
|
||||
mwait = m;
|
||||
m = NULL;
|
||||
|
|
@ -1649,7 +1712,6 @@ tr_setup:
|
|||
usbd_xfer_set_stall(xfer);
|
||||
goto tr_setup;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1698,7 +1760,7 @@ uhso_if_init(void *priv)
|
|||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
UHSO_DPRINTF(3, "ifnet initialized\n");
|
||||
UHSO_DPRINTF(2, "ifnet initialized\n");
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -1722,7 +1784,6 @@ uhso_if_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
|
|||
return (ENOBUFS);
|
||||
}
|
||||
ifp->if_opackets++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -1749,6 +1810,5 @@ uhso_if_stop(struct uhso_softc *sc)
|
|||
|
||||
usbd_transfer_stop(sc->sc_if_xfer[UHSO_IFNET_READ]);
|
||||
usbd_transfer_stop(sc->sc_if_xfer[UHSO_IFNET_WRITE]);
|
||||
|
||||
sc->sc_ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2111,6 +2111,7 @@ product OPTION GE40X_3 0x7381 Globetrotter HSUPA
|
|||
product OPTION ICONEDGE 0xc031 GlobeSurfer iCON EDGE
|
||||
product OPTION MODHSXPA 0xd013 Globetrotter HSUPA
|
||||
product OPTION ICON321 0xd031 Globetrotter HSUPA
|
||||
product OPTION ICON505 0xd055 Globetrotter iCON 505
|
||||
|
||||
/* OQO */
|
||||
product OQO WIFI01 0x0002 model 01 WiFi interface
|
||||
|
|
|
|||
Loading…
Reference in a new issue