Home | History | Annotate | Line # | Download | only in usb
u3g.c revision 1.3
      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 	{ 0, 0 }
    134  1.1  joerg };
    135  1.1  joerg 
    136  1.1  joerg #ifdef U3G_DEBUG
    137  1.1  joerg static void
    138  1.1  joerg u3g_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
    139  1.1  joerg {
    140  1.1  joerg 	struct u3g_softc *sc = (struct u3g_softc *)priv;
    141  1.1  joerg 	aprint_normal_dev(sc->sc_dev, "INTERRUPT CALLBACK\n");
    142  1.1  joerg }
    143  1.1  joerg #endif
    144  1.1  joerg 
    145  1.1  joerg static int
    146  1.2  joerg u3g_novatel_reinit(struct usb_attach_arg *uaa)
    147  1.2  joerg {
    148  1.2  joerg 	unsigned char cmd[31];
    149  1.2  joerg 	usbd_interface_handle iface;
    150  1.2  joerg 	usb_interface_descriptor_t *id;
    151  1.2  joerg 	usb_endpoint_descriptor_t *ed;
    152  1.2  joerg 	usbd_pipe_handle pipe;
    153  1.2  joerg 	usbd_xfer_handle xfer;
    154  1.2  joerg 	int err, i;
    155  1.2  joerg 
    156  1.2  joerg 	memset(cmd, 0, sizeof(cmd));
    157  1.2  joerg 	/* Byte 0..3: Command Block Wrapper (CBW) signature */
    158  1.2  joerg 	cmd[0] = 0x55;
    159  1.2  joerg 	cmd[1] = 0x53;
    160  1.2  joerg 	cmd[2] = 0x42;
    161  1.2  joerg 	cmd[3] = 0x43;
    162  1.2  joerg 	/* 4..7: CBW Tag, has to unique, but only a single transfer used. */
    163  1.2  joerg 	cmd[4] = 0x01;
    164  1.2  joerg 	/* 8..11: CBW Transfer Length, no data here */
    165  1.2  joerg 	/* 12: CBW Flag: output, so 0 */
    166  1.2  joerg 	/* 13: CBW Lun: 0 */
    167  1.2  joerg 	/* 14: CBW Length */
    168  1.2  joerg 	cmd[14] = 0x06;
    169  1.2  joerg 	/* Rest is the SCSI payload */
    170  1.2  joerg 	/* 0: SCSI START/STOP opcode */
    171  1.2  joerg 	cmd[15] = 0x1b;
    172  1.2  joerg 	/* 1..3 unused */
    173  1.2  joerg 	/* 4 Load/Eject command */
    174  1.2  joerg 	cmd[19] = 0x02;
    175  1.2  joerg 	/* 5: unused */
    176  1.2  joerg 
    177  1.2  joerg 
    178  1.2  joerg 	/* Move the device into the configured state. */
    179  1.2  joerg 	err = usbd_set_config_index(uaa->device, 0, 0);
    180  1.2  joerg 	if (err) {
    181  1.2  joerg 		aprint_error("u3g: failed to set configuration index\n");
    182  1.2  joerg 		return UMATCH_NONE;
    183  1.2  joerg 	}
    184  1.2  joerg 
    185  1.2  joerg 	err = usbd_device2interface_handle(uaa->device, 0, &iface);
    186  1.2  joerg 	if (err != 0) {
    187  1.2  joerg 		aprint_error("u3g: failed to get interface\n");
    188  1.2  joerg 		return UMATCH_NONE;
    189  1.2  joerg 	}
    190  1.2  joerg 
    191  1.2  joerg 	id = usbd_get_interface_descriptor(iface);
    192  1.2  joerg 	ed = NULL;
    193  1.2  joerg 	for (i = 0 ; i < id->bNumEndpoints ; i++) {
    194  1.2  joerg 		ed = usbd_interface2endpoint_descriptor(iface, i);
    195  1.2  joerg 		if (ed == NULL)
    196  1.2  joerg 			continue;
    197  1.2  joerg 		if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
    198  1.2  joerg 			continue;
    199  1.2  joerg 		if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
    200  1.2  joerg 			break;
    201  1.2  joerg 	}
    202  1.2  joerg 
    203  1.2  joerg 	if (i == id->bNumEndpoints)
    204  1.2  joerg 		return UMATCH_NONE;
    205  1.2  joerg 
    206  1.2  joerg 	err = usbd_open_pipe(iface, ed->bEndpointAddress, USBD_EXCLUSIVE_USE,
    207  1.2  joerg 	    &pipe);
    208  1.2  joerg 	if (err != 0) {
    209  1.2  joerg 		aprint_error("u3g: failed to open bulk transfer pipe %d\n",
    210  1.2  joerg 		    ed->bEndpointAddress);
    211  1.2  joerg 		return UMATCH_NONE;
    212  1.2  joerg 	}
    213  1.2  joerg 
    214  1.2  joerg 	xfer = usbd_alloc_xfer(uaa->device);
    215  1.2  joerg 	if (xfer != NULL) {
    216  1.2  joerg 		usbd_setup_xfer(xfer, pipe, NULL, cmd, sizeof(cmd),
    217  1.2  joerg 		    USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
    218  1.2  joerg 
    219  1.2  joerg 		err = usbd_transfer(xfer);
    220  1.2  joerg 		if (err)
    221  1.2  joerg 			aprint_error("u3g: transfer failed\n");
    222  1.2  joerg 		usbd_free_xfer(xfer);
    223  1.2  joerg 	} else {
    224  1.2  joerg 		aprint_error("u3g: failed to allocate xfer\n");
    225  1.2  joerg 		err = USBD_NOMEM;
    226  1.2  joerg 	}
    227  1.2  joerg 
    228  1.2  joerg 	usbd_abort_pipe(pipe);
    229  1.2  joerg 	usbd_close_pipe(pipe);
    230  1.2  joerg 
    231  1.2  joerg 	return (err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE);
    232  1.2  joerg }
    233  1.2  joerg 
    234  1.2  joerg static int
    235  1.1  joerg u3g_huawei_reinit(usbd_device_handle dev)
    236  1.1  joerg {
    237  1.1  joerg 	/* The Huawei device presents itself as a umass device with Windows
    238  1.1  joerg 	 * drivers on it. After installation of the driver, it reinits into a
    239  1.1  joerg 	 * 3G serial device.
    240  1.1  joerg 	 */
    241  1.1  joerg 	usb_device_request_t req;
    242  1.1  joerg 	usb_config_descriptor_t *cdesc;
    243  1.1  joerg 
    244  1.1  joerg 	/* Get the config descriptor */
    245  1.1  joerg 	cdesc = usbd_get_config_descriptor(dev);
    246  1.1  joerg 	if (cdesc == NULL)
    247  1.1  joerg 		return (UMATCH_NONE);
    248  1.1  joerg 
    249  1.1  joerg 	/* One iface means umass mode, more than 1 (4 usually) means 3G mode */
    250  1.1  joerg 	if (cdesc->bNumInterface > 1)
    251  1.1  joerg 		return (UMATCH_VENDOR_PRODUCT);
    252  1.1  joerg 
    253  1.1  joerg 	req.bmRequestType = UT_WRITE_DEVICE;
    254  1.1  joerg 	req.bRequest = UR_SET_FEATURE;
    255  1.1  joerg 	USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
    256  1.1  joerg 	USETW(req.wIndex, UHF_PORT_SUSPEND);
    257  1.1  joerg 	USETW(req.wLength, 0);
    258  1.1  joerg 
    259  1.1  joerg 	(void) usbd_do_request(dev, &req, 0);
    260  1.1  joerg 
    261  1.2  joerg 
    262  1.2  joerg 	return (UMATCH_HIGHEST); /* Match to prevent umass from attaching */
    263  1.1  joerg }
    264  1.1  joerg 
    265  1.1  joerg static int
    266  1.1  joerg u3g_match(device_t parent, cfdata_t match, void *aux)
    267  1.1  joerg {
    268  1.1  joerg 	struct usb_attach_arg *uaa = aux;
    269  1.1  joerg 
    270  1.1  joerg 	if (uaa->vendor == USB_VENDOR_HUAWEI)
    271  1.1  joerg 		return u3g_huawei_reinit(uaa->device);
    272  1.1  joerg 
    273  1.2  joerg 	if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
    274  1.2  joerg 	    uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER)
    275  1.2  joerg 		return u3g_novatel_reinit(uaa);
    276  1.2  joerg 
    277  1.1  joerg 	if (usb_lookup(u3g_devs, uaa->vendor, uaa->product))
    278  1.1  joerg 		return UMATCH_VENDOR_PRODUCT;
    279  1.1  joerg 
    280  1.1  joerg 	return UMATCH_NONE;
    281  1.1  joerg }
    282  1.1  joerg 
    283  1.1  joerg static void
    284  1.1  joerg u3g_attach(device_t parent, device_t self, void *aux)
    285  1.1  joerg {
    286  1.1  joerg 	struct u3g_softc *sc = device_private(self);
    287  1.1  joerg 	struct usb_attach_arg *uaa = aux;
    288  1.1  joerg 	usbd_device_handle dev = uaa->device;
    289  1.1  joerg 	usbd_interface_handle iface;
    290  1.1  joerg 	usb_interface_descriptor_t *id;
    291  1.1  joerg 	usb_endpoint_descriptor_t *ed;
    292  1.1  joerg 	usbd_status error;
    293  1.1  joerg 	int i, n;
    294  1.1  joerg 	usb_config_descriptor_t *cdesc;
    295  1.1  joerg 
    296  1.1  joerg 	aprint_naive("\n");
    297  1.1  joerg 	aprint_normal("\n");
    298  1.1  joerg 
    299  1.2  joerg 	if (uaa->vendor == USB_VENDOR_NOVATEL2 &&
    300  1.2  joerg 	    uaa->product == USB_PRODUCT_NOVATEL2_MC950D_DRIVER) {
    301  1.2  joerg 		/* About to disappear... */
    302  1.2  joerg 		sc->sc_pseudodev = true;
    303  1.2  joerg 		return;
    304  1.2  joerg 	}
    305  1.2  joerg 
    306  1.1  joerg 	sc->sc_dev = self;
    307  1.1  joerg #ifdef U3G_DEBUG
    308  1.1  joerg 	sc->sc_intr_number = -1;
    309  1.1  joerg 	sc->sc_intr_pipe = NULL;
    310  1.1  joerg #endif
    311  1.1  joerg 	/* Move the device into the configured state. */
    312  1.1  joerg 	error = usbd_set_config_index(dev, 0, 1);
    313  1.1  joerg 	if (error) {
    314  1.1  joerg 		aprint_error_dev(self, "failed to set configuration: %s\n",
    315  1.1  joerg 			      usbd_errstr(error));
    316  1.1  joerg 		return;
    317  1.1  joerg 	}
    318  1.1  joerg 
    319  1.1  joerg 	/* get the config descriptor */
    320  1.1  joerg 	cdesc = usbd_get_config_descriptor(dev);
    321  1.1  joerg 
    322  1.1  joerg 	if (cdesc == NULL) {
    323  1.1  joerg 		aprint_error_dev(self, "failed to get configuration descriptor\n");
    324  1.1  joerg 		return;
    325  1.1  joerg 	}
    326  1.1  joerg 
    327  1.2  joerg 	if (uaa->vendor == USB_VENDOR_HUAWEI && cdesc->bNumInterface > 1) {
    328  1.2  joerg 		/* About to disappear... */
    329  1.2  joerg 		sc->sc_pseudodev = true;
    330  1.2  joerg 		return;
    331  1.2  joerg 	}
    332  1.2  joerg 
    333  1.1  joerg 	sc->sc_udev = dev;
    334  1.1  joerg 	sc->numports = (cdesc->bNumInterface <= U3G_MAXPORTS)?cdesc->bNumInterface:U3G_MAXPORTS;
    335  1.1  joerg 	for ( i = 0; i < sc->numports; i++ ) {
    336  1.1  joerg 		struct ucom_attach_args uca;
    337  1.1  joerg 
    338  1.1  joerg 		error = usbd_device2interface_handle(dev, i, &iface);
    339  1.1  joerg 		if (error) {
    340  1.1  joerg 			aprint_error_dev(self,
    341  1.1  joerg 			    "failed to get interface, err=%s\n",
    342  1.1  joerg 			    usbd_errstr(error));
    343  1.1  joerg 			return;
    344  1.1  joerg 		}
    345  1.1  joerg 		id = usbd_get_interface_descriptor(iface);
    346  1.1  joerg 
    347  1.1  joerg 		uca.info = "Generic 3G Serial Device";
    348  1.1  joerg 		uca.ibufsize = U3GBUFSZ;
    349  1.1  joerg 		uca.obufsize = U3GBUFSZ;
    350  1.1  joerg 		uca.ibufsizepad = U3GBUFSZ;
    351  1.1  joerg 		uca.portno = i;
    352  1.1  joerg 		uca.opkthdrlen = 0;
    353  1.1  joerg 		uca.device = dev;
    354  1.1  joerg 		uca.iface = iface;
    355  1.1  joerg 		uca.methods = &u3g_methods;
    356  1.1  joerg 		uca.arg = sc;
    357  1.1  joerg 
    358  1.1  joerg 		uca.bulkin = uca.bulkout = -1;
    359  1.1  joerg 		for (n = 0; n < id->bNumEndpoints; n++) {
    360  1.1  joerg 			ed = usbd_interface2endpoint_descriptor(iface, n);
    361  1.1  joerg 			if (ed == NULL) {
    362  1.1  joerg 				aprint_error_dev(self,
    363  1.1  joerg 					"could not read endpoint descriptor\n");
    364  1.1  joerg 				return;
    365  1.1  joerg 			}
    366  1.1  joerg 			if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    367  1.1  joerg 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    368  1.1  joerg 				uca.bulkin = ed->bEndpointAddress;
    369  1.1  joerg 			else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    370  1.1  joerg 			    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    371  1.1  joerg 				uca.bulkout = ed->bEndpointAddress;
    372  1.1  joerg 		}
    373  1.1  joerg 		if (uca.bulkin == -1 || uca.bulkout == -1) {
    374  1.1  joerg 			aprint_error_dev(self, "missing endpoint\n");
    375  1.1  joerg 			return;
    376  1.1  joerg 		}
    377  1.1  joerg 
    378  1.1  joerg 		sc->sc_ucom[i] = config_found_sm_loc(self, "ucombus", NULL, &uca,
    379  1.1  joerg 						    ucomprint, ucomsubmatch);
    380  1.1  joerg 	}
    381  1.1  joerg 
    382  1.1  joerg #ifdef U3G_DEBUG
    383  1.1  joerg 	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
    384  1.1  joerg 		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
    385  1.1  joerg 		error = usbd_open_pipe_intr(sc->sc_intr_iface,
    386  1.1  joerg 					    sc->sc_intr_number,
    387  1.1  joerg 					    USBD_SHORT_XFER_OK,
    388  1.1  joerg 					    &sc->sc_intr_pipe,
    389  1.1  joerg 					    sc,
    390  1.1  joerg 					    sc->sc_intr_buf,
    391  1.1  joerg 					    sc->sc_isize,
    392  1.1  joerg 					    u3g_intr,
    393  1.1  joerg 					    100);
    394  1.1  joerg 		if (error) {
    395  1.1  joerg 			aprint_error_dev(self,
    396  1.1  joerg 			    "cannot open interrupt pipe (addr %d)\n",
    397  1.1  joerg 			    sc->sc_intr_number);
    398  1.1  joerg 			return;
    399  1.1  joerg 		}
    400  1.1  joerg 	}
    401  1.1  joerg #endif
    402  1.1  joerg 
    403  1.1  joerg 
    404  1.1  joerg 	if (!pmf_device_register(self, NULL, NULL))
    405  1.1  joerg 		aprint_error_dev(self, "couldn't establish power handler\n");
    406  1.1  joerg }
    407  1.1  joerg 
    408  1.1  joerg static int
    409  1.1  joerg u3g_detach(device_t self, int flags)
    410  1.1  joerg {
    411  1.1  joerg 	struct u3g_softc *sc = device_private(self);
    412  1.1  joerg 	int rv = 0;
    413  1.1  joerg 	int i;
    414  1.1  joerg 
    415  1.2  joerg 	if (sc->sc_pseudodev)
    416  1.2  joerg 		return 0;
    417  1.2  joerg 
    418  1.1  joerg 	pmf_device_deregister(self);
    419  1.1  joerg 
    420  1.1  joerg 	for (i = 0; i < sc->numports; i++) {
    421  1.1  joerg 		if(sc->sc_ucom[i]) {
    422  1.1  joerg 			rv = config_detach(sc->sc_ucom[i], flags);
    423  1.1  joerg 			if(rv != 0) {
    424  1.1  joerg 				aprint_verbose_dev(self, "Can't deallocat port %d", i);
    425  1.1  joerg 				return rv;
    426  1.1  joerg 			}
    427  1.1  joerg 		}
    428  1.1  joerg 	}
    429  1.1  joerg 
    430  1.1  joerg #ifdef U3G_DEBUG
    431  1.1  joerg 	if (sc->sc_intr_pipe != NULL) {
    432  1.1  joerg 		int err = usbd_abort_pipe(sc->sc_intr_pipe);
    433  1.1  joerg 		if (err)
    434  1.1  joerg 			aprint_error_dev(self,
    435  1.1  joerg 				"abort interrupt pipe failed: %s\n",
    436  1.1  joerg 				usbd_errstr(err));
    437  1.1  joerg 		err = usbd_close_pipe(sc->sc_intr_pipe);
    438  1.1  joerg 		if (err)
    439  1.1  joerg 			aprint_error_dev(self,
    440  1.1  joerg 			    "close interrupt pipe failed: %s\n",
    441  1.1  joerg 			    usbd_errstr(err));
    442  1.1  joerg 		free(sc->sc_intr_buf, M_USBDEV);
    443  1.1  joerg 		sc->sc_intr_pipe = NULL;
    444  1.1  joerg 	}
    445  1.1  joerg #endif
    446  1.1  joerg 
    447  1.1  joerg 	return 0;
    448  1.1  joerg }
    449  1.1  joerg 
    450  1.1  joerg static void
    451  1.1  joerg u3g_childdet(device_t self, device_t child)
    452  1.1  joerg {
    453  1.1  joerg 	struct u3g_softc *sc = device_private(self);
    454  1.1  joerg 	int i;
    455  1.1  joerg 
    456  1.1  joerg 	for (i = 0; i < sc->numports; i++) {
    457  1.1  joerg 		if (sc->sc_ucom[i] == child)
    458  1.1  joerg 			sc->sc_ucom[i] = NULL;
    459  1.1  joerg 	}
    460  1.1  joerg }
    461  1.1  joerg 
    462  1.1  joerg static int
    463  1.1  joerg u3g_activate(device_t self, enum devact act)
    464  1.1  joerg {
    465  1.1  joerg 	struct u3g_softc *sc = device_private(self);
    466  1.1  joerg 	int i, rv = 0;
    467  1.1  joerg 
    468  1.1  joerg 	switch (act) {
    469  1.1  joerg 	case DVACT_ACTIVATE:
    470  1.1  joerg 		return (EOPNOTSUPP);
    471  1.1  joerg 		break;
    472  1.1  joerg 
    473  1.1  joerg 	case DVACT_DEACTIVATE:
    474  1.1  joerg 		for (i = 0; i < sc->numports; i++) {
    475  1.1  joerg 			if (sc->sc_ucom[i] && config_deactivate(sc->sc_ucom[i]))
    476  1.1  joerg 				rv = -1;
    477  1.1  joerg 		}
    478  1.1  joerg 		break;
    479  1.1  joerg 	}
    480  1.1  joerg 	return (rv);
    481  1.1  joerg }
    482  1.1  joerg 
    483  1.1  joerg CFATTACH_DECL2_NEW(u3g, sizeof(struct u3g_softc), u3g_match,
    484  1.1  joerg     u3g_attach, u3g_detach, u3g_activate, NULL, u3g_childdet);
    485