]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/usb/usbdi.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / usb / usbdi.c
1 /*      $NetBSD: usbdi.c,v 1.106 2004/10/24 12:52:40 augustss Exp $     */
2
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
5
6 /*-
7  * Copyright (c) 1998 The NetBSD Foundation, Inc.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to The NetBSD Foundation
11  * by Lennart Augustsson (lennart@augustsson.net) at
12  * Carlstedt Research & Technology.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *        This product includes software developed by the NetBSD
25  *        Foundation, Inc. and its contributors.
26  * 4. Neither the name of The NetBSD Foundation nor the names of its
27  *    contributors may be used to endorse or promote products derived
28  *    from this software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40  * POSSIBILITY OF SUCH DAMAGE.
41  */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/module.h>
46 #include <sys/bus.h>
47 #include "usb_if.h"
48 #if defined(DIAGNOSTIC) && defined(__i386__)
49 #include <machine/cpu.h>
50 #endif
51 #include <sys/malloc.h>
52 #include <sys/proc.h>
53
54 #include <machine/bus.h>
55
56 #include <dev/usb/usb.h>
57 #include <dev/usb/usbdi.h>
58 #include <dev/usb/usbdi_util.h>
59 #include <dev/usb/usbdivar.h>
60 #include <dev/usb/usb_mem.h>
61 #include <dev/usb/usb_quirks.h>
62
63 #include "usb_if.h"
64 #define delay(d)        DELAY(d)
65
66 #ifdef USB_DEBUG
67 #define DPRINTF(x)      if (usbdebug) printf x
68 #define DPRINTFN(n,x)   if (usbdebug>(n)) printf x
69 extern int usbdebug;
70 #else
71 #define DPRINTF(x)
72 #define DPRINTFN(n,x)
73 #endif
74
75 static usbd_status usbd_ar_pipe(usbd_pipe_handle pipe);
76 static void usbd_do_request_async_cb
77         (usbd_xfer_handle, usbd_private_handle, usbd_status);
78 static void usbd_start_next(usbd_pipe_handle pipe);
79 static usbd_status usbd_open_pipe_ival
80         (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int);
81 static int usbd_xfer_isread(usbd_xfer_handle xfer);
82 static void usbd_start_transfer(void *arg, bus_dma_segment_t *segs, int nseg,
83     int error);
84 static void usbd_alloc_callback(void *arg, bus_dma_segment_t *segs, int nseg,
85     int error);
86
87 static int usbd_nbuses = 0;
88
89 void
90 usbd_init(void)
91 {
92         usbd_nbuses++;
93 }
94
95 void
96 usbd_finish(void)
97 {
98         --usbd_nbuses;
99 }
100
101 static __inline int
102 usbd_xfer_isread(usbd_xfer_handle xfer)
103 {
104         if (xfer->rqflags & URQ_REQUEST)
105                 return (xfer->request.bmRequestType & UT_READ);
106         else
107                 return (xfer->pipe->endpoint->edesc->bEndpointAddress &
108                         UE_DIR_IN);
109 }
110
111 #ifdef USB_DEBUG
112 void
113 usbd_dump_iface(struct usbd_interface *iface)
114 {
115         printf("usbd_dump_iface: iface=%p\n", iface);
116         if (iface == NULL)
117                 return;
118         printf(" device=%p idesc=%p index=%d altindex=%d priv=%p\n",
119                iface->device, iface->idesc, iface->index, iface->altindex,
120                iface->priv);
121 }
122
123 void
124 usbd_dump_device(struct usbd_device *dev)
125 {
126         printf("usbd_dump_device: dev=%p\n", dev);
127         if (dev == NULL)
128                 return;
129         printf(" bus=%p default_pipe=%p\n", dev->bus, dev->default_pipe);
130         printf(" address=%d config=%d depth=%d speed=%d self_powered=%d "
131                "power=%d langid=%d\n",
132                dev->address, dev->config, dev->depth, dev->speed,
133                dev->self_powered, dev->power, dev->langid);
134 }
135
136 void
137 usbd_dump_endpoint(struct usbd_endpoint *endp)
138 {
139         printf("usbd_dump_endpoint: endp=%p\n", endp);
140         if (endp == NULL)
141                 return;
142         printf(" edesc=%p refcnt=%d\n", endp->edesc, endp->refcnt);
143         if (endp->edesc)
144                 printf(" bEndpointAddress=0x%02x\n",
145                        endp->edesc->bEndpointAddress);
146 }
147
148 void
149 usbd_dump_queue(usbd_pipe_handle pipe)
150 {
151         usbd_xfer_handle xfer;
152
153         printf("usbd_dump_queue: pipe=%p\n", pipe);
154         STAILQ_FOREACH(xfer, &pipe->queue, next) {
155                 printf("  xfer=%p\n", xfer);
156         }
157 }
158
159 void
160 usbd_dump_pipe(usbd_pipe_handle pipe)
161 {
162         printf("usbd_dump_pipe: pipe=%p\n", pipe);
163         if (pipe == NULL)
164                 return;
165         usbd_dump_iface(pipe->iface);
166         usbd_dump_device(pipe->device);
167         usbd_dump_endpoint(pipe->endpoint);
168         printf(" (usbd_dump_pipe:)\n refcnt=%d running=%d aborting=%d\n",
169                pipe->refcnt, pipe->running, pipe->aborting);
170         printf(" intrxfer=%p, repeat=%d, interval=%d\n",
171                pipe->intrxfer, pipe->repeat, pipe->interval);
172 }
173 #endif
174
175 usbd_status
176 usbd_open_pipe(usbd_interface_handle iface, u_int8_t address,
177                u_int8_t flags, usbd_pipe_handle *pipe)
178 {
179         return (usbd_open_pipe_ival(iface, address, flags, pipe,
180                                     USBD_DEFAULT_INTERVAL));
181 }
182
183 usbd_status
184 usbd_open_pipe_ival(usbd_interface_handle iface, u_int8_t address,
185                     u_int8_t flags, usbd_pipe_handle *pipe, int ival)
186 {
187         usbd_pipe_handle p;
188         struct usbd_endpoint *ep;
189         usbd_status err;
190         int i;
191
192         DPRINTFN(3,("usbd_open_pipe: iface=%p address=0x%x flags=0x%x\n",
193                     iface, address, flags));
194
195         for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
196                 ep = &iface->endpoints[i];
197                 if (ep->edesc == NULL)
198                         return (USBD_IOERROR);
199                 if (ep->edesc->bEndpointAddress == address)
200                         goto found;
201         }
202         return (USBD_BAD_ADDRESS);
203  found:
204         if ((flags & USBD_EXCLUSIVE_USE) && ep->refcnt != 0)
205                 return (USBD_IN_USE);
206         err = usbd_setup_pipe(iface->device, iface, ep, ival, &p);
207         if (err)
208                 return (err);
209         LIST_INSERT_HEAD(&iface->pipes, p, next);
210         *pipe = p;
211         return (USBD_NORMAL_COMPLETION);
212 }
213
214 usbd_status
215 usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address,
216                     u_int8_t flags, usbd_pipe_handle *pipe,
217                     usbd_private_handle priv, void *buffer, u_int32_t len,
218                     usbd_callback cb, int ival)
219 {
220         usbd_status err;
221         usbd_xfer_handle xfer;
222         usbd_pipe_handle ipipe;
223
224         DPRINTFN(3,("usbd_open_pipe_intr: address=0x%x flags=0x%x len=%d\n",
225                     address, flags, len));
226
227         err = usbd_open_pipe_ival(iface, address, USBD_EXCLUSIVE_USE,
228                                   &ipipe, ival);
229         if (err)
230                 return (err);
231         xfer = usbd_alloc_xfer(iface->device);
232         if (xfer == NULL) {
233                 err = USBD_NOMEM;
234                 goto bad1;
235         }
236         usbd_setup_xfer(xfer, ipipe, priv, buffer, len, flags,
237             USBD_NO_TIMEOUT, cb);
238         ipipe->intrxfer = xfer;
239         ipipe->repeat = 1;
240         err = usbd_transfer(xfer);
241         *pipe = ipipe;
242         if (err != USBD_IN_PROGRESS && err)
243                 goto bad2;
244         return (USBD_NORMAL_COMPLETION);
245
246  bad2:
247         ipipe->intrxfer = NULL;
248         ipipe->repeat = 0;
249         usbd_free_xfer(xfer);
250  bad1:
251         usbd_close_pipe(ipipe);
252         return (err);
253 }
254
255 usbd_status
256 usbd_close_pipe(usbd_pipe_handle pipe)
257 {
258 #ifdef DIAGNOSTIC
259         if (pipe == NULL) {
260                 printf("usbd_close_pipe: pipe==NULL\n");
261                 return (USBD_NORMAL_COMPLETION);
262         }
263 #endif
264
265         if (--pipe->refcnt != 0)
266                 return (USBD_NORMAL_COMPLETION);
267         if (! STAILQ_EMPTY(&pipe->queue))
268                 return (USBD_PENDING_REQUESTS);
269         LIST_REMOVE(pipe, next);
270         pipe->endpoint->refcnt--;
271         pipe->methods->close(pipe);
272         if (pipe->intrxfer != NULL)
273                 usbd_free_xfer(pipe->intrxfer);
274         free(pipe, M_USB);
275         return (USBD_NORMAL_COMPLETION);
276 }
277
278 usbd_status
279 usbd_transfer(usbd_xfer_handle xfer)
280 {
281         usbd_pipe_handle pipe = xfer->pipe;
282         struct usb_dma_mapping *dmap = &xfer->dmamap;
283         usbd_status err;
284         u_int size;
285         int s;
286
287         DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%d, pipe=%p, running=%d\n",
288                     xfer, xfer->flags, pipe, pipe->running));
289 #ifdef USB_DEBUG
290         if (usbdebug > 5)
291                 usbd_dump_queue(pipe);
292 #endif
293         xfer->done = 0;
294
295         if (pipe->aborting)
296                 return (USBD_CANCELLED);
297
298         size = xfer->length;
299         /* If there is no buffer, allocate one. */
300         if (!(xfer->rqflags & URQ_DEV_DMABUF) && size != 0) {
301                 bus_dma_tag_t tag = pipe->device->bus->buffer_dmatag;
302
303 #ifdef DIAGNOSTIC
304                 if (xfer->rqflags & URQ_AUTO_DMABUF)
305                         printf("usbd_transfer: has old buffer!\n");
306 #endif
307                 err = bus_dmamap_create(tag, 0, &dmap->map);
308                 if (err)
309                         return (USBD_NOMEM);
310
311                 xfer->rqflags |= URQ_AUTO_DMABUF;
312                 err = bus_dmamap_load(tag, dmap->map, xfer->buffer, size,
313                     usbd_start_transfer, xfer, 0);
314                 if (err != 0 && err != EINPROGRESS) {
315                         xfer->rqflags &= ~URQ_AUTO_DMABUF;
316                         bus_dmamap_destroy(tag, dmap->map);
317                         return (USBD_INVAL);
318                 }
319         } else if (size != 0) {
320                 usbd_start_transfer(xfer, dmap->segs, dmap->nsegs, 0);
321         } else {
322                 usbd_start_transfer(xfer, NULL, 0, 0);
323         }
324
325         if (!(xfer->flags & USBD_SYNCHRONOUS))
326                 return (xfer->done ? 0 : USBD_IN_PROGRESS);
327
328         /* Sync transfer, wait for completion. */
329         s = splusb();
330         while (!xfer->done) {
331                 if (pipe->device->bus->use_polling)
332                         panic("usbd_transfer: not done");
333                 tsleep(xfer, PRIBIO, "usbsyn", 0);
334         }
335         splx(s);
336         return (xfer->status);
337 }
338
339 static void
340 usbd_start_transfer(void *arg, bus_dma_segment_t *segs, int nseg, int error)
341 {
342         usbd_xfer_handle xfer = arg;
343         usbd_pipe_handle pipe = xfer->pipe;
344         struct usb_dma_mapping *dmap = &xfer->dmamap;
345         bus_dma_tag_t tag = pipe->device->bus->buffer_dmatag;
346         int err, i;
347
348         if (error != 0) {
349                 KASSERT(xfer->rqflags & URQ_AUTO_DMABUF,
350                     ("usbd_start_transfer: error with non-auto buf"));
351                 if (nseg > 0)
352                         bus_dmamap_unload(tag, dmap->map);
353                 bus_dmamap_destroy(tag, dmap->map);
354                 /* XXX */
355                 usb_insert_transfer(xfer);
356                 xfer->status = USBD_IOERROR;
357                 usb_transfer_complete(xfer);
358                 return;
359         }
360
361         if (segs != dmap->segs) {
362                 for (i = 0; i < nseg; i++)
363                         dmap->segs[i] = segs[i];
364         }
365         dmap->nsegs = nseg;
366
367         if (nseg > 0) {
368                 if (!usbd_xfer_isread(xfer)) {
369                         /*
370                          * Copy data if it is not already in the correct
371                          * buffer.
372                          */
373                         if (!(xfer->flags & USBD_NO_COPY) &&
374                             xfer->allocbuf != NULL &&
375                             xfer->buffer != xfer->allocbuf)
376                                 memcpy(xfer->allocbuf, xfer->buffer,
377                                     xfer->length);
378                         bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREWRITE);
379                 } else if (xfer->rqflags & URQ_REQUEST) {
380                         /*
381                          * Even if we have no data portion we still need to
382                          * sync the dmamap for the request data in the SETUP
383                          * packet.
384                          */
385                         bus_dmamap_sync(tag, dmap->map,
386                             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
387                 } else
388                         bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_PREREAD);
389         }
390         err = pipe->methods->transfer(xfer);
391         if (err != USBD_IN_PROGRESS && err) {
392                 if (xfer->rqflags & URQ_AUTO_DMABUF) {
393                         bus_dmamap_unload(tag, dmap->map);
394                         bus_dmamap_destroy(tag, dmap->map);
395                         xfer->rqflags &= ~URQ_AUTO_DMABUF;
396                 }
397                 xfer->status = err;
398                 usb_transfer_complete(xfer);
399                 return;
400         }
401 }
402
403 /* Like usbd_transfer(), but waits for completion. */
404 usbd_status
405 usbd_sync_transfer(usbd_xfer_handle xfer)
406 {
407         xfer->flags |= USBD_SYNCHRONOUS;
408         return (usbd_transfer(xfer));
409 }
410
411 struct usbd_allocstate {
412         usbd_xfer_handle xfer;
413         int done;
414         int error;
415         int waiting;
416 };
417
418 void *
419 usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size)
420 {
421         struct usbd_allocstate allocstate;
422         struct usb_dma_mapping *dmap = &xfer->dmamap;
423         bus_dma_tag_t tag = xfer->device->bus->buffer_dmatag;
424         void *buf;
425         usbd_status err;
426         int error, s;
427
428         KASSERT((xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) == 0,
429             ("usbd_alloc_buffer: xfer already has a buffer"));
430         err = bus_dmamap_create(tag, 0, &dmap->map);
431         if (err)
432                 return (NULL);
433         buf = malloc(size, M_USB, M_WAITOK);
434
435         allocstate.xfer = xfer;
436         allocstate.done = 0;
437         allocstate.error = 0;
438         allocstate.waiting = 0;
439         error = bus_dmamap_load(tag, dmap->map, buf, size, usbd_alloc_callback,
440             &allocstate, 0);
441         if (error && error != EINPROGRESS) {
442                 bus_dmamap_destroy(tag, dmap->map);
443                 free(buf, M_USB);
444                 return (NULL);
445         }
446         if (error == EINPROGRESS) {
447                 /* Wait for completion. */
448                 s = splusb();
449                 allocstate.waiting = 1;
450                 while (!allocstate.done)
451                         tsleep(&allocstate, PRIBIO, "usbdab", 0);
452                 splx(s);
453                 error = allocstate.error;
454         }
455         if (error) {
456                 bus_dmamap_unload(tag, dmap->map);
457                 bus_dmamap_destroy(tag, dmap->map);
458                 free(buf, M_USB);
459                 return (NULL);
460         }
461
462         xfer->allocbuf = buf;
463         xfer->rqflags |= URQ_DEV_DMABUF;
464         return (buf);
465 }
466
467 void
468 usbd_free_buffer(usbd_xfer_handle xfer)
469 {
470         struct usb_dma_mapping *dmap = &xfer->dmamap;
471         bus_dma_tag_t tag = xfer->device->bus->buffer_dmatag;
472
473         KASSERT((xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF)) ==
474             URQ_DEV_DMABUF, ("usbd_free_buffer: no/auto buffer"));
475
476         xfer->rqflags &= ~URQ_DEV_DMABUF;
477         bus_dmamap_unload(tag, dmap->map);
478         bus_dmamap_destroy(tag, dmap->map);
479         free(xfer->allocbuf, M_USB);
480         xfer->allocbuf = NULL;
481 }
482
483 void *
484 usbd_get_buffer(usbd_xfer_handle xfer)
485 {
486         if (!(xfer->rqflags & URQ_DEV_DMABUF))
487                 return (NULL);
488         return (xfer->allocbuf);
489 }
490
491 static void
492 usbd_alloc_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
493 {
494         struct usbd_allocstate *allocstate = arg;
495         usbd_xfer_handle xfer = allocstate->xfer;
496         struct usb_dma_mapping *dmap = &xfer->dmamap;
497         int i;
498
499         allocstate->error = error;
500         if (error == 0) {
501                 for (i = 0; i < nseg; i++)
502                         dmap->segs[i] = segs[i];
503                 dmap->nsegs = nseg;
504         }
505         allocstate->done = 1;
506         if (allocstate->waiting)
507                 wakeup(&allocstate);
508 }
509
510 usbd_xfer_handle
511 usbd_alloc_xfer(usbd_device_handle dev)
512 {
513         usbd_xfer_handle xfer;
514
515         xfer = dev->bus->methods->allocx(dev->bus);
516         if (xfer == NULL)
517                 return (NULL);
518         xfer->device = dev;
519         callout_init(&xfer->timeout_handle, 0);
520         DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer));
521         return (xfer);
522 }
523
524 usbd_status
525 usbd_free_xfer(usbd_xfer_handle xfer)
526 {
527         DPRINTFN(5,("usbd_free_xfer: %p\n", xfer));
528         if (xfer->rqflags & URQ_DEV_DMABUF)
529                 usbd_free_buffer(xfer);
530 /* XXX Does FreeBSD need to do something similar? */
531 #if defined(__NetBSD__) && defined(DIAGNOSTIC)
532         if (callout_pending(&xfer->timeout_handle)) {
533                 callout_stop(&xfer->timeout_handle);
534                 printf("usbd_free_xfer: timout_handle pending");
535         }
536 #endif
537         xfer->device->bus->methods->freex(xfer->device->bus, xfer);
538         return (USBD_NORMAL_COMPLETION);
539 }
540
541 void
542 usbd_setup_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
543                 usbd_private_handle priv, void *buffer, u_int32_t length,
544                 u_int16_t flags, u_int32_t timeout,
545                 usbd_callback callback)
546 {
547         xfer->pipe = pipe;
548         xfer->priv = priv;
549         xfer->buffer = buffer;
550         xfer->length = length;
551         xfer->actlen = 0;
552         xfer->flags = flags;
553         xfer->timeout = timeout;
554         xfer->status = USBD_NOT_STARTED;
555         xfer->callback = callback;
556         xfer->rqflags &= ~URQ_REQUEST;
557         xfer->nframes = 0;
558 }
559
560 void
561 usbd_setup_default_xfer(usbd_xfer_handle xfer, usbd_device_handle dev,
562                         usbd_private_handle priv, u_int32_t timeout,
563                         usb_device_request_t *req, void *buffer,
564                         u_int32_t length, u_int16_t flags,
565                         usbd_callback callback)
566 {
567         xfer->pipe = dev->default_pipe;
568         xfer->priv = priv;
569         xfer->buffer = buffer;
570         xfer->length = length;
571         xfer->actlen = 0;
572         xfer->flags = flags;
573         xfer->timeout = timeout;
574         xfer->status = USBD_NOT_STARTED;
575         xfer->callback = callback;
576         xfer->request = *req;
577         xfer->rqflags |= URQ_REQUEST;
578         xfer->nframes = 0;
579 }
580
581 void
582 usbd_setup_isoc_xfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
583                      usbd_private_handle priv, u_int16_t *frlengths,
584                      u_int32_t nframes, u_int16_t flags, usbd_callback callback)
585 {
586         int i;
587
588         xfer->pipe = pipe;
589         xfer->priv = priv;
590         xfer->buffer = 0;
591         xfer->length = 0;
592         for (i = 0; i < nframes; i++)
593                 xfer->length += frlengths[i];
594         xfer->actlen = 0;
595         xfer->flags = flags;
596         xfer->timeout = USBD_NO_TIMEOUT;
597         xfer->status = USBD_NOT_STARTED;
598         xfer->callback = callback;
599         xfer->rqflags &= ~URQ_REQUEST;
600         xfer->frlengths = frlengths;
601         xfer->nframes = nframes;
602 }
603
604 void
605 usbd_get_xfer_status(usbd_xfer_handle xfer, usbd_private_handle *priv,
606                      void **buffer, u_int32_t *count, usbd_status *status)
607 {
608         if (priv != NULL)
609                 *priv = xfer->priv;
610         if (buffer != NULL)
611                 *buffer = xfer->buffer;
612         if (count != NULL)
613                 *count = xfer->actlen;
614         if (status != NULL)
615                 *status = xfer->status;
616 }
617
618 usb_config_descriptor_t *
619 usbd_get_config_descriptor(usbd_device_handle dev)
620 {
621 #ifdef DIAGNOSTIC
622         if (dev == NULL) {
623                 printf("usbd_get_config_descriptor: dev == NULL\n");
624                 return (NULL);
625         }
626 #endif
627         return (dev->cdesc);
628 }
629
630 int
631 usbd_get_speed(usbd_device_handle dev)
632 {
633         return (dev->speed);
634 }
635
636 usb_interface_descriptor_t *
637 usbd_get_interface_descriptor(usbd_interface_handle iface)
638 {
639 #ifdef DIAGNOSTIC
640         if (iface == NULL) {
641                 printf("usbd_get_interface_descriptor: dev == NULL\n");
642                 return (NULL);
643         }
644 #endif
645         return (iface->idesc);
646 }
647
648 usb_device_descriptor_t *
649 usbd_get_device_descriptor(usbd_device_handle dev)
650 {
651         return (&dev->ddesc);
652 }
653
654 usb_endpoint_descriptor_t *
655 usbd_interface2endpoint_descriptor(usbd_interface_handle iface, u_int8_t index)
656 {
657         if (index >= iface->idesc->bNumEndpoints)
658                 return (0);
659         return (iface->endpoints[index].edesc);
660 }
661
662 usbd_status
663 usbd_abort_pipe(usbd_pipe_handle pipe)
664 {
665         usbd_status err;
666         int s;
667
668 #ifdef DIAGNOSTIC
669         if (pipe == NULL) {
670                 printf("usbd_close_pipe: pipe==NULL\n");
671                 return (USBD_NORMAL_COMPLETION);
672         }
673 #endif
674         s = splusb();
675         err = usbd_ar_pipe(pipe);
676         splx(s);
677         return (err);
678 }
679
680 usbd_status
681 usbd_abort_default_pipe(usbd_device_handle dev)
682 {
683         return (usbd_abort_pipe(dev->default_pipe));
684 }
685
686 usbd_status
687 usbd_clear_endpoint_stall(usbd_pipe_handle pipe)
688 {
689         usbd_device_handle dev = pipe->device;
690         usb_device_request_t req;
691         usbd_status err;
692
693         DPRINTFN(8, ("usbd_clear_endpoint_stall\n"));
694
695         /*
696          * Clearing en endpoint stall resets the endpoint toggle, so
697          * do the same to the HC toggle.
698          */
699         pipe->methods->cleartoggle(pipe);
700
701         req.bmRequestType = UT_WRITE_ENDPOINT;
702         req.bRequest = UR_CLEAR_FEATURE;
703         USETW(req.wValue, UF_ENDPOINT_HALT);
704         USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
705         USETW(req.wLength, 0);
706         err = usbd_do_request(dev, &req, 0);
707 #if 0
708 XXX should we do this?
709         if (!err) {
710                 pipe->state = USBD_PIPE_ACTIVE;
711                 /* XXX activate pipe */
712         }
713 #endif
714         return (err);
715 }
716
717 usbd_status
718 usbd_clear_endpoint_stall_async(usbd_pipe_handle pipe)
719 {
720         usbd_device_handle dev = pipe->device;
721         usb_device_request_t req;
722         usbd_status err;
723
724         pipe->methods->cleartoggle(pipe);
725
726         req.bmRequestType = UT_WRITE_ENDPOINT;
727         req.bRequest = UR_CLEAR_FEATURE;
728         USETW(req.wValue, UF_ENDPOINT_HALT);
729         USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);
730         USETW(req.wLength, 0);
731         err = usbd_do_request_async(dev, &req, 0);
732         return (err);
733 }
734
735 void
736 usbd_clear_endpoint_toggle(usbd_pipe_handle pipe)
737 {
738         pipe->methods->cleartoggle(pipe);
739 }
740
741 usbd_status
742 usbd_endpoint_count(usbd_interface_handle iface, u_int8_t *count)
743 {
744 #ifdef DIAGNOSTIC
745         if (iface == NULL || iface->idesc == NULL) {
746                 printf("usbd_endpoint_count: NULL pointer\n");
747                 return (USBD_INVAL);
748         }
749 #endif
750         *count = iface->idesc->bNumEndpoints;
751         return (USBD_NORMAL_COMPLETION);
752 }
753
754 usbd_status
755 usbd_interface_count(usbd_device_handle dev, u_int8_t *count)
756 {
757         if (dev->cdesc == NULL)
758                 return (USBD_NOT_CONFIGURED);
759         *count = dev->cdesc->bNumInterface;
760         return (USBD_NORMAL_COMPLETION);
761 }
762
763 void
764 usbd_interface2device_handle(usbd_interface_handle iface,
765                              usbd_device_handle *dev)
766 {
767         *dev = iface->device;
768 }
769
770 usbd_status
771 usbd_device2interface_handle(usbd_device_handle dev,
772                              u_int8_t ifaceno, usbd_interface_handle *iface)
773 {
774         if (dev->cdesc == NULL)
775                 return (USBD_NOT_CONFIGURED);
776         if (ifaceno >= dev->cdesc->bNumInterface)
777                 return (USBD_INVAL);
778         *iface = &dev->ifaces[ifaceno];
779         return (USBD_NORMAL_COMPLETION);
780 }
781
782 usbd_device_handle
783 usbd_pipe2device_handle(usbd_pipe_handle pipe)
784 {
785         return (pipe->device);
786 }
787
788 /* XXXX use altno */
789 usbd_status
790 usbd_set_interface(usbd_interface_handle iface, int altidx)
791 {
792         usb_device_request_t req;
793         usbd_status err;
794         void *endpoints;
795
796         if (LIST_FIRST(&iface->pipes) != 0)
797                 return (USBD_IN_USE);
798
799         endpoints = iface->endpoints;
800         err = usbd_fill_iface_data(iface->device, iface->index, altidx);
801         if (err)
802                 return (err);
803
804         /* new setting works, we can free old endpoints */
805         if (endpoints != NULL)
806                 free(endpoints, M_USB);
807
808 #ifdef DIAGNOSTIC
809         if (iface->idesc == NULL) {
810                 printf("usbd_set_interface: NULL pointer\n");
811                 return (USBD_INVAL);
812         }
813 #endif
814
815         req.bmRequestType = UT_WRITE_INTERFACE;
816         req.bRequest = UR_SET_INTERFACE;
817         USETW(req.wValue, iface->idesc->bAlternateSetting);
818         USETW(req.wIndex, iface->idesc->bInterfaceNumber);
819         USETW(req.wLength, 0);
820         return (usbd_do_request(iface->device, &req, 0));
821 }
822
823 int
824 usbd_get_no_alts(usb_config_descriptor_t *cdesc, int ifaceno)
825 {
826         char *p = (char *)cdesc;
827         char *end = p + UGETW(cdesc->wTotalLength);
828         usb_interface_descriptor_t *d;
829         int n;
830
831         for (n = 0; p < end; p += d->bLength) {
832                 d = (usb_interface_descriptor_t *)p;
833                 if (p + d->bLength <= end &&
834                     d->bDescriptorType == UDESC_INTERFACE &&
835                     d->bInterfaceNumber == ifaceno)
836                         n++;
837         }
838         return (n);
839 }
840
841 int
842 usbd_get_interface_altindex(usbd_interface_handle iface)
843 {
844         return (iface->altindex);
845 }
846
847 usbd_status
848 usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface)
849 {
850         usb_device_request_t req;
851
852         req.bmRequestType = UT_READ_INTERFACE;
853         req.bRequest = UR_GET_INTERFACE;
854         USETW(req.wValue, 0);
855         USETW(req.wIndex, iface->idesc->bInterfaceNumber);
856         USETW(req.wLength, 1);
857         return (usbd_do_request(iface->device, &req, aiface));
858 }
859
860 /*** Internal routines ***/
861
862 /* Dequeue all pipe operations, called at splusb(). */
863 static usbd_status
864 usbd_ar_pipe(usbd_pipe_handle pipe)
865 {
866         usbd_xfer_handle xfer;
867
868         SPLUSBCHECK;
869
870         DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
871 #ifdef USB_DEBUG
872         if (usbdebug > 5)
873                 usbd_dump_queue(pipe);
874 #endif
875         pipe->repeat = 0;
876         pipe->aborting = 1;
877         while ((xfer = STAILQ_FIRST(&pipe->queue)) != NULL) {
878                 DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n",
879                             pipe, xfer, pipe->methods));
880                 /* Make the HC abort it (and invoke the callback). */
881                 pipe->methods->abort(xfer);
882                 KASSERT(STAILQ_FIRST(&pipe->queue) != xfer, ("usbd_ar_pipe"));
883                 /* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
884         }
885         pipe->aborting = 0;
886         return (USBD_NORMAL_COMPLETION);
887 }
888
889 /* Called at splusb() */
890 void
891 usb_transfer_complete(usbd_xfer_handle xfer)
892 {
893         usbd_pipe_handle pipe = xfer->pipe;
894         struct usb_dma_mapping *dmap = &xfer->dmamap;
895         bus_dma_tag_t tag = pipe->device->bus->buffer_dmatag;
896         int sync = xfer->flags & USBD_SYNCHRONOUS;
897         int erred = xfer->status == USBD_CANCELLED ||
898             xfer->status == USBD_TIMEOUT;
899         int repeat = pipe->repeat;
900         int polling;
901
902         SPLUSBCHECK;
903
904         DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d "
905                      "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen));
906 #ifdef DIAGNOSTIC
907         if (xfer->busy_free != XFER_ONQU) {
908                 printf("usb_transfer_complete: xfer=%p not busy 0x%08x\n",
909                        xfer, xfer->busy_free);
910                 return;
911         }
912 #endif
913
914 #ifdef DIAGNOSTIC
915         if (pipe == NULL) {
916                 printf("usbd_transfer_cb: pipe==0, xfer=%p\n", xfer);
917                 return;
918         }
919 #endif
920         polling = pipe->device->bus->use_polling;
921         /* XXXX */
922         if (polling)
923                 pipe->running = 0;
924
925         if (xfer->actlen != 0 && usbd_xfer_isread(xfer)) {
926                 bus_dmamap_sync(tag, dmap->map, BUS_DMASYNC_POSTREAD);
927                 /* Copy data if it is not already in the correct buffer. */
928                 if (!(xfer->flags & USBD_NO_COPY) && xfer->allocbuf != NULL &&
929                     xfer->buffer != xfer->allocbuf)
930                         memcpy(xfer->buffer, xfer->allocbuf, xfer->actlen);
931         }
932
933         /* if we mapped the buffer in usbd_transfer() we unmap it here. */
934         if (xfer->rqflags & URQ_AUTO_DMABUF) {
935                 if (!repeat) {
936                         bus_dmamap_unload(tag, dmap->map);
937                         bus_dmamap_destroy(tag, dmap->map);
938                         xfer->rqflags &= ~URQ_AUTO_DMABUF;
939                 }
940         }
941
942         if (!repeat) {
943                 /* Remove request from queue. */
944 #ifdef DIAGNOSTIC
945                 xfer->busy_free = XFER_BUSY;
946 #endif
947                 KASSERT(STAILQ_FIRST(&pipe->queue) == xfer,
948                     ("usb_transfer_complete: bad dequeue"));
949                 STAILQ_REMOVE_HEAD(&pipe->queue, next);
950         }
951         DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n",
952                     repeat, STAILQ_FIRST(&pipe->queue)));
953
954         /* Count completed transfers. */
955         ++pipe->device->bus->stats.uds_requests
956                 [pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE];
957
958         xfer->done = 1;
959         if (!xfer->status && xfer->actlen < xfer->length &&
960             !(xfer->flags & USBD_SHORT_XFER_OK)) {
961                 DPRINTFN(-1,("usbd_transfer_cb: short transfer %d<%d\n",
962                              xfer->actlen, xfer->length));
963                 xfer->status = USBD_SHORT_XFER;
964         }
965
966         /*
967          * For repeat operations, call the callback first, as the xfer
968          * will not go away and the "done" method may modify it. Otherwise
969          * reverse the order in case the callback wants to free or reuse
970          * the xfer.
971          */
972         if (repeat) {
973                 if (xfer->callback)
974                         xfer->callback(xfer, xfer->priv, xfer->status);
975                 pipe->methods->done(xfer);
976         } else {
977                 pipe->methods->done(xfer);
978                 if (xfer->callback)
979                         xfer->callback(xfer, xfer->priv, xfer->status);
980         }
981
982         if (sync && !polling)
983                 wakeup(xfer);
984
985         if (!repeat) {
986                 /* XXX should we stop the queue on all errors? */
987                 if (erred && pipe->iface != NULL)       /* not control pipe */
988                         pipe->running = 0;
989                 else
990                         usbd_start_next(pipe);
991         }
992 }
993
994 usbd_status
995 usb_insert_transfer(usbd_xfer_handle xfer)
996 {
997         usbd_pipe_handle pipe = xfer->pipe;
998         usbd_status err;
999         int s;
1000
1001         DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n",
1002                     pipe, pipe->running, xfer->timeout));
1003 #ifdef DIAGNOSTIC
1004         if (xfer->busy_free != XFER_BUSY) {
1005                 printf("usb_insert_transfer: xfer=%p not busy 0x%08x\n",
1006                        xfer, xfer->busy_free);
1007                 return (USBD_INVAL);
1008         }
1009         xfer->busy_free = XFER_ONQU;
1010 #endif
1011         s = splusb();
1012         KASSERT(STAILQ_FIRST(&pipe->queue) != xfer, ("usb_insert_transfer"));
1013         STAILQ_INSERT_TAIL(&pipe->queue, xfer, next);
1014         if (pipe->running)
1015                 err = USBD_IN_PROGRESS;
1016         else {
1017                 pipe->running = 1;
1018                 err = USBD_NORMAL_COMPLETION;
1019         }
1020         splx(s);
1021         return (err);
1022 }
1023
1024 /* Called at splusb() */
1025 void
1026 usbd_start_next(usbd_pipe_handle pipe)
1027 {
1028         usbd_xfer_handle xfer;
1029         usbd_status err;
1030
1031         SPLUSBCHECK;
1032
1033 #ifdef DIAGNOSTIC
1034         if (pipe == NULL) {
1035                 printf("usbd_start_next: pipe == NULL\n");
1036                 return;
1037         }
1038         if (pipe->methods == NULL || pipe->methods->start == NULL) {
1039                 printf("usbd_start_next: pipe=%p no start method\n", pipe);
1040                 return;
1041         }
1042 #endif
1043
1044         /* Get next request in queue. */
1045         xfer = STAILQ_FIRST(&pipe->queue);
1046         DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer));
1047         if (xfer == NULL) {
1048                 pipe->running = 0;
1049         } else {
1050                 err = pipe->methods->start(xfer);
1051                 if (err != USBD_IN_PROGRESS) {
1052                         printf("usbd_start_next: error=%d\n", err);
1053                         pipe->running = 0;
1054                         /* XXX do what? */
1055                 }
1056         }
1057 }
1058
1059 usbd_status
1060 usbd_do_request(usbd_device_handle dev, usb_device_request_t *req, void *data)
1061 {
1062         return (usbd_do_request_flags(dev, req, data, 0, 0,
1063                                       USBD_DEFAULT_TIMEOUT));
1064 }
1065
1066 usbd_status
1067 usbd_do_request_flags(usbd_device_handle dev, usb_device_request_t *req,
1068                       void *data, u_int16_t flags, int *actlen, u_int32_t timo)
1069 {
1070         return (usbd_do_request_flags_pipe(dev, dev->default_pipe, req,
1071                                            data, flags, actlen, timo));
1072 }
1073
1074 usbd_status
1075 usbd_do_request_flags_pipe(usbd_device_handle dev, usbd_pipe_handle pipe,
1076         usb_device_request_t *req, void *data, u_int16_t flags, int *actlen,
1077         u_int32_t timeout)
1078 {
1079         usbd_xfer_handle xfer;
1080         usbd_status err;
1081
1082 #ifdef DIAGNOSTIC
1083 /* XXX amd64 too? */
1084 #if defined(__i386__)
1085         KASSERT(curthread->td_intr_nesting_level == 0,
1086                 ("usbd_do_request: in interrupt context"));
1087 #endif
1088         if (dev->bus->intr_context) {
1089                 printf("usbd_do_request: not in process context\n");
1090                 return (USBD_INVAL);
1091         }
1092 #endif
1093
1094         xfer = usbd_alloc_xfer(dev);
1095         if (xfer == NULL)
1096                 return (USBD_NOMEM);
1097         usbd_setup_default_xfer(xfer, dev, 0, timeout, req,
1098                                 data, UGETW(req->wLength), flags, 0);
1099         xfer->pipe = pipe;
1100         err = usbd_sync_transfer(xfer);
1101 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1102         if (xfer->actlen > xfer->length)
1103                 DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1104                          "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1105                          dev->address, xfer->request.bmRequestType,
1106                          xfer->request.bRequest, UGETW(xfer->request.wValue),
1107                          UGETW(xfer->request.wIndex),
1108                          UGETW(xfer->request.wLength),
1109                          xfer->length, xfer->actlen));
1110 #endif
1111         if (actlen != NULL)
1112                 *actlen = xfer->actlen;
1113         if (err == USBD_STALLED) {
1114                 /*
1115                  * The control endpoint has stalled.  Control endpoints
1116                  * should not halt, but some may do so anyway so clear
1117                  * any halt condition.
1118                  */
1119                 usb_device_request_t treq;
1120                 usb_status_t status;
1121                 u_int16_t s;
1122                 usbd_status nerr;
1123
1124                 treq.bmRequestType = UT_READ_ENDPOINT;
1125                 treq.bRequest = UR_GET_STATUS;
1126                 USETW(treq.wValue, 0);
1127                 USETW(treq.wIndex, 0);
1128                 USETW(treq.wLength, sizeof(usb_status_t));
1129                 usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT,
1130                                            &treq, &status,sizeof(usb_status_t),
1131                                            0, 0);
1132                 nerr = usbd_sync_transfer(xfer);
1133                 if (nerr)
1134                         goto bad;
1135                 s = UGETW(status.wStatus);
1136                 DPRINTF(("usbd_do_request: status = 0x%04x\n", s));
1137                 if (!(s & UES_HALT))
1138                         goto bad;
1139                 treq.bmRequestType = UT_WRITE_ENDPOINT;
1140                 treq.bRequest = UR_CLEAR_FEATURE;
1141                 USETW(treq.wValue, UF_ENDPOINT_HALT);
1142                 USETW(treq.wIndex, 0);
1143                 USETW(treq.wLength, 0);
1144                 usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT,
1145                                            &treq, &status, 0, 0, 0);
1146                 nerr = usbd_sync_transfer(xfer);
1147                 if (nerr)
1148                         goto bad;
1149         }
1150
1151  bad:
1152         usbd_free_xfer(xfer);
1153         return (err);
1154 }
1155
1156 void
1157 usbd_do_request_async_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
1158                          usbd_status status)
1159 {
1160 #if defined(USB_DEBUG) || defined(DIAGNOSTIC)
1161         if (xfer->actlen > xfer->length)
1162                 DPRINTF(("usbd_do_request: overrun addr=%d type=0x%02x req=0x"
1163                          "%02x val=%d index=%d rlen=%d length=%d actlen=%d\n",
1164                          xfer->pipe->device->address,
1165                          xfer->request.bmRequestType,
1166                          xfer->request.bRequest, UGETW(xfer->request.wValue),
1167                          UGETW(xfer->request.wIndex),
1168                          UGETW(xfer->request.wLength),
1169                          xfer->length, xfer->actlen));
1170 #endif
1171         usbd_free_xfer(xfer);
1172 }
1173
1174 /*
1175  * Execute a request without waiting for completion.
1176  * Can be used from interrupt context.
1177  */
1178 usbd_status
1179 usbd_do_request_async(usbd_device_handle dev, usb_device_request_t *req,
1180                       void *data)
1181 {
1182         usbd_xfer_handle xfer;
1183         usbd_status err;
1184
1185         xfer = usbd_alloc_xfer(dev);
1186         if (xfer == NULL)
1187                 return (USBD_NOMEM);
1188         usbd_setup_default_xfer(xfer, dev, 0, USBD_DEFAULT_TIMEOUT, req,
1189             data, UGETW(req->wLength), 0, usbd_do_request_async_cb);
1190         err = usbd_transfer(xfer);
1191         if (err != USBD_IN_PROGRESS && err) {
1192                 usbd_free_xfer(xfer);
1193                 return (err);
1194         }
1195         return (USBD_NORMAL_COMPLETION);
1196 }
1197
1198 const struct usbd_quirks *
1199 usbd_get_quirks(usbd_device_handle dev)
1200 {
1201 #ifdef DIAGNOSTIC
1202         if (dev == NULL) {
1203                 printf("usbd_get_quirks: dev == NULL\n");
1204                 return 0;
1205         }
1206 #endif
1207         return (dev->quirks);
1208 }
1209
1210 /* XXX do periodic free() of free list */
1211
1212 /*
1213  * Called from keyboard driver when in polling mode.
1214  */
1215 void
1216 usbd_dopoll(usbd_interface_handle iface)
1217 {
1218         iface->device->bus->methods->do_poll(iface->device->bus);
1219 }
1220
1221 void
1222 usbd_set_polling(usbd_device_handle dev, int on)
1223 {
1224         if (on)
1225                 dev->bus->use_polling++;
1226         else
1227                 dev->bus->use_polling--;
1228         /* When polling we need to make sure there is nothing pending to do. */
1229         if (dev->bus->use_polling)
1230                 dev->bus->methods->soft_intr(dev->bus);
1231 }
1232
1233 usbd_status
1234 usbd_reset_device(usbd_device_handle dev)
1235 {
1236         usbd_device_handle parent = dev->myhub;
1237         struct usbd_port *up = dev->powersrc;
1238
1239         return usbd_reset_port(parent, up->portno, &up->status);
1240 }
1241
1242
1243 usb_endpoint_descriptor_t *
1244 usbd_get_endpoint_descriptor(usbd_interface_handle iface, u_int8_t address)
1245 {
1246         struct usbd_endpoint *ep;
1247         int i;
1248
1249         for (i = 0; i < iface->idesc->bNumEndpoints; i++) {
1250                 ep = &iface->endpoints[i];
1251                 if (ep->edesc->bEndpointAddress == address)
1252                         return (iface->endpoints[i].edesc);
1253         }
1254         return (0);
1255 }
1256
1257 /*
1258  * usbd_ratecheck() can limit the number of error messages that occurs.
1259  * When a device is unplugged it may take up to 0.25s for the hub driver
1260  * to notice it.  If the driver continuosly tries to do I/O operations
1261  * this can generate a large number of messages.
1262  */
1263 int
1264 usbd_ratecheck(struct timeval *last)
1265 {
1266         if (last->tv_sec == time_second)
1267                 return (0);
1268         last->tv_sec = time_second;
1269         return (1);
1270 }
1271
1272 /*
1273  * Search for a vendor/product pair in an array.  The item size is
1274  * given as an argument.
1275  */
1276 const struct usb_devno *
1277 usb_match_device(const struct usb_devno *tbl, u_int nentries, u_int sz,
1278                  u_int16_t vendor, u_int16_t product)
1279 {
1280         while (nentries-- > 0) {
1281                 u_int16_t tproduct = tbl->ud_product;
1282                 if (tbl->ud_vendor == vendor &&
1283                     (tproduct == product || tproduct == USB_PRODUCT_ANY))
1284                         return (tbl);
1285                 tbl = (const struct usb_devno *)((const char *)tbl + sz);
1286         }
1287         return (NULL);
1288 }
1289
1290
1291 void
1292 usb_desc_iter_init(usbd_device_handle dev, usbd_desc_iter_t *iter)
1293 {
1294         const usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev);
1295
1296         iter->cur = (const uByte *)cd;
1297         iter->end = (const uByte *)cd + UGETW(cd->wTotalLength);
1298 }
1299
1300 const usb_descriptor_t *
1301 usb_desc_iter_next(usbd_desc_iter_t *iter)
1302 {
1303         const usb_descriptor_t *desc;
1304
1305         if (iter->cur + sizeof(usb_descriptor_t) >= iter->end) {
1306                 if (iter->cur != iter->end)
1307                         printf("usb_desc_iter_next: bad descriptor\n");
1308                 return NULL;
1309         }
1310         desc = (const usb_descriptor_t *)iter->cur;
1311         if (desc->bLength == 0) {
1312                 printf("usb_desc_iter_next: descriptor length = 0\n");
1313                 return NULL;
1314         }
1315         iter->cur += desc->bLength;
1316         if (iter->cur > iter->end) {
1317                 printf("usb_desc_iter_next: descriptor length too large\n");
1318                 return NULL;
1319         }
1320         return desc;
1321 }
1322
1323 usbd_status
1324 usbd_get_string(usbd_device_handle dev, int si, char *buf, size_t len)
1325 {
1326         int swap = dev->quirks->uq_flags & UQ_SWAP_UNICODE;
1327         usb_string_descriptor_t us;
1328         char *s;
1329         int i, n;
1330         u_int16_t c;
1331         usbd_status err;
1332         int size;
1333
1334         buf[0] = '\0';
1335         if (len == 0)
1336                 return (USBD_NORMAL_COMPLETION);
1337         if (si == 0)
1338                 return (USBD_INVAL);
1339         if (dev->quirks->uq_flags & UQ_NO_STRINGS)
1340                 return (USBD_STALLED);
1341         if (dev->langid == USBD_NOLANG) {
1342                 /* Set up default language */
1343                 err = usbd_get_string_desc(dev, USB_LANGUAGE_TABLE, 0, &us,
1344                     &size);
1345                 if (err || size < 4) {
1346                         DPRINTFN(-1,("usbd_get_string: getting lang failed, using 0\n"));
1347                         dev->langid = 0; /* Well, just pick something then */
1348                 } else {
1349                         /* Pick the first language as the default. */
1350                         dev->langid = UGETW(us.bString[0]);
1351                 }
1352         }
1353         err = usbd_get_string_desc(dev, si, dev->langid, &us, &size);
1354         if (err)
1355                 return (err);
1356         s = buf;
1357         n = size / 2 - 1;
1358         for (i = 0; i < n && i < len - 1; i++) {
1359                 c = UGETW(us.bString[i]);
1360                 /* Convert from Unicode, handle buggy strings. */
1361                 if ((c & 0xff00) == 0)
1362                         *s++ = c;
1363                 else if ((c & 0x00ff) == 0 && swap)
1364                         *s++ = c >> 8;
1365                 else
1366                         *s++ = '?';
1367         }
1368         *s++ = 0;
1369         return (USBD_NORMAL_COMPLETION);
1370 }
1371
1372 int
1373 usbd_driver_load(module_t mod, int what, void *arg)
1374 {
1375         /* XXX should implement something like a function that removes all generic devices */
1376
1377         return (0);
1378 }