LCOV - code coverage report
Current view: top level - dev/wscons - wsmux.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 302 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: wsmux.c,v 1.32 2017/06/12 13:45:39 deraadt Exp $      */
       2             : /*      $NetBSD: wsmux.c,v 1.37 2005/04/30 03:47:12 augustss Exp $      */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1998, 2005 The NetBSD Foundation, Inc.
       6             :  * All rights reserved.
       7             :  *
       8             :  * Author: Lennart Augustsson <augustss@carlstedt.se>
       9             :  *         Carlstedt Research & Technology
      10             :  *
      11             :  * Redistribution and use in source and binary forms, with or without
      12             :  * modification, are permitted provided that the following conditions
      13             :  * are met:
      14             :  * 1. Redistributions of source code must retain the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer.
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      21             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      22             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      23             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      24             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      25             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      26             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      27             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      28             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      29             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      30             :  * POSSIBILITY OF SUCH DAMAGE.
      31             :  */
      32             : 
      33             : #include "wsmux.h"
      34             : #include "wsdisplay.h"
      35             : #include "wskbd.h"
      36             : #include "wsmouse.h"
      37             : 
      38             : /*
      39             :  * wscons mux device.
      40             :  *
      41             :  * The mux device is a collection of real mice and keyboards and acts as 
      42             :  * a merge point for all the events from the different real devices.
      43             :  */
      44             : 
      45             : #include <sys/param.h>
      46             : #include <sys/conf.h>
      47             : #include <sys/ioctl.h>
      48             : #include <sys/fcntl.h>
      49             : #include <sys/kernel.h>
      50             : #include <sys/malloc.h>
      51             : #include <sys/proc.h>
      52             : #include <sys/queue.h>
      53             : #include <sys/syslog.h>
      54             : #include <sys/systm.h>
      55             : #include <sys/tty.h>
      56             : #include <sys/signalvar.h>
      57             : #include <sys/device.h>
      58             : #include <sys/poll.h>
      59             : 
      60             : #include <dev/wscons/wsconsio.h>
      61             : #include <dev/wscons/wsksymdef.h>
      62             : #include <dev/wscons/wseventvar.h>
      63             : #include <dev/wscons/wsmuxvar.h>
      64             : 
      65             : #ifdef WSMUX_DEBUG
      66             : #define DPRINTF(x)      if (wsmuxdebug) printf x
      67             : #define DPRINTFN(n,x)   if (wsmuxdebug > (n)) printf x
      68             : int     wsmuxdebug = 0;
      69             : #else
      70             : #define DPRINTF(x)
      71             : #define DPRINTFN(n,x)
      72             : #endif
      73             : 
      74             : /*
      75             :  * The wsmux pseudo device is used to multiplex events from several wsmouse,
      76             :  * wskbd, and/or wsmux devices together.
      77             :  * The devices connected together form a tree with muxes in the interior
      78             :  * and real devices (mouse and kbd) at the leaves.  The special case of
      79             :  * a tree with one node (mux or other) is supported as well.
      80             :  * Only the device at the root of the tree can be opened (if a non-root
      81             :  * device is opened the subtree rooted at that point is severed from the
      82             :  * containing tree).  When the root is opened it allocates a wseventvar
      83             :  * struct which all the nodes in the tree will send their events too.
      84             :  * An ioctl() performed on the root is propagated to all the nodes.
      85             :  * There are also ioctl() operations to add and remove nodes from a tree.
      86             :  */
      87             : 
      88             : int     wsmux_mux_open(struct wsevsrc *, struct wseventvar *);
      89             : int     wsmux_mux_close(struct wsevsrc *);
      90             : 
      91             : void    wsmux_do_open(struct wsmux_softc *, struct wseventvar *);
      92             : 
      93             : void    wsmux_do_close(struct wsmux_softc *);
      94             : #if NWSDISPLAY > 0
      95             : int     wsmux_evsrc_set_display(struct device *, struct device *);
      96             : #else
      97             : #define wsmux_evsrc_set_display NULL
      98             : #endif
      99             : 
     100             : int     wsmux_do_displayioctl(struct device *dev, u_long cmd, caddr_t data,
     101             :             int flag, struct proc *p);
     102             : int     wsmux_do_ioctl(struct device *, u_long, caddr_t,int,struct proc *);
     103             : 
     104             : int     wsmux_add_mux(int, struct wsmux_softc *);
     105             : 
     106             : void    wsmuxattach(int);
     107             : 
     108             : struct wssrcops wsmux_srcops = {
     109             :         WSMUX_MUX,
     110             :         wsmux_mux_open, wsmux_mux_close, wsmux_do_ioctl, wsmux_do_displayioctl,
     111             :         wsmux_evsrc_set_display
     112             : };
     113             : 
     114             : /* From upper level */
     115             : void
     116           0 : wsmuxattach(int n)
     117             : {
     118           0 : }
     119             : 
     120             : /* Keep track of all muxes that have been allocated */
     121             : int nwsmux = 0;
     122             : struct wsmux_softc **wsmuxdevs = NULL;
     123             : 
     124             : /* Return mux n, create if necessary */
     125             : struct wsmux_softc *
     126           0 : wsmux_getmux(int n)
     127             : {
     128             :         struct wsmux_softc *sc;
     129             :         struct wsmux_softc **new, **old;
     130             :         int i;
     131             : 
     132             :         /* Make sure there is room for mux n in the table */
     133           0 :         if (n >= nwsmux) {
     134           0 :                 old = wsmuxdevs;
     135           0 :                 new = mallocarray(n + 1, sizeof (*wsmuxdevs),
     136             :                     M_DEVBUF, M_NOWAIT);
     137           0 :                 if (new == NULL) {
     138           0 :                         printf("wsmux_getmux: no memory for mux %d\n", n);
     139           0 :                         return (NULL);
     140             :                 }
     141           0 :                 if (old != NULL)
     142           0 :                         bcopy(old, new, nwsmux * sizeof(*wsmuxdevs));
     143           0 :                 for (i = nwsmux; i < (n + 1); i++)
     144           0 :                         new[i] = NULL;
     145           0 :                 if (old != NULL)
     146           0 :                         free(old, M_DEVBUF, nwsmux * sizeof(*wsmuxdevs));
     147           0 :                 wsmuxdevs = new;
     148           0 :                 nwsmux = n + 1;
     149           0 :         }
     150             : 
     151           0 :         sc = wsmuxdevs[n];
     152           0 :         if (sc == NULL) {
     153           0 :                 sc = wsmux_create("wsmux", n);
     154           0 :                 if (sc == NULL)
     155           0 :                         printf("wsmux: attach out of memory\n");
     156           0 :                 wsmuxdevs[n] = sc;
     157           0 :         }
     158           0 :         return (sc);
     159           0 : }
     160             : 
     161             : /*
     162             :  * open() of the pseudo device from device table.
     163             :  */
     164             : int
     165           0 : wsmuxopen(dev_t dev, int flags, int mode, struct proc *p)
     166             : {
     167             :         struct wsmux_softc *sc;
     168             :         struct wseventvar *evar;
     169             :         int unit;
     170             : 
     171           0 :         unit = minor(dev);
     172           0 :         sc = wsmux_getmux(unit);
     173           0 :         if (sc == NULL)
     174           0 :                 return (ENXIO);
     175             : 
     176             :         DPRINTF(("wsmuxopen: %s: sc=%p p=%p\n", sc->sc_base.me_dv.dv_xname, sc, p));
     177             :         
     178           0 :         if ((flags & (FREAD | FWRITE)) == FWRITE) {
     179             :                 /* Not opening for read, only ioctl is available. */
     180           0 :                 return (0);
     181             :         }
     182             : 
     183           0 :         if (sc->sc_base.me_parent != NULL) {
     184             :                 /* Grab the mux out of the greedy hands of the parent mux. */
     185             :                 DPRINTF(("wsmuxopen: detach\n"));
     186           0 :                 wsmux_detach_sc(&sc->sc_base);
     187           0 :         }
     188             : 
     189           0 :         if (sc->sc_base.me_evp != NULL)
     190             :                 /* Already open. */
     191           0 :                 return (EBUSY);
     192             : 
     193           0 :         evar = &sc->sc_base.me_evar;
     194           0 :         wsevent_init(evar);
     195           0 :         evar->io = p->p_p;
     196             : #ifdef WSDISPLAY_COMPAT_RAWKBD
     197           0 :         sc->sc_rawkbd = 0;
     198             : #endif
     199             : 
     200           0 :         wsmux_do_open(sc, evar);
     201             : 
     202           0 :         return (0);
     203           0 : }
     204             : 
     205             : /*
     206             :  * Open of a mux via the parent mux.
     207             :  */
     208             : int
     209           0 : wsmux_mux_open(struct wsevsrc *me, struct wseventvar *evar)
     210             : {
     211           0 :         struct wsmux_softc *sc = (struct wsmux_softc *)me;
     212             : 
     213             : #ifdef DIAGNOSTIC
     214           0 :         if (sc->sc_base.me_evp != NULL) {
     215           0 :                 printf("wsmux_mux_open: busy\n");
     216           0 :                 return (EBUSY);
     217             :         }
     218           0 :         if (sc->sc_base.me_parent == NULL) {
     219           0 :                 printf("wsmux_mux_open: no parent\n");
     220           0 :                 return (EINVAL);
     221             :         }
     222             : #endif
     223             : 
     224           0 :         wsmux_do_open(sc, evar);
     225             : 
     226           0 :         return (0);
     227           0 : }
     228             : 
     229             : /* Common part of opening a mux. */
     230             : void
     231           0 : wsmux_do_open(struct wsmux_softc *sc, struct wseventvar *evar)
     232             : {
     233             :         struct wsevsrc *me;
     234             : #ifdef DIAGNOSTIC
     235             :         int error;
     236             : #endif
     237             : 
     238           0 :         sc->sc_base.me_evp = evar; /* remember event variable, mark as open */
     239             : 
     240             :         /* Open all children. */
     241           0 :         TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
     242             :                 DPRINTF(("wsmuxopen: %s: m=%p dev=%s\n",
     243             :                          sc->sc_base.me_dv.dv_xname, me, me->me_dv.dv_xname));
     244             : #ifdef DIAGNOSTIC
     245           0 :                 if (me->me_evp != NULL) {
     246           0 :                         printf("wsmuxopen: dev already in use\n");
     247           0 :                         continue;
     248             :                 }
     249           0 :                 if (me->me_parent != sc) {
     250           0 :                         printf("wsmux_do_open: bad child=%p\n", me);
     251           0 :                         continue;
     252             :                 }
     253           0 :                 error = wsevsrc_open(me, evar);
     254             :                 if (error) {
     255             :                         DPRINTF(("wsmuxopen: open failed %d\n", error));
     256             :                 }
     257             : #else
     258             :                 /* ignore errors, failing children will not be marked open */
     259             :                 (void)wsevsrc_open(me, evar);
     260             : #endif
     261           0 :         }
     262           0 : }
     263             : 
     264             : /*
     265             :  * close() of the pseudo device from device table.
     266             :  */
     267             : int
     268           0 : wsmuxclose(dev_t dev, int flags, int mode, struct proc *p)
     269             : {
     270             :         struct wsmux_softc *sc =
     271           0 :             (struct wsmux_softc *)wsmuxdevs[minor(dev)];
     272           0 :         struct wseventvar *evar = sc->sc_base.me_evp;
     273             : 
     274           0 :         if (evar == NULL)
     275             :                 /* Not open for read */
     276           0 :                 return (0);
     277             : 
     278           0 :         wsmux_do_close(sc);
     279           0 :         sc->sc_base.me_evp = NULL;
     280           0 :         wsevent_fini(evar);
     281           0 :         return (0);
     282           0 : }
     283             : 
     284             : /*
     285             :  * Close of a mux via the parent mux.
     286             :  */
     287             : int
     288           0 : wsmux_mux_close(struct wsevsrc *me)
     289             : {
     290           0 :         me->me_evp = NULL;
     291           0 :         wsmux_do_close((struct wsmux_softc *)me);
     292           0 :         return (0);
     293             : }
     294             : 
     295             : /* Common part of closing a mux. */
     296             : void
     297           0 : wsmux_do_close(struct wsmux_softc *sc)
     298             : {
     299             :         struct wsevsrc *me;
     300             : 
     301             :         DPRINTF(("wsmuxclose: %s: sc=%p\n", sc->sc_base.me_dv.dv_xname, sc));
     302             : 
     303             :         /* Close all the children. */
     304           0 :         TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
     305             :                 DPRINTF(("wsmuxclose %s: m=%p dev=%s\n",
     306             :                          sc->sc_base.me_dv.dv_xname, me, me->me_dv.dv_xname));
     307             : #ifdef DIAGNOSTIC
     308           0 :                 if (me->me_parent != sc) {
     309           0 :                         printf("wsmuxclose: bad child=%p\n", me);
     310           0 :                         continue;
     311             :                 }
     312             : #endif
     313           0 :                 (void)wsevsrc_close(me);
     314           0 :                 me->me_evp = NULL;
     315           0 :         }
     316           0 : }
     317             : 
     318             : /*
     319             :  * read() of the pseudo device from device table.
     320             :  */
     321             : int
     322           0 : wsmuxread(dev_t dev, struct uio *uio, int flags)
     323             : {
     324           0 :         struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
     325             :         struct wseventvar *evar;
     326             :         int error;
     327             : 
     328           0 :         evar = sc->sc_base.me_evp;
     329           0 :         if (evar == NULL) {
     330             : #ifdef DIAGNOSTIC
     331             :                 /* XXX can we get here? */
     332           0 :                 printf("wsmuxread: not open\n");
     333             : #endif
     334           0 :                 return (EINVAL);
     335             :         }
     336             : 
     337             :         DPRINTFN(5,("wsmuxread: %s event read evar=%p\n",
     338             :                     sc->sc_base.me_dv.dv_xname, evar));
     339           0 :         error = wsevent_read(evar, uio, flags);
     340             :         DPRINTFN(5,("wsmuxread: %s event read ==> error=%d\n",
     341             :                     sc->sc_base.me_dv.dv_xname, error));
     342           0 :         return (error);
     343           0 : }
     344             : 
     345             : /*
     346             :  * ioctl of the pseudo device from device table.
     347             :  */
     348             : int
     349           0 : wsmuxioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
     350             : {
     351           0 :         return wsmux_do_ioctl(&wsmuxdevs[minor(dev)]->sc_base.me_dv, cmd, data, flag, p);
     352             : }
     353             : 
     354             : /*
     355             :  * ioctl of a mux via the parent mux, continuation of wsmuxioctl().
     356             :  */
     357             : int
     358           0 : wsmux_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
     359             :     struct proc *p)
     360             : {
     361           0 :         struct wsmux_softc *sc = (struct wsmux_softc *)dv;
     362             :         struct wsevsrc *me;
     363             :         int error, ok;
     364             :         int s, put, get, n;
     365             :         struct wseventvar *evar;
     366             :         struct wscons_event *ev;
     367             :         struct wsmux_device_list *l;
     368             : 
     369             :         DPRINTF(("wsmux_do_ioctl: %s: enter sc=%p, cmd=%08lx\n",
     370             :                  sc->sc_base.me_dv.dv_xname, sc, cmd));
     371             : 
     372           0 :         switch (cmd) {
     373             :         case WSMUXIO_INJECTEVENT:
     374             :         case WSMUXIO_ADD_DEVICE:
     375             :         case WSMUXIO_REMOVE_DEVICE:
     376             : #ifdef WSDISPLAY_COMPAT_RAWKBD
     377             :         case WSKBDIO_SETMODE:
     378             : #endif
     379           0 :                 if ((flag & FWRITE) == 0)
     380           0 :                         return (EACCES);
     381             :         }
     382             : 
     383           0 :         switch (cmd) {
     384             :         case WSMUXIO_INJECTEVENT:
     385             :                 /* Inject an event, e.g., from moused. */
     386             :                 DPRINTF(("%s: inject\n", sc->sc_base.me_dv.dv_xname));
     387           0 :                 evar = sc->sc_base.me_evp;
     388           0 :                 if (evar == NULL) {
     389             :                         /* No event sink, so ignore it. */
     390             :                         DPRINTF(("wsmux_do_ioctl: event ignored\n"));
     391           0 :                         return (0);
     392             :                 }
     393             : 
     394           0 :                 s = spltty();
     395           0 :                 get = evar->get;
     396           0 :                 put = evar->put;
     397           0 :                 ev = &evar->q[put];
     398           0 :                 if (++put % WSEVENT_QSIZE == get) {
     399             :                         put--;
     400           0 :                         splx(s);
     401           0 :                         return (ENOSPC);
     402             :                 }
     403           0 :                 if (put >= WSEVENT_QSIZE)
     404           0 :                         put = 0;
     405           0 :                 *ev = *(struct wscons_event *)data;
     406           0 :                 nanotime(&ev->time);
     407           0 :                 evar->put = put;
     408           0 :                 WSEVENT_WAKEUP(evar);
     409           0 :                 splx(s);
     410           0 :                 return (0);
     411             :         case WSMUXIO_ADD_DEVICE:
     412             : #define d ((struct wsmux_device *)data)
     413             :                 DPRINTF(("%s: add type=%d, no=%d\n", sc->sc_base.me_dv.dv_xname,
     414             :                          d->type, d->idx));
     415           0 :                 switch (d->type) {
     416             : #if NWSMOUSE > 0
     417             :                 case WSMUX_MOUSE:
     418           0 :                         return (wsmouse_add_mux(d->idx, sc));
     419             : #endif
     420             : #if NWSKBD > 0
     421             :                 case WSMUX_KBD:
     422           0 :                         return (wskbd_add_mux(d->idx, sc));
     423             : #endif
     424             :                 case WSMUX_MUX:
     425           0 :                         return (wsmux_add_mux(d->idx, sc));
     426             :                 default:
     427           0 :                         return (EINVAL);
     428             :                 }
     429             :         case WSMUXIO_REMOVE_DEVICE:
     430             :                 DPRINTF(("%s: rem type=%d, no=%d\n", sc->sc_base.me_dv.dv_xname,
     431             :                          d->type, d->idx));
     432             :                 /* Locate the device */
     433           0 :                 TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
     434           0 :                         if (me->me_ops->type == d->type &&
     435           0 :                             me->me_dv.dv_unit == d->idx) {
     436             :                                 DPRINTF(("wsmux_do_ioctl: detach\n"));
     437           0 :                                 wsmux_detach_sc(me);
     438           0 :                                 return (0);
     439             :                         }
     440             :                 }
     441           0 :                 return (EINVAL);
     442             : #undef d
     443             : 
     444             :         case WSMUXIO_LIST_DEVICES:
     445             :                 DPRINTF(("%s: list\n", sc->sc_base.me_dv.dv_xname));
     446           0 :                 l = (struct wsmux_device_list *)data;
     447             :                 n = 0;
     448           0 :                 TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
     449           0 :                         if (n >= WSMUX_MAXDEV)
     450             :                                 break;
     451           0 :                         l->devices[n].type = me->me_ops->type;
     452           0 :                         l->devices[n].idx = me->me_dv.dv_unit;
     453           0 :                         n++;
     454             :                 }
     455           0 :                 l->ndevices = n;
     456           0 :                 return (0);
     457             : #ifdef WSDISPLAY_COMPAT_RAWKBD
     458             :         case WSKBDIO_SETMODE:
     459           0 :                 sc->sc_rawkbd = *(int *)data;
     460             :                 DPRINTF(("wsmux_do_ioctl: save rawkbd = %d\n", sc->sc_rawkbd));
     461           0 :                 break;
     462             : #endif
     463             :         case FIONBIO:
     464             :                 DPRINTF(("%s: FIONBIO\n", sc->sc_base.me_dv.dv_xname));
     465           0 :                 return (0);
     466             : 
     467             :         case FIOASYNC:
     468             :                 DPRINTF(("%s: FIOASYNC\n", sc->sc_base.me_dv.dv_xname));
     469           0 :                 evar = sc->sc_base.me_evp;
     470           0 :                 if (evar == NULL)
     471           0 :                         return (EINVAL);
     472           0 :                 evar->async = *(int *)data != 0;
     473           0 :                 return (0);
     474             :         case FIOSETOWN:
     475             :                 DPRINTF(("%s: FIOSETOWN\n", sc->sc_base.me_dv.dv_xname));
     476           0 :                 evar = sc->sc_base.me_evp;
     477           0 :                 if (evar == NULL)
     478           0 :                         return (EINVAL);
     479           0 :                 if (-*(int *)data != evar->io->ps_pgid
     480           0 :                     && *(int *)data != evar->io->ps_pid)
     481           0 :                         return (EPERM);
     482           0 :                 return (0);
     483             :         case TIOCSPGRP:
     484             :                 DPRINTF(("%s: TIOCSPGRP\n", sc->sc_base.me_dv.dv_xname));
     485           0 :                 evar = sc->sc_base.me_evp;
     486           0 :                 if (evar == NULL)
     487           0 :                         return (EINVAL);
     488           0 :                 if (*(int *)data != evar->io->ps_pgid)
     489           0 :                         return (EPERM);
     490           0 :                 return (0);
     491             :         default:
     492             :                 DPRINTF(("%s: unknown\n", sc->sc_base.me_dv.dv_xname));
     493             :                 break;
     494             :         }
     495             : 
     496           0 :         if (sc->sc_base.me_evp == NULL
     497             : #if NWSDISPLAY > 0
     498           0 :             && sc->sc_displaydv == NULL
     499             : #endif
     500             :             )
     501           0 :                 return (EACCES);
     502             : 
     503             :         /* Return 0 if any of the ioctl() succeeds, otherwise the last error */
     504             :         error = 0;
     505             :         ok = 0;
     506           0 :         TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
     507             : #ifdef DIAGNOSTIC
     508             :                 /* XXX check evp? */
     509           0 :                 if (me->me_parent != sc) {
     510           0 :                         printf("wsmux_do_ioctl: bad child %p\n", me);
     511           0 :                         continue;
     512             :                 }
     513             : #endif
     514           0 :                 error = wsevsrc_ioctl(me, cmd, data, flag, p);
     515             :                 DPRINTF(("wsmux_do_ioctl: %s: me=%p dev=%s ==> %d\n",
     516             :                          sc->sc_base.me_dv.dv_xname, me, me->me_dv.dv_xname,
     517             :                          error));
     518           0 :                 if (!error)
     519           0 :                         ok = 1;
     520             :         }
     521           0 :         if (ok)
     522           0 :                 error = 0;
     523             : 
     524           0 :         return (error);
     525           0 : }
     526             : 
     527             : /*
     528             :  * poll() of the pseudo device from device table.
     529             :  */
     530             : int
     531           0 : wsmuxpoll(dev_t dev, int events, struct proc *p)
     532             : {
     533           0 :         struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
     534             : 
     535           0 :         if (sc->sc_base.me_evp == NULL) {
     536             : #ifdef DIAGNOSTIC
     537           0 :                 printf("wsmuxpoll: not open\n");
     538             : #endif
     539           0 :                 return (POLLERR);
     540             :         }
     541             : 
     542           0 :         return (wsevent_poll(sc->sc_base.me_evp, events, p));
     543           0 : }
     544             : 
     545             : int
     546           0 : wsmuxkqfilter(dev_t dev, struct knote *kn)
     547             : {
     548           0 :         struct wsmux_softc *sc = wsmuxdevs[minor(dev)];
     549             : 
     550           0 :         if (sc->sc_base.me_evp == NULL)
     551           0 :                 return (ENXIO);
     552           0 :         return (wsevent_kqfilter(sc->sc_base.me_evp, kn));
     553           0 : }
     554             : 
     555             : /*
     556             :  * Add mux unit as a child to muxsc.
     557             :  */
     558             : int
     559           0 : wsmux_add_mux(int unit, struct wsmux_softc *muxsc)
     560             : {
     561             :         struct wsmux_softc *sc, *m;
     562             : 
     563           0 :         sc = wsmux_getmux(unit);
     564           0 :         if (sc == NULL)
     565           0 :                 return (ENXIO);
     566             : 
     567             :         DPRINTF(("wsmux_add_mux: %s(%p) to %s(%p)\n",
     568             :                  sc->sc_base.me_dv.dv_xname, sc, muxsc->sc_base.me_dv.dv_xname,
     569             :                  muxsc));
     570             : 
     571           0 :         if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL)
     572           0 :                 return (EBUSY);
     573             : 
     574             :         /* The mux we are adding must not be an ancestor of itself. */
     575           0 :         for (m = muxsc; m != NULL ; m = m->sc_base.me_parent)
     576           0 :                 if (m == sc)
     577           0 :                         return (EINVAL);
     578             : 
     579           0 :         return (wsmux_attach_sc(muxsc, &sc->sc_base));
     580           0 : }
     581             : 
     582             : /* Create a new mux softc. */
     583             : struct wsmux_softc *
     584           0 : wsmux_create(const char *name, int unit)
     585             : {
     586             :         struct wsmux_softc *sc;
     587             : 
     588             :         DPRINTF(("wsmux_create: allocating\n"));
     589           0 :         sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT | M_ZERO);
     590           0 :         if (sc == NULL)
     591           0 :                 return (NULL);
     592           0 :         TAILQ_INIT(&sc->sc_cld);
     593           0 :         snprintf(sc->sc_base.me_dv.dv_xname, sizeof sc->sc_base.me_dv.dv_xname,
     594             :                  "%s%d", name, unit);
     595           0 :         sc->sc_base.me_dv.dv_unit = unit;
     596           0 :         sc->sc_base.me_ops = &wsmux_srcops;
     597           0 :         sc->sc_kbd_layout = KB_NONE;
     598           0 :         return (sc);
     599           0 : }
     600             : 
     601             : /* Attach me as a child to sc. */
     602             : int
     603           0 : wsmux_attach_sc(struct wsmux_softc *sc, struct wsevsrc *me)
     604             : {
     605             :         int error;
     606             : 
     607           0 :         if (sc == NULL)
     608           0 :                 return (EINVAL);
     609             : 
     610             :         DPRINTF(("wsmux_attach_sc: %s(%p): type=%d\n",
     611             :                  sc->sc_base.me_dv.dv_xname, sc, me->me_ops->type));
     612             : 
     613             : #ifdef DIAGNOSTIC
     614           0 :         if (me->me_parent != NULL) {
     615           0 :                 printf("wsmux_attach_sc: busy\n");
     616           0 :                 return (EBUSY);
     617             :         }
     618             : #endif
     619           0 :         me->me_parent = sc;
     620           0 :         TAILQ_INSERT_TAIL(&sc->sc_cld, me, me_next);
     621             : 
     622             :         error = 0;
     623             : #if NWSDISPLAY > 0
     624           0 :         if (sc->sc_displaydv != NULL) {
     625             :                 /* This is a display mux, so attach the new device to it. */
     626             :                 DPRINTF(("wsmux_attach_sc: %s: set display %p\n",
     627             :                          sc->sc_base.me_dv.dv_xname, sc->sc_displaydv));
     628           0 :                 if (me->me_ops->dsetdisplay != NULL) {
     629           0 :                         error = wsevsrc_set_display(me, sc->sc_displaydv);
     630             :                         /* Ignore that the console already has a display. */
     631           0 :                         if (error == EBUSY)
     632             :                                 error = 0;
     633           0 :                         if (!error) {
     634             : #ifdef WSDISPLAY_COMPAT_RAWKBD
     635             :                                 DPRINTF(("wsmux_attach_sc: %s set rawkbd=%d\n",
     636             :                                          me->me_dv.dv_xname, sc->sc_rawkbd));
     637           0 :                                 (void)wsevsrc_ioctl(me, WSKBDIO_SETMODE,
     638             :                                                     &sc->sc_rawkbd, FWRITE, 0);
     639             : #endif
     640           0 :                         }
     641             :                 }
     642             :         }
     643             : #endif
     644           0 :         if (sc->sc_base.me_evp != NULL) {
     645             :                 /* Mux is open, so open the new subdevice */
     646             :                 DPRINTF(("wsmux_attach_sc: %s: calling open of %s\n",
     647             :                          sc->sc_base.me_dv.dv_xname, me->me_dv.dv_xname));
     648           0 :                 error = wsevsrc_open(me, sc->sc_base.me_evp);
     649           0 :         } else {
     650             :                 DPRINTF(("wsmux_attach_sc: %s not open\n",
     651             :                          sc->sc_base.me_dv.dv_xname));
     652             :         }
     653             : 
     654           0 :         if (error) {
     655           0 :                 me->me_parent = NULL;
     656           0 :                 TAILQ_REMOVE(&sc->sc_cld, me, me_next);
     657           0 :         }
     658             : 
     659             :         DPRINTF(("wsmux_attach_sc: %s(%p) done, error=%d\n",
     660             :                  sc->sc_base.me_dv.dv_xname, sc, error));
     661           0 :         return (error);
     662           0 : }
     663             : 
     664             : /* Remove me from the parent. */
     665             : void
     666           0 : wsmux_detach_sc(struct wsevsrc *me)
     667             : {
     668           0 :         struct wsmux_softc *sc = me->me_parent;
     669             : 
     670             :         DPRINTF(("wsmux_detach_sc: %s(%p) parent=%p\n",
     671             :                  me->me_dv.dv_xname, me, sc));
     672             : 
     673             : #ifdef DIAGNOSTIC
     674           0 :         if (sc == NULL) {
     675           0 :                 printf("wsmux_detach_sc: %s has no parent\n",
     676           0 :                        me->me_dv.dv_xname);
     677           0 :                 return;
     678             :         }
     679             : #endif
     680             : 
     681             : #if NWSDISPLAY > 0
     682           0 :         if (sc->sc_displaydv != NULL) {
     683           0 :                 if (me->me_ops->dsetdisplay != NULL)
     684             :                         /* ignore error, there's nothing we can do */
     685           0 :                         (void)wsevsrc_set_display(me, NULL);
     686             :         } else
     687             : #endif
     688           0 :                 if (me->me_evp != NULL) {
     689             :                 DPRINTF(("wsmux_detach_sc: close\n"));
     690             :                 /* mux device is open, so close multiplexee */
     691           0 :                 (void)wsevsrc_close(me);
     692           0 :         }
     693             : 
     694           0 :         TAILQ_REMOVE(&sc->sc_cld, me, me_next);
     695           0 :         me->me_parent = NULL;
     696             : 
     697             :         DPRINTF(("wsmux_detach_sc: done sc=%p\n", sc));
     698           0 : }
     699             : 
     700             : /*
     701             :  * Display ioctl() of a mux via the parent mux.
     702             :  */
     703             : int
     704           0 : wsmux_do_displayioctl(struct device *dv, u_long cmd, caddr_t data, int flag,
     705             :     struct proc *p)
     706             : {
     707           0 :         struct wsmux_softc *sc = (struct wsmux_softc *)dv;
     708             :         struct wsevsrc *me;
     709             :         int error, ok;
     710             : 
     711             :         DPRINTF(("wsmux_displayioctl: %s: sc=%p, cmd=%08lx\n",
     712             :                  sc->sc_base.me_dv.dv_xname, sc, cmd));
     713             : 
     714             : #ifdef WSDISPLAY_COMPAT_RAWKBD
     715           0 :         if (cmd == WSKBDIO_SETMODE) {
     716           0 :                 sc->sc_rawkbd = *(int *)data;
     717             :                 DPRINTF(("wsmux_displayioctl: rawkbd = %d\n", sc->sc_rawkbd));
     718           0 :         }
     719             : #endif
     720             : 
     721             :         /*
     722             :          * Return 0 if any of the ioctl() succeeds, otherwise the last error.
     723             :          * Return -1 if no mux component accepts the ioctl.
     724             :          */
     725             :         error = -1;
     726             :         ok = 0;
     727           0 :         TAILQ_FOREACH(me, &sc->sc_cld, me_next) {
     728             :                 DPRINTF(("wsmux_displayioctl: me=%p\n", me));
     729             : #ifdef DIAGNOSTIC
     730           0 :                 if (me->me_parent != sc) {
     731           0 :                         printf("wsmux_displayioctl: bad child %p\n", me);
     732           0 :                         continue;
     733             :                 }
     734             : #endif
     735           0 :                 if (me->me_ops->ddispioctl != NULL) {
     736           0 :                         error = wsevsrc_display_ioctl(me, cmd, data, flag, p);
     737             :                         DPRINTF(("wsmux_displayioctl: me=%p dev=%s ==> %d\n",
     738             :                                  me, me->me_dv.dv_xname, error));
     739           0 :                         if (!error)
     740           0 :                                 ok = 1;
     741             :                 }
     742             :         }
     743           0 :         if (ok)
     744           0 :                 error = 0;
     745             : 
     746           0 :         return (error);
     747             : }
     748             : 
     749             : #if NWSDISPLAY > 0
     750             : /*
     751             :  * Set display of a mux via the parent mux.
     752             :  */
     753             : int
     754           0 : wsmux_evsrc_set_display(struct device *dv, struct device *displaydv)
     755             : {
     756           0 :         struct wsmux_softc *sc = (struct wsmux_softc *)dv;
     757             : 
     758             :         DPRINTF(("wsmux_evsrc_set_display: %s: displaydv=%p\n",
     759             :                  sc->sc_base.me_dv.dv_xname, displaydv));
     760             : 
     761           0 :         if (displaydv != NULL) {
     762           0 :                 if (sc->sc_displaydv != NULL)
     763           0 :                         return (EBUSY);
     764             :         } else {
     765           0 :                 if (sc->sc_displaydv == NULL)
     766           0 :                         return (ENXIO);
     767             :         }
     768             : 
     769           0 :         return wsmux_set_display(sc, displaydv);
     770           0 : }
     771             : 
     772             : int
     773           0 : wsmux_set_display(struct wsmux_softc *sc, struct device *displaydv)
     774             : {
     775             :         struct device *odisplaydv;
     776             :         struct wsevsrc *me;
     777           0 :         struct wsmux_softc *nsc = displaydv ? sc : NULL;
     778             :         int error, ok;
     779             : 
     780           0 :         odisplaydv = sc->sc_displaydv;
     781           0 :         sc->sc_displaydv = displaydv;
     782             : 
     783             :         if (displaydv) {
     784             :                 DPRINTF(("%s: connecting to %s\n",
     785             :                        sc->sc_base.me_dv.dv_xname, displaydv->dv_xname));
     786             :         }
     787             :         ok = 0;
     788             :         error = 0;
     789           0 :         TAILQ_FOREACH(me, &sc->sc_cld,me_next) {
     790             : #ifdef DIAGNOSTIC
     791           0 :                 if (me->me_parent != sc) {
     792           0 :                         printf("wsmux_set_display: bad child parent %p\n", me);
     793           0 :                         continue;
     794             :                 }
     795             : #endif
     796           0 :                 if (me->me_ops->dsetdisplay != NULL) {
     797           0 :                         error = wsevsrc_set_display(me,
     798             :                             nsc ? nsc->sc_displaydv : NULL);
     799             :                         DPRINTF(("wsmux_set_display: m=%p dev=%s error=%d\n",
     800             :                                  me, me->me_dv.dv_xname, error));
     801           0 :                         if (!error) {
     802             :                                 ok = 1;
     803             : #ifdef WSDISPLAY_COMPAT_RAWKBD
     804             :                                 DPRINTF(("wsmux_set_display: %s set rawkbd=%d\n"
     805             : ,
     806             :                                          me->me_dv.dv_xname, sc->sc_rawkbd));
     807           0 :                                 (void)wsevsrc_ioctl(me, WSKBDIO_SETMODE,
     808             :                                                     &sc->sc_rawkbd, FWRITE, 0);
     809             : #endif
     810           0 :                         }
     811             :                 }
     812             :         }
     813           0 :         if (ok)
     814           0 :                 error = 0;
     815             : 
     816             :         if (displaydv == NULL) {
     817             :                 DPRINTF(("%s: disconnecting from %s\n",
     818             :                        sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname));
     819             :         }
     820             : 
     821           0 :         return (error);
     822             : }
     823             : #endif /* NWSDISPLAY > 0 */
     824             : 
     825             : uint32_t
     826           0 : wsmux_get_layout(struct wsmux_softc *sc)
     827             : {
     828           0 :         return sc->sc_kbd_layout;
     829             : }
     830             : 
     831             : void
     832           0 : wsmux_set_layout(struct wsmux_softc *sc, uint32_t layout)
     833             : {
     834           0 :         if ((layout & KB_DEFAULT) == 0)
     835           0 :                 sc->sc_kbd_layout = layout;
     836           0 : }

Generated by: LCOV version 1.13