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