[BACK]Return to wsmux.c CVS log [TXT][DIR] Up to [local] / sys / dev / wscons

Annotation of sys/dev/wscons/wsmux.c, Revision 1.1.1.1

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

CVSweb