[BACK]Return to spkr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev

Annotation of src/sys/dev/spkr.c, Revision 1.15.4.1

1.15.4.1! pgoyette    1: /*     $NetBSD: spkr.c,v 1.16 2018/09/03 16:29:30 riastradh Exp $      */
1.1       christos    2:
                      3: /*
                      4:  * Copyright (c) 1990 Eric S. Raymond (esr@snark.thyrsus.com)
                      5:  * Copyright (c) 1990 Andrew A. Chernov (ache@astral.msk.su)
                      6:  * Copyright (c) 1990 Lennart Augustsson (lennart@augustsson.net)
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *     This product includes software developed by Eric S. Raymond
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35:
                     36: /*
                     37:  * spkr.c -- device driver for console speaker on 80386
                     38:  *
                     39:  * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
                     40:  *      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
                     41:  *      386bsd only clean version, all SYSV stuff removed
                     42:  *      use hz value from param.c
                     43:  */
                     44:
                     45: #include <sys/cdefs.h>
1.15.4.1! pgoyette   46: __KERNEL_RCSID(0, "$NetBSD: spkr.c,v 1.16 2018/09/03 16:29:30 riastradh Exp $");
1.1       christos   47:
1.10      pgoyette   48: #if defined(_KERNEL_OPT)
1.9       nat        49: #include "wsmux.h"
1.10      pgoyette   50: #endif
1.9       nat        51:
1.1       christos   52: #include <sys/param.h>
                     53: #include <sys/systm.h>
                     54: #include <sys/kernel.h>
                     55: #include <sys/errno.h>
                     56: #include <sys/device.h>
                     57: #include <sys/malloc.h>
                     58: #include <sys/module.h>
                     59: #include <sys/uio.h>
                     60: #include <sys/proc.h>
                     61: #include <sys/ioctl.h>
                     62: #include <sys/conf.h>
                     63:
                     64: #include <sys/bus.h>
                     65:
                     66: #include <dev/spkrio.h>
1.2       christos   67: #include <dev/spkrvar.h>
1.9       nat        68: #include <dev/wscons/wsconsio.h>
                     69: #include <dev/wscons/wsbellvar.h>
                     70: #include <dev/wscons/wsbellmuxvar.h>
1.1       christos   71:
1.15      riastrad   72: #include "ioconf.h"
                     73:
1.1       christos   74: dev_type_open(spkropen);
                     75: dev_type_close(spkrclose);
                     76: dev_type_write(spkrwrite);
                     77: dev_type_ioctl(spkrioctl);
                     78:
                     79: const struct cdevsw spkr_cdevsw = {
                     80:        .d_open = spkropen,
                     81:        .d_close = spkrclose,
                     82:        .d_read = noread,
                     83:        .d_write = spkrwrite,
                     84:        .d_ioctl = spkrioctl,
                     85:        .d_stop = nostop,
                     86:        .d_tty = notty,
                     87:        .d_poll = nopoll,
                     88:        .d_mmap = nommap,
                     89:        .d_kqfilter = nokqfilter,
                     90:        .d_discard = nodiscard,
                     91:        .d_flag = D_OTHER
                     92: };
                     93:
1.4       christos   94: static void playinit(struct spkr_softc *);
                     95: static void playtone(struct spkr_softc *, int, int, int);
                     96: static void playstring(struct spkr_softc *, const char *, size_t);
1.1       christos   97:
                     98: /**************** PLAY STRING INTERPRETER BEGINS HERE **********************
                     99:  *
                    100:  * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
                    101:  * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
                    102:  * Requires spkr_tone(), spkr_rest(). String play is not interruptible
                    103:  * except possibly at physical block boundaries.
                    104:  */
                    105:
                    106: #define dtoi(c)                ((c) - '0')
                    107:
                    108: /*
                    109:  * Magic number avoidance...
                    110:  */
                    111: #define SECS_PER_MIN   60      /* seconds per minute */
                    112: #define WHOLE_NOTE     4       /* quarter notes per whole note */
                    113: #define MIN_VALUE      64      /* the most we can divide a note by */
                    114: #define DFLT_VALUE     4       /* default value (quarter-note) */
                    115: #define FILLTIME       8       /* for articulation, break note in parts */
                    116: #define STACCATO       6       /* 6/8 = 3/4 of note is filled */
                    117: #define NORMAL         7       /* 7/8ths of note interval is filled */
                    118: #define LEGATO         8       /* all of note interval is filled */
                    119: #define DFLT_OCTAVE    4       /* default octave */
                    120: #define MIN_TEMPO      32      /* minimum tempo */
                    121: #define DFLT_TEMPO     120     /* default tempo */
                    122: #define MAX_TEMPO      255     /* max tempo */
                    123: #define NUM_MULT       3       /* numerator of dot multiplier */
                    124: #define DENOM_MULT     2       /* denominator of dot multiplier */
                    125:
                    126: /* letter to half-tone:  A   B  C  D  E  F  G */
                    127: static const int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
                    128:
                    129: /*
                    130:  * This is the American Standard A440 Equal-Tempered scale with frequencies
                    131:  * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
                    132:  * our octave 0 is standard octave 2.
                    133:  */
                    134: #define OCTAVE_NOTES   12      /* semitones per octave */
                    135: static const int pitchtab[] =
                    136: {
                    137: /*        C     C#    D     D#    E     F     F#    G     G#    A     A#    B*/
                    138: /* 0 */   65,   69,   73,   78,   82,   87,   93,   98,  103,  110,  117,  123,
                    139: /* 1 */  131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
                    140: /* 2 */  262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,
                    141: /* 3 */  523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,
                    142: /* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
                    143: /* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
                    144: /* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
                    145: };
                    146: #define NOCTAVES (int)(__arraycount(pitchtab) / OCTAVE_NOTES)
                    147:
                    148: static void
1.4       christos  149: playinit(struct spkr_softc *sc)
1.1       christos  150: {
1.4       christos  151:        sc->sc_octave = DFLT_OCTAVE;
                    152:        sc->sc_whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
                    153:        sc->sc_fill = NORMAL;
                    154:        sc->sc_value = DFLT_VALUE;
                    155:        sc->sc_octtrack = false;
                    156:        sc->sc_octprefix = true;/* act as though there was an initial O(n) */
1.1       christos  157: }
                    158:
1.4       christos  159: /* play tone of proper duration for current rhythm signature */
1.1       christos  160: static void
1.4       christos  161: playtone(struct spkr_softc *sc, int pitch, int val, int sustain)
1.1       christos  162: {
1.4       christos  163:        int sound, silence, snum = 1, sdenom = 1;
1.1       christos  164:
1.4       christos  165:        /* this weirdness avoids floating-point arithmetic */
                    166:        for (; sustain; sustain--) {
                    167:                snum *= NUM_MULT;
                    168:                sdenom *= DENOM_MULT;
                    169:        }
1.1       christos  170:
1.4       christos  171:        if (pitch == -1) {
                    172:                (*sc->sc_rest)(sc->sc_dev, sc->sc_whole
                    173:                    * snum / (val * sdenom));
                    174:                return;
                    175:        }
                    176:
                    177:        int fac = sc->sc_whole * (FILLTIME - sc->sc_fill);
                    178:        int fval = FILLTIME * val;
                    179:        sound = (sc->sc_whole * snum) / (val * sdenom) -  fac / fval;
                    180:        silence = fac * snum / (fval * sdenom);
1.1       christos  181:
                    182: #ifdef SPKRDEBUG
1.4       christos  183:        aprint_debug_dev(sc->sc_dev,
                    184:            "%s: pitch %d for %d ticks, rest for %d ticks\n", __func__,
1.1       christos  185:            pitch, sound, silence);
                    186: #endif /* SPKRDEBUG */
                    187:
1.4       christos  188:        (*sc->sc_tone)(sc->sc_dev, pitchtab[pitch], sound);
                    189:        if (sc->sc_fill != LEGATO)
                    190:                (*sc->sc_rest)(sc->sc_dev, silence);
1.1       christos  191: }
                    192:
1.4       christos  193: /* interpret and play an item from a notation string */
1.1       christos  194: static void
1.4       christos  195: playstring(struct spkr_softc *sc, const char *cp, size_t slen)
1.1       christos  196: {
1.4       christos  197:        int             pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
                    198:
                    199: #define GETNUM(cp, v)  \
                    200:        for (v = 0; slen > 0 && isdigit((unsigned char)cp[1]); ) { \
                    201:                v = v * 10 + (*++cp - '0'); \
                    202:                slen--; \
                    203:        }
1.1       christos  204:
1.4       christos  205:        for (; slen--; cp++) {
                    206:                int sustain, timeval, tempo;
                    207:                char c = toupper((unsigned char)*cp);
1.1       christos  208:
                    209: #ifdef SPKRDEBUG
1.4       christos  210:                aprint_debug_dev(sc->sc_dev, "%s: %c (%x)\n", __func__, c, c);
1.1       christos  211: #endif /* SPKRDEBUG */
                    212:
1.4       christos  213:                switch (c) {
                    214:                case 'A':  case 'B': case 'C': case 'D':
                    215:                case 'E': case 'F': case 'G':
                    216:                        /* compute pitch */
                    217:                        pitch = notetab[c - 'A'] + sc->sc_octave * OCTAVE_NOTES;
                    218:
                    219:                        /* this may be followed by an accidental sign */
                    220:                        if (slen > 0 && (cp[1] == '#' || cp[1] == '+')) {
                    221:                                ++pitch;
                    222:                                ++cp;
                    223:                                slen--;
                    224:                        } else if (slen > 0 && cp[1] == '-') {
                    225:                                --pitch;
                    226:                                ++cp;
                    227:                                slen--;
                    228:                        }
                    229:
                    230:                        /*
                    231:                         * If octave-tracking mode is on, and there has been no
                    232:                         * octave- setting prefix, find the version of the
                    233:                         * current letter note * closest to the last
                    234:                         * regardless of octave.
                    235:                         */
                    236:                        if (sc->sc_octtrack && !sc->sc_octprefix) {
                    237:                                int d = abs(pitch - lastpitch);
                    238:                                if (d > abs(pitch + OCTAVE_NOTES - lastpitch)) {
                    239:                                        if (sc->sc_octave < NOCTAVES - 1) {
                    240:                                                ++sc->sc_octave;
                    241:                                                pitch += OCTAVE_NOTES;
                    242:                                        }
                    243:                                }
                    244:
                    245:                                if (d > abs(pitch - OCTAVE_NOTES - lastpitch)) {
                    246:                                        if (sc->sc_octave > 0) {
                    247:                                                --sc->sc_octave;
                    248:                                                pitch -= OCTAVE_NOTES;
                    249:                                        }
                    250:                                }
                    251:                        }
                    252:                        sc->sc_octprefix = false;
                    253:                        lastpitch = pitch;
                    254:
                    255:                        /*
                    256:                         * ...which may in turn be followed by an override
                    257:                         * time value
                    258:                         */
                    259:                        GETNUM(cp, timeval);
                    260:                        if (timeval <= 0 || timeval > MIN_VALUE)
                    261:                                timeval = sc->sc_value;
                    262:
                    263:                        /* ...and/or sustain dots */
                    264:                        for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) {
                    265:                                slen--;
                    266:                                sustain++;
                    267:                        }
                    268:
                    269:                        /* time to emit the actual tone */
                    270:                        playtone(sc, pitch, timeval, sustain);
                    271:                        break;
                    272:
                    273:                case 'O':
                    274:                        if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) {
                    275:                                sc->sc_octprefix = sc->sc_octtrack = false;
                    276:                                ++cp;
                    277:                                slen--;
                    278:                        } else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) {
                    279:                                sc->sc_octtrack = true;
                    280:                                ++cp;
                    281:                                slen--;
                    282:                        } else {
                    283:                                GETNUM(cp, sc->sc_octave);
                    284:                                if (sc->sc_octave >= NOCTAVES)
                    285:                                        sc->sc_octave = DFLT_OCTAVE;
                    286:                                sc->sc_octprefix = true;
                    287:                        }
                    288:                        break;
                    289:
                    290:                case '>':
                    291:                        if (sc->sc_octave < NOCTAVES - 1)
                    292:                                sc->sc_octave++;
                    293:                        sc->sc_octprefix = true;
                    294:                        break;
                    295:
                    296:                case '<':
                    297:                        if (sc->sc_octave > 0)
                    298:                                sc->sc_octave--;
                    299:                        sc->sc_octprefix = true;
                    300:                        break;
                    301:
                    302:                case 'N':
                    303:                        GETNUM(cp, pitch);
                    304:                        for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) {
                    305:                                slen--;
                    306:                                sustain++;
                    307:                        }
                    308:                        playtone(sc, pitch - 1, sc->sc_value, sustain);
                    309:                        break;
                    310:
                    311:                case 'L':
                    312:                        GETNUM(cp, sc->sc_value);
                    313:                        if (sc->sc_value <= 0 || sc->sc_value > MIN_VALUE)
                    314:                                sc->sc_value = DFLT_VALUE;
                    315:                        break;
                    316:
                    317:                case 'P':
                    318:                case '~':
                    319:                        /* this may be followed by an override time value */
                    320:                        GETNUM(cp, timeval);
                    321:                        if (timeval <= 0 || timeval > MIN_VALUE)
                    322:                                timeval = sc->sc_value;
                    323:                        for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) {
                    324:                                slen--;
                    325:                                sustain++;
                    326:                        }
                    327:                        playtone(sc, -1, timeval, sustain);
                    328:                        break;
                    329:
                    330:                case 'T':
                    331:                        GETNUM(cp, tempo);
                    332:                        if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
                    333:                                tempo = DFLT_TEMPO;
                    334:                        sc->sc_whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
                    335:                        break;
1.1       christos  336:
1.4       christos  337:                case 'M':
                    338:                        if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) {
                    339:                                sc->sc_fill = NORMAL;
                    340:                                ++cp;
                    341:                                slen--;
                    342:                        } else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) {
                    343:                                sc->sc_fill = LEGATO;
                    344:                                ++cp;
                    345:                                slen--;
                    346:                        } else if (slen > 0 && (cp[1] == 'S' || cp[1] == 's')) {
                    347:                                sc->sc_fill = STACCATO;
                    348:                                ++cp;
                    349:                                slen--;
                    350:                        }
                    351:                        break;
1.1       christos  352:                }
                    353:        }
                    354: }
                    355:
                    356: /******************* UNIX DRIVER HOOKS BEGIN HERE **************************
                    357:  *
                    358:  * This section implements driver hooks to run playstring() and the spkr_tone()
                    359:  * and spkr_rest() functions defined above.
                    360:  */
1.4       christos  361: #define spkrenter(d)   device_lookup_private(&spkr_cd, d)
1.1       christos  362:
1.4       christos  363: void
                    364: spkr_attach(device_t self, void (*tone)(device_t, u_int, u_int),
                    365:     void (*rest)(device_t, int))
                    366: {
                    367:        struct spkr_softc *sc = device_private(self);
1.1       christos  368:
1.6       pgoyette  369: #ifdef SPKRDEBUG
                    370:        aprint_debug("%s: entering for unit %d\n", __func__, self->dv_unit);
                    371: #endif /* SPKRDEBUG */
1.4       christos  372:        sc->sc_dev = self;
                    373:        sc->sc_tone = tone;
                    374:        sc->sc_rest = rest;
                    375:        sc->sc_inbuf = NULL;
1.12      pgoyette  376:        sc->sc_wsbelldev = NULL;
1.9       nat       377:
1.12      pgoyette  378:        spkr_rescan(self, "", NULL);
1.1       christos  379: }
                    380:
                    381: int
1.6       pgoyette  382: spkr_detach(device_t self, int flags)
                    383: {
                    384:        struct spkr_softc *sc = device_private(self);
1.13      nat       385:        int rc;
1.6       pgoyette  386:
                    387: #ifdef SPKRDEBUG
                    388:        aprint_debug("%s: entering for unit %d\n", __func__, self->dv_unit);
                    389: #endif /* SPKRDEBUG */
                    390:        if (sc == NULL)
                    391:                return ENXIO;
1.14      nat       392:
                    393:        /* XXXNS If speaker never closes, we cannot complete the detach. */
                    394:        while ((flags & DETACH_FORCE) != 0 && sc->sc_inbuf != NULL)
                    395:                kpause("spkrwait", TRUE, 1, NULL);
1.6       pgoyette  396:        if (sc->sc_inbuf != NULL)
                    397:                return EBUSY;
                    398:
1.13      nat       399:        rc = config_detach_children(self, flags);
                    400:
                    401:        return rc;
1.6       pgoyette  402: }
                    403:
1.12      pgoyette  404: /* ARGSUSED */
                    405: int
                    406: spkr_rescan(device_t self, const char *iattr, const int *locators)
                    407: {
                    408: #if NWSMUX > 0
                    409:        struct spkr_softc *sc = device_private(self);
                    410:        struct wsbelldev_attach_args a;
                    411:
                    412:        if (sc->sc_wsbelldev == NULL) {
                    413:                a.accesscookie = sc;
                    414:                sc->sc_wsbelldev = config_found(self, &a, wsbelldevprint);
                    415:        }
                    416: #endif
                    417:        return 0;
                    418: }
                    419:
                    420: int
                    421: spkr_childdet(device_t self, device_t child)
                    422: {
                    423:        struct spkr_softc *sc = device_private(self);
                    424:
                    425:        if (sc->sc_wsbelldev == child)
                    426:                sc->sc_wsbelldev = NULL;
                    427:
                    428:        return 0;
                    429: }
                    430:
1.6       pgoyette  431: int
1.1       christos  432: spkropen(dev_t dev, int        flags, int mode, struct lwp *l)
                    433: {
                    434: #ifdef SPKRDEBUG
1.4       christos  435:        aprint_debug("%s: entering with dev = %"PRIx64"\n", __func__, dev);
1.1       christos  436: #endif /* SPKRDEBUG */
1.4       christos  437:        struct spkr_softc *sc = spkrenter(minor(dev));
1.1       christos  438:
1.4       christos  439:        if (sc == NULL)
                    440:                return ENXIO;
1.6       pgoyette  441:        if (sc->sc_inbuf != NULL)
1.4       christos  442:                return EBUSY;
                    443:
                    444:        sc->sc_inbuf = malloc(DEV_BSIZE, M_DEVBUF, M_WAITOK);
                    445:        playinit(sc);
                    446:        return 0;
1.1       christos  447: }
                    448:
                    449: int
                    450: spkrwrite(dev_t dev, struct uio *uio, int flags)
                    451: {
                    452: #ifdef SPKRDEBUG
1.4       christos  453:        aprint_debug("%s: entering with dev = %"PRIx64", count = %zu\n",
                    454:            __func__, dev, uio->uio_resid);
1.1       christos  455: #endif /* SPKRDEBUG */
1.4       christos  456:        struct spkr_softc *sc = spkrenter(minor(dev));
1.1       christos  457:
1.4       christos  458:        if (sc == NULL)
                    459:                return ENXIO;
1.6       pgoyette  460:        if (sc->sc_inbuf == NULL)
1.4       christos  461:                return EINVAL;
                    462:
1.15.4.1! pgoyette  463:        size_t n = uimin(DEV_BSIZE, uio->uio_resid);
1.4       christos  464:        int error = uiomove(sc->sc_inbuf, n, uio);
                    465:        if (error)
                    466:                return error;
                    467:        playstring(sc, sc->sc_inbuf, n);
                    468:        return 0;
1.1       christos  469: }
                    470:
                    471: int
                    472: spkrclose(dev_t dev, int flags, int mode, struct lwp *l)
                    473: {
                    474: #ifdef SPKRDEBUG
1.4       christos  475:        aprint_debug("%s: entering with dev = %"PRIx64"\n", __func__, dev);
1.1       christos  476: #endif /* SPKRDEBUG */
1.4       christos  477:        struct spkr_softc *sc = spkrenter(minor(dev));
                    478:
                    479:        if (sc == NULL)
                    480:                return ENXIO;
1.6       pgoyette  481:        if (sc->sc_inbuf == NULL)
1.4       christos  482:                return EINVAL;
                    483:
                    484:        sc->sc_tone(sc->sc_dev, 0, 0);
                    485:        free(sc->sc_inbuf, M_DEVBUF);
                    486:        sc->sc_inbuf = NULL;
1.1       christos  487:
1.4       christos  488:        return 0;
                    489: }
                    490:
                    491: static void
                    492: playonetone(struct spkr_softc *sc, tone_t *tp)
                    493: {
                    494:     if (tp->frequency == 0)
                    495:            (*sc->sc_rest)(sc->sc_dev, tp->duration);
1.1       christos  496:     else
1.4       christos  497:            (*sc->sc_tone)(sc->sc_dev, tp->frequency, tp->duration);
1.1       christos  498: }
                    499:
                    500: int
                    501: spkrioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
                    502: {
1.4       christos  503:        tone_t *tp;
                    504:        tone_t ttp;
                    505:        int error;
1.1       christos  506: #ifdef SPKRDEBUG
1.4       christos  507:        aprint_debug("%s: entering with dev = %"PRIx64", cmd = %lx\n",
                    508:            __func__, dev, cmd);
1.1       christos  509: #endif /* SPKRDEBUG */
                    510:
1.4       christos  511:        struct spkr_softc *sc = spkrenter(minor(dev));
1.1       christos  512:
1.4       christos  513:        if (sc == NULL)
                    514:                return ENXIO;
1.6       pgoyette  515:        if (sc->sc_inbuf == NULL)
1.4       christos  516:                return EINVAL;
                    517:
                    518:        switch (cmd) {
                    519:        case SPKRTONE:
                    520:                playonetone(sc, data);
                    521:                return 0;
                    522:        case SPKRTUNE:
                    523:                for (tp = *(void **)data;; tp++) {
                    524:                        error = copyin(tp, &ttp, sizeof(tone_t));
                    525:                        if (error)
                    526:                                return(error);
                    527:                        if (ttp.duration == 0)
                    528:                                break;
                    529:                        playonetone(sc, &ttp);
                    530:                }
                    531:                return 0;
1.8       nat       532:        case SPKRGETVOL:
                    533:                if (data != NULL)
                    534:                        *(u_int *)data = sc->sc_vol;
                    535:                return 0;
                    536:        case SPKRSETVOL:
                    537:                if (data != NULL && *(u_int *)data <= 100)
                    538:                        sc->sc_vol = *(u_int *)data;
                    539:                return 0;
1.4       christos  540:        default:
                    541:                return ENOTTY;
1.1       christos  542:        }
                    543: }
                    544:
1.3       christos  545: #ifdef _MODULE
                    546: #include "ioconf.c"
                    547: #endif
                    548:
1.7       pgoyette  549: MODULE(MODULE_CLASS_DRIVER, spkr, "audio" /* and/or pcppi */ );
1.5       pgoyette  550:
1.1       christos  551: int
1.5       pgoyette  552: spkr_modcmd(modcmd_t cmd, void *arg)
1.1       christos  553: {
1.11      pgoyette  554:        int error = 0;
1.1       christos  555: #ifdef _MODULE
                    556:        devmajor_t bmajor, cmajor;
1.11      pgoyette  557: #endif
1.1       christos  558:
                    559:        switch(cmd) {
                    560:        case MODULE_CMD_INIT:
1.11      pgoyette  561: #ifdef _MODULE
1.1       christos  562:                bmajor = cmajor = -1;
                    563:                error = devsw_attach(spkr_cd.cd_name, NULL, &bmajor,
                    564:                    &spkr_cdevsw, &cmajor);
                    565:                if (error)
                    566:                        break;
                    567:
                    568:                error = config_init_component(cfdriver_ioconf_spkr,
1.6       pgoyette  569:                    cfattach_ioconf_spkr, cfdata_ioconf_spkr);
1.1       christos  570:                if (error) {
                    571:                        devsw_detach(NULL, &spkr_cdevsw);
                    572:                }
1.11      pgoyette  573: #endif
1.1       christos  574:                break;
                    575:
                    576:        case MODULE_CMD_FINI:
1.11      pgoyette  577: #ifdef _MODULE
1.6       pgoyette  578:                devsw_detach(NULL, &spkr_cdevsw);
1.1       christos  579:                error = config_fini_component(cfdriver_ioconf_spkr,
1.6       pgoyette  580:                    cfattach_ioconf_spkr, cfdata_ioconf_spkr);
                    581:                if (error)
                    582:                        devsw_attach(spkr_cd.cd_name, NULL, &bmajor,
                    583:                            &spkr_cdevsw, &cmajor);
1.11      pgoyette  584: #endif
1.1       christos  585:                break;
1.6       pgoyette  586:
1.1       christos  587:        default:
                    588:                error = ENOTTY;
                    589:                break;
                    590:        }
                    591:
                    592:        return error;
                    593: }

CVSweb <webmaster@jp.NetBSD.org>