spkr.c revision 50477
1119418Sobrien/* 251694Sroger * spkr.c -- device driver for console speaker 351694Sroger * 451694Sroger * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993 551694Sroger * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su> 651694Sroger * 751694Sroger * $FreeBSD: head/sys/dev/speaker/spkr.c 50477 1999-08-28 01:08:13Z peter $ 851694Sroger */ 951694Sroger 1051694Sroger#include "speaker.h" 1151694Sroger 1251694Sroger#if NSPEAKER > 0 1351694Sroger 1451694Sroger#include <sys/param.h> 1551694Sroger#include <sys/systm.h> 1651694Sroger#include <sys/kernel.h> 1751694Sroger#include <sys/buf.h> 1851694Sroger#include <sys/uio.h> 1951694Sroger#include <sys/conf.h> 2051694Sroger#include <i386/isa/isa.h> 2151694Sroger#include <i386/isa/timerreg.h> 2251694Sroger#include <machine/clock.h> 2351694Sroger#include <machine/speaker.h> 2451694Sroger 2551694Srogerstatic d_open_t spkropen; 2651694Srogerstatic d_close_t spkrclose; 2751694Srogerstatic d_write_t spkrwrite; 2851694Srogerstatic d_ioctl_t spkrioctl; 2951694Sroger 3051694Sroger#define CDEV_MAJOR 26 3151694Srogerstatic struct cdevsw spkr_cdevsw = { 3251694Sroger /* open */ spkropen, 3351694Sroger /* close */ spkrclose, 34119418Sobrien /* read */ noread, 35119418Sobrien /* write */ spkrwrite, 3651694Sroger /* ioctl */ spkrioctl, 37119418Sobrien /* stop */ nostop, 38119418Sobrien /* reset */ noreset, 39119418Sobrien /* devtotty */ nodevtotty, 40119418Sobrien /* poll */ nopoll, 41119418Sobrien /* mmap */ nommap, 42119418Sobrien /* strategy */ nostrategy, 43119418Sobrien /* name */ "spkr", 44119418Sobrien /* parms */ noparms, 45119418Sobrien /* maj */ CDEV_MAJOR, 46119418Sobrien /* dump */ nodump, 47119418Sobrien /* psize */ nopsize, 48119418Sobrien /* flags */ 0, 4959014Sroger /* maxio */ 0, 5051694Sroger /* bmaj */ -1 5151694Sroger}; 5251694Sroger 5351694Sroger/**************** MACHINE DEPENDENT PART STARTS HERE ************************* 5462214Sroger * 5562214Sroger * This section defines a function tone() which causes a tone of given 5662214Sroger * frequency and duration from the ISA console speaker. 5762214Sroger * Another function endtone() is defined to force sound off, and there is 5862214Sroger * also a rest() entry point to do pauses. 5962214Sroger * 6051694Sroger * Audible sound is generated using the Programmable Interval Timer (PIT) and 6151694Sroger * Programmable Peripheral Interface (PPI) attached to the ISA speaker. The 6251694Sroger * PPI controls whether sound is passed through at all; the PIT's channel 2 is 6351694Sroger * used to generate clicks (a square wave) of whatever frequency is desired. 6451694Sroger */ 6551694Sroger 6651694Sroger/* 6751694Sroger * PPI control values. 6870834Swollman * XXX should be in a header and used in clock.c. 6970834Swollman */ 7070834Swollman#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ 7151694Sroger 7270834Swollman#define SPKRPRI PSOCK 7351694Srogerstatic char endtone, endrest; 7451694Sroger 7551694Srogerstatic void tone __P((unsigned int thz, unsigned int ticks)); 7651694Srogerstatic void rest __P((int ticks)); 7751694Srogerstatic void playinit __P((void)); 7851694Srogerstatic void playtone __P((int pitch, int value, int sustain)); 7951694Srogerstatic int abs __P((int n)); 8093023Snsouchstatic void playstring __P((char *cp, size_t slen)); 8151694Sroger 8251694Sroger/* emit tone of frequency thz for given number of ticks */ 8351694Srogerstatic void 8459014Srogertone(thz, ticks) 8559014Sroger unsigned int thz, ticks; 8659014Sroger{ 8759014Sroger unsigned int divisor; 8859014Sroger int sps; 8959014Sroger 9051694Sroger if (thz <= 0) 9151694Sroger return; 9251694Sroger 9351694Sroger divisor = timer_freq / thz; 9451694Sroger 9567306Sroger#ifdef DEBUG 9667306Sroger (void) printf("tone: thz=%d ticks=%d\n", thz, ticks); 9751694Sroger#endif /* DEBUG */ 9851694Sroger 99119277Simp /* set timer to generate clicks at given frequency in Hertz */ 100119277Simp sps = splclock(); 101119277Simp 102119277Simp if (acquire_timer2(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT)) { 10351694Sroger /* enter list of waiting procs ??? */ 10451694Sroger splx(sps); 10551694Sroger return; 10651694Sroger } 10751694Sroger splx(sps); 10851694Sroger disable_intr(); 10959014Sroger outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */ 110118819Salex outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */ 111118819Salex enable_intr(); 112118819Salex 113118819Salex /* turn the speaker on */ 114118819Salex outb(IO_PPI, inb(IO_PPI) | PPI_SPKR); 115118819Salex 11651694Sroger /* 11751694Sroger * Set timeout to endtone function, then give up the timeslice. 11851694Sroger * This is so other processes can execute while the tone is being 11951694Sroger * emitted. 12051694Sroger */ 12151694Sroger if (ticks > 0) 12259014Sroger tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks); 123118819Salex outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR); 124118819Salex sps = splclock(); 125118819Salex release_timer2(); 126118819Salex splx(sps); 127118819Salex} 12851694Sroger 12962214Sroger/* rest for given number of ticks */ 13051694Srogerstatic void 13162214Srogerrest(ticks) 13262214Sroger int ticks; 13351694Sroger{ 13451694Sroger /* 13551694Sroger * Set timeout to endrest function, then give up the timeslice. 13651694Sroger * This is so other processes can execute while the rest is being 13751694Sroger * waited out. 13851694Sroger */ 13951694Sroger#ifdef DEBUG 14051694Sroger (void) printf("rest: %d\n", ticks); 14151694Sroger#endif /* DEBUG */ 14251694Sroger if (ticks > 0) 14351694Sroger tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks); 14462214Sroger} 14562214Sroger 14662214Sroger/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 14762214Sroger * 14862214Sroger * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 14962214Sroger * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- 15062214Sroger * tracking facility are added. 15162214Sroger * Requires tone(), rest(), and endtone(). String play is not interruptible 15262214Sroger * except possibly at physical block boundaries. 15362214Sroger */ 15462214Sroger 15562214Srogertypedef int bool; 15662214Sroger#define TRUE 1 15762214Sroger#define FALSE 0 15862214Sroger 15962214Sroger#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) 16062214Sroger#define isdigit(c) (((c) >= '0') && ((c) <= '9')) 16162214Sroger#define dtoi(c) ((c) - '0') 16262214Sroger 16362214Srogerstatic int octave; /* currently selected octave */ 16459014Srogerstatic int whole; /* whole-note time at current tempo, in ticks */ 16559014Srogerstatic int value; /* whole divisor for note time, quarter note = 1 */ 16659014Srogerstatic int fill; /* controls spacing of notes */ 16759014Srogerstatic bool octtrack; /* octave-tracking on? */ 16859014Srogerstatic bool octprefix; /* override current octave-tracking state? */ 16959014Sroger 17059014Sroger/* 17159014Sroger * Magic number avoidance... 17259014Sroger */ 17359014Sroger#define SECS_PER_MIN 60 /* seconds per minute */ 17459014Sroger#define WHOLE_NOTE 4 /* quarter notes per whole note */ 17559014Sroger#define MIN_VALUE 64 /* the most we can divide a note by */ 17651694Sroger#define DFLT_VALUE 4 /* default value (quarter-note) */ 17751694Sroger#define FILLTIME 8 /* for articulation, break note in parts */ 17851694Sroger#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 17962214Sroger#define NORMAL 7 /* 7/8ths of note interval is filled */ 18062214Sroger#define LEGATO 8 /* all of note interval is filled */ 18162214Sroger#define DFLT_OCTAVE 4 /* default octave */ 18262214Sroger#define MIN_TEMPO 32 /* minimum tempo */ 18362214Sroger#define DFLT_TEMPO 120 /* default tempo */ 18462214Sroger#define MAX_TEMPO 255 /* max tempo */ 18562214Sroger#define NUM_MULT 3 /* numerator of dot multiplier */ 18662214Sroger#define DENOM_MULT 2 /* denominator of dot multiplier */ 18762214Sroger 188123291Sobrien/* letter to half-tone: A B C D E F G */ 189123291Sobrienstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 19062214Sroger 19162214Sroger/* 19262214Sroger * This is the American Standard A440 Equal-Tempered scale with frequencies 19362214Sroger * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 19462214Sroger * our octave 0 is standard octave 2. 19562214Sroger */ 19693023Snsouch#define OCTAVE_NOTES 12 /* semitones per octave */ 19765692Srogerstatic int pitchtab[] = 19865392Speter{ 19993023Snsouch/* C C# D D# E F F# G G# A A# B*/ 20093023Snsouch/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 20193023Snsouch/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 20262214Sroger/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 20365392Speter/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 20451694Sroger/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 20562214Sroger/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 20651694Sroger/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 20751694Sroger}; 20851694Sroger 20951694Srogerstatic void 21051694Srogerplayinit() 21151694Sroger{ 21251694Sroger octave = DFLT_OCTAVE; 21351694Sroger whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 21451694Sroger fill = NORMAL; 21551694Sroger value = DFLT_VALUE; 21651694Sroger octtrack = FALSE; 21751694Sroger octprefix = TRUE; /* act as though there was an initial O(n) */ 21851694Sroger} 21951694Sroger 22051694Sroger/* play tone of proper duration for current rhythm signature */ 22151694Srogerstatic void 22251694Srogerplaytone(pitch, value, sustain) 22351694Sroger int pitch, value, sustain; 22493023Snsouch{ 22593023Snsouch register int sound, silence, snum = 1, sdenom = 1; 22693023Snsouch 22793023Snsouch /* this weirdness avoids floating-point arithmetic */ 22893023Snsouch for (; sustain; sustain--) 22993023Snsouch { 23093023Snsouch /* See the BUGS section in the man page for discussion */ 23193023Snsouch snum *= NUM_MULT; 23293023Snsouch sdenom *= DENOM_MULT; 23393023Snsouch } 23493023Snsouch 23593023Snsouch if (value == 0 || sdenom == 0) 23693023Snsouch return; 23793023Snsouch 23893023Snsouch if (pitch == -1) 23993023Snsouch rest(whole * snum / (value * sdenom)); 24051694Sroger else 24151694Sroger { 24251694Sroger sound = (whole * snum) / (value * sdenom) 24351694Sroger - (whole * (FILLTIME - fill)) / (value * FILLTIME); 24451694Sroger silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 24551694Sroger 24651694Sroger#ifdef DEBUG 24751694Sroger (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 24851694Sroger pitch, sound, silence); 24951694Sroger#endif /* DEBUG */ 25051694Sroger 25151694Sroger tone(pitchtab[pitch], sound); 25251694Sroger if (fill != LEGATO) 25351694Sroger rest(silence); 25451694Sroger } 25551694Sroger} 25651694Sroger 25751694Srogerstatic int 25851694Srogerabs(n) 25951694Sroger int n; 26051694Sroger{ 261111815Sphk if (n < 0) 262111815Sphk return(-n); 263111815Sphk else 264111815Sphk return(n); 265111815Sphk} 266111815Sphk 267111815Sphk/* interpret and play an item from a notation string */ 268111815Sphkstatic void 269111815Sphkplaystring(cp, slen) 27051694Sroger char *cp; 27151694Sroger size_t slen; 27252995Speter{ 27367306Sroger int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 27465728Sroger 27565728Sroger#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 27667306Sroger {v = v * 10 + (*++cp - '0'); slen--;} 27751694Sroger for (; slen--; cp++) 27851694Sroger { 27951694Sroger int sustain, timeval, tempo; 28051694Sroger register char c = toupper(*cp); 28151694Sroger 28251694Sroger#ifdef DEBUG 28351694Sroger (void) printf("playstring: %c (%x)\n", c, c); 28451694Sroger#endif /* DEBUG */ 28551694Sroger 28651694Sroger switch (c) 28751694Sroger { 28867306Sroger case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 28967306Sroger 29067306Sroger /* compute pitch */ 29167306Sroger pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 29267306Sroger 29367306Sroger /* this may be followed by an accidental sign */ 29467306Sroger if (cp[1] == '#' || cp[1] == '+') 29567306Sroger { 29667306Sroger ++pitch; 29767306Sroger ++cp; 29867306Sroger slen--; 29967306Sroger } 30067306Sroger else if (cp[1] == '-') 30167306Sroger { 30267306Sroger --pitch; 30367306Sroger ++cp; 30467306Sroger slen--; 30567306Sroger } 30667306Sroger 30751694Sroger /* 30851694Sroger * If octave-tracking mode is on, and there has been no octave- 30951694Sroger * setting prefix, find the version of the current letter note 31051694Sroger * closest to the last regardless of octave. 31151694Sroger */ 31251694Sroger if (octtrack && !octprefix) 31351694Sroger { 31451694Sroger if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 31551694Sroger { 31651694Sroger ++octave; 31751694Sroger pitch += OCTAVE_NOTES; 31851694Sroger } 31951694Sroger 32051694Sroger if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 32151694Sroger { 32251694Sroger --octave; 32351694Sroger pitch -= OCTAVE_NOTES; 32451694Sroger } 32551694Sroger } 32651694Sroger octprefix = FALSE; 32751694Sroger lastpitch = pitch; 32851694Sroger 32951694Sroger /* ...which may in turn be followed by an override time value */ 33051694Sroger GETNUM(cp, timeval); 33151694Sroger if (timeval <= 0 || timeval > MIN_VALUE) 33251694Sroger timeval = value; 33362112Sroger 33462112Sroger /* ...and/or sustain dots */ 33562112Sroger for (sustain = 0; cp[1] == '.'; cp++) 33651694Sroger { 33751694Sroger slen--; 33851694Sroger sustain++; 33951694Sroger } 34051694Sroger 34151694Sroger /* ...and/or a slur mark */ 34251694Sroger oldfill = fill; 34351694Sroger if (cp[1] == '_') 34451694Sroger { 34551694Sroger fill = LEGATO; 346119690Sjhb ++cp; 34765049Sroger slen--; 34865049Sroger } 34951694Sroger 35065049Sroger /* time to emit the actual tone */ 35151694Sroger playtone(pitch, timeval, sustain); 35251694Sroger 35351694Sroger fill = oldfill; 35451694Sroger break; 35551694Sroger 35659014Sroger case 'O': 35759014Sroger if (cp[1] == 'N' || cp[1] == 'n') 35851694Sroger { 35959014Sroger octprefix = octtrack = FALSE; 36051694Sroger ++cp; 36151694Sroger slen--; 36251694Sroger } 36359014Sroger else if (cp[1] == 'L' || cp[1] == 'l') 36459014Sroger { 36551694Sroger octtrack = TRUE; 36651694Sroger ++cp; 36751694Sroger slen--; 36851694Sroger } 36951694Sroger else 37051694Sroger { 37151694Sroger GETNUM(cp, octave); 37251694Sroger if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES) 37351694Sroger octave = DFLT_OCTAVE; 37451694Sroger octprefix = TRUE; 37551694Sroger } 37651694Sroger break; 37751694Sroger 37865049Sroger case '>': 37965049Sroger if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1) 38065049Sroger octave++; 38151694Sroger octprefix = TRUE; 38251694Sroger break; 38351694Sroger 38451694Sroger case '<': 38551694Sroger if (octave > 0) 38651694Sroger octave--; 38759250Sroger octprefix = TRUE; 38851694Sroger break; 38951694Sroger 39051694Sroger case 'N': 39151694Sroger GETNUM(cp, pitch); 39251694Sroger for (sustain = 0; cp[1] == '.'; cp++) 39351694Sroger { 39451694Sroger slen--; 39551694Sroger sustain++; 39651694Sroger } 39751694Sroger oldfill = fill; 39851694Sroger if (cp[1] == '_') 39951694Sroger { 40051694Sroger fill = LEGATO; 40151694Sroger ++cp; 40251694Sroger slen--; 40351694Sroger } 40451694Sroger playtone(pitch - 1, value, sustain); 40551694Sroger fill = oldfill; 40651694Sroger break; 40751694Sroger 40851694Sroger case 'L': 40951694Sroger GETNUM(cp, value); 41051694Sroger if (value <= 0 || value > MIN_VALUE) 41151694Sroger value = DFLT_VALUE; 41251694Sroger break; 41365692Sroger 41493023Snsouch case 'P': 41551694Sroger case '~': 41651694Sroger /* this may be followed by an override time value */ 41751694Sroger GETNUM(cp, timeval); 41851694Sroger if (timeval <= 0 || timeval > MIN_VALUE) 41951694Sroger timeval = value; 42051694Sroger for (sustain = 0; cp[1] == '.'; cp++) 42151694Sroger { 42251694Sroger slen--; 42351694Sroger sustain++; 42451694Sroger } 42551694Sroger playtone(-1, timeval, sustain); 42651694Sroger break; 42751694Sroger 42851694Sroger case 'T': 42951694Sroger GETNUM(cp, tempo); 43051694Sroger if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 43151694Sroger tempo = DFLT_TEMPO; 43251694Sroger whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; 43351694Sroger break; 43451694Sroger 43551694Sroger case 'M': 43651694Sroger if (cp[1] == 'N' || cp[1] == 'n') 43751694Sroger { 43851694Sroger fill = NORMAL; 43951694Sroger ++cp; 44051694Sroger slen--; 44151694Sroger } 44251694Sroger else if (cp[1] == 'L' || cp[1] == 'l') 44351694Sroger { 44451694Sroger fill = LEGATO; 44551694Sroger ++cp; 44651694Sroger slen--; 44751694Sroger } 44851694Sroger else if (cp[1] == 'S' || cp[1] == 's') 44967306Sroger { 45067306Sroger fill = STACCATO; 45167306Sroger ++cp; 45267306Sroger slen--; 45367306Sroger } 45467306Sroger break; 45567306Sroger } 45651694Sroger } 45767306Sroger} 45867306Sroger 45967306Sroger/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 46067306Sroger * 46167306Sroger * This section implements driver hooks to run playstring() and the tone(), 46267306Sroger * endtone(), and rest() functions defined above. 46367306Sroger */ 46467306Sroger 46567306Srogerstatic int spkr_active = FALSE; /* exclusion flag */ 46667306Srogerstatic struct buf *spkr_inbuf; /* incoming buf */ 46767306Sroger 46851694Srogerint 46951694Srogerspkropen(dev, flags, fmt, p) 47051694Sroger dev_t dev; 47165049Sroger int flags; 47265049Sroger int fmt; 47365049Sroger struct proc *p; 47465049Sroger{ 47551694Sroger#ifdef DEBUG 47651694Sroger (void) printf("spkropen: entering with dev = %s\n", devtoname(dev)); 47751694Sroger#endif /* DEBUG */ 47851694Sroger 47951694Sroger if (minor(dev) != 0) 48051694Sroger return(ENXIO); 48151694Sroger else if (spkr_active) 48251694Sroger return(EBUSY); 48351694Sroger else 48451694Sroger { 48551694Sroger#ifdef DEBUG 48651694Sroger (void) printf("spkropen: about to perform play initialization\n"); 487118819Salex#endif /* DEBUG */ 488118819Salex playinit(); 489118819Salex spkr_inbuf = geteblk(DEV_BSIZE); 490118819Salex spkr_active = TRUE; 491118819Salex return(0); 492118819Salex } 49351694Sroger} 49459014Sroger 49559014Srogerint 49651694Srogerspkrwrite(dev, uio, ioflag) 49793023Snsouch dev_t dev; 49893023Snsouch struct uio *uio; 499115556Sphk int ioflag; 500115556Sphk{ 50193023Snsouch#ifdef DEBUG 502123088Struckman printf("spkrwrite: entering with dev = %s, count = %d\n", 503123088Struckman devtoname(dev), uio->uio_resid); 504123088Struckman#endif /* DEBUG */ 50593023Snsouch 50667306Sroger if (minor(dev) != 0) 50767306Sroger return(ENXIO); 50867306Sroger else if (uio->uio_resid > (DEV_BSIZE - 1)) /* prevent system crashes */ 50951694Sroger return(E2BIG); 510107699Sroger else 511107699Sroger { 51267306Sroger unsigned n; 51367306Sroger char *cp; 51467306Sroger int error; 51567306Sroger 51651694Sroger n = uio->uio_resid; 51751694Sroger cp = spkr_inbuf->b_data; 51851694Sroger error = uiomove(cp, n, uio); 51951694Sroger if (!error) { 52065049Sroger cp[n] = '\0'; 52165049Sroger playstring(cp, n); 52265049Sroger } 52351694Sroger return(error); 52451694Sroger } 52551694Sroger} 52651694Sroger 52751694Srogerint 52851694Srogerspkrclose(dev, flags, fmt, p) 52951694Sroger dev_t dev; 53051694Sroger int flags; 53151694Sroger int fmt; 53251694Sroger struct proc *p; 53351694Sroger{ 53451694Sroger#ifdef DEBUG 53559014Sroger (void) printf("spkrclose: entering with dev = %s\n", devtoname(dev)); 53659014Sroger#endif /* DEBUG */ 53751694Sroger 53851694Sroger if (minor(dev) != 0) 53951694Sroger return(ENXIO); 54051694Sroger else 54151694Sroger { 54251694Sroger wakeup((caddr_t)&endtone); 54351694Sroger wakeup((caddr_t)&endrest); 54451694Sroger brelse(spkr_inbuf); 54551694Sroger spkr_active = FALSE; 54651694Sroger return(0); 54751694Sroger } 54851694Sroger} 54951694Sroger 55051694Srogerint 55151694Srogerspkrioctl(dev, cmd, cmdarg, flags, p) 55251694Sroger dev_t dev; 55351694Sroger unsigned long cmd; 55451694Sroger caddr_t cmdarg; 55551694Sroger int flags; 55651694Sroger struct proc *p; 55751694Sroger{ 55851694Sroger#ifdef DEBUG 55951694Sroger (void) printf("spkrioctl: entering with dev = %s, cmd = %lx\n", 56051694Sroger devtoname(dev), cmd); 56151694Sroger#endif /* DEBUG */ 56251694Sroger 56351694Sroger if (minor(dev) != 0) 56451694Sroger return(ENXIO); 56551694Sroger else if (cmd == SPKRTONE) 56651694Sroger { 56751694Sroger tone_t *tp = (tone_t *)cmdarg; 56851694Sroger 56951694Sroger if (tp->frequency == 0) 57051694Sroger rest(tp->duration); 57151694Sroger else 57251694Sroger tone(tp->frequency, tp->duration); 57351694Sroger return 0; 57451694Sroger } 57551694Sroger else if (cmd == SPKRTUNE) 57651694Sroger { 57751694Sroger tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 57851694Sroger tone_t ttp; 579104094Sphk int error; 58083366Sjulian 58151694Sroger for (; ; tp++) { 58251694Sroger error = copyin(tp, &ttp, sizeof(tone_t)); 58351694Sroger if (error) 58451694Sroger return(error); 58551694Sroger if (ttp.duration == 0) 58651694Sroger break; 58751694Sroger if (ttp.frequency == 0) 58851694Sroger rest(ttp.duration); 58951694Sroger else 59051694Sroger tone(ttp.frequency, ttp.duration); 59151694Sroger } 59251694Sroger return(0); 59351694Sroger } 59451694Sroger return(EINVAL); 59551694Sroger} 59651694Sroger 59751694Srogerstatic void 59851694Srogerspkr_drvinit(void *unused) 59951694Sroger{ 60051694Sroger make_dev(&spkr_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "speaker"); 60151694Sroger} 60251694Sroger 60351694SrogerSYSINIT(spkrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,spkr_drvinit,NULL) 60451694Sroger 60551694Sroger 60651694Sroger#endif /* NSPEAKER > 0 */ 60751694Sroger/* spkr.c ends here */ 60851694Sroger