The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/wscons/wsmux.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 31e2d35e0a5d13555a44b6394d5b21bc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.