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