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

Annotation of sys/dev/isa/spkr.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: spkr.c,v 1.10 2006/03/09 22:35:23 miod Exp $  */
        !             2: /*     $NetBSD: spkr.c,v 1.1 1998/04/15 20:26:18 drochner Exp $        */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1990 Eric S. Raymond (esr@snark.thyrsus.com)
        !             6:  * Copyright (c) 1990 Andrew A. Chernov (ache@astral.msk.su)
        !             7:  * Copyright (c) 1990 Lennart Augustsson (lennart@augustsson.net)
        !             8:  * All rights reserved.
        !             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 Eric S. Raymond
        !            21:  * 4. The name of the author may not be used to endorse or promote products
        !            22:  *    derived from this software without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            26:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            27:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            28:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            29:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            30:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            32:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            33:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            34:  * POSSIBILITY OF SUCH DAMAGE.
        !            35:  */
        !            36:
        !            37: /*
        !            38:  * spkr.c -- device driver for console speaker on 80386
        !            39:  *
        !            40:  * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990
        !            41:  *      modified for 386bsd by Andrew A. Chernov <ache@astral.msk.su>
        !            42:  *      386bsd only clean version, all SYSV stuff removed
        !            43:  *      use hz value from param.c
        !            44:  */
        !            45:
        !            46: #include <sys/param.h>
        !            47: #include <sys/systm.h>
        !            48: #include <sys/kernel.h>
        !            49: #include <sys/errno.h>
        !            50: #include <sys/device.h>
        !            51: #include <sys/malloc.h>
        !            52: #include <sys/uio.h>
        !            53: #include <sys/proc.h>
        !            54: #include <sys/ioctl.h>
        !            55: #include <sys/conf.h>
        !            56:
        !            57: #include <dev/isa/pcppivar.h>
        !            58:
        !            59: #include <dev/isa/spkrio.h>
        !            60:
        !            61: cdev_decl(spkr);
        !            62:
        !            63: int spkrprobe(struct device *, void *, void *);
        !            64: void spkrattach(struct device *, struct device *, void *);
        !            65:
        !            66: struct cfattach spkr_ca = {
        !            67:        sizeof(struct device), spkrprobe, spkrattach
        !            68: };
        !            69:
        !            70: struct cfdriver spkr_cd = {
        !            71:        NULL, "spkr", DV_DULL
        !            72: };
        !            73:
        !            74: static pcppi_tag_t ppicookie;
        !            75:
        !            76: #define SPKRPRI (PZERO - 1)
        !            77:
        !            78: static void tone(u_int, u_int);
        !            79: static void rest(int);
        !            80: static void playinit(void);
        !            81: static void playtone(int, int, int);
        !            82: static void playstring(char *, int);
        !            83:
        !            84: /* emit tone of frequency hz for given number of ticks */
        !            85: static void
        !            86: tone(hz, ticks)
        !            87:        u_int hz, ticks;
        !            88: {
        !            89:        pcppi_bell(ppicookie, hz, ticks, PCPPI_BELL_SLEEP);
        !            90: }
        !            91:
        !            92: /* rest for given number of ticks */
        !            93: static void
        !            94: rest(ticks)
        !            95:        int ticks;
        !            96: {
        !            97:        /*
        !            98:         * Set timeout to endrest function, then give up the timeslice.
        !            99:         * This is so other processes can execute while the rest is being
        !           100:         * waited out.
        !           101:         */
        !           102: #ifdef SPKRDEBUG
        !           103:        printf("rest: %d\n", ticks);
        !           104: #endif /* SPKRDEBUG */
        !           105:        if (ticks > 0)
        !           106:                tsleep(rest, SPKRPRI | PCATCH, "rest", ticks);
        !           107: }
        !           108:
        !           109: /**************** PLAY STRING INTERPRETER BEGINS HERE **********************
        !           110:  *
        !           111:  * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
        !           112:  * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
        !           113:  * Requires tone(), rest(), and endtone(). String play is not interruptible
        !           114:  * except possibly at physical block boundaries.
        !           115:  */
        !           116:
        !           117: typedef int    bool;
        !           118: #define TRUE   1
        !           119: #define FALSE  0
        !           120:
        !           121: #define toupper(c)     ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
        !           122: #define isdigit(c)     (((c) >= '0') && ((c) <= '9'))
        !           123: #define dtoi(c)                ((c) - '0')
        !           124:
        !           125: static int octave;     /* currently selected octave */
        !           126: static int whole;      /* whole-note time at current tempo, in ticks */
        !           127: static int value;      /* whole divisor for note time, quarter note = 1 */
        !           128: static int fill;       /* controls spacing of notes */
        !           129: static bool octtrack;  /* octave-tracking on? */
        !           130: static bool octprefix; /* override current octave-tracking state? */
        !           131:
        !           132: /*
        !           133:  * Magic number avoidance...
        !           134:  */
        !           135: #define SECS_PER_MIN   60      /* seconds per minute */
        !           136: #define WHOLE_NOTE     4       /* quarter notes per whole note */
        !           137: #define MIN_VALUE      64      /* the most we can divide a note by */
        !           138: #define DFLT_VALUE     4       /* default value (quarter-note) */
        !           139: #define FILLTIME       8       /* for articulation, break note in parts */
        !           140: #define STACCATO       6       /* 6/8 = 3/4 of note is filled */
        !           141: #define NORMAL         7       /* 7/8ths of note interval is filled */
        !           142: #define LEGATO         8       /* all of note interval is filled */
        !           143: #define DFLT_OCTAVE    4       /* default octave */
        !           144: #define MIN_TEMPO      32      /* minimum tempo */
        !           145: #define DFLT_TEMPO     120     /* default tempo */
        !           146: #define MAX_TEMPO      255     /* max tempo */
        !           147: #define NUM_MULT       3       /* numerator of dot multiplier */
        !           148: #define DENOM_MULT     2       /* denominator of dot multiplier */
        !           149:
        !           150: /* letter to half-tone:  A   B  C  D  E  F  G */
        !           151: static int notetab[8] = { 9, 11, 0, 2, 4, 5, 7 };
        !           152:
        !           153: /*
        !           154:  * This is the American Standard A440 Equal-Tempered scale with frequencies
        !           155:  * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
        !           156:  * our octave 0 is standard octave 2.
        !           157:  */
        !           158: #define OCTAVE_NOTES   12      /* semitones per octave */
        !           159: static int pitchtab[] =
        !           160: {
        !           161: /*        C     C#    D     D#    E     F     F#    G     G#    A     A#    B*/
        !           162: /* 0 */   65,   69,   73,   78,   82,   87,   93,   98,  103,  110,  117,  123,
        !           163: /* 1 */  131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
        !           164: /* 2 */  262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,
        !           165: /* 3 */  523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,
        !           166: /* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
        !           167: /* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
        !           168: /* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
        !           169: };
        !           170: #define NOCTAVES (sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES)
        !           171:
        !           172: static void
        !           173: playinit()
        !           174: {
        !           175:        octave = DFLT_OCTAVE;
        !           176:        whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
        !           177:        fill = NORMAL;
        !           178:        value = DFLT_VALUE;
        !           179:        octtrack = FALSE;
        !           180:        octprefix = TRUE;       /* act as though there was an initial O(n) */
        !           181: }
        !           182:
        !           183: /* play tone of proper duration for current rhythm signature */
        !           184: static void
        !           185: playtone(pitch, value, sustain)
        !           186:        int pitch, value, sustain;
        !           187: {
        !           188:        int sound, silence, snum = 1, sdenom = 1;
        !           189:
        !           190:        /* this weirdness avoids floating-point arithmetic */
        !           191:        for (; sustain; sustain--) {
        !           192:                snum *= NUM_MULT;
        !           193:                sdenom *= DENOM_MULT;
        !           194:        }
        !           195:
        !           196:        if (pitch == -1)
        !           197:                rest(whole * snum / (value * sdenom));
        !           198:        else if (pitch >= 0 &&
        !           199:            pitch < (sizeof(pitchtab) / sizeof(pitchtab[0]))) {
        !           200:                sound = (whole * snum) / (value * sdenom) -
        !           201:                    (whole * (FILLTIME - fill)) / (value * FILLTIME);
        !           202:                silence = whole * (FILLTIME-fill) * snum /
        !           203:                    (FILLTIME * value * sdenom);
        !           204:
        !           205: #ifdef SPKRDEBUG
        !           206:                printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
        !           207:                    pitch, sound, silence);
        !           208: #endif /* SPKRDEBUG */
        !           209:
        !           210:                tone(pitchtab[pitch], sound);
        !           211:                if (fill != LEGATO)
        !           212:                        rest(silence);
        !           213:        }
        !           214: }
        !           215:
        !           216: /* interpret and play an item from a notation string */
        !           217: static void
        !           218: playstring(cp, slen)
        !           219:        char *cp;
        !           220:        int slen;
        !           221: {
        !           222:        int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
        !           223:
        !           224: #define GETNUM(cp, v) \
        !           225: do { \
        !           226:        for (v = 0; slen > 0 && isdigit(cp[1]); ) { \
        !           227:                v = v * 10 + (*++cp - '0'); \
        !           228:                slen--; \
        !           229:        } \
        !           230: } while (0)
        !           231:
        !           232:        for (; slen--; cp++) {
        !           233:                int sustain, timeval, tempo;
        !           234:                char c = toupper(*cp);
        !           235:
        !           236: #ifdef SPKRDEBUG
        !           237:                printf("playstring: %c (%x)\n", c, c);
        !           238: #endif /* SPKRDEBUG */
        !           239:
        !           240:                switch (c) {
        !           241:                case 'A':
        !           242:                case 'B':
        !           243:                case 'C':
        !           244:                case 'D':
        !           245:                case 'E':
        !           246:                case 'F':
        !           247:                case 'G':
        !           248:                        /* compute pitch */
        !           249:                        pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
        !           250:
        !           251:                        /* this may be followed by an accidental sign */
        !           252:                        if (slen > 0 && (cp[1] == '#' || cp[1] == '+')) {
        !           253:                                ++pitch;
        !           254:                                ++cp;
        !           255:                                slen--;
        !           256:                        } else if (slen > 0 && cp[1] == '-') {
        !           257:                                --pitch;
        !           258:                                ++cp;
        !           259:                                slen--;
        !           260:                        }
        !           261:
        !           262:                        /*
        !           263:                         * If octave-tracking mode is on, and there has been
        !           264:                         * no octave-setting prefix, find the version of the
        !           265:                         * current letter note closest to the last regardless
        !           266:                         * of octave.
        !           267:                         */
        !           268:                        if (octtrack && !octprefix) {
        !           269:                                if (abs(pitch - lastpitch) >
        !           270:                                    abs(pitch + OCTAVE_NOTES - lastpitch)) {
        !           271:                                        ++octave;
        !           272:                                        pitch += OCTAVE_NOTES;
        !           273:                                }
        !           274:
        !           275:                                if (abs(pitch - lastpitch) >
        !           276:                                    abs(pitch - OCTAVE_NOTES - lastpitch)) {
        !           277:                                        --octave;
        !           278:                                        pitch -= OCTAVE_NOTES;
        !           279:                                }
        !           280:                        }
        !           281:                        octprefix = FALSE;
        !           282:                        lastpitch = pitch;
        !           283:
        !           284:                        /*
        !           285:                         * ...which may in turn be followed by an override
        !           286:                         * time value
        !           287:                         */
        !           288:                        GETNUM(cp, timeval);
        !           289:                        if (timeval <= 0 || timeval > MIN_VALUE)
        !           290:                                timeval = value;
        !           291:
        !           292:                        /* ...and/or sustain dots */
        !           293:                        for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) {
        !           294:                                slen--;
        !           295:                                sustain++;
        !           296:                        }
        !           297:
        !           298:                        /* time to emit the actual tone */
        !           299:                        playtone(pitch, timeval, sustain);
        !           300:                        break;
        !           301:
        !           302:                case 'O':
        !           303:                        if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) {
        !           304:                                octprefix = octtrack = FALSE;
        !           305:                                ++cp;
        !           306:                                slen--;
        !           307:                        } else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) {
        !           308:                                octtrack = TRUE;
        !           309:                                ++cp;
        !           310:                                slen--;
        !           311:                        } else {
        !           312:                                GETNUM(cp, octave);
        !           313:                                if (octave >= NOCTAVES)
        !           314:                                        octave = DFLT_OCTAVE;
        !           315:                                octprefix = TRUE;
        !           316:                        }
        !           317:                        break;
        !           318:
        !           319:                case '>':
        !           320:                        if (octave < NOCTAVES - 1)
        !           321:                                octave++;
        !           322:                        octprefix = TRUE;
        !           323:                        break;
        !           324:
        !           325:                case '<':
        !           326:                        if (octave > 0)
        !           327:                                octave--;
        !           328:                        octprefix = TRUE;
        !           329:                        break;
        !           330:
        !           331:                case 'N':
        !           332:                        GETNUM(cp, pitch);
        !           333:                        for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) {
        !           334:                                slen--;
        !           335:                                sustain++;
        !           336:                        }
        !           337:                        playtone(pitch - 1, value, sustain);
        !           338:                        break;
        !           339:
        !           340:                case 'L':
        !           341:                        GETNUM(cp, value);
        !           342:                        if (value <= 0 || value > MIN_VALUE)
        !           343:                                value = DFLT_VALUE;
        !           344:                        break;
        !           345:
        !           346:                case 'P':
        !           347:                case '~':
        !           348:                        /* this may be followed by an override time value */
        !           349:                        GETNUM(cp, timeval);
        !           350:                        if (timeval <= 0 || timeval > MIN_VALUE)
        !           351:                                timeval = value;
        !           352:                        for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) {
        !           353:                                slen--;
        !           354:                                sustain++;
        !           355:                        }
        !           356:                        playtone(-1, timeval, sustain);
        !           357:                        break;
        !           358:
        !           359:                case 'T':
        !           360:                        GETNUM(cp, tempo);
        !           361:                        if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
        !           362:                                tempo = DFLT_TEMPO;
        !           363:                        whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
        !           364:                        break;
        !           365:
        !           366:                case 'M':
        !           367:                        if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) {
        !           368:                                fill = NORMAL;
        !           369:                                ++cp;
        !           370:                                slen--;
        !           371:                        } else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) {
        !           372:                                fill = LEGATO;
        !           373:                                ++cp;
        !           374:                                slen--;
        !           375:                        } else if (slen > 0 && (cp[1] == 'S' || cp[1] == 's')) {
        !           376:                                fill = STACCATO;
        !           377:                                ++cp;
        !           378:                                slen--;
        !           379:                        }
        !           380:                        break;
        !           381:                }
        !           382:        }
        !           383: }
        !           384:
        !           385: /******************* UNIX DRIVER HOOKS BEGIN HERE **************************
        !           386:  *
        !           387:  * This section implements driver hooks to run playstring() and the tone(),
        !           388:  * endtone(), and rest() functions defined above.
        !           389:  */
        !           390:
        !           391: static int spkr_active;        /* exclusion flag */
        !           392: static void *spkr_inbuf;
        !           393:
        !           394: static int spkr_attached = 0;
        !           395:
        !           396: int
        !           397: spkrprobe(parent, match, aux)
        !           398:        struct device *parent;
        !           399:        void *match;
        !           400:        void *aux;
        !           401: {
        !           402:        return (!spkr_attached);
        !           403: }
        !           404:
        !           405: void
        !           406: spkrattach(parent, self, aux)
        !           407:        struct device *parent;
        !           408:        struct device *self;
        !           409:        void *aux;
        !           410: {
        !           411:        printf("\n");
        !           412:        ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie;
        !           413:        spkr_attached = 1;
        !           414: }
        !           415:
        !           416: int
        !           417: spkropen(dev, flags, mode, p)
        !           418:        dev_t dev;
        !           419:        int flags;
        !           420:        int mode;
        !           421:        struct proc *p;
        !           422: {
        !           423: #ifdef SPKRDEBUG
        !           424:        printf("spkropen: entering with dev = %x\n", dev);
        !           425: #endif /* SPKRDEBUG */
        !           426:
        !           427:        if (minor(dev) != 0 || !spkr_attached)
        !           428:                return (ENXIO);
        !           429:        else if (spkr_active)
        !           430:                return (EBUSY);
        !           431:        else {
        !           432:                playinit();
        !           433:                spkr_inbuf = malloc(DEV_BSIZE, M_DEVBUF, M_WAITOK);
        !           434:                spkr_active = 1;
        !           435:        }
        !           436:        return (0);
        !           437: }
        !           438:
        !           439: int
        !           440: spkrwrite(dev, uio, flags)
        !           441:        dev_t dev;
        !           442:        struct uio *uio;
        !           443:        int flags;
        !           444: {
        !           445:        int n;
        !           446:        int error;
        !           447: #ifdef SPKRDEBUG
        !           448:        printf("spkrwrite: entering with dev = %x, count = %d\n",
        !           449:            dev, uio->uio_resid);
        !           450: #endif /* SPKRDEBUG */
        !           451:
        !           452:        if (minor(dev) != 0)
        !           453:                return (ENXIO);
        !           454:        else {
        !           455:                n = min(DEV_BSIZE, uio->uio_resid);
        !           456:                error = uiomove(spkr_inbuf, n, uio);
        !           457:                if (!error)
        !           458:                        playstring((char *)spkr_inbuf, n);
        !           459:                return (error);
        !           460:        }
        !           461: }
        !           462:
        !           463: int
        !           464: spkrclose(dev, flags, mode, p)
        !           465:        dev_t dev;
        !           466:        int flags;
        !           467:        int mode;
        !           468:        struct proc *p;
        !           469: {
        !           470: #ifdef SPKRDEBUG
        !           471:        printf("spkrclose: entering with dev = %x\n", dev);
        !           472: #endif /* SPKRDEBUG */
        !           473:
        !           474:        if (minor(dev) != 0)
        !           475:                return (ENXIO);
        !           476:        else {
        !           477:                tone(0, 0);
        !           478:                free(spkr_inbuf, M_DEVBUF);
        !           479:                spkr_active = 0;
        !           480:        }
        !           481:        return (0);
        !           482: }
        !           483:
        !           484: int
        !           485: spkrioctl(dev, cmd, data, flag, p)
        !           486:        dev_t dev;
        !           487:        u_long cmd;
        !           488:        caddr_t data;
        !           489:        int flag;
        !           490:        struct proc *p;
        !           491: {
        !           492:        tone_t *tp, ttp;
        !           493:        int error;
        !           494:
        !           495: #ifdef SPKRDEBUG
        !           496:        printf("spkrioctl: entering with dev = %x, cmd = %lx\n", dev, cmd);
        !           497: #endif /* SPKRDEBUG */
        !           498:
        !           499:        if (minor(dev) != 0)
        !           500:                return (ENXIO);
        !           501:
        !           502:        switch (cmd) {
        !           503:        case SPKRTONE:
        !           504:                tp = (tone_t *)data;
        !           505:
        !           506:                if (tp->frequency == 0)
        !           507:                        rest(tp->duration);
        !           508:                else
        !           509:                        tone(tp->frequency, tp->duration);
        !           510:                break;
        !           511:        case SPKRTUNE:
        !           512:                tp = (tone_t *)(*(caddr_t *)data);
        !           513:
        !           514:                for (; ; tp++) {
        !           515:                        error = copyin(tp, &ttp, sizeof(tone_t));
        !           516:                        if (error)
        !           517:                                return (error);
        !           518:                        if (ttp.duration == 0)
        !           519:                                break;
        !           520:                        if (ttp.frequency == 0)
        !           521:                                rest(ttp.duration);
        !           522:                        else
        !           523:                                tone(ttp.frequency, ttp.duration);
        !           524:                }
        !           525:                break;
        !           526:        default:
        !           527:                return (ENOTTY);
        !           528:        }
        !           529:
        !           530:        return (0);
        !           531: }

CVSweb