Annotation of Net2/arch/i386/isa/spkr.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * spkr.c -- device driver for console speaker on 80386
                      3:  *
                      4:  * v1.1 by Eric S. Raymond ([email protected]) Feb 1990
                      5:  *      modified for 386bsd by Andrew A. Chernov <[email protected]>
                      6:  *      386bsd only clean version, all SYSV stuff removed
                      7:  *      use hz value from param.c
                      8:  *
                      9:  *     spkr.c,v 1.5 1993/06/16 19:41:54 brezak Exp
                     10:  */
                     11: 
                     12: #include "speaker.h"
                     13: 
                     14: #if NSPEAKER > 0
                     15: 
                     16: #include "param.h"
                     17: #include "kernel.h"
                     18: #include "errno.h"
                     19: #include "buf.h"
                     20: #include "uio.h"
                     21: #include "i386/include/spkr.h"
                     22: #include "isa.h"
                     23: #include "timerreg.h"
                     24: #include "spkr_reg.h"
                     25: 
                     26: /**************** MACHINE DEPENDENT PART STARTS HERE *************************
                     27:  *
                     28:  * This section defines a function tone() which causes a tone of given
                     29:  * frequency and duration from the 80x86's console speaker.
                     30:  * Another function endtone() is defined to force sound off, and there is
                     31:  * also a rest() entry point to do pauses.
                     32:  *
                     33:  * Audible sound is generated using the Programmable Interval Timer (PIT) and
                     34:  * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
                     35:  * PPI controls whether sound is passed through at all; the PIT's channel 2 is
                     36:  * used to generate clicks (a square wave) of whatever frequency is desired.
                     37:  */
                     38: 
                     39: /*
                     40:  * Magic numbers for timer control. 
                     41:  */
                     42: #define PIT_MODE       (TIMER_SEL2|TIMER_MSB|TIMER_SQWAVE)
                     43: 
                     44: static int endtone()
                     45: /* turn off the speaker, ending current tone */
                     46: {
                     47:     wakeup((caddr_t)endtone);
                     48:     outb(PITAUX_PORT, inb(PITAUX_PORT) & ~PIT_SPKR);
                     49: }
                     50: 
                     51: static void tone(hz, ticks)
                     52: /* emit tone of frequency hz for given number of ticks */
                     53: unsigned int hz, ticks;
                     54: {
                     55:     unsigned int divisor = TIMER_DIV(hz);
                     56:     int sps;
                     57: 
                     58: #ifdef DEBUG
                     59:     printf("tone: hz=%d ticks=%d\n", hz, ticks);
                     60: #endif /* DEBUG */
                     61: 
                     62:     /* set timer to generate clicks at given frequency in Hertz */
                     63:     sps = spltty();
                     64:     outb(TIMER_MODE, PIT_MODE);                /* prepare timer */
                     65:     outb(TIMER_CNTR2, (unsigned char) divisor);  /* send lo byte */
                     66:     outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */
                     67:     splx(sps);
                     68: 
                     69:     /* turn the speaker on */
                     70:     outb(PITAUX_PORT, inb(PITAUX_PORT) | PIT_SPKR);
                     71: 
                     72:     /*
                     73:      * Set timeout to endtone function, then give up the timeslice.
                     74:      * This is so other processes can execute while the tone is being
                     75:      * emitted.
                     76:      */
                     77:     timeout((caddr_t)endtone, (caddr_t)NULL, ticks);
                     78:     sleep((caddr_t)endtone, PZERO - 1);
                     79: }
                     80: 
                     81: static int endrest()
                     82: /* end a rest */
                     83: {
                     84:     wakeup((caddr_t)endrest);
                     85: }
                     86: 
                     87: static void rest(ticks)
                     88: /* rest for given number of ticks */
                     89: int    ticks;
                     90: {
                     91:     /*
                     92:      * Set timeout to endrest function, then give up the timeslice.
                     93:      * This is so other processes can execute while the rest is being
                     94:      * waited out.
                     95:      */
                     96: #ifdef DEBUG
                     97:     printf("rest: %d\n", ticks);
                     98: #endif /* DEBUG */
                     99:     timeout((caddr_t)endrest, (caddr_t)NULL, ticks);
                    100:     sleep((caddr_t)endrest, PZERO - 1);
                    101: }
                    102: 
                    103: /**************** PLAY STRING INTERPRETER BEGINS HERE **********************
                    104:  *
                    105:  * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
                    106:  * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
                    107:  * Requires tone(), rest(), and endtone(). String play is not interruptible
                    108:  * except possibly at physical block boundaries.
                    109:  */
                    110: 
                    111: typedef int    bool;
                    112: #define TRUE   1
                    113: #define FALSE  0
                    114: 
                    115: #define toupper(c)     ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
                    116: #define isdigit(c)     (((c) >= '0') && ((c) <= '9'))
                    117: #define dtoi(c)                ((c) - '0')
                    118: 
                    119: static int octave;     /* currently selected octave */
                    120: static int whole;      /* whole-note time at current tempo, in ticks */
                    121: static int value;      /* whole divisor for note time, quarter note = 1 */
                    122: static int fill;       /* controls spacing of notes */
                    123: static bool octtrack;  /* octave-tracking on? */
                    124: static bool octprefix; /* override current octave-tracking state? */
                    125: 
                    126: /*
                    127:  * Magic number avoidance...
                    128:  */
                    129: #define SECS_PER_MIN   60      /* seconds per minute */
                    130: #define WHOLE_NOTE     4       /* quarter notes per whole note */
                    131: #define MIN_VALUE      64      /* the most we can divide a note by */
                    132: #define DFLT_VALUE     4       /* default value (quarter-note) */
                    133: #define FILLTIME       8       /* for articulation, break note in parts */
                    134: #define STACCATO       6       /* 6/8 = 3/4 of note is filled */
                    135: #define NORMAL         7       /* 7/8ths of note interval is filled */
                    136: #define LEGATO         8       /* all of note interval is filled */
                    137: #define DFLT_OCTAVE    4       /* default octave */
                    138: #define MIN_TEMPO      32      /* minimum tempo */
                    139: #define DFLT_TEMPO     120     /* default tempo */
                    140: #define MAX_TEMPO      255     /* max tempo */
                    141: #define NUM_MULT       3       /* numerator of dot multiplier */
                    142: #define DENOM_MULT     2       /* denominator of dot multiplier */
                    143: 
                    144: /* letter to half-tone:  A   B  C  D  E  F  G */
                    145: static int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
                    146: 
                    147: /*
                    148:  * This is the American Standard A440 Equal-Tempered scale with frequencies
                    149:  * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
                    150:  * our octave 0 is standard octave 2.
                    151:  */
                    152: #define OCTAVE_NOTES   12      /* semitones per octave */
                    153: static int pitchtab[] =
                    154: {
                    155: /*        C     C#    D     D#    E     F     F#    G     G#    A     A#    B*/
                    156: /* 0 */   65,   69,   73,   78,   82,   87,   93,   98,  103,  110,  117,  123,
                    157: /* 1 */  131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
                    158: /* 2 */  262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,
                    159: /* 3 */  523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,
                    160: /* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
                    161: /* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
                    162: /* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
                    163: };
                    164: 
                    165: static void playinit()
                    166: {
                    167:     octave = DFLT_OCTAVE;
                    168:     whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
                    169:     fill = NORMAL;
                    170:     value = DFLT_VALUE;
                    171:     octtrack = FALSE;
                    172:     octprefix = TRUE;  /* act as though there was an initial O(n) */
                    173: }
                    174: 
                    175: static void playtone(pitch, value, sustain)
                    176: /* play tone of proper duration for current rhythm signature */
                    177: int    pitch, value, sustain;
                    178: {
                    179:     register int       sound, silence, snum = 1, sdenom = 1;
                    180: 
                    181:     /* this weirdness avoids floating-point arithmetic */
                    182:     for (; sustain; sustain--)
                    183:     {
                    184:        snum *= NUM_MULT;
                    185:        sdenom *= DENOM_MULT;
                    186:     }
                    187: 
                    188:     if (pitch == -1)
                    189:        rest(whole * snum / (value * sdenom));
                    190:     else
                    191:     {
                    192:        sound = (whole * snum) / (value * sdenom)
                    193:                - (whole * (FILLTIME - fill)) / (value * FILLTIME);
                    194:        silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
                    195: 
                    196: #ifdef DEBUG
                    197:        printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
                    198:                        pitch, sound, silence);
                    199: #endif /* DEBUG */
                    200: 
                    201:        tone(pitchtab[pitch], sound);
                    202:        if (fill != LEGATO)
                    203:            rest(silence);
                    204:     }
                    205: }
                    206: 
                    207: static int abs(n)
                    208: int n;
                    209: {
                    210:     if (n < 0)
                    211:        return(-n);
                    212:     else
                    213:        return(n);
                    214: }
                    215: 
                    216: static void playstring(cp, slen)
                    217: /* interpret and play an item from a notation string */
                    218: char   *cp;
                    219: size_t slen;
                    220: {
                    221:     int                pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
                    222: 
                    223: #define GETNUM(cp, v)  for(v=0; isdigit(cp[1]) && slen > 0; ) \
                    224:                                {v = v * 10 + (*++cp - '0'); slen--;}
                    225:     for (; slen--; cp++)
                    226:     {
                    227:        int             sustain, timeval, tempo;
                    228:        register char   c = toupper(*cp);
                    229: 
                    230: #ifdef DEBUG
                    231:        printf("playstring: %c (%x)\n", c, c);
                    232: #endif /* DEBUG */
                    233: 
                    234:        switch (c)
                    235:        {
                    236:        case 'A':  case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
                    237: 
                    238:            /* compute pitch */
                    239:            pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
                    240: 
                    241:            /* this may be followed by an accidental sign */
                    242:            if (cp[1] == '#' || cp[1] == '+')
                    243:            {
                    244:                ++pitch;
                    245:                ++cp;
                    246:                slen--;
                    247:            }
                    248:            else if (cp[1] == '-')
                    249:            {
                    250:                --pitch;
                    251:                ++cp;
                    252:                slen--;
                    253:            }
                    254: 
                    255:            /*
                    256:             * If octave-tracking mode is on, and there has been no octave-
                    257:             * setting prefix, find the version of the current letter note
                    258:             * closest to the last regardless of octave.
                    259:             */
                    260:            if (octtrack && !octprefix)
                    261:            {
                    262:                if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
                    263:                {
                    264:                    ++octave;
                    265:                    pitch += OCTAVE_NOTES;
                    266:                }
                    267: 
                    268:                if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
                    269:                {
                    270:                    --octave;
                    271:                    pitch -= OCTAVE_NOTES;
                    272:                }
                    273:            }
                    274:            octprefix = FALSE;
                    275:            lastpitch = pitch;
                    276: 
                    277:            /* ...which may in turn be followed by an override time value */
                    278:            GETNUM(cp, timeval);
                    279:            if (timeval <= 0 || timeval > MIN_VALUE)
                    280:                timeval = value;
                    281: 
                    282:            /* ...and/or sustain dots */
                    283:            for (sustain = 0; cp[1] == '.'; cp++)
                    284:            {
                    285:                slen--;
                    286:                sustain++;
                    287:            }
                    288: 
                    289:            /* time to emit the actual tone */
                    290:            playtone(pitch, timeval, sustain);
                    291:            break;
                    292: 
                    293:        case 'O':
                    294:            if (cp[1] == 'N' || cp[1] == 'n')
                    295:            {
                    296:                octprefix = octtrack = FALSE;
                    297:                ++cp;
                    298:                slen--;
                    299:            }
                    300:            else if (cp[1] == 'L' || cp[1] == 'l')
                    301:            {
                    302:                octtrack = TRUE;
                    303:                ++cp;
                    304:                slen--;
                    305:            }
                    306:            else
                    307:            {
                    308:                GETNUM(cp, octave);
                    309:                if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
                    310:                    octave = DFLT_OCTAVE;
                    311:                octprefix = TRUE;
                    312:            }
                    313:            break;
                    314: 
                    315:        case '>':
                    316:            if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
                    317:                octave++;
                    318:            octprefix = TRUE;
                    319:            break;
                    320: 
                    321:        case '<':
                    322:            if (octave > 0)
                    323:                octave--;
                    324:            octprefix = TRUE;
                    325:            break;
                    326: 
                    327:        case 'N':
                    328:            GETNUM(cp, pitch);
                    329:            for (sustain = 0; cp[1] == '.'; cp++)
                    330:            {
                    331:                slen--;
                    332:                sustain++;
                    333:            }
                    334:            playtone(pitch - 1, value, sustain);
                    335:            break;
                    336: 
                    337:        case 'L':
                    338:            GETNUM(cp, value);
                    339:            if (value <= 0 || value > MIN_VALUE)
                    340:                value = DFLT_VALUE;
                    341:            break;
                    342: 
                    343:        case 'P':
                    344:        case '~':
                    345:            /* this may be followed by an override time value */
                    346:            GETNUM(cp, timeval);
                    347:            if (timeval <= 0 || timeval > MIN_VALUE)
                    348:                timeval = value;
                    349:            for (sustain = 0; cp[1] == '.'; cp++)
                    350:            {
                    351:                slen--;
                    352:                sustain++;
                    353:            }
                    354:            playtone(-1, timeval, sustain);
                    355:            break;
                    356: 
                    357:        case 'T':
                    358:            GETNUM(cp, tempo);
                    359:            if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
                    360:                tempo = DFLT_TEMPO;
                    361:            whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
                    362:            break;
                    363: 
                    364:        case 'M':
                    365:            if (cp[1] == 'N' || cp[1] == 'n')
                    366:            {
                    367:                fill = NORMAL;
                    368:                ++cp;
                    369:                slen--;
                    370:            }
                    371:            else if (cp[1] == 'L' || cp[1] == 'l')
                    372:            {
                    373:                fill = LEGATO;
                    374:                ++cp;
                    375:                slen--;
                    376:            }
                    377:            else if (cp[1] == 'S' || cp[1] == 's')
                    378:            {
                    379:                fill = STACCATO;
                    380:                ++cp;
                    381:                slen--;
                    382:            }
                    383:            break;
                    384:        }
                    385:     }
                    386: }
                    387: 
                    388: /******************* UNIX DRIVER HOOKS BEGIN HERE **************************
                    389:  *
                    390:  * This section implements driver hooks to run playstring() and the tone(),
                    391:  * endtone(), and rest() functions defined above.
                    392:  */
                    393: 
                    394: static int spkr_active;        /* exclusion flag */
                    395: static struct buf *spkr_inbuf; /* incoming buf */
                    396: 
                    397: int spkropen(dev)
                    398: dev_t  dev;
                    399: {
                    400: #ifdef DEBUG
                    401:     printf("spkropen: entering with dev = %x\n", dev);
                    402: #endif /* DEBUG */
                    403: 
                    404:     if (minor(dev) != 0)
                    405:        return(ENXIO);
                    406:     else if (spkr_active)
                    407:        return(EBUSY);
                    408:     else
                    409:     {
                    410:        playinit();
                    411:        spkr_inbuf = geteblk(DEV_BSIZE);
                    412:        spkr_active = 1;
                    413:     }
                    414:     return(0);
                    415: }
                    416: 
                    417: int spkrwrite(dev, uio)
                    418: dev_t  dev;
                    419: struct uio *uio;
                    420: {
                    421:     register unsigned n;
                    422:     char *cp;
                    423:     int error;
                    424: #ifdef DEBUG
                    425:     printf("spkrwrite: entering with dev = %x, count = %d\n",
                    426:                dev, uio->uio_resid);
                    427: #endif /* DEBUG */
                    428: 
                    429:     if (minor(dev) != 0)
                    430:        return(ENXIO);
                    431:     else
                    432:     {
                    433:        n = MIN(DEV_BSIZE, uio->uio_resid);
                    434:        cp = spkr_inbuf->b_un.b_addr;
                    435:        error = uiomove(cp, n, uio);
                    436:        if (!error)
                    437:                playstring(cp, n);
                    438:        return(error);
                    439:     }
                    440: }
                    441: 
                    442: int spkrclose(dev)
                    443: dev_t  dev;
                    444: {
                    445: #ifdef DEBUG
                    446:     printf("spkrclose: entering with dev = %x\n", dev);
                    447: #endif /* DEBUG */
                    448: 
                    449:     if (minor(dev) != 0)
                    450:        return(ENXIO);
                    451:     else
                    452:     {
                    453:        endtone();
                    454:        brelse(spkr_inbuf);
                    455:        spkr_active = 0;
                    456:     }
                    457:     return(0);
                    458: }
                    459: 
                    460: int spkrioctl(dev, cmd, cmdarg)
                    461: dev_t  dev;
                    462: int    cmd;
                    463: caddr_t cmdarg;
                    464: {
                    465: #ifdef DEBUG
                    466:     printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd);
                    467: #endif /* DEBUG */
                    468: 
                    469:     if (minor(dev) != 0)
                    470:        return(ENXIO);
                    471:     else if (cmd == SPKRTONE)
                    472:     {
                    473:        tone_t  *tp = (tone_t *)cmdarg;
                    474: 
                    475:        if (tp->frequency == 0)
                    476:            rest(tp->duration);
                    477:        else
                    478:            tone(tp->frequency, tp->duration);
                    479:     }
                    480:     else if (cmd == SPKRTUNE)
                    481:     {
                    482:        tone_t  *tp = (tone_t *)(*(caddr_t *)cmdarg);
                    483:        tone_t ttp;
                    484:        int error;
                    485: 
                    486:        for (; ; tp++) {
                    487:            error = copyin(tp, &ttp, sizeof(tone_t));
                    488:            if (error)
                    489:                    return(error);
                    490:            if (ttp.duration == 0)
                    491:                    break;
                    492:            if (ttp.frequency == 0)
                    493:                rest(ttp.duration);
                    494:            else
                    495:                tone(ttp.frequency, ttp.duration);
                    496:        }
                    497:     }
                    498:     else
                    499:        return(EINVAL);
                    500:     return(0);
                    501: }
                    502: 
                    503: #endif  /* NSPEAKER > 0 */
                    504: /* spkr.c ends here */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.