Home | History | Annotate | Line # | Download | only in usb
ugensa.c revision 1.15.6.3
      1  1.15.6.1       mjf /*	$NetBSD: ugensa.c,v 1.15.6.3 2008/09/28 10:40:33 mjf Exp $	*/
      2       1.1     elric 
      3       1.1     elric /*
      4       1.1     elric  * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
      5       1.1     elric  * All rights reserved.
      6       1.1     elric  *
      7       1.1     elric  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1     elric  * by Roland C. Dowdeswell <elric (at) netbsd.org>.
      9       1.1     elric  *
     10       1.1     elric  * Redistribution and use in source and binary forms, with or without
     11       1.1     elric  * modification, are permitted provided that the following conditions
     12       1.1     elric  * are met:
     13       1.1     elric  * 1. Redistributions of source code must retain the above copyright
     14       1.1     elric  *    notice, this list of conditions and the following disclaimer.
     15       1.1     elric  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1     elric  *    notice, this list of conditions and the following disclaimer in the
     17       1.1     elric  *    documentation and/or other materials provided with the distribution.
     18       1.1     elric  *
     19       1.1     elric  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1     elric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1     elric  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1     elric  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1     elric  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1     elric  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1     elric  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1     elric  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1     elric  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1     elric  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1     elric  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1     elric  */
     31       1.1     elric 
     32      1.13     lukem #include <sys/cdefs.h>
     33  1.15.6.1       mjf __KERNEL_RCSID(0, "$NetBSD: ugensa.c,v 1.15.6.3 2008/09/28 10:40:33 mjf Exp $");
     34      1.13     lukem 
     35       1.1     elric #include <sys/param.h>
     36       1.1     elric #include <sys/systm.h>
     37       1.1     elric #include <sys/kernel.h>
     38       1.1     elric #include <sys/device.h>
     39       1.1     elric #include <sys/conf.h>
     40       1.1     elric #include <sys/tty.h>
     41       1.1     elric 
     42       1.1     elric #include <dev/usb/usb.h>
     43       1.1     elric 
     44       1.1     elric #include <dev/usb/usbdi.h>
     45       1.1     elric #include <dev/usb/usbdi_util.h>
     46       1.1     elric #include <dev/usb/usbdevs.h>
     47       1.1     elric 
     48       1.1     elric #include <dev/usb/ucomvar.h>
     49       1.1     elric 
     50       1.1     elric /* XXXrcd: heh */
     51       1.1     elric #define UGENSA_DEBUG 1
     52       1.1     elric 
     53       1.1     elric #ifdef UGENSA_DEBUG
     54       1.1     elric #define DPRINTF(x)	if (ugensadebug) printf x
     55       1.1     elric #define DPRINTFN(n,x)	if (ugensadebug>(n)) printf x
     56       1.1     elric int ugensadebug = 0;
     57       1.1     elric #else
     58       1.1     elric #define DPRINTF(x)
     59       1.1     elric #define DPRINTFN(n,x)
     60       1.1     elric #endif
     61       1.1     elric 
     62       1.1     elric struct ugensa_softc {
     63       1.1     elric 	USBBASEDEVICE		sc_dev;		/* base device */
     64       1.1     elric 	usbd_device_handle	sc_udev;	/* device */
     65       1.1     elric 	usbd_interface_handle	sc_iface;	/* interface */
     66       1.1     elric 
     67      1.15    dyoung 	device_t		sc_subdev;
     68       1.1     elric 	int			sc_numcon;
     69       1.1     elric 
     70       1.1     elric 	u_char			sc_dying;
     71       1.1     elric };
     72       1.1     elric 
     73       1.1     elric struct ucom_methods ugensa_methods = {
     74       1.1     elric 	NULL,
     75       1.1     elric 	NULL,
     76       1.1     elric 	NULL,
     77       1.1     elric 	NULL,
     78       1.1     elric 	NULL,
     79       1.1     elric 	NULL,
     80       1.1     elric 	NULL,
     81       1.1     elric 	NULL,
     82       1.1     elric };
     83       1.1     elric 
     84       1.1     elric #define UGENSA_CONFIG_INDEX	0
     85       1.1     elric #define UGENSA_IFACE_INDEX	0
     86       1.1     elric #define UGENSA_BUFSIZE		1024
     87       1.1     elric 
     88  1.15.6.1       mjf struct ugensa_type {
     89  1.15.6.1       mjf 	struct usb_devno	ugensa_dev;
     90  1.15.6.1       mjf 	u_int16_t		ugensa_flags;
     91  1.15.6.1       mjf #define UNTESTED		0x0001
     92       1.1     elric };
     93  1.15.6.1       mjf 
     94  1.15.6.1       mjf static const struct ugensa_type ugensa_devs[] = {
     95  1.15.6.1       mjf 	{{ USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220 }, 0 },
     96  1.15.6.1       mjf 	{{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_FLEXPACKGPS }, 0 },
     97  1.15.6.1       mjf 	{{ USB_VENDOR_QUALCOMM_K, USB_PRODUCT_QUALCOMM_K_CDMA_MSM_K }, 0 },
     98  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 }, 0 },
     99  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 }, 0 },
    100  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725}, 0 },
    101  1.15.6.1       mjf 	{{ USB_VENDOR_DELL, USB_PRODUCT_DELL_HSDPA }, 0 },
    102  1.15.6.1       mjf 
    103  1.15.6.1       mjf 	/*
    104  1.15.6.1       mjf 	 * The following devices are untested, but they are purported to
    105  1.15.6.1       mjf 	 * to work in similar device drivers on other OSes:
    106  1.15.6.1       mjf 	 */
    107  1.15.6.1       mjf 
    108  1.15.6.1       mjf         {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A }, UNTESTED },
    109  1.15.6.1       mjf         {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 }, UNTESTED },
    110  1.15.6.1       mjf         {{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_EXPRESSCARD }, UNTESTED },
    111  1.15.6.1       mjf 	{{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 }, UNTESTED },
    112  1.15.6.1       mjf 	{{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 }, UNTESTED },
    113  1.15.6.1       mjf 	{{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 }, UNTESTED },
    114  1.15.6.3       mjf 	{{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U727 }, UNTESTED },
    115  1.15.6.1       mjf 	{{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 }, UNTESTED },
    116  1.15.6.1       mjf 	{{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 }, UNTESTED },
    117  1.15.6.1       mjf 	{{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_HSDPA }, UNTESTED },
    118  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 }, UNTESTED },
    119  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 }, UNTESTED },
    120  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 }, UNTESTED },
    121  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 }, UNTESTED },
    122  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 }, UNTESTED },
    123  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 }, UNTESTED },
    124  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 }, UNTESTED },
    125  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 }, UNTESTED },
    126  1.15.6.1       mjf 	{{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775 }, UNTESTED }
    127  1.15.6.1       mjf };
    128  1.15.6.1       mjf #define ugensa_lookup(v, p) \
    129  1.15.6.1       mjf 	((const struct ugensa_type *)usb_lookup(ugensa_devs, v, p))
    130       1.1     elric 
    131  1.15.6.2       mjf int ugensa_match(device_t, cfdata_t, void *);
    132      1.15    dyoung void ugensa_attach(device_t, device_t, void *);
    133      1.15    dyoung void ugensa_childdet(device_t, device_t);
    134      1.15    dyoung int ugensa_detach(device_t, int);
    135      1.15    dyoung int ugensa_activate(device_t, enum devact);
    136      1.15    dyoung extern struct cfdriver ugensa_cd;
    137  1.15.6.2       mjf CFATTACH_DECL2_NEW(ugensa, sizeof(struct ugensa_softc), ugensa_match,
    138      1.15    dyoung     ugensa_attach, ugensa_detach, ugensa_activate, NULL, ugensa_childdet);
    139       1.1     elric 
    140       1.1     elric USB_MATCH(ugensa)
    141       1.1     elric {
    142       1.1     elric 	USB_MATCH_START(ugensa, uaa);
    143       1.1     elric 
    144       1.1     elric 	DPRINTFN(20,("ugensa: vendor=0x%x, product=0x%x\n",
    145       1.1     elric 		     uaa->vendor, uaa->product));
    146       1.1     elric 
    147       1.1     elric 	return (ugensa_lookup(uaa->vendor, uaa->product) != NULL ?
    148       1.1     elric 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
    149       1.1     elric }
    150       1.1     elric 
    151       1.1     elric USB_ATTACH(ugensa)
    152       1.1     elric {
    153       1.1     elric 	USB_ATTACH_START(ugensa, sc, uaa);
    154       1.1     elric 	usbd_device_handle dev = uaa->device;
    155       1.1     elric 	usbd_interface_handle iface;
    156       1.1     elric 	usb_interface_descriptor_t *id;
    157       1.1     elric 	usb_endpoint_descriptor_t *ed;
    158       1.3  augustss 	char *devinfop;
    159  1.15.6.2       mjf 	const char *devname = device_xname(self);
    160       1.1     elric 	usbd_status err;
    161       1.1     elric 	struct ucom_attach_args uca;
    162       1.1     elric 	int i;
    163       1.1     elric 
    164       1.1     elric 	DPRINTFN(10,("\nugensa_attach: sc=%p\n", sc));
    165       1.1     elric 
    166  1.15.6.2       mjf 	sc->sc_dev = self;
    167  1.15.6.2       mjf 
    168       1.1     elric 	/* Move the device into the configured state. */
    169       1.1     elric 	err = usbd_set_config_index(dev, UGENSA_CONFIG_INDEX, 1);
    170       1.1     elric 	if (err) {
    171  1.15.6.2       mjf 		aprint_error("\n%s: failed to set configuration, err=%s\n",
    172       1.1     elric 		       devname, usbd_errstr(err));
    173       1.1     elric 		goto bad;
    174       1.1     elric 	}
    175       1.1     elric 
    176       1.1     elric 	err = usbd_device2interface_handle(dev, UGENSA_IFACE_INDEX, &iface);
    177       1.1     elric 	if (err) {
    178  1.15.6.2       mjf 		aprint_error("\n%s: failed to get interface, err=%s\n",
    179       1.1     elric 		       devname, usbd_errstr(err));
    180       1.1     elric 		goto bad;
    181       1.1     elric 	}
    182       1.1     elric 
    183       1.3  augustss 	devinfop = usbd_devinfo_alloc(dev, 0);
    184       1.1     elric 	USB_ATTACH_SETUP;
    185  1.15.6.2       mjf 	aprint_normal_dev(self, "%s\n", devinfop);
    186       1.3  augustss 	usbd_devinfo_free(devinfop);
    187       1.1     elric 
    188  1.15.6.1       mjf 	if (ugensa_lookup(uaa->vendor, uaa->product)->ugensa_flags & UNTESTED)
    189  1.15.6.2       mjf 		aprint_normal_dev(self, "WARNING: This device is marked as "
    190  1.15.6.2       mjf 		    "untested. Please submit a report via send-pr(1).\n");
    191  1.15.6.1       mjf 
    192       1.1     elric 	id = usbd_get_interface_descriptor(iface);
    193       1.1     elric 
    194       1.1     elric 	sc->sc_udev = dev;
    195       1.1     elric 	sc->sc_iface = iface;
    196       1.1     elric 
    197       1.2     elric 	uca.info = "Generic Serial Device";
    198       1.1     elric 	uca.ibufsize = UGENSA_BUFSIZE;
    199       1.1     elric 	uca.obufsize = UGENSA_BUFSIZE;
    200       1.1     elric 	uca.ibufsizepad = UGENSA_BUFSIZE;
    201       1.7    martin 	uca.portno = UCOM_UNK_PORTNO;
    202       1.1     elric 	uca.opkthdrlen = 0;
    203       1.1     elric 	uca.device = dev;
    204       1.1     elric 	uca.iface = iface;
    205       1.1     elric 	uca.methods = &ugensa_methods;
    206       1.1     elric 	uca.arg = sc;
    207       1.1     elric 
    208       1.1     elric 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
    209       1.1     elric 			   USBDEV(sc->sc_dev));
    210       1.1     elric 
    211       1.1     elric 	uca.bulkin = uca.bulkout = -1;
    212       1.1     elric 	for (i = 0; i < id->bNumEndpoints; i++) {
    213       1.1     elric 		int addr, dir, attr;
    214       1.1     elric 
    215       1.1     elric 		ed = usbd_interface2endpoint_descriptor(iface, i);
    216       1.1     elric 		if (ed == NULL) {
    217  1.15.6.2       mjf 			aprint_error_dev(self,
    218  1.15.6.2       mjf 			    "could not read endpoint descriptor: %s\n",
    219  1.15.6.2       mjf 			    usbd_errstr(err));
    220       1.1     elric 			goto bad;
    221       1.1     elric 		}
    222       1.1     elric 
    223       1.1     elric 		addr = ed->bEndpointAddress;
    224       1.1     elric 		dir = UE_GET_DIR(ed->bEndpointAddress);
    225       1.1     elric 		attr = ed->bmAttributes & UE_XFERTYPE;
    226  1.15.6.1       mjf 		if (attr == UE_BULK) {
    227  1.15.6.1       mjf 			if (uca.bulkin == -1 && dir == UE_DIR_IN) {
    228  1.15.6.1       mjf 				DPRINTF(("%s: Bulk in %d\n", devname, i));
    229  1.15.6.1       mjf 				uca.bulkin = addr;
    230  1.15.6.1       mjf 				continue;
    231  1.15.6.1       mjf 			}
    232  1.15.6.1       mjf 			if (uca.bulkout == -1 && dir == UE_DIR_OUT) {
    233  1.15.6.1       mjf 				DPRINTF(("%s: Bulk out %d\n", devname, i));
    234  1.15.6.1       mjf 				uca.bulkout = addr;
    235  1.15.6.1       mjf 				continue;
    236  1.15.6.1       mjf 			}
    237  1.15.6.1       mjf 		}
    238  1.15.6.2       mjf 		aprint_error_dev(self, "unexpected endpoint\n");
    239       1.1     elric 	}
    240       1.1     elric 	if (uca.bulkin == -1) {
    241  1.15.6.2       mjf 		aprint_error_dev(self, "Could not find data bulk in\n");
    242       1.1     elric 		goto bad;
    243       1.1     elric 	}
    244       1.1     elric 	if (uca.bulkout == -1) {
    245  1.15.6.2       mjf 		aprint_error_dev(self, "Could not find data bulk out\n");
    246       1.1     elric 		goto bad;
    247       1.1     elric 	}
    248       1.1     elric 
    249       1.1     elric 	DPRINTF(("ugensa: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
    250       1.1     elric 	sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca,
    251       1.1     elric 					    ucomprint, ucomsubmatch);
    252       1.1     elric 
    253      1.14       smb 	if (!pmf_device_register(self, NULL, NULL))
    254      1.14       smb 		aprint_error_dev(self, "couldn't establish power handler\n");
    255       1.1     elric 	USB_ATTACH_SUCCESS_RETURN;
    256       1.1     elric 
    257       1.1     elric bad:
    258       1.1     elric 	DPRINTF(("ugensa_attach: ATTACH ERROR\n"));
    259       1.1     elric 	sc->sc_dying = 1;
    260       1.1     elric 	USB_ATTACH_ERROR_RETURN;
    261       1.1     elric }
    262       1.1     elric 
    263      1.15    dyoung void
    264      1.15    dyoung ugensa_childdet(device_t self, device_t child)
    265      1.15    dyoung {
    266      1.15    dyoung 	struct ugensa_softc *sc = device_private(self);
    267      1.15    dyoung 
    268      1.15    dyoung 	KASSERT(sc->sc_subdev == child);
    269      1.15    dyoung 	sc->sc_subdev = NULL;
    270      1.15    dyoung }
    271      1.15    dyoung 
    272       1.1     elric int
    273      1.15    dyoung ugensa_activate(device_t self, enum devact act)
    274       1.1     elric {
    275      1.15    dyoung 	struct ugensa_softc *sc = device_private(self);
    276       1.1     elric 	int rv = 0;
    277       1.1     elric 
    278  1.15.6.1       mjf 	DPRINTF(("ugensa_activate: sc=%p\n", sc));
    279  1.15.6.1       mjf 
    280       1.1     elric 	switch (act) {
    281       1.1     elric 	case DVACT_ACTIVATE:
    282       1.1     elric 		return (EOPNOTSUPP);
    283       1.1     elric 		break;
    284       1.1     elric 
    285       1.1     elric 	case DVACT_DEACTIVATE:
    286       1.1     elric 		sc->sc_dying = 1;
    287       1.1     elric 		if (sc->sc_subdev)
    288       1.1     elric 			rv = config_deactivate(sc->sc_subdev);
    289       1.1     elric 		break;
    290       1.1     elric 	}
    291       1.1     elric 	return (rv);
    292       1.1     elric }
    293       1.1     elric 
    294       1.1     elric USB_DETACH(ugensa)
    295       1.1     elric {
    296       1.1     elric 	USB_DETACH_START(ugensa, sc);
    297       1.1     elric 	int rv = 0;
    298       1.1     elric 
    299       1.1     elric 	DPRINTF(("ugensa_detach: sc=%p flags=%d\n", sc, flags));
    300       1.1     elric 
    301       1.1     elric 	sc->sc_dying = 1;
    302      1.14       smb 	pmf_device_deregister(self);
    303       1.1     elric 
    304       1.1     elric 	if (sc->sc_subdev != NULL)
    305       1.1     elric 		rv = config_detach(sc->sc_subdev, flags);
    306       1.1     elric 
    307       1.1     elric 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
    308       1.1     elric 			   USBDEV(sc->sc_dev));
    309       1.1     elric 
    310       1.1     elric 	return (rv);
    311       1.1     elric }
    312