Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Jul 2010 03:10:22 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r210275 - in head: share/man/man4 sys/dev/usb sys/dev/usb/net
Message-ID:  <201007200310.o6K3AMLe067018@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Tue Jul 20 03:10:22 2010
New Revision: 210275
URL: http://svn.freebsd.org/changeset/base/210275

Log:
  - Support for Globetrotter iCON 452.
  - Fixed the interface probe routine to only attach to USB interfaces the driver
    actually supports.  This allows other drivers to attach to things like
    MicroSD slots etc.
  - Fixed network interface enumeration to be globally sequential instead of
    relying on the USB interface numbers.  This make sure the first network
    interface always is at uhso0 and the second at usho1 and so on.
  - Added a radio kill switch; exposed through sysctl.
  - Updated the manual page to be verbose about the number of serial ports and
    include iCON 452 in the set of tested hardware.
  
  Submitted by:	Fredrik Lindberg

Modified:
  head/share/man/man4/uhso.4
  head/sys/dev/usb/net/uhso.c
  head/sys/dev/usb/usbdevs

Modified: head/share/man/man4/uhso.4
==============================================================================
--- head/share/man/man4/uhso.4	Tue Jul 20 02:23:12 2010	(r210274)
+++ head/share/man/man4/uhso.4	Tue Jul 20 03:10:22 2010	(r210275)
@@ -43,8 +43,9 @@ 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 .
+driver which makes them behave like
+.Xr tty 4
+devices.
 The packet interface is exposed as a network interface.
 .Pp
 Establishing a connection on the packet interface is achieved by using the
@@ -60,10 +61,19 @@ these calls.
 Each device usually have at least two or more serial ports, their individual purpose
 can be identified through
 .Xr sysctl 8 .
+Ports identified as
+.Dq Modem
+features a normal modem interface that can be used with PPP.
+Ports identified as
+.Dq Diagnostic
+uses a proprietary binary interface used for firmware upgrades, this port does not
+have a AT command interface and can not be used to control the device.
+Other ports features an AT command interface that can be used for normal device control.
 .Sh HARDWARE
 The
 .Nm
-driver supports at least the following cards
+driver should work with most devices from Option.
+The following devices have been verified to work
 .Pp
 .Bl -bullet -compact
 .It
@@ -71,6 +81,8 @@ Option GlobeSurfer iCON 7.2 (new firmwar
 .It
 Option iCON 225
 .It
+Option iCON 452
+.It
 Option iCON 505
 .El
 .Pp
@@ -92,7 +104,8 @@ to 0 using
 .It Pa /dev/cuaU?.?
 .El
 .Sh EXAMPLES
-Establishing a packet interface connection
+Establishing a packet interface connection using the AT command interface available
+at one of the serial ports
 .Bd -literal -offset indent
 AT+CGDCONT=1,,"apn.provider"
 AT_OWANCALL=1,1,1

Modified: head/sys/dev/usb/net/uhso.c
==============================================================================
--- head/sys/dev/usb/net/uhso.c	Tue Jul 20 02:23:12 2010	(r210274)
+++ head/sys/dev/usb/net/uhso.c	Tue Jul 20 03:10:22 2010	(r210275)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2009 Fredrik Lindberg <fli@shapeshifter.se>
+ * Copyright (c) 2010 Fredrik Lindberg <fli@shapeshifter.se>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/conf.h>
 #include <sys/bus.h>
 #include <sys/systm.h>
+#include <sys/limits.h>
 
 #include <machine/bus.h>
 
@@ -81,6 +82,7 @@ struct uhso_softc {
 	struct usb_device	*sc_udev;
 	struct mtx		sc_mtx;
 	uint32_t		sc_type;	/* Interface definition */
+	int			sc_radio;
 
 	struct usb_xfer		*sc_xfer[3];
 	uint8_t			sc_iface_no;
@@ -155,6 +157,7 @@ struct uhso_softc {
  * Note that these definitions are arbitrary and do not match the values
  * returned by the auto config descriptor.
  */
+#define UHSO_PORT_TYPE_UNKNOWN	0x00
 #define UHSO_PORT_TYPE_CTL	0x01
 #define UHSO_PORT_TYPE_APP	0x02
 #define UHSO_PORT_TYPE_APP2	0x03
@@ -185,7 +188,7 @@ static char *uhso_port[] = {
  * descriptor values.
  */
 static unsigned char uhso_port_map[] = {
-	0,
+	UHSO_PORT_TYPE_UNKNOWN,
 	UHSO_PORT_TYPE_DIAG,
 	UHSO_PORT_TYPE_GPS,
 	UHSO_PORT_TYPE_GPSCTL,
@@ -243,6 +246,9 @@ static char *uhso_port_type_sysctl[] = {
 #define UHSO_STATIC_IFACE	0x01
 #define UHSO_AUTO_IFACE		0x02
 
+/* ifnet device unit allocations */
+static struct unrhdr *uhso_ifnet_unit = NULL;
+
 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 */
@@ -272,6 +278,8 @@ static const struct usb_device_id uhso_d
 	UHSO_DEV(OPTION, GTICON322, UHSO_STATIC_IFACE),
 	/* Option iCON 505 */
 	UHSO_DEV(OPTION, ICON505, UHSO_AUTO_IFACE),
+	/* Option iCON 452 */
+	UHSO_DEV(OPTION, ICON505, UHSO_AUTO_IFACE),
 #undef UHSO_DEV
 };
 
@@ -432,9 +440,9 @@ static const struct usb_config uhso_bs_c
 };
 
 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);
+    int (*probe)(struct usb_device *, int));
+static int  uhso_probe_iface_auto(struct usb_device *, int);
+static int  uhso_probe_iface_static(struct usb_device *, 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 *,
@@ -444,6 +452,8 @@ static int  uhso_attach_ifnet(struct uhs
 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_radio_sysctl(SYSCTL_HANDLER_ARGS);
+static int uhso_radio_ctrl(struct uhso_softc *, int);
 
 static void uhso_ucom_start_read(struct ucom_softc *);
 static void uhso_ucom_stop_read(struct ucom_softc *);
@@ -497,6 +507,7 @@ static int
 uhso_probe(device_t self)
 {
 	struct usb_attach_arg *uaa = device_get_ivars(self);
+	int error;
 
 	if (uaa->usb_mode != USB_MODE_HOST)
 		return (ENXIO);
@@ -505,7 +516,20 @@ uhso_probe(device_t self)
 	if (uaa->device->ddesc.bDeviceClass != 0xff)
 		return (ENXIO);
 
-	return (usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa));
+	error = usbd_lookup_id_by_uaa(uhso_devs, sizeof(uhso_devs), uaa);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Probe device to see if we are able to attach
+	 * to this interface or not.
+	 */
+	if (USB_GET_DRIVER_INFO(uaa) == UHSO_AUTO_IFACE) {
+		if (uhso_probe_iface_auto(uaa->device,
+		    uaa->info.bIfaceNum) == 0)
+			return (ENXIO);
+	}
+	return (error);
 }
 
 static int
@@ -517,7 +541,7 @@ uhso_attach(device_t self)
 	struct usb_interface_descriptor *id;
 	struct sysctl_ctx_list *sctx;
 	struct sysctl_oid *soid;
-	struct sysctl_oid *tree, *tty_node;
+	struct sysctl_oid *tree = NULL, *tty_node;
 	struct ucom_softc *ucom;
 	struct uhso_tty *ht;
 	int i, error, port;
@@ -531,6 +555,7 @@ uhso_attach(device_t self)
 
 	sc->sc_ucom = NULL;
 	sc->sc_ttys = 0;
+	sc->sc_radio = 1;
 
 	cd = usbd_get_config_descriptor(uaa->device);
 	id = usbd_get_interface_descriptor(uaa->iface);
@@ -566,6 +591,8 @@ uhso_attach(device_t self)
 	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");
+	SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "radio",
+	    CTLTYPE_INT | CTLFLAG_RW, sc, 0, uhso_radio_sysctl, "I", "Enable radio");
 
 	/*
 	 * The default interface description on most Option devices isn't
@@ -655,6 +682,7 @@ uhso_detach(device_t self)
 
 	if (sc->sc_ifp != NULL) {
 		callout_drain(&sc->sc_c);
+		free_unr(uhso_ifnet_unit, sc->sc_ifp->if_dunit);
 		mtx_lock(&sc->sc_mtx);
 		uhso_if_stop(sc);
 		bpfdetach(sc->sc_ifp);
@@ -701,9 +729,12 @@ uhso_driver_loaded(struct module *mod, i
 		/* register our autoinstall handler */
 		uhso_etag = EVENTHANDLER_REGISTER(usb_dev_configured,
 		    uhso_test_autoinst, NULL, EVENTHANDLER_PRI_ANY);
+		/* create our unit allocator for inet devs */
+		uhso_ifnet_unit = new_unrhdr(0, INT_MAX, NULL);
 		break;
 	case MOD_UNLOAD:
 		EVENTHANDLER_DEREGISTER(usb_dev_configured, uhso_etag);
+		delete_unrhdr(uhso_ifnet_unit);
 		break;
 	default:
 		return (EOPNOTSUPP);
@@ -717,7 +748,7 @@ uhso_driver_loaded(struct module *mod, i
  * Returns a bit mask with the interface capabilities.
  */
 static int
-uhso_probe_iface_auto(struct uhso_softc *sc, int index)
+uhso_probe_iface_auto(struct usb_device *udev, int index)
 {
 	struct usb_device_request req;
 	usb_error_t uerr;
@@ -731,11 +762,11 @@ uhso_probe_iface_auto(struct uhso_softc 
 	USETW(req.wIndex, 0);
 	USETW(req.wLength, 17);
 
-	uerr = usbd_do_request_flags(sc->sc_udev, NULL, &req, buf,
+	uerr = usbd_do_request_flags(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));
+		printf("%s: usbd_do_request_flags failed, %s\n",
+		    __func__, usbd_errstr(uerr));
 		return (0);
 	}
 
@@ -759,23 +790,35 @@ uhso_probe_iface_auto(struct uhso_softc 
 	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);
-	default:
+	case UHSO_PORT_TYPE_DIAG:
+	case UHSO_PORT_TYPE_DIAG2:
+	case UHSO_PORT_TYPE_CTL:
+	case UHSO_PORT_TYPE_APP:
+	case UHSO_PORT_TYPE_APP2:
+	case UHSO_PORT_TYPE_MODEM:
 		return (UHSO_IFACE_SPEC(UHSO_IF_BULK,
 		    UHSO_PORT_SERIAL, port));
+	case UHSO_PORT_TYPE_MSD:
+		return (0);
+	case UHSO_PORT_TYPE_UNKNOWN:
+	default:
+		return (0);
 	}
 
 	return (0);
 }
 
+/*
+ * Returns the capabilities of interfaces for devices that don't
+ * support the automatic query.
+ * Returns a bit mask with the interface capabilities.
+ */
 static int
-uhso_probe_iface_static(struct uhso_softc *sc, int index)
+uhso_probe_iface_static(struct usb_device *udev, int index)
 {
 	struct usb_config_descriptor *cd;
 
-	cd = usbd_get_config_descriptor(sc->sc_udev);
+	cd = usbd_get_config_descriptor(udev);
 	if (cd->bNumInterface <= 3) {
 		/* Cards with 3 or less interfaces */
 		switch (index) {
@@ -817,14 +860,14 @@ uhso_probe_iface_static(struct uhso_soft
  */
 static int
 uhso_probe_iface(struct uhso_softc *sc, int index,
-    int (*probe)(struct uhso_softc *, int))
+    int (*probe)(struct usb_device *, int))
 {
 	struct usb_interface *iface;
 	int type, error;
 
 	UHSO_DPRINTF(1, "Probing for interface %d, probe_func=%p\n", index, probe);
 
-	type = probe(sc, index);
+	type = probe(sc->sc_udev, index);
 	UHSO_DPRINTF(1, "Probe result %x\n", type);
 	if (type <= 0)
 		return (ENXIO);
@@ -888,6 +931,47 @@ uhso_probe_iface(struct uhso_softc *sc, 
 	return (0);
 }
 
+static int
+uhso_radio_ctrl(struct uhso_softc *sc, int onoff)
+{
+	struct usb_device_request req;
+	usb_error_t uerr;
+
+	req.bmRequestType = UT_VENDOR;
+	req.bRequest = onoff ? 0x82 : 0x81;
+	USETW(req.wValue, 0);
+	USETW(req.wIndex, 0);
+	USETW(req.wLength, 0);
+
+	uerr = usbd_do_request(sc->sc_udev, NULL, &req, NULL);
+	if (uerr != 0) {
+		device_printf(sc->sc_dev, "usbd_do_request_flags failed: %s\n",
+		    usbd_errstr(uerr));
+		return (-1);
+	}
+	return (onoff);
+}
+
+static int
+uhso_radio_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct uhso_softc *sc = arg1;
+	int error, radio;
+
+	radio = sc->sc_radio;
+	error = sysctl_handle_int(oidp, &radio, 0, req);
+	if (error)
+		return (error);
+	if (radio != sc->sc_radio) {
+		radio = radio != 0 ? 1 : 0;
+		error = uhso_radio_ctrl(sc, radio);
+		if (error != -1)
+			sc->sc_radio = radio;
+			
+	}	
+	return (0);
+}
+
 /*
  * Expands allocated memory to fit an additional TTY.
  * Two arrays are kept with matching indexes, one for ucom and one
@@ -1435,13 +1519,14 @@ uhso_ucom_stop_write(struct ucom_softc *
 	}
 }
 
-static int uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface,
-    int type)
+static int
+uhso_attach_ifnet(struct uhso_softc *sc, struct usb_interface *iface, int type)
 {
 	struct ifnet *ifp;
 	usb_error_t uerr;
 	struct sysctl_ctx_list *sctx;
 	struct sysctl_oid *soid;
+	unsigned int devunit;
 
 	uerr = usbd_transfer_setup(sc->sc_udev,
 	    &iface->idesc->bInterfaceNumber, sc->sc_if_xfer,
@@ -1463,7 +1548,14 @@ static int uhso_attach_ifnet(struct uhso
 	callout_reset(&sc->sc_c, 1, uhso_if_rxflush, sc);
 	mtx_unlock(&sc->sc_mtx);
 
-	if_initname(ifp, device_get_name(sc->sc_dev), device_get_unit(sc->sc_dev));
+	/*
+	 * We create our own unit numbers for ifnet devices because the
+	 * USB interface unit numbers can be at arbitrary positions yielding
+	 * odd looking device names.
+	 */
+	devunit = alloc_unr(uhso_ifnet_unit);
+
+	if_initname(ifp, device_get_name(sc->sc_dev), devunit);
 	ifp->if_mtu = UHSO_MAX_MTU;
 	ifp->if_ioctl = uhso_if_ioctl;
 	ifp->if_init = uhso_if_init;

Modified: head/sys/dev/usb/usbdevs
==============================================================================
--- head/sys/dev/usb/usbdevs	Tue Jul 20 02:23:12 2010	(r210274)
+++ head/sys/dev/usb/usbdevs	Tue Jul 20 03:10:22 2010	(r210275)
@@ -2301,6 +2301,7 @@ product OPTION ICONEDGE		0xc031	GlobeSur
 product OPTION MODHSXPA		0xd013	Globetrotter HSUPA
 product OPTION ICON321		0xd031	Globetrotter HSUPA
 product OPTION ICON505		0xd055	Globetrotter iCON 505
+product OPTION_ICON452		0x7901	Globetrotter iCON 452
 
 /* OvisLink product */
 product OVISLINK RT3072		0x3072	RT3072



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007200310.o6K3AMLe067018>