Add u3g(4) driver from FreeBSD. This driver provides better support for

3G datacards than ugensa and will replace the latter for the supported
devices.
This commit is contained in:
joerg 2008-10-10 16:37:15 +00:00
parent 4c43f08c6f
commit db5825abd5
5 changed files with 444 additions and 4 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1103 2008/10/08 01:15:11 pgoyette Exp $
# $NetBSD: mi,v 1.1104 2008/10/10 16:37:15 joerg Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -1504,6 +1504,7 @@
./usr/share/man/cat4/twa.0 man-sys-catman .cat
./usr/share/man/cat4/twe.0 man-sys-catman .cat
./usr/share/man/cat4/txp.0 man-sys-catman .cat
./usr/share/man/cat4/u3g.0 man-sys-catman .cat
./usr/share/man/cat4/uaudio.0 man-sys-catman .cat
./usr/share/man/cat4/uax.0 man-obsolete obsolete
./usr/share/man/cat4/uberry.0 man-sys-catman .cat
@ -3952,6 +3953,7 @@
./usr/share/man/html4/twa.html man-sys-htmlman html
./usr/share/man/html4/twe.html man-sys-htmlman html
./usr/share/man/html4/txp.html man-sys-htmlman html
./usr/share/man/html4/u3g.html man-sys-htmlman html
./usr/share/man/html4/uaudio.html man-sys-htmlman html
./usr/share/man/html4/uberry.html man-sys-htmlman html
./usr/share/man/html4/ubsa.html man-sys-htmlman html
@ -6326,6 +6328,7 @@
./usr/share/man/man4/twa.4 man-sys-man .man
./usr/share/man/man4/twe.4 man-sys-man .man
./usr/share/man/man4/txp.4 man-sys-man .man
./usr/share/man/man4/u3g.4 man-sys-man .man
./usr/share/man/man4/uaudio.4 man-sys-man .man
./usr/share/man/man4/uax.4 man-obsolete obsolete
./usr/share/man/man4/uberry.4 man-sys-man .man

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.478 2008/10/08 01:15:11 pgoyette Exp $
# $NetBSD: Makefile,v 1.479 2008/10/10 16:37:15 joerg Exp $
# @(#)Makefile 8.1 (Berkeley) 6/18/93
MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 acpidalb.4 \
@ -62,7 +62,7 @@ MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 acpidalb.4 \
zero.4 zstty.4 zyd.4
# USB devices
MAN+= stuirda.4 uaudio.4 uberry.4 ubsa.4 ubt.4 uchcom.4 ucom.4 ucycom.4 \
MAN+= stuirda.4 u3g.4 uaudio.4 uberry.4 ubsa.4 ubt.4 uchcom.4 ucom.4 ucycom.4 \
udsbr.4 uftdi.4 ugen.4 ugensa.4 uhid.4 \
uhidev.4 uhmodem.4 uipaq.4 uirda.4 ukbd.4 ukyopon.4 ulpt.4 \
umass.4 umct.4 umidi.4 umodem.4 ums.4 uplcom.4 urio.4 usb.4 \

102
share/man/man4/u3g.4 Normal file
View File

@ -0,0 +1,102 @@
.\"
.\" Copyright (c) 2008 AnyWi Technologies
.\" All rights reserved.
.\"
.\" This code is derived from uark.c
.\"
.\" 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.
.\"
.\" $NetBSD: u3g.4,v 1.1 2008/10/10 16:37:16 joerg Exp $
.\"
.Dd October 7, 2008
.Dt U3G 4
.Os
.Sh NAME
.Nm u3g
.Nd USB support for 3G datacards
.Sh SYNOPSIS
To compile this driver into the kernel,
place the following lines in your
kernel configuration file:
.Bd -ragged -offset indent
.Cd "device u3g"
.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
u3g_load="YES"
.Ed
.Sh DESCRIPTION
The
.Nm
driver provides support for the multiple USB-to-serial interfaces exposed by
many 3G usb/pccard modems.
.Pp
The device is accessed through the
.Xr ucom 4
driver which makes it behave like a
.Xr tty 4 .
.Sh HARDWARE
The
.Nm
driver supports the following adapters:
.Pp
.Bl -bullet -compact
.It
Option Globetrotter 3G Fusion (only 3G part, not WLAN)
.It
Option Globetrotter 3G Fusion Quad (only 3G part, not WLAN)
.It
Option Globetrotter 3G Quad
.It
Option Globetrotter 3G
.It
Vodafone Mobile Connect Card 3G
.It
Huawei E220 (E270?)
.It
Huawei Mobile
.It
Novatel MC950D
.El
.Pp
The supported 3G cards provide the necessary modem port for ppp,
pppd, or mpd connections as well as extra ports (depending on the specific
device) to provide other functions (diagnostic port, SIM toolkit port)
.Sh SEE ALSO
.Xr tty 4 ,
.Xr ucom 4 ,
.Xr usb 4 ,
.Xr ubsa 4
.Sh HISTORY
The
.Nm
driver
appeared in
.Nx 5.0 .
The
.Xr ubsa 4
manual page was modified for
.Nm
by
.An Andrea Guzzo Aq aguzzo@anywi.com
in September 2008.
.Sh AUTHORS
The
.Nm
driver was written by
.An Andrea Guzzo Aq aguzzo@anywi.com .
Hardware for testing provided by AnyWi Technologies, Leiden, NL.

View File

@ -1,4 +1,4 @@
# $NetBSD: files.usb,v 1.89 2008/09/19 11:29:35 jmcneill Exp $
# $NetBSD: files.usb,v 1.90 2008/10/10 16:37:16 joerg Exp $
#
# Config file and device description for machine-independent USB code.
# Included by ports that need it. Ports that use it must provide
@ -170,6 +170,11 @@ device ugensa: ucombus
attach ugensa at usbdevif
file dev/usb/ugensa.c ugensa
# Generic Serial Adapter
device u3g: ucombus
attach u3g at usbdevif
file dev/usb/u3g.c u3g
# YAP phone firmware loader
device uyap: ezload
attach uyap at usbdevif

330
sys/dev/usb/u3g.c Normal file
View File

@ -0,0 +1,330 @@
/*
* Copyright (c) 2008 AnyWi Technologies
* Author: Andrea Guzzo <aguzzo@anywi.com>
* * based on uark.c 1.1 2006/08/14 08:30:22 jsg *
* * parts from ubsa.c 183348 2008-09-25 12:00:56Z phk *
*
* 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.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/ioccom.h>
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <sys/tty.h>
#include <sys/file.h>
#include <sys/selinfo.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/ucomvar.h>
#include "usbdevs.h"
#define U3GBUFSZ 1024
#define U3G_MAXPORTS 4
struct u3g_softc {
device_t sc_ucom[U3G_MAXPORTS];;
device_t sc_dev;
usbd_device_handle sc_udev;
u_char sc_msr;
u_char sc_lsr;
u_char numports;
usbd_interface_handle sc_intr_iface; /* interrupt interface */
#ifdef U3G_DEBUG
int sc_intr_number; /* interrupt number */
usbd_pipe_handle sc_intr_pipe; /* interrupt pipe */
u_char *sc_intr_buf; /* interrupt buffer */
#endif
int sc_isize;
};
struct ucom_methods u3g_methods = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static const struct usb_devno u3g_devs[] = {
/* OEM: Option N.V. */
{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADUMTS2 },
{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADUMTS },
{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADPLUSUMTS },
{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_HSDPA },
{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_VODAFONEMC3G },
/* OEM: Huawei */
{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
/* OEM: Novatel */
{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D },
// { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D_DRIVER },
{ 0, 0 }
};
#ifdef U3G_DEBUG
static void
u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
struct u3g_softc *sc = (struct u3g_softc *)priv;
aprint_normal_dev(sc->sc_dev, "INTERRUPT CALLBACK\n");
}
#endif
static int
u3g_huawei_reinit(usbd_device_handle dev)
{
/* The Huawei device presents itself as a umass device with Windows
* drivers on it. After installation of the driver, it reinits into a
* 3G serial device.
*/
usb_device_request_t req;
usb_config_descriptor_t *cdesc;
/* Get the config descriptor */
cdesc = usbd_get_config_descriptor(dev);
if (cdesc == NULL)
return (UMATCH_NONE);
/* One iface means umass mode, more than 1 (4 usually) means 3G mode */
if (cdesc->bNumInterface > 1)
return (UMATCH_VENDOR_PRODUCT);
req.bmRequestType = UT_WRITE_DEVICE;
req.bRequest = UR_SET_FEATURE;
USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
USETW(req.wIndex, UHF_PORT_SUSPEND);
USETW(req.wLength, 0);
(void) usbd_do_request(dev, &req, 0);
return UMATCH_NONE; /* mismatch; it will be gone and reappear */
}
static int
u3g_match(device_t parent, cfdata_t match, void *aux)
{
struct usb_attach_arg *uaa = aux;
if (uaa->vendor == USB_VENDOR_HUAWEI)
return u3g_huawei_reinit(uaa->device);
if (usb_lookup(u3g_devs, uaa->vendor, uaa->product))
return UMATCH_VENDOR_PRODUCT;
return UMATCH_NONE;
}
static void
u3g_attach(device_t parent, device_t self, void *aux)
{
struct u3g_softc *sc = device_private(self);
struct usb_attach_arg *uaa = aux;
usbd_device_handle dev = uaa->device;
usbd_interface_handle iface;
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
usbd_status error;
int i, n;
usb_config_descriptor_t *cdesc;
aprint_naive("\n");
aprint_normal("\n");
sc->sc_dev = self;
#ifdef U3G_DEBUG
sc->sc_intr_number = -1;
sc->sc_intr_pipe = NULL;
#endif
/* Move the device into the configured state. */
error = usbd_set_config_index(dev, 0, 1);
if (error) {
aprint_error_dev(self, "failed to set configuration: %s\n",
usbd_errstr(error));
return;
}
/* get the config descriptor */
cdesc = usbd_get_config_descriptor(dev);
if (cdesc == NULL) {
aprint_error_dev(self, "failed to get configuration descriptor\n");
return;
}
sc->sc_udev = dev;
sc->numports = (cdesc->bNumInterface <= U3G_MAXPORTS)?cdesc->bNumInterface:U3G_MAXPORTS;
for ( i = 0; i < sc->numports; i++ ) {
struct ucom_attach_args uca;
error = usbd_device2interface_handle(dev, i, &iface);
if (error) {
aprint_error_dev(self,
"failed to get interface, err=%s\n",
usbd_errstr(error));
return;
}
id = usbd_get_interface_descriptor(iface);
uca.info = "Generic 3G Serial Device";
uca.ibufsize = U3GBUFSZ;
uca.obufsize = U3GBUFSZ;
uca.ibufsizepad = U3GBUFSZ;
uca.portno = i;
uca.opkthdrlen = 0;
uca.device = dev;
uca.iface = iface;
uca.methods = &u3g_methods;
uca.arg = sc;
uca.bulkin = uca.bulkout = -1;
for (n = 0; n < id->bNumEndpoints; n++) {
ed = usbd_interface2endpoint_descriptor(iface, n);
if (ed == NULL) {
aprint_error_dev(self,
"could not read endpoint descriptor\n");
return;
}
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
uca.bulkin = ed->bEndpointAddress;
else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
uca.bulkout = ed->bEndpointAddress;
}
if (uca.bulkin == -1 || uca.bulkout == -1) {
aprint_error_dev(self, "missing endpoint\n");
return;
}
sc->sc_ucom[i] = config_found_sm_loc(self, "ucombus", NULL, &uca,
ucomprint, ucomsubmatch);
}
#ifdef U3G_DEBUG
if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
error = usbd_open_pipe_intr(sc->sc_intr_iface,
sc->sc_intr_number,
USBD_SHORT_XFER_OK,
&sc->sc_intr_pipe,
sc,
sc->sc_intr_buf,
sc->sc_isize,
u3g_intr,
100);
if (error) {
aprint_error_dev(self,
"cannot open interrupt pipe (addr %d)\n",
sc->sc_intr_number);
return;
}
}
#endif
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
}
static int
u3g_detach(device_t self, int flags)
{
struct u3g_softc *sc = device_private(self);
int rv = 0;
int i;
pmf_device_deregister(self);
for (i = 0; i < sc->numports; i++) {
if(sc->sc_ucom[i]) {
rv = config_detach(sc->sc_ucom[i], flags);
if(rv != 0) {
aprint_verbose_dev(self, "Can't deallocat port %d", i);
return rv;
}
}
}
#ifdef U3G_DEBUG
if (sc->sc_intr_pipe != NULL) {
int err = usbd_abort_pipe(sc->sc_intr_pipe);
if (err)
aprint_error_dev(self,
"abort interrupt pipe failed: %s\n",
usbd_errstr(err));
err = usbd_close_pipe(sc->sc_intr_pipe);
if (err)
aprint_error_dev(self,
"close interrupt pipe failed: %s\n",
usbd_errstr(err));
free(sc->sc_intr_buf, M_USBDEV);
sc->sc_intr_pipe = NULL;
}
#endif
return 0;
}
static void
u3g_childdet(device_t self, device_t child)
{
struct u3g_softc *sc = device_private(self);
int i;
for (i = 0; i < sc->numports; i++) {
if (sc->sc_ucom[i] == child)
sc->sc_ucom[i] = NULL;
}
}
static int
u3g_activate(device_t self, enum devact act)
{
struct u3g_softc *sc = device_private(self);
int i, rv = 0;
switch (act) {
case DVACT_ACTIVATE:
return (EOPNOTSUPP);
break;
case DVACT_DEACTIVATE:
for (i = 0; i < sc->numports; i++) {
if (sc->sc_ucom[i] && config_deactivate(sc->sc_ucom[i]))
rv = -1;
}
break;
}
return (rv);
}
CFATTACH_DECL2_NEW(u3g, sizeof(struct u3g_softc), u3g_match,
u3g_attach, u3g_detach, u3g_activate, NULL, u3g_childdet);