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

Nick Hibma n_hibma at FreeBSD.org
Mon Oct 13 20:41:11 UTC 2008


Author: n_hibma
Date: Mon Oct 13 20:41:11 2008
New Revision: 183843
URL: http://svn.freebsd.org/changeset/base/183843

Log:
  - Add better support for Huawei cards, by attaching as an interface driver.
  - Be bold and add Novatel cards to the list of supported devices. One person
    reported success with the Novatal U950D.

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

Modified: head/sys/dev/usb/u3g.c
==============================================================================
--- head/sys/dev/usb/u3g.c	Mon Oct 13 20:38:33 2008	(r183842)
+++ head/sys/dev/usb/u3g.c	Mon Oct 13 20:41:11 2008	(r183843)
@@ -1,8 +1,8 @@
 /*
  * Copyright (c) 2008 AnyWi Technologies
- *   Author: Andrea Guzzo <aguzzo at 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 *
+ * Author: Andrea Guzzo <aguzzo at 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
@@ -41,31 +41,33 @@
 #include "usbdevs.h"
 
 #ifdef U3G_DEBUG
-#define DPRINTFN(n, x)    do { if (u3gdebug > (n)) printf x; } while (0)
-int    u3gtebug = 0;
+#define DPRINTFN(n, x)	do { if (u3gdebug > (n)) printf x; } while (0)
+int	u3gtebug = 0;
 #else
 #define DPRINTFN(n, x)
 #endif
 #define DPRINTF(x) DPRINTFN(0, x)
 
-#define U3GBUFSZ        1024
-#define U3G_MAXPORTS           4
+#define U3G_BUFSIZ		1024
+#define U3G_MAXPORTS		4
+#define U3G_CONFIG_INDEX	0
 
 struct u3g_softc {
-	struct ucom_softc           sc_ucom[U3G_MAXPORTS];;
-	device_t                    sc_dev;
-	usbd_device_handle          sc_udev;
-	u_char                      sc_msr;
-	u_char                      sc_lsr;
-	u_char                      numports;
+	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 */
+	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 */
+	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;
+	int			sc_isize;
 };
 
 struct ucom_callback u3g_callback = {
@@ -79,49 +81,79 @@ struct ucom_callback u3g_callback = {
 	NULL,
 };
 
-static const struct usb_devno u3g_devs[] = {
+
+/*
+ * 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 */
+#define U3GFL_EJECT		0x0002		/* Send SCSI eject to reset first iface to ucom mode */
+};
+
+static const struct u3g_dev_type_s u3g_devs[] = {
 	/* OEM: Option */
-	{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G },
-	{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD },
-	{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS },
-	{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36 },
-	{ USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G },
+	{{ 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},
+	/* OEM: Qualcomm, Inc. */
+	{{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },	U3GFL_EJECT},
 	/* OEM: Huawei */
-	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
-	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
-	/* OEM: Qualcomm */
-	{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },
-
-	{ 0, 0 }
+	{{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },		U3GFL_HUAWEI_INIT},
+	{{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },		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_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_U950D },		U3GFL_EJECT },
+	{{ 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_U870 },		U3GFL_NONE },
+	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 },		U3GFL_NONE },
+	{{ USB_VENDOR_DELL,    USB_PRODUCT_DELL_U740 },			U3GFL_NONE },
 };
+#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");
+	device_printf(sc->sc_dev, "Interrupt callback\n");
 }
 #endif
 
 static int
-u3g_huawei_reinit(usbd_device_handle dev)
+u3g_huawei_reinit(usbd_device_handle dev, usbd_interface_handle iface)
 {
 	/* 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;
+	usb_interface_descriptor_t *idesc;
 
-	/* Get the config descriptor */
-	cdesc = usbd_get_config_descriptor(dev);
-	if (cdesc == NULL)
-		return (UMATCH_NONE);
+	if (iface == NULL)
+		return UMATCH_NONE;
+	idesc = usbd_get_interface_descriptor(iface);
+	if (idesc == 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);
+	/* If the interface class is no longer mass storage it has changed
+	 * appearance and we should attach it.
+	 */
+	if (idesc->bInterfaceClass == UICLASS_VENDOR)
+		return (UMATCH_VENDOR_PRODUCT_CONF_IFACE);
 
 	req.bmRequestType = UT_WRITE_DEVICE;
 	req.bRequest = UR_SET_FEATURE;
@@ -139,15 +171,14 @@ u3g_match(device_t self)
 {
 	struct usb_attach_arg *uaa = device_get_ivars(self);
 
-	if (uaa->iface != NULL)
-		return (UMATCH_NONE);
-
-	if (uaa->vendor == USB_VENDOR_HUAWEI)
-		return u3g_huawei_reinit(uaa->device);
+	const struct u3g_dev_type_s *u3g_dev_type = u3g_lookup(uaa->vendor, uaa->product);
+	if (u3g_dev_type) {
+		if (u3g_dev_type->u3g_flags & U3GFL_HUAWEI_INIT)
+			return u3g_huawei_reinit(uaa->device, uaa->iface);
+		else
+			return UMATCH_VENDOR_PRODUCT;
+	}
 
-	if (usb_lookup(u3g_devs, uaa->vendor, uaa->product))
-		return UMATCH_VENDOR_PRODUCT;
-	
 	return UMATCH_NONE;
 }
 
@@ -172,7 +203,7 @@ u3g_attach(device_t self)
 	sc->sc_intr_pipe = NULL;
 #endif
 	/* Move the device into the configured state. */
-	error = usbd_set_config_index(dev, 1, 1);
+	error = usbd_set_config_index(dev, U3G_CONFIG_INDEX, 1);
 	if (error) {
 		device_printf(self, "failed to set configuration: %s\n",
 			      usbd_errstr(error));
@@ -210,14 +241,14 @@ u3g_attach(device_t self)
 			ed = usbd_interface2endpoint_descriptor(iface, n);
 			if (ed == NULL) {
 				device_printf(ucom->sc_dev,
-					"could not read endpoint descriptor\n");
+					      "could not read endpoint descriptor\n");
 				goto bad;
 			}
-			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
-			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
+			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN
+			    && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
 				ucom->sc_bulkin_no = ed->bEndpointAddress;
-			else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
-			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
+			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) {
@@ -225,9 +256,9 @@ u3g_attach(device_t self)
 			goto bad;
 		}
 		ucom->sc_parent = sc;
-		ucom->sc_ibufsize = U3GBUFSZ;
-		ucom->sc_obufsize = U3GBUFSZ;
-		ucom->sc_ibufsizepad = U3GBUFSZ;
+		ucom->sc_ibufsize = U3G_BUFSIZ;
+		ucom->sc_obufsize = U3G_BUFSIZ;
+		ucom->sc_ibufsizepad = U3G_BUFSIZ;
 		ucom->sc_opkthdrlen = 0;
 
 		ucom->sc_callback = &u3g_callback;
@@ -254,14 +285,14 @@ u3g_attach(device_t self)
 					    u3g_intr,
 					    100);
 		if (error) {
-		    device_printf(self,
-			    "cannot open interrupt pipe (addr %d)\n",
-			    sc->sc_intr_number);
-		    goto bad;
+			device_printf(self,
+				      "cannot open interrupt pipe (addr %d)\n",
+				      sc->sc_intr_number);
+			goto bad;
 		}
 	}
 #endif
-	device_printf(self, "configured %d serial ports (/dev/cuaU%d.X)",
+	device_printf(self, "configured %d serial ports (/dev/cuaU%d.X)\n",
 		      sc->numports, device_get_unit(self));
 
 	return 0;
@@ -286,7 +317,7 @@ u3g_detach(device_t self)
 			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", i);
+				device_printf(self, "Can't deallocat port %d\n", i);
 				return rv;
 			}
 		}
@@ -302,8 +333,8 @@ u3g_detach(device_t self)
 		err = usbd_close_pipe(sc->sc_intr_pipe);
 		if (err)
 			device_printf(self,
-			    "close interrupt pipe failed: %s\n",
-			    usbd_errstr(err));
+				      "close interrupt pipe failed: %s\n",
+				      usbd_errstr(err));
 		free(sc->sc_intr_buf, M_USBDEV);
 		sc->sc_intr_pipe = NULL;
 	}

Modified: head/sys/dev/usb/ubsa.c
==============================================================================
--- head/sys/dev/usb/ubsa.c	Mon Oct 13 20:38:33 2008	(r183842)
+++ head/sys/dev/usb/ubsa.c	Mon Oct 13 20:41:11 2008	(r183843)
@@ -228,34 +228,6 @@ static const struct ubsa_product {
 	{ USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_SERIAL1 },
 	/* Merlin */
 	{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
-	/* Novatel */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM },
-	/* Novatel Wireless Merlin ES620 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620 },
-	/* Novatel Wireless Merlin U720 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720 },
-	/* Novatel Wireless Merlin U727 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727 },
-	/* Novatel Wireless Merlin U740 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740 },
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2 },
-	/* Dell version of the Novatel 740 */
-	{ USB_VENDOR_DELL, USB_PRODUCT_DELL_U740 },
-	/* Novatel Wireless Merlin U950D */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U950D },
-	/* Novatel Wireless Merlin V620 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620 },
-	/* Novatel Wireless Merlin V640 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640 },
-	/* Novatel Wireless Merlin V720 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720 },
-	/* Novatel Wireless Merlin V740 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740 },
-	/* Novatel Wireless Merlin X950D */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D },
-	/* Novatel Wireless Merlin U870 */
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870 },
-	{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870 },
 	/* Sierra Wireless AirCard 580 */
 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
 	/* Sierra Wireless AirCard 595 */


More information about the svn-src-head mailing list