From db5825abd5fe47fe46388b7750ea91278c40cd0e Mon Sep 17 00:00:00 2001 From: joerg Date: Fri, 10 Oct 2008 16:37:15 +0000 Subject: [PATCH] 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. --- distrib/sets/lists/man/mi | 5 +- share/man/man4/Makefile | 4 +- share/man/man4/u3g.4 | 102 ++++++++++++ sys/dev/usb/files.usb | 7 +- sys/dev/usb/u3g.c | 330 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 444 insertions(+), 4 deletions(-) create mode 100644 share/man/man4/u3g.4 create mode 100644 sys/dev/usb/u3g.c diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi index 96ae56979808..999f2f1219de 100644 --- a/distrib/sets/lists/man/mi +++ b/distrib/sets/lists/man/mi @@ -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 diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index fc20dbe4b280..cade06726fe3 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -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 \ diff --git a/share/man/man4/u3g.4 b/share/man/man4/u3g.4 new file mode 100644 index 000000000000..7b7f649898d0 --- /dev/null +++ b/share/man/man4/u3g.4 @@ -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. diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 8df5ae7c47fc..6cd7f6ed09ba 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -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 diff --git a/sys/dev/usb/u3g.c b/sys/dev/usb/u3g.c new file mode 100644 index 000000000000..ea0a70df1cd2 --- /dev/null +++ b/sys/dev/usb/u3g.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2008 AnyWi Technologies + * Author: Andrea Guzzo + * * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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);