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