Home | History | Annotate | Line # | Download | only in usb
u3g.c revision 1.23
      1 /*	$NetBSD: u3g.c,v 1.23 2011/12/22 20:07:00 jakllsch Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2009 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * Copyright (c) 2008 AnyWi Technologies
     33  *   Author: Andrea Guzzo <aguzzo (at) anywi.com>
     34  *   * based on uark.c 1.1 2006/08/14 08:30:22 jsg *
     35  *   * parts from ubsa.c 183348 2008-09-25 12:00:56Z phk *
     36  *
     37  * Permission to use, copy, modify, and distribute this software for any
     38  * purpose with or without fee is hereby granted, provided that the above
     39  * copyright notice and this permission notice appear in all copies.
     40  *
     41  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     42  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     43  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     44  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     45  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     46  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     47  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     48  *
     49  * $FreeBSD$
     50  */
     51 
     52 #include <sys/cdefs.h>
     53 __KERNEL_RCSID(0, "$NetBSD: u3g.c,v 1.23 2011/12/22 20:07:00 jakllsch Exp $");
     54 
     55 #include <sys/param.h>
     56 #include <sys/systm.h>
     57 #include <sys/kernel.h>
     58 #include <sys/malloc.h>
     59 #include <sys/bus.h>
     60 #include <sys/conf.h>
     61 #include <sys/tty.h>
     62 
     63 #include <dev/usb/usb.h>
     64 #include <dev/usb/usbdi.h>
     65 #include <dev/usb/usbdivar.h>
     66 #include <dev/usb/usbdi_util.h>
     67 
     68 #include <dev/usb/ucomvar.h>
     69 
     70 #include "usbdevs.h"
     71 
     72 /*
     73  * We read/write data from/to the device in 4KB chunks to maximise
     74  * performance.
     75  */
     76 #define U3G_BUFF_SIZE	4096
     77 
     78 /*
     79  * Some 3G devices (the Huawei E160/E220 springs to mind here) buffer up
     80  * data internally even when the USB pipes are closed. So on first open,
     81  * we can receive a large chunk of stale data.
     82  *
     83  * This causes a real problem because the default TTYDEF_LFLAG (applied
     84  * on first open) has the ECHO flag set, resulting in all the stale data
     85  * being echoed straight back to the device by the tty(4) layer. Some
     86  * devices (again, the Huawei E160/E220 for example) react to this spew
     87  * by going catatonic.
     88  *
     89  * All this happens before the application gets a chance to disable ECHO.
     90  *
     91  * We work around this by ignoring all data received from the device for
     92  * a period of two seconds, or until the application starts sending data -
     93  * whichever comes first.
     94  */
     95 #define	U3G_PURGE_SECS	2
     96 
     97 /*
     98  * Define bits for the virtual modem control pins.
     99  * The input pin states are reported via the interrupt pipe on some devices.
    100  */
    101 #define	U3G_OUTPIN_DTR	(1u << 0)
    102 #define	U3G_OUTPIN_RTS	(1u << 1)
    103 #define	U3G_INPIN_DCD	(1u << 0)
    104 #define	U3G_INPIN_DSR	(1u << 1)
    105 #define	U3G_INPIN_RI	(1u << 3)
    106 
    107 /*
    108  * USB request to set the output pin status
    109  */
    110 #define	U3G_SET_PIN	0x22
    111 
    112 struct u3g_softc {
    113 	device_t		sc_dev;
    114 	usbd_device_handle	sc_udev;
    115 	bool			sc_dying;	/* We're going away */
    116 
    117 	device_t		sc_ucom;	/* Child ucom(4) handle */
    118 	int			sc_ifaceno;	/* Device interface number */
    119 
    120 	bool			sc_open;	/* Device is in use */
    121 	bool			sc_purging;	/* Purging stale data */
    122 	struct timeval		sc_purge_start;	/* Control duration of purge */
    123 
    124 	u_char			sc_msr;		/* Emulated 'msr' */
    125 	uint16_t		sc_outpins;	/* Output pin state */
    126 
    127 	usbd_pipe_handle	sc_intr_pipe;	/* Interrupt pipe */
    128 	u_char			*sc_intr_buff;	/* Interrupt buffer */
    129 };
    130 
    131 /*
    132  * The device driver has two personalities. The first uses the 'usbdevif'
    133  * interface attribute so that a match will claim the entire USB device
    134  * for itself. This is used for when a device needs to be mode-switched
    135  * and ensures any other interfaces present cannot be claimed by other
    136  * drivers while the mode-switch is in progress.
    137  *
    138  * The second personality uses the 'usbifif' interface attribute so that
    139  * it can claim the 3G modem interfaces for itself, leaving others (such
    140  * as the mass storage interfaces on some devices) for other drivers.
    141  */
    142 static int u3ginit_match(device_t, cfdata_t, void *);
    143 static void u3ginit_attach(device_t, device_t, void *);
    144 static int u3ginit_detach(device_t, int);
    145 
    146 CFATTACH_DECL2_NEW(u3ginit, 0, u3ginit_match,
    147     u3ginit_attach, u3ginit_detach, NULL, NULL, NULL);
    148 
    149 
    150 static int u3g_match(device_t, cfdata_t, void *);
    151 static void u3g_attach(device_t, device_t, void *);
    152 static int u3g_detach(device_t, int);
    153 static int u3g_activate(device_t, enum devact);
    154 static void u3g_childdet(device_t, device_t);
    155 
    156 CFATTACH_DECL2_NEW(u3g, sizeof(struct u3g_softc), u3g_match,
    157     u3g_attach, u3g_detach, u3g_activate, NULL, u3g_childdet);
    158 
    159 
    160 static void u3g_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
    161 static void u3g_get_status(void *, int, u_char *, u_char *);
    162 static void u3g_set(void *, int, int, int);
    163 static int  u3g_open(void *, int);
    164 static void u3g_close(void *, int);
    165 static void u3g_read(void *, int, u_char **, uint32_t *);
    166 static void u3g_write(void *, int, u_char *, u_char *, u_int32_t *);
    167 
    168 struct ucom_methods u3g_methods = {
    169 	u3g_get_status,
    170 	u3g_set,
    171 	NULL,
    172 	NULL,
    173 	u3g_open,
    174 	u3g_close,
    175 	u3g_read,
    176 	u3g_write,
    177 };
    178 
    179 /*
    180  * Allegedly supported devices
    181  */
    182 static const struct usb_devno u3g_devs[] = {
    183         { USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 },
    184 	/* OEM: Huawei */
    185 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1750 },
    186 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1820 },
    187 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
    188 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_K3765 },
    189 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
    190 	/* OEM: Merlin */
    191 	{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
    192 	/* OEM: Novatel */
    193 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 },
    194 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_EU8X0D },
    195 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D },
    196 #if 0
    197 	/* These are matched in u3ginit_match() */
    198 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D_DRIVER },
    199 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U760_DRIVER },
    200 #endif
    201 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINU740 },
    202 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
    203 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 },
    204 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 },
    205 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U727 },
    206 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U740_2 },
    207 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U760 },
    208 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U870 },
    209 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_V740 },
    210 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_X950D },
    211 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 },
    212 	/* OEM: Option N.V. */
    213 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADPLUSUMTS },
    214 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_HSDPA },
    215 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTMAXHSUPA },
    216 	/* OEM: Qualcomm, Inc. */
    217 	{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },
    218 	{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_MF626 },
    219 
    220 	/* OEM: Sierra Wireless: */
    221 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },
    222 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },
    223 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },
    224 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },
    225 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },
    226 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },
    227 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },
    228 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },
    229 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },
    230 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
    231 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },
    232 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },
    233 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },
    234 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },
    235 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },
    236 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },
    237 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },
    238 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },
    239 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },
    240 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },
    241 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },
    242 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },
    243 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },
    244 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },
    245 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },
    246 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_USB305 },
    247 
    248 	/* Toshiba */
    249 	{ USB_VENDOR_TOSHIBA, USB_PRODUCT_TOSHIBA_HSDPA_MODEM_EU870DT1 },
    250 
    251 	/* 4G Systems */
    252 	{ USB_VENDOR_4GSYSTEMS, USB_PRODUCT_4GSYSTEMS_XSSTICK_P14 },
    253 };
    254 
    255 static int
    256 send_bulkmsg(usbd_device_handle dev, void *cmd, size_t cmdlen)
    257 {
    258 	usbd_interface_handle iface;
    259 	usb_interface_descriptor_t *id;
    260 	usb_endpoint_descriptor_t *ed;
    261 	usbd_pipe_handle pipe;
    262 	usbd_xfer_handle xfer;
    263 	int err, i;
    264 
    265 	/* Move the device into the configured state. */
    266 	err = usbd_set_config_index(dev, 0, 0);
    267 	if (err) {
    268 		aprint_error("u3g: failed to set configuration index\n");
    269 		return UMATCH_NONE;
    270 	}
    271 
    272 	err = usbd_device2interface_handle(dev, 0, &iface);
    273 	if (err != 0) {
    274 		aprint_error("u3ginit: failed to get interface\n");
    275 		return UMATCH_NONE;
    276 	}
    277 
    278 	id = usbd_get_interface_descriptor(iface);
    279 	ed = NULL;
    280 	for (i = 0 ; i < id->bNumEndpoints ; i++) {
    281 		ed = usbd_interface2endpoint_descriptor(iface, i);
    282 		if (ed == NULL)
    283 			continue;
    284 		if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
    285 			continue;
    286 		if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
    287 			break;
    288 	}
    289 
    290 	if (i == id->bNumEndpoints)
    291 		return UMATCH_NONE;
    292 
    293 	err = usbd_open_pipe(iface, ed->bEndpointAddress,
    294 	    USBD_EXCLUSIVE_USE, &pipe);
    295 	if (err != 0) {
    296 		aprint_error("u3ginit: failed to open bulk transfer pipe %d\n",
    297 		    ed->bEndpointAddress);
    298 		return UMATCH_NONE;
    299 	}
    300 
    301 	xfer = usbd_alloc_xfer(dev);
    302 	if (xfer != NULL) {
    303 		usbd_setup_xfer(xfer, pipe, NULL, cmd, cmdlen,
    304 		    USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
    305 
    306 		err = usbd_transfer(xfer);
    307 
    308 #if 0 /* XXXpooka: at least my huawei "fails" this always, but still detaches */
    309 		if (err)
    310 			aprint_error("u3ginit: transfer failed\n");
    311 #else
    312 		err = 0;
    313 #endif
    314 		usbd_free_xfer(xfer);
    315 	} else {
    316 		aprint_error("u3ginit: failed to allocate xfer\n");
    317 		err = USBD_NOMEM;
    318 	}
    319 
    320 	usbd_abort_pipe(pipe);
    321 	usbd_close_pipe(pipe);
    322 
    323 	return (err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE);
    324 }
    325 
    326 static int
    327 u3g_novatel_reinit(usbd_device_handle dev)
    328 {
    329 	unsigned char cmd[31];
    330 
    331 	memset(cmd, 0, sizeof(cmd));
    332 	/* Byte 0..3: Command Block Wrapper (CBW) signature */
    333 	cmd[0] = 0x55;
    334 	cmd[1] = 0x53;
    335 	cmd[2] = 0x42;
    336 	cmd[3] = 0x43;
    337 	/* 4..7: CBW Tag, has to unique, but only a single transfer used. */
    338 	cmd[4] = 0x01;
    339 	/* 8..11: CBW Transfer Length, no data here */
    340 	/* 12: CBW Flag: output, so 0 */
    341 	/* 13: CBW Lun: 0 */
    342 	/* 14: CBW Length */
    343 	cmd[14] = 0x06;
    344 	/* Rest is the SCSI payload */
    345 	/* 0: SCSI START/STOP opcode */
    346 	cmd[15] = 0x1b;
    347 	/* 1..3 unused */
    348 	/* 4 Load/Eject command */
    349 	cmd[19] = 0x02;
    350 	/* 5: unused */
    351 
    352 	return send_bulkmsg(dev, cmd, sizeof(cmd));
    353 }
    354 
    355 static int
    356 u3g_huawei_reinit(usbd_device_handle dev)
    357 {
    358 	/*
    359 	 * The Huawei device presents itself as a umass device with Windows
    360 	 * drivers on it. After installation of the driver, it reinits into a
    361 	 * 3G serial device.
    362 	 */
    363 	usb_device_request_t req;
    364 	usb_config_descriptor_t *cdesc;
    365 
    366 	/* Get the config descriptor */
    367 	cdesc = usbd_get_config_descriptor(dev);
    368 	if (cdesc == NULL) {
    369 		usb_device_descriptor_t dd;
    370 
    371 		if (usbd_get_device_desc(dev, &dd) != 0)
    372 			return (UMATCH_NONE);
    373 
    374 		if (dd.bNumConfigurations != 1)
    375 			return (UMATCH_NONE);
    376 
    377 		if (usbd_set_config_index(dev, 0, 1) != 0)
    378 			return (UMATCH_NONE);
    379 
    380 		cdesc = usbd_get_config_descriptor(dev);
    381 
    382 		if (cdesc == NULL)
    383 			return (UMATCH_NONE);
    384 	}
    385 
    386 	/*
    387 	 * One iface means umass mode, more than 1 (4 usually) means 3G mode.
    388 	 *
    389 	 * XXX: We should check the first interface's device class just to be
    390 	 * sure. If it's a mass storage device, then we can be fairly certain
    391 	 * it needs a mode-switch.
    392 	 */
    393 	if (cdesc->bNumInterface > 1)
    394 		return (UMATCH_NONE);
    395 
    396 	req.bmRequestType = UT_WRITE_DEVICE;
    397 	req.bRequest = UR_SET_FEATURE;
    398 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
    399 	USETW(req.wIndex, UHF_PORT_SUSPEND);
    400 	USETW(req.wLength, 0);
    401 
    402 	(void) usbd_do_request(dev, &req, 0);
    403 
    404 	return (UMATCH_HIGHEST); /* Prevent umass from attaching */
    405 }
    406 
    407 static int
    408 u3g_huawei_k3765_reinit(usbd_device_handle dev)
    409 {
    410 	unsigned char cmd[31];
    411 
    412 	/* magic string adapted from some webpage */
    413 	memset(cmd, 0, sizeof(cmd));
    414 	cmd[0] = 0x55;
    415 	cmd[1] = 0x53;
    416 	cmd[2] = 0x42;
    417 	cmd[3] = 0x43;
    418 	cmd[15]= 0x11;
    419 	cmd[16]= 0x06;
    420 
    421 	return send_bulkmsg(dev, cmd, sizeof(cmd));
    422 }
    423 
    424 static int
    425 u3g_sierra_reinit(usbd_device_handle dev)
    426 {
    427 	/* Some Sierra devices presents themselves as a umass device with
    428 	 * Windows drivers on it. After installation of the driver, it
    429 	 * reinits into a * 3G serial device.
    430 	 */
    431 	usb_device_request_t req;
    432 
    433 	req.bmRequestType = UT_VENDOR;
    434 	req.bRequest = UR_SET_INTERFACE;
    435 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
    436 	USETW(req.wIndex, UHF_PORT_CONNECTION);
    437 	USETW(req.wLength, 0);
    438 
    439 	(void) usbd_do_request(dev, &req, 0);
    440 
    441 	return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
    442 }
    443 
    444 static int
    445 u3g_4gsystems_reinit(usbd_device_handle dev)
    446 {
    447 	/* magic string adapted from usb_modeswitch database */
    448 	static unsigned char cmd[31] = {
    449 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0x80, 0x00,
    450 		0x00, 0x00, 0x80, 0x00, 0x06, 0x06, 0xf5, 0x04, 0x02, 0x52,
    451 		0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    452 		0x00
    453 	};
    454 
    455 	return send_bulkmsg(dev, cmd, sizeof(cmd));
    456 }
    457 
    458 /*
    459  * First personality:
    460  *
    461  * Claim the entire device if a mode-switch is required.
    462  */
    463 
    464 static int
    465 u3ginit_match(device_t parent, cfdata_t match, void *aux)
    466 {
    467 	struct usb_attach_arg *uaa = aux;
    468 
    469 	/*
    470 	 * Huawei changes product when it is configured as a modem.
    471 	 */
    472 	switch (uaa->vendor) {
    473 	case USB_VENDOR_HUAWEI:
    474 		if (uaa->product == USB_PRODUCT_HUAWEI_K3765)
    475 			return UMATCH_NONE;
    476 
    477 		switch (uaa->product) {
    478 		case USB_PRODUCT_HUAWEI_E1750INIT:
    479 		case USB_PRODUCT_HUAWEI_K3765INIT:
    480 			return u3g_huawei_k3765_reinit(uaa->device);
    481 			break;
    482 		default:
    483 			return u3g_huawei_reinit(uaa->device);
    484 			break;
    485 		}
    486 		break;
    487 
    488 	case USB_VENDOR_NOVATEL2:
    489 		switch (uaa->product){
    490 		case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
    491 		case USB_PRODUCT_NOVATEL2_U760_DRIVER:
    492 			return u3g_novatel_reinit(uaa->device);
    493 			break;
    494 		default:
    495 			break;
    496 		}
    497 		break;
    498 
    499 	case USB_VENDOR_SIERRA:
    500 		if (uaa->product == USB_PRODUCT_SIERRA_INSTALLER)
    501 			return u3g_sierra_reinit(uaa->device);
    502 		break;
    503 
    504 	case USB_VENDOR_QUALCOMMINC:
    505 		if (uaa->product == USB_PRODUCT_QUALCOMMINC_ZTE_STOR)
    506 			return u3g_novatel_reinit(uaa->device);
    507 		break;
    508 
    509 	case USB_VENDOR_4GSYSTEMS:
    510 		if (uaa->product == USB_PRODUCT_4GSYSTEMS_XSSTICK_P14_INSTALLER)
    511 			return u3g_4gsystems_reinit(uaa->device);
    512 		break;
    513 
    514 	default:
    515 		break;
    516 	}
    517 
    518 	return UMATCH_NONE;
    519 }
    520 
    521 static void
    522 u3ginit_attach(device_t parent, device_t self, void *aux)
    523 {
    524 	struct usb_attach_arg *uaa = aux;
    525 
    526 	aprint_naive("\n");
    527 	aprint_normal(": Switching to 3G mode\n");
    528 
    529 	if (uaa->vendor == USB_VENDOR_NOVATEL2) {
    530 		switch (uaa->product) {
    531 	    	case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
    532 	    	case USB_PRODUCT_NOVATEL2_U760_DRIVER:
    533 			/* About to disappear... */
    534 			return;
    535 			break;
    536 		default:
    537 			break;
    538 		}
    539 	}
    540 
    541 	/* Move the device into the configured state. */
    542 	(void) usbd_set_config_index(uaa->device, 0, 1);
    543 }
    544 
    545 static int
    546 u3ginit_detach(device_t self, int flags)
    547 {
    548 
    549 	return (0);
    550 }
    551 
    552 
    553 /*
    554  * Second personality:
    555  *
    556  * Claim only those interfaces required for 3G modem operation.
    557  */
    558 
    559 static int
    560 u3g_match(device_t parent, cfdata_t match, void *aux)
    561 {
    562 	struct usbif_attach_arg *uaa = aux;
    563 	usbd_interface_handle iface;
    564 	usb_interface_descriptor_t *id;
    565 	usbd_status error;
    566 
    567 	if (!usb_lookup(u3g_devs, uaa->vendor, uaa->product))
    568 		return (UMATCH_NONE);
    569 
    570 	error = usbd_device2interface_handle(uaa->device, uaa->ifaceno, &iface);
    571 	if (error) {
    572 		printf("u3g_match: failed to get interface, err=%s\n",
    573 		    usbd_errstr(error));
    574 		return (UMATCH_NONE);
    575 	}
    576 
    577 	id = usbd_get_interface_descriptor(iface);
    578 	if (id == NULL) {
    579 		printf("u3g_match: failed to get interface descriptor\n");
    580 		return (UMATCH_NONE);
    581 	}
    582 
    583 	/*
    584 	 * 3G modems generally report vendor-specific class
    585 	 *
    586 	 * XXX: this may be too generalised.
    587 	 */
    588 	return ((id->bInterfaceClass == UICLASS_VENDOR) ?
    589 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
    590 }
    591 
    592 static void
    593 u3g_attach(device_t parent, device_t self, void *aux)
    594 {
    595 	struct u3g_softc *sc = device_private(self);
    596 	struct usbif_attach_arg *uaa = aux;
    597 	usbd_device_handle dev = uaa->device;
    598 	usbd_interface_handle iface;
    599 	usb_interface_descriptor_t *id;
    600 	usb_endpoint_descriptor_t *ed;
    601 	struct ucom_attach_args uca;
    602 	usbd_status error;
    603 	int n, intr_address, intr_size;
    604 
    605 	aprint_naive("\n");
    606 	aprint_normal("\n");
    607 
    608 	sc->sc_dev = self;
    609 	sc->sc_dying = false;
    610 	sc->sc_udev = dev;
    611 
    612 	error = usbd_device2interface_handle(dev, uaa->ifaceno, &iface);
    613 	if (error) {
    614 		aprint_error_dev(self, "failed to get interface, err=%s\n",
    615 		    usbd_errstr(error));
    616 		return;
    617 	}
    618 
    619 	id = usbd_get_interface_descriptor(iface);
    620 
    621 	uca.info = "3G Modem";
    622 	uca.ibufsize = U3G_BUFF_SIZE;
    623 	uca.obufsize = U3G_BUFF_SIZE;
    624 	uca.ibufsizepad = U3G_BUFF_SIZE;
    625 	uca.portno = uaa->ifaceno;
    626 	uca.opkthdrlen = 0;
    627 	uca.device = dev;
    628 	uca.iface = iface;
    629 	uca.methods = &u3g_methods;
    630 	uca.arg = sc;
    631 	uca.bulkin = uca.bulkout = -1;
    632 
    633 	sc->sc_outpins = 0;
    634 	sc->sc_msr = UMSR_DSR | UMSR_CTS | UMSR_DCD;
    635 	sc->sc_ifaceno = uaa->ifaceno;
    636 	sc->sc_open = false;
    637 	sc->sc_purging = false;
    638 
    639 	intr_address = -1;
    640 	intr_size = 0;
    641 
    642 	for (n = 0; n < id->bNumEndpoints; n++) {
    643 		ed = usbd_interface2endpoint_descriptor(iface, n);
    644 		if (ed == NULL) {
    645 			aprint_error_dev(self, "no endpoint descriptor "
    646 			    "for %d (interface: %d)\n", n, sc->sc_ifaceno);
    647 			sc->sc_dying = true;
    648 			return;
    649 		}
    650 
    651 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    652 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
    653 			intr_address = ed->bEndpointAddress;
    654 			intr_size = UGETW(ed->wMaxPacketSize);
    655 		} else
    656 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    657 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    658 			uca.bulkin = ed->bEndpointAddress;
    659 		} else
    660 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    661 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    662 			uca.bulkout = ed->bEndpointAddress;
    663 		}
    664 	}
    665 
    666 	if (uca.bulkin == -1) {
    667 		aprint_error_dev(self, "Missing bulk in for interface %d\n",
    668 		    sc->sc_ifaceno);
    669 		sc->sc_dying = true;
    670 		return;
    671 	}
    672 
    673 	if (uca.bulkout == -1) {
    674 		aprint_error_dev(self, "Missing bulk out for interface %d\n",
    675 		    sc->sc_ifaceno);
    676 		sc->sc_dying = true;
    677 		return;
    678 	}
    679 
    680 	sc->sc_ucom = config_found_sm_loc(self, "ucombus",
    681 	    NULL, &uca, ucomprint, ucomsubmatch);
    682 
    683 	/*
    684 	 * If the interface has an interrupt pipe, open it immediately so
    685 	 * that we can track input pin state changes regardless of whether
    686 	 * the tty(4) device is open or not.
    687 	 */
    688 	if (intr_address != -1) {
    689 		sc->sc_intr_buff = malloc(intr_size, M_USBDEV, M_WAITOK);
    690 		error = usbd_open_pipe_intr(iface, intr_address,
    691 		    USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buff,
    692 		    intr_size, u3g_intr, 100);
    693 		if (error) {
    694 			aprint_error_dev(self, "cannot open interrupt pipe "
    695 			    "(addr %d)\n", intr_address);
    696 			return;
    697 		}
    698 	} else {
    699 		sc->sc_intr_pipe = NULL;
    700 		sc->sc_intr_buff = NULL;
    701 	}
    702 
    703 	if (!pmf_device_register(self, NULL, NULL))
    704 		aprint_error_dev(self, "couldn't establish power handler\n");
    705 }
    706 
    707 static int
    708 u3g_detach(device_t self, int flags)
    709 {
    710 	struct u3g_softc *sc = device_private(self);
    711 	int rv;
    712 
    713 	if (sc->sc_dying)
    714 		return 0;
    715 
    716 	pmf_device_deregister(self);
    717 
    718 	if (sc->sc_ucom != NULL) {
    719 		rv = config_detach(sc->sc_ucom, flags);
    720 		if (rv != 0) {
    721 			aprint_verbose_dev(self, "Can't deallocate "
    722 			    "port (%d)", rv);
    723 		}
    724 	}
    725 
    726 	if (sc->sc_intr_pipe != NULL) {
    727 		(void) usbd_abort_pipe(sc->sc_intr_pipe);
    728 		(void) usbd_close_pipe(sc->sc_intr_pipe);
    729 		sc->sc_intr_pipe = NULL;
    730 	}
    731 	if (sc->sc_intr_buff != NULL) {
    732 		free(sc->sc_intr_buff, M_USBDEV);
    733 		sc->sc_intr_buff = NULL;
    734 	}
    735 
    736 	return (0);
    737 }
    738 
    739 static void
    740 u3g_childdet(device_t self, device_t child)
    741 {
    742 	struct u3g_softc *sc = device_private(self);
    743 
    744 	if (sc->sc_ucom == child)
    745 		sc->sc_ucom = NULL;
    746 }
    747 
    748 static int
    749 u3g_activate(device_t self, enum devact act)
    750 {
    751 	struct u3g_softc *sc = device_private(self);
    752 	int rv;
    753 
    754 	switch (act) {
    755 	case DVACT_DEACTIVATE:
    756 		if (sc->sc_ucom != NULL && config_deactivate(sc->sc_ucom))
    757 			rv = -1;
    758 		else
    759 			rv = 0;
    760 		break;
    761 
    762 	default:
    763 		rv = 0;
    764 		break;
    765 	}
    766 
    767 	return (rv);
    768 }
    769 
    770 static void
    771 u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
    772 {
    773 	struct u3g_softc *sc = (struct u3g_softc *)priv;
    774 	u_char *buf;
    775 
    776 	if (sc->sc_dying)
    777 		return;
    778 
    779 	if (status != USBD_NORMAL_COMPLETION) {
    780 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    781 			return;
    782 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
    783 		return;
    784 	}
    785 
    786 	buf = sc->sc_intr_buff;
    787 	if (buf[0] == 0xa1 && buf[1] == 0x20) {
    788 		u_char msr;
    789 
    790 		msr = sc->sc_msr & ~(UMSR_DCD | UMSR_DSR | UMSR_RI);
    791 
    792 		if (buf[8] & U3G_INPIN_DCD)
    793 			msr |= UMSR_DCD;
    794 
    795 		if (buf[8] & U3G_INPIN_DSR)
    796 			msr |= UMSR_DSR;
    797 
    798 		if (buf[8] & U3G_INPIN_RI)
    799 			msr |= UMSR_RI;
    800 
    801 		if (msr != sc->sc_msr) {
    802 			sc->sc_msr = msr;
    803 			if (sc->sc_open)
    804 				ucom_status_change(device_private(sc->sc_ucom));
    805 		}
    806 	}
    807 }
    808 
    809 /*ARGSUSED*/
    810 static void
    811 u3g_get_status(void *arg, int portno, u_char *lsr, u_char *msr)
    812 {
    813 	struct u3g_softc *sc = arg;
    814 
    815 	if (lsr != NULL)
    816 		*lsr = 0;	/* LSR isn't supported */
    817 	if (msr != NULL)
    818 		*msr = sc->sc_msr;
    819 }
    820 
    821 /*ARGSUSED*/
    822 static void
    823 u3g_set(void *arg, int portno, int reg, int onoff)
    824 {
    825 	struct u3g_softc *sc = arg;
    826 	usb_device_request_t req;
    827 	uint16_t mask, new_state;
    828 	usbd_status err;
    829 
    830 	if (sc->sc_dying)
    831 		return;
    832 
    833 	switch (reg) {
    834 	case UCOM_SET_DTR:
    835 		mask = U3G_OUTPIN_DTR;
    836 		break;
    837 	case UCOM_SET_RTS:
    838 		mask = U3G_OUTPIN_RTS;
    839 		break;
    840 	default:
    841 		return;
    842 	}
    843 
    844 	new_state = sc->sc_outpins & ~mask;
    845 	if (onoff)
    846 		new_state |= mask;
    847 
    848 	if (new_state == sc->sc_outpins)
    849 		return;
    850 
    851 	sc->sc_outpins = new_state;
    852 
    853 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    854 	req.bRequest = U3G_SET_PIN;
    855 	USETW(req.wValue, new_state);
    856 	USETW(req.wIndex, sc->sc_ifaceno);
    857 	USETW(req.wLength, 0);
    858 
    859 	err = usbd_do_request(sc->sc_udev, &req, 0);
    860 	if (err == USBD_STALLED)
    861 		usbd_clear_endpoint_stall(sc->sc_udev->default_pipe);
    862 }
    863 
    864 /*ARGSUSED*/
    865 static int
    866 u3g_open(void *arg, int portno)
    867 {
    868 	struct u3g_softc *sc = arg;
    869 	usb_device_request_t req;
    870 	usb_endpoint_descriptor_t *ed;
    871 	usb_interface_descriptor_t *id;
    872 	usbd_interface_handle ih;
    873 	usbd_status err;
    874 	int i;
    875 
    876 	if (sc->sc_dying)
    877 		return (0);
    878 
    879 	err = usbd_device2interface_handle(sc->sc_udev, portno, &ih);
    880 	if (err)
    881 		return (EIO);
    882 
    883 	id = usbd_get_interface_descriptor(ih);
    884 
    885 	for (i = 0; i < id->bNumEndpoints; i++) {
    886 		ed = usbd_interface2endpoint_descriptor(ih, i);
    887 		if (ed == NULL)
    888 			return (EIO);
    889 
    890 		if (UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    891 			/* Issue ENDPOINT_HALT request */
    892 			req.bmRequestType = UT_WRITE_ENDPOINT;
    893 			req.bRequest = UR_CLEAR_FEATURE;
    894 			USETW(req.wValue, UF_ENDPOINT_HALT);
    895 			USETW(req.wIndex, ed->bEndpointAddress);
    896 			USETW(req.wLength, 0);
    897 			err = usbd_do_request(sc->sc_udev, &req, 0);
    898 			if (err)
    899 				return (EIO);
    900 		}
    901 	}
    902 
    903 	sc->sc_open = true;
    904 	sc->sc_purging = true;
    905 	getmicrotime(&sc->sc_purge_start);
    906 
    907 	return (0);
    908 }
    909 
    910 /*ARGSUSED*/
    911 static void
    912 u3g_close(void *arg, int portno)
    913 {
    914 	struct u3g_softc *sc = arg;
    915 
    916 	sc->sc_open = false;
    917 }
    918 
    919 /*ARGSUSED*/
    920 static void
    921 u3g_read(void *arg, int portno, u_char **cpp, uint32_t *ccp)
    922 {
    923 	struct u3g_softc *sc = arg;
    924 	struct timeval curr_tv, diff_tv;
    925 
    926 	/*
    927 	 * If we're not purging input data following first open, do nothing.
    928 	 */
    929 	if (sc->sc_purging == false)
    930 		return;
    931 
    932 	/*
    933 	 * Otherwise check if the purge timeout has expired
    934 	 */
    935 	getmicrotime(&curr_tv);
    936 	timersub(&curr_tv, &sc->sc_purge_start, &diff_tv);
    937 
    938 	if (diff_tv.tv_sec >= U3G_PURGE_SECS) {
    939 		/* Timeout expired. */
    940 		sc->sc_purging = false;
    941 	} else {
    942 		/* Still purging. Adjust the caller's byte count. */
    943 		*ccp = 0;
    944 	}
    945 }
    946 
    947 /*ARGSUSED*/
    948 static void
    949 u3g_write(void *arg, int portno, u_char *to, u_char *from, u_int32_t *count)
    950 {
    951 	struct u3g_softc *sc = arg;
    952 
    953 	/*
    954 	 * Stop purging as soon as the first data is written to the device.
    955 	 */
    956 	sc->sc_purging = false;
    957 	memcpy(to, from, *count);
    958 }
    959