Module Name: src Committed By: pooka Date: Fri Feb 19 15:10:02 UTC 2010
Modified Files: src/sys/dev/usb: u3g.c Log Message: Huawei K3765 requires another kind of magic to get it out of CD mode. It also changes product id after being configured. Without this change the device just lingers in u3ginit forever. With this change: u3ginit0 at uhub0 port 1: Switching to 3G mode u3ginit0: detached u3ginit0: at uhub0 port 1 (addr 2) disconnected u3g0 at uhub0 port 1 configuration 1 interface 0 ucom0 at u3g0 portno 0: 3G Modem u3g1 at uhub0 port 1 configuration 1 interface 1 ucom1 at u3g1 portno 1: 3G Modem u3g2 at uhub0 port 1 configuration 1 interface 2 ucom2 at u3g2 portno 2: 3G Modem u3g3 at uhub0 port 1 configuration 1 interface 3 ucom3 at u3g3 portno 3: 3G Modem (tested with rump) To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/sys/dev/usb/u3g.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/u3g.c diff -u src/sys/dev/usb/u3g.c:1.10 src/sys/dev/usb/u3g.c:1.11 --- src/sys/dev/usb/u3g.c:1.10 Mon Feb 8 20:45:43 2010 +++ src/sys/dev/usb/u3g.c Fri Feb 19 15:10:02 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: u3g.c,v 1.10 2010/02/08 20:45:43 snj Exp $ */ +/* $NetBSD: u3g.c,v 1.11 2010/02/19 15:10:02 pooka Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -50,7 +50,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: u3g.c,v 1.10 2010/02/08 20:45:43 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: u3g.c,v 1.11 2010/02/19 15:10:02 pooka Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -190,6 +190,7 @@ /* OEM: Huawei */ { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE }, { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }, + { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_K3765 }, /* OEM: Novatel */ { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 }, { USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 }, @@ -240,9 +241,8 @@ }; static int -u3g_novatel_reinit(usbd_device_handle dev) +send_bulkmsg(usbd_device_handle dev, char *cmd, size_t cmdlen) { - unsigned char cmd[31]; usbd_interface_handle iface; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; @@ -250,28 +250,6 @@ usbd_xfer_handle xfer; int err, i; - memset(cmd, 0, sizeof(cmd)); - /* Byte 0..3: Command Block Wrapper (CBW) signature */ - cmd[0] = 0x55; - cmd[1] = 0x53; - cmd[2] = 0x42; - cmd[3] = 0x43; - /* 4..7: CBW Tag, has to unique, but only a single transfer used. */ - cmd[4] = 0x01; - /* 8..11: CBW Transfer Length, no data here */ - /* 12: CBW Flag: output, so 0 */ - /* 13: CBW Lun: 0 */ - /* 14: CBW Length */ - cmd[14] = 0x06; - /* Rest is the SCSI payload */ - /* 0: SCSI START/STOP opcode */ - cmd[15] = 0x1b; - /* 1..3 unused */ - /* 4 Load/Eject command */ - cmd[19] = 0x02; - /* 5: unused */ - - /* Move the device into the configured state. */ err = usbd_set_config_index(dev, 0, 0); if (err) { @@ -281,7 +259,7 @@ err = usbd_device2interface_handle(dev, 0, &iface); if (err != 0) { - aprint_error("u3g: failed to get interface\n"); + aprint_error("u3ginit: failed to get interface\n"); return UMATCH_NONE; } @@ -300,25 +278,30 @@ if (i == id->bNumEndpoints) return UMATCH_NONE; - err = usbd_open_pipe(iface, ed->bEndpointAddress, USBD_EXCLUSIVE_USE, - &pipe); + err = usbd_open_pipe(iface, ed->bEndpointAddress, + USBD_EXCLUSIVE_USE, &pipe); if (err != 0) { - aprint_error("u3g: failed to open bulk transfer pipe %d\n", + aprint_error("u3ginit: failed to open bulk transfer pipe %d\n", ed->bEndpointAddress); return UMATCH_NONE; } xfer = usbd_alloc_xfer(dev); if (xfer != NULL) { - usbd_setup_xfer(xfer, pipe, NULL, cmd, sizeof(cmd), + usbd_setup_xfer(xfer, pipe, NULL, cmd, cmdlen, USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL); err = usbd_transfer(xfer); + +#if 0 /* XXXpooka: at least my huawei "fails" this always, but still detaches */ if (err) - aprint_error("u3g: transfer failed\n"); + aprint_error("u3ginit: transfer failed\n"); +#else + err = 0; +#endif usbd_free_xfer(xfer); } else { - aprint_error("u3g: failed to allocate xfer\n"); + aprint_error("u3ginit: failed to allocate xfer\n"); err = USBD_NOMEM; } @@ -329,6 +312,35 @@ } static int +u3g_novatel_reinit(usbd_device_handle dev) +{ + unsigned char cmd[31]; + + memset(cmd, 0, sizeof(cmd)); + /* Byte 0..3: Command Block Wrapper (CBW) signature */ + cmd[0] = 0x55; + cmd[1] = 0x53; + cmd[2] = 0x42; + cmd[3] = 0x43; + /* 4..7: CBW Tag, has to unique, but only a single transfer used. */ + cmd[4] = 0x01; + /* 8..11: CBW Transfer Length, no data here */ + /* 12: CBW Flag: output, so 0 */ + /* 13: CBW Lun: 0 */ + /* 14: CBW Length */ + cmd[14] = 0x06; + /* Rest is the SCSI payload */ + /* 0: SCSI START/STOP opcode */ + cmd[15] = 0x1b; + /* 1..3 unused */ + /* 4 Load/Eject command */ + cmd[19] = 0x02; + /* 5: unused */ + + return send_bulkmsg(dev, cmd, sizeof(cmd)); +} + +static int u3g_huawei_reinit(usbd_device_handle dev) { /* @@ -377,7 +389,24 @@ (void) usbd_do_request(dev, &req, 0); - return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */ + return (UMATCH_HIGHEST); /* Prevent umass from attaching */ +} + +static int +u3g_huawei_k3765_reinit(usbd_device_handle dev) +{ + unsigned char cmd[31]; + + /* magic string adapted from some webpage */ + memset(cmd, 0, sizeof(cmd)); + cmd[0] = 0x55; + cmd[1] = 0x53; + cmd[2] = 0x42; + cmd[3] = 0x43; + cmd[15]= 0x11; + cmd[16]= 0x06; + + return send_bulkmsg(dev, cmd, sizeof(cmd)); } static int @@ -400,7 +429,6 @@ return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */ } - /* * First personality: * @@ -412,8 +440,18 @@ { struct usb_attach_arg *uaa = aux; - if (uaa->vendor == USB_VENDOR_HUAWEI) - return u3g_huawei_reinit(uaa->device); + /* + * Huawei changes product when it is configured as a modem. + */ + if (uaa->vendor == USB_VENDOR_HUAWEI) { + if (uaa->product == USB_PRODUCT_HUAWEI_K3765) + return UMATCH_NONE; + + if (uaa->product == USB_PRODUCT_HUAWEI_K3765INIT) + return u3g_huawei_k3765_reinit(uaa->device); + else + return u3g_huawei_reinit(uaa->device); + } if (uaa->vendor == USB_VENDOR_NOVATEL2 && uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER)