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