Subject: kern/37600: [PATCH] HUAWEI E220 (Emobile D02HW - japan) support
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <yuo@nui.org>
List: netbsd-bugs
Date: 12/23/2007 11:50:00
>Number:         37600
>Category:       kern
>Synopsis:       add HUAWEI E220 data modem support to ubsa serial driver
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Dec 23 11:50:00 +0000 2007
>Originator:     Yojiro UO
>Release:        NetBSD 4.99.44
>Organization:
	
>Environment:
	
	
System: NetBSD robohoc-ha 4.99.44 NetBSD 4.99.44 (ALIX) #101: Sun Dec 23 15:27:37 JST 2007 yuo@ns.robohoc.net:/Volumes/work/Users2/yuo/ROBOHOC/NetBSD-original/src/sys/arch/i386/compile/obj/ALIX i386
Architecture: i386
Machine: i386
>Description:
	New device (HUAWEI E220 aka D02HW in Japan) suppot to 
	ubsa serial driver.
	The device needs special USB request to enable modem function
	(default umass driver will be used to attach as umass disk).
	This patch allow to attach the device as ubsa modem.

	Note: this patch contains umass_quirks part to disable storage
	function of the device. If you don't need it, please ignore.

>How-To-Repeat:
	apply following patch
>Fix:
	apply following patch


Index: ubsa.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ubsa.c,v
retrieving revision 1.19
diff -u -r1.19 ubsa.c
--- ubsa.c	13 Mar 2007 13:51:55 -0000	1.19
+++ ubsa.c	23 Dec 2007 10:20:44 -0000
@@ -95,8 +95,9 @@
 
 #include <dev/usb/ucomvar.h>
 
+#define UBSA_DEBUG
 #ifdef UBSA_DEBUG
-Static int	ubsadebug = 0;
+Static int	ubsadebug = 1;
 #ifdef __FreeBSD__
 SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa");
 SYSCTL_INT(_hw_usb_ubsa, OID_AUTO, debug, CTLFLAG_RW,
@@ -114,7 +115,7 @@
 
 #define	UBSA_MODVER		1	/* module version */
 
-#define	UBSA_CONFIG_INDEX	1
+#define	UBSA_DEFAULT_CONFIG_INDEX	1
 #define	UBSA_IFACE_INDEX	0
 
 #define	UBSA_INTR_INTERVAL	100	/* ms */
@@ -174,6 +175,7 @@
 	usbd_interface_handle	sc_iface;	/* interface */
 
 	int			sc_iface_number;	/* interface number */
+	int			sc_config_index;	/* USB CONFIG_INDEX */
 
 	int			sc_intr_number;	/* interrupt number */
 	usbd_pipe_handle	sc_intr_pipe;	/* interrupt pipe */
@@ -190,6 +192,7 @@
 
 	u_char			sc_dying;	/* disconnecting */
 	u_char			sc_quadumts;
+	int			sc_devtype_e220;	/* hauwei e220 */
 
 };
 
@@ -213,6 +216,8 @@
 Static	void ubsa_stopbits(struct ubsa_softc *, tcflag_t);
 Static	void ubsa_flow(struct ubsa_softc *, tcflag_t, tcflag_t);
 
+Static  usbd_status ubsa_e220_modechange_request(struct ubsa_softc *);
+
 struct	ucom_methods ubsa_methods = {
 	ubsa_get_status,
 	ubsa_set,
@@ -241,6 +246,8 @@
 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADUMTS },
 	/* AnyDATA ADU-E100H */
 	{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_E100H },
+	/* HUAWEI E220 / Emobile D0[12]HW */
+	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
 };
 #define ubsa_lookup(v, p) usb_lookup(ubsa_devs, v, p)
 
@@ -273,6 +280,8 @@
 	usbd_devinfo_free(devinfop);
 
         sc->sc_udev = dev;
+	sc->sc_config_index = UBSA_DEFAULT_CONFIG_INDEX;
+	sc->sc_devtype_e220 = 0;
 
 	/*
 	 * initialize rts, dtr variables to something
@@ -294,6 +303,13 @@
 			break;
 		}
 	}
+	/* Huawei E220 needs special care */
+	if (uaa->vendor == USB_VENDOR_HUAWEI) 
+		if (uaa->product == USB_PRODUCT_HUAWEI_E220) {
+			sc->sc_quadumts = 1;
+			sc->sc_config_index = 0;
+			sc->sc_devtype_e220 = 1;
+		}
 
 	DPRINTF(("ubsa attach: sc = %p\n", sc));
 
@@ -303,7 +319,7 @@
 	sc->sc_intr_pipe = NULL;
 
 	/* Move the device into the configured state. */
-	err = usbd_set_config_index(dev, UBSA_CONFIG_INDEX, 1);
+	err = usbd_set_config_index(dev, sc->sc_config_index, 1);
 	if (err) {
 		printf("%s: failed to set configuration: %s\n",
 		    devname, usbd_errstr(err));
@@ -332,6 +348,17 @@
 	}
 
 	/* Find the endpoints */
+	/* Hauwei E220 need special request to change its mode to modem */
+	if (sc->sc_devtype_e220) {
+		err = ubsa_e220_modechange_request(sc);
+		if (err) {
+			printf("%s: failed to change mode: %s\n",
+				devname, usbd_errstr(err));
+			sc->sc_dying = 1;
+			goto error;
+		}
+//		usbd_delay_ms(dev, 50);
+	}
 
 	id = usbd_get_interface_descriptor(sc->sc_iface);
 	sc->sc_iface_number = id->bInterfaceNumber;
@@ -361,7 +388,10 @@
 	}
 
 	if (sc->sc_intr_number == -1) {
-		printf("%s: Could not find interrupt in\n", devname);
+		if (sc->sc_devtype_e220)
+			printf("%s: HUAWEI E220 need to re-attach to enable modem function\n", devname);
+		else
+			printf("%s: Could not find interrupt in\n", devname);
 		sc->sc_dying = 1;
 		goto error;
 	}
@@ -785,3 +815,31 @@
 	if (msr != NULL)
 		*msr = sc->sc_msr;
 }
+
+/*
+ * Hauwei E220 needs special request to enable modem function
+ * XXX: is there more smart methods?
+ */
+Static  usbd_status 
+ubsa_e220_modechange_request(struct ubsa_softc *sc)
+{
+#define UBSA_E220_MODE_CHANGE_REQUEST 0x2
+	usb_device_request_t req;
+	usbd_status err;
+
+	req.bmRequestType = UT_WRITE_DEVICE;
+	req.bRequest = UR_SET_FEATURE;
+	USETW(req.wValue, 0x1);
+	USETW(req.wIndex, UBSA_E220_MODE_CHANGE_REQUEST);
+	USETW(req.wLength, 0);
+
+	DPRINTF(("%s: send e220 mode change request\n", __func__));
+	err = usbd_do_request(sc->sc_udev, &req, 0);
+	if (err) {
+		DPRINTF(("%s: E220 mode change fail\n", __func__));
+		return (EIO);
+	}
+
+	return (0);
+#undef UBSA_E220_MODE_CHANGE_REQUEST
+}
Index: umass_quirks.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/umass_quirks.c,v
retrieving revision 1.71
diff -u -r1.71 umass_quirks.c
--- umass_quirks.c	9 Jan 2007 16:46:02 -0000	1.71
+++ umass_quirks.c	23 Dec 2007 10:20:44 -0000
@@ -194,6 +194,13 @@
 	  UMATCH_DEVCLASS_DEVSUBCLASS_DEVPROTO,
 	  NULL, NULL
 	},
+	{ { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
+	   0, 0,
+	   0,
+	   0,
+	   0,
+	   NULL, NULL
+	},
 };
 
 const struct umass_quirk *

>Unformatted: