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