Home | History | Annotate | Line # | Download | only in usb
usbdi.c revision 1.5
      1 /*	$NetBSD: usbdi.c,v 1.5 1998/07/25 15:22:11 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 
     70 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
     71 
     72 usbd_status
     73 usbd_open_pipe(iface, address, flags, pipe)
     74 	usbd_interface_handle iface;
     75 	u_int8_t address;
     76 	u_int8_t flags;
     77 	usbd_pipe_handle *pipe;
     78 {
     79 	usbd_pipe_handle p;
     80 	struct usbd_endpoint *ep;
     81 	int i, r;
     82 
     83 	if (iface->state != USBD_INTERFACE_ACTIVE)
     84 		return (USBD_INTERFACE_NOT_ACTIVE);
     85 	for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
     86 		ep = &iface->endpoints[i];
     87 		if (ep->edesc->bEndpointAddress == address)
     88 			goto found;
     89 	}
     90 	return (USBD_BAD_ADDRESS);
     91  found:
     92 	if ((flags & USBD_EXCLUSIVE_USE) &&
     93 	    ep->refcnt != 0)
     94 		return (USBD_IN_USE);
     95 	r = usbd_setup_pipe(iface->device, iface, ep, &p);
     96 	if (r != USBD_NORMAL_COMPLETION)
     97 		return (r);
     98 	LIST_INSERT_HEAD(&iface->pipes, p, next);
     99 	*pipe = p;
    100 	return (USBD_NORMAL_COMPLETION);
    101 }
    102 
    103 usbd_status
    104 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
    105 	usbd_interface_handle iface;
    106 	u_int8_t address;
    107 	u_int8_t flags;
    108 	usbd_pipe_handle *pipe;
    109 	usbd_private_handle priv;
    110 	void *buffer;
    111 	u_int32_t length;
    112 	usbd_callback cb;
    113 {
    114 	usbd_status r;
    115 	usbd_request_handle reqh;
    116 	usbd_pipe_handle ipipe;
    117 
    118 	reqh = usbd_alloc_request();
    119 	if (reqh == 0)
    120 		return (USBD_NOMEM);
    121 	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
    122 	if (r != USBD_NORMAL_COMPLETION)
    123 		goto bad1;
    124 	r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
    125 			       USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
    126 	if (r != USBD_NORMAL_COMPLETION)
    127 		goto bad2;
    128 	ipipe->intrreqh = reqh;
    129 	r = usbd_transfer(reqh);
    130 	*pipe = ipipe;
    131 	if (r != USBD_IN_PROGRESS)
    132 		goto bad3;
    133 	return (USBD_NORMAL_COMPLETION);
    134 
    135  bad3:
    136 	ipipe->intrreqh = 0;
    137  bad2:
    138 	usbd_close_pipe(ipipe);
    139  bad1:
    140 	usbd_free_request(reqh);
    141 	return r;
    142 }
    143 
    144 usbd_status
    145 usbd_close_pipe(pipe)
    146 	usbd_pipe_handle pipe;
    147 {
    148 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    149 		return (USBD_INTERFACE_NOT_ACTIVE);
    150 	if (--pipe->refcnt != 0)
    151 		return (USBD_NORMAL_COMPLETION);
    152 	if (SIMPLEQ_FIRST(&pipe->queue) != 0)
    153 		return (USBD_PENDING_REQUESTS);
    154 	LIST_REMOVE(pipe, next);
    155 	pipe->endpoint->refcnt--;
    156 	pipe->methods->close(pipe);
    157 	if (pipe->intrreqh)
    158 		usbd_free_request(pipe->intrreqh);
    159 	free(pipe, M_USB);
    160 	return (USBD_NORMAL_COMPLETION);
    161 }
    162 
    163 usbd_status
    164 usbd_transfer(reqh)
    165 	usbd_request_handle reqh;
    166 {
    167 	reqh->xfercb = usbd_transfer_cb;
    168 	return (usbd_do_transfer(reqh));
    169 }
    170 
    171 static usbd_status
    172 usbd_do_transfer(reqh)
    173 	usbd_request_handle reqh;
    174 {
    175 	usbd_pipe_handle pipe = reqh->pipe;
    176 	usbd_interface_handle iface = pipe->iface;
    177 	usbd_status r;
    178 	int s;
    179 
    180 	DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
    181 	reqh->done = 0;
    182 	s = splusb();
    183 	if (pipe->state == USBD_PIPE_IDLE ||
    184 	    (iface && iface->state == USBD_INTERFACE_IDLE)) {
    185 		splx(s);
    186 		return (USBD_IS_IDLE);
    187 	}
    188 	SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);
    189 	if (pipe->state == USBD_PIPE_ACTIVE &&
    190 	    (!iface || iface->state == USBD_INTERFACE_ACTIVE)) {
    191 		r = usbd_start(pipe);
    192 	} else
    193 		r = USBD_NOT_STARTED;
    194 	splx(s);
    195 	return (r);
    196 }
    197 
    198 static usbd_status
    199 usbd_start(pipe)
    200 	usbd_pipe_handle pipe;
    201 {
    202 	usbd_request_handle reqh;
    203 
    204 	DPRINTFN(1, ("usbd_start: pipe=%p, running=%d\n",
    205 		     pipe, pipe->running));
    206 	if (pipe->running)
    207 		return (USBD_IN_PROGRESS);
    208 	reqh = SIMPLEQ_FIRST(&pipe->queue);
    209 	if (!reqh) {
    210 		/* XXX */
    211 		printf("usbd_start: pipe empty!\n");
    212 		pipe->running = 0;
    213 		return (USBD_XXX);
    214 	}
    215 	SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    216 	pipe->running = 1;
    217 	pipe->curreqh = reqh;
    218 	return (pipe->methods->transfer(reqh));
    219 }
    220 
    221 
    222 usbd_request_handle
    223 usbd_alloc_request()
    224 {
    225 	usbd_request_handle reqh;
    226 
    227 	reqh = SIMPLEQ_FIRST(&usbd_free_requests);
    228 	if (reqh)
    229 		SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
    230 	else
    231 		reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
    232 	if (!reqh)
    233 		return (0);
    234 	memset(reqh, 0, sizeof *reqh);
    235 	return (reqh);
    236 }
    237 
    238 usbd_status
    239 usbd_free_request(reqh)
    240 	usbd_request_handle reqh;
    241 {
    242 	SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
    243 	return (USBD_NORMAL_COMPLETION);
    244 }
    245 
    246 usbd_status
    247 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
    248 	usbd_request_handle reqh;
    249 	usbd_pipe_handle pipe;
    250 	usbd_private_handle priv;
    251 	void *buffer;
    252 	u_int32_t length;
    253 	u_int16_t flags;
    254 	u_int32_t timeout;
    255 	void (*callback) __P((usbd_request_handle,
    256 			      usbd_private_handle,
    257 			      usbd_status));
    258 {
    259 	reqh->pipe = pipe;
    260 	reqh->isreq = 0;
    261 	reqh->priv = priv;
    262 	reqh->buffer = buffer;
    263 	reqh->length = length;
    264 	reqh->actlen = 0;
    265 	reqh->flags = flags;
    266 	reqh->callback = callback;
    267 	reqh->status = USBD_NOT_STARTED;
    268 	reqh->retries = 1;
    269 	return (USBD_NORMAL_COMPLETION);
    270 }
    271 
    272 usbd_status
    273 usbd_setup_device_request(reqh, req)
    274 	usbd_request_handle reqh;
    275 	usb_device_request_t *req;
    276 {
    277 	reqh->isreq = 1;
    278 	reqh->request = *req;
    279 	return (USBD_NORMAL_COMPLETION);
    280 }
    281 
    282 usbd_status
    283 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
    284 			   length, flags, callback)
    285 	usbd_request_handle reqh;
    286 	usbd_device_handle dev;
    287 	usbd_private_handle priv;
    288 	u_int32_t timeout;
    289 	usb_device_request_t *req;
    290 	void *buffer;
    291 	u_int32_t length;
    292 	u_int16_t flags;
    293 	void (*callback) __P((usbd_request_handle,
    294 			      usbd_private_handle,
    295 			      usbd_status));
    296 {
    297 	reqh->pipe = dev->default_pipe;
    298 	reqh->priv = priv;
    299 	reqh->buffer = buffer;
    300 	reqh->length = length;
    301 	reqh->actlen = 0;
    302 	reqh->flags = flags;
    303 	reqh->timeout = timeout;
    304 	reqh->status = USBD_NOT_STARTED;
    305 	reqh->callback = callback;
    306 	reqh->request = *req;
    307 	reqh->isreq = 1;
    308 	reqh->retries = 1;
    309 	return (USBD_NORMAL_COMPLETION);
    310 }
    311 
    312 usbd_status
    313 usbd_set_request_timeout(reqh, timeout)
    314 	usbd_request_handle reqh;
    315 	u_int32_t timeout;
    316 {
    317 	reqh->timeout = timeout;
    318 	return (USBD_NORMAL_COMPLETION);
    319 }
    320 
    321 usbd_status
    322 usbd_get_request_status(reqh, priv, buffer, count, status)
    323 	usbd_request_handle reqh;
    324 	usbd_private_handle *priv;
    325 	void **buffer;
    326 	u_int32_t *count;
    327 	usbd_status *status;
    328 {
    329 	*priv = reqh->priv;
    330 	*buffer = reqh->buffer;
    331 	*count = reqh->actlen;
    332 	*status = reqh->status;
    333 	return (USBD_NORMAL_COMPLETION);
    334 }
    335 
    336 usbd_status
    337 usbd_request_device_data(reqh, req)
    338 	usbd_request_handle reqh;
    339 	usb_device_request_t *req;
    340 {
    341 	if (!reqh->isreq)
    342 		return (USBD_INVAL);
    343 	*req = reqh->request;
    344 	return (USBD_NORMAL_COMPLETION);
    345 }
    346 
    347 #if 0
    348 usb_descriptor_t *
    349 usbd_get_descriptor(iface, desc_type)
    350 	usbd_interface_handle *iface;
    351 	u_int8_t desc_type;
    352 XX
    353 #endif
    354 
    355 usb_config_descriptor_t *
    356 usbd_get_config_descriptor(dev)
    357 	usbd_device_handle dev;
    358 {
    359 	return (dev->cdesc);
    360 }
    361 
    362 usb_interface_descriptor_t *
    363 usbd_get_interface_descriptor(iface)
    364 	usbd_interface_handle iface;
    365 {
    366 	return (iface->idesc);
    367 }
    368 
    369 usb_device_descriptor_t *
    370 usbd_get_device_descriptor(dev)
    371 	usbd_device_handle dev;
    372 {
    373 	return (&dev->ddesc);
    374 }
    375 
    376 usb_endpoint_descriptor_t *
    377 usbd_interface2endpoint_descriptor(iface, index)
    378 	usbd_interface_handle iface;
    379 	u_int8_t index;
    380 {
    381 	if (index >= iface->idesc->bNumEndpoints)
    382 		return 0;
    383 	return (iface->endpoints[index].edesc);
    384 }
    385 
    386 usbd_status usbd_set_configuration(dev, conf)
    387 	usbd_device_handle dev;
    388 	u_int16_t conf;
    389 {
    390 	return usbd_set_config_no(dev, conf);
    391 }
    392 
    393 usbd_status
    394 usbd_retry_request(reqh, retry_count)
    395 	usbd_request_handle reqh;
    396 	u_int32_t retry_count;
    397 {
    398 	usbd_status r;
    399 
    400 	r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
    401 	if (r != USBD_NORMAL_COMPLETION)
    402 		return (r);
    403 	reqh->retries = retry_count;
    404 	return (usbd_transfer(reqh));
    405 }
    406 
    407 usbd_status
    408 usbd_abort_pipe(pipe)
    409 	usbd_pipe_handle pipe;
    410 {
    411 	usbd_status r;
    412 	int s, st;
    413 
    414 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    415 		return (USBD_INTERFACE_NOT_ACTIVE);
    416 	s = splusb();
    417 	st = pipe->state;
    418 	r = usbd_ar_pipe(pipe);
    419 	pipe->state = st;
    420 	splx(s);
    421 	return (r);
    422 }
    423 
    424 usbd_status
    425 usbd_abort_interface(iface)
    426 	usbd_interface_handle iface;
    427 {
    428 	usbd_status r;
    429 	int s, st;
    430 
    431 	s = splusb();
    432 	st = iface->state;
    433 	r = usbd_ar_iface(iface);
    434 	iface->state = st;
    435 	splx(s);
    436 	return (r);
    437 }
    438 
    439 usbd_status
    440 usbd_reset_pipe(pipe)
    441 	usbd_pipe_handle pipe;
    442 {
    443 	usbd_status r;
    444 	int s;
    445 
    446 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    447 		return (USBD_INTERFACE_NOT_ACTIVE);
    448 	s = splusb();
    449 	r = usbd_ar_pipe(pipe);
    450 	/* XXX anything else */
    451 	pipe->state = USBD_PIPE_ACTIVE;
    452 	splx(s);
    453 	return (r);
    454 }
    455 
    456 usbd_status
    457 usbd_reset_interface(iface)
    458 	usbd_interface_handle iface;
    459 {
    460 	usbd_status r;
    461 	int s;
    462 
    463 	s = splusb();
    464 	r = usbd_ar_iface(iface);
    465 	/* XXX anything else */
    466 	iface->state = USBD_INTERFACE_ACTIVE;
    467 	splx(s);
    468 	return (r);
    469 }
    470 
    471 usbd_status
    472 usbd_clear_endpoint_stall(pipe)
    473 	usbd_pipe_handle pipe;
    474 {
    475 	usbd_device_handle dev = pipe->device;
    476 	usb_device_request_t req;
    477 	usbd_status r;
    478 
    479 	req.bmRequestType = UT_WRITE_ENDPOINT;
    480 	req.bRequest = UR_CLEAR_FEATURE;
    481 	USETW(req.wValue, UF_ENDPOINT_STALL);
    482 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); /* XXX mask/ */
    483 	USETW(req.wLength, 0);
    484 	r = usbd_do_request(dev, &req, 0);
    485 #if 0
    486 XXX should we do this?
    487 	if (r == USBD_NORMAL_COMPLETION) {
    488 		pipe->state = USBD_PIPE_ACTIVE;
    489 		/* XXX activate pipe */
    490 	}
    491 #endif
    492 	return (r);
    493 }
    494 
    495 usbd_status
    496 usbd_set_pipe_state(pipe, state)
    497 	usbd_pipe_handle pipe;
    498 	usbd_pipe_state state;
    499 {
    500 	int s;
    501 
    502 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    503 		return (USBD_INTERFACE_NOT_ACTIVE);
    504 	if (state != USBD_PIPE_ACTIVE &&
    505 	    state != USBD_PIPE_STALLED &&
    506 	    state != USBD_PIPE_IDLE)
    507 		return (USBD_INVAL);
    508 	pipe->state = state;
    509 	if (state == USBD_PIPE_ACTIVE) {
    510 		s = splusb();
    511 		usbd_start(pipe);
    512 		splx(s);
    513 	}
    514 	return (USBD_NORMAL_COMPLETION);
    515 }
    516 
    517 usbd_status
    518 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
    519 	usbd_pipe_handle pipe;
    520 	usbd_pipe_state *state;
    521 	u_int32_t *endpoint_state;
    522 	u_int32_t *request_count;
    523 {
    524 	int n;
    525 	usbd_request_handle r;
    526 
    527 	*state = pipe->state;
    528 	*endpoint_state = pipe->endpoint->state;
    529 	for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
    530 	     r != 0;
    531 	     r = SIMPLEQ_NEXT(r, next), n++)
    532 		;
    533 	*request_count = n;
    534 	return (USBD_NORMAL_COMPLETION);
    535 }
    536 
    537 usbd_status
    538 usbd_set_interface_state(iface, state)
    539 	usbd_interface_handle iface;
    540 	usbd_interface_state state;
    541 {
    542 	int ps;
    543 	usbd_pipe_handle p;
    544 
    545 	if (state == USBD_INTERFACE_ACTIVE)
    546 		ps = USBD_PIPE_ACTIVE;
    547 	else if (state == USBD_INTERFACE_STALLED)
    548 		ps = USBD_PIPE_STALLED;
    549 	else if (state == USBD_INTERFACE_IDLE)
    550 		ps = USBD_PIPE_IDLE;
    551 	else
    552 		return (USBD_INVAL);
    553 	iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
    554 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
    555 		usbd_set_pipe_state(p, ps);
    556 	iface->state = state;
    557 	return (USBD_NORMAL_COMPLETION);
    558 }
    559 
    560 usbd_status
    561 usbd_get_interface_state(iface, state)
    562 	usbd_interface_handle iface;
    563 	usbd_interface_state *state;
    564 {
    565 	*state = iface->state;
    566 	return (USBD_NORMAL_COMPLETION);
    567 }
    568 
    569 usbd_status
    570 usbd_get_device_state(dev, state)
    571 	usbd_device_handle dev;
    572 	usbd_device_state *state;
    573 {
    574 	*state = dev->state;
    575 	return (USBD_NORMAL_COMPLETION);
    576 }
    577 
    578 #if 0
    579 usbd_status
    580 usbd_set_device_state(dev, state)
    581 	usbd_device_handle dev;
    582 	usbd_device_state state;
    583 X
    584 #endif
    585 
    586 usbd_status
    587 usbd_device_address(dev, address)
    588 	usbd_device_handle dev;
    589 	u_int8_t *address;
    590 {
    591 	*address = dev->address;
    592 	return (USBD_NORMAL_COMPLETION);
    593 }
    594 
    595 usbd_status
    596 usbd_endpoint_address(pipe, address)
    597 	usbd_pipe_handle pipe;
    598 	u_int8_t *address;
    599 {
    600 	*address = pipe->endpoint->edesc->bEndpointAddress;
    601 	return (USBD_NORMAL_COMPLETION);
    602 }
    603 
    604 usbd_status
    605 usbd_endpoint_count(iface, count)
    606 	usbd_interface_handle iface;
    607 	u_int8_t *count;
    608 {
    609 	*count = iface->idesc->bNumEndpoints;
    610 	return (USBD_NORMAL_COMPLETION);
    611 }
    612 
    613 usbd_status
    614 usbd_interface_count(dev, count)
    615 	usbd_device_handle dev;
    616 	u_int8_t *count;
    617 {
    618 	if (!dev->cdesc)
    619 		return (USBD_NOT_CONFIGURED);
    620 	*count = dev->cdesc->bNumInterface;
    621 	return (USBD_NORMAL_COMPLETION);
    622 }
    623 
    624 u_int8_t
    625 usbd_bus_count()
    626 {
    627 	return (usb_bus_count());
    628 }
    629 
    630 usbd_status
    631 usbd_get_bus_handle(index, bus)
    632 	u_int8_t index;
    633 	usbd_bus_handle *bus;
    634 {
    635 	return (usb_get_bus_handle(index, bus));
    636 }
    637 
    638 usbd_status
    639 usbd_get_root_hub(bus, dev)
    640 	usbd_bus_handle bus;
    641 	usbd_device_handle *dev;
    642 {
    643 	*dev = bus->root_hub;
    644 	return (USBD_NORMAL_COMPLETION);
    645 }
    646 
    647 usbd_status
    648 usbd_port_count(dev, nports)
    649 	usbd_device_handle dev;
    650 	u_int8_t *nports;
    651 {
    652 	if (dev->hub == 0)
    653 		return (USBD_INVAL);
    654 	*nports = dev->hub->hubdesc.bNbrPorts;
    655 	return (USBD_NORMAL_COMPLETION);
    656 }
    657 
    658 usbd_status
    659 usbd_hub2device_handle(dev, port, devp)
    660 	usbd_device_handle dev;
    661 	u_int8_t port;
    662 	usbd_device_handle *devp;
    663 {
    664 	if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
    665 	    dev->hub->ports[port].device == 0)
    666 		return (USBD_INVAL);
    667 	*devp = dev->hub->ports[port].device;
    668 	return (USBD_NORMAL_COMPLETION);
    669 }
    670 
    671 usbd_status
    672 usbd_request2pipe_handle(reqh, pipe)
    673 	usbd_request_handle reqh;
    674 	usbd_pipe_handle *pipe;
    675 {
    676 	*pipe = reqh->pipe;
    677 	return (USBD_NORMAL_COMPLETION);
    678 }
    679 
    680 usbd_status
    681 usbd_pipe2interface_handle(pipe, iface)
    682 	usbd_pipe_handle pipe;
    683 	usbd_interface_handle *iface;
    684 {
    685 	*iface = pipe->iface;
    686 	return (USBD_NORMAL_COMPLETION);
    687 }
    688 
    689 usbd_status
    690 usbd_interface2device_handle(iface, dev)
    691 	usbd_interface_handle iface;
    692 	usbd_device_handle *dev;
    693 {
    694 	*dev = iface->device;
    695 	return (USBD_NORMAL_COMPLETION);
    696 }
    697 
    698 usbd_status
    699 usbd_device2bus_handle(dev, bus)
    700 	usbd_device_handle dev;
    701 	usbd_bus_handle *bus;
    702 {
    703 	*bus = dev->bus;
    704 	return (USBD_NORMAL_COMPLETION);
    705 }
    706 
    707 usbd_status
    708 usbd_device2interface_handle(dev, ifaceno, iface)
    709 	usbd_device_handle dev;
    710 	u_int8_t ifaceno;
    711 	usbd_interface_handle *iface;
    712 {
    713 	if (!dev->cdesc)
    714 		return (USBD_NOT_CONFIGURED);
    715 	if (ifaceno >= dev->cdesc->bNumInterface)
    716 		return (USBD_INVAL);
    717 	*iface = &dev->ifaces[ifaceno];
    718 	return (USBD_NORMAL_COMPLETION);
    719 }
    720 
    721 usbd_status
    722 usbd_set_interface_private_handle(iface, priv)
    723 	usbd_interface_handle iface;
    724 	usbd_private_handle priv;
    725 {
    726 	iface->priv = priv;
    727 	return (USBD_NORMAL_COMPLETION);
    728 }
    729 
    730 usbd_status
    731 usbd_get_interface_private_handle(iface, priv)
    732 	usbd_interface_handle iface;
    733 	usbd_private_handle *priv;
    734 {
    735 	*priv = iface->priv;
    736 	return (USBD_NORMAL_COMPLETION);
    737 }
    738 
    739 usbd_status
    740 usbd_reference_pipe(pipe)
    741 	usbd_pipe_handle pipe;
    742 {
    743 	pipe->refcnt++;
    744 	return (USBD_NORMAL_COMPLETION);
    745 }
    746 
    747 usbd_status
    748 usbd_dereference_pipe(pipe)
    749 	usbd_pipe_handle pipe;
    750 {
    751 	pipe->refcnt--;
    752 	return (USBD_NORMAL_COMPLETION);
    753 }
    754 
    755 usbd_lock_token
    756 usbd_lock()
    757 {
    758 	return (splusb());
    759 }
    760 
    761 void
    762 usbd_unlock(tok)
    763 	usbd_lock_token tok;
    764 {
    765 	splx(tok);
    766 }
    767 
    768 /* XXX need to check that the interface is idle */
    769 usbd_status
    770 usbd_set_interface(iface, aiface)
    771 	usbd_interface_handle iface;
    772 	int aiface;
    773 {
    774 	usb_device_request_t req;
    775 
    776 	req.bmRequestType = UT_WRITE_INTERFACE;
    777 	req.bRequest = UR_SET_INTERFACE;
    778 	USETW(req.wValue, aiface);
    779 	USETW(req.wIndex, iface->idesc->iInterface);
    780 	USETW(req.wLength, 0);
    781 	return usbd_do_request(iface->device, &req, 0);
    782 }
    783 
    784 /*** Internal routines ***/
    785 
    786 /* Dequeue all pipe operations, called at splusb(). */
    787 static usbd_status
    788 usbd_ar_pipe(pipe)
    789 	usbd_pipe_handle pipe;
    790 {
    791 	usbd_request_handle reqh;
    792 
    793 	if (pipe->curreqh != 0)
    794 		pipe->methods->abort(pipe->curreqh);
    795 
    796 	for (;;) {
    797 		reqh = SIMPLEQ_FIRST(&pipe->queue);
    798 		if (reqh == 0)
    799 			break;
    800 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    801 		reqh->status = USBD_CANCELLED;
    802 		if (reqh->callback)
    803 			reqh->callback(reqh, reqh->priv, reqh->status);
    804 	}
    805 	return (USBD_NORMAL_COMPLETION);
    806 }
    807 
    808 /* Dequeue all interface operations, called at splusb(). */
    809 static usbd_status
    810 usbd_ar_iface(iface)
    811 	usbd_interface_handle iface;
    812 {
    813 	usbd_pipe_handle p;
    814 	usbd_status r, ret = USBD_NORMAL_COMPLETION;
    815 
    816 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
    817 		r = usbd_ar_pipe(p);
    818 		if (r != USBD_NORMAL_COMPLETION)
    819 			ret = r;
    820 	}
    821 	return (ret);
    822 }
    823 
    824 static int usbd_global_init_done = 0;
    825 
    826 void
    827 usbd_init()
    828 {
    829 	if (!usbd_global_init_done) {
    830 		usbd_global_init_done = 1;
    831 		SIMPLEQ_INIT(&usbd_free_requests);
    832 	}
    833 }
    834 
    835 static void
    836 usbd_transfer_cb(reqh)
    837 	usbd_request_handle reqh;
    838 {
    839 	usbd_pipe_handle pipe = reqh->pipe;
    840 	usbd_request_handle nreqh;
    841 	usbd_status r;
    842 
    843 	/* Count completed transfers. */
    844 	++pipe->device->bus->stats.requests
    845 		[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
    846 
    847 	/* XXX check retry count */
    848 	reqh->done = 1;
    849 	if (reqh->status == USBD_NORMAL_COMPLETION &&
    850 	    reqh->actlen < reqh->length &&
    851 	    !(reqh->flags & USBD_SHORT_XFER_OK)) {
    852 		DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d < %d\n",
    853 			      reqh->actlen, reqh->length));
    854 		reqh->status = USBD_SHORT_XFER;
    855 	}
    856 	pipe->curreqh = 0;
    857 	if (reqh->callback)
    858 		reqh->callback(reqh, reqh->priv, reqh->status);
    859 
    860 	if (pipe->state != USBD_PIPE_ACTIVE) {
    861 		pipe->running = 0;
    862 		return;
    863 	}
    864 	nreqh = SIMPLEQ_FIRST(&pipe->queue);
    865 	DPRINTFN(5, ("usbd_transfer_cb: nreqh=%p\n", nreqh));
    866 	if (!nreqh)
    867 		pipe->running = 0;
    868 	else {
    869 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, nreqh, next);
    870 		pipe->curreqh = reqh;
    871 		r = pipe->methods->transfer(nreqh);
    872 		if (r != USBD_IN_PROGRESS)
    873 			printf("usbd_transfer_cb: error=%d\n", r);
    874 	}
    875 }
    876 
    877 static void
    878 usbd_sync_transfer_cb(reqh)
    879 	usbd_request_handle reqh;
    880 {
    881 	usbd_transfer_cb(reqh);
    882 	if (!usbd_use_polling)
    883 		wakeup(reqh);
    884 }
    885 
    886 /* Like usbd_transfer(), but waits for completion. */
    887 usbd_status
    888 usbd_sync_transfer(reqh)
    889 	usbd_request_handle reqh;
    890 {
    891 	usbd_status r;
    892 	int s;
    893 
    894 	reqh->xfercb = usbd_sync_transfer_cb;
    895 	r = usbd_do_transfer(reqh);
    896 	if (r != USBD_IN_PROGRESS)
    897 		return (r);
    898 	s = splusb();
    899 	if (!reqh->done) {
    900 		if (usbd_use_polling)
    901 			panic("usbd_sync_transfer: not done\n");
    902 		tsleep(reqh, PRIBIO, "usbsyn", 0);
    903 	}
    904 	splx(s);
    905 	return (reqh->status);
    906 }
    907 
    908 usbd_status
    909 usbd_do_request(dev, req, data)
    910 	usbd_device_handle dev;
    911 	usb_device_request_t *req;
    912 	void *data;
    913 {
    914 	usbd_request_handle reqh;
    915 	usbd_status r;
    916 
    917 	reqh = usbd_alloc_request();
    918 	if (reqh == 0)
    919 		return (USBD_NOMEM);
    920 	r = usbd_setup_default_request(
    921 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
    922 		UGETW(req->wLength), 0, 0);
    923 	if (r != USBD_NORMAL_COMPLETION) {
    924 		usbd_free_request(reqh);
    925 		return (r);
    926 	}
    927 	r = usbd_sync_transfer(reqh);
    928 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
    929 	if (reqh->actlen > reqh->length)
    930 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
    931 		       dev->address, reqh->request.bmRequestType,
    932 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
    933 		       UGETW(reqh->request.wIndex),
    934 		       UGETW(reqh->request.wLength),
    935 		       reqh->length, reqh->actlen);
    936 #endif
    937 	usbd_free_request(reqh);
    938 	return (r);
    939 }
    940 
    941 struct usbd_quirks *
    942 usbd_get_quirks(dev)
    943 	usbd_device_handle dev;
    944 {
    945 	return (dev->quirks);
    946 }
    947 
    948 void
    949 usbd_set_disco(p, hdl, data)
    950 	usbd_pipe_handle p;
    951 	void (*hdl) __P((void *));
    952 	void *data;
    953 {
    954 	p->disco = hdl;
    955 	p->discoarg = data;
    956 }
    957 
    958 /* XXX do periodic free() of free list */
    959 
    960