svn commit: r183925 - head/sys/dev/usb

Nick Hibma n_hibma at FreeBSD.org
Wed Oct 15 21:25:12 UTC 2008


Author: n_hibma
Date: Wed Oct 15 21:25:11 2008
New Revision: 183925
URL: http://svn.freebsd.org/changeset/base/183925

Log:
  Rewrite the driver to better support the Huawei devices. It should now support
  the Sierra and Novatel devices, ignore all umass devices and hide the umass
  devices that represent the CD ROM devices (but not the SD card slot in the
  Huawei Mobile dongle).
  
  Note: This driver in FBSD7 seems to suffer from memory corruption when used
  with an Option GT Quad. The E220 however works flawlessly.
  
  Also add the ID for the Option GTMaxHSUPA, provided by Olivier Fromme.

Modified:
  head/sys/dev/usb/u3g.c
  head/sys/dev/usb/ubsa.c
  head/sys/dev/usb/usbdevs

Modified: head/sys/dev/usb/u3g.c
==============================================================================
--- head/sys/dev/usb/u3g.c	Wed Oct 15 20:44:00 2008	(r183924)
+++ head/sys/dev/usb/u3g.c	Wed Oct 15 21:25:11 2008	(r183925)
@@ -19,6 +19,14 @@
  * $FreeBSD$
  */
 
+/*
+ * Notes:
+ * - The detour through the tty layer is ridiculously expensive wrt buffering
+ *   due to the high speeds.
+ *   We should consider adding a simple r/w device which allows attaching of PPP
+ *   in a more efficient way.
+ */
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
@@ -40,43 +48,39 @@
 
 #include "usbdevs.h"
 
+#define U3G_DEBUG	1
 #ifdef U3G_DEBUG
-#define DPRINTFN(n, x)	do { if (u3gdebug > (n)) printf x; } while (0)
-int	u3gtebug = 0;
+#define DPRINTF(x...)		do { if (u3gdebug) device_printf(self, ##x); } while (0)
+#define DPRINTFN(n, x...)	do { if (u3gdebug > (n)) device_printf(self, ##x); } while (0)
+int	u3gdebug = 1;
 #else
-#define DPRINTFN(n, x)
+#define DPRINTF(x...)		/* nop */
+#define DPRINTFN(n, x...)	/* nop */
 #endif
-#define DPRINTF(x) DPRINTFN(0, x)
 
-#define U3G_BUFSIZ		1024
+#define U3G_BUFSIZ		10240
 #define U3G_MAXPORTS		4
 #define U3G_CONFIG_INDEX	0
 
 struct u3g_softc {
-	struct ucom_softc	sc_ucom[U3G_MAXPORTS];;
+	struct ucom_softc	sc_ucom[U3G_MAXPORTS];
 	device_t		sc_dev;
 	usbd_device_handle	sc_udev;
-	u_int16_t		sc_flags;
-	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;
+	u_int8_t		sc_speed;
+	u_int8_t		sc_flags;
+	u_char			sc_numports;
 };
 
+static int u3g_open(void *addr, int portno);
+static void u3g_close(void *addr, int portno);
+
 struct ucom_callback u3g_callback = {
 	NULL,
 	NULL,
 	NULL,
 	NULL,
-	NULL,
-	NULL,
+	u3g_open,
+	u3g_close,
 	NULL,
 	NULL,
 };
@@ -86,81 +90,106 @@ struct ucom_callback u3g_callback = {
  * Various supported device vendors/products.
  */
 struct u3g_dev_type_s {
-	struct usb_devno	u3g_dev;
-	u_int16_t		u3g_flags;
-#define U3GFL_NONE		0x0000
-#define U3GFL_HUAWEI_INIT	0x0001		/* Send USB command to reset iface to ucom mode */
+	struct usb_devno	devno;
+	u_int8_t		speed;
+#define U3GSP_GPRS		1
+#define U3GSP_EDGE		2
+#define U3GSP_UMTS		3
+#define U3GSP_HSDPA		4
+#define U3GSP_HSUPA		5
+#define U3GSP_HSPA		6
+
+	u_int8_t		flags;
+#define U3GFL_NONE		0x00
+#define U3GFL_HUAWEI_INIT	0x01		// Requires init (Huawei cards)
+#define U3GFL_STUB_WAIT		0x02		// Device reappears after a short delay
 };
 
 static const struct u3g_dev_type_s u3g_devs[] = {
 	/* OEM: Option */
-	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G },		U3GFL_NONE },
-	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD },		U3GFL_NONE },
-	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS },		U3GFL_NONE },
-	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36 },		U3GFL_NONE },
-	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G },	U3GFL_NONE },
+	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G },		U3GSP_UMTS,	U3GFL_NONE },
+	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD },		U3GSP_UMTS,	U3GFL_NONE },
+	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS },		U3GSP_UMTS,	U3GFL_NONE },
+	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36 },		U3GSP_HSDPA,	U3GFL_NONE },
+	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAXHSUPA },		U3GSP_HSDPA,	U3GFL_NONE },
+	{{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G },	U3GSP_UMTS,	U3GFL_NONE },
 	/* OEM: Qualcomm, Inc. */
-	{{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },	U3GFL_NONE },
+	{{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },	U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
 	/* OEM: Huawei */
-	/* Handled separately. Do not add!
-	{{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },		U3GFL_NONE },
-	{{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },		U3GFL_NONE },
-	 */
+	{{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },		U3GSP_HSDPA,	U3GFL_HUAWEI_INIT },
+	{{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },		U3GSP_HSDPA,	U3GFL_HUAWEI_INIT },
 	/* OEM: Novatel */
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM },	U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740 },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D },		U3GFL_NONE },
-	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 },		U3GFL_NONE },
-	{{ USB_VENDOR_DELL,    USB_PRODUCT_DELL_U740 },			U3GFL_NONE },
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM },	U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 },		U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D },		U3GSP_HSUPA,	U3GFL_STUB_WAIT },
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 },		U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727 },		U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740 },		U3GSP_HSDPA,	U3GFL_STUB_WAIT },
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2 },		U3GSP_HSDPA,	U3GFL_STUB_WAIT },
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870 },		U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620 },		U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640 },		U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720 },		U3GSP_UMTS,	U3GFL_STUB_WAIT },	// XXX
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740 },		U3GSP_HSDPA,	U3GFL_STUB_WAIT },
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D },		U3GSP_HSUPA,	U3GFL_STUB_WAIT },
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 },		U3GSP_HSDPA,	U3GFL_STUB_WAIT },
+	{{ USB_VENDOR_DELL,    USB_PRODUCT_DELL_U740 },			U3GSP_HSDPA,	U3GFL_STUB_WAIT },
+	/* OEM: Merlin */
+	{{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	/* OEM: Sierra Wireless: */
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
+	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },		U3GSP_UMTS,	U3GFL_NONE },		// XXX
 };
 #define u3g_lookup(v, p) ((const struct u3g_dev_type_s *)usb_lookup(u3g_devs, v, p))
 
-#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;
-	device_printf(sc->sc_dev, "Interrupt callback\n");
-}
-#endif
-
 static int
 u3g_match(device_t self)
 {
 	struct usb_attach_arg *uaa = device_get_ivars(self);
-	usb_interface_descriptor_t *id;
 	const struct u3g_dev_type_s *u3g_dev_type;
 
-	if (uaa->vendor == USB_VENDOR_HUAWEI) {
-		if (uaa->iface) {
-			/* We attach to the interface instead of the device as
-			 * some devices have a built-in SD card reader on the
-			 * second interface. If the interface class of the
-			 * first interface is no longer mass storage it has
-			 * changed appearance and we should attach it.
-			 */
-			id = usbd_get_interface_descriptor(uaa->iface);
-			if (id && id->bInterfaceClass == UICLASS_VENDOR)
-				return (UMATCH_VENDOR_PRODUCT_CONF_IFACE);
-		}
+	if (!uaa->iface)
 		return UMATCH_NONE;
-	}
 
 	u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product);
-	if (u3g_dev_type)
-		return UMATCH_VENDOR_PRODUCT;
+	if (!u3g_dev_type)
+		return UMATCH_NONE;
 
-	return UMATCH_NONE;
+	if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT) {
+		/* If the interface class of the first interface is no longer
+		 * mass storage the card has changed to modem (see u3g_attach()
+		 * below).
+		 */
+		usb_interface_descriptor_t *id;
+		id = usbd_get_interface_descriptor(uaa->iface);
+		if (!id || id->bInterfaceClass == UICLASS_MASS)
+			return UMATCH_NONE;
+	}
+
+	return UMATCH_VENDOR_PRODUCT_CONF_IFACE;
 }
 
 static int
@@ -168,120 +197,105 @@ u3g_attach(device_t self)
 {
 	struct u3g_softc *sc = device_get_softc(self);
 	struct usb_attach_arg *uaa = device_get_ivars(self);
+	const struct u3g_dev_type_s *u3g_dev_type;
 	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 *cd;
-	struct ucom_softc *ucom = NULL;
 	char devnamefmt[32];
 
-	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, U3G_CONFIG_INDEX, 1);
-	if (error) {
-		device_printf(self, "failed to set configuration: %s\n",
-			      usbd_errstr(error));
-		goto bad;
-	}
-
 	/* get the config descriptor */
 	cd = usbd_get_config_descriptor(dev);
-
 	if (cd == NULL) {
 		device_printf(self, "failed to get configuration descriptor\n");
-		goto bad;
+		return ENXIO;
 	}
 
+	sc->sc_dev = self;
 	sc->sc_udev = dev;
-	sc->numports = (cd->bNumInterface <= U3G_MAXPORTS)?cd->bNumInterface:U3G_MAXPORTS;
-	for ( i = 0; i < sc->numports; i++ ) {
-		ucom = &sc->sc_ucom[i];
-
-		ucom->sc_dev = self;
-		ucom->sc_udev = dev;
-		error = usbd_device2interface_handle(dev, i, &iface);
-		if (error) {
-			device_printf(ucom->sc_dev,
-				"failed to get interface, err=%s\n",
-			usbd_errstr(error));
-			ucom->sc_dying = 1;
-			goto bad;
+
+	u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product);
+	sc->sc_flags = u3g_dev_type->flags;
+	sc->sc_speed = u3g_dev_type->speed;
+
+	sprintf(devnamefmt,"U%d.%%d", device_get_unit(self));
+	int portno = 0;
+	for (i = 0; i < uaa->nifaces && portno < U3G_MAXPORTS; i++) {
+		if (uaa->ifaces[i] == NULL)
+			continue;
+
+		id = usbd_get_interface_descriptor(uaa->ifaces[i]);
+		if (id && id->bInterfaceClass == UICLASS_MASS) {
+			/* We attach to the interface instead of the device as
+			 * some devices have a built-in SD card reader.
+			 * Claim the first umass device (cdX) as it contains
+			 * only Windows drivers anyway (CD-ROM), hiding it.
+			 */
+#ifndef U3G_DEBUG
+			if (!bootverbose)
+				if (uaa->vendor == USB_VENDOR_HUAWEI)
+					if (id->bInterfaceNumber == 2)
+						uaa->ifaces[i] = NULL;
+#endif
+			continue;
 		}
-		id = usbd_get_interface_descriptor(iface);
-		ucom->sc_iface = iface;
 
-		ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
+		int bulkin_no = -1, bulkout_no = -1;
 		for (n = 0; n < id->bNumEndpoints; n++) {
-			ed = usbd_interface2endpoint_descriptor(iface, n);
-			if (ed == NULL) {
-				device_printf(ucom->sc_dev,
-					      "could not read endpoint descriptor\n");
-				goto bad;
-			}
+			ed = usbd_interface2endpoint_descriptor(uaa->ifaces[i], n);
+			if (ed == NULL)
+				continue;
 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
 			    && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
-				ucom->sc_bulkin_no = ed->bEndpointAddress;
+				bulkin_no = ed->bEndpointAddress;
 			else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT
 				 && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
-				ucom->sc_bulkout_no = ed->bEndpointAddress;
-		}
-		if (ucom->sc_bulkin_no == -1 || ucom->sc_bulkout_no == -1) {
-			device_printf(ucom->sc_dev, "missing endpoint\n");
-			goto bad;
-		}
-		ucom->sc_parent = sc;
-		ucom->sc_ibufsize = U3G_BUFSIZ;
-		ucom->sc_obufsize = U3G_BUFSIZ;
-		ucom->sc_ibufsizepad = U3G_BUFSIZ;
-		ucom->sc_opkthdrlen = 0;
-
-		ucom->sc_callback = &u3g_callback;
-
-		sprintf(devnamefmt,"U%d.%%d", device_get_unit(self));
-		DPRINTF(("u3g: in=0x%x out=0x%x, devname=%s\n",
-			 ucom->sc_bulkin_no, ucom->sc_bulkout_no, devnamefmt));
+				bulkout_no = ed->bEndpointAddress;
+
+			/* If we have found a pair of bulk-in/-out endpoints
+			 * create a serial port for it. Note: We assume that
+			 * the bulk-in and bulk-out endpoints appear in pairs.
+			 */
+			if (bulkin_no != -1 && bulkout_no != -1) {
+				struct ucom_softc *ucom = &sc->sc_ucom[portno];
+
+				ucom->sc_dev = self;
+				ucom->sc_udev = dev;
+				ucom->sc_iface = uaa->ifaces[i];
+				ucom->sc_bulkin_no = bulkin_no;
+				ucom->sc_ibufsize = U3G_BUFSIZ;
+				ucom->sc_ibufsizepad = U3G_BUFSIZ;	// XXX What's this?
+				ucom->sc_bulkout_no = bulkout_no;
+				ucom->sc_obufsize = U3G_BUFSIZ;
+				ucom->sc_opkthdrlen = 0;
+
+				ucom->sc_callback = &u3g_callback;
+				ucom->sc_parent = sc;
+				ucom->sc_portno = portno;
+
+				DPRINTF("port=%d iface=%d in=0x%x out=0x%x\n",
+					 portno, i,
+					 ucom->sc_bulkin_no,
+					 ucom->sc_bulkout_no);
 #if __FreeBSD_version < 800000
-		ucom_attach_tty(ucom, TS_CALLOUT, devnamefmt, i);
+				ucom_attach_tty(ucom, TS_CALLOUT, devnamefmt, portno);
 #else
-		ucom_attach_tty(ucom, devnamefmt, i);
+				ucom_attach_tty(ucom, devnamefmt, portno);
 #endif
-	}
-#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) {
-			device_printf(self,
-				      "cannot open interrupt pipe (addr %d)\n",
-				      sc->sc_intr_number);
-			goto bad;
+
+				uaa->ifaces[i] = NULL;
+				portno++;
+				bulkin_no = bulkout_no = -1;
+			}
 		}
+
 	}
-#endif
-	device_printf(self, "configured %d serial ports (/dev/cuaU%d.X)\n",
-		      sc->numports, device_get_unit(self));
+	sc->sc_numports = portno;
 
+	device_printf(self, "configured %d serial ports (%s)\n",
+		      sc->sc_numports, devnamefmt);
 	return 0;
-
-bad:
-	DPRINTF(("u3g_attach: ATTACH ERROR\n"));
-	ucom->sc_dying = 1;
-	return ENXIO;
 }
 
 static int
@@ -291,39 +305,98 @@ u3g_detach(device_t self)
 	int rv = 0;
 	int i;
 
-	DPRINTF(("u3g_detach: sc=%p\n", sc));
-
-	for (i = 0; i < sc->numports; i++) {
-		if(sc->sc_ucom[i].sc_udev) {
-			sc->sc_ucom[i].sc_dying = 1;
-			rv = ucom_detach(&sc->sc_ucom[i]);
-			if(rv != 0) {
-				device_printf(self, "Can't deallocat port %d\n", i);
-				return rv;
-			}
+	for (i = 0; i < sc->sc_numports; i++) {
+		sc->sc_ucom[i].sc_dying = 1;
+		rv = ucom_detach(&sc->sc_ucom[i]);
+		if (rv != 0) {
+			device_printf(self, "ucom_detach(U%d.%d\n", device_get_unit(self), i);
+			return rv;
 		}
 	}
 
+	return 0;
+}
+
+static int
+u3g_open(void *addr, int portno)
+{
+#if __FreeBSD_version < 800000
+	/* Supply generous buffering for these cards to avoid disappointments
+	 * when setting the speed incorrectly. Only do this for the first port
+	 * assuming that the rest of the ports are used for diagnostics only
+	 * anyway.
+	 * Note: We abuse the fact that ucom sets the speed through
+	 * ispeed/ospeed, not through ispeedwat/ospeedwat.
+	 */
+	if (portno == 0) {
+		struct u3g_softc *sc = addr;
+		struct ucom_softc *ucom = &sc->sc_ucom[portno];
+		struct tty *tp = ucom->sc_tty;
 #ifdef U3G_DEBUG
-	if (sc->sc_intr_pipe != NULL) {
-		int err = usbd_abort_pipe(sc->sc_intr_pipe);
-		if (err)
-			device_printf(self,
-				"abort interrupt pipe failed: %s\n",
-				usbd_errstr(err));
-		err = usbd_close_pipe(sc->sc_intr_pipe);
-		if (err)
-			device_printf(self,
-				      "close interrupt pipe failed: %s\n",
-				      usbd_errstr(err));
-		free(sc->sc_intr_buf, M_USBDEV);
-		sc->sc_intr_pipe = NULL;
+		device_t self = sc->sc_dev;
+#endif
+
+		if (sc->sc_speed&U3GSP_HSPA) {
+			tp->t_ispeedwat = 7200000;
+			tp->t_ospeedwat = 384000;
+		} else if (sc->sc_speed&U3GSP_HSUPA) {
+			tp->t_ispeedwat = 1200000;
+			tp->t_ospeedwat = 384000;
+		} else if (sc->sc_speed&U3GSP_HSDPA) {
+			tp->t_ispeedwat = 1200000;
+			tp->t_ospeedwat = 384000;
+		} else if (sc->sc_speed&U3GSP_UMTS) {
+			tp->t_ispeedwat = 384000;
+			tp->t_ospeedwat = 64000;
+		} else if (sc->sc_speed&U3GSP_EDGE) {
+			tp->t_ispeedwat = 384000;
+			tp->t_ospeedwat = 64000;
+		} else {
+			tp->t_ispeedwat = 64000;
+			tp->t_ospeedwat = 64000;
+		}
+
+		/* Avoid excessive buffer sizes. On modern fast machines this is
+		 * not needed.
+		 * XXX The values here should be checked. Lower them and see
+		 * whether 'lost chars' messages appear.
+		 */
+		if (tp->t_ispeedwat > 384000)
+		    tp->t_ispeedwat = 384000;
+		if (tp->t_ospeedwat > 384000)
+		    tp->t_ospeedwat = 384000;
+
+		DPRINTF("ispeedwat = %d, ospeedwat = %d\n",
+			tp->t_ispeedwat, tp->t_ospeedwat);
+		ttsetwater(tp);
 	}
 #endif
 
 	return 0;
 }
 
+static void
+u3g_close(void *addr, int portno)
+{
+#if __FreeBSD_version < 800000
+	if (portno == 0) {	/* see u3g_open() */
+		/* Reduce the buffers allocated above again */
+		struct u3g_softc *sc = addr;
+		struct ucom_softc *ucom = &sc->sc_ucom[portno];
+		struct tty *tp = ucom->sc_tty;
+#ifdef U3G_DEBUG
+		device_t self = sc->sc_dev;
+#endif
+
+		tp->t_ispeedwat = (speed_t)-1;
+		tp->t_ospeedwat = (speed_t)-1;
+
+		DPRINTF("ispeedwat = default, ospeedwat = default\n");
+		ttsetwater(tp);
+	}
+#endif
+}	
+
 static device_method_t u3g_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, u3g_match),
@@ -365,32 +438,29 @@ static int
 u3gstub_match(device_t self)
 {
 	struct usb_attach_arg *uaa = device_get_ivars(self);
-	usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
+	const struct u3g_dev_type_s *u3g_dev_type;
 	usb_interface_descriptor_t *id;
 
-	/* These are 3G modem devices (E220, Mobile, etc.) with auto-install
-	 * flash disks for Windows/MacOSX through the first interface.
+	/* This stub handles 3G modem devices (E220, Mobile, etc.) with
+	 * auto-install flash disks for Windows/MacOSX on the first interface.
+	 * After some command or some delay they change appearance to a modem.
 	 */
-	if (uaa->vendor == USB_VENDOR_HUAWEI) {
-		/* 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.
-		 */
-		if (uaa->iface) {
-			id = usbd_get_interface_descriptor(uaa->iface);
-			if (id && id->bInterfaceNumber == 0 && id->bInterfaceClass == UICLASS_MASS) {
-				u3gstub_huawei_init(uaa->device);
-				return (UMATCH_VENDOR_PRODUCT_CONF_IFACE);
-			}
-		}
-	}
 
-	if (UGETW(dd->idVendor) == USB_VENDOR_QUALCOMMINC
-	    || UGETW(dd->idVendor) == USB_VENDOR_NOVATEL) {
-		/* Device by these vendors will automatically reappear as a
-		 * ucom device if ignored (or if sent an eject command).
+	if (!uaa->iface)
+		return UMATCH_NONE;
+
+	u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product);
+	if (!u3g_dev_type)
+		return UMATCH_NONE;
+
+	if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT
+	    || u3g_dev_type->flags&U3GFL_STUB_WAIT) {
+		/* We assume that if the first interface is still a mass
+		 * storage device the device has not yet changed appearance.
 		 */
-		return UMATCH_VENDOR_PRODUCT;
+		id = usbd_get_interface_descriptor(uaa->iface);
+		if (id && id->bInterfaceNumber == 0 && id->bInterfaceClass == UICLASS_MASS)
+			return UMATCH_VENDOR_PRODUCT;
 	}
 
 	return UMATCH_NONE;
@@ -399,11 +469,28 @@ u3gstub_match(device_t self)
 static int
 u3gstub_attach(device_t self)
 {
-#if 0
-	if (!bootverbose)
+	struct usb_attach_arg *uaa = device_get_ivars(self);
+	const struct u3g_dev_type_s *u3g_dev_type;
+	int i;
+#ifndef U3G_DEBUG
+	if (!bootverbose)				// hide the stub attachment
 		device_quiet(self);
 #endif
 
+	if (uaa->iface)
+		for (i = 0; i < uaa->nifaces; i++)
+			uaa->ifaces[i] = NULL;		// claim all interfaces
+
+	u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product);
+	if (u3g_dev_type->flags&U3GFL_HUAWEI_INIT) {
+		/* XXX Should we delay the kick?
+		 */
+		DPRINTF("changing Huawei modem to modem mode\n");
+		u3gstub_huawei_init(uaa->device);
+	} else if (u3g_dev_type->flags&U3GFL_STUB_WAIT) {
+		/* nop  */
+	}
+
 	return 0;
 }
 

Modified: head/sys/dev/usb/ubsa.c
==============================================================================
--- head/sys/dev/usb/ubsa.c	Wed Oct 15 20:44:00 2008	(r183924)
+++ head/sys/dev/usb/ubsa.c	Wed Oct 15 21:25:11 2008	(r183925)
@@ -226,52 +226,6 @@ static const struct ubsa_product {
 	{ USB_VENDOR_GOHUBS, USB_PRODUCT_GOHUBS_GOCOM232 },
 	/* Peracom */
 	{ USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_SERIAL1 },
-	/* Merlin */
-	{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
-	/* Sierra Wireless AirCard 580 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
-	/* Sierra Wireless AirCard 595 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },
-	/* Sierra Wireless AirCard 595U */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },
-	/* Sierra Wireless AirCard 597E */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },
-	/* Sierra Wireless Compass 597 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },
-	/* Sierra Wireless AirCard 880 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },
-	/* Sierra Wireless AirCard 880E */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },
-	/* Sierra Wireless AirCard 880U */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },
-	/* Sierra Wireless AirCard 881 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },
-	/* Sierra Wireless AirCard 881E */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },
-	/* Sierra Wireless AirCard 881U */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },
-	/* Sierra Wireless EM5625 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },
-	/* Sierra Wireless MC5720 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },
-	/* Sierra Wireless MC5725 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },
-	/* Sierra Wireless MC8755 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },
-	/* Sierra Wireless MC8765 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },
-	/* Sierra Wireless MC8775 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },
-	/* Sierra Wireless MC8780 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },
-	/* Sierra Wireless MC8781 */
-	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },
 	{ 0, 0 }
 };
 

Modified: head/sys/dev/usb/usbdevs
==============================================================================
--- head/sys/dev/usb/usbdevs	Wed Oct 15 20:44:00 2008	(r183924)
+++ head/sys/dev/usb/usbdevs	Wed Oct 15 21:25:11 2008	(r183925)
@@ -1872,6 +1872,7 @@ product OPTION GT3G		0x6000	GlobeTrotter
 product OPTION GT3GQUAD		0x6300	GlobeTrotter 3G QUAD datacard
 product OPTION GT3GPLUS		0x6600	GlobeTrotter 3G+ datacard
 product OPTION GTMAX36		0x6701	GlobeTrotter Max 3.6 Modem
+product OPTION GTMAXHSUPA	0x7001	GlobeTrotter HSUPA
 
 /* OQO */
 product OQO WIFI01		0x0002	model 01 WiFi interface


More information about the svn-src-head mailing list