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