Home | History | Annotate | Line # | Download | only in usb
u3g.c revision 1.20.2.4
      1 /*	$NetBSD: u3g.c,v 1.20.2.4 2013/01/16 05:33:34 yamt 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.20.2.4 2013/01/16 05:33:34 yamt 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 	int			sc_ifaceno;	/* Device interface number */
    117 
    118 	struct u3g_com {
    119 		device_t	c_dev;		/* Child ucom(4) handle */
    120 
    121 		bool		c_open;		/* Device is in use */
    122 		bool		c_purging;	/* Purging stale data */
    123 		struct timeval	c_purge_start;	/* Control duration of purge */
    124 
    125 		u_char		c_msr;		/* Emulated 'msr' */
    126 		uint16_t	c_outpins;	/* Output pin state */
    127 	} sc_com[10];
    128 	size_t			sc_ncom;
    129 
    130 	usbd_pipe_handle	sc_intr_pipe;	/* Interrupt pipe */
    131 	u_char			*sc_intr_buff;	/* Interrupt buffer */
    132 };
    133 
    134 /*
    135  * The device driver has two personalities. The first uses the 'usbdevif'
    136  * interface attribute so that a match will claim the entire USB device
    137  * for itself. This is used for when a device needs to be mode-switched
    138  * and ensures any other interfaces present cannot be claimed by other
    139  * drivers while the mode-switch is in progress.
    140  *
    141  * The second personality uses the 'usbifif' interface attribute so that
    142  * it can claim the 3G modem interfaces for itself, leaving others (such
    143  * as the mass storage interfaces on some devices) for other drivers.
    144  */
    145 static int u3ginit_match(device_t, cfdata_t, void *);
    146 static void u3ginit_attach(device_t, device_t, void *);
    147 static int u3ginit_detach(device_t, int);
    148 
    149 CFATTACH_DECL2_NEW(u3ginit, 0, u3ginit_match,
    150     u3ginit_attach, u3ginit_detach, NULL, NULL, NULL);
    151 
    152 
    153 static int u3g_match(device_t, cfdata_t, void *);
    154 static void u3g_attach(device_t, device_t, void *);
    155 static int u3g_detach(device_t, int);
    156 static int u3g_activate(device_t, enum devact);
    157 static void u3g_childdet(device_t, device_t);
    158 
    159 CFATTACH_DECL2_NEW(u3g, sizeof(struct u3g_softc), u3g_match,
    160     u3g_attach, u3g_detach, u3g_activate, NULL, u3g_childdet);
    161 
    162 
    163 static void u3g_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
    164 static void u3g_get_status(void *, int, u_char *, u_char *);
    165 static void u3g_set(void *, int, int, int);
    166 static int  u3g_open(void *, int);
    167 static void u3g_close(void *, int);
    168 static void u3g_read(void *, int, u_char **, uint32_t *);
    169 static void u3g_write(void *, int, u_char *, u_char *, u_int32_t *);
    170 
    171 struct ucom_methods u3g_methods = {
    172 	u3g_get_status,
    173 	u3g_set,
    174 	NULL,
    175 	NULL,
    176 	u3g_open,
    177 	u3g_close,
    178 	u3g_read,
    179 	u3g_write,
    180 };
    181 
    182 /*
    183  * Allegedly supported devices
    184  */
    185 static const struct usb_devno u3g_devs[] = {
    186         { USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 },
    187 	/* OEM: Huawei */
    188 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1750 },
    189 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E1820 },
    190 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
    191 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_EM770W },
    192 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_K3765 },
    193 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
    194 	/* OEM: Merlin */
    195 	{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
    196 	/* OEM: Novatel */
    197 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 },
    198 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_EU8X0D },
    199 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D },
    200 #if 0
    201 	/* These are matched in u3ginit_match() */
    202 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D_DRIVER },
    203 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U760_DRIVER },
    204 #endif
    205 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINU740 },
    206 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
    207 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 },
    208 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 },
    209 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U727 },
    210 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U740_2 },
    211 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U760 },
    212 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U870 },
    213 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_V740 },
    214 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_X950D },
    215 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 },
    216 	/* OEM: Option N.V. */
    217 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADPLUSUMTS },
    218 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_HSDPA },
    219 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTMAXHSUPA },
    220 	/* OEM: Qualcomm, Inc. */
    221 	{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },
    222 	{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_MF626 },
    223 	{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_NTT_DOCOMO_L02C_MODEM },
    224 
    225 	/* OEM: Sierra Wireless: */
    226 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },
    227 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },
    228 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },
    229 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },
    230 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },
    231 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },
    232 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },
    233 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },
    234 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },
    235 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
    236 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },
    237 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },
    238 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },
    239 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },
    240 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },
    241 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },
    242 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },
    243 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },
    244 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },
    245 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },
    246 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },
    247 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },
    248 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },
    249 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },
    250 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },
    251 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_USB305 },
    252 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_250U },
    253 	/* Toshiba */
    254 	{ USB_VENDOR_TOSHIBA, USB_PRODUCT_TOSHIBA_HSDPA_MODEM_EU870DT1 },
    255 
    256 	/* 4G Systems */
    257 	{ USB_VENDOR_4GSYSTEMS, USB_PRODUCT_4GSYSTEMS_XSSTICK_P14 },
    258 };
    259 
    260 static int
    261 send_bulkmsg(usbd_device_handle dev, void *cmd, size_t cmdlen)
    262 {
    263 	usbd_interface_handle iface;
    264 	usb_interface_descriptor_t *id;
    265 	usb_endpoint_descriptor_t *ed;
    266 	usbd_pipe_handle pipe;
    267 	usbd_xfer_handle xfer;
    268 	int err, i;
    269 
    270 	/* Move the device into the configured state. */
    271 	err = usbd_set_config_index(dev, 0, 0);
    272 	if (err) {
    273 		aprint_error("u3g: failed to set configuration index\n");
    274 		return UMATCH_NONE;
    275 	}
    276 
    277 	err = usbd_device2interface_handle(dev, 0, &iface);
    278 	if (err != 0) {
    279 		aprint_error("u3ginit: failed to get interface\n");
    280 		return UMATCH_NONE;
    281 	}
    282 
    283 	id = usbd_get_interface_descriptor(iface);
    284 	ed = NULL;
    285 	for (i = 0 ; i < id->bNumEndpoints ; i++) {
    286 		ed = usbd_interface2endpoint_descriptor(iface, i);
    287 		if (ed == NULL)
    288 			continue;
    289 		if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
    290 			continue;
    291 		if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
    292 			break;
    293 	}
    294 
    295 	if (i == id->bNumEndpoints)
    296 		return UMATCH_NONE;
    297 
    298 	err = usbd_open_pipe(iface, ed->bEndpointAddress,
    299 	    USBD_EXCLUSIVE_USE, &pipe);
    300 	if (err != 0) {
    301 		aprint_error("u3ginit: failed to open bulk transfer pipe %d\n",
    302 		    ed->bEndpointAddress);
    303 		return UMATCH_NONE;
    304 	}
    305 
    306 	xfer = usbd_alloc_xfer(dev);
    307 	if (xfer != NULL) {
    308 		usbd_setup_xfer(xfer, pipe, NULL, cmd, cmdlen,
    309 		    USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
    310 
    311 		err = usbd_transfer(xfer);
    312 
    313 #if 0 /* XXXpooka: at least my huawei "fails" this always, but still detaches */
    314 		if (err)
    315 			aprint_error("u3ginit: transfer failed\n");
    316 #else
    317 		err = 0;
    318 #endif
    319 		usbd_free_xfer(xfer);
    320 	} else {
    321 		aprint_error("u3ginit: failed to allocate xfer\n");
    322 		err = USBD_NOMEM;
    323 	}
    324 
    325 	usbd_abort_pipe(pipe);
    326 	usbd_close_pipe(pipe);
    327 
    328 	return (err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE);
    329 }
    330 
    331 static int
    332 u3g_novatel_reinit(usbd_device_handle dev)
    333 {
    334 	unsigned char cmd[31];
    335 
    336 	memset(cmd, 0, sizeof(cmd));
    337 	/* Byte 0..3: Command Block Wrapper (CBW) signature */
    338 	cmd[0] = 0x55;
    339 	cmd[1] = 0x53;
    340 	cmd[2] = 0x42;
    341 	cmd[3] = 0x43;
    342 	/* 4..7: CBW Tag, has to unique, but only a single transfer used. */
    343 	cmd[4] = 0x01;
    344 	/* 8..11: CBW Transfer Length, no data here */
    345 	/* 12: CBW Flag: output, so 0 */
    346 	/* 13: CBW Lun: 0 */
    347 	/* 14: CBW Length */
    348 	cmd[14] = 0x06;
    349 	/* Rest is the SCSI payload */
    350 	/* 0: SCSI START/STOP opcode */
    351 	cmd[15] = 0x1b;
    352 	/* 1..3 unused */
    353 	/* 4 Load/Eject command */
    354 	cmd[19] = 0x02;
    355 	/* 5: unused */
    356 
    357 	return send_bulkmsg(dev, cmd, sizeof(cmd));
    358 }
    359 
    360 static int
    361 u3g_huawei_reinit(usbd_device_handle dev)
    362 {
    363 	/*
    364 	 * The Huawei device presents itself as a umass device with Windows
    365 	 * drivers on it. After installation of the driver, it reinits into a
    366 	 * 3G serial device.
    367 	 */
    368 	usb_device_request_t req;
    369 	usb_config_descriptor_t *cdesc;
    370 
    371 	/* Get the config descriptor */
    372 	cdesc = usbd_get_config_descriptor(dev);
    373 	if (cdesc == NULL) {
    374 		usb_device_descriptor_t dd;
    375 
    376 		if (usbd_get_device_desc(dev, &dd) != 0)
    377 			return (UMATCH_NONE);
    378 
    379 		if (dd.bNumConfigurations != 1)
    380 			return (UMATCH_NONE);
    381 
    382 		if (usbd_set_config_index(dev, 0, 1) != 0)
    383 			return (UMATCH_NONE);
    384 
    385 		cdesc = usbd_get_config_descriptor(dev);
    386 
    387 		if (cdesc == NULL)
    388 			return (UMATCH_NONE);
    389 	}
    390 
    391 	/*
    392 	 * One iface means umass mode, more than 1 (4 usually) means 3G mode.
    393 	 *
    394 	 * XXX: We should check the first interface's device class just to be
    395 	 * sure. If it's a mass storage device, then we can be fairly certain
    396 	 * it needs a mode-switch.
    397 	 */
    398 	if (cdesc->bNumInterface > 1)
    399 		return (UMATCH_NONE);
    400 
    401 	req.bmRequestType = UT_WRITE_DEVICE;
    402 	req.bRequest = UR_SET_FEATURE;
    403 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
    404 	USETW(req.wIndex, UHF_PORT_SUSPEND);
    405 	USETW(req.wLength, 0);
    406 
    407 	(void) usbd_do_request(dev, &req, 0);
    408 
    409 	return (UMATCH_HIGHEST); /* Prevent umass from attaching */
    410 }
    411 
    412 static int
    413 u3g_huawei_k3765_reinit(usbd_device_handle dev)
    414 {
    415 	unsigned char cmd[31];
    416 
    417 	/* magic string adapted from some webpage */
    418 	memset(cmd, 0, sizeof(cmd));
    419 	cmd[0] = 0x55;
    420 	cmd[1] = 0x53;
    421 	cmd[2] = 0x42;
    422 	cmd[3] = 0x43;
    423 	cmd[15]= 0x11;
    424 	cmd[16]= 0x06;
    425 
    426 	return send_bulkmsg(dev, cmd, sizeof(cmd));
    427 }
    428 
    429 static int
    430 u3g_sierra_reinit(usbd_device_handle dev)
    431 {
    432 	/* Some Sierra devices presents themselves as a umass device with
    433 	 * Windows drivers on it. After installation of the driver, it
    434 	 * reinits into a * 3G serial device.
    435 	 */
    436 	usb_device_request_t req;
    437 
    438 	req.bmRequestType = UT_VENDOR;
    439 	req.bRequest = UR_SET_INTERFACE;
    440 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
    441 	USETW(req.wIndex, UHF_PORT_CONNECTION);
    442 	USETW(req.wLength, 0);
    443 
    444 	(void) usbd_do_request(dev, &req, 0);
    445 
    446 	return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
    447 }
    448 
    449 static int
    450 u3g_4gsystems_reinit(usbd_device_handle dev)
    451 {
    452 	/* magic string adapted from usb_modeswitch database */
    453 	static unsigned char cmd[31] = {
    454 		0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0x80, 0x00,
    455 		0x00, 0x00, 0x80, 0x00, 0x06, 0x06, 0xf5, 0x04, 0x02, 0x52,
    456 		0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    457 		0x00
    458 	};
    459 
    460 	return send_bulkmsg(dev, cmd, sizeof(cmd));
    461 }
    462 
    463 /*
    464  * First personality:
    465  *
    466  * Claim the entire device if a mode-switch is required.
    467  */
    468 
    469 static int
    470 u3ginit_match(device_t parent, cfdata_t match, void *aux)
    471 {
    472 	struct usb_attach_arg *uaa = aux;
    473 
    474 	/*
    475 	 * Huawei changes product when it is configured as a modem.
    476 	 */
    477 	switch (uaa->vendor) {
    478 	case USB_VENDOR_HUAWEI:
    479 		if (uaa->product == USB_PRODUCT_HUAWEI_K3765)
    480 			return UMATCH_NONE;
    481 
    482 		switch (uaa->product) {
    483 		case USB_PRODUCT_HUAWEI_E1750INIT:
    484 		case USB_PRODUCT_HUAWEI_K3765INIT:
    485 			return u3g_huawei_k3765_reinit(uaa->device);
    486 			break;
    487 		default:
    488 			return u3g_huawei_reinit(uaa->device);
    489 			break;
    490 		}
    491 		break;
    492 
    493 	case USB_VENDOR_NOVATEL2:
    494 		switch (uaa->product){
    495 		case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
    496 		case USB_PRODUCT_NOVATEL2_U760_DRIVER:
    497 			return u3g_novatel_reinit(uaa->device);
    498 			break;
    499 		default:
    500 			break;
    501 		}
    502 		break;
    503 
    504 	case USB_VENDOR_SIERRA:
    505 		if (uaa->product == USB_PRODUCT_SIERRA_INSTALLER)
    506 			return u3g_sierra_reinit(uaa->device);
    507 		break;
    508 
    509 	case USB_VENDOR_QUALCOMMINC:
    510 		if (uaa->product == USB_PRODUCT_QUALCOMMINC_ZTE_STOR)
    511 			return u3g_novatel_reinit(uaa->device);
    512 		break;
    513 
    514 	case USB_VENDOR_QUALCOMM:
    515 		if (uaa->product == USB_PRODUCT_QUALCOMM_NTT_DOCOMO_L02C_STORAGE)
    516 			return u3g_novatel_reinit(uaa->device);
    517 		break;
    518 
    519 	case USB_VENDOR_4GSYSTEMS:
    520 		if (uaa->product == USB_PRODUCT_4GSYSTEMS_XSSTICK_P14_INSTALLER)
    521 			return u3g_4gsystems_reinit(uaa->device);
    522 		break;
    523 
    524 	default:
    525 		break;
    526 	}
    527 
    528 	return UMATCH_NONE;
    529 }
    530 
    531 static void
    532 u3ginit_attach(device_t parent, device_t self, void *aux)
    533 {
    534 	struct usb_attach_arg *uaa = aux;
    535 
    536 	aprint_naive("\n");
    537 	aprint_normal(": Switching to 3G mode\n");
    538 
    539 	if (uaa->vendor == USB_VENDOR_NOVATEL2) {
    540 		switch (uaa->product) {
    541 	    	case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
    542 	    	case USB_PRODUCT_NOVATEL2_U760_DRIVER:
    543 			/* About to disappear... */
    544 			return;
    545 			break;
    546 		default:
    547 			break;
    548 		}
    549 	}
    550 
    551 	/* Move the device into the configured state. */
    552 	(void) usbd_set_config_index(uaa->device, 0, 1);
    553 }
    554 
    555 static int
    556 u3ginit_detach(device_t self, int flags)
    557 {
    558 
    559 	return (0);
    560 }
    561 
    562 
    563 /*
    564  * Second personality:
    565  *
    566  * Claim only those interfaces required for 3G modem operation.
    567  */
    568 
    569 static int
    570 u3g_match(device_t parent, cfdata_t match, void *aux)
    571 {
    572 	struct usbif_attach_arg *uaa = aux;
    573 	usbd_interface_handle iface;
    574 	usb_interface_descriptor_t *id;
    575 	usbd_status error;
    576 
    577 	if (!usb_lookup(u3g_devs, uaa->vendor, uaa->product))
    578 		return (UMATCH_NONE);
    579 
    580 	error = usbd_device2interface_handle(uaa->device, uaa->ifaceno, &iface);
    581 	if (error) {
    582 		printf("u3g_match: failed to get interface, err=%s\n",
    583 		    usbd_errstr(error));
    584 		return (UMATCH_NONE);
    585 	}
    586 
    587 	id = usbd_get_interface_descriptor(iface);
    588 	if (id == NULL) {
    589 		printf("u3g_match: failed to get interface descriptor\n");
    590 		return (UMATCH_NONE);
    591 	}
    592 
    593 	/*
    594 	 * 3G modems generally report vendor-specific class
    595 	 *
    596 	 * XXX: this may be too generalised.
    597 	 */
    598 	return ((id->bInterfaceClass == UICLASS_VENDOR) ?
    599 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
    600 }
    601 
    602 static void
    603 u3g_attach(device_t parent, device_t self, void *aux)
    604 {
    605 	struct u3g_softc *sc = device_private(self);
    606 	struct usbif_attach_arg *uaa = aux;
    607 	usbd_device_handle dev = uaa->device;
    608 	usbd_interface_handle iface;
    609 	usb_interface_descriptor_t *id;
    610 	usb_endpoint_descriptor_t *ed;
    611 	struct ucom_attach_args uca;
    612 	usbd_status error;
    613 	int n, intr_address, intr_size;
    614 
    615 	aprint_naive("\n");
    616 	aprint_normal("\n");
    617 
    618 	sc->sc_dev = self;
    619 	sc->sc_dying = false;
    620 	sc->sc_udev = dev;
    621 
    622 	error = usbd_device2interface_handle(dev, uaa->ifaceno, &iface);
    623 	if (error) {
    624 		aprint_error_dev(self, "failed to get interface, err=%s\n",
    625 		    usbd_errstr(error));
    626 		return;
    627 	}
    628 
    629 	id = usbd_get_interface_descriptor(iface);
    630 
    631 	uca.info = "3G Modem";
    632 	uca.ibufsize = U3G_BUFF_SIZE;
    633 	uca.obufsize = U3G_BUFF_SIZE;
    634 	uca.ibufsizepad = U3G_BUFF_SIZE;
    635 	uca.opkthdrlen = 0;
    636 	uca.device = dev;
    637 	uca.iface = iface;
    638 	uca.methods = &u3g_methods;
    639 	uca.arg = sc;
    640 	uca.portno = -1;
    641 	uca.bulkin = uca.bulkout = -1;
    642 
    643 
    644 	sc->sc_ifaceno = uaa->ifaceno;
    645 	intr_address = -1;
    646 	intr_size = 0;
    647 
    648 	for (n = 0; n < id->bNumEndpoints; n++) {
    649 		ed = usbd_interface2endpoint_descriptor(iface, n);
    650 		if (ed == NULL) {
    651 			aprint_error_dev(self, "no endpoint descriptor "
    652 			    "for %d (interface: %d)\n", n, sc->sc_ifaceno);
    653 			sc->sc_dying = true;
    654 			return;
    655 		}
    656 
    657 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    658 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
    659 			intr_address = ed->bEndpointAddress;
    660 			intr_size = UGETW(ed->wMaxPacketSize);
    661 		} else
    662 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    663 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    664 			uca.bulkin = ed->bEndpointAddress;
    665 		} else
    666 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    667 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    668 			uca.bulkout = ed->bEndpointAddress;
    669 		}
    670 		if (uca.bulkin != -1 && uca.bulkout != -1) {
    671 			struct u3g_com *com;
    672 			if (sc->sc_ncom == __arraycount(sc->sc_com)) {
    673 				aprint_error_dev(self, "Need to configure "
    674 				    "more than %zu ttys", sc->sc_ncom);
    675 				continue;
    676 			}
    677 			uca.portno = sc->sc_ncom++;
    678 			com = &sc->sc_com[uca.portno];
    679 			com->c_outpins = 0;
    680 			com->c_msr = UMSR_DSR | UMSR_CTS | UMSR_DCD;
    681 			com->c_open = false;
    682 			com->c_purging = false;
    683 			com->c_dev = config_found_sm_loc(self, "ucombus",
    684 				NULL, &uca, ucomprint, ucomsubmatch);
    685 			uca.bulkin = -1;
    686 			uca.bulkout = -1;
    687 		}
    688 	}
    689 
    690 	if (sc->sc_ncom == 0) {
    691 		aprint_error_dev(self, "Missing bulk in/out for interface %d\n",
    692 		    sc->sc_ifaceno);
    693 		sc->sc_dying = true;
    694 		return;
    695 	}
    696 
    697 	/*
    698 	 * If the interface has an interrupt pipe, open it immediately so
    699 	 * that we can track input pin state changes regardless of whether
    700 	 * the tty(4) device is open or not.
    701 	 */
    702 	if (intr_address != -1) {
    703 		sc->sc_intr_buff = malloc(intr_size, M_USBDEV, M_WAITOK);
    704 		error = usbd_open_pipe_intr(iface, intr_address,
    705 		    USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buff,
    706 		    intr_size, u3g_intr, 100);
    707 		if (error) {
    708 			aprint_error_dev(self, "cannot open interrupt pipe "
    709 			    "(addr %d)\n", intr_address);
    710 			return;
    711 		}
    712 	} else {
    713 		sc->sc_intr_pipe = NULL;
    714 		sc->sc_intr_buff = NULL;
    715 	}
    716 
    717 	if (!pmf_device_register(self, NULL, NULL))
    718 		aprint_error_dev(self, "couldn't establish power handler\n");
    719 }
    720 
    721 static int
    722 u3g_detach(device_t self, int flags)
    723 {
    724 	struct u3g_softc *sc = device_private(self);
    725 	int rv;
    726 
    727 	if (sc->sc_dying)
    728 		return 0;
    729 
    730 	pmf_device_deregister(self);
    731 
    732 	for (size_t i = 0; i < sc->sc_ncom; i++)
    733 		if (sc->sc_com[i].c_dev != NULL) {
    734 			rv = config_detach(sc->sc_com[i].c_dev, flags);
    735 			if (rv != 0) {
    736 				aprint_verbose_dev(self, "Can't deallocate "
    737 				    "port (%d)", rv);
    738 			}
    739 		}
    740 
    741 	if (sc->sc_intr_pipe != NULL) {
    742 		(void) usbd_abort_pipe(sc->sc_intr_pipe);
    743 		(void) usbd_close_pipe(sc->sc_intr_pipe);
    744 		sc->sc_intr_pipe = NULL;
    745 	}
    746 	if (sc->sc_intr_buff != NULL) {
    747 		free(sc->sc_intr_buff, M_USBDEV);
    748 		sc->sc_intr_buff = NULL;
    749 	}
    750 
    751 	return (0);
    752 }
    753 
    754 static void
    755 u3g_childdet(device_t self, device_t child)
    756 {
    757 	struct u3g_softc *sc = device_private(self);
    758 
    759 	for (size_t i = 0; i < sc->sc_ncom; i++)
    760 		    if (sc->sc_com[i].c_dev == child)
    761 			    sc->sc_com[i].c_dev = NULL;
    762 }
    763 
    764 static int
    765 u3g_activate(device_t self, enum devact act)
    766 {
    767 	struct u3g_softc *sc = device_private(self);
    768 	int rv = 0;
    769 
    770 	switch (act) {
    771 	case DVACT_DEACTIVATE:
    772 		for (size_t i = 0; i < sc->sc_ncom; i++)
    773 			if (sc->sc_com[i].c_dev != NULL &&
    774 			    config_deactivate(sc->sc_com[i].c_dev) && rv == 0)
    775 			rv = -1;
    776 		else
    777 			rv = 0;
    778 		break;
    779 
    780 	default:
    781 		break;
    782 	}
    783 
    784 	return rv;
    785 }
    786 
    787 static void
    788 u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
    789 {
    790 	struct u3g_softc *sc = (struct u3g_softc *)priv;
    791 	u_char *buf;
    792 	int portno = 0;	/* XXX */
    793 	struct u3g_com *com = &sc->sc_com[portno];
    794 
    795 	if (sc->sc_dying)
    796 		return;
    797 
    798 	if (status != USBD_NORMAL_COMPLETION) {
    799 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    800 			return;
    801 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
    802 		return;
    803 	}
    804 
    805 	buf = sc->sc_intr_buff;
    806 	if (buf[0] == 0xa1 && buf[1] == 0x20) {
    807 		u_char msr;
    808 
    809 		msr = com->c_msr & ~(UMSR_DCD | UMSR_DSR | UMSR_RI);
    810 
    811 		if (buf[8] & U3G_INPIN_DCD)
    812 			msr |= UMSR_DCD;
    813 
    814 		if (buf[8] & U3G_INPIN_DSR)
    815 			msr |= UMSR_DSR;
    816 
    817 		if (buf[8] & U3G_INPIN_RI)
    818 			msr |= UMSR_RI;
    819 
    820 		if (msr != com->c_msr) {
    821 			com->c_msr = msr;
    822 			if (com->c_open)
    823 				ucom_status_change(device_private(com->c_dev));
    824 		}
    825 	}
    826 }
    827 
    828 /*ARGSUSED*/
    829 static void
    830 u3g_get_status(void *arg, int portno, u_char *lsr, u_char *msr)
    831 {
    832 	struct u3g_softc *sc = arg;
    833 
    834 	if (lsr != NULL)
    835 		*lsr = 0;	/* LSR isn't supported */
    836 	if (msr != NULL)
    837 		*msr = sc->sc_com[portno].c_msr;
    838 }
    839 
    840 /*ARGSUSED*/
    841 static void
    842 u3g_set(void *arg, int portno, int reg, int onoff)
    843 {
    844 	struct u3g_softc *sc = arg;
    845 	usb_device_request_t req;
    846 	uint16_t mask, new_state;
    847 	usbd_status err;
    848 	struct u3g_com *com = &sc->sc_com[portno];
    849 
    850 	if (sc->sc_dying)
    851 		return;
    852 
    853 	switch (reg) {
    854 	case UCOM_SET_DTR:
    855 		mask = U3G_OUTPIN_DTR;
    856 		break;
    857 	case UCOM_SET_RTS:
    858 		mask = U3G_OUTPIN_RTS;
    859 		break;
    860 	default:
    861 		return;
    862 	}
    863 
    864 	new_state = com->c_outpins & ~mask;
    865 	if (onoff)
    866 		new_state |= mask;
    867 
    868 	if (new_state == com->c_outpins)
    869 		return;
    870 
    871 	com->c_outpins = new_state;
    872 
    873 	req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    874 	req.bRequest = U3G_SET_PIN;
    875 	USETW(req.wValue, new_state);
    876 	USETW(req.wIndex, sc->sc_ifaceno);
    877 	USETW(req.wLength, 0);
    878 
    879 	err = usbd_do_request(sc->sc_udev, &req, 0);
    880 	if (err == USBD_STALLED)
    881 		usbd_clear_endpoint_stall(sc->sc_udev->default_pipe);
    882 }
    883 
    884 /*ARGSUSED*/
    885 static int
    886 u3g_open(void *arg, int portno)
    887 {
    888 	struct u3g_softc *sc = arg;
    889 	usb_device_request_t req;
    890 	usb_endpoint_descriptor_t *ed;
    891 	usb_interface_descriptor_t *id;
    892 	usbd_interface_handle ih;
    893 	usbd_status err;
    894 	struct u3g_com *com = &sc->sc_com[portno];
    895 	int i, nin;
    896 
    897 	if (sc->sc_dying)
    898 		return (0);
    899 
    900 	err = usbd_device2interface_handle(sc->sc_udev, sc->sc_ifaceno, &ih);
    901 	if (err)
    902 		return (EIO);
    903 
    904 	id = usbd_get_interface_descriptor(ih);
    905 
    906 	for (nin = i = 0; i < id->bNumEndpoints; i++) {
    907 		ed = usbd_interface2endpoint_descriptor(ih, i);
    908 		if (ed == NULL)
    909 			return (EIO);
    910 
    911 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    912 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK &&
    913 		    nin++ == portno) {
    914 			/* Issue ENDPOINT_HALT request */
    915 			req.bmRequestType = UT_WRITE_ENDPOINT;
    916 			req.bRequest = UR_CLEAR_FEATURE;
    917 			USETW(req.wValue, UF_ENDPOINT_HALT);
    918 			USETW(req.wIndex, ed->bEndpointAddress);
    919 			USETW(req.wLength, 0);
    920 			err = usbd_do_request(sc->sc_udev, &req, 0);
    921 			if (err)
    922 				return (EIO);
    923 		}
    924 	}
    925 
    926 	com->c_open = true;
    927 	com->c_purging = true;
    928 	getmicrotime(&com->c_purge_start);
    929 
    930 	return (0);
    931 }
    932 
    933 /*ARGSUSED*/
    934 static void
    935 u3g_close(void *arg, int portno)
    936 {
    937 	struct u3g_softc *sc = arg;
    938 	struct u3g_com *com = &sc->sc_com[portno];
    939 
    940 	com->c_open = false;
    941 }
    942 
    943 /*ARGSUSED*/
    944 static void
    945 u3g_read(void *arg, int portno, u_char **cpp, uint32_t *ccp)
    946 {
    947 	struct u3g_softc *sc = arg;
    948 	struct timeval curr_tv, diff_tv;
    949 	struct u3g_com *com = &sc->sc_com[portno];
    950 
    951 	/*
    952 	 * If we're not purging input data following first open, do nothing.
    953 	 */
    954 	if (com->c_purging == false)
    955 		return;
    956 
    957 	/*
    958 	 * Otherwise check if the purge timeout has expired
    959 	 */
    960 	getmicrotime(&curr_tv);
    961 	timersub(&curr_tv, &com->c_purge_start, &diff_tv);
    962 
    963 	if (diff_tv.tv_sec >= U3G_PURGE_SECS) {
    964 		/* Timeout expired. */
    965 		com->c_purging = false;
    966 	} else {
    967 		/* Still purging. Adjust the caller's byte count. */
    968 		*ccp = 0;
    969 	}
    970 }
    971 
    972 /*ARGSUSED*/
    973 static void
    974 u3g_write(void *arg, int portno, u_char *to, u_char *from, u_int32_t *count)
    975 {
    976 	struct u3g_softc *sc = arg;
    977 	struct u3g_com *com = &sc->sc_com[portno];
    978 
    979 	/*
    980 	 * Stop purging as soon as the first data is written to the device.
    981 	 */
    982 	com->c_purging = false;
    983 	memcpy(to, from, *count);
    984 }
    985