spkr.c revision 12854
14Srgrimes/* 2738Sache * spkr.c -- device driver for console speaker 34Srgrimes * 4738Sache * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993 5738Sache * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su> 6619Srgrimes * 712854Sbde * $Id: spkr.c,v 1.22 1995/12/08 23:20:48 phk Exp $ 84Srgrimes */ 94Srgrimes 104Srgrimes#include "speaker.h" 114Srgrimes 124Srgrimes#if NSPEAKER > 0 134Srgrimes 142056Swollman#include <sys/param.h> 152056Swollman#include <sys/systm.h> 162056Swollman#include <sys/kernel.h> 172056Swollman#include <sys/errno.h> 182056Swollman#include <sys/buf.h> 197090Sbde#include <sys/proc.h> 202056Swollman#include <sys/uio.h> 2112675Sjulian#include <sys/conf.h> 222056Swollman#include <i386/isa/isa.h> 232056Swollman#include <i386/isa/timerreg.h> 247090Sbde#include <machine/clock.h> 252056Swollman#include <machine/speaker.h> 264Srgrimes 2712502Sjulian 2812502Sjulian 2910537Sjulian#ifdef DEVFS 3010537Sjulian#include <sys/devfsext.h> 3112675Sjulianvoid *devfs_token; 3212502Sjulian#endif 3310537Sjulian 3412675Sjulianstatic d_open_t spkropen; 3512675Sjulianstatic d_close_t spkrclose; 3612675Sjulianstatic d_write_t spkrwrite; 3712675Sjulianstatic d_ioctl_t spkrioctl; 3812502Sjulian 3912675Sjulian#define CDEV_MAJOR 26 4012678Sphkstatic struct cdevsw spkr_cdevsw = 4112675Sjulian { spkropen, spkrclose, noread, spkrwrite, /*26*/ 4212675Sjulian spkrioctl, nostop, nullreset, nodevtotty,/* spkr */ 4312675Sjulian seltrue, nommap, NULL, "spkr", NULL, -1 }; 4412675Sjulian 454Srgrimes/**************** MACHINE DEPENDENT PART STARTS HERE ************************* 464Srgrimes * 474Srgrimes * This section defines a function tone() which causes a tone of given 484Srgrimes * frequency and duration from the 80x86's console speaker. 494Srgrimes * Another function endtone() is defined to force sound off, and there is 504Srgrimes * also a rest() entry point to do pauses. 514Srgrimes * 524Srgrimes * Audible sound is generated using the Programmable Interval Timer (PIT) and 534Srgrimes * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The 544Srgrimes * PPI controls whether sound is passed through at all; the PIT's channel 2 is 554Srgrimes * used to generate clicks (a square wave) of whatever frequency is desired. 564Srgrimes */ 574Srgrimes 584Srgrimes/* 594Srgrimes * PIT and PPI port addresses and control values 604Srgrimes * 614Srgrimes * Most of the magic is hidden in the TIMER_PREP value, which selects PIT 624Srgrimes * channel 2, frequency LSB first, square-wave mode and binary encoding. 634Srgrimes * The encoding is as follows: 644Srgrimes * 654Srgrimes * +----------+----------+---------------+-----+ 664Srgrimes * | 1 0 | 1 1 | 0 1 1 | 0 | 674Srgrimes * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | 684Srgrimes * +----------+----------+---------------+-----+ 694Srgrimes * Counter Write Mode 3 Binary 708876Srgrimes * Channel 2 LSB first, (Square Wave) Encoding 714Srgrimes * MSB second 724Srgrimes */ 734Srgrimes#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ 744Srgrimes#define PIT_MODE 0xB6 /* set timer mode for sound generation */ 754Srgrimes 764Srgrimes/* 778876Srgrimes * Magic numbers for timer control. 784Srgrimes */ 794Srgrimes#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ 804Srgrimes 81766Sache#define SPKRPRI PSOCK 82766Sachestatic char endtone, endrest; 834Srgrimes 8412854Sbdestatic void tone __P((unsigned int thz, unsigned int ticks)); 8512854Sbdestatic void rest __P((int ticks)); 8612854Sbdestatic void playinit __P((void)); 8712854Sbdestatic void playtone __P((int pitch, int value, int sustain)); 8812854Sbdestatic int abs __P((int n)); 8912854Sbdestatic void playstring __P((char *cp, size_t slen)); 9012854Sbde 911016Sachestatic void tone(thz, ticks) 92766Sache/* emit tone of frequency thz for given number of ticks */ 93766Sacheunsigned int thz, ticks; 944Srgrimes{ 958288Sdg unsigned int divisor; 961016Sache int sps; 974Srgrimes 988288Sdg if (thz <= 0) 998288Sdg return; 1008288Sdg 1018288Sdg divisor = TIMER_CLK / thz; 1028288Sdg 1034Srgrimes#ifdef DEBUG 104766Sache (void) printf("tone: thz=%d ticks=%d\n", thz, ticks); 1054Srgrimes#endif /* DEBUG */ 1064Srgrimes 1074Srgrimes /* set timer to generate clicks at given frequency in Hertz */ 1084Srgrimes sps = spltty(); 1091393Ssos 1101393Ssos if (acquire_timer2(PIT_MODE)) { 1111393Ssos /* enter list of waiting procs ??? */ 1121393Ssos return; 1131393Ssos } 1141393Ssos outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */ 1151393Ssos outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */ 1164Srgrimes splx(sps); 1174Srgrimes 1184Srgrimes /* turn the speaker on */ 1191393Ssos outb(IO_PPI, inb(IO_PPI) | PPI_SPKR); 1204Srgrimes 1214Srgrimes /* 1224Srgrimes * Set timeout to endtone function, then give up the timeslice. 1234Srgrimes * This is so other processes can execute while the tone is being 1244Srgrimes * emitted. 1254Srgrimes */ 1266152Sache if (ticks > 0) 1276152Sache tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks); 1281393Ssos outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR); 1291393Ssos release_timer2(); 1304Srgrimes} 1314Srgrimes 1321016Sachestatic void rest(ticks) 1334Srgrimes/* rest for given number of ticks */ 1344Srgrimesint ticks; 1354Srgrimes{ 1364Srgrimes /* 1374Srgrimes * Set timeout to endrest function, then give up the timeslice. 1384Srgrimes * This is so other processes can execute while the rest is being 1394Srgrimes * waited out. 1404Srgrimes */ 1414Srgrimes#ifdef DEBUG 142738Sache (void) printf("rest: %d\n", ticks); 1434Srgrimes#endif /* DEBUG */ 1446152Sache if (ticks > 0) 1456152Sache tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks); 1464Srgrimes} 1474Srgrimes 1484Srgrimes/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 1494Srgrimes * 1504Srgrimes * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 151738Sache * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- 152738Sache * tracking facility are added. 1534Srgrimes * Requires tone(), rest(), and endtone(). String play is not interruptible 1544Srgrimes * except possibly at physical block boundaries. 1554Srgrimes */ 1564Srgrimes 1574Srgrimestypedef int bool; 1584Srgrimes#define TRUE 1 1594Srgrimes#define FALSE 0 1604Srgrimes 1614Srgrimes#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) 1624Srgrimes#define isdigit(c) (((c) >= '0') && ((c) <= '9')) 1634Srgrimes#define dtoi(c) ((c) - '0') 1644Srgrimes 1654Srgrimesstatic int octave; /* currently selected octave */ 1664Srgrimesstatic int whole; /* whole-note time at current tempo, in ticks */ 1674Srgrimesstatic int value; /* whole divisor for note time, quarter note = 1 */ 1684Srgrimesstatic int fill; /* controls spacing of notes */ 1694Srgrimesstatic bool octtrack; /* octave-tracking on? */ 1704Srgrimesstatic bool octprefix; /* override current octave-tracking state? */ 1714Srgrimes 1724Srgrimes/* 1734Srgrimes * Magic number avoidance... 1744Srgrimes */ 1754Srgrimes#define SECS_PER_MIN 60 /* seconds per minute */ 1764Srgrimes#define WHOLE_NOTE 4 /* quarter notes per whole note */ 1774Srgrimes#define MIN_VALUE 64 /* the most we can divide a note by */ 1784Srgrimes#define DFLT_VALUE 4 /* default value (quarter-note) */ 1794Srgrimes#define FILLTIME 8 /* for articulation, break note in parts */ 1804Srgrimes#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 1814Srgrimes#define NORMAL 7 /* 7/8ths of note interval is filled */ 1824Srgrimes#define LEGATO 8 /* all of note interval is filled */ 1834Srgrimes#define DFLT_OCTAVE 4 /* default octave */ 1844Srgrimes#define MIN_TEMPO 32 /* minimum tempo */ 1854Srgrimes#define DFLT_TEMPO 120 /* default tempo */ 1864Srgrimes#define MAX_TEMPO 255 /* max tempo */ 1874Srgrimes#define NUM_MULT 3 /* numerator of dot multiplier */ 1884Srgrimes#define DENOM_MULT 2 /* denominator of dot multiplier */ 1894Srgrimes 1904Srgrimes/* letter to half-tone: A B C D E F G */ 1914Srgrimesstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 1924Srgrimes 1934Srgrimes/* 1944Srgrimes * This is the American Standard A440 Equal-Tempered scale with frequencies 1954Srgrimes * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 1964Srgrimes * our octave 0 is standard octave 2. 1974Srgrimes */ 1984Srgrimes#define OCTAVE_NOTES 12 /* semitones per octave */ 1994Srgrimesstatic int pitchtab[] = 2004Srgrimes{ 2014Srgrimes/* C C# D D# E F F# G G# A A# B*/ 2024Srgrimes/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 2034Srgrimes/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 2044Srgrimes/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 2054Srgrimes/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 2064Srgrimes/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 2074Srgrimes/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 2084Srgrimes/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 2094Srgrimes}; 2104Srgrimes 2114Srgrimesstatic void playinit() 2124Srgrimes{ 2134Srgrimes octave = DFLT_OCTAVE; 214766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 2154Srgrimes fill = NORMAL; 2164Srgrimes value = DFLT_VALUE; 2174Srgrimes octtrack = FALSE; 2184Srgrimes octprefix = TRUE; /* act as though there was an initial O(n) */ 2194Srgrimes} 2204Srgrimes 2211016Sachestatic void playtone(pitch, value, sustain) 2224Srgrimes/* play tone of proper duration for current rhythm signature */ 2234Srgrimesint pitch, value, sustain; 2244Srgrimes{ 2254Srgrimes register int sound, silence, snum = 1, sdenom = 1; 2264Srgrimes 2274Srgrimes /* this weirdness avoids floating-point arithmetic */ 2284Srgrimes for (; sustain; sustain--) 2294Srgrimes { 230738Sache /* See the BUGS section in the man page for discussion */ 2314Srgrimes snum *= NUM_MULT; 2324Srgrimes sdenom *= DENOM_MULT; 2334Srgrimes } 2344Srgrimes 2358288Sdg if (value == 0 || sdenom == 0) 2368288Sdg return; 2378288Sdg 2384Srgrimes if (pitch == -1) 2391016Sache rest(whole * snum / (value * sdenom)); 2404Srgrimes else 2414Srgrimes { 2424Srgrimes sound = (whole * snum) / (value * sdenom) 2434Srgrimes - (whole * (FILLTIME - fill)) / (value * FILLTIME); 2444Srgrimes silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 2454Srgrimes 2464Srgrimes#ifdef DEBUG 247738Sache (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 2484Srgrimes pitch, sound, silence); 2494Srgrimes#endif /* DEBUG */ 2504Srgrimes 2511016Sache tone(pitchtab[pitch], sound); 2524Srgrimes if (fill != LEGATO) 2531016Sache rest(silence); 2544Srgrimes } 2554Srgrimes} 2564Srgrimes 2574Srgrimesstatic int abs(n) 2584Srgrimesint n; 2594Srgrimes{ 2604Srgrimes if (n < 0) 2614Srgrimes return(-n); 2624Srgrimes else 2634Srgrimes return(n); 2644Srgrimes} 2654Srgrimes 2661016Sachestatic void playstring(cp, slen) 2674Srgrimes/* interpret and play an item from a notation string */ 2684Srgrimeschar *cp; 2694Srgrimessize_t slen; 2704Srgrimes{ 271738Sache int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 2724Srgrimes 2734Srgrimes#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 2744Srgrimes {v = v * 10 + (*++cp - '0'); slen--;} 2754Srgrimes for (; slen--; cp++) 2764Srgrimes { 2774Srgrimes int sustain, timeval, tempo; 2784Srgrimes register char c = toupper(*cp); 2794Srgrimes 2804Srgrimes#ifdef DEBUG 281738Sache (void) printf("playstring: %c (%x)\n", c, c); 2824Srgrimes#endif /* DEBUG */ 2834Srgrimes 2844Srgrimes switch (c) 2854Srgrimes { 2864Srgrimes case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 2874Srgrimes 2884Srgrimes /* compute pitch */ 2894Srgrimes pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 2904Srgrimes 2914Srgrimes /* this may be followed by an accidental sign */ 2924Srgrimes if (cp[1] == '#' || cp[1] == '+') 2934Srgrimes { 2944Srgrimes ++pitch; 2954Srgrimes ++cp; 2964Srgrimes slen--; 2974Srgrimes } 2984Srgrimes else if (cp[1] == '-') 2994Srgrimes { 3004Srgrimes --pitch; 3014Srgrimes ++cp; 3024Srgrimes slen--; 3034Srgrimes } 3044Srgrimes 3054Srgrimes /* 3064Srgrimes * If octave-tracking mode is on, and there has been no octave- 3074Srgrimes * setting prefix, find the version of the current letter note 3084Srgrimes * closest to the last regardless of octave. 3094Srgrimes */ 3104Srgrimes if (octtrack && !octprefix) 3114Srgrimes { 3124Srgrimes if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 3134Srgrimes { 3144Srgrimes ++octave; 3154Srgrimes pitch += OCTAVE_NOTES; 3164Srgrimes } 3174Srgrimes 3184Srgrimes if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 3194Srgrimes { 3204Srgrimes --octave; 3214Srgrimes pitch -= OCTAVE_NOTES; 3224Srgrimes } 3234Srgrimes } 3244Srgrimes octprefix = FALSE; 3254Srgrimes lastpitch = pitch; 3264Srgrimes 3274Srgrimes /* ...which may in turn be followed by an override time value */ 3284Srgrimes GETNUM(cp, timeval); 3294Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 3304Srgrimes timeval = value; 3314Srgrimes 3324Srgrimes /* ...and/or sustain dots */ 3334Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3344Srgrimes { 3354Srgrimes slen--; 3364Srgrimes sustain++; 3374Srgrimes } 3384Srgrimes 339738Sache /* ...and/or a slur mark */ 340738Sache oldfill = fill; 341738Sache if (cp[1] == '_') 342738Sache { 343738Sache fill = LEGATO; 344738Sache ++cp; 345738Sache slen--; 346738Sache } 347738Sache 3484Srgrimes /* time to emit the actual tone */ 3491016Sache playtone(pitch, timeval, sustain); 350738Sache 351738Sache fill = oldfill; 3524Srgrimes break; 3534Srgrimes 3544Srgrimes case 'O': 3554Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 3564Srgrimes { 3574Srgrimes octprefix = octtrack = FALSE; 3584Srgrimes ++cp; 3594Srgrimes slen--; 3604Srgrimes } 3614Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 3624Srgrimes { 3634Srgrimes octtrack = TRUE; 3644Srgrimes ++cp; 3654Srgrimes slen--; 3664Srgrimes } 3674Srgrimes else 3684Srgrimes { 3694Srgrimes GETNUM(cp, octave); 3703593Sache if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES) 3714Srgrimes octave = DFLT_OCTAVE; 3724Srgrimes octprefix = TRUE; 3734Srgrimes } 3744Srgrimes break; 3754Srgrimes 3764Srgrimes case '>': 3773593Sache if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1) 3784Srgrimes octave++; 3794Srgrimes octprefix = TRUE; 3804Srgrimes break; 3814Srgrimes 3824Srgrimes case '<': 3834Srgrimes if (octave > 0) 3844Srgrimes octave--; 3854Srgrimes octprefix = TRUE; 3864Srgrimes break; 3874Srgrimes 3884Srgrimes case 'N': 3894Srgrimes GETNUM(cp, pitch); 3904Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3914Srgrimes { 3924Srgrimes slen--; 3934Srgrimes sustain++; 3944Srgrimes } 395738Sache oldfill = fill; 396738Sache if (cp[1] == '_') 397738Sache { 398738Sache fill = LEGATO; 399738Sache ++cp; 400738Sache slen--; 401738Sache } 4021016Sache playtone(pitch - 1, value, sustain); 403738Sache fill = oldfill; 4044Srgrimes break; 4054Srgrimes 4064Srgrimes case 'L': 4074Srgrimes GETNUM(cp, value); 4084Srgrimes if (value <= 0 || value > MIN_VALUE) 4094Srgrimes value = DFLT_VALUE; 4104Srgrimes break; 4114Srgrimes 4124Srgrimes case 'P': 4134Srgrimes case '~': 4144Srgrimes /* this may be followed by an override time value */ 4154Srgrimes GETNUM(cp, timeval); 4164Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 4174Srgrimes timeval = value; 4184Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 4194Srgrimes { 4204Srgrimes slen--; 4214Srgrimes sustain++; 4224Srgrimes } 4231016Sache playtone(-1, timeval, sustain); 4244Srgrimes break; 4254Srgrimes 4264Srgrimes case 'T': 4274Srgrimes GETNUM(cp, tempo); 4284Srgrimes if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 4294Srgrimes tempo = DFLT_TEMPO; 430766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; 4314Srgrimes break; 4324Srgrimes 4334Srgrimes case 'M': 4344Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 4354Srgrimes { 4364Srgrimes fill = NORMAL; 4374Srgrimes ++cp; 4384Srgrimes slen--; 4394Srgrimes } 4404Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 4414Srgrimes { 4424Srgrimes fill = LEGATO; 4434Srgrimes ++cp; 4444Srgrimes slen--; 4454Srgrimes } 4464Srgrimes else if (cp[1] == 'S' || cp[1] == 's') 4474Srgrimes { 4484Srgrimes fill = STACCATO; 4494Srgrimes ++cp; 4504Srgrimes slen--; 4514Srgrimes } 4524Srgrimes break; 4534Srgrimes } 4544Srgrimes } 4554Srgrimes} 4564Srgrimes 4574Srgrimes/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 4584Srgrimes * 4594Srgrimes * This section implements driver hooks to run playstring() and the tone(), 4604Srgrimes * endtone(), and rest() functions defined above. 4614Srgrimes */ 4624Srgrimes 463738Sachestatic int spkr_active = FALSE; /* exclusion flag */ 464738Sachestatic struct buf *spkr_inbuf; /* incoming buf */ 4654Srgrimes 46610624Sbdeint spkropen(dev, flags, fmt, p) 46710624Sbdedev_t dev; 46810624Sbdeint flags; 46910624Sbdeint fmt; 47010624Sbdestruct proc *p; 4714Srgrimes{ 4724Srgrimes#ifdef DEBUG 473738Sache (void) printf("spkropen: entering with dev = %x\n", dev); 4744Srgrimes#endif /* DEBUG */ 4754Srgrimes 4764Srgrimes if (minor(dev) != 0) 4774Srgrimes return(ENXIO); 4784Srgrimes else if (spkr_active) 4794Srgrimes return(EBUSY); 4804Srgrimes else 4814Srgrimes { 482738Sache#ifdef DEBUG 483738Sache (void) printf("spkropen: about to perform play initialization\n"); 484738Sache#endif /* DEBUG */ 4854Srgrimes playinit(); 4864Srgrimes spkr_inbuf = geteblk(DEV_BSIZE); 487738Sache spkr_active = TRUE; 488738Sache return(0); 4894Srgrimes } 4904Srgrimes} 4914Srgrimes 49210624Sbdeint spkrwrite(dev, uio, ioflag) 493738Sachedev_t dev; 494738Sachestruct uio *uio; 49510624Sbdeint ioflag; 4964Srgrimes{ 4974Srgrimes#ifdef DEBUG 4984Srgrimes printf("spkrwrite: entering with dev = %x, count = %d\n", 4994Srgrimes dev, uio->uio_resid); 5004Srgrimes#endif /* DEBUG */ 5014Srgrimes 5024Srgrimes if (minor(dev) != 0) 5034Srgrimes return(ENXIO); 504738Sache else if (uio->uio_resid > DEV_BSIZE) /* prevent system crashes */ 505738Sache return(E2BIG); 5064Srgrimes else 5074Srgrimes { 508738Sache unsigned n; 509738Sache char *cp; 510738Sache int error; 511738Sache 512738Sache n = uio->uio_resid; 5134Srgrimes cp = spkr_inbuf->b_un.b_addr; 514738Sache if (!(error = uiomove(cp, n, uio))) 5151016Sache playstring(cp, n); 5164Srgrimes return(error); 5174Srgrimes } 5184Srgrimes} 5194Srgrimes 52010624Sbdeint spkrclose(dev, flags, fmt, p) 52110624Sbdedev_t dev; 52210624Sbdeint flags; 52310624Sbdeint fmt; 52410624Sbdestruct proc *p; 5254Srgrimes{ 5264Srgrimes#ifdef DEBUG 527738Sache (void) printf("spkrclose: entering with dev = %x\n", dev); 5284Srgrimes#endif /* DEBUG */ 5294Srgrimes 5304Srgrimes if (minor(dev) != 0) 5314Srgrimes return(ENXIO); 5324Srgrimes else 5334Srgrimes { 534766Sache wakeup((caddr_t)&endtone); 535766Sache wakeup((caddr_t)&endrest); 5364Srgrimes brelse(spkr_inbuf); 537738Sache spkr_active = FALSE; 538738Sache return(0); 5394Srgrimes } 5404Srgrimes} 5414Srgrimes 54210624Sbdeint spkrioctl(dev, cmd, cmdarg, flags, p) 54310624Sbdedev_t dev; 54410624Sbdeint cmd; 54510624Sbdecaddr_t cmdarg; 54610624Sbdeint flags; 54710624Sbdestruct proc *p; 5484Srgrimes{ 5494Srgrimes#ifdef DEBUG 550738Sache (void) printf("spkrioctl: entering with dev = %x, cmd = %x\n"); 5514Srgrimes#endif /* DEBUG */ 5524Srgrimes 5534Srgrimes if (minor(dev) != 0) 5544Srgrimes return(ENXIO); 5554Srgrimes else if (cmd == SPKRTONE) 5564Srgrimes { 5574Srgrimes tone_t *tp = (tone_t *)cmdarg; 5584Srgrimes 5594Srgrimes if (tp->frequency == 0) 5601016Sache rest(tp->duration); 5614Srgrimes else 5621016Sache tone(tp->frequency, tp->duration); 5631016Sache return 0; 5644Srgrimes } 5654Srgrimes else if (cmd == SPKRTUNE) 5664Srgrimes { 5674Srgrimes tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 5684Srgrimes tone_t ttp; 5694Srgrimes int error; 5704Srgrimes 5714Srgrimes for (; ; tp++) { 5724Srgrimes error = copyin(tp, &ttp, sizeof(tone_t)); 5734Srgrimes if (error) 5744Srgrimes return(error); 5754Srgrimes if (ttp.duration == 0) 5764Srgrimes break; 5774Srgrimes if (ttp.frequency == 0) 5781016Sache rest(ttp.duration); 5794Srgrimes else 5801016Sache tone(ttp.frequency, ttp.duration); 5814Srgrimes } 582738Sache return(0); 5834Srgrimes } 584738Sache return(EINVAL); 5854Srgrimes} 5864Srgrimes 58712502Sjulian 58812502Sjulianstatic spkr_devsw_installed = 0; 58912502Sjulian 59012517Sjulianstatic void spkr_drvinit(void *unused) 59112502Sjulian{ 59212517Sjulian dev_t dev; 59312517Sjulian 59412502Sjulian if( ! spkr_devsw_installed ) { 59512675Sjulian dev = makedev(CDEV_MAJOR, 0); 59612675Sjulian cdevsw_add(&dev,&spkr_cdevsw, NULL); 59712502Sjulian spkr_devsw_installed = 1; 59812517Sjulian#ifdef DEVFS 59912675Sjulian devfs_token = devfs_add_devsw("/", "spkr", 60012675Sjulian &spkr_cdevsw, 0, 60112675Sjulian DV_CHR, 0, 0, 0600); 60212521Sjulian#endif 60312517Sjulian } 60412502Sjulian} 60512517Sjulian 60612517SjulianSYSINIT(spkrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,spkr_drvinit,NULL) 60712517Sjulian 60812517Sjulian 6094Srgrimes#endif /* NSPEAKER > 0 */ 6104Srgrimes/* spkr.c ends here */ 611