Subject: Re: Huawei E220 support?
To: None <current-users@netbsd.org>
From: Yojiro UO <yuo@nui.org>
List: current-users
Date: 12/23/2007 20:07:52
This is a multi-part message in MIME format.
--------------060608060000090702080701
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hi

Marco Trillo wrote:
> Maybe this can be fixed by making ubsa(4) issue the non-standard
> request to switch device mode that the Linux hack does; but I haven't
> tried it yet.

I wrote a patch to send special request to enable modem function of
E220 deivce. It seems to work well (I use OEM version of E220 /
Emobile D02HW). (special thanks to ichiro@netbsd.org)

Once the device is plugged in, this patch act as
attach -> send special request -> re-attach -> attach as ucom.

Following is dmesg:

ubsa0 at uhub0 port 2
ubsa0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
ubsa0: HAUWEI E220 need to re-attach to enable modem function
ubsa0: at uhub0 port 2 (addr 2) disconnected
ubsa0 detached
ubsa0 at uhub0 port 2
ubsa0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
ucom0 at ubsa0

This patch is send-pred.

-- Yojiro UO




--------------060608060000090702080701
Content-Type: text/plain;
 name="diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="diff"

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 *

--------------060608060000090702080701--