Home | History | Annotate | Line # | Download | only in usb
ugen.c revision 1.6
      1 /*	$NetBSD: ugen.c,v 1.6 1998/12/29 03:13: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 
    136 	usbd_devinfo(uaa->device, 0, devinfo);
    137 	USB_ATTACH_SETUP;
    138 	printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
    139 
    140 	sc->sc_udev = uaa->device;
    141 	r = ugen_set_config(sc, 1); /* XXX 1 */
    142 	if (r != USBD_NORMAL_COMPLETION) {
    143 		printf("%s: setting configuration 1 failed\n",
    144 		       USBDEVNAME(sc->sc_dev));
    145 		sc->sc_disconnected = 1;
    146 		USB_ATTACH_ERROR_RETURN;
    147 	}
    148 	USB_ATTACH_SUCCESS_RETURN;
    149 }
    150 
    151 int
    152 ugen_set_config(sc, configno)
    153 	struct ugen_softc *sc;
    154 	int configno;
    155 {
    156 	usbd_device_handle dev = sc->sc_udev;
    157 	usbd_interface_handle iface;
    158 	usb_endpoint_descriptor_t *ed;
    159 	struct ugen_endpoint *sce;
    160 	u_int8_t niface, nendpt;
    161 	int ifaceno, endptno, endpt;
    162 	usbd_status r;
    163 
    164 	DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
    165 		    USBDEVNAME(sc->sc_dev), configno, sc));
    166 	r = usbd_set_config_no(dev, configno, 0);
    167 	if (r != USBD_NORMAL_COMPLETION)
    168 		return (r);
    169 
    170 	r = usbd_interface_count(dev, &niface);
    171 	if (r != USBD_NORMAL_COMPLETION)
    172 		return (r);
    173 	memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
    174 	for (ifaceno = 0; ifaceno < niface; ifaceno++) {
    175 		DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
    176 		r = usbd_device2interface_handle(dev, ifaceno, &iface);
    177 		if (r != USBD_NORMAL_COMPLETION)
    178 			return (r);
    179 		r = usbd_endpoint_count(iface, &nendpt);
    180 		if (r != USBD_NORMAL_COMPLETION)
    181 			return (r);
    182 		for (endptno = 0; endptno < nendpt; endptno++) {
    183 			ed = usbd_interface2endpoint_descriptor(iface,endptno);
    184 			endpt = ed->bEndpointAddress;
    185 			sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)]
    186 				               [UE_GET_IN(endpt)];
    187 			DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
    188 				    "(%d,%d), sce=%p\n",
    189 				    endptno, endpt, UE_GET_ADDR(endpt),
    190 				    UE_GET_IN(endpt), sce));
    191 			sce->sc = sc;
    192 			sce->edesc = ed;
    193 			sce->iface = iface;
    194 		}
    195 	}
    196 	return (USBD_NORMAL_COMPLETION);
    197 }
    198 
    199 void
    200 ugen_disco(p)
    201 	void *p;
    202 {
    203 	struct ugen_softc *sc = p;
    204 	sc->sc_disconnected = 1;
    205 }
    206 
    207 int
    208 ugenopen(dev, flag, mode, p)
    209 	dev_t dev;
    210 	int flag;
    211 	int mode;
    212 	struct proc *p;
    213 {
    214 	int unit = UGENUNIT(dev);
    215 	int endpt = UGENENDPOINT(dev);
    216 	usb_endpoint_descriptor_t *edesc;
    217 	struct ugen_softc *sc;
    218 	struct ugen_endpoint *sce;
    219 	int dir, isize;
    220 	usbd_status r;
    221 
    222 	DPRINTFN(5, ("ugenopen: flag=%d, unit=%d endpt=%d\n",
    223 		     flag, unit, endpt));
    224 	if (unit >= ugen_cd.cd_ndevs)
    225 		return (ENXIO);
    226 	sc = ugen_cd.cd_devs[unit];
    227 	if (!sc)
    228 		return (ENXIO);
    229 
    230 	if (sc->sc_disconnected)
    231 		return (EIO);
    232 
    233 	if (endpt == USB_CONTROL_ENDPOINT) {
    234 		/*if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
    235 		  return (EACCES);*/
    236 		sce = &sc->sc_endpoints[USB_CONTROL_ENDPOINT][OUT];
    237 		if (sce->state & UGEN_OPEN)
    238 			return (EBUSY);
    239 	} else {
    240 		switch (flag & (FWRITE|FREAD)) {
    241 		case FWRITE:
    242 			dir = OUT;
    243 			break;
    244 		case FREAD:
    245 			dir = IN;
    246 			break;
    247 		default:
    248 			return (EACCES);
    249 		}
    250 		sce = &sc->sc_endpoints[endpt][dir];
    251 		DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n",
    252 			     sc, endpt, dir, sce));
    253 		if (sce->state & UGEN_OPEN)
    254 			return (EBUSY);
    255 		edesc = sce->edesc;
    256 		if (!edesc)
    257 			return (ENXIO);
    258 		switch (edesc->bmAttributes & UE_XFERTYPE) {
    259 		case UE_INTERRUPT:
    260 			isize = UGETW(edesc->wMaxPacketSize);
    261 			if (isize == 0)	/* shouldn't happen */
    262 				return (EINVAL);
    263 			sce->ibuf = malloc(isize, M_USB, M_NOWAIT);
    264 			DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n",
    265 				     endpt, isize));
    266 			if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
    267 				return (ENOMEM);
    268 			r = usbd_open_pipe_intr(sce->iface,
    269 				edesc->bEndpointAddress,
    270 				USBD_SHORT_XFER_OK, &sce->pipeh, sce,
    271 				sce->ibuf, isize, ugenintr);
    272 			if (r != USBD_NORMAL_COMPLETION) {
    273 				free(sce->ibuf, M_USB);
    274 				clfree(&sce->q);
    275 				return (EIO);
    276 			}
    277 			usbd_set_disco(sce->pipeh, ugen_disco, sc);
    278 			DPRINTFN(5, ("ugenopen: interrupt open done\n"));
    279 			break;
    280 		case UE_BULK:
    281 			r = usbd_open_pipe(sce->iface,
    282 					   edesc->bEndpointAddress, 0,
    283 					   &sce->pipeh);
    284 			if (r != USBD_NORMAL_COMPLETION)
    285 				return (EIO);
    286 			break;
    287 		case UE_CONTROL:
    288 		case UE_ISOCHRONOUS:
    289 			return (EINVAL);
    290 		}
    291 	}
    292 	sce->state |= UGEN_OPEN;
    293 	return (0);
    294 }
    295 
    296 int
    297 ugenclose(dev, flag, mode, p)
    298 	dev_t dev;
    299 	int flag;
    300 	int mode;
    301 	struct proc *p;
    302 {
    303 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    304 	int endpt = UGENENDPOINT(dev);
    305 	struct ugen_endpoint *sce;
    306 	int dir;
    307 
    308 	DPRINTFN(5, ("ugenclose\n"));
    309 	if (sc->sc_disconnected)
    310 		return (EIO);
    311 
    312 	if (endpt == USB_CONTROL_ENDPOINT) {
    313 		sc->sc_endpoints[endpt][OUT].state &= ~UGEN_OPEN;
    314 		return (0);
    315 	}
    316 	dir = flag & FWRITE ? OUT : IN;
    317 	sce = &sc->sc_endpoints[endpt][dir];
    318 	sce->state &= ~UGEN_OPEN;
    319 
    320 	usbd_abort_pipe(sce->pipeh);
    321 	usbd_close_pipe(sce->pipeh);
    322 
    323 	if (sce->ibuf) {
    324 		free(sce->ibuf, M_USB);
    325 		sce->ibuf = 0;
    326 	}
    327 
    328 	return (0);
    329 }
    330 
    331 int
    332 ugenread(dev, uio, flag)
    333 	dev_t dev;
    334 	struct uio *uio;
    335 	int flag;
    336 {
    337 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    338 	int endpt = UGENENDPOINT(dev);
    339 	struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
    340 	size_t n;
    341 	char buf[UGEN_BBSIZE];
    342 	usbd_request_handle reqh;
    343 	usbd_status r;
    344 	int s;
    345 	int error = 0;
    346 	u_char buffer[UGEN_CHUNK];
    347 
    348 	DPRINTFN(5, ("ugenread: %d:%d\n", UGENUNIT(dev), UGENENDPOINT(dev)));
    349 	if (sc->sc_disconnected)
    350 		return (EIO);
    351 
    352 #ifdef DIAGNOSTIC
    353 	if (!sce->edesc) {
    354 		printf("ugenread: no edesc\n");
    355 		return (EIO);
    356 	}
    357 #endif
    358 
    359 	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
    360 	case UE_INTERRUPT:
    361 		/* Block until activity occured. */
    362 		s = splusb();
    363 		while (sce->q.c_cc == 0) {
    364 			if (flag & IO_NDELAY) {
    365 				splx(s);
    366 				return EWOULDBLOCK;
    367 			}
    368 			sce->state |= UGEN_ASLP;
    369 			DPRINTFN(5, ("ugenread: sleep on %p\n", sc));
    370 			error = tsleep((caddr_t)sce, PZERO | PCATCH,
    371 				       "ugenrea", 0);
    372 			DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
    373 			if (error) {
    374 				sce->state &= ~UGEN_ASLP;
    375 				splx(s);
    376 				return (error);
    377 			}
    378 		}
    379 		splx(s);
    380 
    381 		/* Transfer as many chunks as possible. */
    382 		while (sce->q.c_cc > 0 && uio->uio_resid > 0) {
    383 			n = min(sce->q.c_cc, uio->uio_resid);
    384 			if (n > sizeof(buffer))
    385 				n = sizeof(buffer);
    386 
    387 			/* Remove a small chunk from the input queue. */
    388 			q_to_b(&sce->q, buffer, n);
    389 			DPRINTFN(5, ("ugenread: got %d chars\n", n));
    390 
    391 			/* Copy the data to the user process. */
    392 			error = uiomove(buffer, n, uio);
    393 			if (error)
    394 				break;
    395 		}
    396 		break;
    397 	case UE_BULK:
    398 		reqh = usbd_alloc_request();
    399 		if (reqh == 0)
    400 			return (ENOMEM);
    401 		while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
    402 			/* XXX use callback to enable interrupt? */
    403 			r = usbd_setup_request(reqh, sce->pipeh, 0, buf, n,
    404 					       0, USBD_NO_TIMEOUT, 0);
    405 			if (r != USBD_NORMAL_COMPLETION) {
    406 				error = EIO;
    407 				break;
    408 			}
    409 			DPRINTFN(1, ("ugenread: transfer %d bytes\n", n));
    410 			r = usbd_sync_transfer(reqh);
    411 			if (r != USBD_NORMAL_COMPLETION) {
    412 				DPRINTF(("ugenread: error=%d\n", r));
    413 				usbd_clear_endpoint_stall(sce->pipeh);
    414 				error = EIO;
    415 				break;
    416 			}
    417 			error = uiomove(buf, n, uio);
    418 			if (error)
    419 				break;
    420 		}
    421 		usbd_free_request(reqh);
    422 		break;
    423 	default:
    424 		return (ENXIO);
    425 	}
    426 
    427 	return (error);
    428 }
    429 
    430 int
    431 ugenwrite(dev, uio, flag)
    432 	dev_t dev;
    433 	struct uio *uio;
    434 	int flag;
    435 {
    436 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    437 	int endpt = UGENENDPOINT(dev);
    438 	struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
    439 	size_t n;
    440 	int error = 0;
    441 	char buf[UGEN_BBSIZE];
    442 	usbd_request_handle reqh;
    443 	usbd_status r;
    444 
    445 	if (sc->sc_disconnected)
    446 		return (EIO);
    447 
    448 #ifdef DIAGNOSTIC
    449 	if (!sce->edesc) {
    450 		printf("ugenwrite: no edesc\n");
    451 		return (EIO);
    452 	}
    453 #endif
    454 
    455 	DPRINTF(("ugenwrite\n"));
    456 	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
    457 	case UE_BULK:
    458 		reqh = usbd_alloc_request();
    459 		if (reqh == 0)
    460 			return (EIO);
    461 		while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
    462 			error = uiomove(buf, n, uio);
    463 			if (error)
    464 				break;
    465 			/* XXX use callback to enable interrupt? */
    466 			r = usbd_setup_request(reqh, sce->pipeh, 0, buf, n,
    467 					       0, USBD_NO_TIMEOUT, 0);
    468 			if (r != USBD_NORMAL_COMPLETION) {
    469 				error = EIO;
    470 				break;
    471 			}
    472 			DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
    473 			r = usbd_sync_transfer(reqh);
    474 			if (r != USBD_NORMAL_COMPLETION) {
    475 				DPRINTF(("ugenwrite: error=%d\n", r));
    476 				usbd_clear_endpoint_stall(sce->pipeh);
    477 				error = EIO;
    478 				break;
    479 			}
    480 		}
    481 		usbd_free_request(reqh);
    482 		break;
    483 	default:
    484 		return (ENXIO);
    485 	}
    486 	return (error);
    487 }
    488 
    489 
    490 void
    491 ugenintr(reqh, addr, status)
    492 	usbd_request_handle reqh;
    493 	usbd_private_handle addr;
    494 	usbd_status status;
    495 {
    496 	struct ugen_endpoint *sce = addr;
    497 	/*struct ugen_softc *sc = sce->sc;*/
    498 	u_char *ibuf;
    499 	int isize;
    500 
    501 	if (status == USBD_CANCELLED)
    502 		return;
    503 
    504 	if (status != USBD_NORMAL_COMPLETION) {
    505 		DPRINTF(("ugenintr: status=%d\n", status));
    506 		usbd_clear_endpoint_stall_async(sce->pipeh);
    507 		return;
    508 	}
    509 
    510 	ibuf = sce->ibuf;
    511 	isize = UGETW(sce->edesc->wMaxPacketSize);
    512 
    513 	/*DPRINTFN(5, ("ugenintr: addr=%d endpt=%d\n",
    514 		     addr, endpt, isize));
    515 	DPRINTFN(5, ("          data = %02x %02x %02x\n",
    516 	ibuf[0], ibuf[1], ibuf[2]));*/
    517 
    518 	(void)b_to_q(ibuf, isize, &sce->q);
    519 
    520 	if (sce->state & UGEN_ASLP) {
    521 		sce->state &= ~UGEN_ASLP;
    522 		DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
    523 		wakeup((caddr_t)sce);
    524 	}
    525 	selwakeup(&sce->rsel);
    526 }
    527 
    528 usbd_status
    529 ugen_set_interface(sc, ifaceidx, altno)
    530 	struct ugen_softc *sc;
    531 	int ifaceidx, altno;
    532 {
    533 	usbd_interface_handle iface;
    534 	usb_endpoint_descriptor_t *ed;
    535 	usbd_status r;
    536 	struct ugen_endpoint *sce;
    537 	u_int8_t niface, nendpt, endptno, endpt;
    538 
    539 	DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
    540 
    541 	r = usbd_interface_count(sc->sc_udev, &niface);
    542 	if (r != USBD_NORMAL_COMPLETION)
    543 		return (r);
    544 	if (ifaceidx < 0 || ifaceidx >= niface)
    545 		return (USBD_INVAL);
    546 
    547 	r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
    548 	if (r != USBD_NORMAL_COMPLETION)
    549 		return (r);
    550 	r = usbd_endpoint_count(iface, &nendpt);
    551 	if (r != USBD_NORMAL_COMPLETION)
    552 		return (r);
    553 	for (endptno = 0; endptno < nendpt; endptno++) {
    554 		ed = usbd_interface2endpoint_descriptor(iface,endptno);
    555 		endpt = ed->bEndpointAddress;
    556 		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
    557 		sce->sc = 0;
    558 		sce->edesc = 0;
    559 		sce->iface = 0;
    560 	}
    561 
    562 	/* change setting */
    563 	r = usbd_set_interface(iface, altno);
    564 	if (r != USBD_NORMAL_COMPLETION)
    565 		return (r);
    566 
    567 	r = usbd_endpoint_count(iface, &nendpt);
    568 	if (r != USBD_NORMAL_COMPLETION)
    569 		return (r);
    570 	for (endptno = 0; endptno < nendpt; endptno++) {
    571 		ed = usbd_interface2endpoint_descriptor(iface,endptno);
    572 		endpt = ed->bEndpointAddress;
    573 		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];
    574 		sce->sc = sc;
    575 		sce->edesc = ed;
    576 		sce->iface = iface;
    577 	}
    578 	return (0);
    579 }
    580 
    581 /* Retrieve a complete descriptor for a certain device and index. */
    582 usb_config_descriptor_t *
    583 ugen_get_cdesc(sc, index, lenp)
    584 	struct ugen_softc *sc;
    585 	int index;
    586 	int *lenp;
    587 {
    588 	usb_config_descriptor_t *cdesc, *tdesc, cdescr;
    589 	int len;
    590 	usbd_status r;
    591 
    592 	if (index == USB_CURRENT_CONFIG_INDEX) {
    593 		tdesc = usbd_get_config_descriptor(sc->sc_udev);
    594 		len = UGETW(tdesc->wTotalLength);
    595 		if (lenp)
    596 			*lenp = len;
    597 		cdesc = malloc(len, M_TEMP, M_WAITOK);
    598 		memcpy(cdesc, tdesc, len);
    599 		DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
    600 	} else {
    601 		r = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
    602 		if (r != USBD_NORMAL_COMPLETION)
    603 			return (0);
    604 		len = UGETW(cdescr.wTotalLength);
    605 		DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
    606 		if (lenp)
    607 			*lenp = len;
    608 		cdesc = malloc(len, M_TEMP, M_WAITOK);
    609 		r = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);
    610 		if (r != USBD_NORMAL_COMPLETION) {
    611 			free(cdesc, M_TEMP);
    612 			return (0);
    613 		}
    614 	}
    615 	return (cdesc);
    616 }
    617 
    618 int
    619 ugen_get_alt_index(sc, ifaceidx)
    620 	struct ugen_softc *sc;
    621 	int ifaceidx;
    622 {
    623 	usbd_interface_handle iface;
    624 	usbd_status r;
    625 
    626 	r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
    627 	if (r != USBD_NORMAL_COMPLETION)
    628 			return (-1);
    629 	return (usbd_get_interface_altindex(iface));
    630 }
    631 
    632 int
    633 ugenioctl(dev, cmd, addr, flag, p)
    634 	dev_t dev;
    635 	u_long cmd;
    636 	caddr_t addr;
    637 	int flag;
    638 	struct proc *p;
    639 {
    640 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    641 	int endpt = UGENENDPOINT(dev);
    642 	usbd_status r;
    643 	usbd_interface_handle iface;
    644 	struct usb_config_desc *cd;
    645 	usb_config_descriptor_t *cdesc;
    646 	struct usb_interface_desc *id;
    647 	usb_interface_descriptor_t *idesc;
    648 	struct usb_endpoint_desc *ed;
    649 	usb_endpoint_descriptor_t *edesc;
    650 	struct usb_alt_interface *ai;
    651 	struct usb_string_desc *si;
    652 	u_int8_t conf, alt;
    653 
    654 	DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
    655 	if (sc->sc_disconnected)
    656 		return (EIO);
    657 
    658 	switch (cmd) {
    659 	case FIONBIO:
    660 		/* All handled in the upper FS layer. */
    661 		return (0);
    662 	default:
    663 		break;
    664 	}
    665 
    666 	if (endpt != USB_CONTROL_ENDPOINT)
    667 		return (EINVAL);
    668 
    669 	switch (cmd) {
    670 	case USB_GET_CONFIG:
    671 		r = usbd_get_config(sc->sc_udev, &conf);
    672 		if (r != USBD_NORMAL_COMPLETION)
    673 			return (EIO);
    674 		*(int *)addr = conf;
    675 		break;
    676 	case USB_SET_CONFIG:
    677 		if (!(flag & FWRITE))
    678 			return (EPERM);
    679 		r = ugen_set_config(sc, *(int *)addr);
    680 		if (r != USBD_NORMAL_COMPLETION)
    681 			return (EIO);
    682 		break;
    683 	case USB_GET_ALTINTERFACE:
    684 		ai = (struct usb_alt_interface *)addr;
    685 		r = usbd_device2interface_handle(sc->sc_udev,
    686 						 ai->interface_index, &iface);
    687 		if (r != USBD_NORMAL_COMPLETION)
    688 			return (EINVAL);
    689 		idesc = usbd_get_interface_descriptor(iface);
    690 		if (!idesc)
    691 			return (EIO);
    692 		ai->alt_no = idesc->bAlternateSetting;
    693 		break;
    694 	case USB_SET_ALTINTERFACE:
    695 		if (!(flag & FWRITE))
    696 			return (EPERM);
    697 		ai = (struct usb_alt_interface *)addr;
    698 		r = usbd_device2interface_handle(sc->sc_udev,
    699 						 ai->interface_index, &iface);
    700 		if (r != USBD_NORMAL_COMPLETION)
    701 			return (EINVAL);
    702 		r = ugen_set_interface(sc, ai->interface_index, ai->alt_no);
    703 		if (r != USBD_NORMAL_COMPLETION)
    704 			return (EINVAL);
    705 		break;
    706 	case USB_GET_NO_ALT:
    707 		ai = (struct usb_alt_interface *)addr;
    708 		cdesc = ugen_get_cdesc(sc, ai->config_index, 0);
    709 		if (!cdesc)
    710 			return (EINVAL);
    711 		idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);
    712 		if (!idesc)
    713 			return (EINVAL);
    714 		ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
    715 		break;
    716 	case USB_GET_DEVICE_DESC:
    717 		*(usb_device_descriptor_t *)addr =
    718 			*usbd_get_device_descriptor(sc->sc_udev);
    719 		break;
    720 	case USB_GET_CONFIG_DESC:
    721 		cd = (struct usb_config_desc *)addr;
    722 		cdesc = ugen_get_cdesc(sc, cd->config_index, 0);
    723 		if (!cdesc)
    724 			return (EINVAL);
    725 		cd->desc = *cdesc;
    726 		free(cdesc, M_TEMP);
    727 		break;
    728 	case USB_GET_INTERFACE_DESC:
    729 		id = (struct usb_interface_desc *)addr;
    730 		cdesc = ugen_get_cdesc(sc, id->config_index, 0);
    731 		if (!cdesc)
    732 			return (EINVAL);
    733 		if (id->config_index == USB_CURRENT_CONFIG_INDEX &&
    734 		    id->alt_index == USB_CURRENT_ALT_INDEX)
    735 			alt = ugen_get_alt_index(sc, id->interface_index);
    736 		else
    737 			alt = id->alt_index;
    738 		idesc = usbd_find_idesc(cdesc, id->interface_index, alt);
    739 		if (!idesc) {
    740 			free(cdesc, M_TEMP);
    741 			return (EINVAL);
    742 		}
    743 		id->desc = *idesc;
    744 		free(cdesc, M_TEMP);
    745 		break;
    746 	case USB_GET_ENDPOINT_DESC:
    747 		ed = (struct usb_endpoint_desc *)addr;
    748 		cdesc = ugen_get_cdesc(sc, ed->config_index, 0);
    749 		if (!cdesc)
    750 			return (EINVAL);
    751 		if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&
    752 		    ed->alt_index == USB_CURRENT_ALT_INDEX)
    753 			alt = ugen_get_alt_index(sc, ed->interface_index);
    754 		else
    755 			alt = ed->alt_index;
    756 		edesc = usbd_find_edesc(cdesc, ed->interface_index,
    757 					alt, ed->endpoint_index);
    758 		if (!edesc) {
    759 			free(cdesc, M_TEMP);
    760 			return (EINVAL);
    761 		}
    762 		ed->desc = *edesc;
    763 		free(cdesc, M_TEMP);
    764 		break;
    765 	case USB_GET_FULL_DESC:
    766 	{
    767 		int len;
    768 		struct iovec iov;
    769 		struct uio uio;
    770 		struct usb_full_desc *fd = (struct usb_full_desc *)addr;
    771 		int error;
    772 
    773 		cdesc = ugen_get_cdesc(sc, fd->config_index, &len);
    774 		if (len > fd->size)
    775 			len = fd->size;
    776 		iov.iov_base = (caddr_t)fd->data;
    777 		iov.iov_len = len;
    778 		uio.uio_iov = &iov;
    779 		uio.uio_iovcnt = 1;
    780 		uio.uio_resid = len;
    781 		uio.uio_offset = 0;
    782 		uio.uio_segflg = UIO_USERSPACE;
    783 		uio.uio_rw = UIO_READ;
    784 		uio.uio_procp = p;
    785 		error = uiomove(cdesc, len, &uio);
    786 		free(cdesc, M_TEMP);
    787 		return (error);
    788 	}
    789 	case USB_GET_STRING_DESC:
    790 		si = (struct usb_string_desc *)addr;
    791 		r = usbd_get_string_desc(sc->sc_udev, si->string_index,
    792 					 si->language_id, &si->desc);
    793 		if (r != USBD_NORMAL_COMPLETION)
    794 			return (EINVAL);
    795 		break;
    796 	case USB_DO_REQUEST:
    797 	{
    798 		struct usb_ctl_request *ur = (void *)addr;
    799 		int len = UGETW(ur->request.wLength);
    800 		struct iovec iov;
    801 		struct uio uio;
    802 		void *ptr = 0;
    803 		usbd_status r;
    804 		int error = 0;
    805 
    806 		if (!(flag & FWRITE))
    807 			return (EPERM);
    808 		/* Avoid requests that would damage the bus integrity. */
    809 		if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&
    810 		     ur->request.bRequest == UR_SET_ADDRESS) ||
    811 		    (ur->request.bmRequestType == UT_WRITE_DEVICE &&
    812 		     ur->request.bRequest == UR_SET_CONFIG) ||
    813 		    (ur->request.bmRequestType == UT_WRITE_INTERFACE &&
    814 		     ur->request.bRequest == UR_SET_INTERFACE))
    815 			return (EINVAL);
    816 
    817 		if (len < 0 || len > 32767)
    818 			return (EINVAL);
    819 		if (len != 0) {
    820 			iov.iov_base = (caddr_t)ur->data;
    821 			iov.iov_len = len;
    822 			uio.uio_iov = &iov;
    823 			uio.uio_iovcnt = 1;
    824 			uio.uio_resid = len;
    825 			uio.uio_offset = 0;
    826 			uio.uio_segflg = UIO_USERSPACE;
    827 			uio.uio_rw =
    828 				ur->request.bmRequestType & UT_READ ?
    829 				UIO_READ : UIO_WRITE;
    830 			uio.uio_procp = p;
    831 			ptr = malloc(len, M_TEMP, M_WAITOK);
    832 			if (uio.uio_rw == UIO_WRITE) {
    833 				error = uiomove(ptr, len, &uio);
    834 				if (error)
    835 					goto ret;
    836 			}
    837 		}
    838 		r = usbd_do_request_flags(sc->sc_udev, &ur->request,
    839 					  ptr, ur->flags);
    840 		if (r) {
    841 			error = EIO;
    842 			goto ret;
    843 		}
    844 		if (len != 0) {
    845 			if (uio.uio_rw == UIO_READ) {
    846 				error = uiomove(ptr, len, &uio);
    847 				if (error)
    848 					goto ret;
    849 			}
    850 		}
    851 	ret:
    852 		if (ptr)
    853 			free(ptr, M_TEMP);
    854 		return (error);
    855 	}
    856 	case USB_GET_DEVICEINFO:
    857 		usbd_fill_deviceinfo(sc->sc_udev,
    858 				     (struct usb_device_info *)addr);
    859 		break;
    860 	default:
    861 		return (EINVAL);
    862 	}
    863 	return (0);
    864 }
    865 
    866 int
    867 ugenpoll(dev, events, p)
    868 	dev_t dev;
    869 	int events;
    870 	struct proc *p;
    871 {
    872 	struct ugen_softc *sc = ugen_cd.cd_devs[UGENUNIT(dev)];
    873 	/* XXX */
    874 	struct ugen_endpoint *sce;
    875 	int revents = 0;
    876 	int s;
    877 
    878 	if (sc->sc_disconnected)
    879 		return (EIO);
    880 
    881 	sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
    882 	if (!sce->edesc) return (0); /* XXX */
    883 	s = splusb();
    884 	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
    885 	case UE_INTERRUPT:
    886 		if (events & (POLLIN | POLLRDNORM)) {
    887 			if (sce->q.c_cc > 0)
    888 				revents |= events & (POLLIN | POLLRDNORM);
    889 			else
    890 				selrecord(p, &sce->rsel);
    891 		}
    892 		break;
    893 	case UE_BULK:
    894 		/*
    895 		 * We have no easy way of determining if a read will
    896 		 * yield any data or a write will happen.
    897 		 * Pretend they will.
    898 		 */
    899 		revents |= events &
    900 			   (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
    901 		break;
    902 	default:
    903 		break;
    904 	}
    905 	splx(s);
    906 	return (revents);
    907 }
    908 
    909 #if defined(__FreeBSD__)
    910 static int
    911 ugen_detach(device_t self)
    912 {
    913         struct ugen_softc *sc = device_get_softc(self);
    914 	char *devinfo = (char *) device_get_desc(self);
    915 
    916 	if (devinfo) {
    917 		device_set_desc(self, NULL);
    918 		free(devinfo, M_USB);
    919 	}
    920 	return 0;
    921 }
    922 #endif
    923