The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/usbmisc/ugen/ugen.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 70750728c5839e6fde913045868951a8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.