Home | History | Annotate | Line # | Download | only in usb
u3g.c revision 1.6.4.1
      1  1.6.4.1       jym /*	$NetBSD: u3g.c,v 1.6.4.1 2009/07/23 23:32:21 jym Exp $	*/
      2  1.6.4.1       jym 
      3      1.1     joerg /*
      4      1.1     joerg  * Copyright (c) 2008 AnyWi Technologies
      5      1.1     joerg  *   Author: Andrea Guzzo <aguzzo (at) anywi.com>
      6      1.1     joerg  *   * based on uark.c 1.1 2006/08/14 08:30:22 jsg *
      7      1.1     joerg  *   * parts from ubsa.c 183348 2008-09-25 12:00:56Z phk *
      8      1.1     joerg  *
      9      1.1     joerg  * Permission to use, copy, modify, and distribute this software for any
     10      1.1     joerg  * purpose with or without fee is hereby granted, provided that the above
     11      1.1     joerg  * copyright notice and this permission notice appear in all copies.
     12      1.1     joerg  *
     13      1.1     joerg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     14      1.1     joerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     15      1.1     joerg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     16      1.1     joerg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     17      1.1     joerg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     18      1.1     joerg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     19      1.1     joerg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     20      1.1     joerg  *
     21      1.1     joerg  * $FreeBSD$
     22      1.1     joerg  */
     23      1.1     joerg 
     24  1.6.4.1       jym #include <sys/cdefs.h>
     25  1.6.4.1       jym __KERNEL_RCSID(0, "$NetBSD: u3g.c,v 1.6.4.1 2009/07/23 23:32:21 jym Exp $");
     26  1.6.4.1       jym 
     27      1.1     joerg #include <sys/param.h>
     28      1.1     joerg #include <sys/systm.h>
     29      1.1     joerg #include <sys/kernel.h>
     30      1.1     joerg #include <sys/malloc.h>
     31      1.1     joerg #include <sys/module.h>
     32      1.1     joerg #include <sys/bus.h>
     33      1.1     joerg #include <sys/ioccom.h>
     34      1.1     joerg #include <sys/fcntl.h>
     35      1.1     joerg #include <sys/conf.h>
     36      1.1     joerg #include <sys/tty.h>
     37      1.1     joerg #include <sys/file.h>
     38      1.1     joerg #include <sys/selinfo.h>
     39      1.1     joerg 
     40      1.1     joerg #include <dev/usb/usb.h>
     41      1.1     joerg #include <dev/usb/usbdi.h>
     42      1.1     joerg #include <dev/usb/usbdivar.h>
     43      1.1     joerg #include <dev/usb/usbdi_util.h>
     44      1.1     joerg 
     45      1.1     joerg #include <dev/usb/ucomvar.h>
     46      1.1     joerg 
     47      1.1     joerg #include "usbdevs.h"
     48      1.1     joerg 
     49      1.1     joerg #define U3GBUFSZ        1024
     50      1.1     joerg #define U3G_MAXPORTS           4
     51      1.1     joerg 
     52      1.1     joerg struct u3g_softc {
     53      1.6      yamt 	device_t                    sc_ucom[U3G_MAXPORTS];
     54      1.1     joerg 	device_t                    sc_dev;
     55      1.1     joerg 	usbd_device_handle          sc_udev;
     56      1.1     joerg 	u_char                      sc_msr;
     57      1.1     joerg 	u_char                      sc_lsr;
     58      1.1     joerg 	u_char                      numports;
     59      1.1     joerg 
     60      1.1     joerg 	usbd_interface_handle       sc_intr_iface;   /* interrupt interface */
     61      1.1     joerg #ifdef U3G_DEBUG
     62      1.1     joerg 	int                         sc_intr_number;  /* interrupt number */
     63      1.1     joerg 	usbd_pipe_handle            sc_intr_pipe;    /* interrupt pipe */
     64      1.1     joerg 	u_char                      *sc_intr_buf;    /* interrupt buffer */
     65      1.1     joerg #endif
     66      1.1     joerg 	int                         sc_isize;
     67      1.2     joerg 	bool                        sc_pseudodev;
     68      1.1     joerg };
     69      1.1     joerg 
     70      1.1     joerg struct ucom_methods u3g_methods = {
     71      1.1     joerg 	NULL,
     72      1.1     joerg 	NULL,
     73      1.1     joerg 	NULL,
     74      1.1     joerg 	NULL,
     75      1.1     joerg 	NULL,
     76      1.1     joerg 	NULL,
     77      1.1     joerg 	NULL,
     78      1.1     joerg 	NULL,
     79      1.1     joerg };
     80      1.1     joerg 
     81      1.1     joerg static const struct usb_devno u3g_devs[] = {
     82      1.1     joerg 	/* OEM: Option N.V. */
     83      1.1     joerg 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_QUADPLUSUMTS },
     84      1.1     joerg 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_HSDPA },
     85      1.3     joerg 	{ USB_VENDOR_OPTIONNV, USB_PRODUCT_OPTIONNV_GTMAXHSUPA },
     86      1.3     joerg 	/* OEM: Qualcomm, Inc. */
     87      1.3     joerg 	{ USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM },
     88      1.1     joerg 	/* OEM: Huawei */
     89      1.1     joerg 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE },
     90      1.1     joerg 	{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
     91      1.1     joerg 	/* OEM: Novatel */
     92      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
     93      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 },
     94      1.1     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D },
     95      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 },
     96      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U727 },
     97      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINU740 },
     98      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U740_2 },
     99      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U870 },
    100      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 },
    101      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 },
    102      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_V740 },
    103      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_X950D },
    104      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 },
    105      1.3     joerg         { USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 },
    106      1.3     joerg #if 0
    107      1.3     joerg 	{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MC950D_DRIVER },
    108      1.3     joerg #endif
    109      1.3     joerg 	/* OEM: Merlin */
    110      1.3     joerg 	{ USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620 },
    111      1.1     joerg 
    112      1.3     joerg 	/* OEM: Sierra Wireless: */
    113      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 },
    114      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 },
    115      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U },
    116      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E },
    117      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597 },
    118      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880 },
    119      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E },
    120      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U },
    121      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881 },
    122      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E },
    123      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U },
    124      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 },
    125      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 },
    126      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2 },
    127      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 },
    128      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725 },
    129      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 },
    130      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 },
    131      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 },
    132      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 },
    133      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 },
    134      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U },
    135      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2 },
    136      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780 },
    137      1.3     joerg 	{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781 },
    138      1.1     joerg };
    139      1.1     joerg 
    140      1.1     joerg #ifdef U3G_DEBUG
    141      1.1     joerg static void
    142      1.1     joerg u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
    143      1.1     joerg {
    144      1.1     joerg 	struct u3g_softc *sc = (struct u3g_softc *)priv;
    145      1.1     joerg 	aprint_normal_dev(sc->sc_dev, "INTERRUPT CALLBACK\n");
    146      1.1     joerg }
    147      1.1     joerg #endif
    148      1.1     joerg 
    149      1.1     joerg static int
    150      1.2     joerg u3g_novatel_reinit(struct usb_attach_arg *uaa)
    151      1.2     joerg {
    152      1.2     joerg 	unsigned char cmd[31];
    153      1.2     joerg 	usbd_interface_handle iface;
    154      1.2     joerg 	usb_interface_descriptor_t *id;
    155      1.2     joerg 	usb_endpoint_descriptor_t *ed;
    156      1.2     joerg 	usbd_pipe_handle pipe;
    157      1.2     joerg 	usbd_xfer_handle xfer;
    158      1.2     joerg 	int err, i;
    159      1.2     joerg 
    160      1.2     joerg 	memset(cmd, 0, sizeof(cmd));
    161      1.2     joerg 	/* Byte 0..3: Command Block Wrapper (CBW) signature */
    162      1.2     joerg 	cmd[0] = 0x55;
    163      1.2     joerg 	cmd[1] = 0x53;
    164      1.2     joerg 	cmd[2] = 0x42;
    165      1.2     joerg 	cmd[3] = 0x43;
    166      1.2     joerg 	/* 4..7: CBW Tag, has to unique, but only a single transfer used. */
    167      1.2     joerg 	cmd[4] = 0x01;
    168      1.2     joerg 	/* 8..11: CBW Transfer Length, no data here */
    169      1.2     joerg 	/* 12: CBW Flag: output, so 0 */
    170      1.2     joerg 	/* 13: CBW Lun: 0 */
    171      1.2     joerg 	/* 14: CBW Length */
    172      1.2     joerg 	cmd[14] = 0x06;
    173      1.2     joerg 	/* Rest is the SCSI payload */
    174      1.2     joerg 	/* 0: SCSI START/STOP opcode */
    175      1.2     joerg 	cmd[15] = 0x1b;
    176      1.2     joerg 	/* 1..3 unused */
    177      1.2     joerg 	/* 4 Load/Eject command */
    178      1.2     joerg 	cmd[19] = 0x02;
    179      1.2     joerg 	/* 5: unused */
    180      1.2     joerg 
    181      1.2     joerg 
    182      1.2     joerg 	/* Move the device into the configured state. */
    183      1.2     joerg 	err = usbd_set_config_index(uaa->device, 0, 0);
    184      1.2     joerg 	if (err) {
    185      1.2     joerg 		aprint_error("u3g: failed to set configuration index\n");
    186      1.2     joerg 		return UMATCH_NONE;
    187      1.2     joerg 	}
    188      1.2     joerg 
    189      1.2     joerg 	err = usbd_device2interface_handle(uaa->device, 0, &iface);
    190      1.2     joerg 	if (err != 0) {
    191      1.2     joerg 		aprint_error("u3g: failed to get interface\n");
    192      1.2     joerg 		return UMATCH_NONE;
    193      1.2     joerg 	}
    194      1.2     joerg 
    195      1.2     joerg 	id = usbd_get_interface_descriptor(iface);
    196      1.2     joerg 	ed = NULL;
    197      1.2     joerg 	for (i = 0 ; i < id->bNumEndpoints ; i++) {
    198      1.2     joerg 		ed = usbd_interface2endpoint_descriptor(iface, i);
    199      1.2     joerg 		if (ed == NULL)
    200      1.2     joerg 			continue;
    201      1.2     joerg 		if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
    202      1.2     joerg 			continue;
    203      1.2     joerg 		if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
    204      1.2     joerg 			break;
    205      1.2     joerg 	}
    206      1.2     joerg 
    207      1.2     joerg 	if (i == id->bNumEndpoints)
    208      1.2     joerg 		return UMATCH_NONE;
    209      1.2     joerg 
    210      1.2     joerg 	err = usbd_open_pipe(iface, ed->bEndpointAddress, USBD_EXCLUSIVE_USE,
    211      1.2     joerg 	    &pipe);
    212      1.2     joerg 	if (err != 0) {
    213      1.2     joerg 		aprint_error("u3g: failed to open bulk transfer pipe %d\n",
    214      1.2     joerg 		    ed->bEndpointAddress);
    215      1.2     joerg 		return UMATCH_NONE;
    216      1.2     joerg 	}
    217      1.2     joerg 
    218      1.2     joerg 	xfer = usbd_alloc_xfer(uaa->device);
    219      1.2     joerg 	if (xfer != NULL) {
    220      1.2     joerg 		usbd_setup_xfer(xfer, pipe, NULL, cmd, sizeof(cmd),
    221      1.2     joerg 		    USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
    222      1.2     joerg 
    223      1.2     joerg 		err = usbd_transfer(xfer);
    224      1.2     joerg 		if (err)
    225      1.2     joerg 			aprint_error("u3g: transfer failed\n");
    226      1.2     joerg 		usbd_free_xfer(xfer);
    227      1.2     joerg 	} else {
    228      1.2     joerg 		aprint_error("u3g: failed to allocate xfer\n");
    229      1.2     joerg 		err = USBD_NOMEM;
    230      1.2     joerg 	}
    231      1.2     joerg 
    232      1.2     joerg 	usbd_abort_pipe(pipe);
    233      1.2     joerg 	usbd_close_pipe(pipe);
    234      1.2     joerg 
    235      1.2     joerg 	return (err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE);
    236      1.2     joerg }
    237      1.2     joerg 
    238      1.2     joerg static int
    239      1.1     joerg u3g_huawei_reinit(usbd_device_handle dev)
    240      1.1     joerg {
    241      1.1     joerg 	/* The Huawei device presents itself as a umass device with Windows
    242      1.1     joerg 	 * drivers on it. After installation of the driver, it reinits into a
    243      1.1     joerg 	 * 3G serial device.
    244      1.1     joerg 	 */
    245      1.1     joerg 	usb_device_request_t req;
    246      1.1     joerg 	usb_config_descriptor_t *cdesc;
    247      1.1     joerg 
    248      1.1     joerg 	/* Get the config descriptor */
    249      1.1     joerg 	cdesc = usbd_get_config_descriptor(dev);
    250      1.1     joerg 	if (cdesc == NULL)
    251      1.1     joerg 		return (UMATCH_NONE);
    252      1.1     joerg 
    253      1.1     joerg 	/* One iface means umass mode, more than 1 (4 usually) means 3G mode */
    254      1.1     joerg 	if (cdesc->bNumInterface > 1)
    255      1.1     joerg 		return (UMATCH_VENDOR_PRODUCT);
    256      1.1     joerg 
    257      1.1     joerg 	req.bmRequestType = UT_WRITE_DEVICE;
    258      1.1     joerg 	req.bRequest = UR_SET_FEATURE;
    259      1.1     joerg 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
    260      1.1     joerg 	USETW(req.wIndex, UHF_PORT_SUSPEND);
    261      1.1     joerg 	USETW(req.wLength, 0);
    262      1.1     joerg 
    263      1.1     joerg 	(void) usbd_do_request(dev, &req, 0);
    264      1.1     joerg 
    265      1.2     joerg 
    266      1.2     joerg 	return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
    267      1.1     joerg }
    268      1.1     joerg 
    269      1.1     joerg static int
    270      1.4  christos u3g_sierra_reinit(usbd_device_handle dev)
    271      1.4  christos {
    272      1.4  christos 	/* Some Sierra devices presents themselves as a umass device with
    273      1.4  christos 	 * Windows drivers on it. After installation of the driver, it
    274      1.4  christos 	 * reinits into a * 3G serial device.
    275      1.4  christos 	 */
    276      1.4  christos 	usb_device_request_t req;
    277      1.4  christos 	usb_config_descriptor_t *cdesc;
    278      1.4  christos 
    279      1.4  christos 	/* Get the config descriptor */
    280      1.4  christos 	cdesc = usbd_get_config_descriptor(dev);
    281      1.4  christos 	if (cdesc == NULL)
    282      1.4  christos 		return (UMATCH_NONE);
    283      1.4  christos 
    284      1.4  christos 	req.bmRequestType = UT_VENDOR;
    285      1.4  christos 	req.bRequest = UR_SET_INTERFACE;
    286      1.4  christos 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
    287      1.4  christos 	USETW(req.wIndex, UHF_PORT_CONNECTION);
    288      1.4  christos 	USETW(req.wLength, 0);
    289      1.4  christos 
    290      1.4  christos 	(void) usbd_do_request(dev, &req, 0);
    291      1.4  christos 
    292      1.4  christos 	return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
    293      1.4  christos }
    294      1.4  christos 
    295      1.4  christos static int
    296      1.1     joerg u3g_match(device_t parent, cfdata_t match, void *aux)
    297      1.1     joerg {
    298      1.1     joerg 	struct usb_attach_arg *uaa = aux;
    299      1.1     joerg 
    300      1.1     joerg 	if (uaa->vendor == USB_VENDOR_HUAWEI)
    301      1.1     joerg 		return u3g_huawei_reinit(uaa->device);
    302      1.1     joerg 
    303      1.2     joerg 	if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
    304      1.2     joerg 	    uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER)
    305      1.2     joerg 		return u3g_novatel_reinit(uaa);
    306      1.2     joerg 
    307      1.4  christos 	if (uaa->vendor == USB_VENDOR_SIERRA &&
    308      1.4  christos 	    uaa->product == USB_PRODUCT_SIERRA_INSTALLER)
    309      1.4  christos 		return u3g_sierra_reinit(uaa->device);
    310      1.4  christos 
    311      1.1     joerg 	if (usb_lookup(u3g_devs, uaa->vendor, uaa->product))
    312      1.1     joerg 		return UMATCH_VENDOR_PRODUCT;
    313      1.1     joerg 
    314      1.1     joerg 	return UMATCH_NONE;
    315      1.1     joerg }
    316      1.1     joerg 
    317      1.1     joerg static void
    318      1.1     joerg u3g_attach(device_t parent, device_t self, void *aux)
    319      1.1     joerg {
    320      1.1     joerg 	struct u3g_softc *sc = device_private(self);
    321      1.1     joerg 	struct usb_attach_arg *uaa = aux;
    322      1.1     joerg 	usbd_device_handle dev = uaa->device;
    323      1.1     joerg 	usbd_interface_handle iface;
    324      1.1     joerg 	usb_interface_descriptor_t *id;
    325      1.1     joerg 	usb_endpoint_descriptor_t *ed;
    326      1.1     joerg 	usbd_status error;
    327      1.1     joerg 	int i, n;
    328      1.1     joerg 	usb_config_descriptor_t *cdesc;
    329      1.1     joerg 
    330      1.1     joerg 	aprint_naive("\n");
    331      1.1     joerg 	aprint_normal("\n");
    332      1.1     joerg 
    333      1.2     joerg 	if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
    334      1.2     joerg 	    uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER) {
    335      1.2     joerg 		/* About to disappear... */
    336      1.2     joerg 		sc->sc_pseudodev = true;
    337      1.2     joerg 		return;
    338      1.2     joerg 	}
    339      1.2     joerg 
    340      1.1     joerg 	sc->sc_dev = self;
    341      1.1     joerg #ifdef U3G_DEBUG
    342      1.1     joerg 	sc->sc_intr_number = -1;
    343      1.1     joerg 	sc->sc_intr_pipe = NULL;
    344      1.1     joerg #endif
    345      1.1     joerg 	/* Move the device into the configured state. */
    346      1.1     joerg 	error = usbd_set_config_index(dev, 0, 1);
    347      1.1     joerg 	if (error) {
    348      1.1     joerg 		aprint_error_dev(self, "failed to set configuration: %s\n",
    349      1.1     joerg 			      usbd_errstr(error));
    350      1.1     joerg 		return;
    351      1.1     joerg 	}
    352      1.1     joerg 
    353      1.1     joerg 	/* get the config descriptor */
    354      1.1     joerg 	cdesc = usbd_get_config_descriptor(dev);
    355      1.1     joerg 
    356      1.1     joerg 	if (cdesc == NULL) {
    357      1.1     joerg 		aprint_error_dev(self, "failed to get configuration descriptor\n");
    358      1.1     joerg 		return;
    359      1.1     joerg 	}
    360      1.1     joerg 
    361      1.2     joerg 	if (uaa->vendor == USB_VENDOR_HUAWEI && cdesc->bNumInterface > 1) {
    362      1.2     joerg 		/* About to disappear... */
    363      1.2     joerg 		sc->sc_pseudodev = true;
    364      1.2     joerg 		return;
    365      1.2     joerg 	}
    366      1.2     joerg 
    367      1.4  christos 	if (uaa->vendor == USB_VENDOR_SIERRA &&
    368      1.4  christos 	    uaa->product == USB_PRODUCT_SIERRA_INSTALLER) {
    369      1.4  christos 		/* About to disappear... */
    370      1.4  christos 		sc->sc_pseudodev = true;
    371      1.4  christos 		return;
    372      1.4  christos 	}
    373      1.4  christos 
    374      1.1     joerg 	sc->sc_udev = dev;
    375      1.1     joerg 	sc->numports = (cdesc->bNumInterface <= U3G_MAXPORTS)?cdesc->bNumInterface:U3G_MAXPORTS;
    376      1.1     joerg 	for ( i = 0; i < sc->numports; i++ ) {
    377      1.1     joerg 		struct ucom_attach_args uca;
    378      1.1     joerg 
    379      1.1     joerg 		error = usbd_device2interface_handle(dev, i, &iface);
    380      1.1     joerg 		if (error) {
    381      1.1     joerg 			aprint_error_dev(self,
    382      1.1     joerg 			    "failed to get interface, err=%s\n",
    383      1.1     joerg 			    usbd_errstr(error));
    384      1.1     joerg 			return;
    385      1.1     joerg 		}
    386      1.1     joerg 		id = usbd_get_interface_descriptor(iface);
    387      1.1     joerg 
    388      1.1     joerg 		uca.info = "Generic 3G Serial Device";
    389      1.1     joerg 		uca.ibufsize = U3GBUFSZ;
    390      1.1     joerg 		uca.obufsize = U3GBUFSZ;
    391      1.1     joerg 		uca.ibufsizepad = U3GBUFSZ;
    392      1.1     joerg 		uca.portno = i;
    393      1.1     joerg 		uca.opkthdrlen = 0;
    394      1.1     joerg 		uca.device = dev;
    395      1.1     joerg 		uca.iface = iface;
    396      1.1     joerg 		uca.methods = &u3g_methods;
    397      1.1     joerg 		uca.arg = sc;
    398      1.1     joerg 
    399      1.1     joerg 		uca.bulkin = uca.bulkout = -1;
    400      1.1     joerg 		for (n = 0; n < id->bNumEndpoints; n++) {
    401      1.1     joerg 			ed = usbd_interface2endpoint_descriptor(iface, n);
    402      1.1     joerg 			if (ed == NULL) {
    403      1.1     joerg 				aprint_error_dev(self,
    404      1.1     joerg 					"could not read endpoint descriptor\n");
    405      1.1     joerg 				return;
    406      1.1     joerg 			}
    407      1.1     joerg 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    408      1.1     joerg 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    409      1.1     joerg 				uca.bulkin = ed->bEndpointAddress;
    410      1.1     joerg 			else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    411      1.1     joerg 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    412      1.1     joerg 				uca.bulkout = ed->bEndpointAddress;
    413      1.1     joerg 		}
    414      1.1     joerg 		if (uca.bulkin == -1 || uca.bulkout == -1) {
    415      1.1     joerg 			aprint_error_dev(self, "missing endpoint\n");
    416      1.1     joerg 			return;
    417      1.1     joerg 		}
    418      1.1     joerg 
    419      1.1     joerg 		sc->sc_ucom[i] = config_found_sm_loc(self, "ucombus", NULL, &uca,
    420      1.1     joerg 						    ucomprint, ucomsubmatch);
    421      1.1     joerg 	}
    422      1.1     joerg 
    423      1.1     joerg #ifdef U3G_DEBUG
    424      1.1     joerg 	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
    425      1.1     joerg 		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
    426      1.1     joerg 		error = usbd_open_pipe_intr(sc->sc_intr_iface,
    427      1.1     joerg 					    sc->sc_intr_number,
    428      1.1     joerg 					    USBD_SHORT_XFER_OK,
    429      1.1     joerg 					    &sc->sc_intr_pipe,
    430      1.1     joerg 					    sc,
    431      1.1     joerg 					    sc->sc_intr_buf,
    432      1.1     joerg 					    sc->sc_isize,
    433      1.1     joerg 					    u3g_intr,
    434      1.1     joerg 					    100);
    435      1.1     joerg 		if (error) {
    436      1.1     joerg 			aprint_error_dev(self,
    437      1.1     joerg 			    "cannot open interrupt pipe (addr %d)\n",
    438      1.1     joerg 			    sc->sc_intr_number);
    439      1.1     joerg 			return;
    440      1.1     joerg 		}
    441      1.1     joerg 	}
    442      1.1     joerg #endif
    443      1.1     joerg 
    444      1.1     joerg 
    445      1.1     joerg 	if (!pmf_device_register(self, NULL, NULL))
    446      1.1     joerg 		aprint_error_dev(self, "couldn't establish power handler\n");
    447      1.1     joerg }
    448      1.1     joerg 
    449      1.1     joerg static int
    450      1.1     joerg u3g_detach(device_t self, int flags)
    451      1.1     joerg {
    452      1.1     joerg 	struct u3g_softc *sc = device_private(self);
    453      1.1     joerg 	int rv = 0;
    454      1.1     joerg 	int i;
    455      1.1     joerg 
    456      1.2     joerg 	if (sc->sc_pseudodev)
    457      1.2     joerg 		return 0;
    458      1.2     joerg 
    459      1.1     joerg 	pmf_device_deregister(self);
    460      1.1     joerg 
    461      1.1     joerg 	for (i = 0; i < sc->numports; i++) {
    462      1.1     joerg 		if(sc->sc_ucom[i]) {
    463      1.1     joerg 			rv = config_detach(sc->sc_ucom[i], flags);
    464      1.1     joerg 			if(rv != 0) {
    465      1.1     joerg 				aprint_verbose_dev(self, "Can't deallocat port %d", i);
    466      1.1     joerg 				return rv;
    467      1.1     joerg 			}
    468      1.1     joerg 		}
    469      1.1     joerg 	}
    470      1.1     joerg 
    471      1.1     joerg #ifdef U3G_DEBUG
    472      1.1     joerg 	if (sc->sc_intr_pipe != NULL) {
    473      1.1     joerg 		int err = usbd_abort_pipe(sc->sc_intr_pipe);
    474      1.1     joerg 		if (err)
    475      1.1     joerg 			aprint_error_dev(self,
    476      1.1     joerg 				"abort interrupt pipe failed: %s\n",
    477      1.1     joerg 				usbd_errstr(err));
    478      1.1     joerg 		err = usbd_close_pipe(sc->sc_intr_pipe);
    479      1.1     joerg 		if (err)
    480      1.1     joerg 			aprint_error_dev(self,
    481      1.1     joerg 			    "close interrupt pipe failed: %s\n",
    482      1.1     joerg 			    usbd_errstr(err));
    483      1.1     joerg 		free(sc->sc_intr_buf, M_USBDEV);
    484      1.1     joerg 		sc->sc_intr_pipe = NULL;
    485      1.1     joerg 	}
    486      1.1     joerg #endif
    487      1.1     joerg 
    488      1.1     joerg 	return 0;
    489      1.1     joerg }
    490      1.1     joerg 
    491      1.1     joerg static void
    492      1.1     joerg u3g_childdet(device_t self, device_t child)
    493      1.1     joerg {
    494      1.1     joerg 	struct u3g_softc *sc = device_private(self);
    495      1.1     joerg 	int i;
    496      1.1     joerg 
    497      1.1     joerg 	for (i = 0; i < sc->numports; i++) {
    498      1.1     joerg 		if (sc->sc_ucom[i] == child)
    499      1.1     joerg 			sc->sc_ucom[i] = NULL;
    500      1.1     joerg 	}
    501      1.1     joerg }
    502      1.1     joerg 
    503      1.1     joerg static int
    504      1.1     joerg u3g_activate(device_t self, enum devact act)
    505      1.1     joerg {
    506      1.1     joerg 	struct u3g_softc *sc = device_private(self);
    507      1.1     joerg 	int i, rv = 0;
    508      1.1     joerg 
    509      1.1     joerg 	switch (act) {
    510      1.1     joerg 	case DVACT_ACTIVATE:
    511      1.1     joerg 		return (EOPNOTSUPP);
    512      1.1     joerg 		break;
    513      1.1     joerg 
    514      1.1     joerg 	case DVACT_DEACTIVATE:
    515      1.1     joerg 		for (i = 0; i < sc->numports; i++) {
    516      1.1     joerg 			if (sc->sc_ucom[i] && config_deactivate(sc->sc_ucom[i]))
    517      1.1     joerg 				rv = -1;
    518      1.1     joerg 		}
    519      1.1     joerg 		break;
    520      1.1     joerg 	}
    521      1.1     joerg 	return (rv);
    522      1.1     joerg }
    523      1.1     joerg 
    524      1.1     joerg CFATTACH_DECL2_NEW(u3g, sizeof(struct u3g_softc), u3g_match,
    525      1.1     joerg     u3g_attach, u3g_detach, u3g_activate, NULL, u3g_childdet);
    526