Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 23 Dec 2008 19:58:26 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 155195 for review
Message-ID:  <200812231958.mBNJwQQ2030240@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=155195

Change 155195 by hselasky@hselasky_laptop001 on 2008/12/23 19:57:37

	
	U3G cleanup - move Huawei ID's out of the USB core.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_device.c#42 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.c#7 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.h#7 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_msctest.c#15 edit
.. //depot/projects/usb/src/sys/dev/usb2/core/usb2_msctest.h#8 edit
.. //depot/projects/usb/src/sys/dev/usb2/serial/u3g2.c#3 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_device.c#42 (text+ko) ====

@@ -1635,7 +1635,7 @@
 					goto repeat_set_config;
 				}
 			}
-		} else if (usb2_test_huawei(udev, &uaa) == 0) {
+		} else if (usb2_test_huawei_autoinst_p(udev, &uaa) == 0) {
 			DPRINTFN(0, "Found Huawei auto-install disk!\n");
 			err = USB_ERR_STALLED;	/* fake an error */
 		}

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.c#7 (text+ko) ====

@@ -39,6 +39,7 @@
 static usb2_temp_setup_by_index_t usb2_temp_setup_by_index_w;
 static usb2_temp_unsetup_t usb2_temp_unsetup_w;
 static usb2_test_quirk_t usb2_test_quirk_w;
+static usb2_test_huawei_autoinst_t usb2_test_huawei_autoinst_w;
 static usb2_quirk_ioctl_t usb2_quirk_ioctl_w;
 
 /* global variables */
@@ -46,6 +47,7 @@
 usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p = &usb2_temp_setup_by_index_w;
 usb2_temp_unsetup_t *usb2_temp_unsetup_p = &usb2_temp_unsetup_w;
 usb2_test_quirk_t *usb2_test_quirk_p = &usb2_test_quirk_w;
+usb2_test_huawei_autoinst_t *usb2_test_huawei_autoinst_p = &usb2_test_huawei_autoinst_w;
 usb2_quirk_ioctl_t *usb2_quirk_ioctl_p = &usb2_quirk_ioctl_w;
 devclass_t usb2_devclass_ptr = NULL;
 
@@ -86,6 +88,13 @@
 	}
 }
 
+static uint8_t
+usb2_test_huawei_autoinst_w(struct usb2_device *udev,
+    struct usb2_attach_arg *uaa)
+{
+	return (USB_ERR_INVAL);
+}
+
 void
 usb2_quirk_unload(void *arg)
 {
@@ -130,3 +139,17 @@
 
 	pause("WAIT", hz);
 }
+
+void
+usb2_test_huawei_unload(void *arg)
+{
+	/* reset function pointers */
+
+	usb2_test_huawei_autoinst_p = &usb2_test_huawei_autoinst_w;
+
+	/* wait for CPU to exit the loaded functions, if any */
+
+	/* XXX this is a tradeoff */
+
+	pause("WAIT", 16*hz);
+}

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_dynamic.h#7 (text+ko) ====

@@ -37,6 +37,8 @@
 
 typedef usb2_error_t	(usb2_temp_setup_by_index_t)(struct usb2_device *udev,
 			    uint16_t index);
+typedef usb2_error_t	(usb2_test_huawei_autoinst_t)(struct usb2_device *udev, 
+			    struct usb2_attach_arg *uaa);
 typedef uint8_t		(usb2_test_quirk_t)(const struct usb2_lookup_info *info,
 			    uint16_t quirk);
 typedef int		(usb2_quirk_ioctl_t)(unsigned long cmd, caddr_t data,
@@ -52,11 +54,13 @@
 extern usb2_temp_setup_by_index_t *usb2_temp_setup_by_index_p;
 extern usb2_temp_unsetup_t *usb2_temp_unsetup_p;
 extern usb2_test_quirk_t *usb2_test_quirk_p;
+extern usb2_test_huawei_autoinst_t *usb2_test_huawei_autoinst_p;
 extern usb2_quirk_ioctl_t *usb2_quirk_ioctl_p;
 extern devclass_t usb2_devclass_ptr;
 
 /* function prototypes */
 
+void	usb2_test_huawei_unload(void *);
 void	usb2_temp_unload(void *);
 void	usb2_quirk_unload(void *);
 void	usb2_bus_unload(void *);

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_msctest.c#15 (text+ko) ====

@@ -36,7 +36,6 @@
 #include <dev/usb2/include/usb2_mfunc.h>
 #include <dev/usb2/include/usb2_error.h>
 #include <dev/usb2/include/usb2_standard.h>
-#include <dev/usb2/include/usb2_devid.h>
 
 #define	USB_DEBUG_VAR usb2_debug
 
@@ -577,164 +576,3 @@
 	free(sc, M_USB);
 	return (err);
 }
-
-/*
- * NOTE: The entries marked with XXX should be checked for the correct
- * speed indication to set the buffer sizes.
- */
-static const struct usb2_device_id u3g_devs[] = {
-	/* OEM: Option */
-	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
-	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
-	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
-	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
-	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAXHSUPA, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
-	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
-	/* OEM: Qualcomm, Inc. */
-	{USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_STOR, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
-	/* OEM: Huawei */
-	{USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE, U3GINFO(U3GSP_HSDPA, U3GFL_HUAWEI_INIT))},
-	{USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220, U3GINFO(U3GSP_HSPA, U3GFL_HUAWEI_INIT))},
-	/* OEM: Novatel */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
-	{USB_VPI(USB_VENDOR_DELL, USB_PRODUCT_DELL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
-	/* OEM: Merlin */
-	{USB_VPI(USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	/* OEM: Sierra Wireless: */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
-	{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HS2300, U3GINFO(U3GSP_HSPA, U3GFL_NONE))},	/* XXX */
-	/* Sierra TruInstaller device ID */
-	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL, U3GINFO(U3GSP_UMTS, U3GFL_SIERRA_INIT))},
-};
-
-static void
-u3g_sierra_init(struct usb2_device *udev)
-{
-	struct usb2_device_request req;
-
-	DPRINTFN(0, "\n");
-
-	req.bmRequestType = UT_VENDOR;
-	req.bRequest = UR_SET_INTERFACE;
-	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
-	USETW(req.wIndex, UHF_PORT_CONNECTION);
-	USETW(req.wLength, 0);
-
-	if (usb2_do_request_flags(udev, NULL, &req,
-	    NULL, 0, NULL, USB_MS_HZ)) {
-		/* ignore any errors */
-	}
-	return;
-}
-
-static void
-u3g_huawei_init(struct usb2_device *udev)
-{
-	struct usb2_device_request req;
-
-	DPRINTFN(0, "\n");
-
-	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);
-
-	if (usb2_do_request_flags(udev, NULL, &req,
-	    NULL, 0, NULL, USB_MS_HZ)) {
-		/* ignore any errors */
-	}
-	return;
-}
-
-int
-usb2_lookup_huawei(struct usb2_attach_arg *uaa)
-{
-	/* Calling the lookup function will also set the driver info! */
-	return (usb2_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa));
-}
-
-/*
- * The following function 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.
- */
-usb2_error_t
-usb2_test_huawei(struct usb2_device *udev, struct usb2_attach_arg *uaa)
-{
-	struct usb2_interface *iface;
-	struct usb2_interface_descriptor *id;
-	uint32_t flags;
-
-	if (udev == NULL) {
-		return (USB_ERR_INVAL);
-	}
-	iface = usb2_get_iface(udev, 0);
-	if (iface == NULL) {
-		return (USB_ERR_INVAL);
-	}
-	id = iface->idesc;
-	if (id == NULL) {
-		return (USB_ERR_INVAL);
-	}
-	if (id->bInterfaceClass != UICLASS_MASS) {
-		return (USB_ERR_INVAL);
-	}
-	if (usb2_lookup_huawei(uaa)) {
-		/* no device match */
-		return (USB_ERR_INVAL);
-	}
-	flags = USB_GET_DRIVER_INFO(uaa);
-
-	if (flags & U3GFL_HUAWEI_INIT) {
-		u3g_huawei_init(udev);
-	} else if (flags & U3GFL_SCSI_EJECT) {
-		return (usb2_test_autoinstall(udev, 0, 1));
-	} else if (flags & U3GFL_SIERRA_INIT) {
-		u3g_sierra_init(udev);
-	} else {
-		/* no quirks */
-		return (USB_ERR_INVAL);
-	}
-	return (0);			/* success */
-}

==== //depot/projects/usb/src/sys/dev/usb2/core/usb2_msctest.h#8 (text+ko) ====

@@ -29,30 +29,5 @@
 
 usb2_error_t usb2_test_autoinstall(struct usb2_device *udev,
 	    uint8_t iface_index, uint8_t do_eject);
-usb2_error_t usb2_test_huawei(struct usb2_device *udev,
-	    struct usb2_attach_arg *uaa);
-int	usb2_lookup_huawei(struct usb2_attach_arg *uaa);
-
-/* Huawei specific defines */
-
-#define	U3GINFO(flag,speed) ((flag)|((speed) * 256))
-#define	U3G_GET_SPEED(uaa) (USB_GET_DRIVER_INFO(uaa) / 256)
-
-#define	U3GFL_NONE		0x00
-#define	U3GFL_HUAWEI_INIT	0x01	/* Requires init command (Huawei
-					 * cards) */
-#define	U3GFL_SCSI_EJECT	0x02	/* Requires SCSI eject command
-					 * (Novatel) */
-#define	U3GFL_SIERRA_INIT	0x04	/* Requires init command (Sierra
-					 * cards) */
-
-#define	U3GSP_GPRS		0
-#define	U3GSP_EDGE		1
-#define	U3GSP_CDMA		2
-#define	U3GSP_UMTS		3
-#define	U3GSP_HSDPA		4
-#define	U3GSP_HSUPA		5
-#define	U3GSP_HSPA		6
-#define	U3GSP_MAX		7
 
 #endif					/* _USB2_MSCTEST_H_ */

==== //depot/projects/usb/src/sys/dev/usb2/serial/u3g2.c#3 (text+ko) ====

@@ -37,7 +37,7 @@
 #include <dev/usb2/include/usb2_standard.h>
 #include <dev/usb2/include/usb2_mfunc.h>
 #include <dev/usb2/include/usb2_error.h>
-#include <dev/usb2/include/usb2_cdc.h>
+#include <dev/usb2/include/usb2_defs.h>
 
 #define	USB_DEBUG_VAR u3g_debug
 
@@ -50,6 +50,8 @@
 #include <dev/usb2/core/usb2_util.h>
 #include <dev/usb2/core/usb2_busdma.h>
 #include <dev/usb2/core/usb2_msctest.h>
+#include <dev/usb2/core/usb2_dynamic.h>
+#include <dev/usb2/core/usb2_device.h>
 
 #include <dev/usb2/serial/usb2_serial.h>
 
@@ -66,6 +68,20 @@
 #define	U3G_CONFIG_INDEX	0
 #define	U3G_BSIZE		2048
 
+#define	U3GSP_GPRS		0
+#define	U3GSP_EDGE		1
+#define	U3GSP_CDMA		2
+#define	U3GSP_UMTS		3
+#define	U3GSP_HSDPA		4
+#define	U3GSP_HSUPA		5
+#define	U3GSP_HSPA		6
+#define	U3GSP_MAX		7
+
+#define	U3GFL_NONE		0x00	/* No flags */
+#define	U3GFL_HUAWEI_INIT	0x01	/* Init command required */
+#define	U3GFL_SCSI_EJECT	0x02	/* SCSI eject command required */
+#define	U3GFL_SIERRA_INIT	0x04	/* Init command required */
+
 struct u3g_speeds_s {
 	uint32_t ispeed;
 	uint32_t ospeed;
@@ -98,6 +114,8 @@
 static void u3g_start_write(struct usb2_com_softc *ucom);
 static void u3g_stop_write(struct usb2_com_softc *ucom);
 
+static int u3g_driver_loaded(struct module *mod, int what, void *arg);
+
 static const struct usb2_config u3g_config[U3G_N_TRANSFER] = {
 
 	[0] = {
@@ -151,10 +169,195 @@
 	.size = sizeof(struct u3g_softc),
 };
 
-DRIVER_MODULE(u3g, ushub, u3g_driver, u3g_devclass, NULL, 0);
+DRIVER_MODULE(u3g, ushub, u3g_driver, u3g_devclass, u3g_driver_loaded, 0);
 MODULE_DEPEND(u3g, usb2_serial, 1, 1, 1);
 MODULE_DEPEND(u3g, usb2_core, 1, 1, 1);
 
+/* Huawei specific defines */
+
+#define	U3GINFO(flag,speed) ((flag)|((speed) * 256))
+#define	U3G_GET_SPEED(uaa) (USB_GET_DRIVER_INFO(uaa) / 256)
+
+/*
+ * NOTE: The entries marked with XXX should be checked for the correct
+ * speed indication to set the buffer sizes.
+ */
+static const struct usb2_device_id u3g_devs[] = {
+	/* OEM: Option */
+	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
+	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAXHSUPA, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
+	{USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},
+	/* OEM: Qualcomm, Inc. */
+	{USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_STOR, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
+	/* OEM: Huawei */
+	{USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE, U3GINFO(U3GSP_HSDPA, U3GFL_HUAWEI_INIT))},
+	{USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220, U3GINFO(U3GSP_HSPA, U3GFL_HUAWEI_INIT))},
+	/* OEM: Novatel */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM, U3GINFO(U3GSP_CDMA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720, U3GINFO(U3GSP_UMTS, U3GFL_SCSI_EJECT))},	/* XXX */
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD, U3GINFO(U3GSP_HSUPA, U3GFL_SCSI_EJECT))},
+	{USB_VPI(USB_VENDOR_DELL, USB_PRODUCT_DELL_U740, U3GINFO(U3GSP_HSDPA, U3GFL_SCSI_EJECT))},
+	/* OEM: Merlin */
+	{USB_VPI(USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	/* OEM: Sierra Wireless: */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HS2300, U3GINFO(U3GSP_HSDPA, U3GFL_NONE))},
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781, U3GINFO(U3GSP_UMTS, U3GFL_NONE))},	/* XXX */
+	{USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HS2300, U3GINFO(U3GSP_HSPA, U3GFL_NONE))},	/* XXX */
+	/* Sierra TruInstaller device ID */
+	{USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL, U3GINFO(U3GSP_UMTS, U3GFL_SIERRA_INIT))},
+};
+
+static void
+u3g_sierra_init(struct usb2_device *udev)
+{
+	struct usb2_device_request req;
+
+	DPRINTFN(0, "\n");
+
+	req.bmRequestType = UT_VENDOR;
+	req.bRequest = UR_SET_INTERFACE;
+	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
+	USETW(req.wIndex, UHF_PORT_CONNECTION);
+	USETW(req.wLength, 0);
+
+	if (usb2_do_request_flags(udev, NULL, &req,
+	    NULL, 0, NULL, USB_MS_HZ)) {
+		/* ignore any errors */
+	}
+	return;
+}
+
+static void
+u3g_huawei_init(struct usb2_device *udev)
+{
+	struct usb2_device_request req;
+
+	DPRINTFN(0, "\n");
+
+	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);
+
+	if (usb2_do_request_flags(udev, NULL, &req,
+	    NULL, 0, NULL, USB_MS_HZ)) {
+		/* ignore any errors */
+	}
+	return;
+}
+
+static int
+u3g_lookup_huawei(struct usb2_attach_arg *uaa)
+{
+	/* Calling the lookup function will also set the driver info! */
+	return (usb2_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa));
+}
+
+/*
+ * The following function 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.
+ */
+static usb2_error_t
+u3g_test_huawei_autoinst(struct usb2_device *udev,
+    struct usb2_attach_arg *uaa)
+{
+	struct usb2_interface *iface;
+	struct usb2_interface_descriptor *id;
+	uint32_t flags;
+
+	if (udev == NULL) {
+		return (USB_ERR_INVAL);
+	}
+	iface = usb2_get_iface(udev, 0);
+	if (iface == NULL) {
+		return (USB_ERR_INVAL);
+	}
+	id = iface->idesc;
+	if (id == NULL) {
+		return (USB_ERR_INVAL);
+	}
+	if (id->bInterfaceClass != UICLASS_MASS) {
+		return (USB_ERR_INVAL);
+	}
+	if (u3g_lookup_huawei(uaa)) {
+		/* no device match */
+		return (USB_ERR_INVAL);
+	}
+	flags = USB_GET_DRIVER_INFO(uaa);
+
+	if (flags & U3GFL_HUAWEI_INIT) {
+		u3g_huawei_init(udev);
+	} else if (flags & U3GFL_SCSI_EJECT) {
+		return (usb2_test_autoinstall(udev, 0, 1));
+	} else if (flags & U3GFL_SIERRA_INIT) {
+		u3g_sierra_init(udev);
+	} else {
+		/* no quirks */
+		return (USB_ERR_INVAL);
+	}
+	return (0);			/* success */
+}
+
+static int
+u3g_driver_loaded(struct module *mod, int what, void *arg)
+{
+	switch (what) {
+	case MOD_LOAD:
+		/* register our autoinstall handler */
+		usb2_test_huawei_autoinst_p = &u3g_test_huawei_autoinst;
+		break;
+	case MOD_UNLOAD:
+		usb2_test_huawei_unload(NULL);
+		break;
+	default:
+		return (EOPNOTSUPP);
+	}
+ 	return (0);
+}
+
 static int
 u3g_probe(device_t self)
 {
@@ -169,7 +372,7 @@
 	if (uaa->info.bInterfaceClass != UICLASS_VENDOR) {
 		return (ENXIO);
 	}
-	return (usb2_lookup_huawei(uaa));
+	return (u3g_lookup_huawei(uaa));
 }
 
 static int



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