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