Home | History | Annotate | Line # | Download | only in usb
usbdi.c revision 1.8
      1 /*	$NetBSD: usbdi.c,v 1.8 1998/08/01 18:16:20 augustss Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Author: Lennart Augustsson <augustss (at) carlstedt.se>
      8  *         Carlstedt Research & Technology
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include "opt_usbverbose.h"
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 #include <sys/kernel.h>
     44 #include <sys/malloc.h>
     45 #include <sys/proc.h>
     46 #include <sys/device.h>
     47 
     48 #include <dev/usb/usb.h>
     49 
     50 #include <dev/usb/usbdi.h>
     51 #include <dev/usb/usbdi_util.h>
     52 #include <dev/usb/usbdivar.h>
     53 
     54 #ifdef USB_DEBUG
     55 #define DPRINTF(x)	if (usbdebug) printf x
     56 #define DPRINTFN(n,x)	if (usbdebug>(n)) printf x
     57 extern int usbdebug;
     58 #else
     59 #define DPRINTF(x)
     60 #define DPRINTFN(n,x)
     61 #endif
     62 
     63 static usbd_status usbd_ar_pipe  __P((usbd_pipe_handle pipe));
     64 static usbd_status usbd_ar_iface __P((usbd_interface_handle iface));
     65 static void usbd_transfer_cb __P((usbd_request_handle reqh));
     66 static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
     67 static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
     68 static usbd_status usbd_start __P((usbd_pipe_handle pipe));
     69 void usbd_do_request_async_cb
     70 	__P((usbd_request_handle, usbd_private_handle, usbd_status));
     71 
     72 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
     73 
     74 usbd_status
     75 usbd_open_pipe(iface, address, flags, pipe)
     76 	usbd_interface_handle iface;
     77 	u_int8_t address;
     78 	u_int8_t flags;
     79 	usbd_pipe_handle *pipe;
     80 {
     81 	usbd_pipe_handle p;
     82 	struct usbd_endpoint *ep;
     83 	int i, r;
     84 
     85 	if (iface->state != USBD_INTERFACE_ACTIVE)
     86 		return (USBD_INTERFACE_NOT_ACTIVE);
     87 	for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
     88 		ep = &iface->endpoints[i];
     89 		if (ep->edesc->bEndpointAddress == address)
     90 			goto found;
     91 	}
     92 	return (USBD_BAD_ADDRESS);
     93  found:
     94 	if ((flags & USBD_EXCLUSIVE_USE) &&
     95 	    ep->refcnt != 0)
     96 		return (USBD_IN_USE);
     97 	r = usbd_setup_pipe(iface->device, iface, ep, &p);
     98 	if (r != USBD_NORMAL_COMPLETION)
     99 		return (r);
    100 	LIST_INSERT_HEAD(&iface->pipes, p, next);
    101 	*pipe = p;
    102 	return (USBD_NORMAL_COMPLETION);
    103 }
    104 
    105 usbd_status
    106 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
    107 	usbd_interface_handle iface;
    108 	u_int8_t address;
    109 	u_int8_t flags;
    110 	usbd_pipe_handle *pipe;
    111 	usbd_private_handle priv;
    112 	void *buffer;
    113 	u_int32_t length;
    114 	usbd_callback cb;
    115 {
    116 	usbd_status r;
    117 	usbd_request_handle reqh;
    118 	usbd_pipe_handle ipipe;
    119 
    120 	reqh = usbd_alloc_request();
    121 	if (reqh == 0)
    122 		return (USBD_NOMEM);
    123 	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
    124 	if (r != USBD_NORMAL_COMPLETION)
    125 		goto bad1;
    126 	r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
    127 			       USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
    128 	if (r != USBD_NORMAL_COMPLETION)
    129 		goto bad2;
    130 	ipipe->intrreqh = reqh;
    131 	r = usbd_transfer(reqh);
    132 	*pipe = ipipe;
    133 	if (r != USBD_IN_PROGRESS)
    134 		goto bad3;
    135 	return (USBD_NORMAL_COMPLETION);
    136 
    137  bad3:
    138 	ipipe->intrreqh = 0;
    139  bad2:
    140 	usbd_close_pipe(ipipe);
    141  bad1:
    142 	usbd_free_request(reqh);
    143 	return r;
    144 }
    145 
    146 usbd_status
    147 usbd_close_pipe(pipe)
    148 	usbd_pipe_handle pipe;
    149 {
    150 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    151 		return (USBD_INTERFACE_NOT_ACTIVE);
    152 	if (--pipe->refcnt != 0)
    153 		return (USBD_NORMAL_COMPLETION);
    154 	if (SIMPLEQ_FIRST(&pipe->queue) != 0)
    155 		return (USBD_PENDING_REQUESTS);
    156 	LIST_REMOVE(pipe, next);
    157 	pipe->endpoint->refcnt--;
    158 	pipe->methods->close(pipe);
    159 	if (pipe->intrreqh)
    160 		usbd_free_request(pipe->intrreqh);
    161 	free(pipe, M_USB);
    162 	return (USBD_NORMAL_COMPLETION);
    163 }
    164 
    165 usbd_status
    166 usbd_transfer(reqh)
    167 	usbd_request_handle reqh;
    168 {
    169 	reqh->xfercb = usbd_transfer_cb;
    170 	return (usbd_do_transfer(reqh));
    171 }
    172 
    173 static usbd_status
    174 usbd_do_transfer(reqh)
    175 	usbd_request_handle reqh;
    176 {
    177 	usbd_pipe_handle pipe = reqh->pipe;
    178 	usbd_interface_handle iface = pipe->iface;
    179 	usbd_status r;
    180 	int s;
    181 
    182 	DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
    183 	reqh->done = 0;
    184 	s = splusb();
    185 	if (pipe->state == USBD_PIPE_IDLE ||
    186 	    (iface && iface->state == USBD_INTERFACE_IDLE)) {
    187 		splx(s);
    188 		return (USBD_IS_IDLE);
    189 	}
    190 	SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);
    191 	if (pipe->state == USBD_PIPE_ACTIVE &&
    192 	    (!iface || iface->state == USBD_INTERFACE_ACTIVE)) {
    193 		r = usbd_start(pipe);
    194 	} else
    195 		r = USBD_NOT_STARTED;
    196 	splx(s);
    197 	return (r);
    198 }
    199 
    200 static usbd_status
    201 usbd_start(pipe)
    202 	usbd_pipe_handle pipe;
    203 {
    204 	usbd_request_handle reqh;
    205 
    206 	DPRINTFN(1, ("usbd_start: pipe=%p, running=%d\n",
    207 		     pipe, pipe->running));
    208 	if (pipe->running)
    209 		return (USBD_IN_PROGRESS);
    210 	reqh = SIMPLEQ_FIRST(&pipe->queue);
    211 	if (!reqh) {
    212 		/* XXX */
    213 		printf("usbd_start: pipe empty!\n");
    214 		pipe->running = 0;
    215 		return (USBD_XXX);
    216 	}
    217 	SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    218 	pipe->running = 1;
    219 	pipe->curreqh = reqh;
    220 	return (pipe->methods->transfer(reqh));
    221 }
    222 
    223 
    224 usbd_request_handle
    225 usbd_alloc_request()
    226 {
    227 	usbd_request_handle reqh;
    228 
    229 	reqh = SIMPLEQ_FIRST(&usbd_free_requests);
    230 	if (reqh)
    231 		SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
    232 	else
    233 		reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
    234 	if (!reqh)
    235 		return (0);
    236 	memset(reqh, 0, sizeof *reqh);
    237 	return (reqh);
    238 }
    239 
    240 usbd_status
    241 usbd_free_request(reqh)
    242 	usbd_request_handle reqh;
    243 {
    244 	SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
    245 	return (USBD_NORMAL_COMPLETION);
    246 }
    247 
    248 usbd_status
    249 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
    250 	usbd_request_handle reqh;
    251 	usbd_pipe_handle pipe;
    252 	usbd_private_handle priv;
    253 	void *buffer;
    254 	u_int32_t length;
    255 	u_int16_t flags;
    256 	u_int32_t timeout;
    257 	void (*callback) __P((usbd_request_handle,
    258 			      usbd_private_handle,
    259 			      usbd_status));
    260 {
    261 	reqh->pipe = pipe;
    262 	reqh->isreq = 0;
    263 	reqh->priv = priv;
    264 	reqh->buffer = buffer;
    265 	reqh->length = length;
    266 	reqh->actlen = 0;
    267 	reqh->flags = flags;
    268 	reqh->callback = callback;
    269 	reqh->status = USBD_NOT_STARTED;
    270 	reqh->retries = 1;
    271 	return (USBD_NORMAL_COMPLETION);
    272 }
    273 
    274 usbd_status
    275 usbd_setup_device_request(reqh, req)
    276 	usbd_request_handle reqh;
    277 	usb_device_request_t *req;
    278 {
    279 	reqh->isreq = 1;
    280 	reqh->request = *req;
    281 	return (USBD_NORMAL_COMPLETION);
    282 }
    283 
    284 usbd_status
    285 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
    286 			   length, flags, callback)
    287 	usbd_request_handle reqh;
    288 	usbd_device_handle dev;
    289 	usbd_private_handle priv;
    290 	u_int32_t timeout;
    291 	usb_device_request_t *req;
    292 	void *buffer;
    293 	u_int32_t length;
    294 	u_int16_t flags;
    295 	void (*callback) __P((usbd_request_handle,
    296 			      usbd_private_handle,
    297 			      usbd_status));
    298 {
    299 	reqh->pipe = dev->default_pipe;
    300 	reqh->priv = priv;
    301 	reqh->buffer = buffer;
    302 	reqh->length = length;
    303 	reqh->actlen = 0;
    304 	reqh->flags = flags;
    305 	reqh->timeout = timeout;
    306 	reqh->status = USBD_NOT_STARTED;
    307 	reqh->callback = callback;
    308 	reqh->request = *req;
    309 	reqh->isreq = 1;
    310 	reqh->retries = 1;
    311 	return (USBD_NORMAL_COMPLETION);
    312 }
    313 
    314 usbd_status
    315 usbd_set_request_timeout(reqh, timeout)
    316 	usbd_request_handle reqh;
    317 	u_int32_t timeout;
    318 {
    319 	reqh->timeout = timeout;
    320 	return (USBD_NORMAL_COMPLETION);
    321 }
    322 
    323 usbd_status
    324 usbd_get_request_status(reqh, priv, buffer, count, status)
    325 	usbd_request_handle reqh;
    326 	usbd_private_handle *priv;
    327 	void **buffer;
    328 	u_int32_t *count;
    329 	usbd_status *status;
    330 {
    331 	*priv = reqh->priv;
    332 	*buffer = reqh->buffer;
    333 	*count = reqh->actlen;
    334 	*status = reqh->status;
    335 	return (USBD_NORMAL_COMPLETION);
    336 }
    337 
    338 usbd_status
    339 usbd_request_device_data(reqh, req)
    340 	usbd_request_handle reqh;
    341 	usb_device_request_t *req;
    342 {
    343 	if (!reqh->isreq)
    344 		return (USBD_INVAL);
    345 	*req = reqh->request;
    346 	return (USBD_NORMAL_COMPLETION);
    347 }
    348 
    349 #if 0
    350 usb_descriptor_t *
    351 usbd_get_descriptor(iface, desc_type)
    352 	usbd_interface_handle *iface;
    353 	u_int8_t desc_type;
    354 XX
    355 #endif
    356 
    357 usb_config_descriptor_t *
    358 usbd_get_config_descriptor(dev)
    359 	usbd_device_handle dev;
    360 {
    361 	return (dev->cdesc);
    362 }
    363 
    364 usb_interface_descriptor_t *
    365 usbd_get_interface_descriptor(iface)
    366 	usbd_interface_handle iface;
    367 {
    368 	return (iface->idesc);
    369 }
    370 
    371 usb_device_descriptor_t *
    372 usbd_get_device_descriptor(dev)
    373 	usbd_device_handle dev;
    374 {
    375 	return (&dev->ddesc);
    376 }
    377 
    378 usb_endpoint_descriptor_t *
    379 usbd_interface2endpoint_descriptor(iface, index)
    380 	usbd_interface_handle iface;
    381 	u_int8_t index;
    382 {
    383 	if (index >= iface->idesc->bNumEndpoints)
    384 		return 0;
    385 	return (iface->endpoints[index].edesc);
    386 }
    387 
    388 usbd_status usbd_set_configuration(dev, conf)
    389 	usbd_device_handle dev;
    390 	u_int16_t conf;
    391 {
    392 	return usbd_set_config_no(dev, conf);
    393 }
    394 
    395 usbd_status
    396 usbd_retry_request(reqh, retry_count)
    397 	usbd_request_handle reqh;
    398 	u_int32_t retry_count;
    399 {
    400 	usbd_status r;
    401 
    402 	r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
    403 	if (r != USBD_NORMAL_COMPLETION)
    404 		return (r);
    405 	reqh->retries = retry_count;
    406 	return (usbd_transfer(reqh));
    407 }
    408 
    409 usbd_status
    410 usbd_abort_pipe(pipe)
    411 	usbd_pipe_handle pipe;
    412 {
    413 	usbd_status r;
    414 	int s, st;
    415 
    416 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    417 		return (USBD_INTERFACE_NOT_ACTIVE);
    418 	s = splusb();
    419 	st = pipe->state;
    420 	r = usbd_ar_pipe(pipe);
    421 	pipe->state = st;
    422 	splx(s);
    423 	return (r);
    424 }
    425 
    426 usbd_status
    427 usbd_abort_interface(iface)
    428 	usbd_interface_handle iface;
    429 {
    430 	usbd_status r;
    431 	int s, st;
    432 
    433 	s = splusb();
    434 	st = iface->state;
    435 	r = usbd_ar_iface(iface);
    436 	iface->state = st;
    437 	splx(s);
    438 	return (r);
    439 }
    440 
    441 usbd_status
    442 usbd_reset_pipe(pipe)
    443 	usbd_pipe_handle pipe;
    444 {
    445 	usbd_status r;
    446 	int s;
    447 
    448 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    449 		return (USBD_INTERFACE_NOT_ACTIVE);
    450 	s = splusb();
    451 	r = usbd_ar_pipe(pipe);
    452 	/* XXX anything else */
    453 	pipe->state = USBD_PIPE_ACTIVE;
    454 	splx(s);
    455 	return (r);
    456 }
    457 
    458 usbd_status
    459 usbd_reset_interface(iface)
    460 	usbd_interface_handle iface;
    461 {
    462 	usbd_status r;
    463 	int s;
    464 
    465 	s = splusb();
    466 	r = usbd_ar_iface(iface);
    467 	/* XXX anything else */
    468 	iface->state = USBD_INTERFACE_ACTIVE;
    469 	splx(s);
    470 	return (r);
    471 }
    472 
    473 usbd_status
    474 usbd_clear_endpoint_stall(pipe)
    475 	usbd_pipe_handle pipe;
    476 {
    477 	usbd_device_handle dev = pipe->device;
    478 	usb_device_request_t req;
    479 	usbd_status r;
    480 
    481 	req.bmRequestType = UT_WRITE_ENDPOINT;
    482 	req.bRequest = UR_CLEAR_FEATURE;
    483 	USETW(req.wValue, UF_ENDPOINT_STALL);
    484 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
    485 	USETW(req.wLength, 0);
    486 	r = usbd_do_request(dev, &req, 0);
    487 #if 0
    488 XXX should we do this?
    489 	if (r == USBD_NORMAL_COMPLETION) {
    490 		pipe->state = USBD_PIPE_ACTIVE;
    491 		/* XXX activate pipe */
    492 	}
    493 #endif
    494 	return (r);
    495 }
    496 
    497 usbd_status
    498 usbd_clear_endpoint_stall_async(pipe)
    499 	usbd_pipe_handle pipe;
    500 {
    501 	usbd_device_handle dev = pipe->device;
    502 	usb_device_request_t req;
    503 	usbd_status r;
    504 
    505 	req.bmRequestType = UT_WRITE_ENDPOINT;
    506 	req.bRequest = UR_CLEAR_FEATURE;
    507 	USETW(req.wValue, UF_ENDPOINT_STALL);
    508 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
    509 	USETW(req.wLength, 0);
    510 	r = usbd_do_request_async(dev, &req, 0);
    511 	return (r);
    512 }
    513 
    514 usbd_status
    515 usbd_set_pipe_state(pipe, state)
    516 	usbd_pipe_handle pipe;
    517 	usbd_pipe_state state;
    518 {
    519 	int s;
    520 
    521 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    522 		return (USBD_INTERFACE_NOT_ACTIVE);
    523 	if (state != USBD_PIPE_ACTIVE &&
    524 	    state != USBD_PIPE_STALLED &&
    525 	    state != USBD_PIPE_IDLE)
    526 		return (USBD_INVAL);
    527 	pipe->state = state;
    528 	if (state == USBD_PIPE_ACTIVE) {
    529 		s = splusb();
    530 		usbd_start(pipe);
    531 		splx(s);
    532 	}
    533 	return (USBD_NORMAL_COMPLETION);
    534 }
    535 
    536 usbd_status
    537 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
    538 	usbd_pipe_handle pipe;
    539 	usbd_pipe_state *state;
    540 	u_int32_t *endpoint_state;
    541 	u_int32_t *request_count;
    542 {
    543 	int n;
    544 	usbd_request_handle r;
    545 
    546 	*state = pipe->state;
    547 	*endpoint_state = pipe->endpoint->state;
    548 	for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
    549 	     r != 0;
    550 	     r = SIMPLEQ_NEXT(r, next), n++)
    551 		;
    552 	*request_count = n;
    553 	return (USBD_NORMAL_COMPLETION);
    554 }
    555 
    556 usbd_status
    557 usbd_set_interface_state(iface, state)
    558 	usbd_interface_handle iface;
    559 	usbd_interface_state state;
    560 {
    561 	int ps;
    562 	usbd_pipe_handle p;
    563 
    564 	if (state == USBD_INTERFACE_ACTIVE)
    565 		ps = USBD_PIPE_ACTIVE;
    566 	else if (state == USBD_INTERFACE_STALLED)
    567 		ps = USBD_PIPE_STALLED;
    568 	else if (state == USBD_INTERFACE_IDLE)
    569 		ps = USBD_PIPE_IDLE;
    570 	else
    571 		return (USBD_INVAL);
    572 	iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
    573 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
    574 		usbd_set_pipe_state(p, ps);
    575 	iface->state = state;
    576 	return (USBD_NORMAL_COMPLETION);
    577 }
    578 
    579 usbd_status
    580 usbd_get_interface_state(iface, state)
    581 	usbd_interface_handle iface;
    582 	usbd_interface_state *state;
    583 {
    584 	*state = iface->state;
    585 	return (USBD_NORMAL_COMPLETION);
    586 }
    587 
    588 usbd_status
    589 usbd_get_device_state(dev, state)
    590 	usbd_device_handle dev;
    591 	usbd_device_state *state;
    592 {
    593 	*state = dev->state;
    594 	return (USBD_NORMAL_COMPLETION);
    595 }
    596 
    597 #if 0
    598 usbd_status
    599 usbd_set_device_state(dev, state)
    600 	usbd_device_handle dev;
    601 	usbd_device_state state;
    602 X
    603 #endif
    604 
    605 usbd_status
    606 usbd_device_address(dev, address)
    607 	usbd_device_handle dev;
    608 	u_int8_t *address;
    609 {
    610 	*address = dev->address;
    611 	return (USBD_NORMAL_COMPLETION);
    612 }
    613 
    614 usbd_status
    615 usbd_endpoint_address(pipe, address)
    616 	usbd_pipe_handle pipe;
    617 	u_int8_t *address;
    618 {
    619 	*address = pipe->endpoint->edesc->bEndpointAddress;
    620 	return (USBD_NORMAL_COMPLETION);
    621 }
    622 
    623 usbd_status
    624 usbd_endpoint_count(iface, count)
    625 	usbd_interface_handle iface;
    626 	u_int8_t *count;
    627 {
    628 	*count = iface->idesc->bNumEndpoints;
    629 	return (USBD_NORMAL_COMPLETION);
    630 }
    631 
    632 usbd_status
    633 usbd_interface_count(dev, count)
    634 	usbd_device_handle dev;
    635 	u_int8_t *count;
    636 {
    637 	if (!dev->cdesc)
    638 		return (USBD_NOT_CONFIGURED);
    639 	*count = dev->cdesc->bNumInterface;
    640 	return (USBD_NORMAL_COMPLETION);
    641 }
    642 
    643 u_int8_t
    644 usbd_bus_count()
    645 {
    646 	return (usb_bus_count());
    647 }
    648 
    649 usbd_status
    650 usbd_get_bus_handle(index, bus)
    651 	u_int8_t index;
    652 	usbd_bus_handle *bus;
    653 {
    654 	return (usb_get_bus_handle(index, bus));
    655 }
    656 
    657 usbd_status
    658 usbd_get_root_hub(bus, dev)
    659 	usbd_bus_handle bus;
    660 	usbd_device_handle *dev;
    661 {
    662 	*dev = bus->root_hub;
    663 	return (USBD_NORMAL_COMPLETION);
    664 }
    665 
    666 usbd_status
    667 usbd_port_count(dev, nports)
    668 	usbd_device_handle dev;
    669 	u_int8_t *nports;
    670 {
    671 	if (dev->hub == 0)
    672 		return (USBD_INVAL);
    673 	*nports = dev->hub->hubdesc.bNbrPorts;
    674 	return (USBD_NORMAL_COMPLETION);
    675 }
    676 
    677 usbd_status
    678 usbd_hub2device_handle(dev, port, devp)
    679 	usbd_device_handle dev;
    680 	u_int8_t port;
    681 	usbd_device_handle *devp;
    682 {
    683 	if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
    684 	    dev->hub->ports[port].device == 0)
    685 		return (USBD_INVAL);
    686 	*devp = dev->hub->ports[port].device;
    687 	return (USBD_NORMAL_COMPLETION);
    688 }
    689 
    690 usbd_status
    691 usbd_request2pipe_handle(reqh, pipe)
    692 	usbd_request_handle reqh;
    693 	usbd_pipe_handle *pipe;
    694 {
    695 	*pipe = reqh->pipe;
    696 	return (USBD_NORMAL_COMPLETION);
    697 }
    698 
    699 usbd_status
    700 usbd_pipe2interface_handle(pipe, iface)
    701 	usbd_pipe_handle pipe;
    702 	usbd_interface_handle *iface;
    703 {
    704 	*iface = pipe->iface;
    705 	return (USBD_NORMAL_COMPLETION);
    706 }
    707 
    708 usbd_status
    709 usbd_interface2device_handle(iface, dev)
    710 	usbd_interface_handle iface;
    711 	usbd_device_handle *dev;
    712 {
    713 	*dev = iface->device;
    714 	return (USBD_NORMAL_COMPLETION);
    715 }
    716 
    717 usbd_status
    718 usbd_device2bus_handle(dev, bus)
    719 	usbd_device_handle dev;
    720 	usbd_bus_handle *bus;
    721 {
    722 	*bus = dev->bus;
    723 	return (USBD_NORMAL_COMPLETION);
    724 }
    725 
    726 usbd_status
    727 usbd_device2interface_handle(dev, ifaceno, iface)
    728 	usbd_device_handle dev;
    729 	u_int8_t ifaceno;
    730 	usbd_interface_handle *iface;
    731 {
    732 	if (!dev->cdesc)
    733 		return (USBD_NOT_CONFIGURED);
    734 	if (ifaceno >= dev->cdesc->bNumInterface)
    735 		return (USBD_INVAL);
    736 	*iface = &dev->ifaces[ifaceno];
    737 	return (USBD_NORMAL_COMPLETION);
    738 }
    739 
    740 usbd_status
    741 usbd_set_interface_private_handle(iface, priv)
    742 	usbd_interface_handle iface;
    743 	usbd_private_handle priv;
    744 {
    745 	iface->priv = priv;
    746 	return (USBD_NORMAL_COMPLETION);
    747 }
    748 
    749 usbd_status
    750 usbd_get_interface_private_handle(iface, priv)
    751 	usbd_interface_handle iface;
    752 	usbd_private_handle *priv;
    753 {
    754 	*priv = iface->priv;
    755 	return (USBD_NORMAL_COMPLETION);
    756 }
    757 
    758 usbd_status
    759 usbd_reference_pipe(pipe)
    760 	usbd_pipe_handle pipe;
    761 {
    762 	pipe->refcnt++;
    763 	return (USBD_NORMAL_COMPLETION);
    764 }
    765 
    766 usbd_status
    767 usbd_dereference_pipe(pipe)
    768 	usbd_pipe_handle pipe;
    769 {
    770 	pipe->refcnt--;
    771 	return (USBD_NORMAL_COMPLETION);
    772 }
    773 
    774 usbd_lock_token
    775 usbd_lock()
    776 {
    777 	return (splusb());
    778 }
    779 
    780 void
    781 usbd_unlock(tok)
    782 	usbd_lock_token tok;
    783 {
    784 	splx(tok);
    785 }
    786 
    787 /* XXX need to check that the interface is idle */
    788 usbd_status
    789 usbd_set_interface(iface, aiface)
    790 	usbd_interface_handle iface;
    791 	int aiface;
    792 {
    793 	usb_device_request_t req;
    794 
    795 	req.bmRequestType = UT_WRITE_INTERFACE;
    796 	req.bRequest = UR_SET_INTERFACE;
    797 	USETW(req.wValue, aiface);
    798 	USETW(req.wIndex, iface->idesc->iInterface);
    799 	USETW(req.wLength, 0);
    800 	return usbd_do_request(iface->device, &req, 0);
    801 }
    802 
    803 /*** Internal routines ***/
    804 
    805 /* Dequeue all pipe operations, called at splusb(). */
    806 static usbd_status
    807 usbd_ar_pipe(pipe)
    808 	usbd_pipe_handle pipe;
    809 {
    810 	usbd_request_handle reqh;
    811 
    812 	if (pipe->curreqh != 0)
    813 		pipe->methods->abort(pipe->curreqh);
    814 
    815 	for (;;) {
    816 		reqh = SIMPLEQ_FIRST(&pipe->queue);
    817 		if (reqh == 0)
    818 			break;
    819 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    820 		reqh->status = USBD_CANCELLED;
    821 		if (reqh->callback)
    822 			reqh->callback(reqh, reqh->priv, reqh->status);
    823 	}
    824 	return (USBD_NORMAL_COMPLETION);
    825 }
    826 
    827 /* Dequeue all interface operations, called at splusb(). */
    828 static usbd_status
    829 usbd_ar_iface(iface)
    830 	usbd_interface_handle iface;
    831 {
    832 	usbd_pipe_handle p;
    833 	usbd_status r, ret = USBD_NORMAL_COMPLETION;
    834 
    835 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
    836 		r = usbd_ar_pipe(p);
    837 		if (r != USBD_NORMAL_COMPLETION)
    838 			ret = r;
    839 	}
    840 	return (ret);
    841 }
    842 
    843 static int usbd_global_init_done = 0;
    844 
    845 void
    846 usbd_init()
    847 {
    848 	if (!usbd_global_init_done) {
    849 		usbd_global_init_done = 1;
    850 		SIMPLEQ_INIT(&usbd_free_requests);
    851 	}
    852 }
    853 
    854 static void
    855 usbd_transfer_cb(reqh)
    856 	usbd_request_handle reqh;
    857 {
    858 	usbd_pipe_handle pipe = reqh->pipe;
    859 	usbd_request_handle nreqh;
    860 	usbd_status r;
    861 
    862 	/* Count completed transfers. */
    863 	++pipe->device->bus->stats.requests
    864 		[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
    865 
    866 	/* XXX check retry count */
    867 	reqh->done = 1;
    868 	if (reqh->status == USBD_NORMAL_COMPLETION &&
    869 	    reqh->actlen < reqh->length &&
    870 	    !(reqh->flags & USBD_SHORT_XFER_OK)) {
    871 		DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d < %d\n",
    872 			      reqh->actlen, reqh->length));
    873 		reqh->status = USBD_SHORT_XFER;
    874 	}
    875 	pipe->curreqh = 0;
    876 	if (reqh->callback)
    877 		reqh->callback(reqh, reqh->priv, reqh->status);
    878 
    879 	if (pipe->state != USBD_PIPE_ACTIVE) {
    880 		pipe->running = 0;
    881 		return;
    882 	}
    883 	nreqh = SIMPLEQ_FIRST(&pipe->queue);
    884 	DPRINTFN(5, ("usbd_transfer_cb: nreqh=%p\n", nreqh));
    885 	if (!nreqh)
    886 		pipe->running = 0;
    887 	else {
    888 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, nreqh, next);
    889 		pipe->curreqh = reqh;
    890 		r = pipe->methods->transfer(nreqh);
    891 		if (r != USBD_IN_PROGRESS)
    892 			printf("usbd_transfer_cb: error=%d\n", r);
    893 	}
    894 }
    895 
    896 static void
    897 usbd_sync_transfer_cb(reqh)
    898 	usbd_request_handle reqh;
    899 {
    900 	usbd_transfer_cb(reqh);
    901 	if (!reqh->pipe->device->bus->use_polling)
    902 		wakeup(reqh);
    903 }
    904 
    905 /* Like usbd_transfer(), but waits for completion. */
    906 usbd_status
    907 usbd_sync_transfer(reqh)
    908 	usbd_request_handle reqh;
    909 {
    910 	usbd_status r;
    911 	int s;
    912 
    913 	reqh->xfercb = usbd_sync_transfer_cb;
    914 	r = usbd_do_transfer(reqh);
    915 	if (r != USBD_IN_PROGRESS)
    916 		return (r);
    917 	s = splusb();
    918 	if (!reqh->done) {
    919 		if (reqh->pipe->device->bus->use_polling)
    920 			panic("usbd_sync_transfer: not done\n");
    921 		tsleep(reqh, PRIBIO, "usbsyn", 0);
    922 	}
    923 	splx(s);
    924 	return (reqh->status);
    925 }
    926 
    927 usbd_status
    928 usbd_do_request(dev, req, data)
    929 	usbd_device_handle dev;
    930 	usb_device_request_t *req;
    931 	void *data;
    932 {
    933 	usbd_request_handle reqh;
    934 	usbd_status r;
    935 
    936 #ifdef DIAGNOSTIC
    937 	if (!curproc) {
    938 		printf("usbd_do_request: not in process context\n");
    939 		return (USBD_XXX);
    940 	}
    941 #endif
    942 
    943 	reqh = usbd_alloc_request();
    944 	if (reqh == 0)
    945 		return (USBD_NOMEM);
    946 	r = usbd_setup_default_request(
    947 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
    948 		UGETW(req->wLength), 0, 0);
    949 	if (r != USBD_NORMAL_COMPLETION) {
    950 		usbd_free_request(reqh);
    951 		return (r);
    952 	}
    953 	r = usbd_sync_transfer(reqh);
    954 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
    955 	if (reqh->actlen > reqh->length)
    956 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
    957 		       dev->address, reqh->request.bmRequestType,
    958 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
    959 		       UGETW(reqh->request.wIndex),
    960 		       UGETW(reqh->request.wLength),
    961 		       reqh->length, reqh->actlen);
    962 #endif
    963 	usbd_free_request(reqh);
    964 	return (r);
    965 }
    966 
    967 void
    968 usbd_do_request_async_cb(reqh, priv, status)
    969 	usbd_request_handle reqh;
    970 	usbd_private_handle priv;
    971 	usbd_status status;
    972 {
    973 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
    974 	if (reqh->actlen > reqh->length)
    975 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
    976 		       reqh->pipe->device->address,
    977 		       reqh->request.bmRequestType,
    978 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
    979 		       UGETW(reqh->request.wIndex),
    980 		       UGETW(reqh->request.wLength),
    981 		       reqh->length, reqh->actlen);
    982 #endif
    983 	usbd_free_request(reqh);
    984 }
    985 
    986 /*
    987  * Execute a request without waiting for completion.
    988  * Can be used from interrupt context.
    989  */
    990 usbd_status
    991 usbd_do_request_async(dev, req, data)
    992 	usbd_device_handle dev;
    993 	usb_device_request_t *req;
    994 	void *data;
    995 {
    996 	usbd_request_handle reqh;
    997 	usbd_status r;
    998 
    999 	reqh = usbd_alloc_request();
   1000 	if (reqh == 0)
   1001 		return (USBD_NOMEM);
   1002 	r = usbd_setup_default_request(
   1003 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
   1004 		UGETW(req->wLength), 0, usbd_do_request_async_cb);
   1005 	if (r != USBD_NORMAL_COMPLETION) {
   1006 		usbd_free_request(reqh);
   1007 		return (r);
   1008 	}
   1009 	r = usbd_transfer(reqh);
   1010 	if (r != USBD_IN_PROGRESS)
   1011 		return (r);
   1012 	return (USBD_NORMAL_COMPLETION);
   1013 }
   1014 
   1015 struct usbd_quirks *
   1016 usbd_get_quirks(dev)
   1017 	usbd_device_handle dev;
   1018 {
   1019 	return (dev->quirks);
   1020 }
   1021 
   1022 void
   1023 usbd_set_disco(p, hdl, data)
   1024 	usbd_pipe_handle p;
   1025 	void (*hdl) __P((void *));
   1026 	void *data;
   1027 {
   1028 	p->disco = hdl;
   1029 	p->discoarg = data;
   1030 }
   1031 
   1032 /* XXX do periodic free() of free list */
   1033 
   1034 /*
   1035  * Called from keyboard driver when in polling mode.
   1036  */
   1037 void
   1038 usbd_dopoll(iface)
   1039 	usbd_interface_handle iface;
   1040 {
   1041 	iface->device->bus->do_poll(iface->device->bus);
   1042 }
   1043 
   1044 void
   1045 usbd_set_polling(iface, on)
   1046 	usbd_interface_handle iface;
   1047 	int on;
   1048 {
   1049 	iface->device->bus->use_polling = on;
   1050 }
   1051