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

          Line data    Source code
       1             : /*      $OpenBSD: video.c,v 1.41 2017/10/11 08:08:50 mpi Exp $  */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
       5             :  * Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org>
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : #include <sys/param.h>
      21             : #include <sys/systm.h>
      22             : #include <sys/errno.h>
      23             : #include <sys/ioctl.h>
      24             : #include <sys/fcntl.h>
      25             : #include <sys/poll.h>
      26             : #include <sys/device.h>
      27             : #include <sys/vnode.h>
      28             : #include <sys/kernel.h>
      29             : #include <sys/malloc.h>
      30             : #include <sys/conf.h>
      31             : #include <sys/videoio.h>
      32             : 
      33             : #include <dev/video_if.h>
      34             : 
      35             : #include <uvm/uvm_extern.h>
      36             : 
      37             : #ifdef VIDEO_DEBUG
      38             : #define DPRINTF(x)      do { printf x; } while (0)
      39             : #else
      40             : #define DPRINTF(x)
      41             : #endif
      42             : 
      43             : struct video_softc {
      44             :         struct device            dev;
      45             :         void                    *hw_hdl;        /* hardware driver handle */
      46             :         struct device           *sc_dev;        /* hardware device struct */
      47             :         struct video_hw_if      *hw_if;         /* hardware interface */
      48             :         char                     sc_dying;      /* device detached */
      49             : #define VIDEO_OPEN      0x01
      50             :         char                     sc_open;
      51             : 
      52             :         int                      sc_fsize;
      53             :         uint8_t                 *sc_fbuffer;
      54             :         size_t                   sc_fbufferlen;
      55             :         int                      sc_vidmode;    /* access mode */
      56             : #define         VIDMODE_NONE    0
      57             : #define         VIDMODE_MMAP    1
      58             : #define         VIDMODE_READ    2
      59             :         int                      sc_frames_ready;
      60             : 
      61             :         struct selinfo           sc_rsel;       /* read selector */
      62             : };
      63             : 
      64             : int     videoprobe(struct device *, void *, void *);
      65             : void    videoattach(struct device *, struct device *, void *);
      66             : int     videodetach(struct device *, int);
      67             : int     videoactivate(struct device *, int);
      68             : int     videoprint(void *, const char *);
      69             : 
      70             : void    video_intr(void *);
      71             : 
      72             : struct cfattach video_ca = {
      73             :         sizeof(struct video_softc), videoprobe, videoattach,
      74             :         videodetach, videoactivate
      75             : };
      76             : 
      77             : struct cfdriver video_cd = {
      78             :         NULL, "video", DV_DULL
      79             : };
      80             : 
      81             : int
      82           0 : videoprobe(struct device *parent, void *match, void *aux)
      83             : {
      84           0 :         return (1);
      85             : }
      86             : 
      87             : void
      88           0 : videoattach(struct device *parent, struct device *self, void *aux)
      89             : {
      90           0 :         struct video_softc *sc = (void *)self;
      91           0 :         struct video_attach_args *sa = aux;
      92             : 
      93           0 :         printf("\n");
      94           0 :         sc->hw_if = sa->hwif;
      95           0 :         sc->hw_hdl = sa->hdl;
      96           0 :         sc->sc_dev = parent;
      97           0 :         sc->sc_fbufferlen = 0;
      98             : 
      99           0 :         if (sc->hw_if->get_bufsize)
     100           0 :                 sc->sc_fbufferlen = (sc->hw_if->get_bufsize)(sc->hw_hdl);
     101           0 :         if (sc->sc_fbufferlen == 0) {
     102           0 :                 printf("video: could not request frame buffer size\n");
     103           0 :                 return;
     104             :         }
     105             : 
     106           0 :         sc->sc_fbuffer = malloc(sc->sc_fbufferlen, M_DEVBUF, M_NOWAIT);
     107           0 :         if (sc->sc_fbuffer == NULL) {
     108           0 :                 printf("video: could not allocate frame buffer\n");
     109           0 :                 return;
     110             :         }
     111           0 : }
     112             : 
     113             : int
     114           0 : videoopen(dev_t dev, int flags, int fmt, struct proc *p)
     115             : {
     116             :         int     unit;
     117             :         struct video_softc *sc;
     118             : 
     119           0 :         unit = VIDEOUNIT(dev);
     120           0 :         if (unit >= video_cd.cd_ndevs ||
     121           0 :             (sc = video_cd.cd_devs[unit]) == NULL ||
     122           0 :              sc->hw_if == NULL)
     123           0 :                 return (ENXIO);
     124             : 
     125           0 :         if (sc->sc_open & VIDEO_OPEN)
     126           0 :                 return (EBUSY);
     127           0 :         sc->sc_open |= VIDEO_OPEN;
     128             : 
     129           0 :         sc->sc_vidmode = VIDMODE_NONE;
     130           0 :         sc->sc_frames_ready = 0;
     131             : 
     132           0 :         if (sc->hw_if->open != NULL)
     133           0 :                 return (sc->hw_if->open(sc->hw_hdl, flags, &sc->sc_fsize,
     134           0 :                     sc->sc_fbuffer, video_intr, sc));
     135             :         else
     136           0 :                 return (0);
     137           0 : }
     138             : 
     139             : int
     140           0 : videoclose(dev_t dev, int flags, int fmt, struct proc *p)
     141             : {
     142             :         struct video_softc *sc;
     143             :         int r = 0;
     144             : 
     145           0 :         sc = video_cd.cd_devs[VIDEOUNIT(dev)];
     146             : 
     147           0 :         if (sc->hw_if->close != NULL)
     148           0 :                 r = sc->hw_if->close(sc->hw_hdl);
     149             : 
     150           0 :         sc->sc_open &= ~VIDEO_OPEN;
     151             : 
     152           0 :         return (r);
     153             : }
     154             : 
     155             : int
     156           0 : videoread(dev_t dev, struct uio *uio, int ioflag)
     157             : {
     158             :         struct video_softc *sc;
     159             :         int unit, error;
     160             :         size_t size;
     161             : 
     162           0 :         unit = VIDEOUNIT(dev);
     163           0 :         if (unit >= video_cd.cd_ndevs ||
     164           0 :             (sc = video_cd.cd_devs[unit]) == NULL)
     165           0 :                 return (ENXIO);
     166             : 
     167           0 :         if (sc->sc_dying)
     168           0 :                 return (EIO);
     169             : 
     170           0 :         if (sc->sc_vidmode == VIDMODE_MMAP)
     171           0 :                 return (EBUSY);
     172             : 
     173             :         /* start the stream if not already started */
     174           0 :         if (sc->sc_vidmode == VIDMODE_NONE && sc->hw_if->start_read) {
     175           0 :                 error = sc->hw_if->start_read(sc->hw_hdl);
     176           0 :                 if (error)
     177           0 :                         return (error);
     178           0 :                 sc->sc_vidmode = VIDMODE_READ;
     179           0 :         }
     180             :  
     181             :         DPRINTF(("resid=%zu\n", uio->uio_resid));
     182             : 
     183           0 :         if (sc->sc_frames_ready < 1) {
     184             :                 /* block userland read until a frame is ready */
     185           0 :                 error = tsleep(sc, PWAIT | PCATCH, "vid_rd", 0);
     186           0 :                 if (sc->sc_dying)
     187             :                         error = EIO;
     188           0 :                 if (error)
     189           0 :                         return (error);
     190             :         }
     191             : 
     192             :         /* move no more than 1 frame to userland, as per specification */
     193           0 :         size = ulmin(uio->uio_resid, sc->sc_fsize);
     194           0 :         error = uiomove(sc->sc_fbuffer, size, uio);
     195           0 :         sc->sc_frames_ready--;
     196           0 :         if (error)
     197           0 :                 return (error);
     198             : 
     199             :         DPRINTF(("uiomove successfully done (%zu bytes)\n", size));
     200             : 
     201           0 :         return (0);
     202           0 : }
     203             : 
     204             : int
     205           0 : videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
     206             : {
     207             :         struct video_softc *sc;
     208             :         int unit, error;
     209             : 
     210           0 :         unit = VIDEOUNIT(dev);
     211           0 :         if (unit >= video_cd.cd_ndevs ||
     212           0 :             (sc = video_cd.cd_devs[unit]) == NULL || sc->hw_if == NULL)
     213           0 :                 return (ENXIO);
     214             : 
     215             :         DPRINTF(("video_ioctl(%zu, '%c', %zu)\n",
     216             :             IOCPARM_LEN(cmd), (int) IOCGROUP(cmd), cmd & 0xff));
     217             : 
     218             :         error = EOPNOTSUPP;
     219           0 :         switch (cmd) {
     220             :         case VIDIOC_QUERYCAP:
     221           0 :                 if (sc->hw_if->querycap)
     222           0 :                         error = (sc->hw_if->querycap)(sc->hw_hdl,
     223           0 :                             (struct v4l2_capability *)data);
     224             :                 break;
     225             :         case VIDIOC_ENUM_FMT:
     226           0 :                 if (sc->hw_if->enum_fmt)
     227           0 :                         error = (sc->hw_if->enum_fmt)(sc->hw_hdl,
     228           0 :                             (struct v4l2_fmtdesc *)data);
     229             :                 break;
     230             :         case VIDIOC_ENUM_FRAMESIZES:
     231           0 :                 if (sc->hw_if->enum_fsizes)
     232           0 :                         error = (sc->hw_if->enum_fsizes)(sc->hw_hdl,
     233           0 :                             (struct v4l2_frmsizeenum *)data);
     234             :                 break;
     235             :         case VIDIOC_ENUM_FRAMEINTERVALS:
     236           0 :                 if (sc->hw_if->enum_fivals)
     237           0 :                         error = (sc->hw_if->enum_fivals)(sc->hw_hdl,
     238           0 :                             (struct v4l2_frmivalenum *)data);
     239             :                 break;
     240             :         case VIDIOC_S_FMT:
     241           0 :                 if (!(flags & FWRITE))
     242           0 :                         return (EACCES);
     243           0 :                 if (sc->hw_if->s_fmt)
     244           0 :                         error = (sc->hw_if->s_fmt)(sc->hw_hdl,
     245           0 :                             (struct v4l2_format *)data);
     246             :                 break;
     247             :         case VIDIOC_G_FMT:
     248           0 :                 if (sc->hw_if->g_fmt)
     249           0 :                         error = (sc->hw_if->g_fmt)(sc->hw_hdl,
     250           0 :                             (struct v4l2_format *)data);
     251             :                 break;
     252             :         case VIDIOC_S_PARM:
     253           0 :                 if (sc->hw_if->s_parm)
     254           0 :                         error = (sc->hw_if->s_parm)(sc->hw_hdl,
     255           0 :                             (struct v4l2_streamparm *)data);
     256             :                 break;
     257             :         case VIDIOC_G_PARM:
     258           0 :                 if (sc->hw_if->g_parm)
     259           0 :                         error = (sc->hw_if->g_parm)(sc->hw_hdl,
     260           0 :                             (struct v4l2_streamparm *)data);
     261             :                 break;
     262             :         case VIDIOC_ENUMINPUT:
     263           0 :                 if (sc->hw_if->enum_input)
     264           0 :                         error = (sc->hw_if->enum_input)(sc->hw_hdl,
     265           0 :                             (struct v4l2_input *)data);
     266             :                 break;
     267             :         case VIDIOC_S_INPUT:
     268           0 :                 if (sc->hw_if->s_input)
     269           0 :                         error = (sc->hw_if->s_input)(sc->hw_hdl,
     270           0 :                             (int)*data);
     271             :                 break;
     272             :         case VIDIOC_G_INPUT:
     273           0 :                 if (sc->hw_if->g_input)
     274           0 :                         error = (sc->hw_if->g_input)(sc->hw_hdl,
     275           0 :                             (int *)data);
     276             :                 break;
     277             :         case VIDIOC_REQBUFS:
     278           0 :                 if (sc->hw_if->reqbufs)
     279           0 :                         error = (sc->hw_if->reqbufs)(sc->hw_hdl,
     280           0 :                             (struct v4l2_requestbuffers *)data);
     281             :                 break;
     282             :         case VIDIOC_QUERYBUF:
     283           0 :                 if (sc->hw_if->querybuf)
     284           0 :                         error = (sc->hw_if->querybuf)(sc->hw_hdl,
     285           0 :                             (struct v4l2_buffer *)data);
     286             :                 break;
     287             :         case VIDIOC_QBUF:
     288           0 :                 if (sc->hw_if->qbuf)
     289           0 :                         error = (sc->hw_if->qbuf)(sc->hw_hdl,
     290           0 :                             (struct v4l2_buffer *)data);
     291             :                 break;
     292             :         case VIDIOC_DQBUF:
     293           0 :                 if (!sc->hw_if->dqbuf)
     294             :                         break;
     295             :                 /* should have called mmap() before now */
     296           0 :                 if (sc->sc_vidmode != VIDMODE_MMAP) {
     297             :                         error = EINVAL;
     298           0 :                         break;
     299             :                 }
     300           0 :                 error = (sc->hw_if->dqbuf)(sc->hw_hdl,
     301           0 :                     (struct v4l2_buffer *)data);
     302           0 :                 sc->sc_frames_ready--;
     303           0 :                 break;
     304             :         case VIDIOC_STREAMON:
     305           0 :                 if (sc->hw_if->streamon)
     306           0 :                         error = (sc->hw_if->streamon)(sc->hw_hdl,
     307           0 :                             (int)*data);
     308             :                 break;
     309             :         case VIDIOC_STREAMOFF:
     310           0 :                 if (sc->hw_if->streamoff)
     311           0 :                         error = (sc->hw_if->streamoff)(sc->hw_hdl,
     312           0 :                             (int)*data);
     313             :                 break;
     314             :         case VIDIOC_TRY_FMT:
     315           0 :                 if (sc->hw_if->try_fmt)
     316           0 :                         error = (sc->hw_if->try_fmt)(sc->hw_hdl,
     317           0 :                             (struct v4l2_format *)data);
     318             :                 break;
     319             :         case VIDIOC_QUERYCTRL:
     320           0 :                 if (sc->hw_if->queryctrl)
     321           0 :                         error = (sc->hw_if->queryctrl)(sc->hw_hdl,
     322           0 :                             (struct v4l2_queryctrl *)data);
     323             :                 break;
     324             :         case VIDIOC_G_CTRL:
     325           0 :                 if (sc->hw_if->g_ctrl)
     326           0 :                         error = (sc->hw_if->g_ctrl)(sc->hw_hdl,
     327           0 :                             (struct v4l2_control *)data);
     328             :                 break;
     329             :         case VIDIOC_S_CTRL:
     330           0 :                 if (sc->hw_if->s_ctrl)
     331           0 :                         error = (sc->hw_if->s_ctrl)(sc->hw_hdl,
     332           0 :                             (struct v4l2_control *)data);
     333             :                 break;
     334             :         default:
     335             :                 error = (ENOTTY);
     336           0 :         }
     337             : 
     338           0 :         return (error);
     339           0 : }
     340             : 
     341             : int
     342           0 : videopoll(dev_t dev, int events, struct proc *p)
     343             : {
     344           0 :         int unit = VIDEOUNIT(dev);
     345             :         struct video_softc *sc;
     346             :         int error, revents = 0;
     347             : 
     348           0 :         if (unit >= video_cd.cd_ndevs ||
     349           0 :             (sc = video_cd.cd_devs[unit]) == NULL)
     350           0 :                 return (POLLERR);
     351             : 
     352           0 :         if (sc->sc_dying)
     353           0 :                 return (POLLERR);
     354             : 
     355             :         DPRINTF(("%s: events=0x%x\n", __func__, events));
     356             : 
     357           0 :         if (events & (POLLIN | POLLRDNORM)) {
     358           0 :                 if (sc->sc_frames_ready > 0)
     359           0 :                         revents |= events & (POLLIN | POLLRDNORM);
     360             :         }
     361           0 :         if (revents == 0) {
     362           0 :                 if (events & (POLLIN | POLLRDNORM)) {
     363             :                         /*
     364             :                          * Start the stream in read() mode if not already
     365             :                          * started.  If the user wanted mmap() mode,
     366             :                          * he should have called mmap() before now.
     367             :                          */
     368           0 :                         if (sc->sc_vidmode == VIDMODE_NONE &&
     369           0 :                             sc->hw_if->start_read) {
     370           0 :                                 error = sc->hw_if->start_read(sc->hw_hdl);
     371           0 :                                 if (error)
     372           0 :                                         return (POLLERR);
     373           0 :                                 sc->sc_vidmode = VIDMODE_READ;
     374           0 :                         }
     375           0 :                         selrecord(p, &sc->sc_rsel);
     376           0 :                 }
     377             :         }
     378             : 
     379             :         DPRINTF(("%s: revents=0x%x\n", __func__, revents));
     380             : 
     381           0 :         return (revents);
     382           0 : }
     383             : 
     384             : paddr_t
     385           0 : videommap(dev_t dev, off_t off, int prot)
     386             : {
     387             :         struct video_softc *sc;
     388             :         int unit;
     389             :         caddr_t p;
     390           0 :         paddr_t pa;
     391             : 
     392             :         DPRINTF(("%s: off=%lld, prot=%d\n", __func__, off, prot));
     393             : 
     394           0 :         unit = VIDEOUNIT(dev);
     395           0 :         if (unit >= video_cd.cd_ndevs ||
     396           0 :             (sc = video_cd.cd_devs[unit]) == NULL)
     397           0 :                 return (-1);
     398             : 
     399           0 :         if (sc->sc_dying)
     400           0 :                 return (-1);
     401             : 
     402           0 :         if (sc->hw_if->mappage == NULL)
     403           0 :                 return (-1);
     404             : 
     405           0 :         p = sc->hw_if->mappage(sc->hw_hdl, off, prot);
     406           0 :         if (p == NULL)
     407           0 :                 return (-1);
     408           0 :         if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE)
     409           0 :                 panic("videommap: invalid page");
     410           0 :         sc->sc_vidmode = VIDMODE_MMAP;
     411             : 
     412           0 :         return (pa);
     413           0 : }
     414             : 
     415             : int
     416           0 : video_submatch(struct device *parent, void *match, void *aux)
     417             : {
     418           0 :         struct cfdata *cf = match;
     419             : 
     420           0 :         return (cf->cf_driver == &video_cd);
     421             : }
     422             : 
     423             : /*
     424             :  * Called from hardware driver. This is where the MI video driver gets
     425             :  * probed/attached to the hardware driver
     426             :  */
     427             : struct device *
     428           0 : video_attach_mi(struct video_hw_if *rhwp, void *hdlp, struct device *dev)
     429             : {
     430           0 :         struct video_attach_args arg;
     431             : 
     432           0 :         arg.hwif = rhwp;
     433           0 :         arg.hdl = hdlp;
     434           0 :         return (config_found_sm(dev, &arg, videoprint, video_submatch));
     435           0 : }
     436             : 
     437             : void
     438           0 : video_intr(void *addr)
     439             : {
     440           0 :         struct video_softc *sc = (struct video_softc *)addr;
     441             : 
     442             :         DPRINTF(("video_intr sc=%p\n", sc));
     443           0 :         if (sc->sc_vidmode != VIDMODE_NONE)
     444           0 :                 sc->sc_frames_ready++;
     445             :         else
     446           0 :                 printf("%s: interrupt but no streams!\n", __func__);
     447           0 :         if (sc->sc_vidmode == VIDMODE_READ)
     448           0 :                 wakeup(sc);
     449           0 :         selwakeup(&sc->sc_rsel);
     450           0 : }
     451             : 
     452             : int
     453           0 : videoprint(void *aux, const char *pnp)
     454             : {
     455           0 :         if (pnp != NULL)
     456           0 :                 printf("video at %s", pnp);
     457           0 :         return (UNCONF);
     458             : }
     459             : 
     460             : int
     461           0 : videodetach(struct device *self, int flags)
     462             : {
     463           0 :         struct video_softc *sc = (struct video_softc *)self;
     464             :         int maj, mn;
     465             : 
     466           0 :         if (sc->sc_fbuffer != NULL)
     467           0 :                 free(sc->sc_fbuffer, M_DEVBUF, sc->sc_fbufferlen);
     468             : 
     469             :         /* locate the major number */
     470           0 :         for (maj = 0; maj < nchrdev; maj++)
     471           0 :                 if (cdevsw[maj].d_open == videoopen)
     472             :                         break;
     473             : 
     474             :         /* Nuke the vnodes for any open instances (calls close). */
     475           0 :         mn = self->dv_unit;
     476           0 :         vdevgone(maj, mn, mn, VCHR);
     477             : 
     478           0 :         return (0);
     479             : }
     480             : 
     481             : int
     482           0 : videoactivate(struct device *self, int act)
     483             : {
     484           0 :         struct video_softc *sc = (struct video_softc *)self;
     485             : 
     486           0 :         switch (act) {
     487             :         case DVACT_DEACTIVATE:
     488           0 :                 sc->sc_dying = 1;
     489           0 :                 break;
     490             :         }
     491           0 :         return (0);
     492             : }

Generated by: LCOV version 1.13