Home | History | Annotate | Line # | Download | only in usb
usbdi.c revision 1.16
      1 /*	$NetBSD: usbdi.c,v 1.16 1998/12/28 20:14:00 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 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/kernel.h>
     43 #if defined(__NetBSD__)
     44 #include <sys/device.h>
     45 #else
     46 #include <sys/module.h>
     47 #include <sys/bus.h>
     48 #include <sys/conf.h>
     49 #endif
     50 #include <sys/malloc.h>
     51 #include <sys/proc.h>
     52 
     53 #include <dev/usb/usb.h>
     54 
     55 #include <dev/usb/usbdi.h>
     56 #include <dev/usb/usbdi_util.h>
     57 #include <dev/usb/usbdivar.h>
     58 
     59 #ifdef USB_DEBUG
     60 #define DPRINTF(x)	if (usbdebug) printf x
     61 #define DPRINTFN(n,x)	if (usbdebug>(n)) printf x
     62 extern int usbdebug;
     63 #else
     64 #define DPRINTF(x)
     65 #define DPRINTFN(n,x)
     66 #endif
     67 
     68 static usbd_status usbd_ar_pipe  __P((usbd_pipe_handle pipe));
     69 static usbd_status usbd_ar_iface __P((usbd_interface_handle iface));
     70 static void usbd_transfer_cb __P((usbd_request_handle reqh));
     71 static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
     72 static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
     73 void usbd_do_request_async_cb
     74 	__P((usbd_request_handle, usbd_private_handle, usbd_status));
     75 
     76 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
     77 
     78 #if defined(__FreeBSD__)
     79 #define USB_CDEV_MAJOR	79
     80 
     81 extern struct cdevsw usb_cdevsw;
     82 #endif
     83 
     84 usbd_status
     85 usbd_open_pipe(iface, address, flags, pipe)
     86 	usbd_interface_handle iface;
     87 	u_int8_t address;
     88 	u_int8_t flags;
     89 	usbd_pipe_handle *pipe;
     90 {
     91 	usbd_pipe_handle p;
     92 	struct usbd_endpoint *ep;
     93 	usbd_status r;
     94 	int i;
     95 
     96 	if (iface->state != USBD_INTERFACE_ACTIVE)
     97 		return (USBD_INTERFACE_NOT_ACTIVE);
     98 	for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
     99 		ep = &iface->endpoints[i];
    100 		if (ep->edesc->bEndpointAddress == address)
    101 			goto found;
    102 	}
    103 	return (USBD_BAD_ADDRESS);
    104  found:
    105 	if ((flags & USBD_EXCLUSIVE_USE) &&
    106 	    ep->refcnt != 0)
    107 		return (USBD_IN_USE);
    108 	r = usbd_setup_pipe(iface->device, iface, ep, &p);
    109 	if (r != USBD_NORMAL_COMPLETION)
    110 		return (r);
    111 	LIST_INSERT_HEAD(&iface->pipes, p, next);
    112 	*pipe = p;
    113 	return (USBD_NORMAL_COMPLETION);
    114 }
    115 
    116 usbd_status
    117 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
    118 	usbd_interface_handle iface;
    119 	u_int8_t address;
    120 	u_int8_t flags;
    121 	usbd_pipe_handle *pipe;
    122 	usbd_private_handle priv;
    123 	void *buffer;
    124 	u_int32_t length;
    125 	usbd_callback cb;
    126 {
    127 	usbd_status r;
    128 	usbd_request_handle reqh;
    129 	usbd_pipe_handle ipipe;
    130 
    131 	reqh = usbd_alloc_request();
    132 	if (reqh == 0)
    133 		return (USBD_NOMEM);
    134 	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
    135 	if (r != USBD_NORMAL_COMPLETION)
    136 		goto bad1;
    137 	r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
    138 			       USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
    139 	if (r != USBD_NORMAL_COMPLETION)
    140 		goto bad2;
    141 	ipipe->intrreqh = reqh;
    142 	r = usbd_transfer(reqh);
    143 	*pipe = ipipe;
    144 	if (r != USBD_IN_PROGRESS)
    145 		goto bad3;
    146 	return (USBD_NORMAL_COMPLETION);
    147 
    148  bad3:
    149 	ipipe->intrreqh = 0;
    150  bad2:
    151 	usbd_close_pipe(ipipe);
    152  bad1:
    153 	usbd_free_request(reqh);
    154 	return r;
    155 }
    156 
    157 usbd_status
    158 usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf, cb)
    159 	usbd_interface_handle iface;
    160 	u_int8_t address;
    161 	u_int8_t flags;
    162 	usbd_pipe_handle *pipe;
    163 	usbd_private_handle priv;
    164 	u_int32_t bufsize;
    165 	u_int32_t nbuf;
    166 	usbd_callback cb;
    167 {
    168 	usbd_status r;
    169 	usbd_pipe_handle p;
    170 
    171 	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);
    172 	if (r != USBD_NORMAL_COMPLETION)
    173 		return (r);
    174 	if (!p->methods->isobuf) {
    175 		usbd_close_pipe(p);
    176 		return (USBD_INVAL);
    177 	}
    178 	r = p->methods->isobuf(p, bufsize, nbuf);
    179 	if (r != USBD_NORMAL_COMPLETION) {
    180 		usbd_close_pipe(p);
    181 		return (r);
    182 	}
    183 	*pipe = p;
    184 	return r;
    185 }
    186 
    187 usbd_status
    188 usbd_close_pipe(pipe)
    189 	usbd_pipe_handle pipe;
    190 {
    191 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    192 		return (USBD_INTERFACE_NOT_ACTIVE);
    193 	if (--pipe->refcnt != 0)
    194 		return (USBD_NORMAL_COMPLETION);
    195 	if (SIMPLEQ_FIRST(&pipe->queue) != 0)
    196 		return (USBD_PENDING_REQUESTS);
    197 	LIST_REMOVE(pipe, next);
    198 	pipe->endpoint->refcnt--;
    199 	pipe->methods->close(pipe);
    200 	if (pipe->intrreqh)
    201 		usbd_free_request(pipe->intrreqh);
    202 	free(pipe, M_USB);
    203 	return (USBD_NORMAL_COMPLETION);
    204 }
    205 
    206 usbd_status
    207 usbd_transfer(reqh)
    208 	usbd_request_handle reqh;
    209 {
    210 	reqh->xfercb = usbd_transfer_cb;
    211 	return (usbd_do_transfer(reqh));
    212 }
    213 
    214 static usbd_status
    215 usbd_do_transfer(reqh)
    216 	usbd_request_handle reqh;
    217 {
    218 	usbd_pipe_handle pipe = reqh->pipe;
    219 
    220 	DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
    221 	reqh->done = 0;
    222 	return (pipe->methods->transfer(reqh));
    223 }
    224 
    225 #if 0
    226 static usbd_status
    227 usbd_do_transfer(reqh)
    228 	usbd_request_handle reqh;
    229 {
    230 	usbd_pipe_handle pipe = reqh->pipe;
    231 
    232 	DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
    233 	reqh->done = 0;
    234 	s = splusb();
    235 	if (pipe->state == USBD_PIPE_IDLE ||
    236 	    (iface && iface->state == USBD_INTERFACE_IDLE)) {
    237 		splx(s);
    238 		return (USBD_IS_IDLE);
    239 	}
    240 	SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);
    241 	if (pipe->state == USBD_PIPE_ACTIVE &&
    242 	    (!iface || iface->state == USBD_INTERFACE_ACTIVE)) {
    243 		r = usbd_start(pipe);
    244 	} else
    245 		r = USBD_NOT_STARTED;
    246 	splx(s);
    247 	return (r);
    248 }
    249 
    250 static usbd_status
    251 usbd_start(pipe)
    252 	usbd_pipe_handle pipe;
    253 {
    254 	usbd_request_handle reqh;
    255 
    256 	DPRINTFN(5, ("usbd_start: pipe=%p, running=%d\n",
    257 		     pipe, pipe->running));
    258 	if (pipe->running)
    259 		return (USBD_IN_PROGRESS);
    260 	reqh = SIMPLEQ_FIRST(&pipe->queue);
    261 	if (!reqh) {
    262 		/* XXX */
    263 		printf("usbd_start: pipe empty!\n");
    264 		pipe->running = 0;
    265 		return (USBD_XXX);
    266 	}
    267 	SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    268 	pipe->running = 1;
    269 	pipe->curreqh = reqh;
    270 	return (pipe->methods->transfer(reqh));
    271 }
    272 #endif
    273 
    274 usbd_request_handle
    275 usbd_alloc_request()
    276 {
    277 	usbd_request_handle reqh;
    278 
    279 	reqh = SIMPLEQ_FIRST(&usbd_free_requests);
    280 	if (reqh)
    281 		SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
    282 	else
    283 		reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
    284 	if (!reqh)
    285 		return (0);
    286 	memset(reqh, 0, sizeof *reqh);
    287 	return (reqh);
    288 }
    289 
    290 usbd_status
    291 usbd_free_request(reqh)
    292 	usbd_request_handle reqh;
    293 {
    294 	SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
    295 	return (USBD_NORMAL_COMPLETION);
    296 }
    297 
    298 usbd_status
    299 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
    300 	usbd_request_handle reqh;
    301 	usbd_pipe_handle pipe;
    302 	usbd_private_handle priv;
    303 	void *buffer;
    304 	u_int32_t length;
    305 	u_int16_t flags;
    306 	u_int32_t timeout;
    307 	void (*callback) __P((usbd_request_handle,
    308 			      usbd_private_handle,
    309 			      usbd_status));
    310 {
    311 	reqh->pipe = pipe;
    312 	reqh->isreq = 0;
    313 	reqh->priv = priv;
    314 	reqh->buffer = buffer;
    315 	reqh->length = length;
    316 	reqh->actlen = 0;
    317 	reqh->flags = flags;
    318 	reqh->callback = callback;
    319 	reqh->status = USBD_NOT_STARTED;
    320 	reqh->retries = 1;
    321 	return (USBD_NORMAL_COMPLETION);
    322 }
    323 
    324 usbd_status
    325 usbd_setup_device_request(reqh, req)
    326 	usbd_request_handle reqh;
    327 	usb_device_request_t *req;
    328 {
    329 	reqh->isreq = 1;
    330 	reqh->request = *req;
    331 	return (USBD_NORMAL_COMPLETION);
    332 }
    333 
    334 usbd_status
    335 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
    336 			   length, flags, callback)
    337 	usbd_request_handle reqh;
    338 	usbd_device_handle dev;
    339 	usbd_private_handle priv;
    340 	u_int32_t timeout;
    341 	usb_device_request_t *req;
    342 	void *buffer;
    343 	u_int32_t length;
    344 	u_int16_t flags;
    345 	void (*callback) __P((usbd_request_handle,
    346 			      usbd_private_handle,
    347 			      usbd_status));
    348 {
    349 	reqh->pipe = dev->default_pipe;
    350 	reqh->priv = priv;
    351 	reqh->buffer = buffer;
    352 	reqh->length = length;
    353 	reqh->actlen = 0;
    354 	reqh->flags = flags;
    355 	reqh->timeout = timeout;
    356 	reqh->status = USBD_NOT_STARTED;
    357 	reqh->callback = callback;
    358 	reqh->request = *req;
    359 	reqh->isreq = 1;
    360 	reqh->retries = 1;
    361 	return (USBD_NORMAL_COMPLETION);
    362 }
    363 
    364 usbd_status
    365 usbd_set_request_timeout(reqh, timeout)
    366 	usbd_request_handle reqh;
    367 	u_int32_t timeout;
    368 {
    369 	reqh->timeout = timeout;
    370 	return (USBD_NORMAL_COMPLETION);
    371 }
    372 
    373 usbd_status
    374 usbd_get_request_status(reqh, priv, buffer, count, status)
    375 	usbd_request_handle reqh;
    376 	usbd_private_handle *priv;
    377 	void **buffer;
    378 	u_int32_t *count;
    379 	usbd_status *status;
    380 {
    381 	*priv = reqh->priv;
    382 	*buffer = reqh->buffer;
    383 	*count = reqh->actlen;
    384 	*status = reqh->status;
    385 	return (USBD_NORMAL_COMPLETION);
    386 }
    387 
    388 usbd_status
    389 usbd_request_device_data(reqh, req)
    390 	usbd_request_handle reqh;
    391 	usb_device_request_t *req;
    392 {
    393 	if (!reqh->isreq)
    394 		return (USBD_INVAL);
    395 	*req = reqh->request;
    396 	return (USBD_NORMAL_COMPLETION);
    397 }
    398 
    399 #if 0
    400 usb_descriptor_t *
    401 usbd_get_descriptor(iface, desc_type)
    402 	usbd_interface_handle *iface;
    403 	u_int8_t desc_type;
    404 XX
    405 #endif
    406 
    407 usb_config_descriptor_t *
    408 usbd_get_config_descriptor(dev)
    409 	usbd_device_handle dev;
    410 {
    411 	return (dev->cdesc);
    412 }
    413 
    414 usb_interface_descriptor_t *
    415 usbd_get_interface_descriptor(iface)
    416 	usbd_interface_handle iface;
    417 {
    418 	return (iface->idesc);
    419 }
    420 
    421 usb_device_descriptor_t *
    422 usbd_get_device_descriptor(dev)
    423 	usbd_device_handle dev;
    424 {
    425 	return (&dev->ddesc);
    426 }
    427 
    428 usb_endpoint_descriptor_t *
    429 usbd_interface2endpoint_descriptor(iface, index)
    430 	usbd_interface_handle iface;
    431 	u_int8_t index;
    432 {
    433 	if (index >= iface->idesc->bNumEndpoints)
    434 		return (0);
    435 	return (iface->endpoints[index].edesc);
    436 }
    437 
    438 usbd_status
    439 usbd_set_configuration(dev, conf)
    440 	usbd_device_handle dev;
    441 	u_int8_t conf;
    442 {
    443 	return usbd_set_config_no(dev, conf, 0);
    444 }
    445 
    446 usbd_status
    447 usbd_retry_request(reqh, retry_count)
    448 	usbd_request_handle reqh;
    449 	u_int32_t retry_count;
    450 {
    451 	usbd_status r;
    452 
    453 	r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
    454 	if (r != USBD_NORMAL_COMPLETION)
    455 		return (r);
    456 	reqh->retries = retry_count;
    457 	return (usbd_transfer(reqh));
    458 }
    459 
    460 usbd_status
    461 usbd_abort_pipe(pipe)
    462 	usbd_pipe_handle pipe;
    463 {
    464 	usbd_status r;
    465 	int s, st;
    466 
    467 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    468 		return (USBD_INTERFACE_NOT_ACTIVE);
    469 	s = splusb();
    470 	st = pipe->state;
    471 	r = usbd_ar_pipe(pipe);
    472 	pipe->state = st;
    473 	splx(s);
    474 	return (r);
    475 }
    476 
    477 usbd_status
    478 usbd_abort_interface(iface)
    479 	usbd_interface_handle iface;
    480 {
    481 	usbd_status r;
    482 	int s, st;
    483 
    484 	s = splusb();
    485 	st = iface->state;
    486 	r = usbd_ar_iface(iface);
    487 	iface->state = st;
    488 	splx(s);
    489 	return (r);
    490 }
    491 
    492 usbd_status
    493 usbd_reset_pipe(pipe)
    494 	usbd_pipe_handle pipe;
    495 {
    496 	usbd_status r;
    497 	int s;
    498 
    499 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    500 		return (USBD_INTERFACE_NOT_ACTIVE);
    501 	s = splusb();
    502 	r = usbd_ar_pipe(pipe);
    503 	/* XXX anything else */
    504 	pipe->state = USBD_PIPE_ACTIVE;
    505 	splx(s);
    506 	return (r);
    507 }
    508 
    509 usbd_status
    510 usbd_reset_interface(iface)
    511 	usbd_interface_handle iface;
    512 {
    513 	usbd_status r;
    514 	int s;
    515 
    516 	s = splusb();
    517 	r = usbd_ar_iface(iface);
    518 	/* XXX anything else */
    519 	iface->state = USBD_INTERFACE_ACTIVE;
    520 	splx(s);
    521 	return (r);
    522 }
    523 
    524 usbd_status
    525 usbd_clear_endpoint_stall(pipe)
    526 	usbd_pipe_handle pipe;
    527 {
    528 	usbd_device_handle dev = pipe->device;
    529 	usb_device_request_t req;
    530 	usbd_status r;
    531 
    532 	req.bmRequestType = UT_WRITE_ENDPOINT;
    533 	req.bRequest = UR_CLEAR_FEATURE;
    534 	USETW(req.wValue, UF_ENDPOINT_HALT);
    535 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
    536 	USETW(req.wLength, 0);
    537 	r = usbd_do_request(dev, &req, 0);
    538 #if 0
    539 XXX should we do this?
    540 	if (r == USBD_NORMAL_COMPLETION) {
    541 		pipe->state = USBD_PIPE_ACTIVE;
    542 		/* XXX activate pipe */
    543 	}
    544 #endif
    545 	return (r);
    546 }
    547 
    548 usbd_status
    549 usbd_clear_endpoint_stall_async(pipe)
    550 	usbd_pipe_handle pipe;
    551 {
    552 	usbd_device_handle dev = pipe->device;
    553 	usb_device_request_t req;
    554 	usbd_status r;
    555 
    556 	req.bmRequestType = UT_WRITE_ENDPOINT;
    557 	req.bRequest = UR_CLEAR_FEATURE;
    558 	USETW(req.wValue, UF_ENDPOINT_HALT);
    559 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
    560 	USETW(req.wLength, 0);
    561 	r = usbd_do_request_async(dev, &req, 0);
    562 	return (r);
    563 }
    564 
    565 usbd_status
    566 usbd_set_pipe_state(pipe, state)
    567 	usbd_pipe_handle pipe;
    568 	usbd_pipe_state state;
    569 {
    570 	int s;
    571 	usbd_status r;
    572 	usbd_request_handle reqh;
    573 
    574 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    575 		return (USBD_INTERFACE_NOT_ACTIVE);
    576 	if (state != USBD_PIPE_ACTIVE &&
    577 	    state != USBD_PIPE_STALLED &&
    578 	    state != USBD_PIPE_IDLE)
    579 		return (USBD_INVAL);
    580 	pipe->state = state;
    581 	r = USBD_NORMAL_COMPLETION;
    582 	if (state == USBD_PIPE_ACTIVE) {
    583 		s = splusb();
    584 		if (!pipe->running) {
    585 			reqh = SIMPLEQ_FIRST(&pipe->queue);
    586 			if (reqh != 0) {
    587 				pipe->running = 1;
    588 				splx(s);
    589 				r = pipe->methods->start(reqh);
    590 			} else
    591 				splx(s);
    592 		} else
    593 			splx(s);
    594 	}
    595 	return (r);
    596 }
    597 
    598 usbd_status
    599 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
    600 	usbd_pipe_handle pipe;
    601 	usbd_pipe_state *state;
    602 	u_int32_t *endpoint_state;
    603 	u_int32_t *request_count;
    604 {
    605 	int n;
    606 	usbd_request_handle r;
    607 
    608 	*state = pipe->state;
    609 	*endpoint_state = pipe->endpoint->state;
    610 	for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
    611 	     r != 0;
    612 	     r = SIMPLEQ_NEXT(r, next), n++)
    613 		;
    614 	*request_count = n;
    615 	return (USBD_NORMAL_COMPLETION);
    616 }
    617 
    618 usbd_status
    619 usbd_set_interface_state(iface, state)
    620 	usbd_interface_handle iface;
    621 	usbd_interface_state state;
    622 {
    623 	int ps;
    624 	usbd_pipe_handle p;
    625 
    626 	if (state == USBD_INTERFACE_ACTIVE)
    627 		ps = USBD_PIPE_ACTIVE;
    628 	else if (state == USBD_INTERFACE_STALLED)
    629 		ps = USBD_PIPE_STALLED;
    630 	else if (state == USBD_INTERFACE_IDLE)
    631 		ps = USBD_PIPE_IDLE;
    632 	else
    633 		return (USBD_INVAL);
    634 	iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
    635 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
    636 		usbd_set_pipe_state(p, ps);
    637 	iface->state = state;
    638 	return (USBD_NORMAL_COMPLETION);
    639 }
    640 
    641 usbd_status
    642 usbd_get_interface_state(iface, state)
    643 	usbd_interface_handle iface;
    644 	usbd_interface_state *state;
    645 {
    646 	*state = iface->state;
    647 	return (USBD_NORMAL_COMPLETION);
    648 }
    649 
    650 usbd_status
    651 usbd_get_device_state(dev, state)
    652 	usbd_device_handle dev;
    653 	usbd_device_state *state;
    654 {
    655 	*state = dev->state;
    656 	return (USBD_NORMAL_COMPLETION);
    657 }
    658 
    659 #if 0
    660 usbd_status
    661 usbd_set_device_state(dev, state)
    662 	usbd_device_handle dev;
    663 	usbd_device_state state;
    664 X
    665 #endif
    666 
    667 usbd_status
    668 usbd_device_address(dev, address)
    669 	usbd_device_handle dev;
    670 	u_int8_t *address;
    671 {
    672 	*address = dev->address;
    673 	return (USBD_NORMAL_COMPLETION);
    674 }
    675 
    676 usbd_status
    677 usbd_endpoint_address(pipe, address)
    678 	usbd_pipe_handle pipe;
    679 	u_int8_t *address;
    680 {
    681 	*address = pipe->endpoint->edesc->bEndpointAddress;
    682 	return (USBD_NORMAL_COMPLETION);
    683 }
    684 
    685 usbd_status
    686 usbd_endpoint_count(iface, count)
    687 	usbd_interface_handle iface;
    688 	u_int8_t *count;
    689 {
    690 	*count = iface->idesc->bNumEndpoints;
    691 	return (USBD_NORMAL_COMPLETION);
    692 }
    693 
    694 usbd_status
    695 usbd_interface_count(dev, count)
    696 	usbd_device_handle dev;
    697 	u_int8_t *count;
    698 {
    699 	if (!dev->cdesc)
    700 		return (USBD_NOT_CONFIGURED);
    701 	*count = dev->cdesc->bNumInterface;
    702 	return (USBD_NORMAL_COMPLETION);
    703 }
    704 
    705 u_int8_t
    706 usbd_bus_count()
    707 {
    708 	return (usb_bus_count());
    709 }
    710 
    711 usbd_status
    712 usbd_get_bus_handle(index, bus)
    713 	u_int8_t index;
    714 	usbd_bus_handle *bus;
    715 {
    716 	return (usb_get_bus_handle(index, bus));
    717 }
    718 
    719 usbd_status
    720 usbd_get_root_hub(bus, dev)
    721 	usbd_bus_handle bus;
    722 	usbd_device_handle *dev;
    723 {
    724 	*dev = bus->root_hub;
    725 	return (USBD_NORMAL_COMPLETION);
    726 }
    727 
    728 usbd_status
    729 usbd_port_count(dev, nports)
    730 	usbd_device_handle dev;
    731 	u_int8_t *nports;
    732 {
    733 	if (dev->hub == 0)
    734 		return (USBD_INVAL);
    735 	*nports = dev->hub->hubdesc.bNbrPorts;
    736 	return (USBD_NORMAL_COMPLETION);
    737 }
    738 
    739 usbd_status
    740 usbd_hub2device_handle(dev, port, devp)
    741 	usbd_device_handle dev;
    742 	u_int8_t port;
    743 	usbd_device_handle *devp;
    744 {
    745 	if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
    746 	    dev->hub->ports[port].device == 0)
    747 		return (USBD_INVAL);
    748 	*devp = dev->hub->ports[port].device;
    749 	return (USBD_NORMAL_COMPLETION);
    750 }
    751 
    752 usbd_status
    753 usbd_request2pipe_handle(reqh, pipe)
    754 	usbd_request_handle reqh;
    755 	usbd_pipe_handle *pipe;
    756 {
    757 	*pipe = reqh->pipe;
    758 	return (USBD_NORMAL_COMPLETION);
    759 }
    760 
    761 usbd_status
    762 usbd_pipe2interface_handle(pipe, iface)
    763 	usbd_pipe_handle pipe;
    764 	usbd_interface_handle *iface;
    765 {
    766 	*iface = pipe->iface;
    767 	return (USBD_NORMAL_COMPLETION);
    768 }
    769 
    770 usbd_status
    771 usbd_interface2device_handle(iface, dev)
    772 	usbd_interface_handle iface;
    773 	usbd_device_handle *dev;
    774 {
    775 	*dev = iface->device;
    776 	return (USBD_NORMAL_COMPLETION);
    777 }
    778 
    779 usbd_status
    780 usbd_device2bus_handle(dev, bus)
    781 	usbd_device_handle dev;
    782 	usbd_bus_handle *bus;
    783 {
    784 	*bus = dev->bus;
    785 	return (USBD_NORMAL_COMPLETION);
    786 }
    787 
    788 usbd_status
    789 usbd_device2interface_handle(dev, ifaceno, iface)
    790 	usbd_device_handle dev;
    791 	u_int8_t ifaceno;
    792 	usbd_interface_handle *iface;
    793 {
    794 	if (!dev->cdesc)
    795 		return (USBD_NOT_CONFIGURED);
    796 	if (ifaceno >= dev->cdesc->bNumInterface)
    797 		return (USBD_INVAL);
    798 	*iface = &dev->ifaces[ifaceno];
    799 	return (USBD_NORMAL_COMPLETION);
    800 }
    801 
    802 usbd_status
    803 usbd_set_interface_private_handle(iface, priv)
    804 	usbd_interface_handle iface;
    805 	usbd_private_handle priv;
    806 {
    807 	iface->priv = priv;
    808 	return (USBD_NORMAL_COMPLETION);
    809 }
    810 
    811 usbd_status
    812 usbd_get_interface_private_handle(iface, priv)
    813 	usbd_interface_handle iface;
    814 	usbd_private_handle *priv;
    815 {
    816 	*priv = iface->priv;
    817 	return (USBD_NORMAL_COMPLETION);
    818 }
    819 
    820 usbd_status
    821 usbd_reference_pipe(pipe)
    822 	usbd_pipe_handle pipe;
    823 {
    824 	pipe->refcnt++;
    825 	return (USBD_NORMAL_COMPLETION);
    826 }
    827 
    828 usbd_status
    829 usbd_dereference_pipe(pipe)
    830 	usbd_pipe_handle pipe;
    831 {
    832 	pipe->refcnt--;
    833 	return (USBD_NORMAL_COMPLETION);
    834 }
    835 
    836 usbd_lock_token
    837 usbd_lock()
    838 {
    839 	return (splusb());
    840 }
    841 
    842 void
    843 usbd_unlock(tok)
    844 	usbd_lock_token tok;
    845 {
    846 	splx(tok);
    847 }
    848 
    849 /* XXXX use altno */
    850 usbd_status
    851 usbd_set_interface(iface, altidx)
    852 	usbd_interface_handle iface;
    853 	int altidx;
    854 {
    855 	usb_device_request_t req;
    856 	usbd_status r;
    857 
    858 	if (LIST_FIRST(&iface->pipes) != 0)
    859 		return (USBD_IN_USE);
    860 
    861 	if (iface->endpoints)
    862 		free(iface->endpoints, M_USB);
    863 	iface->endpoints = 0;
    864 	iface->idesc = 0;
    865 	iface->state = USBD_INTERFACE_IDLE;
    866 
    867 	r = usbd_fill_iface_data(iface->device, iface->index, altidx);
    868 	if (r != USBD_NORMAL_COMPLETION)
    869 		return (r);
    870 
    871 	req.bmRequestType = UT_WRITE_INTERFACE;
    872 	req.bRequest = UR_SET_INTERFACE;
    873 	USETW(req.wValue, iface->idesc->bAlternateSetting);
    874 	USETW(req.wIndex, iface->idesc->bInterfaceNumber);
    875 	USETW(req.wLength, 0);
    876 	return usbd_do_request(iface->device, &req, 0);
    877 }
    878 
    879 int
    880 usbd_get_no_alts(cdesc, ifaceno)
    881 	usb_config_descriptor_t *cdesc;
    882 	int ifaceno;
    883 {
    884 	char *p = (char *)cdesc;
    885 	char *end = p + UGETW(cdesc->wTotalLength);
    886 	usb_interface_descriptor_t *d;
    887 	int n;
    888 
    889 	for (n = 0; p < end; p += d->bLength) {
    890 		d = (usb_interface_descriptor_t *)p;
    891 		if (p + d->bLength <= end &&
    892 		    d->bDescriptorType == UDESC_INTERFACE &&
    893 		    d->bInterfaceNumber == ifaceno)
    894 			n++;
    895 	}
    896 	return (n);
    897 }
    898 
    899 int
    900 usbd_get_interface_altindex(iface)
    901 	usbd_interface_handle iface;
    902 {
    903 	return (iface->altindex);
    904 }
    905 
    906 usbd_status
    907 usbd_get_interface(iface, aiface)
    908 	usbd_interface_handle iface;
    909 	u_int8_t *aiface;
    910 {
    911 	usb_device_request_t req;
    912 
    913 	req.bmRequestType = UT_READ_INTERFACE;
    914 	req.bRequest = UR_GET_INTERFACE;
    915 	USETW(req.wValue, 0);
    916 	USETW(req.wIndex, iface->idesc->bInterfaceNumber);
    917 	USETW(req.wLength, 1);
    918 	return usbd_do_request(iface->device, &req, aiface);
    919 }
    920 
    921 /*** Internal routines ***/
    922 
    923 /* Dequeue all pipe operations, called at splusb(). */
    924 static usbd_status
    925 usbd_ar_pipe(pipe)
    926 	usbd_pipe_handle pipe;
    927 {
    928 	usbd_request_handle reqh;
    929 
    930 	for (;;) {
    931 		reqh = SIMPLEQ_FIRST(&pipe->queue);
    932 		if (reqh == 0)
    933 			break;
    934 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    935 		reqh->status = USBD_CANCELLED;
    936 		if (reqh->callback)
    937 			reqh->callback(reqh, reqh->priv, reqh->status);
    938 	}
    939 	return (USBD_NORMAL_COMPLETION);
    940 }
    941 
    942 /* Dequeue all interface operations, called at splusb(). */
    943 static usbd_status
    944 usbd_ar_iface(iface)
    945 	usbd_interface_handle iface;
    946 {
    947 	usbd_pipe_handle p;
    948 	usbd_status r, ret = USBD_NORMAL_COMPLETION;
    949 
    950 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
    951 		r = usbd_ar_pipe(p);
    952 		if (r != USBD_NORMAL_COMPLETION)
    953 			ret = r;
    954 	}
    955 	return (ret);
    956 }
    957 
    958 static int usbd_global_init_done = 0;
    959 
    960 void
    961 usbd_init()
    962 {
    963 #if defined(__FreeBSD__)
    964 	dev_t dev;
    965 #endif
    966 
    967 	if (!usbd_global_init_done) {
    968 		usbd_global_init_done = 1;
    969 		SIMPLEQ_INIT(&usbd_free_requests);
    970 
    971 #if defined(__FreeBSD__)
    972 		dev = makedev(USB_CDEV_MAJOR, 0);
    973 		cdevsw_add(&dev, &usb_cdevsw, NULL);
    974 #endif
    975 	}
    976 }
    977 
    978 static void
    979 usbd_transfer_cb(reqh)
    980 	usbd_request_handle reqh;
    981 {
    982 	usbd_pipe_handle pipe = reqh->pipe;
    983 
    984 	/* Count completed transfers. */
    985 	++pipe->device->bus->stats.requests
    986 		[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
    987 
    988 	/* XXX check retry count */
    989 	reqh->done = 1;
    990 	if (reqh->status == USBD_NORMAL_COMPLETION &&
    991 	    reqh->actlen < reqh->length &&
    992 	    !(reqh->flags & USBD_SHORT_XFER_OK)) {
    993 		DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d+1<%d+1 (bytes)\n",
    994 			      reqh->actlen, reqh->length));
    995 		reqh->status = USBD_SHORT_XFER;
    996 	}
    997 	if (reqh->callback)
    998 		reqh->callback(reqh, reqh->priv, reqh->status);
    999 }
   1000 
   1001 static void
   1002 usbd_sync_transfer_cb(reqh)
   1003 	usbd_request_handle reqh;
   1004 {
   1005 	usbd_transfer_cb(reqh);
   1006 	if (!reqh->pipe->device->bus->use_polling)
   1007 		wakeup(reqh);
   1008 }
   1009 
   1010 /* Like usbd_transfer(), but waits for completion. */
   1011 usbd_status
   1012 usbd_sync_transfer(reqh)
   1013 	usbd_request_handle reqh;
   1014 {
   1015 	usbd_status r;
   1016 	int s;
   1017 
   1018 	reqh->xfercb = usbd_sync_transfer_cb;
   1019 	r = usbd_do_transfer(reqh);
   1020 	if (r != USBD_IN_PROGRESS)
   1021 		return (r);
   1022 	s = splusb();
   1023 	if (!reqh->done) {
   1024 		if (reqh->pipe->device->bus->use_polling)
   1025 			panic("usbd_sync_transfer: not done\n");
   1026 		tsleep(reqh, PRIBIO, "usbsyn", 0);
   1027 	}
   1028 	splx(s);
   1029 	return (reqh->status);
   1030 }
   1031 
   1032 usbd_status
   1033 usbd_do_request(dev, req, data)
   1034 	usbd_device_handle dev;
   1035 	usb_device_request_t *req;
   1036 	void *data;
   1037 {
   1038 	usbd_request_handle reqh;
   1039 	usbd_status r;
   1040 
   1041 #ifdef DIAGNOSTIC
   1042 	if (!curproc) {
   1043 		printf("usbd_do_request: not in process context\n");
   1044 		return (USBD_XXX);
   1045 	}
   1046 #endif
   1047 
   1048 	reqh = usbd_alloc_request();
   1049 	if (reqh == 0)
   1050 		return (USBD_NOMEM);
   1051 	r = usbd_setup_default_request(
   1052 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
   1053 		UGETW(req->wLength), 0, 0);
   1054 	if (r != USBD_NORMAL_COMPLETION)
   1055 		goto bad;
   1056 	r = usbd_sync_transfer(reqh);
   1057 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
   1058 	if (reqh->actlen > reqh->length)
   1059 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
   1060 		       "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
   1061 		       dev->address, reqh->request.bmRequestType,
   1062 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
   1063 		       UGETW(reqh->request.wIndex),
   1064 		       UGETW(reqh->request.wLength),
   1065 		       reqh->length, reqh->actlen);
   1066 #endif
   1067 	if (r == USBD_STALLED) {
   1068 		/*
   1069 		 * The control endpoint has stalled.  Control endpoints
   1070 		 * should not halt, but some may do so anyway so clear
   1071 		 * any halt condition.
   1072 		 */
   1073 		usb_device_request_t treq;
   1074 		usb_status_t status;
   1075 		u_int16_t s;
   1076 		usbd_status nr;
   1077 
   1078 		treq.bmRequestType = UT_READ_ENDPOINT;
   1079 		treq.bRequest = UR_GET_STATUS;
   1080 		USETW(treq.wValue, 0);
   1081 		USETW(treq.wIndex, 0);
   1082 		USETW(treq.wLength, sizeof(usb_status_t));
   1083 		nr = usbd_setup_default_request(
   1084 			reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
   1085 			sizeof(usb_status_t), 0, 0);
   1086 		if (nr != USBD_NORMAL_COMPLETION)
   1087 			goto bad;
   1088 		nr = usbd_sync_transfer(reqh);
   1089 		if (nr != USBD_NORMAL_COMPLETION)
   1090 			goto bad;
   1091 		s = UGETW(status.wStatus);
   1092 		DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
   1093 		if (!(s & UES_HALT))
   1094 			goto bad;
   1095 		treq.bmRequestType = UT_WRITE_ENDPOINT;
   1096 		treq.bRequest = UR_CLEAR_FEATURE;
   1097 		USETW(treq.wValue, UF_ENDPOINT_HALT);
   1098 		USETW(treq.wIndex, 0);
   1099 		USETW(treq.wLength, 0);
   1100 		nr = usbd_setup_default_request(
   1101 			reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
   1102 			0, 0, 0);
   1103 		if (nr != USBD_NORMAL_COMPLETION)
   1104 			goto bad;
   1105 		nr = usbd_sync_transfer(reqh);
   1106 		if (nr != USBD_NORMAL_COMPLETION)
   1107 			goto bad;
   1108 	}
   1109 
   1110  bad:
   1111 	usbd_free_request(reqh);
   1112 	return (r);
   1113 }
   1114 
   1115 void
   1116 usbd_do_request_async_cb(reqh, priv, status)
   1117 	usbd_request_handle reqh;
   1118 	usbd_private_handle priv;
   1119 	usbd_status status;
   1120 {
   1121 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
   1122 	if (reqh->actlen > reqh->length)
   1123 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
   1124 		       "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
   1125 		       reqh->pipe->device->address,
   1126 		       reqh->request.bmRequestType,
   1127 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
   1128 		       UGETW(reqh->request.wIndex),
   1129 		       UGETW(reqh->request.wLength),
   1130 		       reqh->length, reqh->actlen);
   1131 #endif
   1132 	usbd_free_request(reqh);
   1133 }
   1134 
   1135 /*
   1136  * Execute a request without waiting for completion.
   1137  * Can be used from interrupt context.
   1138  */
   1139 usbd_status
   1140 usbd_do_request_async(dev, req, data)
   1141 	usbd_device_handle dev;
   1142 	usb_device_request_t *req;
   1143 	void *data;
   1144 {
   1145 	usbd_request_handle reqh;
   1146 	usbd_status r;
   1147 
   1148 	reqh = usbd_alloc_request();
   1149 	if (reqh == 0)
   1150 		return (USBD_NOMEM);
   1151 	r = usbd_setup_default_request(
   1152 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
   1153 		UGETW(req->wLength), 0, usbd_do_request_async_cb);
   1154 	if (r != USBD_NORMAL_COMPLETION) {
   1155 		usbd_free_request(reqh);
   1156 		return (r);
   1157 	}
   1158 	r = usbd_transfer(reqh);
   1159 	if (r != USBD_IN_PROGRESS)
   1160 		return (r);
   1161 	return (USBD_NORMAL_COMPLETION);
   1162 }
   1163 
   1164 struct usbd_quirks *
   1165 usbd_get_quirks(dev)
   1166 	usbd_device_handle dev;
   1167 {
   1168 	return (dev->quirks);
   1169 }
   1170 
   1171 void
   1172 usbd_set_disco(p, hdl, data)
   1173 	usbd_pipe_handle p;
   1174 	void (*hdl) __P((void *));
   1175 	void *data;
   1176 {
   1177 	p->disco = hdl;
   1178 	p->discoarg = data;
   1179 }
   1180 
   1181 /* XXX do periodic free() of free list */
   1182 
   1183 /*
   1184  * Called from keyboard driver when in polling mode.
   1185  */
   1186 void
   1187 usbd_dopoll(iface)
   1188 	usbd_interface_handle iface;
   1189 {
   1190 	iface->device->bus->do_poll(iface->device->bus);
   1191 }
   1192 
   1193 void
   1194 usbd_set_polling(iface, on)
   1195 	usbd_interface_handle iface;
   1196 	int on;
   1197 {
   1198 	iface->device->bus->use_polling = on;
   1199 }
   1200 
   1201 
   1202 usb_endpoint_descriptor_t *
   1203 usbd_get_endpoint_descriptor(iface, address)
   1204 	usbd_interface_handle iface;
   1205 	u_int8_t address;
   1206 {
   1207 	struct usbd_endpoint *ep;
   1208 	int i;
   1209 
   1210 	for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
   1211 		ep = &iface->endpoints[i];
   1212 		if (ep->edesc->bEndpointAddress == address)
   1213 			return (iface->endpoints[i].edesc);
   1214 	}
   1215 	return (0);
   1216 }
   1217 
   1218