Home | History | Annotate | Line # | Download | only in usb
usbdi.c revision 1.3
      1 /*	$NetBSD: usbdi.c,v 1.3 1998/07/23 13:44:22 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 	return (pipe->methods->transfer(reqh));
    218 }
    219 
    220 
    221 usbd_request_handle
    222 usbd_alloc_request()
    223 {
    224 	usbd_request_handle reqh;
    225 
    226 	reqh = SIMPLEQ_FIRST(&usbd_free_requests);
    227 	if (reqh)
    228 		SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
    229 	else
    230 		reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
    231 	if (!reqh)
    232 		return (0);
    233 	memset(reqh, 0, sizeof *reqh);
    234 	return (reqh);
    235 }
    236 
    237 usbd_status
    238 usbd_free_request(reqh)
    239 	usbd_request_handle reqh;
    240 {
    241 	SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
    242 	return (USBD_NORMAL_COMPLETION);
    243 }
    244 
    245 usbd_status
    246 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
    247 	usbd_request_handle reqh;
    248 	usbd_pipe_handle pipe;
    249 	usbd_private_handle priv;
    250 	void *buffer;
    251 	u_int32_t length;
    252 	u_int16_t flags;
    253 	u_int32_t timeout;
    254 	void (*callback) __P((usbd_request_handle,
    255 			      usbd_private_handle,
    256 			      usbd_status));
    257 {
    258 	reqh->pipe = pipe;
    259 	reqh->isreq = 0;
    260 	reqh->priv = priv;
    261 	reqh->buffer = buffer;
    262 	reqh->length = length;
    263 	reqh->actlen = 0;
    264 	reqh->flags = flags;
    265 	reqh->callback = callback;
    266 	reqh->status = USBD_NOT_STARTED;
    267 	reqh->retries = 1;
    268 	return (USBD_NORMAL_COMPLETION);
    269 }
    270 
    271 usbd_status
    272 usbd_setup_device_request(reqh, req)
    273 	usbd_request_handle reqh;
    274 	usb_device_request_t *req;
    275 {
    276 	reqh->isreq = 1;
    277 	reqh->request = *req;
    278 	return (USBD_NORMAL_COMPLETION);
    279 }
    280 
    281 usbd_status
    282 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
    283 			   length, flags, callback)
    284 	usbd_request_handle reqh;
    285 	usbd_device_handle dev;
    286 	usbd_private_handle priv;
    287 	u_int32_t timeout;
    288 	usb_device_request_t *req;
    289 	void *buffer;
    290 	u_int32_t length;
    291 	u_int16_t flags;
    292 	void (*callback) __P((usbd_request_handle,
    293 			      usbd_private_handle,
    294 			      usbd_status));
    295 {
    296 	reqh->pipe = dev->default_pipe;
    297 	reqh->priv = priv;
    298 	reqh->buffer = buffer;
    299 	reqh->length = length;
    300 	reqh->actlen = 0;
    301 	reqh->flags = flags;
    302 	reqh->timeout = timeout;
    303 	reqh->status = USBD_NOT_STARTED;
    304 	reqh->callback = callback;
    305 	reqh->request = *req;
    306 	reqh->isreq = 1;
    307 	reqh->retries = 1;
    308 	return (USBD_NORMAL_COMPLETION);
    309 }
    310 
    311 usbd_status
    312 usbd_set_request_timeout(reqh, timeout)
    313 	usbd_request_handle reqh;
    314 	u_int32_t timeout;
    315 {
    316 	reqh->timeout = timeout;
    317 	return (USBD_NORMAL_COMPLETION);
    318 }
    319 
    320 usbd_status
    321 usbd_get_request_status(reqh, priv, buffer, count, status)
    322 	usbd_request_handle reqh;
    323 	usbd_private_handle *priv;
    324 	void **buffer;
    325 	u_int32_t *count;
    326 	usbd_status *status;
    327 {
    328 	*priv = reqh->priv;
    329 	*buffer = reqh->buffer;
    330 	*count = reqh->actlen;
    331 	*status = reqh->status;
    332 	return (USBD_NORMAL_COMPLETION);
    333 }
    334 
    335 usbd_status
    336 usbd_request_device_data(reqh, req)
    337 	usbd_request_handle reqh;
    338 	usb_device_request_t *req;
    339 {
    340 	if (!reqh->isreq)
    341 		return (USBD_INVAL);
    342 	*req = reqh->request;
    343 	return (USBD_NORMAL_COMPLETION);
    344 }
    345 
    346 #if 0
    347 usb_descriptor_t *
    348 usbd_get_descriptor(iface, desc_type)
    349 	usbd_interface_handle *iface;
    350 	u_int8_t desc_type;
    351 XX
    352 #endif
    353 
    354 usb_config_descriptor_t *
    355 usbd_get_config_descriptor(dev)
    356 	usbd_device_handle dev;
    357 {
    358 	return (dev->cdesc);
    359 }
    360 
    361 usb_interface_descriptor_t *
    362 usbd_get_interface_descriptor(iface)
    363 	usbd_interface_handle iface;
    364 {
    365 	return (iface->idesc);
    366 }
    367 
    368 usb_device_descriptor_t *
    369 usbd_get_device_descriptor(dev)
    370 	usbd_device_handle dev;
    371 {
    372 	return (&dev->ddesc);
    373 }
    374 
    375 usb_endpoint_descriptor_t *
    376 usbd_interface2endpoint_descriptor(iface, index)
    377 	usbd_interface_handle iface;
    378 	u_int8_t index;
    379 {
    380 	if (index >= iface->idesc->bNumEndpoints)
    381 		return 0;
    382 	return (iface->endpoints[index].edesc);
    383 }
    384 
    385 usbd_status usbd_set_configuration(dev, conf)
    386 	usbd_device_handle dev;
    387 	u_int16_t conf;
    388 {
    389 	return usbd_set_config_no(dev, conf);
    390 }
    391 
    392 usbd_status
    393 usbd_retry_request(reqh, retry_count)
    394 	usbd_request_handle reqh;
    395 	u_int32_t retry_count;
    396 {
    397 	usbd_status r;
    398 
    399 	r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
    400 	if (r != USBD_NORMAL_COMPLETION)
    401 		return (r);
    402 	reqh->retries = retry_count;
    403 	return (usbd_transfer(reqh));
    404 }
    405 
    406 usbd_status
    407 usbd_abort_pipe(pipe)
    408 	usbd_pipe_handle pipe;
    409 {
    410 	usbd_status r;
    411 	int s, st;
    412 
    413 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    414 		return (USBD_INTERFACE_NOT_ACTIVE);
    415 	s = splusb();
    416 	st = pipe->state;
    417 	r = usbd_ar_pipe(pipe);
    418 	pipe->state = st;
    419 	splx(s);
    420 	return (r);
    421 }
    422 
    423 usbd_status
    424 usbd_abort_interface(iface)
    425 	usbd_interface_handle iface;
    426 {
    427 	usbd_status r;
    428 	int s, st;
    429 
    430 	s = splusb();
    431 	st = iface->state;
    432 	r = usbd_ar_iface(iface);
    433 	iface->state = st;
    434 	splx(s);
    435 	return (r);
    436 }
    437 
    438 usbd_status
    439 usbd_reset_pipe(pipe)
    440 	usbd_pipe_handle pipe;
    441 {
    442 	usbd_status r;
    443 	int s;
    444 
    445 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    446 		return (USBD_INTERFACE_NOT_ACTIVE);
    447 	s = splusb();
    448 	r = usbd_ar_pipe(pipe);
    449 	/* XXX anything else */
    450 	pipe->state = USBD_PIPE_ACTIVE;
    451 	splx(s);
    452 	return (r);
    453 }
    454 
    455 usbd_status
    456 usbd_reset_interface(iface)
    457 	usbd_interface_handle iface;
    458 {
    459 	usbd_status r;
    460 	int s;
    461 
    462 	s = splusb();
    463 	r = usbd_ar_iface(iface);
    464 	/* XXX anything else */
    465 	iface->state = USBD_INTERFACE_ACTIVE;
    466 	splx(s);
    467 	return (r);
    468 }
    469 
    470 usbd_status
    471 usbd_clear_endpoint_stall(pipe)
    472 	usbd_pipe_handle pipe;
    473 {
    474 	usbd_device_handle dev = pipe->device;
    475 	usb_device_request_t req;
    476 	usbd_status r;
    477 
    478 	req.bmRequestType = UT_WRITE_ENDPOINT;
    479 	req.bRequest = UR_CLEAR_FEATURE;
    480 	USETW(req.wValue, UF_ENDPOINT_STALL);
    481 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress); /* XXX mask/ */
    482 	USETW(req.wLength, 0);
    483 	r = usbd_do_request(dev, &req, 0);
    484 #if 0
    485 XXX should we do this?
    486 	if (r == USBD_NORMAL_COMPLETION) {
    487 		pipe->state = USBD_PIPE_ACTIVE;
    488 		/* XXX activate pipe */
    489 	}
    490 #endif
    491 	return (r);
    492 }
    493 
    494 usbd_status
    495 usbd_set_pipe_state(pipe, state)
    496 	usbd_pipe_handle pipe;
    497 	usbd_pipe_state state;
    498 {
    499 	int s;
    500 
    501 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    502 		return (USBD_INTERFACE_NOT_ACTIVE);
    503 	if (state != USBD_PIPE_ACTIVE &&
    504 	    state != USBD_PIPE_STALLED &&
    505 	    state != USBD_PIPE_IDLE)
    506 		return (USBD_INVAL);
    507 	pipe->state = state;
    508 	if (state == USBD_PIPE_ACTIVE) {
    509 		s = splusb();
    510 		usbd_start(pipe);
    511 		splx(s);
    512 	}
    513 	return (USBD_NORMAL_COMPLETION);
    514 }
    515 
    516 usbd_status
    517 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
    518 	usbd_pipe_handle pipe;
    519 	usbd_pipe_state *state;
    520 	u_int32_t *endpoint_state;
    521 	u_int32_t *request_count;
    522 {
    523 	int n;
    524 	usbd_request_handle r;
    525 
    526 	*state = pipe->state;
    527 	*endpoint_state = pipe->endpoint->state;
    528 	for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
    529 	     r != 0;
    530 	     r = SIMPLEQ_NEXT(r, next), n++)
    531 		;
    532 	*request_count = n;
    533 	return (USBD_NORMAL_COMPLETION);
    534 }
    535 
    536 usbd_status
    537 usbd_set_interface_state(iface, state)
    538 	usbd_interface_handle iface;
    539 	usbd_interface_state state;
    540 {
    541 	int ps;
    542 	usbd_pipe_handle p;
    543 
    544 	if (state == USBD_INTERFACE_ACTIVE)
    545 		ps = USBD_PIPE_ACTIVE;
    546 	else if (state == USBD_INTERFACE_STALLED)
    547 		ps = USBD_PIPE_STALLED;
    548 	else if (state == USBD_INTERFACE_IDLE)
    549 		ps = USBD_PIPE_IDLE;
    550 	else
    551 		return (USBD_INVAL);
    552 	iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
    553 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
    554 		usbd_set_pipe_state(p, ps);
    555 	iface->state = state;
    556 	return (USBD_NORMAL_COMPLETION);
    557 }
    558 
    559 usbd_status
    560 usbd_get_interface_state(iface, state)
    561 	usbd_interface_handle iface;
    562 	usbd_interface_state *state;
    563 {
    564 	*state = iface->state;
    565 	return (USBD_NORMAL_COMPLETION);
    566 }
    567 
    568 usbd_status
    569 usbd_get_device_state(dev, state)
    570 	usbd_device_handle dev;
    571 	usbd_device_state *state;
    572 {
    573 	*state = dev->state;
    574 	return (USBD_NORMAL_COMPLETION);
    575 }
    576 
    577 #if 0
    578 usbd_status
    579 usbd_set_device_state(dev, state)
    580 	usbd_device_handle dev;
    581 	usbd_device_state state;
    582 X
    583 #endif
    584 
    585 usbd_status
    586 usbd_device_address(dev, address)
    587 	usbd_device_handle dev;
    588 	u_int8_t *address;
    589 {
    590 	*address = dev->address;
    591 	return (USBD_NORMAL_COMPLETION);
    592 }
    593 
    594 usbd_status
    595 usbd_endpoint_address(pipe, address)
    596 	usbd_pipe_handle pipe;
    597 	u_int8_t *address;
    598 {
    599 	*address = pipe->endpoint->edesc->bEndpointAddress;
    600 	return (USBD_NORMAL_COMPLETION);
    601 }
    602 
    603 usbd_status
    604 usbd_endpoint_count(iface, count)
    605 	usbd_interface_handle iface;
    606 	u_int8_t *count;
    607 {
    608 	*count = iface->idesc->bNumEndpoints;
    609 	return (USBD_NORMAL_COMPLETION);
    610 }
    611 
    612 usbd_status
    613 usbd_interface_count(dev, count)
    614 	usbd_device_handle dev;
    615 	u_int8_t *count;
    616 {
    617 	if (!dev->cdesc)
    618 		return (USBD_NOT_CONFIGURED);
    619 	*count = dev->cdesc->bNumInterface;
    620 	return (USBD_NORMAL_COMPLETION);
    621 }
    622 
    623 u_int8_t
    624 usbd_bus_count()
    625 {
    626 	return (usb_bus_count());
    627 }
    628 
    629 usbd_status
    630 usbd_get_bus_handle(index, bus)
    631 	u_int8_t index;
    632 	usbd_bus_handle *bus;
    633 {
    634 	return (usb_get_bus_handle(index, bus));
    635 }
    636 
    637 usbd_status
    638 usbd_get_root_hub(bus, dev)
    639 	usbd_bus_handle bus;
    640 	usbd_device_handle *dev;
    641 {
    642 	*dev = bus->root_hub;
    643 	return (USBD_NORMAL_COMPLETION);
    644 }
    645 
    646 usbd_status
    647 usbd_port_count(dev, nports)
    648 	usbd_device_handle dev;
    649 	u_int8_t *nports;
    650 {
    651 	if (dev->hub == 0)
    652 		return (USBD_INVAL);
    653 	*nports = dev->hub->hubdesc.bNbrPorts;
    654 	return (USBD_NORMAL_COMPLETION);
    655 }
    656 
    657 usbd_status
    658 usbd_hub2device_handle(dev, port, devp)
    659 	usbd_device_handle dev;
    660 	u_int8_t port;
    661 	usbd_device_handle *devp;
    662 {
    663 	if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
    664 	    dev->hub->ports[port].device == 0)
    665 		return (USBD_INVAL);
    666 	*devp = dev->hub->ports[port].device;
    667 	return (USBD_NORMAL_COMPLETION);
    668 }
    669 
    670 usbd_status
    671 usbd_request2pipe_handle(reqh, pipe)
    672 	usbd_request_handle reqh;
    673 	usbd_pipe_handle *pipe;
    674 {
    675 	*pipe = reqh->pipe;
    676 	return (USBD_NORMAL_COMPLETION);
    677 }
    678 
    679 usbd_status
    680 usbd_pipe2interface_handle(pipe, iface)
    681 	usbd_pipe_handle pipe;
    682 	usbd_interface_handle *iface;
    683 {
    684 	*iface = pipe->iface;
    685 	return (USBD_NORMAL_COMPLETION);
    686 }
    687 
    688 usbd_status
    689 usbd_interface2device_handle(iface, dev)
    690 	usbd_interface_handle iface;
    691 	usbd_device_handle *dev;
    692 {
    693 	*dev = iface->device;
    694 	return (USBD_NORMAL_COMPLETION);
    695 }
    696 
    697 usbd_status
    698 usbd_device2bus_handle(dev, bus)
    699 	usbd_device_handle dev;
    700 	usbd_bus_handle *bus;
    701 {
    702 	*bus = dev->bus;
    703 	return (USBD_NORMAL_COMPLETION);
    704 }
    705 
    706 usbd_status
    707 usbd_device2interface_handle(dev, ifaceno, iface)
    708 	usbd_device_handle dev;
    709 	u_int8_t ifaceno;
    710 	usbd_interface_handle *iface;
    711 {
    712 	if (!dev->cdesc)
    713 		return (USBD_NOT_CONFIGURED);
    714 	if (ifaceno >= dev->cdesc->bNumInterface)
    715 		return (USBD_INVAL);
    716 	*iface = &dev->ifaces[ifaceno];
    717 	return (USBD_NORMAL_COMPLETION);
    718 }
    719 
    720 usbd_status
    721 usbd_set_interface_private_handle(iface, priv)
    722 	usbd_interface_handle iface;
    723 	usbd_private_handle priv;
    724 {
    725 	iface->priv = priv;
    726 	return (USBD_NORMAL_COMPLETION);
    727 }
    728 
    729 usbd_status
    730 usbd_get_interface_private_handle(iface, priv)
    731 	usbd_interface_handle iface;
    732 	usbd_private_handle *priv;
    733 {
    734 	*priv = iface->priv;
    735 	return (USBD_NORMAL_COMPLETION);
    736 }
    737 
    738 usbd_status
    739 usbd_reference_pipe(pipe)
    740 	usbd_pipe_handle pipe;
    741 {
    742 	pipe->refcnt++;
    743 	return (USBD_NORMAL_COMPLETION);
    744 }
    745 
    746 usbd_status
    747 usbd_dereference_pipe(pipe)
    748 	usbd_pipe_handle pipe;
    749 {
    750 	pipe->refcnt--;
    751 	return (USBD_NORMAL_COMPLETION);
    752 }
    753 
    754 usbd_lock_token
    755 usbd_lock()
    756 {
    757 	return (splusb());
    758 }
    759 
    760 void
    761 usbd_unlock(tok)
    762 	usbd_lock_token tok;
    763 {
    764 	splx(tok);
    765 }
    766 
    767 /* XXX need to check that the interface is idle */
    768 usbd_status
    769 usbd_set_interface(iface, aiface)
    770 	usbd_interface_handle iface;
    771 	int aiface;
    772 {
    773 	usb_device_request_t req;
    774 
    775 	req.bmRequestType = UT_WRITE_INTERFACE;
    776 	req.bRequest = UR_SET_INTERFACE;
    777 	USETW(req.wValue, aiface);
    778 	USETW(req.wIndex, iface->idesc->iInterface);
    779 	USETW(req.wLength, 0);
    780 	return usbd_do_request(iface->device, &req, 0);
    781 }
    782 
    783 /*** Internal routines ***/
    784 
    785 /* Dequeue all pipe operations, called at splusb(). */
    786 static usbd_status
    787 usbd_ar_pipe(pipe)
    788 	usbd_pipe_handle pipe;
    789 {
    790 	usbd_request_handle reqh;
    791 
    792 	reqh = SIMPLEQ_FIRST(&pipe->queue);
    793 	if (reqh != 0) {
    794 		pipe->methods->abort(reqh);
    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 	/* XXX check retry count */
    844 	reqh->done = 1;
    845 	if (reqh->status == USBD_NORMAL_COMPLETION &&
    846 	    reqh->actlen < reqh->length &&
    847 	    !(reqh->flags & USBD_SHORT_XFER_OK)) {
    848 		DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d < %d\n",
    849 			      reqh->actlen, reqh->length));
    850 		reqh->status = USBD_SHORT_XFER;
    851 	}
    852 	if (reqh->callback)
    853 		reqh->callback(reqh, reqh->priv, reqh->status);
    854 
    855 	if (pipe->state != USBD_PIPE_ACTIVE) {
    856 		pipe->running = 0;
    857 		return;
    858 	}
    859 	nreqh = SIMPLEQ_FIRST(&pipe->queue);
    860 	DPRINTFN(5, ("usbd_transfer_cb: nreqh=%p\n", nreqh));
    861 	if (!nreqh)
    862 		pipe->running = 0;
    863 	else {
    864 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, nreqh, next);
    865 		r = pipe->methods->transfer(nreqh);
    866 		if (r != USBD_IN_PROGRESS)
    867 			printf("usbd_transfer_cb: error=%d\n", r);
    868 	}
    869 }
    870 
    871 static void
    872 usbd_sync_transfer_cb(reqh)
    873 	usbd_request_handle reqh;
    874 {
    875 	usbd_transfer_cb(reqh);
    876 	if (!usbd_use_polling)
    877 		wakeup(reqh);
    878 }
    879 
    880 /* Like usbd_transfer(), but waits for completion. */
    881 usbd_status
    882 usbd_sync_transfer(reqh)
    883 	usbd_request_handle reqh;
    884 {
    885 	usbd_status r;
    886 	int s;
    887 
    888 	reqh->xfercb = usbd_sync_transfer_cb;
    889 	r = usbd_do_transfer(reqh);
    890 	if (r != USBD_IN_PROGRESS)
    891 		return (r);
    892 	s = splusb();
    893 	if (!reqh->done) {
    894 		if (usbd_use_polling)
    895 			panic("usbd_sync_transfer: not done\n");
    896 		tsleep(reqh, PRIBIO, "usbsyn", 0);
    897 	}
    898 	splx(s);
    899 	return (reqh->status);
    900 }
    901 
    902 usbd_status
    903 usbd_do_request(dev, req, data)
    904 	usbd_device_handle dev;
    905 	usb_device_request_t *req;
    906 	void *data;
    907 {
    908 	usbd_request_handle reqh;
    909 	usbd_status r;
    910 
    911 	reqh = usbd_alloc_request();
    912 	if (reqh == 0)
    913 		return (USBD_NOMEM);
    914 	r = usbd_setup_default_request(
    915 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
    916 		UGETW(req->wLength), 0, 0);
    917 	if (r != USBD_NORMAL_COMPLETION) {
    918 		usbd_free_request(reqh);
    919 		return (r);
    920 	}
    921 	r = usbd_sync_transfer(reqh);
    922 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
    923 	if (reqh->actlen > reqh->length)
    924 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
    925 		       dev->address, reqh->request.bmRequestType,
    926 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
    927 		       UGETW(reqh->request.wIndex),
    928 		       UGETW(reqh->request.wLength),
    929 		       reqh->length, reqh->actlen);
    930 #endif
    931 	usbd_free_request(reqh);
    932 	return (r);
    933 }
    934 
    935 struct usbd_quirks *
    936 usbd_get_quirks(dev)
    937 	usbd_device_handle dev;
    938 {
    939 	return (dev->quirks);
    940 }
    941 
    942 void
    943 usbd_set_disco(p, hdl, data)
    944 	usbd_pipe_handle p;
    945 	void (*hdl) __P((void *));
    946 	void *data;
    947 {
    948 	p->disco = hdl;
    949 	p->discoarg = data;
    950 }
    951 
    952 /* XXX do periodic free() of free list */
    953 
    954