]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/usb/ugen.c
Packed structures are defined differently in older gcc's, like the one
[FreeBSD/FreeBSD.git] / sys / dev / usb / ugen.c
1 /*      $NetBSD: ugen.c,v 1.57 2002/02/11 15:11:49 augustss Exp $       */
2 /*      $FreeBSD$       */
3
4 /*
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Lennart Augustsson (lennart@augustsson.net) at
10  * Carlstedt Research & Technology.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *        This product includes software developed by the NetBSD
23  *        Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/malloc.h>
46 #if defined(__NetBSD__) || defined(__OpenBSD__)
47 #include <sys/device.h>
48 #include <sys/ioctl.h>
49 #elif defined(__FreeBSD__)
50 #include <sys/module.h>
51 #include <sys/bus.h>
52 #include <sys/ioccom.h>
53 #include <sys/conf.h>
54 #include <sys/fcntl.h>
55 #include <sys/filio.h>
56 #endif
57 #include <sys/tty.h>
58 #include <sys/file.h>
59 #if __FreeBSD_version >= 500014
60 #include <sys/selinfo.h>
61 #else
62 #include <sys/select.h>
63 #endif
64 #include <sys/vnode.h>
65 #include <sys/poll.h>
66 #include <sys/sysctl.h>
67
68 #include <dev/usb/usb.h>
69 #include <dev/usb/usbdi.h>
70 #include <dev/usb/usbdi_util.h>
71
72 #ifdef USB_DEBUG
73 #define DPRINTF(x)      if (ugendebug) logprintf x
74 #define DPRINTFN(n,x)   if (ugendebug>(n)) logprintf x
75 int     ugendebug = 0;
76 SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB ugen");
77 SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW,
78            &ugendebug, 0, "ugen debug level");
79 #else
80 #define DPRINTF(x)
81 #define DPRINTFN(n,x)
82 #endif
83
84 #define UGEN_CHUNK      128     /* chunk size for read */
85 #define UGEN_IBSIZE     1020    /* buffer size */
86 #define UGEN_BBSIZE     1024
87
88 #define UGEN_NISOFRAMES 500     /* 0.5 seconds worth */
89 #define UGEN_NISOREQS   6       /* number of outstanding xfer requests */
90 #define UGEN_NISORFRMS  4       /* number of frames (miliseconds) per req */
91
92 struct ugen_endpoint {
93         struct ugen_softc *sc;
94         usb_endpoint_descriptor_t *edesc;
95         usbd_interface_handle iface;
96         int state;
97 #define UGEN_ASLP       0x02    /* waiting for data */
98 #define UGEN_SHORT_OK   0x04    /* short xfers are OK */
99         usbd_pipe_handle pipeh;
100         struct clist q;
101         struct selinfo rsel;
102         u_char *ibuf;           /* start of buffer (circular for isoc) */
103         u_char *fill;           /* location for input (isoc) */
104         u_char *limit;          /* end of circular buffer (isoc) */
105         u_char *cur;            /* current read location (isoc) */
106         u_int32_t timeout;
107         struct isoreq {
108                 struct ugen_endpoint *sce;
109                 usbd_xfer_handle xfer;
110                 void *dmabuf;
111                 u_int16_t sizes[UGEN_NISORFRMS];
112         } isoreqs[UGEN_NISOREQS];
113 };
114
115 struct ugen_softc {
116         USBBASEDEVICE sc_dev;           /* base device */
117         usbd_device_handle sc_udev;
118
119         char sc_is_open[USB_MAX_ENDPOINTS];
120         struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
121 #define OUT 0
122 #define IN  1
123
124         int sc_refcnt;
125         u_char sc_dying;
126 };
127
128 #if defined(__NetBSD__) || defined(__OpenBSD__)
129 cdev_decl(ugen);
130 #elif defined(__FreeBSD__)
131 d_open_t  ugenopen;
132 d_close_t ugenclose;
133 d_read_t  ugenread;
134 d_write_t ugenwrite;
135 d_ioctl_t ugenioctl;
136 d_poll_t  ugenpoll;
137
138 #define UGEN_CDEV_MAJOR 114
139
140 Static struct cdevsw ugen_cdevsw = {
141         /* open */      ugenopen,
142         /* close */     ugenclose,
143         /* read */      ugenread,
144         /* write */     ugenwrite,
145         /* ioctl */     ugenioctl,
146         /* poll */      ugenpoll,
147         /* mmap */      nommap,
148         /* strategy */  nostrategy,
149         /* name */      "ugen",
150         /* maj */       UGEN_CDEV_MAJOR,
151         /* dump */      nodump,
152         /* psize */     nopsize,
153         /* flags */     0,
154 #if __FreeBSD_version < 500014
155         /* bmaj */      -1
156 #endif
157 };
158 #endif
159
160 Static void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, 
161                      usbd_status status);
162 Static void ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
163                             usbd_status status);
164 Static int ugen_do_read(struct ugen_softc *, int, struct uio *, int);
165 Static int ugen_do_write(struct ugen_softc *, int, struct uio *, int);
166 Static int ugen_do_ioctl(struct ugen_softc *, int, u_long, 
167                          caddr_t, int, usb_proc_ptr);
168 #if defined(__FreeBSD__)
169 Static void ugen_make_devnodes(struct ugen_softc *sc);
170 Static void ugen_destroy_devnodes(struct ugen_softc *sc);
171 #endif
172 Static int ugen_set_config(struct ugen_softc *sc, int configno);
173 Static usb_config_descriptor_t *ugen_get_cdesc(struct ugen_softc *sc,
174                                                int index, int *lenp);
175 Static usbd_status ugen_set_interface(struct ugen_softc *, int, int);
176 Static int ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx);
177
178 #define UGENUNIT(n) ((minor(n) >> 4) & 0xf)
179 #define UGENENDPOINT(n) (minor(n) & 0xf)
180 #define UGENMINOR(u, e) (((u) << 4) | (e))
181
182 USB_DECLARE_DRIVER(ugen);
183
184 USB_MATCH(ugen)
185 {
186         USB_MATCH_START(ugen, uaa);
187
188 #if 0
189         if (uaa->matchlvl)
190                 return (uaa->matchlvl);
191 #endif
192         if (uaa->usegeneric)
193                 return (UMATCH_GENERIC);
194         else
195                 return (UMATCH_NONE);
196 }
197
198 USB_ATTACH(ugen)
199 {
200         USB_ATTACH_START(ugen, sc, uaa);
201         usbd_device_handle udev;
202         char devinfo[1024];
203         usbd_status err;
204         int conf;
205         
206         usbd_devinfo(uaa->device, 0, devinfo);
207         USB_ATTACH_SETUP;
208         printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
209
210         sc->sc_udev = udev = uaa->device;
211
212         memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
213
214         /* First set configuration index 0, the default one for ugen. */
215         err = usbd_set_config_index(udev, 0, 0);
216         if (err) {
217                 printf("%s: setting configuration index 0 failed\n", 
218                        USBDEVNAME(sc->sc_dev));
219                 sc->sc_dying = 1;
220                 USB_ATTACH_ERROR_RETURN;
221         }
222         conf = usbd_get_config_descriptor(udev)->bConfigurationValue;
223
224         /* Set up all the local state for this configuration. */
225         err = ugen_set_config(sc, conf);
226         if (err) {
227                 printf("%s: setting configuration %d failed\n", 
228                        USBDEVNAME(sc->sc_dev), conf);
229                 sc->sc_dying = 1;
230                 USB_ATTACH_ERROR_RETURN;
231         }
232
233 #if defined(__FreeBSD__)
234         /* the main device, ctrl endpoint */
235         make_dev(&ugen_cdevsw, UGENMINOR(USBDEVUNIT(sc->sc_dev), 0),
236                 UID_ROOT, GID_OPERATOR, 0644, "%s", USBDEVNAME(sc->sc_dev));
237 #endif
238
239         USB_ATTACH_SUCCESS_RETURN;
240 }
241
242 #if defined(__FreeBSD__)
243 Static void
244 ugen_make_devnodes(struct ugen_softc *sc)
245 {
246         int endptno;
247
248         for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
249                 if (sc->sc_endpoints[endptno][IN].sc != NULL ||
250                     sc->sc_endpoints[endptno][OUT].sc != NULL ) {
251                         /* endpt can be 0x81 and 0x01, representing
252                          * endpoint address 0x01 and IN/OUT directions.
253                          * We map both endpts to the same device,
254                          * IN is reading from it, OUT is writing to it.
255                          *
256                          * In the if clause above we check whether one
257                          * of the structs is populated.
258                          */
259                         make_dev(&ugen_cdevsw,
260                                 UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno),
261                                 UID_ROOT, GID_OPERATOR, 0644,
262                                 "%s.%d",
263                                 USBDEVNAME(sc->sc_dev), endptno);
264                 }
265         }
266 }
267
268 Static void
269 ugen_destroy_devnodes(struct ugen_softc *sc)
270 {
271         int endptno;
272         dev_t dev;
273         struct vnode *vp;
274
275         /* destroy all devices for the other (existing) endpoints as well */
276         for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++) {
277                 if (sc->sc_endpoints[endptno][IN].sc != NULL ||
278                     sc->sc_endpoints[endptno][OUT].sc != NULL ) {
279                         /* endpt can be 0x81 and 0x01, representing
280                          * endpoint address 0x01 and IN/OUT directions.
281                          * We map both endpoint addresses to the same device,
282                          * IN is reading from it, OUT is writing to it.
283                          *
284                          * In the if clause above we check whether one
285                          * of the structs is populated.
286                          */
287                         dev = makedev(UGEN_CDEV_MAJOR,
288                                 UGENMINOR(USBDEVUNIT(sc->sc_dev), endptno));
289                         vp = SLIST_FIRST(&dev->si_hlist);
290                         if (vp)
291                                 VOP_REVOKE(vp, REVOKEALL);
292
293                         destroy_dev(dev);
294                 }
295         }
296 }
297 #endif
298
299 Static int
300 ugen_set_config(struct ugen_softc *sc, int configno)
301 {
302         usbd_device_handle dev = sc->sc_udev;
303         usbd_interface_handle iface;
304         usb_endpoint_descriptor_t *ed;
305         struct ugen_endpoint *sce;
306         u_int8_t niface, nendpt;
307         int ifaceno, endptno, endpt;
308         usbd_status err;
309         int dir;
310
311         DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
312                     USBDEVNAME(sc->sc_dev), configno, sc));
313
314 #if defined(__FreeBSD__)
315         ugen_destroy_devnodes(sc);
316 #endif
317
318         /* We start at 1, not 0, because we don't care whether the
319          * control endpoint is open or not. It is always present.
320          */
321         for (endptno = 1; endptno < USB_MAX_ENDPOINTS; endptno++)
322                 if (sc->sc_is_open[endptno]) {
323                         DPRINTFN(1,
324                              ("ugen_set_config: %s - endpoint %d is open\n",
325                               USBDEVNAME(sc->sc_dev), endptno));
326                         return (USBD_IN_USE);
327                 }
328
329         /* Avoid setting the current value. */
330         if (usbd_get_config_descriptor(dev)->bConfigurationValue != configno) {
331                 err = usbd_set_config_no(dev, configno, 1);
332                 if (err)
333                         return (err);
334         }
335
336         err = usbd_interface_count(dev, &niface);
337         if (err)
338                 return (err);
339         memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
340         for (ifaceno = 0; ifaceno < niface; ifaceno++) {
341                 DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
342                 err = usbd_device2interface_handle(dev, ifaceno, &iface);
343                 if (err)
344                         return (err);
345                 err = usbd_endpoint_count(iface, &nendpt);
346                 if (err)
347                         return (err);
348                 for (endptno = 0; endptno < nendpt; endptno++) {
349                         ed = usbd_interface2endpoint_descriptor(iface,endptno);
350                         endpt = ed->bEndpointAddress;
351                         dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
352                         sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
353                         DPRINTFN(1,("ugen_set_config: endptno %d, endpt=0x%02x"
354                                     "(%d,%d), sce=%p\n", 
355                                     endptno, endpt, UE_GET_ADDR(endpt),
356                                     UE_GET_DIR(endpt), sce));
357                         sce->sc = sc;
358                         sce->edesc = ed;
359                         sce->iface = iface;
360                 }
361         }
362
363 #if defined(__FreeBSD__)
364         ugen_make_devnodes(sc);
365 #endif
366
367         return (USBD_NORMAL_COMPLETION);
368 }
369
370 int
371 ugenopen(dev_t dev, int flag, int mode, usb_proc_ptr p)
372 {
373         struct ugen_softc *sc;
374         int unit = UGENUNIT(dev);
375         int endpt = UGENENDPOINT(dev);
376         usb_endpoint_descriptor_t *edesc;
377         struct ugen_endpoint *sce;
378         int dir, isize;
379         usbd_status err;
380         usbd_xfer_handle xfer;
381         void *buf;
382         int i, j;
383
384         USB_GET_SC_OPEN(ugen, unit, sc);
385
386         DPRINTFN(5, ("ugenopen: flag=%d, mode=%d, unit=%d endpt=%d\n", 
387                      flag, mode, unit, endpt));
388
389         if (sc == NULL || sc->sc_dying)
390                 return (ENXIO);
391
392         if (sc->sc_is_open[endpt])
393                 return (EBUSY);
394
395         if (endpt == USB_CONTROL_ENDPOINT) {
396                 sc->sc_is_open[USB_CONTROL_ENDPOINT] = 1;
397                 return (0);
398         }
399
400         /* Make sure there are pipes for all directions. */
401         for (dir = OUT; dir <= IN; dir++) {
402                 if (flag & (dir == OUT ? FWRITE : FREAD)) {
403                         sce = &sc->sc_endpoints[endpt][dir];
404                         if (sce == 0 || sce->edesc == 0)
405                                 return (ENXIO);
406                 }
407         }
408
409         /* Actually open the pipes. */
410         /* XXX Should back out properly if it fails. */
411         for (dir = OUT; dir <= IN; dir++) {
412                 if (!(flag & (dir == OUT ? FWRITE : FREAD)))
413                         continue;
414                 sce = &sc->sc_endpoints[endpt][dir];
415                 sce->state = 0;
416                 sce->timeout = USBD_NO_TIMEOUT;
417                 DPRINTFN(5, ("ugenopen: sc=%p, endpt=%d, dir=%d, sce=%p\n", 
418                              sc, endpt, dir, sce));
419                 edesc = sce->edesc;
420                 switch (edesc->bmAttributes & UE_XFERTYPE) {
421                 case UE_INTERRUPT:
422                         isize = UGETW(edesc->wMaxPacketSize);
423                         if (isize == 0) /* shouldn't happen */
424                                 return (EINVAL);
425                         sce->ibuf = malloc(isize, M_USBDEV, M_WAITOK);
426                         DPRINTFN(5, ("ugenopen: intr endpt=%d,isize=%d\n", 
427                                      endpt, isize));
428                         if (clalloc(&sce->q, UGEN_IBSIZE, 0) == -1)
429                                 return (ENOMEM);
430                         err = usbd_open_pipe_intr(sce->iface, 
431                                 edesc->bEndpointAddress, 
432                                 USBD_SHORT_XFER_OK, &sce->pipeh, sce, 
433                                 sce->ibuf, isize, ugenintr,
434                                 USBD_DEFAULT_INTERVAL);
435                         if (err) {
436                                 free(sce->ibuf, M_USBDEV);
437                                 clfree(&sce->q);
438                                 return (EIO);
439                         }
440                         DPRINTFN(5, ("ugenopen: interrupt open done\n"));
441                         break;
442                 case UE_BULK:
443                         err = usbd_open_pipe(sce->iface, 
444                                   edesc->bEndpointAddress, 0, &sce->pipeh);
445                         if (err)
446                                 return (EIO);
447                         break;
448                 case UE_ISOCHRONOUS:
449                         if (dir == OUT)
450                                 return (EINVAL);
451                         isize = UGETW(edesc->wMaxPacketSize);
452                         if (isize == 0) /* shouldn't happen */
453                                 return (EINVAL);
454                         sce->ibuf = malloc(isize * UGEN_NISOFRAMES,
455                                 M_USBDEV, M_WAITOK);
456                         sce->cur = sce->fill = sce->ibuf;
457                         sce->limit = sce->ibuf + isize * UGEN_NISOFRAMES;
458                         DPRINTFN(5, ("ugenopen: isoc endpt=%d, isize=%d\n", 
459                                      endpt, isize));
460                         err = usbd_open_pipe(sce->iface,
461                                   edesc->bEndpointAddress, 0, &sce->pipeh);
462                         if (err) {
463                                 free(sce->ibuf, M_USBDEV);
464                                 return (EIO);
465                         }
466                         for(i = 0; i < UGEN_NISOREQS; ++i) {
467                                 sce->isoreqs[i].sce = sce;
468                                 xfer = usbd_alloc_xfer(sc->sc_udev);
469                                 if (xfer == 0)
470                                         goto bad;
471                                 sce->isoreqs[i].xfer = xfer;
472                                 buf = usbd_alloc_buffer
473                                         (xfer, isize * UGEN_NISORFRMS);
474                                 if (buf == 0) {
475                                         i++;
476                                         goto bad;
477                                 }
478                                 sce->isoreqs[i].dmabuf = buf;
479                                 for(j = 0; j < UGEN_NISORFRMS; ++j)
480                                         sce->isoreqs[i].sizes[j] = isize;
481                                 usbd_setup_isoc_xfer
482                                         (xfer, sce->pipeh, &sce->isoreqs[i],
483                                          sce->isoreqs[i].sizes,
484                                          UGEN_NISORFRMS, USBD_NO_COPY,
485                                          ugen_isoc_rintr);
486                                 (void)usbd_transfer(xfer);
487                         }
488                         DPRINTFN(5, ("ugenopen: isoc open done\n"));
489                         break;
490                 bad:
491                         while (--i >= 0) /* implicit buffer free */
492                                 usbd_free_xfer(sce->isoreqs[i].xfer);
493                         return (ENOMEM);
494                 case UE_CONTROL:
495                         sce->timeout = USBD_DEFAULT_TIMEOUT;
496                         return (EINVAL);
497                 }
498         }
499         sc->sc_is_open[endpt] = 1;
500         return (0);
501 }
502
503 int
504 ugenclose(dev_t dev, int flag, int mode, usb_proc_ptr p)
505 {
506         int endpt = UGENENDPOINT(dev);
507         struct ugen_softc *sc;
508         struct ugen_endpoint *sce;
509         int dir;
510         int i;
511
512         USB_GET_SC(ugen, UGENUNIT(dev), sc);
513
514         DPRINTFN(5, ("ugenclose: flag=%d, mode=%d, unit=%d, endpt=%d\n",
515                      flag, mode, UGENUNIT(dev), endpt));
516
517 #ifdef DIAGNOSTIC
518         if (!sc->sc_is_open[endpt]) {
519                 printf("ugenclose: not open\n");
520                 return (EINVAL);
521         }
522 #endif
523
524         if (endpt == USB_CONTROL_ENDPOINT) {
525                 DPRINTFN(5, ("ugenclose: close control\n"));
526                 sc->sc_is_open[endpt] = 0;
527                 return (0);
528         }
529
530         for (dir = OUT; dir <= IN; dir++) {
531                 if (!(flag & (dir == OUT ? FWRITE : FREAD)))
532                         continue;
533                 sce = &sc->sc_endpoints[endpt][dir];
534                 if (sce == NULL || sce->pipeh == NULL)
535                         continue;
536                 DPRINTFN(5, ("ugenclose: endpt=%d dir=%d sce=%p\n", 
537                              endpt, dir, sce));
538
539                 usbd_abort_pipe(sce->pipeh);
540                 usbd_close_pipe(sce->pipeh);
541                 sce->pipeh = NULL;
542
543                 switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
544                 case UE_INTERRUPT:
545                         ndflush(&sce->q, sce->q.c_cc);
546                         clfree(&sce->q);
547                         break;
548                 case UE_ISOCHRONOUS:
549                         for (i = 0; i < UGEN_NISOREQS; ++i)
550                                 usbd_free_xfer(sce->isoreqs[i].xfer);
551                 default:
552                         break;
553                 }
554
555                 if (sce->ibuf != NULL) {
556                         free(sce->ibuf, M_USBDEV);
557                         sce->ibuf = NULL;
558                         clfree(&sce->q);
559                 }
560         }
561         sc->sc_is_open[endpt] = 0;
562
563         return (0);
564 }
565
566 Static int
567 ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
568 {
569         struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
570         u_int32_t n, tn;
571         char buf[UGEN_BBSIZE];
572         usbd_xfer_handle xfer;
573         usbd_status err;
574         int s;
575         int error = 0;
576         u_char buffer[UGEN_CHUNK];
577
578         DPRINTFN(5, ("%s: ugenread: %d\n", USBDEVNAME(sc->sc_dev), endpt));
579
580         if (sc->sc_dying)
581                 return (EIO);
582
583         if (endpt == USB_CONTROL_ENDPOINT)
584                 return (ENODEV);
585
586         if (sce == NULL)
587                 return (EINVAL);
588
589         if (sce->edesc == NULL) {
590                 printf("ugenread: no edesc\n");
591                 return (EIO);
592         }
593         if (sce->pipeh == NULL) {
594                 printf("ugenread: no pipe\n");
595                 return (EIO);
596         }
597
598         switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
599         case UE_INTERRUPT:
600                 /* Block until activity occurred. */
601                 s = splusb();
602                 while (sce->q.c_cc == 0) {
603                         if (flag & IO_NDELAY) {
604                                 splx(s);
605                                 return (EWOULDBLOCK);
606                         }
607                         sce->state |= UGEN_ASLP;
608                         DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
609                         error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
610                         DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
611                         if (sc->sc_dying)
612                                 error = EIO;
613                         if (error) {
614                                 sce->state &= ~UGEN_ASLP;
615                                 break;
616                         }
617                 }
618                 splx(s);
619
620                 /* Transfer as many chunks as possible. */
621                 while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
622                         n = min(sce->q.c_cc, uio->uio_resid);
623                         if (n > sizeof(buffer))
624                                 n = sizeof(buffer);
625
626                         /* Remove a small chunk from the input queue. */
627                         q_to_b(&sce->q, buffer, n);
628                         DPRINTFN(5, ("ugenread: got %d chars\n", n));
629
630                         /* Copy the data to the user process. */
631                         error = uiomove(buffer, n, uio);
632                         if (error)
633                                 break;
634                 }
635                 break;
636         case UE_BULK:
637                 xfer = usbd_alloc_xfer(sc->sc_udev);
638                 if (xfer == 0)
639                         return (ENOMEM);
640                 while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
641                         DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
642                         tn = n;
643                         err = usbd_bulk_transfer(
644                                 xfer, sce->pipeh,
645                                 sce->state & UGEN_SHORT_OK ? 
646                                     USBD_SHORT_XFER_OK : 0, 
647                                 sce->timeout, buf, &tn, "ugenrb");
648                         if (err) {
649                                 if (err == USBD_INTERRUPTED)
650                                         error = EINTR;
651                                 else if (err == USBD_TIMEOUT)
652                                         error = ETIMEDOUT;
653                                 else
654                                         error = EIO;
655                                 break;
656                         }
657                         DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
658                         error = uiomove(buf, tn, uio);
659                         if (error || tn < n)
660                                 break;
661                 }
662                 usbd_free_xfer(xfer);
663                 break;
664         case UE_ISOCHRONOUS:
665                 s = splusb();
666                 while (sce->cur == sce->fill) {
667                         if (flag & IO_NDELAY) {
668                                 splx(s);
669                                 return (EWOULDBLOCK);
670                         }
671                         sce->state |= UGEN_ASLP;
672                         DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
673                         error = tsleep(sce, PZERO | PCATCH, "ugenri", 0);
674                         DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
675                         if (sc->sc_dying)
676                                 error = EIO;
677                         if (error) {
678                                 sce->state &= ~UGEN_ASLP;
679                                 break;
680                         }
681                 }
682
683                 while (sce->cur != sce->fill && uio->uio_resid > 0 && !error) {
684                         if(sce->fill > sce->cur)
685                                 n = min(sce->fill - sce->cur, uio->uio_resid);
686                         else
687                                 n = min(sce->limit - sce->cur, uio->uio_resid);
688
689                         DPRINTFN(5, ("ugenread: isoc got %d chars\n", n));
690
691                         /* Copy the data to the user process. */
692                         error = uiomove(sce->cur, n, uio);
693                         if (error)
694                                 break;
695                         sce->cur += n;
696                         if(sce->cur >= sce->limit)
697                                 sce->cur = sce->ibuf;
698                 }
699                 splx(s);
700                 break;
701
702                 
703         default:
704                 return (ENXIO);
705         }
706         return (error);
707 }
708
709 int
710 ugenread(dev_t dev, struct uio *uio, int flag)
711 {
712         int endpt = UGENENDPOINT(dev);
713         struct ugen_softc *sc;
714         int error;
715
716         USB_GET_SC(ugen, UGENUNIT(dev), sc);
717
718         sc->sc_refcnt++;
719         error = ugen_do_read(sc, endpt, uio, flag);
720         if (--sc->sc_refcnt < 0)
721                 usb_detach_wakeup(USBDEV(sc->sc_dev));
722         return (error);
723 }
724
725 Static int
726 ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
727 {
728         struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
729         u_int32_t n;
730         int error = 0;
731         char buf[UGEN_BBSIZE];
732         usbd_xfer_handle xfer;
733         usbd_status err;
734
735         DPRINTFN(5, ("%s: ugenwrite: %d\n", USBDEVNAME(sc->sc_dev), endpt));
736
737         if (sc->sc_dying)
738                 return (EIO);
739
740         if (endpt == USB_CONTROL_ENDPOINT)
741                 return (ENODEV);
742
743         if (sce == NULL)
744                 return (EINVAL);
745
746         if (sce->edesc == NULL) {
747                 printf("ugenwrite: no edesc\n");
748                 return (EIO);
749         }
750         if (sce->pipeh == NULL) {
751                 printf("ugenwrite: no pipe\n");
752                 return (EIO);
753         }
754
755         switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
756         case UE_BULK:
757                 xfer = usbd_alloc_xfer(sc->sc_udev);
758                 if (xfer == 0)
759                         return (EIO);
760                 while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
761                         error = uiomove(buf, n, uio);
762                         if (error)
763                                 break;
764                         DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
765                         err = usbd_bulk_transfer(xfer, sce->pipeh, 0, 
766                                   sce->timeout, buf, &n,"ugenwb");
767                         if (err) {
768                                 if (err == USBD_INTERRUPTED)
769                                         error = EINTR;
770                                 else if (err == USBD_TIMEOUT)
771                                         error = ETIMEDOUT;
772                                 else
773                                         error = EIO;
774                                 break;
775                         }
776                 }
777                 usbd_free_xfer(xfer);
778                 break;
779         default:
780                 return (ENXIO);
781         }
782         return (error);
783 }
784
785 int
786 ugenwrite(dev_t dev, struct uio *uio, int flag)
787 {
788         int endpt = UGENENDPOINT(dev);
789         struct ugen_softc *sc;
790         int error;
791
792         USB_GET_SC(ugen, UGENUNIT(dev), sc);
793
794         sc->sc_refcnt++;
795         error = ugen_do_write(sc, endpt, uio, flag);
796         if (--sc->sc_refcnt < 0)
797                 usb_detach_wakeup(USBDEV(sc->sc_dev));
798         return (error);
799 }
800
801 #if defined(__NetBSD__) || defined(__OpenBSD__)
802 int
803 ugen_activate(device_ptr_t self, enum devact act)
804 {
805         struct ugen_softc *sc = (struct ugen_softc *)self;
806
807         switch (act) {
808         case DVACT_ACTIVATE:
809                 return (EOPNOTSUPP);
810                 break;
811
812         case DVACT_DEACTIVATE:
813                 sc->sc_dying = 1;
814                 break;
815         }
816         return (0);
817 }
818 #endif
819
820 USB_DETACH(ugen)
821 {
822         USB_DETACH_START(ugen, sc);
823         struct ugen_endpoint *sce;
824         int i, dir;
825         int s;
826 #if defined(__NetBSD__) || defined(__OpenBSD__)
827         int maj, mn;
828 #elif defined(__FreeBSD__)
829         dev_t dev;
830         struct vnode *vp;
831 #endif
832
833 #if defined(__NetBSD__) || defined(__OpenBSD__)
834         DPRINTF(("ugen_detach: sc=%p flags=%d\n", sc, flags));
835 #elif defined(__FreeBSD__)
836         DPRINTF(("ugen_detach: sc=%p\n", sc));
837 #endif
838
839         sc->sc_dying = 1;
840         /* Abort all pipes.  Causes processes waiting for transfer to wake. */
841         for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
842                 for (dir = OUT; dir <= IN; dir++) {
843                         sce = &sc->sc_endpoints[i][dir];
844                         if (sce && sce->pipeh)
845                                 usbd_abort_pipe(sce->pipeh);
846                 }
847         }
848
849         s = splusb();
850         if (--sc->sc_refcnt >= 0) {
851                 /* Wake everyone */
852                 for (i = 0; i < USB_MAX_ENDPOINTS; i++)
853                         wakeup(&sc->sc_endpoints[i][IN]);
854                 /* Wait for processes to go away. */
855                 usb_detach_wait(USBDEV(sc->sc_dev));
856         }
857         splx(s);
858
859 #if defined(__NetBSD__) || defined(__OpenBSD__)
860         /* locate the major number */
861         for (maj = 0; maj < nchrdev; maj++)
862                 if (cdevsw[maj].d_open == ugenopen)
863                         break;
864
865         /* Nuke the vnodes for any open instances (calls close). */
866         mn = self->dv_unit * USB_MAX_ENDPOINTS;
867         vdevgone(maj, mn, mn + USB_MAX_ENDPOINTS - 1, VCHR);
868 #elif defined(__FreeBSD__)
869         /* destroy the device for the control endpoint */
870         dev = makedev(UGEN_CDEV_MAJOR, UGENMINOR(USBDEVUNIT(sc->sc_dev), 0));
871         vp = SLIST_FIRST(&dev->si_hlist);
872         if (vp)
873                 VOP_REVOKE(vp, REVOKEALL);
874         destroy_dev(dev);
875         ugen_destroy_devnodes(sc);
876 #endif
877
878         return (0);
879 }
880
881 Static void
882 ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
883 {
884         struct ugen_endpoint *sce = addr;
885         /*struct ugen_softc *sc = sce->sc;*/
886         u_int32_t count;
887         u_char *ibuf;
888
889         if (status == USBD_CANCELLED)
890                 return;
891
892         if (status != USBD_NORMAL_COMPLETION) {
893                 DPRINTF(("ugenintr: status=%d\n", status));
894                 if (status == USBD_STALLED)
895                     usbd_clear_endpoint_stall_async(sce->pipeh);
896                 return;
897         }
898
899         usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
900         ibuf = sce->ibuf;
901
902         DPRINTFN(5, ("ugenintr: xfer=%p status=%d count=%d\n", 
903                      xfer, status, count));
904         DPRINTFN(5, ("          data = %02x %02x %02x\n",
905                      ibuf[0], ibuf[1], ibuf[2]));
906
907         (void)b_to_q(ibuf, count, &sce->q);
908                 
909         if (sce->state & UGEN_ASLP) {
910                 sce->state &= ~UGEN_ASLP;
911                 DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
912                 wakeup(sce);
913         }
914         selwakeup(&sce->rsel);
915 }
916
917 Static void
918 ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr, 
919                 usbd_status status)
920 {
921         struct isoreq *req = addr;
922         struct ugen_endpoint *sce = req->sce;
923         u_int32_t count, n;
924         int i, isize;
925
926         /* Return if we are aborting. */
927         if (status == USBD_CANCELLED)
928                 return;
929
930         usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
931         DPRINTFN(5,("ugen_isoc_rintr: xfer %d, count=%d\n", req - sce->isoreqs,
932                     count));
933
934         /* throw away oldest input if the buffer is full */
935         if(sce->fill < sce->cur && sce->cur <= sce->fill + count) {
936                 sce->cur += count;
937                 if(sce->cur >= sce->limit)
938                         sce->cur = sce->ibuf + (sce->limit - sce->cur);
939                 DPRINTFN(5, ("ugen_isoc_rintr: throwing away %d bytes\n",
940                              count));
941         }
942
943         isize = UGETW(sce->edesc->wMaxPacketSize);
944         for (i = 0; i < UGEN_NISORFRMS; i++) {
945                 u_int32_t actlen = req->sizes[i];
946                 char const *buf = (char const *)req->dmabuf + isize * i;
947
948                 /* copy data to buffer */
949                 while (actlen > 0) {
950                         n = min(actlen, sce->limit - sce->fill);
951                         memcpy(sce->fill, buf, n);
952
953                         buf += n;
954                         actlen -= n;
955                         sce->fill += n;
956                         if(sce->fill == sce->limit)
957                                 sce->fill = sce->ibuf;
958                 }
959
960                 /* setup size for next transfer */
961                 req->sizes[i] = isize;
962         }
963
964         usbd_setup_isoc_xfer(xfer, sce->pipeh, req, req->sizes, UGEN_NISORFRMS,
965                              USBD_NO_COPY, ugen_isoc_rintr);
966         (void)usbd_transfer(xfer);
967
968         if (sce->state & UGEN_ASLP) {
969                 sce->state &= ~UGEN_ASLP;
970                 DPRINTFN(5, ("ugen_isoc_rintr: waking %p\n", sce));
971                 wakeup(sce);
972         }
973         selwakeup(&sce->rsel);
974 }
975
976 Static usbd_status
977 ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
978 {
979         usbd_interface_handle iface;
980         usb_endpoint_descriptor_t *ed;
981         usbd_status err;
982         struct ugen_endpoint *sce;
983         u_int8_t niface, nendpt, endptno, endpt;
984         int dir;
985
986         DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));
987
988         err = usbd_interface_count(sc->sc_udev, &niface);
989         if (err)
990                 return (err);
991         if (ifaceidx < 0 || ifaceidx >= niface)
992                 return (USBD_INVAL);
993         
994         err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
995         if (err)
996                 return (err);
997         err = usbd_endpoint_count(iface, &nendpt);
998         if (err)
999                 return (err);
1000         /* XXX should only do this after setting new altno has succeeded */
1001         for (endptno = 0; endptno < nendpt; endptno++) {
1002                 ed = usbd_interface2endpoint_descriptor(iface,endptno);
1003                 endpt = ed->bEndpointAddress;
1004                 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
1005                 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
1006                 sce->sc = 0;
1007                 sce->edesc = 0;
1008                 sce->iface = 0;
1009         }
1010
1011         /* change setting */
1012         err = usbd_set_interface(iface, altno);
1013         if (err)
1014                 return (err);
1015
1016         err = usbd_endpoint_count(iface, &nendpt);
1017         if (err)
1018                 return (err);
1019         for (endptno = 0; endptno < nendpt; endptno++) {
1020                 ed = usbd_interface2endpoint_descriptor(iface,endptno);
1021                 endpt = ed->bEndpointAddress;
1022                 dir = UE_GET_DIR(endpt) == UE_DIR_IN ? IN : OUT;
1023                 sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][dir];
1024                 sce->sc = sc;
1025                 sce->edesc = ed;
1026                 sce->iface = iface;
1027         }
1028         return (0);
1029 }
1030
1031 /* Retrieve a complete descriptor for a certain device and index. */
1032 Static usb_config_descriptor_t *
1033 ugen_get_cdesc(struct ugen_softc *sc, int index, int *lenp)
1034 {
1035         usb_config_descriptor_t *cdesc, *tdesc, cdescr;
1036         int len;
1037         usbd_status err;
1038
1039         if (index == USB_CURRENT_CONFIG_INDEX) {
1040                 tdesc = usbd_get_config_descriptor(sc->sc_udev);
1041                 len = UGETW(tdesc->wTotalLength);
1042                 if (lenp)
1043                         *lenp = len;
1044                 cdesc = malloc(len, M_TEMP, M_WAITOK);
1045                 memcpy(cdesc, tdesc, len);
1046                 DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));
1047         } else {
1048                 err = usbd_get_config_desc(sc->sc_udev, index, &cdescr);
1049                 if (err)
1050                         return (0);
1051                 len = UGETW(cdescr.wTotalLength);
1052                 DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));
1053                 if (lenp)
1054                         *lenp = len;
1055                 cdesc = malloc(len, M_TEMP, M_WAITOK);
1056                 err = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);
1057                 if (err) {
1058                         free(cdesc, M_TEMP);
1059                         return (0);
1060                 }
1061         }
1062         return (cdesc);
1063 }
1064
1065 Static int
1066 ugen_get_alt_index(struct ugen_softc *sc, int ifaceidx)
1067 {
1068         usbd_interface_handle iface;
1069         usbd_status err;
1070
1071         err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
1072         if (err)
1073                 return (-1);
1074         return (usbd_get_interface_altindex(iface));
1075 }
1076
1077 Static int
1078 ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
1079               caddr_t addr, int flag, usb_proc_ptr p)
1080 {
1081         struct ugen_endpoint *sce;
1082         usbd_status err;
1083         usbd_interface_handle iface;
1084         struct usb_config_desc *cd;
1085         usb_config_descriptor_t *cdesc;
1086         struct usb_interface_desc *id;
1087         usb_interface_descriptor_t *idesc;
1088         struct usb_endpoint_desc *ed;
1089         usb_endpoint_descriptor_t *edesc;
1090         struct usb_alt_interface *ai;
1091         struct usb_string_desc *si;
1092         u_int8_t conf, alt;
1093
1094         DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
1095         if (sc->sc_dying)
1096                 return (EIO);
1097
1098         switch (cmd) {
1099         case FIONBIO:
1100                 /* All handled in the upper FS layer. */
1101                 return (0);
1102         case USB_SET_SHORT_XFER:
1103                 /* This flag only affects read */
1104                 if (endpt == USB_CONTROL_ENDPOINT)
1105                         return (EINVAL);
1106                 sce = &sc->sc_endpoints[endpt][IN];
1107                 if (sce == NULL)
1108                         return (EINVAL);
1109
1110                 if (sce->pipeh == NULL) {
1111                         printf("ugenioctl: USB_SET_SHORT_XFER, no pipe\n");
1112                         return (EIO);
1113                 }
1114
1115                 if (*(int *)addr)
1116                         sce->state |= UGEN_SHORT_OK;
1117                 else
1118                         sce->state &= ~UGEN_SHORT_OK;
1119                 return (0);
1120         case USB_SET_TIMEOUT:
1121                 sce = &sc->sc_endpoints[endpt][IN];
1122                 if (sce == NULL)
1123                         return (EINVAL);
1124                 sce->timeout = *(int *)addr;
1125                 return (0);
1126         default:
1127                 break;
1128         }
1129
1130         if (endpt != USB_CONTROL_ENDPOINT)
1131                 return (EINVAL);
1132
1133         switch (cmd) {
1134 #ifdef USB_DEBUG
1135         case USB_SETDEBUG:
1136                 ugendebug = *(int *)addr;
1137                 break;
1138 #endif
1139         case USB_GET_CONFIG:
1140                 err = usbd_get_config(sc->sc_udev, &conf);
1141                 if (err)
1142                         return (EIO);
1143                 *(int *)addr = conf;
1144                 break;
1145         case USB_SET_CONFIG:
1146                 if (!(flag & FWRITE))
1147                         return (EPERM);
1148                 err = ugen_set_config(sc, *(int *)addr);
1149                 switch (err) {
1150                 case USBD_NORMAL_COMPLETION:
1151                         break;
1152                 case USBD_IN_USE:
1153                         return (EBUSY);
1154                 default:
1155                         return (EIO);
1156                 }
1157                 break;
1158         case USB_GET_ALTINTERFACE:
1159                 ai = (struct usb_alt_interface *)addr;
1160                 err = usbd_device2interface_handle(sc->sc_udev, 
1161                           ai->uai_interface_index, &iface);
1162                 if (err)
1163                         return (EINVAL);
1164                 idesc = usbd_get_interface_descriptor(iface);
1165                 if (idesc == NULL)
1166                         return (EIO);
1167                 ai->uai_alt_no = idesc->bAlternateSetting;
1168                 break;
1169         case USB_SET_ALTINTERFACE:
1170                 if (!(flag & FWRITE))
1171                         return (EPERM);
1172                 ai = (struct usb_alt_interface *)addr;
1173                 err = usbd_device2interface_handle(sc->sc_udev, 
1174                           ai->uai_interface_index, &iface);
1175                 if (err)
1176                         return (EINVAL);
1177                 err = ugen_set_interface(sc, ai->uai_interface_index, ai->uai_alt_no);
1178                 if (err)
1179                         return (EINVAL);
1180                 break;
1181         case USB_GET_NO_ALT:
1182                 ai = (struct usb_alt_interface *)addr;
1183                 cdesc = ugen_get_cdesc(sc, ai->uai_config_index, 0);
1184                 if (cdesc == NULL)
1185                         return (EINVAL);
1186                 idesc = usbd_find_idesc(cdesc, ai->uai_interface_index, 0);
1187                 if (idesc == NULL) {
1188                         free(cdesc, M_TEMP);
1189                         return (EINVAL);
1190                 }
1191                 ai->uai_alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);
1192                 free(cdesc, M_TEMP);
1193                 break;
1194         case USB_GET_DEVICE_DESC:
1195                 *(usb_device_descriptor_t *)addr =
1196                         *usbd_get_device_descriptor(sc->sc_udev);
1197                 break;
1198         case USB_GET_CONFIG_DESC:
1199                 cd = (struct usb_config_desc *)addr;
1200                 cdesc = ugen_get_cdesc(sc, cd->ucd_config_index, 0);
1201                 if (cdesc == NULL)
1202                         return (EINVAL);
1203                 cd->ucd_desc = *cdesc;
1204                 free(cdesc, M_TEMP);
1205                 break;
1206         case USB_GET_INTERFACE_DESC:
1207                 id = (struct usb_interface_desc *)addr;
1208                 cdesc = ugen_get_cdesc(sc, id->uid_config_index, 0);
1209                 if (cdesc == NULL)
1210                         return (EINVAL);
1211                 if (id->uid_config_index == USB_CURRENT_CONFIG_INDEX &&
1212                     id->uid_alt_index == USB_CURRENT_ALT_INDEX)
1213                         alt = ugen_get_alt_index(sc, id->uid_interface_index);
1214                 else
1215                         alt = id->uid_alt_index;
1216                 idesc = usbd_find_idesc(cdesc, id->uid_interface_index, alt);
1217                 if (idesc == NULL) {
1218                         free(cdesc, M_TEMP);
1219                         return (EINVAL);
1220                 }
1221                 id->uid_desc = *idesc;
1222                 free(cdesc, M_TEMP);
1223                 break;
1224         case USB_GET_ENDPOINT_DESC:
1225                 ed = (struct usb_endpoint_desc *)addr;
1226                 cdesc = ugen_get_cdesc(sc, ed->ued_config_index, 0);
1227                 if (cdesc == NULL)
1228                         return (EINVAL);
1229                 if (ed->ued_config_index == USB_CURRENT_CONFIG_INDEX &&
1230                     ed->ued_alt_index == USB_CURRENT_ALT_INDEX)
1231                         alt = ugen_get_alt_index(sc, ed->ued_interface_index);
1232                 else
1233                         alt = ed->ued_alt_index;
1234                 edesc = usbd_find_edesc(cdesc, ed->ued_interface_index, 
1235                                         alt, ed->ued_endpoint_index);
1236                 if (edesc == NULL) {
1237                         free(cdesc, M_TEMP);
1238                         return (EINVAL);
1239                 }
1240                 ed->ued_desc = *edesc;
1241                 free(cdesc, M_TEMP);
1242                 break;
1243         case USB_GET_FULL_DESC:
1244         {
1245                 int len;
1246                 struct iovec iov;
1247                 struct uio uio;
1248                 struct usb_full_desc *fd = (struct usb_full_desc *)addr;
1249                 int error;
1250
1251                 cdesc = ugen_get_cdesc(sc, fd->ufd_config_index, &len);
1252                 if (len > fd->ufd_size)
1253                         len = fd->ufd_size;
1254                 iov.iov_base = (caddr_t)fd->ufd_data;
1255                 iov.iov_len = len;
1256                 uio.uio_iov = &iov;
1257                 uio.uio_iovcnt = 1;
1258                 uio.uio_resid = len;
1259                 uio.uio_offset = 0;
1260                 uio.uio_segflg = UIO_USERSPACE;
1261                 uio.uio_rw = UIO_READ;
1262                 uio.uio_procp = p;
1263                 error = uiomove((void *)cdesc, len, &uio);
1264                 free(cdesc, M_TEMP);
1265                 return (error);
1266         }
1267         case USB_GET_STRING_DESC:
1268                 si = (struct usb_string_desc *)addr;
1269                 err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index, 
1270                           si->usd_language_id, &si->usd_desc);
1271                 if (err)
1272                         return (EINVAL);
1273                 break;
1274         case USB_DO_REQUEST:
1275         {
1276                 struct usb_ctl_request *ur = (void *)addr;
1277                 int len = UGETW(ur->ucr_request.wLength);
1278                 struct iovec iov;
1279                 struct uio uio;
1280                 void *ptr = 0;
1281                 usbd_status err;
1282                 int error = 0;
1283
1284                 if (!(flag & FWRITE))
1285                         return (EPERM);
1286                 /* Avoid requests that would damage the bus integrity. */
1287                 if ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
1288                      ur->ucr_request.bRequest == UR_SET_ADDRESS) ||
1289                     (ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
1290                      ur->ucr_request.bRequest == UR_SET_CONFIG) ||
1291                     (ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE &&
1292                      ur->ucr_request.bRequest == UR_SET_INTERFACE))
1293                         return (EINVAL);
1294
1295                 if (len < 0 || len > 32767)
1296                         return (EINVAL);
1297                 if (len != 0) {
1298                         iov.iov_base = (caddr_t)ur->ucr_data;
1299                         iov.iov_len = len;
1300                         uio.uio_iov = &iov;
1301                         uio.uio_iovcnt = 1;
1302                         uio.uio_resid = len;
1303                         uio.uio_offset = 0;
1304                         uio.uio_segflg = UIO_USERSPACE;
1305                         uio.uio_rw =
1306                                 ur->ucr_request.bmRequestType & UT_READ ? 
1307                                 UIO_READ : UIO_WRITE;
1308                         uio.uio_procp = p;
1309                         ptr = malloc(len, M_TEMP, M_WAITOK);
1310                         if (uio.uio_rw == UIO_WRITE) {
1311                                 error = uiomove(ptr, len, &uio);
1312                                 if (error)
1313                                         goto ret;
1314                         }
1315                 }
1316                 sce = &sc->sc_endpoints[endpt][IN];
1317                 err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request, 
1318                           ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout);
1319                 if (err) {
1320                         error = EIO;
1321                         goto ret;
1322                 }
1323                 if (len != 0) {
1324                         if (uio.uio_rw == UIO_READ) {
1325                                 error = uiomove(ptr, len, &uio);
1326                                 if (error)
1327                                         goto ret;
1328                         }
1329                 }
1330         ret:
1331                 if (ptr)
1332                         free(ptr, M_TEMP);
1333                 return (error);
1334         }
1335         case USB_GET_DEVICEINFO:
1336                 usbd_fill_deviceinfo(sc->sc_udev,
1337                     (struct usb_device_info *)addr, 1);
1338                 break;
1339         default:
1340                 return (EINVAL);
1341         }
1342         return (0);
1343 }
1344
1345 int
1346 ugenioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p)
1347 {
1348         int endpt = UGENENDPOINT(dev);
1349         struct ugen_softc *sc;
1350         int error;
1351
1352         USB_GET_SC(ugen, UGENUNIT(dev), sc);
1353
1354         sc->sc_refcnt++;
1355         error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, p);
1356         if (--sc->sc_refcnt < 0)
1357                 usb_detach_wakeup(USBDEV(sc->sc_dev));
1358         return (error);
1359 }
1360
1361 int
1362 ugenpoll(dev_t dev, int events, usb_proc_ptr p)
1363 {
1364         struct ugen_softc *sc;
1365         struct ugen_endpoint *sce;
1366         int revents = 0;
1367         int s;
1368
1369         USB_GET_SC(ugen, UGENUNIT(dev), sc);
1370
1371         if (sc->sc_dying)
1372                 return (EIO);
1373
1374         /* XXX always IN */
1375         sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];
1376         if (sce == NULL)
1377                 return (EINVAL);
1378
1379         if (!sce->edesc) {
1380                 printf("ugenpoll: no edesc\n");
1381                 return (EIO);
1382         }
1383         if (!sce->pipeh) {
1384                 printf("ugenpoll: no pipe\n");
1385                 return (EIO);
1386         }
1387
1388         s = splusb();
1389         switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
1390         case UE_INTERRUPT:
1391                 if (events & (POLLIN | POLLRDNORM)) {
1392                         if (sce->q.c_cc > 0)
1393                                 revents |= events & (POLLIN | POLLRDNORM);
1394                         else
1395                                 selrecord(p, &sce->rsel);
1396                 }
1397                 break;
1398         case UE_ISOCHRONOUS:
1399                 if (events & (POLLIN | POLLRDNORM)) {
1400                         if (sce->cur != sce->fill)
1401                                 revents |= events & (POLLIN | POLLRDNORM);
1402                         else
1403                                 selrecord(p, &sce->rsel);
1404                 }
1405                 break;
1406         case UE_BULK:
1407                 /* 
1408                  * We have no easy way of determining if a read will
1409                  * yield any data or a write will happen.
1410                  * Pretend they will.
1411                  */
1412                 revents |= events & 
1413                            (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);
1414                 break;
1415         default:
1416                 break;
1417         }
1418         splx(s);
1419         return (revents);
1420 }
1421
1422 #if defined(__FreeBSD__)
1423 DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass, usbd_driver_load, 0);
1424 #endif