spkr.c revision 49982
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 * 749982Sbillf * $Id: spkr.c,v 1.37 1999/05/31 11:26:32 phk Exp $ 84Srgrimes */ 94Srgrimes 104Srgrimes#include "speaker.h" 114Srgrimes 124Srgrimes#if NSPEAKER > 0 134Srgrimes 1432726Seivind#include "opt_devfs.h" 1532726Seivind 162056Swollman#include <sys/param.h> 172056Swollman#include <sys/systm.h> 182056Swollman#include <sys/kernel.h> 192056Swollman#include <sys/buf.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 2710537Sjulian#ifdef DEVFS 2810537Sjulian#include <sys/devfsext.h> 2933181Seivindstatic void *devfs_token; 3012502Sjulian#endif 3110537Sjulian 3212675Sjulianstatic d_open_t spkropen; 3312675Sjulianstatic d_close_t spkrclose; 3412675Sjulianstatic d_write_t spkrwrite; 3512675Sjulianstatic d_ioctl_t spkrioctl; 3612502Sjulian 3712675Sjulian#define CDEV_MAJOR 26 3847625Sphkstatic struct cdevsw spkr_cdevsw = { 3947625Sphk /* open */ spkropen, 4047625Sphk /* close */ spkrclose, 4147625Sphk /* read */ noread, 4247625Sphk /* write */ spkrwrite, 4347625Sphk /* ioctl */ spkrioctl, 4447625Sphk /* stop */ nostop, 4547625Sphk /* reset */ noreset, 4647625Sphk /* devtotty */ nodevtotty, 4747625Sphk /* poll */ nopoll, 4847625Sphk /* mmap */ nommap, 4947625Sphk /* strategy */ nostrategy, 5047625Sphk /* name */ "spkr", 5147625Sphk /* parms */ noparms, 5247625Sphk /* maj */ CDEV_MAJOR, 5347625Sphk /* dump */ nodump, 5447625Sphk /* psize */ nopsize, 5547625Sphk /* flags */ 0, 5647625Sphk /* maxio */ 0, 5747625Sphk /* bmaj */ -1 5847625Sphk}; 5912675Sjulian 604Srgrimes/**************** MACHINE DEPENDENT PART STARTS HERE ************************* 614Srgrimes * 624Srgrimes * This section defines a function tone() which causes a tone of given 6319174Sbde * frequency and duration from the ISA console speaker. 644Srgrimes * Another function endtone() is defined to force sound off, and there is 654Srgrimes * also a rest() entry point to do pauses. 664Srgrimes * 674Srgrimes * Audible sound is generated using the Programmable Interval Timer (PIT) and 6819174Sbde * Programmable Peripheral Interface (PPI) attached to the ISA speaker. The 694Srgrimes * PPI controls whether sound is passed through at all; the PIT's channel 2 is 704Srgrimes * used to generate clicks (a square wave) of whatever frequency is desired. 714Srgrimes */ 724Srgrimes 734Srgrimes/* 7419174Sbde * PPI control values. 7519174Sbde * XXX should be in a header and used in clock.c. 764Srgrimes */ 774Srgrimes#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ 784Srgrimes 79766Sache#define SPKRPRI PSOCK 80766Sachestatic char endtone, endrest; 814Srgrimes 8212854Sbdestatic void tone __P((unsigned int thz, unsigned int ticks)); 8312854Sbdestatic void rest __P((int ticks)); 8412854Sbdestatic void playinit __P((void)); 8512854Sbdestatic void playtone __P((int pitch, int value, int sustain)); 8612854Sbdestatic int abs __P((int n)); 8712854Sbdestatic void playstring __P((char *cp, size_t slen)); 8812854Sbde 89766Sache/* emit tone of frequency thz for given number of ticks */ 9017232Sjoergstatic void 9117232Sjoergtone(thz, ticks) 9217232Sjoerg unsigned int thz, ticks; 934Srgrimes{ 948288Sdg unsigned int divisor; 951016Sache int sps; 964Srgrimes 978288Sdg if (thz <= 0) 988288Sdg return; 998288Sdg 10019174Sbde divisor = timer_freq / thz; 1018288Sdg 1024Srgrimes#ifdef DEBUG 103766Sache (void) printf("tone: thz=%d ticks=%d\n", thz, ticks); 1044Srgrimes#endif /* DEBUG */ 1054Srgrimes 1064Srgrimes /* set timer to generate clicks at given frequency in Hertz */ 10717232Sjoerg sps = splclock(); 1081393Ssos 10919174Sbde if (acquire_timer2(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT)) { 1101393Ssos /* enter list of waiting procs ??? */ 11117232Sjoerg splx(sps); 1121393Ssos return; 1131393Ssos } 11417232Sjoerg splx(sps); 11517232Sjoerg disable_intr(); 1161393Ssos outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */ 1171393Ssos outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */ 11817232Sjoerg enable_intr(); 1194Srgrimes 1204Srgrimes /* turn the speaker on */ 1211393Ssos outb(IO_PPI, inb(IO_PPI) | PPI_SPKR); 1224Srgrimes 1234Srgrimes /* 1244Srgrimes * Set timeout to endtone function, then give up the timeslice. 1254Srgrimes * This is so other processes can execute while the tone is being 1264Srgrimes * emitted. 1274Srgrimes */ 1286152Sache if (ticks > 0) 1296152Sache tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks); 1301393Ssos outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR); 13117232Sjoerg sps = splclock(); 1321393Ssos release_timer2(); 13317232Sjoerg splx(sps); 1344Srgrimes} 1354Srgrimes 1364Srgrimes/* rest for given number of ticks */ 13717232Sjoergstatic void 13817232Sjoergrest(ticks) 13917232Sjoerg int ticks; 1404Srgrimes{ 1414Srgrimes /* 1424Srgrimes * Set timeout to endrest function, then give up the timeslice. 1434Srgrimes * This is so other processes can execute while the rest is being 1444Srgrimes * waited out. 1454Srgrimes */ 1464Srgrimes#ifdef DEBUG 147738Sache (void) printf("rest: %d\n", ticks); 1484Srgrimes#endif /* DEBUG */ 1496152Sache if (ticks > 0) 1506152Sache tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks); 1514Srgrimes} 1524Srgrimes 1534Srgrimes/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 1544Srgrimes * 1554Srgrimes * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 156738Sache * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- 157738Sache * tracking facility are added. 1584Srgrimes * Requires tone(), rest(), and endtone(). String play is not interruptible 1594Srgrimes * except possibly at physical block boundaries. 1604Srgrimes */ 1614Srgrimes 1624Srgrimestypedef int bool; 1634Srgrimes#define TRUE 1 1644Srgrimes#define FALSE 0 1654Srgrimes 1664Srgrimes#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) 1674Srgrimes#define isdigit(c) (((c) >= '0') && ((c) <= '9')) 1684Srgrimes#define dtoi(c) ((c) - '0') 1694Srgrimes 1704Srgrimesstatic int octave; /* currently selected octave */ 1714Srgrimesstatic int whole; /* whole-note time at current tempo, in ticks */ 1724Srgrimesstatic int value; /* whole divisor for note time, quarter note = 1 */ 1734Srgrimesstatic int fill; /* controls spacing of notes */ 1744Srgrimesstatic bool octtrack; /* octave-tracking on? */ 1754Srgrimesstatic bool octprefix; /* override current octave-tracking state? */ 1764Srgrimes 1774Srgrimes/* 1784Srgrimes * Magic number avoidance... 1794Srgrimes */ 1804Srgrimes#define SECS_PER_MIN 60 /* seconds per minute */ 1814Srgrimes#define WHOLE_NOTE 4 /* quarter notes per whole note */ 1824Srgrimes#define MIN_VALUE 64 /* the most we can divide a note by */ 1834Srgrimes#define DFLT_VALUE 4 /* default value (quarter-note) */ 1844Srgrimes#define FILLTIME 8 /* for articulation, break note in parts */ 1854Srgrimes#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 1864Srgrimes#define NORMAL 7 /* 7/8ths of note interval is filled */ 1874Srgrimes#define LEGATO 8 /* all of note interval is filled */ 1884Srgrimes#define DFLT_OCTAVE 4 /* default octave */ 1894Srgrimes#define MIN_TEMPO 32 /* minimum tempo */ 1904Srgrimes#define DFLT_TEMPO 120 /* default tempo */ 1914Srgrimes#define MAX_TEMPO 255 /* max tempo */ 1924Srgrimes#define NUM_MULT 3 /* numerator of dot multiplier */ 1934Srgrimes#define DENOM_MULT 2 /* denominator of dot multiplier */ 1944Srgrimes 1954Srgrimes/* letter to half-tone: A B C D E F G */ 1964Srgrimesstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 1974Srgrimes 1984Srgrimes/* 1994Srgrimes * This is the American Standard A440 Equal-Tempered scale with frequencies 2004Srgrimes * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 2014Srgrimes * our octave 0 is standard octave 2. 2024Srgrimes */ 2034Srgrimes#define OCTAVE_NOTES 12 /* semitones per octave */ 2044Srgrimesstatic int pitchtab[] = 2054Srgrimes{ 2064Srgrimes/* C C# D D# E F F# G G# A A# B*/ 2074Srgrimes/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 2084Srgrimes/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 2094Srgrimes/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 2104Srgrimes/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 2114Srgrimes/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 2124Srgrimes/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 2134Srgrimes/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 2144Srgrimes}; 2154Srgrimes 21617232Sjoergstatic void 21717232Sjoergplayinit() 2184Srgrimes{ 2194Srgrimes octave = DFLT_OCTAVE; 220766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 2214Srgrimes fill = NORMAL; 2224Srgrimes value = DFLT_VALUE; 2234Srgrimes octtrack = FALSE; 2244Srgrimes octprefix = TRUE; /* act as though there was an initial O(n) */ 2254Srgrimes} 2264Srgrimes 2274Srgrimes/* play tone of proper duration for current rhythm signature */ 22817232Sjoergstatic void 22917232Sjoergplaytone(pitch, value, sustain) 23017232Sjoerg int pitch, value, sustain; 2314Srgrimes{ 2324Srgrimes register int sound, silence, snum = 1, sdenom = 1; 2334Srgrimes 2344Srgrimes /* this weirdness avoids floating-point arithmetic */ 2354Srgrimes for (; sustain; sustain--) 2364Srgrimes { 237738Sache /* See the BUGS section in the man page for discussion */ 2384Srgrimes snum *= NUM_MULT; 2394Srgrimes sdenom *= DENOM_MULT; 2404Srgrimes } 2414Srgrimes 2428288Sdg if (value == 0 || sdenom == 0) 2438288Sdg return; 2448288Sdg 2454Srgrimes if (pitch == -1) 2461016Sache rest(whole * snum / (value * sdenom)); 2474Srgrimes else 2484Srgrimes { 2494Srgrimes sound = (whole * snum) / (value * sdenom) 2504Srgrimes - (whole * (FILLTIME - fill)) / (value * FILLTIME); 2514Srgrimes silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 2524Srgrimes 2534Srgrimes#ifdef DEBUG 254738Sache (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 2554Srgrimes pitch, sound, silence); 2564Srgrimes#endif /* DEBUG */ 2574Srgrimes 2581016Sache tone(pitchtab[pitch], sound); 2594Srgrimes if (fill != LEGATO) 2601016Sache rest(silence); 2614Srgrimes } 2624Srgrimes} 2634Srgrimes 26417232Sjoergstatic int 26517232Sjoergabs(n) 26617232Sjoerg int n; 2674Srgrimes{ 2684Srgrimes if (n < 0) 2694Srgrimes return(-n); 2704Srgrimes else 2714Srgrimes return(n); 2724Srgrimes} 2734Srgrimes 2744Srgrimes/* interpret and play an item from a notation string */ 27517232Sjoergstatic void 27617232Sjoergplaystring(cp, slen) 27717232Sjoerg char *cp; 27817232Sjoerg size_t slen; 2794Srgrimes{ 280738Sache int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 2814Srgrimes 2824Srgrimes#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 2834Srgrimes {v = v * 10 + (*++cp - '0'); slen--;} 2844Srgrimes for (; slen--; cp++) 2854Srgrimes { 2864Srgrimes int sustain, timeval, tempo; 2874Srgrimes register char c = toupper(*cp); 2884Srgrimes 2894Srgrimes#ifdef DEBUG 290738Sache (void) printf("playstring: %c (%x)\n", c, c); 2914Srgrimes#endif /* DEBUG */ 2924Srgrimes 2934Srgrimes switch (c) 2944Srgrimes { 2954Srgrimes case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 2964Srgrimes 2974Srgrimes /* compute pitch */ 2984Srgrimes pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 2994Srgrimes 3004Srgrimes /* this may be followed by an accidental sign */ 3014Srgrimes if (cp[1] == '#' || cp[1] == '+') 3024Srgrimes { 3034Srgrimes ++pitch; 3044Srgrimes ++cp; 3054Srgrimes slen--; 3064Srgrimes } 3074Srgrimes else if (cp[1] == '-') 3084Srgrimes { 3094Srgrimes --pitch; 3104Srgrimes ++cp; 3114Srgrimes slen--; 3124Srgrimes } 3134Srgrimes 3144Srgrimes /* 3154Srgrimes * If octave-tracking mode is on, and there has been no octave- 3164Srgrimes * setting prefix, find the version of the current letter note 3174Srgrimes * closest to the last regardless of octave. 3184Srgrimes */ 3194Srgrimes if (octtrack && !octprefix) 3204Srgrimes { 3214Srgrimes if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 3224Srgrimes { 3234Srgrimes ++octave; 3244Srgrimes pitch += OCTAVE_NOTES; 3254Srgrimes } 3264Srgrimes 3274Srgrimes if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 3284Srgrimes { 3294Srgrimes --octave; 3304Srgrimes pitch -= OCTAVE_NOTES; 3314Srgrimes } 3324Srgrimes } 3334Srgrimes octprefix = FALSE; 3344Srgrimes lastpitch = pitch; 3354Srgrimes 3364Srgrimes /* ...which may in turn be followed by an override time value */ 3374Srgrimes GETNUM(cp, timeval); 3384Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 3394Srgrimes timeval = value; 3404Srgrimes 3414Srgrimes /* ...and/or sustain dots */ 3424Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3434Srgrimes { 3444Srgrimes slen--; 3454Srgrimes sustain++; 3464Srgrimes } 3474Srgrimes 348738Sache /* ...and/or a slur mark */ 349738Sache oldfill = fill; 350738Sache if (cp[1] == '_') 351738Sache { 352738Sache fill = LEGATO; 353738Sache ++cp; 354738Sache slen--; 355738Sache } 356738Sache 3574Srgrimes /* time to emit the actual tone */ 3581016Sache playtone(pitch, timeval, sustain); 359738Sache 360738Sache fill = oldfill; 3614Srgrimes break; 3624Srgrimes 3634Srgrimes case 'O': 3644Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 3654Srgrimes { 3664Srgrimes octprefix = octtrack = FALSE; 3674Srgrimes ++cp; 3684Srgrimes slen--; 3694Srgrimes } 3704Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 3714Srgrimes { 3724Srgrimes octtrack = TRUE; 3734Srgrimes ++cp; 3744Srgrimes slen--; 3754Srgrimes } 3764Srgrimes else 3774Srgrimes { 3784Srgrimes GETNUM(cp, octave); 3793593Sache if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES) 3804Srgrimes octave = DFLT_OCTAVE; 3814Srgrimes octprefix = TRUE; 3824Srgrimes } 3834Srgrimes break; 3844Srgrimes 3854Srgrimes case '>': 3863593Sache if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1) 3874Srgrimes octave++; 3884Srgrimes octprefix = TRUE; 3894Srgrimes break; 3904Srgrimes 3914Srgrimes case '<': 3924Srgrimes if (octave > 0) 3934Srgrimes octave--; 3944Srgrimes octprefix = TRUE; 3954Srgrimes break; 3964Srgrimes 3974Srgrimes case 'N': 3984Srgrimes GETNUM(cp, pitch); 3994Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 4004Srgrimes { 4014Srgrimes slen--; 4024Srgrimes sustain++; 4034Srgrimes } 404738Sache oldfill = fill; 405738Sache if (cp[1] == '_') 406738Sache { 407738Sache fill = LEGATO; 408738Sache ++cp; 409738Sache slen--; 410738Sache } 4111016Sache playtone(pitch - 1, value, sustain); 412738Sache fill = oldfill; 4134Srgrimes break; 4144Srgrimes 4154Srgrimes case 'L': 4164Srgrimes GETNUM(cp, value); 4174Srgrimes if (value <= 0 || value > MIN_VALUE) 4184Srgrimes value = DFLT_VALUE; 4194Srgrimes break; 4204Srgrimes 4214Srgrimes case 'P': 4224Srgrimes case '~': 4234Srgrimes /* this may be followed by an override time value */ 4244Srgrimes GETNUM(cp, timeval); 4254Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 4264Srgrimes timeval = value; 4274Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 4284Srgrimes { 4294Srgrimes slen--; 4304Srgrimes sustain++; 4314Srgrimes } 4321016Sache playtone(-1, timeval, sustain); 4334Srgrimes break; 4344Srgrimes 4354Srgrimes case 'T': 4364Srgrimes GETNUM(cp, tempo); 4374Srgrimes if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 4384Srgrimes tempo = DFLT_TEMPO; 439766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; 4404Srgrimes break; 4414Srgrimes 4424Srgrimes case 'M': 4434Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 4444Srgrimes { 4454Srgrimes fill = NORMAL; 4464Srgrimes ++cp; 4474Srgrimes slen--; 4484Srgrimes } 4494Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 4504Srgrimes { 4514Srgrimes fill = LEGATO; 4524Srgrimes ++cp; 4534Srgrimes slen--; 4544Srgrimes } 4554Srgrimes else if (cp[1] == 'S' || cp[1] == 's') 4564Srgrimes { 4574Srgrimes fill = STACCATO; 4584Srgrimes ++cp; 4594Srgrimes slen--; 4604Srgrimes } 4614Srgrimes break; 4624Srgrimes } 4634Srgrimes } 4644Srgrimes} 4654Srgrimes 4664Srgrimes/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 4674Srgrimes * 4684Srgrimes * This section implements driver hooks to run playstring() and the tone(), 4694Srgrimes * endtone(), and rest() functions defined above. 4704Srgrimes */ 4714Srgrimes 472738Sachestatic int spkr_active = FALSE; /* exclusion flag */ 473738Sachestatic struct buf *spkr_inbuf; /* incoming buf */ 4744Srgrimes 47517232Sjoergint 47617232Sjoergspkropen(dev, flags, fmt, p) 47717232Sjoerg dev_t dev; 47817232Sjoerg int flags; 47917232Sjoerg int fmt; 48017232Sjoerg struct proc *p; 4814Srgrimes{ 4824Srgrimes#ifdef DEBUG 48349982Sbillf (void) printf("spkropen: entering with dev = %s\n", devtoname(dev)); 4844Srgrimes#endif /* DEBUG */ 4854Srgrimes 4864Srgrimes if (minor(dev) != 0) 4874Srgrimes return(ENXIO); 4884Srgrimes else if (spkr_active) 4894Srgrimes return(EBUSY); 4904Srgrimes else 4914Srgrimes { 492738Sache#ifdef DEBUG 493738Sache (void) printf("spkropen: about to perform play initialization\n"); 494738Sache#endif /* DEBUG */ 4954Srgrimes playinit(); 4964Srgrimes spkr_inbuf = geteblk(DEV_BSIZE); 497738Sache spkr_active = TRUE; 498738Sache return(0); 4994Srgrimes } 5004Srgrimes} 5014Srgrimes 50217232Sjoergint 50317232Sjoergspkrwrite(dev, uio, ioflag) 50417232Sjoerg dev_t dev; 50517232Sjoerg struct uio *uio; 50617232Sjoerg int ioflag; 5074Srgrimes{ 5084Srgrimes#ifdef DEBUG 50949982Sbillf printf("spkrwrite: entering with dev = %s, count = %d\n", 51049982Sbillf devtoname(dev), uio->uio_resid); 5114Srgrimes#endif /* DEBUG */ 5124Srgrimes 5134Srgrimes if (minor(dev) != 0) 5144Srgrimes return(ENXIO); 51517803Speter else if (uio->uio_resid > (DEV_BSIZE - 1)) /* prevent system crashes */ 516738Sache return(E2BIG); 5174Srgrimes else 5184Srgrimes { 519738Sache unsigned n; 520738Sache char *cp; 521738Sache int error; 522738Sache 523738Sache n = uio->uio_resid; 52431493Sphk cp = spkr_inbuf->b_data; 52517803Speter error = uiomove(cp, n, uio); 52617803Speter if (!error) { 52717803Speter cp[n] = '\0'; 5281016Sache playstring(cp, n); 52917803Speter } 5304Srgrimes return(error); 5314Srgrimes } 5324Srgrimes} 5334Srgrimes 53417232Sjoergint 53517232Sjoergspkrclose(dev, flags, fmt, p) 53617232Sjoerg dev_t dev; 53717232Sjoerg int flags; 53817232Sjoerg int fmt; 53917232Sjoerg struct proc *p; 5404Srgrimes{ 5414Srgrimes#ifdef DEBUG 54249982Sbillf (void) printf("spkrclose: entering with dev = %s\n", devtoname(dev)); 5434Srgrimes#endif /* DEBUG */ 5444Srgrimes 5454Srgrimes if (minor(dev) != 0) 5464Srgrimes return(ENXIO); 5474Srgrimes else 5484Srgrimes { 549766Sache wakeup((caddr_t)&endtone); 550766Sache wakeup((caddr_t)&endrest); 5514Srgrimes brelse(spkr_inbuf); 552738Sache spkr_active = FALSE; 553738Sache return(0); 5544Srgrimes } 5554Srgrimes} 5564Srgrimes 55717232Sjoergint 55817232Sjoergspkrioctl(dev, cmd, cmdarg, flags, p) 55917232Sjoerg dev_t dev; 56038505Sbde unsigned long cmd; 56117232Sjoerg caddr_t cmdarg; 56217232Sjoerg int flags; 56317232Sjoerg struct proc *p; 5644Srgrimes{ 5654Srgrimes#ifdef DEBUG 56638505Sbde (void) printf("spkrioctl: entering with dev = %lx, cmd = %lx\n", 56738505Sbde (unsigned long)dev, cmd); 5684Srgrimes#endif /* DEBUG */ 5694Srgrimes 5704Srgrimes if (minor(dev) != 0) 5714Srgrimes return(ENXIO); 5724Srgrimes else if (cmd == SPKRTONE) 5734Srgrimes { 5744Srgrimes tone_t *tp = (tone_t *)cmdarg; 5754Srgrimes 5764Srgrimes if (tp->frequency == 0) 5771016Sache rest(tp->duration); 5784Srgrimes else 5791016Sache tone(tp->frequency, tp->duration); 5801016Sache return 0; 5814Srgrimes } 5824Srgrimes else if (cmd == SPKRTUNE) 5834Srgrimes { 5844Srgrimes tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 5854Srgrimes tone_t ttp; 5864Srgrimes int error; 5874Srgrimes 5884Srgrimes for (; ; tp++) { 5894Srgrimes error = copyin(tp, &ttp, sizeof(tone_t)); 5904Srgrimes if (error) 5914Srgrimes return(error); 5924Srgrimes if (ttp.duration == 0) 5934Srgrimes break; 5944Srgrimes if (ttp.frequency == 0) 5951016Sache rest(ttp.duration); 5964Srgrimes else 5971016Sache tone(ttp.frequency, ttp.duration); 5984Srgrimes } 599738Sache return(0); 6004Srgrimes } 601738Sache return(EINVAL); 6024Srgrimes} 6034Srgrimes 60417232Sjoergstatic void 60517232Sjoergspkr_drvinit(void *unused) 60612502Sjulian{ 60747640Sphk cdevsw_add(&spkr_cdevsw); 60812517Sjulian#ifdef DEVFS 60947640Sphk devfs_token = devfs_add_devswf(&spkr_cdevsw, 0, DV_CHR, 61047640Sphk UID_ROOT, GID_WHEEL, 0600, "speaker"); 61112521Sjulian#endif 61212502Sjulian} 61312517Sjulian 61412517SjulianSYSINIT(spkrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,spkr_drvinit,NULL) 61512517Sjulian 61612517Sjulian 6174Srgrimes#endif /* NSPEAKER > 0 */ 6184Srgrimes/* spkr.c ends here */ 619