Home | History | Annotate | Line # | Download | only in usb
usbdi.c revision 1.23
      1 /*	$NetBSD: usbdi.c,v 1.23 1999/05/13 23:29:41 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 <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/kernel.h>
     43 #if defined(__NetBSD__)
     44 #include <sys/device.h>
     45 #else
     46 #include <sys/module.h>
     47 #include <sys/bus.h>
     48 #include <sys/conf.h>
     49 #endif
     50 #include <sys/malloc.h>
     51 #include <sys/proc.h>
     52 
     53 #include <dev/usb/usb.h>
     54 
     55 #include <dev/usb/usbdi.h>
     56 #include <dev/usb/usbdi_util.h>
     57 #include <dev/usb/usbdivar.h>
     58 
     59 #if defined(__FreeBSD__)
     60 #include "usb_if.h"
     61 #endif
     62 
     63 #ifdef USB_DEBUG
     64 #define DPRINTF(x)	if (usbdebug) printf x
     65 #define DPRINTFN(n,x)	if (usbdebug>(n)) printf x
     66 extern int usbdebug;
     67 #else
     68 #define DPRINTF(x)
     69 #define DPRINTFN(n,x)
     70 #endif
     71 
     72 static usbd_status usbd_ar_pipe  __P((usbd_pipe_handle pipe));
     73 static usbd_status usbd_ar_iface __P((usbd_interface_handle iface));
     74 static void usbd_transfer_cb __P((usbd_request_handle reqh));
     75 static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));
     76 static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));
     77 void usbd_do_request_async_cb
     78 	__P((usbd_request_handle, usbd_private_handle, usbd_status));
     79 
     80 static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;
     81 
     82 #if defined(__FreeBSD__)
     83 #define USB_CDEV_MAJOR	108
     84 
     85 extern struct cdevsw usb_cdevsw;
     86 #endif
     87 
     88 usbd_status
     89 usbd_open_pipe(iface, address, flags, pipe)
     90 	usbd_interface_handle iface;
     91 	u_int8_t address;
     92 	u_int8_t flags;
     93 	usbd_pipe_handle *pipe;
     94 {
     95 	usbd_pipe_handle p;
     96 	struct usbd_endpoint *ep;
     97 	usbd_status r;
     98 	int i;
     99 
    100 	if (iface->state != USBD_INTERFACE_ACTIVE)
    101 		return (USBD_INTERFACE_NOT_ACTIVE);
    102 	for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
    103 		ep = &iface->endpoints[i];
    104 		if (ep->edesc->bEndpointAddress == address)
    105 			goto found;
    106 	}
    107 	return (USBD_BAD_ADDRESS);
    108  found:
    109 	if ((flags & USBD_EXCLUSIVE_USE) &&
    110 	    ep->refcnt != 0)
    111 		return (USBD_IN_USE);
    112 	r = usbd_setup_pipe(iface->device, iface, ep, &p);
    113 	if (r != USBD_NORMAL_COMPLETION)
    114 		return (r);
    115 	LIST_INSERT_HEAD(&iface->pipes, p, next);
    116 	*pipe = p;
    117 	return (USBD_NORMAL_COMPLETION);
    118 }
    119 
    120 usbd_status
    121 usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)
    122 	usbd_interface_handle iface;
    123 	u_int8_t address;
    124 	u_int8_t flags;
    125 	usbd_pipe_handle *pipe;
    126 	usbd_private_handle priv;
    127 	void *buffer;
    128 	u_int32_t length;
    129 	usbd_callback cb;
    130 {
    131 	usbd_status r;
    132 	usbd_request_handle reqh;
    133 	usbd_pipe_handle ipipe;
    134 
    135 	reqh = usbd_alloc_request();
    136 	if (reqh == 0)
    137 		return (USBD_NOMEM);
    138 	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);
    139 	if (r != USBD_NORMAL_COMPLETION)
    140 		goto bad1;
    141 	r = usbd_setup_request(reqh, ipipe, priv, buffer, length,
    142 			       USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);
    143 	if (r != USBD_NORMAL_COMPLETION)
    144 		goto bad2;
    145 	ipipe->intrreqh = reqh;
    146 	r = usbd_transfer(reqh);
    147 	*pipe = ipipe;
    148 	if (r != USBD_IN_PROGRESS)
    149 		goto bad3;
    150 	return (USBD_NORMAL_COMPLETION);
    151 
    152  bad3:
    153 	ipipe->intrreqh = 0;
    154  bad2:
    155 	usbd_close_pipe(ipipe);
    156  bad1:
    157 	usbd_free_request(reqh);
    158 	return r;
    159 }
    160 
    161 usbd_status
    162 usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf, cb)
    163 	usbd_interface_handle iface;
    164 	u_int8_t address;
    165 	u_int8_t flags;
    166 	usbd_pipe_handle *pipe;
    167 	usbd_private_handle priv;
    168 	u_int32_t bufsize;
    169 	u_int32_t nbuf;
    170 	usbd_callback cb;
    171 {
    172 	usbd_status r;
    173 	usbd_pipe_handle p;
    174 
    175 	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);
    176 	if (r != USBD_NORMAL_COMPLETION)
    177 		return (r);
    178 	if (!p->methods->isobuf) {
    179 		usbd_close_pipe(p);
    180 		return (USBD_INVAL);
    181 	}
    182 	r = p->methods->isobuf(p, bufsize, nbuf);
    183 	if (r != USBD_NORMAL_COMPLETION) {
    184 		usbd_close_pipe(p);
    185 		return (r);
    186 	}
    187 	*pipe = p;
    188 	return r;
    189 }
    190 
    191 usbd_status
    192 usbd_close_pipe(pipe)
    193 	usbd_pipe_handle pipe;
    194 {
    195 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    196 		return (USBD_INTERFACE_NOT_ACTIVE);
    197 	if (--pipe->refcnt != 0)
    198 		return (USBD_NORMAL_COMPLETION);
    199 	if (SIMPLEQ_FIRST(&pipe->queue) != 0)
    200 		return (USBD_PENDING_REQUESTS);
    201 	LIST_REMOVE(pipe, next);
    202 	pipe->endpoint->refcnt--;
    203 	pipe->methods->close(pipe);
    204 	if (pipe->intrreqh)
    205 		usbd_free_request(pipe->intrreqh);
    206 	free(pipe, M_USB);
    207 	return (USBD_NORMAL_COMPLETION);
    208 }
    209 
    210 usbd_status
    211 usbd_transfer(reqh)
    212 	usbd_request_handle reqh;
    213 {
    214 	reqh->xfercb = usbd_transfer_cb;
    215 	return (usbd_do_transfer(reqh));
    216 }
    217 
    218 static usbd_status
    219 usbd_do_transfer(reqh)
    220 	usbd_request_handle reqh;
    221 {
    222 	usbd_pipe_handle pipe = reqh->pipe;
    223 
    224 	DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));
    225 	reqh->done = 0;
    226 	return (pipe->methods->transfer(reqh));
    227 }
    228 
    229 usbd_request_handle
    230 usbd_alloc_request()
    231 {
    232 	usbd_request_handle reqh;
    233 
    234 	reqh = SIMPLEQ_FIRST(&usbd_free_requests);
    235 	if (reqh)
    236 		SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);
    237 	else
    238 		reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);
    239 	if (!reqh)
    240 		return (0);
    241 	memset(reqh, 0, sizeof *reqh);
    242 	return (reqh);
    243 }
    244 
    245 usbd_status
    246 usbd_free_request(reqh)
    247 	usbd_request_handle reqh;
    248 {
    249 	SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);
    250 	return (USBD_NORMAL_COMPLETION);
    251 }
    252 
    253 usbd_status
    254 usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)
    255 	usbd_request_handle reqh;
    256 	usbd_pipe_handle pipe;
    257 	usbd_private_handle priv;
    258 	void *buffer;
    259 	u_int32_t length;
    260 	u_int16_t flags;
    261 	u_int32_t timeout;
    262 	void (*callback) __P((usbd_request_handle,
    263 			      usbd_private_handle,
    264 			      usbd_status));
    265 {
    266 	reqh->pipe = pipe;
    267 	reqh->priv = priv;
    268 	reqh->buffer = buffer;
    269 	reqh->length = length;
    270 	reqh->actlen = 0;
    271 	reqh->flags = flags;
    272 	reqh->timeout = timeout;
    273 	reqh->status = USBD_NOT_STARTED;
    274 	reqh->callback = callback;
    275 	reqh->retries = 1;
    276 	reqh->isreq = 0;
    277 	return (USBD_NORMAL_COMPLETION);
    278 }
    279 
    280 usbd_status
    281 usbd_setup_device_request(reqh, req)
    282 	usbd_request_handle reqh;
    283 	usb_device_request_t *req;
    284 {
    285 	reqh->isreq = 1;
    286 	reqh->request = *req;
    287 	return (USBD_NORMAL_COMPLETION);
    288 }
    289 
    290 usbd_status
    291 usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer,
    292 			   length, flags, callback)
    293 	usbd_request_handle reqh;
    294 	usbd_device_handle dev;
    295 	usbd_private_handle priv;
    296 	u_int32_t timeout;
    297 	usb_device_request_t *req;
    298 	void *buffer;
    299 	u_int32_t length;
    300 	u_int16_t flags;
    301 	void (*callback) __P((usbd_request_handle,
    302 			      usbd_private_handle,
    303 			      usbd_status));
    304 {
    305 	reqh->pipe = dev->default_pipe;
    306 	reqh->priv = priv;
    307 	reqh->buffer = buffer;
    308 	reqh->length = length;
    309 	reqh->actlen = 0;
    310 	reqh->flags = flags;
    311 	reqh->timeout = timeout;
    312 	reqh->status = USBD_NOT_STARTED;
    313 	reqh->callback = callback;
    314 	reqh->request = *req;
    315 	reqh->retries = 1;
    316 	reqh->isreq = 1;
    317 	return (USBD_NORMAL_COMPLETION);
    318 }
    319 
    320 usbd_status
    321 usbd_set_request_timeout(reqh, timeout)
    322 	usbd_request_handle reqh;
    323 	u_int32_t timeout;
    324 {
    325 	reqh->timeout = timeout;
    326 	return (USBD_NORMAL_COMPLETION);
    327 }
    328 
    329 usbd_status
    330 usbd_get_request_status(reqh, priv, buffer, count, status)
    331 	usbd_request_handle reqh;
    332 	usbd_private_handle *priv;
    333 	void **buffer;
    334 	u_int32_t *count;
    335 	usbd_status *status;
    336 {
    337 	*priv = reqh->priv;
    338 	*buffer = reqh->buffer;
    339 	*count = reqh->actlen;
    340 	*status = reqh->status;
    341 	return (USBD_NORMAL_COMPLETION);
    342 }
    343 
    344 usbd_status
    345 usbd_request_device_data(reqh, req)
    346 	usbd_request_handle reqh;
    347 	usb_device_request_t *req;
    348 {
    349 	if (!reqh->isreq)
    350 		return (USBD_INVAL);
    351 	*req = reqh->request;
    352 	return (USBD_NORMAL_COMPLETION);
    353 }
    354 
    355 #if 0
    356 usb_descriptor_t *
    357 usbd_get_descriptor(iface, desc_type)
    358 	usbd_interface_handle *iface;
    359 	u_int8_t desc_type;
    360 XX
    361 #endif
    362 
    363 usb_config_descriptor_t *
    364 usbd_get_config_descriptor(dev)
    365 	usbd_device_handle dev;
    366 {
    367 	return (dev->cdesc);
    368 }
    369 
    370 usb_interface_descriptor_t *
    371 usbd_get_interface_descriptor(iface)
    372 	usbd_interface_handle iface;
    373 {
    374 	return (iface->idesc);
    375 }
    376 
    377 usb_device_descriptor_t *
    378 usbd_get_device_descriptor(dev)
    379 	usbd_device_handle dev;
    380 {
    381 	return (&dev->ddesc);
    382 }
    383 
    384 usb_endpoint_descriptor_t *
    385 usbd_interface2endpoint_descriptor(iface, index)
    386 	usbd_interface_handle iface;
    387 	u_int8_t index;
    388 {
    389 	if (index >= iface->idesc->bNumEndpoints)
    390 		return (0);
    391 	return (iface->endpoints[index].edesc);
    392 }
    393 
    394 usbd_status
    395 usbd_set_configuration(dev, conf)
    396 	usbd_device_handle dev;
    397 	u_int8_t conf;
    398 {
    399 	return usbd_set_config_no(dev, conf, 0);
    400 }
    401 
    402 usbd_status
    403 usbd_retry_request(reqh, retry_count)
    404 	usbd_request_handle reqh;
    405 	u_int32_t retry_count;
    406 {
    407 	usbd_status r;
    408 
    409 	r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);
    410 	if (r != USBD_NORMAL_COMPLETION)
    411 		return (r);
    412 	reqh->retries = retry_count;
    413 	return (usbd_transfer(reqh));
    414 }
    415 
    416 usbd_status
    417 usbd_abort_pipe(pipe)
    418 	usbd_pipe_handle pipe;
    419 {
    420 	usbd_status r;
    421 	int s, st;
    422 
    423 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    424 		return (USBD_INTERFACE_NOT_ACTIVE);
    425 	s = splusb();
    426 	st = pipe->state;
    427 	r = usbd_ar_pipe(pipe);
    428 	pipe->state = st;
    429 	splx(s);
    430 	return (r);
    431 }
    432 
    433 usbd_status
    434 usbd_abort_interface(iface)
    435 	usbd_interface_handle iface;
    436 {
    437 	usbd_status r;
    438 	int s, st;
    439 
    440 	s = splusb();
    441 	st = iface->state;
    442 	r = usbd_ar_iface(iface);
    443 	iface->state = st;
    444 	splx(s);
    445 	return (r);
    446 }
    447 
    448 usbd_status
    449 usbd_reset_pipe(pipe)
    450 	usbd_pipe_handle pipe;
    451 {
    452 	usbd_status r;
    453 	int s;
    454 
    455 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    456 		return (USBD_INTERFACE_NOT_ACTIVE);
    457 	s = splusb();
    458 	r = usbd_ar_pipe(pipe);
    459 	/* XXX anything else */
    460 	pipe->state = USBD_PIPE_ACTIVE;
    461 	splx(s);
    462 	return (r);
    463 }
    464 
    465 usbd_status
    466 usbd_reset_interface(iface)
    467 	usbd_interface_handle iface;
    468 {
    469 	usbd_status r;
    470 	int s;
    471 
    472 	s = splusb();
    473 	r = usbd_ar_iface(iface);
    474 	/* XXX anything else */
    475 	iface->state = USBD_INTERFACE_ACTIVE;
    476 	splx(s);
    477 	return (r);
    478 }
    479 
    480 usbd_status
    481 usbd_clear_endpoint_stall(pipe)
    482 	usbd_pipe_handle pipe;
    483 {
    484 	usbd_device_handle dev = pipe->device;
    485 	usb_device_request_t req;
    486 	usbd_status r;
    487 
    488 	DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
    489 	req.bmRequestType = UT_WRITE_ENDPOINT;
    490 	req.bRequest = UR_CLEAR_FEATURE;
    491 	USETW(req.wValue, UF_ENDPOINT_HALT);
    492 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
    493 	USETW(req.wLength, 0);
    494 	r = usbd_do_request(dev, &req, 0);
    495 #if 0
    496 XXX should we do this?
    497 	if (r == USBD_NORMAL_COMPLETION) {
    498 		pipe->state = USBD_PIPE_ACTIVE;
    499 		/* XXX activate pipe */
    500 	}
    501 #endif
    502 	return (r);
    503 }
    504 
    505 usbd_status
    506 usbd_clear_endpoint_stall_async(pipe)
    507 	usbd_pipe_handle pipe;
    508 {
    509 	usbd_device_handle dev = pipe->device;
    510 	usb_device_request_t req;
    511 	usbd_status r;
    512 
    513 	req.bmRequestType = UT_WRITE_ENDPOINT;
    514 	req.bRequest = UR_CLEAR_FEATURE;
    515 	USETW(req.wValue, UF_ENDPOINT_HALT);
    516 	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
    517 	USETW(req.wLength, 0);
    518 	r = usbd_do_request_async(dev, &req, 0);
    519 	return (r);
    520 }
    521 
    522 usbd_status
    523 usbd_set_pipe_state(pipe, state)
    524 	usbd_pipe_handle pipe;
    525 	usbd_pipe_state state;
    526 {
    527 	int s;
    528 	usbd_status r;
    529 	usbd_request_handle reqh;
    530 
    531 	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)
    532 		return (USBD_INTERFACE_NOT_ACTIVE);
    533 	if (state != USBD_PIPE_ACTIVE &&
    534 	    state != USBD_PIPE_STALLED &&
    535 	    state != USBD_PIPE_IDLE)
    536 		return (USBD_INVAL);
    537 	pipe->state = state;
    538 	r = USBD_NORMAL_COMPLETION;
    539 	if (state == USBD_PIPE_ACTIVE) {
    540 		s = splusb();
    541 		if (!pipe->running) {
    542 			reqh = SIMPLEQ_FIRST(&pipe->queue);
    543 			if (reqh != 0) {
    544 				pipe->running = 1;
    545 				splx(s);
    546 				r = pipe->methods->start(reqh);
    547 			} else
    548 				splx(s);
    549 		} else
    550 			splx(s);
    551 	}
    552 	return (r);
    553 }
    554 
    555 usbd_status
    556 usbd_get_pipe_state(pipe, state, endpoint_state, request_count)
    557 	usbd_pipe_handle pipe;
    558 	usbd_pipe_state *state;
    559 	u_int32_t *endpoint_state;
    560 	u_int32_t *request_count;
    561 {
    562 	int n;
    563 	usbd_request_handle r;
    564 
    565 	*state = pipe->state;
    566 	*endpoint_state = pipe->endpoint->state;
    567 	for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0;
    568 	     r != 0;
    569 	     r = SIMPLEQ_NEXT(r, next), n++)
    570 		;
    571 	*request_count = n;
    572 	return (USBD_NORMAL_COMPLETION);
    573 }
    574 
    575 usbd_status
    576 usbd_set_interface_state(iface, state)
    577 	usbd_interface_handle iface;
    578 	usbd_interface_state state;
    579 {
    580 	int ps;
    581 	usbd_pipe_handle p;
    582 
    583 	if (state == USBD_INTERFACE_ACTIVE)
    584 		ps = USBD_PIPE_ACTIVE;
    585 	else if (state == USBD_INTERFACE_STALLED)
    586 		ps = USBD_PIPE_STALLED;
    587 	else if (state == USBD_INTERFACE_IDLE)
    588 		ps = USBD_PIPE_IDLE;
    589 	else
    590 		return (USBD_INVAL);
    591 	iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */
    592 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))
    593 		usbd_set_pipe_state(p, ps);
    594 	iface->state = state;
    595 	return (USBD_NORMAL_COMPLETION);
    596 }
    597 
    598 usbd_status
    599 usbd_get_interface_state(iface, state)
    600 	usbd_interface_handle iface;
    601 	usbd_interface_state *state;
    602 {
    603 	*state = iface->state;
    604 	return (USBD_NORMAL_COMPLETION);
    605 }
    606 
    607 usbd_status
    608 usbd_get_device_state(dev, state)
    609 	usbd_device_handle dev;
    610 	usbd_device_state *state;
    611 {
    612 	*state = dev->state;
    613 	return (USBD_NORMAL_COMPLETION);
    614 }
    615 
    616 #if 0
    617 usbd_status
    618 usbd_set_device_state(dev, state)
    619 	usbd_device_handle dev;
    620 	usbd_device_state state;
    621 X
    622 #endif
    623 
    624 usbd_status
    625 usbd_device_address(dev, address)
    626 	usbd_device_handle dev;
    627 	u_int8_t *address;
    628 {
    629 	*address = dev->address;
    630 	return (USBD_NORMAL_COMPLETION);
    631 }
    632 
    633 usbd_status
    634 usbd_endpoint_address(pipe, address)
    635 	usbd_pipe_handle pipe;
    636 	u_int8_t *address;
    637 {
    638 	*address = pipe->endpoint->edesc->bEndpointAddress;
    639 	return (USBD_NORMAL_COMPLETION);
    640 }
    641 
    642 usbd_status
    643 usbd_endpoint_count(iface, count)
    644 	usbd_interface_handle iface;
    645 	u_int8_t *count;
    646 {
    647 	*count = iface->idesc->bNumEndpoints;
    648 	return (USBD_NORMAL_COMPLETION);
    649 }
    650 
    651 usbd_status
    652 usbd_interface_count(dev, count)
    653 	usbd_device_handle dev;
    654 	u_int8_t *count;
    655 {
    656 	if (!dev->cdesc)
    657 		return (USBD_NOT_CONFIGURED);
    658 	*count = dev->cdesc->bNumInterface;
    659 	return (USBD_NORMAL_COMPLETION);
    660 }
    661 
    662 #if 0
    663 u_int8_t
    664 usbd_bus_count()
    665 {
    666 	return (usb_bus_count());
    667 }
    668 
    669 usbd_status
    670 usbd_get_bus_handle(index, bus)
    671 	u_int8_t index;
    672 	usbd_bus_handle *bus;
    673 {
    674 	return (usb_get_bus_handle(index, bus));
    675 }
    676 #endif
    677 
    678 usbd_status
    679 usbd_get_root_hub(bus, dev)
    680 	usbd_bus_handle bus;
    681 	usbd_device_handle *dev;
    682 {
    683 	*dev = bus->root_hub;
    684 	return (USBD_NORMAL_COMPLETION);
    685 }
    686 
    687 usbd_status
    688 usbd_port_count(dev, nports)
    689 	usbd_device_handle dev;
    690 	u_int8_t *nports;
    691 {
    692 	if (dev->hub == 0)
    693 		return (USBD_INVAL);
    694 	*nports = dev->hub->hubdesc.bNbrPorts;
    695 	return (USBD_NORMAL_COMPLETION);
    696 }
    697 
    698 usbd_status
    699 usbd_hub2device_handle(dev, port, devp)
    700 	usbd_device_handle dev;
    701 	u_int8_t port;
    702 	usbd_device_handle *devp;
    703 {
    704 	if (dev->hub == 0 || port >= dev->hub->hubdesc.bNbrPorts ||
    705 	    dev->hub->ports[port].device == 0)
    706 		return (USBD_INVAL);
    707 	*devp = dev->hub->ports[port].device;
    708 	return (USBD_NORMAL_COMPLETION);
    709 }
    710 
    711 usbd_status
    712 usbd_request2pipe_handle(reqh, pipe)
    713 	usbd_request_handle reqh;
    714 	usbd_pipe_handle *pipe;
    715 {
    716 	*pipe = reqh->pipe;
    717 	return (USBD_NORMAL_COMPLETION);
    718 }
    719 
    720 usbd_status
    721 usbd_pipe2interface_handle(pipe, iface)
    722 	usbd_pipe_handle pipe;
    723 	usbd_interface_handle *iface;
    724 {
    725 	*iface = pipe->iface;
    726 	return (USBD_NORMAL_COMPLETION);
    727 }
    728 
    729 usbd_status
    730 usbd_interface2device_handle(iface, dev)
    731 	usbd_interface_handle iface;
    732 	usbd_device_handle *dev;
    733 {
    734 	*dev = iface->device;
    735 	return (USBD_NORMAL_COMPLETION);
    736 }
    737 
    738 usbd_status
    739 usbd_device2bus_handle(dev, bus)
    740 	usbd_device_handle dev;
    741 	usbd_bus_handle *bus;
    742 {
    743 	*bus = dev->bus;
    744 	return (USBD_NORMAL_COMPLETION);
    745 }
    746 
    747 usbd_status
    748 usbd_device2interface_handle(dev, ifaceno, iface)
    749 	usbd_device_handle dev;
    750 	u_int8_t ifaceno;
    751 	usbd_interface_handle *iface;
    752 {
    753 	if (!dev->cdesc)
    754 		return (USBD_NOT_CONFIGURED);
    755 	if (ifaceno >= dev->cdesc->bNumInterface)
    756 		return (USBD_INVAL);
    757 	*iface = &dev->ifaces[ifaceno];
    758 	return (USBD_NORMAL_COMPLETION);
    759 }
    760 
    761 usbd_status
    762 usbd_set_interface_private_handle(iface, priv)
    763 	usbd_interface_handle iface;
    764 	usbd_private_handle priv;
    765 {
    766 	iface->priv = priv;
    767 	return (USBD_NORMAL_COMPLETION);
    768 }
    769 
    770 usbd_status
    771 usbd_get_interface_private_handle(iface, priv)
    772 	usbd_interface_handle iface;
    773 	usbd_private_handle *priv;
    774 {
    775 	*priv = iface->priv;
    776 	return (USBD_NORMAL_COMPLETION);
    777 }
    778 
    779 usbd_status
    780 usbd_reference_pipe(pipe)
    781 	usbd_pipe_handle pipe;
    782 {
    783 	pipe->refcnt++;
    784 	return (USBD_NORMAL_COMPLETION);
    785 }
    786 
    787 usbd_status
    788 usbd_dereference_pipe(pipe)
    789 	usbd_pipe_handle pipe;
    790 {
    791 	pipe->refcnt--;
    792 	return (USBD_NORMAL_COMPLETION);
    793 }
    794 
    795 usbd_lock_token
    796 usbd_lock()
    797 {
    798 	return (splusb());
    799 }
    800 
    801 void
    802 usbd_unlock(tok)
    803 	usbd_lock_token tok;
    804 {
    805 	splx(tok);
    806 }
    807 
    808 /* XXXX use altno */
    809 usbd_status
    810 usbd_set_interface(iface, altidx)
    811 	usbd_interface_handle iface;
    812 	int altidx;
    813 {
    814 	usb_device_request_t req;
    815 	usbd_status r;
    816 
    817 	if (LIST_FIRST(&iface->pipes) != 0)
    818 		return (USBD_IN_USE);
    819 
    820 	if (iface->endpoints)
    821 		free(iface->endpoints, M_USB);
    822 	iface->endpoints = 0;
    823 	iface->idesc = 0;
    824 	iface->state = USBD_INTERFACE_IDLE;
    825 
    826 	r = usbd_fill_iface_data(iface->device, iface->index, altidx);
    827 	if (r != USBD_NORMAL_COMPLETION)
    828 		return (r);
    829 
    830 	req.bmRequestType = UT_WRITE_INTERFACE;
    831 	req.bRequest = UR_SET_INTERFACE;
    832 	USETW(req.wValue, iface->idesc->bAlternateSetting);
    833 	USETW(req.wIndex, iface->idesc->bInterfaceNumber);
    834 	USETW(req.wLength, 0);
    835 	return usbd_do_request(iface->device, &req, 0);
    836 }
    837 
    838 int
    839 usbd_get_no_alts(cdesc, ifaceno)
    840 	usb_config_descriptor_t *cdesc;
    841 	int ifaceno;
    842 {
    843 	char *p = (char *)cdesc;
    844 	char *end = p + UGETW(cdesc->wTotalLength);
    845 	usb_interface_descriptor_t *d;
    846 	int n;
    847 
    848 	for (n = 0; p < end; p += d->bLength) {
    849 		d = (usb_interface_descriptor_t *)p;
    850 		if (p + d->bLength <= end &&
    851 		    d->bDescriptorType == UDESC_INTERFACE &&
    852 		    d->bInterfaceNumber == ifaceno)
    853 			n++;
    854 	}
    855 	return (n);
    856 }
    857 
    858 int
    859 usbd_get_interface_altindex(iface)
    860 	usbd_interface_handle iface;
    861 {
    862 	return (iface->altindex);
    863 }
    864 
    865 usbd_status
    866 usbd_get_interface(iface, aiface)
    867 	usbd_interface_handle iface;
    868 	u_int8_t *aiface;
    869 {
    870 	usb_device_request_t req;
    871 
    872 	req.bmRequestType = UT_READ_INTERFACE;
    873 	req.bRequest = UR_GET_INTERFACE;
    874 	USETW(req.wValue, 0);
    875 	USETW(req.wIndex, iface->idesc->bInterfaceNumber);
    876 	USETW(req.wLength, 1);
    877 	return usbd_do_request(iface->device, &req, aiface);
    878 }
    879 
    880 /*** Internal routines ***/
    881 
    882 /* Dequeue all pipe operations, called at splusb(). */
    883 static usbd_status
    884 usbd_ar_pipe(pipe)
    885 	usbd_pipe_handle pipe;
    886 {
    887 	usbd_request_handle reqh;
    888 
    889 #if 0
    890 	for (;;) {
    891 		reqh = SIMPLEQ_FIRST(&pipe->queue);
    892 		if (reqh == 0)
    893 			break;
    894 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    895 		reqh->status = USBD_CANCELLED;
    896 		if (reqh->callback)
    897 			reqh->callback(reqh, reqh->priv, reqh->status);
    898 	}
    899 #else
    900 	while ((reqh = SIMPLEQ_FIRST(&pipe->queue))) {
    901 		pipe->methods->abort(reqh);
    902 		SIMPLEQ_REMOVE_HEAD(&pipe->queue, reqh, next);
    903 	}
    904 #endif
    905 	return (USBD_NORMAL_COMPLETION);
    906 }
    907 
    908 /* Dequeue all interface operations, called at splusb(). */
    909 static usbd_status
    910 usbd_ar_iface(iface)
    911 	usbd_interface_handle iface;
    912 {
    913 	usbd_pipe_handle p;
    914 	usbd_status r, ret = USBD_NORMAL_COMPLETION;
    915 
    916 	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next)) {
    917 		r = usbd_ar_pipe(p);
    918 		if (r != USBD_NORMAL_COMPLETION)
    919 			ret = r;
    920 	}
    921 	return (ret);
    922 }
    923 
    924 static int usbd_global_init_done = 0;
    925 
    926 void
    927 usbd_init()
    928 {
    929 #if defined(__FreeBSD__)
    930 	dev_t dev;
    931 #endif
    932 
    933 	if (!usbd_global_init_done) {
    934 		usbd_global_init_done = 1;
    935 		SIMPLEQ_INIT(&usbd_free_requests);
    936 
    937 #if defined(__FreeBSD__)
    938 		dev = makedev(USB_CDEV_MAJOR, 0);
    939 		cdevsw_add(&dev, &usb_cdevsw, NULL);
    940 #endif
    941 	}
    942 }
    943 
    944 static void
    945 usbd_transfer_cb(reqh)
    946 	usbd_request_handle reqh;
    947 {
    948 	usbd_pipe_handle pipe = reqh->pipe;
    949 
    950 	DPRINTFN(10, ("usbd_transfer_cb: reqh=%p\n", reqh));
    951 	/* Count completed transfers. */
    952 #ifdef DIAGNOSTIC
    953 	if (!pipe)
    954 		printf("usbd_transfer_cb: pipe==0, reqh=%p\n", reqh);
    955 	else
    956 #endif
    957 	++pipe->device->bus->stats.requests
    958 		[pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
    959 
    960 	/* XXX check retry count */
    961 	reqh->done = 1;
    962 	if (reqh->status == USBD_NORMAL_COMPLETION &&
    963 	    reqh->actlen < reqh->length &&
    964 	    !(reqh->flags & USBD_SHORT_XFER_OK)) {
    965 		DPRINTFN(-1, ("usbd_transfer_cb: short xfer %d<%d (bytes)\n",
    966 			      reqh->actlen, reqh->length));
    967 		reqh->status = USBD_SHORT_XFER;
    968 	}
    969 	if (reqh->callback)
    970 		reqh->callback(reqh, reqh->priv, reqh->status);
    971 }
    972 
    973 static void
    974 usbd_sync_transfer_cb(reqh)
    975 	usbd_request_handle reqh;
    976 {
    977 	DPRINTFN(10, ("usbd_sync_transfer_cb: reqh=%p\n", reqh));
    978 	usbd_transfer_cb(reqh);
    979 	if (!reqh->pipe->device->bus->use_polling)
    980 		wakeup(reqh);
    981 }
    982 
    983 /* Like usbd_transfer(), but waits for completion. */
    984 usbd_status
    985 usbd_sync_transfer(reqh)
    986 	usbd_request_handle reqh;
    987 {
    988 	usbd_status r;
    989 	int s;
    990 
    991 	reqh->xfercb = usbd_sync_transfer_cb;
    992 	r = usbd_do_transfer(reqh);
    993 	if (r != USBD_IN_PROGRESS)
    994 		return (r);
    995 	s = splusb();
    996 	if (!reqh->done) {
    997 		if (reqh->pipe->device->bus->use_polling)
    998 			panic("usbd_sync_transfer: not done\n");
    999 		tsleep(reqh, PRIBIO, "usbsyn", 0);
   1000 	}
   1001 	splx(s);
   1002 	return (reqh->status);
   1003 }
   1004 
   1005 usbd_status
   1006 usbd_do_request(dev, req, data)
   1007 	usbd_device_handle dev;
   1008 	usb_device_request_t *req;
   1009 	void *data;
   1010 {
   1011 	return (usbd_do_request_flags(dev, req, data, 0, 0));
   1012 }
   1013 
   1014 usbd_status
   1015 usbd_do_request_flags(dev, req, data, flags, actlen)
   1016 	usbd_device_handle dev;
   1017 	usb_device_request_t *req;
   1018 	void *data;
   1019 	u_int16_t flags;
   1020 	int *actlen;
   1021 {
   1022 	usbd_request_handle reqh;
   1023 	usbd_status r;
   1024 
   1025 #ifdef DIAGNOSTIC
   1026 	if (!curproc) {
   1027 		printf("usbd_do_request: not in process context\n");
   1028 		return (USBD_XXX);
   1029 	}
   1030 #endif
   1031 
   1032 	reqh = usbd_alloc_request();
   1033 	if (reqh == 0)
   1034 		return (USBD_NOMEM);
   1035 	r = usbd_setup_default_request(
   1036 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
   1037 		UGETW(req->wLength), flags, 0);
   1038 	if (r != USBD_NORMAL_COMPLETION)
   1039 		goto bad;
   1040 	r = usbd_sync_transfer(reqh);
   1041 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
   1042 	if (reqh->actlen > reqh->length)
   1043 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
   1044 		       "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
   1045 		       dev->address, reqh->request.bmRequestType,
   1046 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
   1047 		       UGETW(reqh->request.wIndex),
   1048 		       UGETW(reqh->request.wLength),
   1049 		       reqh->length, reqh->actlen);
   1050 #endif
   1051 	if (actlen)
   1052 		*actlen = reqh->actlen;
   1053 	if (r == USBD_STALLED) {
   1054 		/*
   1055 		 * The control endpoint has stalled.  Control endpoints
   1056 		 * should not halt, but some may do so anyway so clear
   1057 		 * any halt condition.
   1058 		 */
   1059 		usb_device_request_t treq;
   1060 		usb_status_t status;
   1061 		u_int16_t s;
   1062 		usbd_status nr;
   1063 
   1064 		treq.bmRequestType = UT_READ_ENDPOINT;
   1065 		treq.bRequest = UR_GET_STATUS;
   1066 		USETW(treq.wValue, 0);
   1067 		USETW(treq.wIndex, 0);
   1068 		USETW(treq.wLength, sizeof(usb_status_t));
   1069 		nr = usbd_setup_default_request(
   1070 			reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
   1071 			sizeof(usb_status_t), 0, 0);
   1072 		if (nr != USBD_NORMAL_COMPLETION)
   1073 			goto bad;
   1074 		nr = usbd_sync_transfer(reqh);
   1075 		if (nr != USBD_NORMAL_COMPLETION)
   1076 			goto bad;
   1077 		s = UGETW(status.wStatus);
   1078 		DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
   1079 		if (!(s & UES_HALT))
   1080 			goto bad;
   1081 		treq.bmRequestType = UT_WRITE_ENDPOINT;
   1082 		treq.bRequest = UR_CLEAR_FEATURE;
   1083 		USETW(treq.wValue, UF_ENDPOINT_HALT);
   1084 		USETW(treq.wIndex, 0);
   1085 		USETW(treq.wLength, 0);
   1086 		nr = usbd_setup_default_request(
   1087 			reqh, dev, 0, USBD_DEFAULT_TIMEOUT, &treq, &status,
   1088 			0, 0, 0);
   1089 		if (nr != USBD_NORMAL_COMPLETION)
   1090 			goto bad;
   1091 		nr = usbd_sync_transfer(reqh);
   1092 		if (nr != USBD_NORMAL_COMPLETION)
   1093 			goto bad;
   1094 	}
   1095 
   1096  bad:
   1097 	usbd_free_request(reqh);
   1098 	return (r);
   1099 }
   1100 
   1101 void
   1102 usbd_do_request_async_cb(reqh, priv, status)
   1103 	usbd_request_handle reqh;
   1104 	usbd_private_handle priv;
   1105 	usbd_status status;
   1106 {
   1107 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
   1108 	if (reqh->actlen > reqh->length)
   1109 		printf("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
   1110 		       "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
   1111 		       reqh->pipe->device->address,
   1112 		       reqh->request.bmRequestType,
   1113 		       reqh->request.bRequest, UGETW(reqh->request.wValue),
   1114 		       UGETW(reqh->request.wIndex),
   1115 		       UGETW(reqh->request.wLength),
   1116 		       reqh->length, reqh->actlen);
   1117 #endif
   1118 	usbd_free_request(reqh);
   1119 }
   1120 
   1121 /*
   1122  * Execute a request without waiting for completion.
   1123  * Can be used from interrupt context.
   1124  */
   1125 usbd_status
   1126 usbd_do_request_async(dev, req, data)
   1127 	usbd_device_handle dev;
   1128 	usb_device_request_t *req;
   1129 	void *data;
   1130 {
   1131 	usbd_request_handle reqh;
   1132 	usbd_status r;
   1133 
   1134 	reqh = usbd_alloc_request();
   1135 	if (reqh == 0)
   1136 		return (USBD_NOMEM);
   1137 	r = usbd_setup_default_request(
   1138 		reqh, dev, 0, USBD_DEFAULT_TIMEOUT, req, data,
   1139 		UGETW(req->wLength), 0, usbd_do_request_async_cb);
   1140 	if (r != USBD_NORMAL_COMPLETION) {
   1141 		usbd_free_request(reqh);
   1142 		return (r);
   1143 	}
   1144 	r = usbd_transfer(reqh);
   1145 	if (r != USBD_IN_PROGRESS)
   1146 		return (r);
   1147 	return (USBD_NORMAL_COMPLETION);
   1148 }
   1149 
   1150 struct usbd_quirks *
   1151 usbd_get_quirks(dev)
   1152 	usbd_device_handle dev;
   1153 {
   1154 	return (dev->quirks);
   1155 }
   1156 
   1157 void
   1158 usbd_set_disco(p, hdl, data)
   1159 	usbd_pipe_handle p;
   1160 	void (*hdl) __P((void *));
   1161 	void *data;
   1162 {
   1163 	p->disco = hdl;
   1164 	p->discoarg = data;
   1165 }
   1166 
   1167 /* XXX do periodic free() of free list */
   1168 
   1169 /*
   1170  * Called from keyboard driver when in polling mode.
   1171  */
   1172 void
   1173 usbd_dopoll(iface)
   1174 	usbd_interface_handle iface;
   1175 {
   1176 	iface->device->bus->do_poll(iface->device->bus);
   1177 }
   1178 
   1179 void
   1180 usbd_set_polling(iface, on)
   1181 	usbd_interface_handle iface;
   1182 	int on;
   1183 {
   1184 	iface->device->bus->use_polling = on;
   1185 }
   1186 
   1187 
   1188 usb_endpoint_descriptor_t *
   1189 usbd_get_endpoint_descriptor(iface, address)
   1190 	usbd_interface_handle iface;
   1191 	u_int8_t address;
   1192 {
   1193 	struct usbd_endpoint *ep;
   1194 	int i;
   1195 
   1196 	for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
   1197 		ep = &iface->endpoints[i];
   1198 		if (ep->edesc->bEndpointAddress == address)
   1199 			return (iface->endpoints[i].edesc);
   1200 	}
   1201 	return (0);
   1202 }
   1203 
   1204 #if defined(__FreeBSD__)
   1205 void
   1206 usbd_print_child(device_t parent, device_t child)
   1207 {
   1208 	/*
   1209 	struct usb_softc *sc = device_get_softc(child);
   1210 	*/
   1211 
   1212 	printf(" at %s%d", device_get_name(parent), device_get_unit(parent));
   1213 
   1214 	/* XXX How do we get to the usbd_device_handle???
   1215 	usbd_device_handle dev = invalidadosch;
   1216 
   1217 	printf(" addr %d", dev->addr);
   1218 
   1219 	if (bootverbose) {
   1220 		if (dev->lowspeed)
   1221 			printf(", lowspeed");
   1222 		if (dev->self_powered)
   1223 			printf(", self powered");
   1224 		else
   1225 			printf(", %dmA", dev->power);
   1226 		printf(", config %d", dev->config);
   1227 	}
   1228 	 */
   1229 }
   1230 
   1231 /* Reconfigure all the USB busses in the system. */
   1232 int
   1233 usbd_driver_load(module_t mod, int what, void *arg)
   1234 {
   1235 	devclass_t usb_devclass = devclass_find("usb");
   1236 	devclass_t ugen_devclass = devclass_find("ugen");
   1237 	device_t *devlist;
   1238 	int devcount;
   1239 	int error;
   1240 
   1241 	switch (what) {
   1242 	case MOD_LOAD:
   1243 	case MOD_UNLOAD:
   1244 		if (!usb_devclass)
   1245 			return 0;	/* just ignore call */
   1246 
   1247 		if (ugen_devclass) {
   1248 			/* detach devices from generic driver if possible */
   1249 			error = devclass_get_devices(ugen_devclass, &devlist,
   1250 						     &devcount);
   1251 			if (!error)
   1252 				for (devcount--; devcount >= 0; devcount--)
   1253 					(void)DEVICE_DETACH(devlist[devcount]);
   1254 		}
   1255 
   1256 		error = devclass_get_devices(usb_devclass, &devlist, &devcount);
   1257 		if (error)
   1258 			return 0;	/* XXX maybe transient, or error? */
   1259 
   1260 		for (devcount--; devcount >= 0; devcount--)
   1261 			USB_RECONFIGURE(devlist[devcount]);
   1262 
   1263 		free(devlist, M_TEMP);
   1264 		return 0;
   1265 	}
   1266 
   1267 	return 0;			/* nothing to do by us */
   1268 }
   1269 
   1270 /* Set the description of the device including a malloc and copy. */
   1271 void
   1272 usbd_device_set_desc(device_t device, char *devinfo)
   1273 {
   1274 	size_t l;
   1275 	char *desc;
   1276 
   1277 	if ( devinfo ) {
   1278 		l = strlen(devinfo);
   1279 		desc = malloc(l+1, M_USB, M_NOWAIT);
   1280 		if (desc)
   1281 			memcpy(desc, devinfo, l+1);
   1282 	} else
   1283 		desc = NULL;
   1284 
   1285 	device_set_desc(device, desc);
   1286 }
   1287 
   1288 char *
   1289 usbd_devname(bdevice *bdev)
   1290 {
   1291 	static char buf[20];
   1292 	/*
   1293 	 * A static buffer is a loss if this routine is used from an interrupt,
   1294 	 * but it's not fatal.
   1295 	 */
   1296 
   1297 	sprintf(buf, "%s%d", device_get_name(*bdev), device_get_unit(*bdev));
   1298 	return (buf);
   1299 }
   1300 
   1301 #endif
   1302