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