Home | History | Annotate | Line # | Download | only in usb
ugen.c revision 1.7
      1 /*	$NetBSD: ugen.c,v 1.7 1998/12/29 15:33:10 augustss Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Lennart Augustsson (augustss (at) carlstedt.se) at
      9  * Carlstedt Research & Technology.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *        This product includes software developed by the NetBSD
     22  *        Foundation, Inc. and its contributors.
     23  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  *    contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/kernel.h>
     44 #include <sys/malloc.h>
     45 #include <sys/device.h>
     46 #include <sys/ioctl.h>
     47 #include <sys/tty.h>
     48 #include <sys/file.h>
     49 #include <sys/select.h>
     50 #include <sys/proc.h>
     51 #include <sys/vnode.h>
     52 #include <sys/device.h>
     53 #include <sys/poll.h>
     54 
     55 #include <dev/usb/usb.h>
     56 #include <dev/usb/usbdi.h>
     57 #include <dev/usb/usbdi_util.h>
     58 
     59 #ifdef USB_DEBUG
     60 #define DPRINTF(x)	if (ugendebug) printf x
     61 #define DPRINTFN(n,x)	if (ugendebug>(n)) printf x
     62 int	ugendebug = 0;
     63 #else
     64 #define DPRINTF(x)
     65 #define DPRINTFN(n,x)
     66 #endif
     67 
     68 struct ugen_endpoint {
     69 	struct ugen_softc *sc;
     70 	usb_endpoint_descriptor_t *edesc;
     71 	usbd_interface_handle iface;
     72 	int state;
     73 #define UGEN_OPEN	0x01	/* device is open */
     74 #define	UGEN_ASLP	0x02	/* waiting for data */
     75 	usbd_pipe_handle pipeh;
     76 	struct clist q;
     77 	struct selinfo rsel;
     78 	void *ibuf;
     79 };
     80 
     81 #define	UGEN_CHUNK	128	/* chunk size for read */
     82 #define	UGEN_IBSIZE	1020	/* buffer size */
     83 #define	UGEN_BBSIZE	1024
     84 
     85 struct ugen_softc {
     86 	struct device sc_dev;		/* base device */
     87 	struct usbd_device *sc_udev;
     88 
     89 	struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
     90 #define OUT 0			/* index order is important, from UE_OUT */
     91 #define IN  1			/* from UE_IN */
     92 
     93 	int sc_disconnected;		/* device is gone */
     94 };
     95 
     96 int ugen_match __P((struct device *, struct cfdata *, void *));
     97 void ugen_attach __P((struct device *, struct device *, void *));
     98 
     99 int ugenopen __P((dev_t, int, int, struct proc *));
    100 int ugenclose __P((dev_t, int, int, struct proc *p));
    101 int ugenread __P((dev_t, struct uio *uio, int));
    102 int ugenwrite __P((dev_t, struct uio *uio, int));
    103 int ugenioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
    104 int ugenpoll __P((dev_t, int, struct proc *));
    105 void ugenintr __P((usbd_request_handle reqh, usbd_private_handle addr,
    106 		   usbd_status status));
    107 void ugen_disco __P((void *));
    108 
    109 int ugen_set_config __P((struct ugen_softc *sc, int configno));
    110 usb_config_descriptor_t *ugen_get_cdesc __P((struct ugen_softc *sc, int index,
    111 					     int *lenp));
    112 usbd_status ugen_set_interface __P((struct ugen_softc *, int, int));
    113 int ugen_get_alt_index __P((struct ugen_softc *sc, int ifaceidx));
    114 
    115 #define UGENUNIT(n) (((n) >> 4) & 0xf)
    116 #define UGENENDPOINT(n) ((n) & 0xf)
    117 
    118 USB_DECLARE_DRIVER(ugen);
    119 
    120 USB_MATCH(ugen)
    121 {
    122 	USB_MATCH_START(ugen, uaa);
    123 
    124 	if (uaa->usegeneric)
    125 		return (UMATCH_GENERIC);
    126 	else
    127 		return (UMATCH_NONE);
    128 }
    129 
    130 USB_ATTACH(ugen)
    131 {
    132 	USB_ATTACH_START(ugen, sc, uaa);
    133 	char devinfo[1024];
    134 	usbd_status r;
    135 	int conf;
    136 
    137 	usbd_devinfo(uaa->device, 0, devinfo);
    138 	USB_ATTACH_SETUP;
    139 	printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
    140 
    141 	sc->sc_udev = uaa->device;
    142 	conf = 1;		/* XXX should not hard code 1 */
    143 	r = ugen_set_config(sc, conf);
    144 	if (r != USBD_NORMAL_COMPLETION) {
    145 		printf("%s: setting configuration %d failed\n",
    146 		       USBDEVNAME(sc->sc_dev), conf);
    147 		sc->sc_disconnected = 1;
    148 		USB_ATTACH_ERROR_RETURN;
    149 	}
    150 	USB_ATTACH_SUCCESS_RETURN;
    151 }
    152 
    153 int
    154 ugen_set_config(sc, configno)
    155 	struct ugen_softc *sc;
    156 	int configno;
    157 {
    158 	usbd_device_handle dev = sc->sc_udev;
    159 	usbd_interface_handle iface;
    160 	usb_endpoint_descriptor_t *ed;
    161 	struct ugen_endpoint *sce;
    162 	u_int8_t niface, nendpt;
    163 	int ifaceno, endptno, endpt;
    164 	usbd_status r;
    165 
    166 	DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
    167 		    USBDEVNAME(sc->sc_dev), configno, sc));
    168 	if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
    169 		/* Avoid setting the current value. */
    170 		r = usbd_set_config_no(dev, configno, 0);
    171 		if (r != USBD_NORMAL_COMPLETION)
    172 			return (r);
    173 	}
    174 
    175 	r = usbd_interface_count(dev, &niface);
    176 	if (r != USBD_NORMAL_COMPLETION)
    177 		return (r);
    178 	memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
    179 	for (ifaceno = 0; ifaceno < niface; ifaceno++) {
    180 		DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
    181 		r = usbd_device2interface_handle(dev, ifaceno, &iface);
    182 		if (r != USBD_NORMAL_COMPLETION)
    183 			return (r);
    184 		r = usbd_endpoint_count(iface, &nendpt);
    185 		if (r != USBD_NORMAL_COMPLETION)
    186 			return (r);
    187 		for (endptno = 0; endptno < nendpt; endptno++) {
    188 			ed = usbd_interface2endpoint_descriptor(iface,endptno);
    189 			endpt = ed->bEndpointAddress;
    190 			sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)]
    191 				               [UE_GET_IN(endpt)];
    192 			DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
    193 				    "(%d,%d), sce=%p\n",
    194 				    endptno, endpt, UE_GET_ADDR(endpt),
    195 				    UE_GET_IN(endpt), sce));
    196 			sce->sc = sc;
    197 			sce->edesc = ed;
    198 			sce->iface = iface;
    199 		}
    200 	}
    201 	return (USBD_NORMAL_COMPLETION);
    202 }
    203 
    204 void
    205 ugen_disco(p)
    206 	void *p;
    207 {
    208 	struct ugen_softc *sc = p;
    209 	sc->sc_disconnected = 1;
    210 }
    211 
    212 int
    213 ugenopen(dev, flag, mode, p)
    214 	dev_t dev;
    215 	int flag;
    216 	int mode;
    217 	struct proc *p;
    218 {
    219 	int unit = UGENUNIT(dev);
    220 	int endpt = UGENENDPOINT(dev);
    221 	usb_endpoint_descriptor_t *edesc;
    222 	struct ugen_softc *sc;
    223 	struct ugen_endpoint *sce;
    224 	int dir, isize;
    225 	usbd_status r;
    226 
    227 	DPRINTFN(5, ("ugenopen: flag=%d, unit=%d endpt=%d\n",
    228 		     flag, unit, endpt));
    229 	if (unit >= ugen_cd.cd_ndevs)
    230 		return (ENXIO);
    231 	sc = ugen_cd.cd_devs[unit];
    232 	if (!sc)
    233 		return (ENXIO);
    234 
    235 	if (sc->sc_disconnected)
    236 		return (EIO);
    237 
    238 	if (endpt == USB_CONTROL_ENDPOINT) {
    239 		/*if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
    240 		  return (EACCES);*/
    241 		sce = &sc->sc_endpoints[USB_CONTROL_ENDPOINT][OUT];
    242 		if (sce->state & UGEN_OPEN)
    243 			return (EBUSY);
    244 	} else {
    245 		switch (flag & (FWRITE|FREAD)) {
    246 		case FWRITE:
    247 			dir = OUT;
    248 			break;
    249 		case FREAD:
    250 			dir = IN;
    251 			break;
    252 		default:
    253 			return (EACCES);
    254 		}
    255 		sce = &sc->sc_endpoints[endpt][dir];
    256 		DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
    257 			     sc, endpt, dir, sce));
    258 		if (sce->state & UGEN_OPEN)
    259 			return (EBUSY);
    260 		edesc = sce->edesc;
    261 		if (!edesc)
    262 			return (ENXIO);
    263 		switch (edesc->bmAttributes & UE_XFERTYPE) {
    264 		case UE_INTERRUPT:
    265 			isize = UGETW(edesc->wMaxPacketSize);
    266 			if (isize == 0)	/* shouldn't happen */
    267 				return (EINVAL);
    268 			sce->ibuf = malloc(isize, M_USB, M_NOWAIT);
    269 			DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
    270 				     endpt, isize));
    271 			if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
    272 				return (ENOMEM);
    273 			r = usbd_open_pipe_intr(sce->iface,
    274 				edesc->bEndpointAddress,
    275 				USBD_SHORT_XFER_OK, &sce->pipeh, sce,
    276 				sce->ibuf, isize, ugenintr);
    277 			if (r != USBD_NORMAL_COMPLETION) {
    278 				free(sce->ibuf, M_USB);
    279 				clfree(&sce->q);
    280 				return (EIO);
    281 			}
    282 			usbd_set_disco(sce->pipeh, ugen_disco, sc);
    283 			DPRINTFN(5, ("ugenopen: interrupt open done\n"));
    284 			break;
    285 		case UE_BULK:
    286 			r = usbd_open_pipe(sce->iface,
    287 					   edesc->bEndpointAddress, 0,
    288 					   &sce->pipeh);
    289 			if (r != USBD_NORMAL_COMPLETION)
    290 				return (EIO);
    291 			break;
    292 		case UE_CONTROL:
    293 		case UE_ISOCHRONOUS:
    294 			return (EINVAL);
    295 		}
    296 	}
    297 	sce->state |= UGEN_OPEN;
    298 	return (0);
    299 }
    300 
    301 int
    302 ugenclose(dev, flag, mode, p)
    303 	dev_t dev;
    304 	int flag;
    305 	int mode;
    306 	struct proc *p;
    307 {
    308 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    309 	int endpt = UGENENDPOINT(dev);
    310 	struct ugen_endpoint *sce;
    311 	int dir;
    312 
    313 	DPRINTFN(5, ("ugenclose\n"));
    314 	if (sc->sc_disconnected)
    315 		return (EIO);
    316 
    317 	if (endpt == USB_CONTROL_ENDPOINT) {
    318 		sc->sc_endpoints[endpt][OUT].state &= ~UGEN_OPEN;
    319 		return (0);
    320 	}
    321 	dir = flag & FWRITE ? OUT : IN;
    322 	sce = &sc->sc_endpoints[endpt][dir];
    323 	sce->state &= ~UGEN_OPEN;
    324 
    325 	usbd_abort_pipe(sce->pipeh);
    326 	usbd_close_pipe(sce->pipeh);
    327 
    328 	if (sce->ibuf) {
    329 		free(sce->ibuf, M_USB);
    330 		sce->ibuf = 0;
    331 	}
    332 
    333 	return (0);
    334 }
    335 
    336 int
    337 ugenread(dev, uio, flag)
    338 	dev_t dev;
    339 	struct uio *uio;
    340 	int flag;
    341 {
    342 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    343 	int endpt = UGENENDPOINT(dev);
    344 	struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
    345 	size_t n;
    346 	char buf[UGEN_BBSIZE];
    347 	usbd_request_handle reqh;
    348 	usbd_status r;
    349 	int s;
    350 	int error = 0;
    351 	u_char buffer[UGEN_CHUNK];
    352 
    353 	DPRINTFN(5, ("ugenread: %d:%d\n", UGENUNIT(dev), UGENENDPOINT(dev)));
    354 	if (sc->sc_disconnected)
    355 		return (EIO);
    356 
    357 #ifdef DIAGNOSTIC
    358 	if (!sce->edesc) {
    359 		printf("ugenread: no edesc\n");
    360 		return (EIO);
    361 	}
    362 #endif
    363 
    364 	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
    365 	case UE_INTERRUPT:
    366 		/* Block until activity occured. */
    367 		s = splusb();
    368 		while (sce->q.c_cc == 0) {
    369 			if (flag & IO_NDELAY) {
    370 				splx(s);
    371 				return EWOULDBLOCK;
    372 			}
    373 			sce->state |= UGEN_ASLP;
    374 			DPRINTFN(5, ("ugenread: sleep on %p\n", sc));
    375 			error = tsleep((caddr_t)sce, PZERO | PCATCH,
    376 				       "ugenrea", 0);
    377 			DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
    378 			if (error) {
    379 				sce->state &= ~UGEN_ASLP;
    380 				splx(s);
    381 				return (error);
    382 			}
    383 		}
    384 		splx(s);
    385 
    386 		/* Transfer as many chunks as possible. */
    387 		while (sce->q.c_cc > 0 && uio->uio_resid > 0) {
    388 			n = min(sce->q.c_cc, uio->uio_resid);
    389 			if (n > sizeof(buffer))
    390 				n = sizeof(buffer);
    391 
    392 			/* Remove a small chunk from the input queue. */
    393 			q_to_b(&sce->q, buffer, n);
    394 			DPRINTFN(5, ("ugenread: got %d chars\n", n));
    395 
    396 			/* Copy the data to the user process. */
    397 			error = uiomove(buffer, n, uio);
    398 			if (error)
    399 				break;
    400 		}
    401 		break;
    402 	case UE_BULK:
    403 		reqh = usbd_alloc_request();
    404 		if (reqh == 0)
    405 			return (ENOMEM);
    406 		while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
    407 			/* XXX use callback to enable interrupt? */
    408 			r = usbd_setup_request(reqh, sce->pipeh, 0, buf, n,
    409 					       0, USBD_NO_TIMEOUT, 0);
    410 			if (r != USBD_NORMAL_COMPLETION) {
    411 				error = EIO;
    412 				break;
    413 			}
    414 			DPRINTFN(1, ("ugenread: transfer %d bytes\n", n));
    415 			r = usbd_sync_transfer(reqh);
    416 			if (r != USBD_NORMAL_COMPLETION) {
    417 				DPRINTF(("ugenread: error=%d\n", r));
    418 				usbd_clear_endpoint_stall(sce->pipeh);
    419 				error = EIO;
    420 				break;
    421 			}
    422 			error = uiomove(buf, n, uio);
    423 			if (error)
    424 				break;
    425 		}
    426 		usbd_free_request(reqh);
    427 		break;
    428 	default:
    429 		return (ENXIO);
    430 	}
    431 
    432 	return (error);
    433 }
    434 
    435 int
    436 ugenwrite(dev, uio, flag)
    437 	dev_t dev;
    438 	struct uio *uio;
    439 	int flag;
    440 {
    441 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    442 	int endpt = UGENENDPOINT(dev);
    443 	struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
    444 	size_t n;
    445 	int error = 0;
    446 	char buf[UGEN_BBSIZE];
    447 	usbd_request_handle reqh;
    448 	usbd_status r;
    449 
    450 	if (sc->sc_disconnected)
    451 		return (EIO);
    452 
    453 #ifdef DIAGNOSTIC
    454 	if (!sce->edesc) {
    455 		printf("ugenwrite: no edesc\n");
    456 		return (EIO);
    457 	}
    458 #endif
    459 
    460 	DPRINTF(("ugenwrite\n"));
    461 	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
    462 	case UE_BULK:
    463 		reqh = usbd_alloc_request();
    464 		if (reqh == 0)
    465 			return (EIO);
    466 		while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
    467 			error = uiomove(buf, n, uio);
    468 			if (error)
    469 				break;
    470 			/* XXX use callback to enable interrupt? */
    471 			r = usbd_setup_request(reqh, sce->pipeh, 0, buf, n,
    472 					       0, USBD_NO_TIMEOUT, 0);
    473 			if (r != USBD_NORMAL_COMPLETION) {
    474 				error = EIO;
    475 				break;
    476 			}
    477 			DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
    478 			r = usbd_sync_transfer(reqh);
    479 			if (r != USBD_NORMAL_COMPLETION) {
    480 				DPRINTF(("ugenwrite: error=%d\n", r));
    481 				usbd_clear_endpoint_stall(sce->pipeh);
    482 				error = EIO;
    483 				break;
    484 			}
    485 		}
    486 		usbd_free_request(reqh);
    487 		break;
    488 	default:
    489 		return (ENXIO);
    490 	}
    491 	return (error);
    492 }
    493 
    494 
    495 void
    496 ugenintr(reqh, addr, status)
    497 	usbd_request_handle reqh;
    498 	usbd_private_handle addr;
    499 	usbd_status status;
    500 {
    501 	struct ugen_endpoint *sce = addr;
    502 	/*struct ugen_softc *sc = sce->sc;*/
    503 	u_char *ibuf;
    504 	int isize;
    505 
    506 	if (status == USBD_CANCELLED)
    507 		return;
    508 
    509 	if (status != USBD_NORMAL_COMPLETION) {
    510 		DPRINTF(("ugenintr: status=%d\n", status));
    511 		usbd_clear_endpoint_stall_async(sce->pipeh);
    512 		return;
    513 	}
    514 
    515 	ibuf = sce->ibuf;
    516 	isize = UGETW(sce->edesc->wMaxPacketSize);
    517 
    518 	/*DPRINTFN(5, ("ugenintr: addr=%d endpt=%d\n",
    519 		     addr, endpt, isize));
    520 	DPRINTFN(5, ("          data = %02x %02x %02x\n",
    521 	ibuf[0], ibuf[1], ibuf[2]));*/
    522 
    523 	(void)b_to_q(ibuf, isize, &sce->q);
    524 
    525 	if (sce->state & UGEN_ASLP) {
    526 		sce->state &= ~UGEN_ASLP;
    527 		DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
    528 		wakeup((caddr_t)sce);
    529 	}
    530 	selwakeup(&sce->rsel);
    531 }
    532 
    533 usbd_status
    534 ugen_set_interface(sc, ifaceidx, altno)
    535 	struct ugen_softc *sc;
    536 	int ifaceidx, altno;
    537 {
    538 	usbd_interface_handle iface;
    539 	usb_endpoint_descriptor_t *ed;
    540 	usbd_status r;
    541 	struct ugen_endpoint *sce;
    542 	u_int8_t niface, nendpt, endptno, endpt;
    543 
    544 	DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
    545 
    546 	r = usbd_interface_count(sc->sc_udev, &niface);
    547 	if (r != USBD_NORMAL_COMPLETION)
    548 		return (r);
    549 	if (ifaceidx < 0 || ifaceidx >= niface)
    550 		return (USBD_INVAL);
    551 
    552 	r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
    553 	if (r != USBD_NORMAL_COMPLETION)
    554 		return (r);
    555 	r = usbd_endpoint_count(iface, &nendpt);
    556 	if (r != USBD_NORMAL_COMPLETION)
    557 		return (r);
    558 	for (endptno = 0; endptno < nendpt; endptno++) {
    559 		ed = usbd_interface2endpoint_descriptor(iface,endptno);
    560 		endpt = ed->bEndpointAddress;
    561 		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
    562 		sce->sc = 0;
    563 		sce->edesc = 0;
    564 		sce->iface = 0;
    565 	}
    566 
    567 	/* change setting */
    568 	r = usbd_set_interface(iface, altno);
    569 	if (r != USBD_NORMAL_COMPLETION)
    570 		return (r);
    571 
    572 	r = usbd_endpoint_count(iface, &nendpt);
    573 	if (r != USBD_NORMAL_COMPLETION)
    574 		return (r);
    575 	for (endptno = 0; endptno < nendpt; endptno++) {
    576 		ed = usbd_interface2endpoint_descriptor(iface,endptno);
    577 		endpt = ed->bEndpointAddress;
    578 		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
    579 		sce->sc = sc;
    580 		sce->edesc = ed;
    581 		sce->iface = iface;
    582 	}
    583 	return (0);
    584 }
    585 
    586 /* Retrieve a complete descriptor for a certain device and index. */
    587 usb_config_descriptor_t *
    588 ugen_get_cdesc(sc, index, lenp)
    589 	struct ugen_softc *sc;
    590 	int index;
    591 	int *lenp;
    592 {
    593 	usb_config_descriptor_t *cdesc, *tdesc, cdescr;
    594 	int len;
    595 	usbd_status r;
    596 
    597 	if (index == USB_CURRENT_CONFIG_INDEX) {
    598 		tdesc = usbd_get_config_descriptor(sc->sc_udev);
    599 		len = UGETW(tdesc->wTotalLength);
    600 		if (lenp)
    601 			*lenp = len;
    602 		cdesc = malloc(len, M_TEMP, M_WAITOK);
    603 		memcpy(cdesc, tdesc, len);
    604 		DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
    605 	} else {
    606 		r = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
    607 		if (r != USBD_NORMAL_COMPLETION)
    608 			return (0);
    609 		len = UGETW(cdescr.wTotalLength);
    610 		DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
    611 		if (lenp)
    612 			*lenp = len;
    613 		cdesc = malloc(len, M_TEMP, M_WAITOK);
    614 		r = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);
    615 		if (r != USBD_NORMAL_COMPLETION) {
    616 			free(cdesc, M_TEMP);
    617 			return (0);
    618 		}
    619 	}
    620 	return (cdesc);
    621 }
    622 
    623 int
    624 ugen_get_alt_index(sc, ifaceidx)
    625 	struct ugen_softc *sc;
    626 	int ifaceidx;
    627 {
    628 	usbd_interface_handle iface;
    629 	usbd_status r;
    630 
    631 	r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
    632 	if (r != USBD_NORMAL_COMPLETION)
    633 			return (-1);
    634 	return (usbd_get_interface_altindex(iface));
    635 }
    636 
    637 int
    638 ugenioctl(dev, cmd, addr, flag, p)
    639 	dev_t dev;
    640 	u_long cmd;
    641 	caddr_t addr;
    642 	int flag;
    643 	struct proc *p;
    644 {
    645 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    646 	int endpt = UGENENDPOINT(dev);
    647 	usbd_status r;
    648 	usbd_interface_handle iface;
    649 	struct usb_config_desc *cd;
    650 	usb_config_descriptor_t *cdesc;
    651 	struct usb_interface_desc *id;
    652 	usb_interface_descriptor_t *idesc;
    653 	struct usb_endpoint_desc *ed;
    654 	usb_endpoint_descriptor_t *edesc;
    655 	struct usb_alt_interface *ai;
    656 	struct usb_string_desc *si;
    657 	u_int8_t conf, alt;
    658 
    659 	DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
    660 	if (sc->sc_disconnected)
    661 		return (EIO);
    662 
    663 	switch (cmd) {
    664 	case FIONBIO:
    665 		/* All handled in the upper FS layer. */
    666 		return (0);
    667 	default:
    668 		break;
    669 	}
    670 
    671 	if (endpt != USB_CONTROL_ENDPOINT)
    672 		return (EINVAL);
    673 
    674 	switch (cmd) {
    675 	case USB_GET_CONFIG:
    676 		r = usbd_get_config(sc->sc_udev, &conf);
    677 		if (r != USBD_NORMAL_COMPLETION)
    678 			return (EIO);
    679 		*(int *)addr = conf;
    680 		break;
    681 	case USB_SET_CONFIG:
    682 		if (!(flag & FWRITE))
    683 			return (EPERM);
    684 		r = ugen_set_config(sc, *(int *)addr);
    685 		if (r != USBD_NORMAL_COMPLETION)
    686 			return (EIO);
    687 		break;
    688 	case USB_GET_ALTINTERFACE:
    689 		ai = (struct usb_alt_interface *)addr;
    690 		r = usbd_device2interface_handle(sc->sc_udev,
    691 						 ai->interface_index, &iface);
    692 		if (r != USBD_NORMAL_COMPLETION)
    693 			return (EINVAL);
    694 		idesc = usbd_get_interface_descriptor(iface);
    695 		if (!idesc)
    696 			return (EIO);
    697 		ai->alt_no = idesc->bAlternateSetting;
    698 		break;
    699 	case USB_SET_ALTINTERFACE:
    700 		if (!(flag & FWRITE))
    701 			return (EPERM);
    702 		ai = (struct usb_alt_interface *)addr;
    703 		r = usbd_device2interface_handle(sc->sc_udev,
    704 						 ai->interface_index, &iface);
    705 		if (r != USBD_NORMAL_COMPLETION)
    706 			return (EINVAL);
    707 		r = ugen_set_interface(sc, ai->interface_index, ai->alt_no);
    708 		if (r != USBD_NORMAL_COMPLETION)
    709 			return (EINVAL);
    710 		break;
    711 	case USB_GET_NO_ALT:
    712 		ai = (struct usb_alt_interface *)addr;
    713 		cdesc = ugen_get_cdesc(sc, ai->config_index, 0);
    714 		if (!cdesc)
    715 			return (EINVAL);
    716 		idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
    717 		if (!idesc)
    718 			return (EINVAL);
    719 		ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
    720 		break;
    721 	case USB_GET_DEVICE_DESC:
    722 		*(usb_device_descriptor_t *)addr =
    723 			*usbd_get_device_descriptor(sc->sc_udev);
    724 		break;
    725 	case USB_GET_CONFIG_DESC:
    726 		cd = (struct usb_config_desc *)addr;
    727 		cdesc = ugen_get_cdesc(sc, cd->config_index, 0);
    728 		if (!cdesc)
    729 			return (EINVAL);
    730 		cd->desc = *cdesc;
    731 		free(cdesc, M_TEMP);
    732 		break;
    733 	case USB_GET_INTERFACE_DESC:
    734 		id = (struct usb_interface_desc *)addr;
    735 		cdesc = ugen_get_cdesc(sc, id->config_index, 0);
    736 		if (!cdesc)
    737 			return (EINVAL);
    738 		if (id->config_index == USB_CURRENT_CONFIG_INDEX &&
    739 		    id->alt_index == USB_CURRENT_ALT_INDEX)
    740 			alt = ugen_get_alt_index(sc, id->interface_index);
    741 		else
    742 			alt = id->alt_index;
    743 		idesc = usbd_find_idesc(cdesc, id->interface_index, alt);
    744 		if (!idesc) {
    745 			free(cdesc, M_TEMP);
    746 			return (EINVAL);
    747 		}
    748 		id->desc = *idesc;
    749 		free(cdesc, M_TEMP);
    750 		break;
    751 	case USB_GET_ENDPOINT_DESC:
    752 		ed = (struct usb_endpoint_desc *)addr;
    753 		cdesc = ugen_get_cdesc(sc, ed->config_index, 0);
    754 		if (!cdesc)
    755 			return (EINVAL);
    756 		if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&
    757 		    ed->alt_index == USB_CURRENT_ALT_INDEX)
    758 			alt = ugen_get_alt_index(sc, ed->interface_index);
    759 		else
    760 			alt = ed->alt_index;
    761 		edesc = usbd_find_edesc(cdesc, ed->interface_index,
    762 					alt, ed->endpoint_index);
    763 		if (!edesc) {
    764 			free(cdesc, M_TEMP);
    765 			return (EINVAL);
    766 		}
    767 		ed->desc = *edesc;
    768 		free(cdesc, M_TEMP);
    769 		break;
    770 	case USB_GET_FULL_DESC:
    771 	{
    772 		int len;
    773 		struct iovec iov;
    774 		struct uio uio;
    775 		struct usb_full_desc *fd = (struct usb_full_desc *)addr;
    776 		int error;
    777 
    778 		cdesc = ugen_get_cdesc(sc, fd->config_index, &len);
    779 		if (len > fd->size)
    780 			len = fd->size;
    781 		iov.iov_base = (caddr_t)fd->data;
    782 		iov.iov_len = len;
    783 		uio.uio_iov = &iov;
    784 		uio.uio_iovcnt = 1;
    785 		uio.uio_resid = len;
    786 		uio.uio_offset = 0;
    787 		uio.uio_segflg = UIO_USERSPACE;
    788 		uio.uio_rw = UIO_READ;
    789 		uio.uio_procp = p;
    790 		error = uiomove(cdesc, len, &uio);
    791 		free(cdesc, M_TEMP);
    792 		return (error);
    793 	}
    794 	case USB_GET_STRING_DESC:
    795 		si = (struct usb_string_desc *)addr;
    796 		r = usbd_get_string_desc(sc->sc_udev, si->string_index,
    797 					 si->language_id, &si->desc);
    798 		if (r != USBD_NORMAL_COMPLETION)
    799 			return (EINVAL);
    800 		break;
    801 	case USB_DO_REQUEST:
    802 	{
    803 		struct usb_ctl_request *ur = (void *)addr;
    804 		int len = UGETW(ur->request.wLength);
    805 		struct iovec iov;
    806 		struct uio uio;
    807 		void *ptr = 0;
    808 		usbd_status r;
    809 		int error = 0;
    810 
    811 		if (!(flag & FWRITE))
    812 			return (EPERM);
    813 		/* Avoid requests that would damage the bus integrity. */
    814 		if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&
    815 		     ur->request.bRequest == UR_SET_ADDRESS) ||
    816 		    (ur->request.bmRequestType == UT_WRITE_DEVICE &&
    817 		     ur->request.bRequest == UR_SET_CONFIG) ||
    818 		    (ur->request.bmRequestType == UT_WRITE_INTERFACE &&
    819 		     ur->request.bRequest == UR_SET_INTERFACE))
    820 			return (EINVAL);
    821 
    822 		if (len < 0 || len > 32767)
    823 			return (EINVAL);
    824 		if (len != 0) {
    825 			iov.iov_base = (caddr_t)ur->data;
    826 			iov.iov_len = len;
    827 			uio.uio_iov = &iov;
    828 			uio.uio_iovcnt = 1;
    829 			uio.uio_resid = len;
    830 			uio.uio_offset = 0;
    831 			uio.uio_segflg = UIO_USERSPACE;
    832 			uio.uio_rw =
    833 				ur->request.bmRequestType & UT_READ ?
    834 				UIO_READ : UIO_WRITE;
    835 			uio.uio_procp = p;
    836 			ptr = malloc(len, M_TEMP, M_WAITOK);
    837 			if (uio.uio_rw == UIO_WRITE) {
    838 				error = uiomove(ptr, len, &uio);
    839 				if (error)
    840 					goto ret;
    841 			}
    842 		}
    843 		r = usbd_do_request_flags(sc->sc_udev, &ur->request,
    844 					  ptr, ur->flags);
    845 		if (r) {
    846 			error = EIO;
    847 			goto ret;
    848 		}
    849 		if (len != 0) {
    850 			if (uio.uio_rw == UIO_READ) {
    851 				error = uiomove(ptr, len, &uio);
    852 				if (error)
    853 					goto ret;
    854 			}
    855 		}
    856 	ret:
    857 		if (ptr)
    858 			free(ptr, M_TEMP);
    859 		return (error);
    860 	}
    861 	case USB_GET_DEVICEINFO:
    862 		usbd_fill_deviceinfo(sc->sc_udev,
    863 				     (struct usb_device_info *)addr);
    864 		break;
    865 	default:
    866 		return (EINVAL);
    867 	}
    868 	return (0);
    869 }
    870 
    871 int
    872 ugenpoll(dev, events, p)
    873 	dev_t dev;
    874 	int events;
    875 	struct proc *p;
    876 {
    877 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    878 	/* XXX */
    879 	struct ugen_endpoint *sce;
    880 	int revents = 0;
    881 	int s;
    882 
    883 	if (sc->sc_disconnected)
    884 		return (EIO);
    885 
    886 	sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
    887 	if (!sce->edesc) return (0); /* XXX */
    888 	s = splusb();
    889 	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
    890 	case UE_INTERRUPT:
    891 		if (events & (POLLIN | POLLRDNORM)) {
    892 			if (sce->q.c_cc > 0)
    893 				revents |= events & (POLLIN | POLLRDNORM);
    894 			else
    895 				selrecord(p, &sce->rsel);
    896 		}
    897 		break;
    898 	case UE_BULK:
    899 		/*
    900 		 * We have no easy way of determining if a read will
    901 		 * yield any data or a write will happen.
    902 		 * Pretend they will.
    903 		 */
    904 		revents |= events &
    905 			   (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
    906 		break;
    907 	default:
    908 		break;
    909 	}
    910 	splx(s);
    911 	return (revents);
    912 }
    913 
    914 #if defined(__FreeBSD__)
    915 static int
    916 ugen_detach(device_t self)
    917 {
    918         struct ugen_softc *sc = device_get_softc(self);
    919 	char *devinfo = (char *) device_get_desc(self);
    920 
    921 	if (devinfo) {
    922 		device_set_desc(self, NULL);
    923 		free(devinfo, M_USB);
    924 	}
    925 	return 0;
    926 }
    927 #endif
    928