LCOV - code coverage report
Current view: top level - dev/usb - ugen.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 722 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13