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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/spkr.c

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

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

Cache object: 7ece97c1a45341180a1e62e39a714bb4


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


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