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: