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

Cache object: 9f9c4f7b42514a1c791cad8f85fb0119


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