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

Cache object: f1e9eeb37458d0e041b0658256ac3825


[ 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.