spkr.c revision 61994
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 * 750477Speter * $FreeBSD: head/sys/dev/speaker/spkr.c 61994 2000-06-23 07:44:33Z msmith $ 84Srgrimes */ 94Srgrimes 102056Swollman#include <sys/param.h> 112056Swollman#include <sys/systm.h> 1261994Smsmith#include <sys/bus.h> 132056Swollman#include <sys/kernel.h> 1461994Smsmith#include <sys/module.h> 152056Swollman#include <sys/uio.h> 1612675Sjulian#include <sys/conf.h> 1752843Sphk#include <sys/ctype.h> 1860038Sphk#include <sys/malloc.h> 1961994Smsmith#include <isa/isavar.h> 202056Swollman#include <i386/isa/isa.h> 212056Swollman#include <i386/isa/timerreg.h> 227090Sbde#include <machine/clock.h> 232056Swollman#include <machine/speaker.h> 244Srgrimes 2512675Sjulianstatic d_open_t spkropen; 2612675Sjulianstatic d_close_t spkrclose; 2712675Sjulianstatic d_write_t spkrwrite; 2812675Sjulianstatic d_ioctl_t spkrioctl; 2912502Sjulian 3012675Sjulian#define CDEV_MAJOR 26 3147625Sphkstatic struct cdevsw spkr_cdevsw = { 3247625Sphk /* open */ spkropen, 3347625Sphk /* close */ spkrclose, 3447625Sphk /* read */ noread, 3547625Sphk /* write */ spkrwrite, 3647625Sphk /* ioctl */ spkrioctl, 3747625Sphk /* poll */ nopoll, 3847625Sphk /* mmap */ nommap, 3947625Sphk /* strategy */ nostrategy, 4047625Sphk /* name */ "spkr", 4147625Sphk /* maj */ CDEV_MAJOR, 4247625Sphk /* dump */ nodump, 4347625Sphk /* psize */ nopsize, 4447625Sphk /* flags */ 0, 4547625Sphk /* bmaj */ -1 4647625Sphk}; 4712675Sjulian 4860038SphkMALLOC_DEFINE(M_SPKR, "spkr", "Speaker buffer"); 4960038Sphk 504Srgrimes/**************** MACHINE DEPENDENT PART STARTS HERE ************************* 514Srgrimes * 524Srgrimes * This section defines a function tone() which causes a tone of given 5319174Sbde * frequency and duration from the ISA console speaker. 544Srgrimes * Another function endtone() is defined to force sound off, and there is 554Srgrimes * also a rest() entry point to do pauses. 564Srgrimes * 574Srgrimes * Audible sound is generated using the Programmable Interval Timer (PIT) and 5819174Sbde * Programmable Peripheral Interface (PPI) attached to the ISA speaker. The 594Srgrimes * PPI controls whether sound is passed through at all; the PIT's channel 2 is 604Srgrimes * used to generate clicks (a square wave) of whatever frequency is desired. 614Srgrimes */ 624Srgrimes 634Srgrimes/* 6419174Sbde * PPI control values. 6519174Sbde * XXX should be in a header and used in clock.c. 664Srgrimes */ 674Srgrimes#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ 684Srgrimes 69766Sache#define SPKRPRI PSOCK 70766Sachestatic char endtone, endrest; 714Srgrimes 7212854Sbdestatic void tone __P((unsigned int thz, unsigned int ticks)); 7312854Sbdestatic void rest __P((int ticks)); 7412854Sbdestatic void playinit __P((void)); 7512854Sbdestatic void playtone __P((int pitch, int value, int sustain)); 7612854Sbdestatic int abs __P((int n)); 7712854Sbdestatic void playstring __P((char *cp, size_t slen)); 7812854Sbde 79766Sache/* emit tone of frequency thz for given number of ticks */ 8017232Sjoergstatic void 8117232Sjoergtone(thz, ticks) 8217232Sjoerg unsigned int thz, ticks; 834Srgrimes{ 848288Sdg unsigned int divisor; 851016Sache int sps; 864Srgrimes 878288Sdg if (thz <= 0) 888288Sdg return; 898288Sdg 9019174Sbde divisor = timer_freq / thz; 918288Sdg 924Srgrimes#ifdef DEBUG 93766Sache (void) printf("tone: thz=%d ticks=%d\n", thz, ticks); 944Srgrimes#endif /* DEBUG */ 954Srgrimes 964Srgrimes /* set timer to generate clicks at given frequency in Hertz */ 9717232Sjoerg sps = splclock(); 981393Ssos 9919174Sbde if (acquire_timer2(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT)) { 1001393Ssos /* enter list of waiting procs ??? */ 10117232Sjoerg splx(sps); 1021393Ssos return; 1031393Ssos } 10417232Sjoerg splx(sps); 10517232Sjoerg disable_intr(); 1061393Ssos outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */ 1071393Ssos outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */ 10817232Sjoerg enable_intr(); 1094Srgrimes 1104Srgrimes /* turn the speaker on */ 1111393Ssos outb(IO_PPI, inb(IO_PPI) | PPI_SPKR); 1124Srgrimes 1134Srgrimes /* 1144Srgrimes * Set timeout to endtone function, then give up the timeslice. 1154Srgrimes * This is so other processes can execute while the tone is being 1164Srgrimes * emitted. 1174Srgrimes */ 1186152Sache if (ticks > 0) 1196152Sache tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks); 1201393Ssos outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR); 12117232Sjoerg sps = splclock(); 1221393Ssos release_timer2(); 12317232Sjoerg splx(sps); 1244Srgrimes} 1254Srgrimes 1264Srgrimes/* rest for given number of ticks */ 12717232Sjoergstatic void 12817232Sjoergrest(ticks) 12917232Sjoerg int ticks; 1304Srgrimes{ 1314Srgrimes /* 1324Srgrimes * Set timeout to endrest function, then give up the timeslice. 1334Srgrimes * This is so other processes can execute while the rest is being 1344Srgrimes * waited out. 1354Srgrimes */ 1364Srgrimes#ifdef DEBUG 137738Sache (void) printf("rest: %d\n", ticks); 1384Srgrimes#endif /* DEBUG */ 1396152Sache if (ticks > 0) 1406152Sache tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks); 1414Srgrimes} 1424Srgrimes 1434Srgrimes/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 1444Srgrimes * 1454Srgrimes * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 146738Sache * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- 147738Sache * tracking facility are added. 1484Srgrimes * Requires tone(), rest(), and endtone(). String play is not interruptible 1494Srgrimes * except possibly at physical block boundaries. 1504Srgrimes */ 1514Srgrimes 1524Srgrimestypedef int bool; 1534Srgrimes#define TRUE 1 1544Srgrimes#define FALSE 0 1554Srgrimes 1564Srgrimes#define dtoi(c) ((c) - '0') 1574Srgrimes 1584Srgrimesstatic int octave; /* currently selected octave */ 1594Srgrimesstatic int whole; /* whole-note time at current tempo, in ticks */ 1604Srgrimesstatic int value; /* whole divisor for note time, quarter note = 1 */ 1614Srgrimesstatic int fill; /* controls spacing of notes */ 1624Srgrimesstatic bool octtrack; /* octave-tracking on? */ 1634Srgrimesstatic bool octprefix; /* override current octave-tracking state? */ 1644Srgrimes 1654Srgrimes/* 1664Srgrimes * Magic number avoidance... 1674Srgrimes */ 1684Srgrimes#define SECS_PER_MIN 60 /* seconds per minute */ 1694Srgrimes#define WHOLE_NOTE 4 /* quarter notes per whole note */ 1704Srgrimes#define MIN_VALUE 64 /* the most we can divide a note by */ 1714Srgrimes#define DFLT_VALUE 4 /* default value (quarter-note) */ 1724Srgrimes#define FILLTIME 8 /* for articulation, break note in parts */ 1734Srgrimes#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 1744Srgrimes#define NORMAL 7 /* 7/8ths of note interval is filled */ 1754Srgrimes#define LEGATO 8 /* all of note interval is filled */ 1764Srgrimes#define DFLT_OCTAVE 4 /* default octave */ 1774Srgrimes#define MIN_TEMPO 32 /* minimum tempo */ 1784Srgrimes#define DFLT_TEMPO 120 /* default tempo */ 1794Srgrimes#define MAX_TEMPO 255 /* max tempo */ 1804Srgrimes#define NUM_MULT 3 /* numerator of dot multiplier */ 1814Srgrimes#define DENOM_MULT 2 /* denominator of dot multiplier */ 1824Srgrimes 1834Srgrimes/* letter to half-tone: A B C D E F G */ 1844Srgrimesstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 1854Srgrimes 1864Srgrimes/* 1874Srgrimes * This is the American Standard A440 Equal-Tempered scale with frequencies 1884Srgrimes * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 1894Srgrimes * our octave 0 is standard octave 2. 1904Srgrimes */ 1914Srgrimes#define OCTAVE_NOTES 12 /* semitones per octave */ 1924Srgrimesstatic int pitchtab[] = 1934Srgrimes{ 1944Srgrimes/* C C# D D# E F F# G G# A A# B*/ 1954Srgrimes/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 1964Srgrimes/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 1974Srgrimes/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 1984Srgrimes/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1994Srgrimes/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 2004Srgrimes/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 2014Srgrimes/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 2024Srgrimes}; 2034Srgrimes 20417232Sjoergstatic void 20517232Sjoergplayinit() 2064Srgrimes{ 2074Srgrimes octave = DFLT_OCTAVE; 208766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 2094Srgrimes fill = NORMAL; 2104Srgrimes value = DFLT_VALUE; 2114Srgrimes octtrack = FALSE; 2124Srgrimes octprefix = TRUE; /* act as though there was an initial O(n) */ 2134Srgrimes} 2144Srgrimes 2154Srgrimes/* play tone of proper duration for current rhythm signature */ 21617232Sjoergstatic void 21717232Sjoergplaytone(pitch, value, sustain) 21817232Sjoerg int pitch, value, sustain; 2194Srgrimes{ 2204Srgrimes register int sound, silence, snum = 1, sdenom = 1; 2214Srgrimes 2224Srgrimes /* this weirdness avoids floating-point arithmetic */ 2234Srgrimes for (; sustain; sustain--) 2244Srgrimes { 225738Sache /* See the BUGS section in the man page for discussion */ 2264Srgrimes snum *= NUM_MULT; 2274Srgrimes sdenom *= DENOM_MULT; 2284Srgrimes } 2294Srgrimes 2308288Sdg if (value == 0 || sdenom == 0) 2318288Sdg return; 2328288Sdg 2334Srgrimes if (pitch == -1) 2341016Sache rest(whole * snum / (value * sdenom)); 2354Srgrimes else 2364Srgrimes { 2374Srgrimes sound = (whole * snum) / (value * sdenom) 2384Srgrimes - (whole * (FILLTIME - fill)) / (value * FILLTIME); 2394Srgrimes silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 2404Srgrimes 2414Srgrimes#ifdef DEBUG 242738Sache (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 2434Srgrimes pitch, sound, silence); 2444Srgrimes#endif /* DEBUG */ 2454Srgrimes 2461016Sache tone(pitchtab[pitch], sound); 2474Srgrimes if (fill != LEGATO) 2481016Sache rest(silence); 2494Srgrimes } 2504Srgrimes} 2514Srgrimes 25217232Sjoergstatic int 25317232Sjoergabs(n) 25417232Sjoerg int n; 2554Srgrimes{ 2564Srgrimes if (n < 0) 2574Srgrimes return(-n); 2584Srgrimes else 2594Srgrimes return(n); 2604Srgrimes} 2614Srgrimes 2624Srgrimes/* interpret and play an item from a notation string */ 26317232Sjoergstatic void 26417232Sjoergplaystring(cp, slen) 26517232Sjoerg char *cp; 26617232Sjoerg size_t slen; 2674Srgrimes{ 268738Sache int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 2694Srgrimes 2704Srgrimes#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 2714Srgrimes {v = v * 10 + (*++cp - '0'); slen--;} 2724Srgrimes for (; slen--; cp++) 2734Srgrimes { 2744Srgrimes int sustain, timeval, tempo; 2754Srgrimes register char c = toupper(*cp); 2764Srgrimes 2774Srgrimes#ifdef DEBUG 278738Sache (void) printf("playstring: %c (%x)\n", c, c); 2794Srgrimes#endif /* DEBUG */ 2804Srgrimes 2814Srgrimes switch (c) 2824Srgrimes { 2834Srgrimes case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 2844Srgrimes 2854Srgrimes /* compute pitch */ 2864Srgrimes pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 2874Srgrimes 2884Srgrimes /* this may be followed by an accidental sign */ 2894Srgrimes if (cp[1] == '#' || cp[1] == '+') 2904Srgrimes { 2914Srgrimes ++pitch; 2924Srgrimes ++cp; 2934Srgrimes slen--; 2944Srgrimes } 2954Srgrimes else if (cp[1] == '-') 2964Srgrimes { 2974Srgrimes --pitch; 2984Srgrimes ++cp; 2994Srgrimes slen--; 3004Srgrimes } 3014Srgrimes 3024Srgrimes /* 3034Srgrimes * If octave-tracking mode is on, and there has been no octave- 3044Srgrimes * setting prefix, find the version of the current letter note 3054Srgrimes * closest to the last regardless of octave. 3064Srgrimes */ 3074Srgrimes if (octtrack && !octprefix) 3084Srgrimes { 3094Srgrimes if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 3104Srgrimes { 3114Srgrimes ++octave; 3124Srgrimes pitch += OCTAVE_NOTES; 3134Srgrimes } 3144Srgrimes 3154Srgrimes if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 3164Srgrimes { 3174Srgrimes --octave; 3184Srgrimes pitch -= OCTAVE_NOTES; 3194Srgrimes } 3204Srgrimes } 3214Srgrimes octprefix = FALSE; 3224Srgrimes lastpitch = pitch; 3234Srgrimes 3244Srgrimes /* ...which may in turn be followed by an override time value */ 3254Srgrimes GETNUM(cp, timeval); 3264Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 3274Srgrimes timeval = value; 3284Srgrimes 3294Srgrimes /* ...and/or sustain dots */ 3304Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3314Srgrimes { 3324Srgrimes slen--; 3334Srgrimes sustain++; 3344Srgrimes } 3354Srgrimes 336738Sache /* ...and/or a slur mark */ 337738Sache oldfill = fill; 338738Sache if (cp[1] == '_') 339738Sache { 340738Sache fill = LEGATO; 341738Sache ++cp; 342738Sache slen--; 343738Sache } 344738Sache 3454Srgrimes /* time to emit the actual tone */ 3461016Sache playtone(pitch, timeval, sustain); 347738Sache 348738Sache fill = oldfill; 3494Srgrimes break; 3504Srgrimes 3514Srgrimes case 'O': 3524Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 3534Srgrimes { 3544Srgrimes octprefix = octtrack = FALSE; 3554Srgrimes ++cp; 3564Srgrimes slen--; 3574Srgrimes } 3584Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 3594Srgrimes { 3604Srgrimes octtrack = TRUE; 3614Srgrimes ++cp; 3624Srgrimes slen--; 3634Srgrimes } 3644Srgrimes else 3654Srgrimes { 3664Srgrimes GETNUM(cp, octave); 3673593Sache if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES) 3684Srgrimes octave = DFLT_OCTAVE; 3694Srgrimes octprefix = TRUE; 3704Srgrimes } 3714Srgrimes break; 3724Srgrimes 3734Srgrimes case '>': 3743593Sache if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1) 3754Srgrimes octave++; 3764Srgrimes octprefix = TRUE; 3774Srgrimes break; 3784Srgrimes 3794Srgrimes case '<': 3804Srgrimes if (octave > 0) 3814Srgrimes octave--; 3824Srgrimes octprefix = TRUE; 3834Srgrimes break; 3844Srgrimes 3854Srgrimes case 'N': 3864Srgrimes GETNUM(cp, pitch); 3874Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3884Srgrimes { 3894Srgrimes slen--; 3904Srgrimes sustain++; 3914Srgrimes } 392738Sache oldfill = fill; 393738Sache if (cp[1] == '_') 394738Sache { 395738Sache fill = LEGATO; 396738Sache ++cp; 397738Sache slen--; 398738Sache } 3991016Sache playtone(pitch - 1, value, sustain); 400738Sache fill = oldfill; 4014Srgrimes break; 4024Srgrimes 4034Srgrimes case 'L': 4044Srgrimes GETNUM(cp, value); 4054Srgrimes if (value <= 0 || value > MIN_VALUE) 4064Srgrimes value = DFLT_VALUE; 4074Srgrimes break; 4084Srgrimes 4094Srgrimes case 'P': 4104Srgrimes case '~': 4114Srgrimes /* this may be followed by an override time value */ 4124Srgrimes GETNUM(cp, timeval); 4134Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 4144Srgrimes timeval = value; 4154Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 4164Srgrimes { 4174Srgrimes slen--; 4184Srgrimes sustain++; 4194Srgrimes } 4201016Sache playtone(-1, timeval, sustain); 4214Srgrimes break; 4224Srgrimes 4234Srgrimes case 'T': 4244Srgrimes GETNUM(cp, tempo); 4254Srgrimes if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 4264Srgrimes tempo = DFLT_TEMPO; 427766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; 4284Srgrimes break; 4294Srgrimes 4304Srgrimes case 'M': 4314Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 4324Srgrimes { 4334Srgrimes fill = NORMAL; 4344Srgrimes ++cp; 4354Srgrimes slen--; 4364Srgrimes } 4374Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 4384Srgrimes { 4394Srgrimes fill = LEGATO; 4404Srgrimes ++cp; 4414Srgrimes slen--; 4424Srgrimes } 4434Srgrimes else if (cp[1] == 'S' || cp[1] == 's') 4444Srgrimes { 4454Srgrimes fill = STACCATO; 4464Srgrimes ++cp; 4474Srgrimes slen--; 4484Srgrimes } 4494Srgrimes break; 4504Srgrimes } 4514Srgrimes } 4524Srgrimes} 4534Srgrimes 4544Srgrimes/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 4554Srgrimes * 4564Srgrimes * This section implements driver hooks to run playstring() and the tone(), 4574Srgrimes * endtone(), and rest() functions defined above. 4584Srgrimes */ 4594Srgrimes 460738Sachestatic int spkr_active = FALSE; /* exclusion flag */ 46160038Sphkstatic char *spkr_inbuf; /* incoming buf */ 4624Srgrimes 46317232Sjoergint 46417232Sjoergspkropen(dev, flags, fmt, p) 46517232Sjoerg dev_t dev; 46617232Sjoerg int flags; 46717232Sjoerg int fmt; 46817232Sjoerg struct proc *p; 4694Srgrimes{ 4704Srgrimes#ifdef DEBUG 47149982Sbillf (void) printf("spkropen: entering with dev = %s\n", devtoname(dev)); 4724Srgrimes#endif /* DEBUG */ 4734Srgrimes 4744Srgrimes if (minor(dev) != 0) 4754Srgrimes return(ENXIO); 4764Srgrimes else if (spkr_active) 4774Srgrimes return(EBUSY); 4784Srgrimes else 4794Srgrimes { 480738Sache#ifdef DEBUG 481738Sache (void) printf("spkropen: about to perform play initialization\n"); 482738Sache#endif /* DEBUG */ 4834Srgrimes playinit(); 48460038Sphk spkr_inbuf = malloc(DEV_BSIZE, M_SPKR, M_WAITOK); 485738Sache spkr_active = TRUE; 486738Sache return(0); 4874Srgrimes } 4884Srgrimes} 4894Srgrimes 49017232Sjoergint 49117232Sjoergspkrwrite(dev, uio, ioflag) 49217232Sjoerg dev_t dev; 49317232Sjoerg struct uio *uio; 49417232Sjoerg int ioflag; 4954Srgrimes{ 4964Srgrimes#ifdef DEBUG 49749982Sbillf printf("spkrwrite: entering with dev = %s, count = %d\n", 49849982Sbillf devtoname(dev), uio->uio_resid); 4994Srgrimes#endif /* DEBUG */ 5004Srgrimes 5014Srgrimes if (minor(dev) != 0) 5024Srgrimes return(ENXIO); 50317803Speter else if (uio->uio_resid > (DEV_BSIZE - 1)) /* prevent system crashes */ 504738Sache return(E2BIG); 5054Srgrimes else 5064Srgrimes { 507738Sache unsigned n; 508738Sache char *cp; 509738Sache int error; 510738Sache 511738Sache n = uio->uio_resid; 51260038Sphk cp = spkr_inbuf; 51317803Speter error = uiomove(cp, n, uio); 51417803Speter if (!error) { 51517803Speter cp[n] = '\0'; 5161016Sache playstring(cp, n); 51717803Speter } 5184Srgrimes return(error); 5194Srgrimes } 5204Srgrimes} 5214Srgrimes 52217232Sjoergint 52317232Sjoergspkrclose(dev, flags, fmt, p) 52417232Sjoerg dev_t dev; 52517232Sjoerg int flags; 52617232Sjoerg int fmt; 52717232Sjoerg struct proc *p; 5284Srgrimes{ 5294Srgrimes#ifdef DEBUG 53049982Sbillf (void) printf("spkrclose: entering with dev = %s\n", devtoname(dev)); 5314Srgrimes#endif /* DEBUG */ 5324Srgrimes 5334Srgrimes if (minor(dev) != 0) 5344Srgrimes return(ENXIO); 5354Srgrimes else 5364Srgrimes { 537766Sache wakeup((caddr_t)&endtone); 538766Sache wakeup((caddr_t)&endrest); 53960038Sphk free(spkr_inbuf, M_SPKR); 540738Sache spkr_active = FALSE; 541738Sache return(0); 5424Srgrimes } 5434Srgrimes} 5444Srgrimes 54517232Sjoergint 54617232Sjoergspkrioctl(dev, cmd, cmdarg, flags, p) 54717232Sjoerg dev_t dev; 54838505Sbde unsigned long cmd; 54917232Sjoerg caddr_t cmdarg; 55017232Sjoerg int flags; 55117232Sjoerg struct proc *p; 5524Srgrimes{ 5534Srgrimes#ifdef DEBUG 55450253Sbde (void) printf("spkrioctl: entering with dev = %s, cmd = %lx\n", 55550253Sbde devtoname(dev), cmd); 5564Srgrimes#endif /* DEBUG */ 5574Srgrimes 5584Srgrimes if (minor(dev) != 0) 5594Srgrimes return(ENXIO); 5604Srgrimes else if (cmd == SPKRTONE) 5614Srgrimes { 5624Srgrimes tone_t *tp = (tone_t *)cmdarg; 5634Srgrimes 5644Srgrimes if (tp->frequency == 0) 5651016Sache rest(tp->duration); 5664Srgrimes else 5671016Sache tone(tp->frequency, tp->duration); 5681016Sache return 0; 5694Srgrimes } 5704Srgrimes else if (cmd == SPKRTUNE) 5714Srgrimes { 5724Srgrimes tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 5734Srgrimes tone_t ttp; 5744Srgrimes int error; 5754Srgrimes 5764Srgrimes for (; ; tp++) { 5774Srgrimes error = copyin(tp, &ttp, sizeof(tone_t)); 5784Srgrimes if (error) 5794Srgrimes return(error); 5804Srgrimes if (ttp.duration == 0) 5814Srgrimes break; 5824Srgrimes if (ttp.frequency == 0) 5831016Sache rest(ttp.duration); 5844Srgrimes else 5851016Sache tone(ttp.frequency, ttp.duration); 5864Srgrimes } 587738Sache return(0); 5884Srgrimes } 589738Sache return(EINVAL); 5904Srgrimes} 5914Srgrimes 59217232Sjoergstatic void 59317232Sjoergspkr_drvinit(void *unused) 59412502Sjulian{ 59550254Sphk make_dev(&spkr_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "speaker"); 59612502Sjulian} 59712517Sjulian 59812517SjulianSYSINIT(spkrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,spkr_drvinit,NULL) 59912517Sjulian 60061994Smsmith/* 60161994Smsmith * Install placeholder to claim the resources owned by the 60261994Smsmith * AT tone generator. 60361994Smsmith */ 60461994Smsmithstatic struct isa_pnp_id atspeaker_ids[] = { 60561994Smsmith { 0x0008d041 /* PNP0800 */, "AT speaker" }, 60661994Smsmith { 0 } 60761994Smsmith}; 60812517Sjulian 60961994Smsmithstatic int 61061994Smsmithatspeaker_probe(device_t dev) 61161994Smsmith{ 61261994Smsmith return(ISA_PNP_PROBE(device_get_parent(dev), dev, atspeaker_ids)); 61361994Smsmith} 61461994Smsmith 61561994Smsmithstatic int 61661994Smsmithatspeaker_attach(device_t dev) 61761994Smsmith{ 61861994Smsmith return(0); 61961994Smsmith} 62061994Smsmith 62161994Smsmithstatic device_method_t atspeaker_methods[] = { 62261994Smsmith /* Device interface */ 62361994Smsmith DEVMETHOD(device_probe, atspeaker_probe), 62461994Smsmith DEVMETHOD(device_attach, atspeaker_attach), 62561994Smsmith DEVMETHOD(device_detach, bus_generic_detach), 62661994Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 62761994Smsmith DEVMETHOD(device_suspend, bus_generic_suspend), 62861994Smsmith DEVMETHOD(device_resume, bus_generic_resume), 62961994Smsmith { 0, 0 } 63061994Smsmith}; 63161994Smsmith 63261994Smsmithstatic driver_t atspeaker_driver = { 63361994Smsmith "atspeaker", 63461994Smsmith atspeaker_methods, 63561994Smsmith 1, /* no softc */ 63661994Smsmith}; 63761994Smsmith 63861994Smsmithstatic devclass_t atspeaker_devclass; 63961994Smsmith 64061994SmsmithDRIVER_MODULE(atspeaker, isa, atspeaker_driver, atspeaker_devclass, 0, 0); 64161994Smsmith 6424Srgrimes/* spkr.c ends here */ 643