spkr.c revision 83366
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 83366 2001-09-12 08:38:13Z julian $ 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}; 4612675Sjulian 4769774Sphkstatic MALLOC_DEFINE(M_SPKR, "spkr", "Speaker buffer"); 4860038Sphk 494Srgrimes/**************** MACHINE DEPENDENT PART STARTS HERE ************************* 504Srgrimes * 514Srgrimes * This section defines a function tone() which causes a tone of given 5219174Sbde * frequency and duration from the ISA console speaker. 534Srgrimes * Another function endtone() is defined to force sound off, and there is 544Srgrimes * also a rest() entry point to do pauses. 554Srgrimes * 564Srgrimes * Audible sound is generated using the Programmable Interval Timer (PIT) and 5719174Sbde * Programmable Peripheral Interface (PPI) attached to the ISA speaker. The 584Srgrimes * PPI controls whether sound is passed through at all; the PIT's channel 2 is 594Srgrimes * used to generate clicks (a square wave) of whatever frequency is desired. 604Srgrimes */ 614Srgrimes 624Srgrimes/* 6319174Sbde * PPI control values. 6419174Sbde * XXX should be in a header and used in clock.c. 654Srgrimes */ 664Srgrimes#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ 674Srgrimes 68766Sache#define SPKRPRI PSOCK 69766Sachestatic char endtone, endrest; 704Srgrimes 7112854Sbdestatic void tone __P((unsigned int thz, unsigned int ticks)); 7212854Sbdestatic void rest __P((int ticks)); 7312854Sbdestatic void playinit __P((void)); 7412854Sbdestatic void playtone __P((int pitch, int value, int sustain)); 7512854Sbdestatic int abs __P((int n)); 7612854Sbdestatic void playstring __P((char *cp, size_t slen)); 7712854Sbde 78766Sache/* emit tone of frequency thz for given number of ticks */ 7917232Sjoergstatic void 8017232Sjoergtone(thz, ticks) 8117232Sjoerg unsigned int thz, ticks; 824Srgrimes{ 838288Sdg unsigned int divisor; 841016Sache int sps; 854Srgrimes 868288Sdg if (thz <= 0) 878288Sdg return; 888288Sdg 8919174Sbde divisor = timer_freq / thz; 908288Sdg 914Srgrimes#ifdef DEBUG 92766Sache (void) printf("tone: thz=%d ticks=%d\n", thz, ticks); 934Srgrimes#endif /* DEBUG */ 944Srgrimes 954Srgrimes /* set timer to generate clicks at given frequency in Hertz */ 9617232Sjoerg sps = splclock(); 971393Ssos 9819174Sbde if (acquire_timer2(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT)) { 991393Ssos /* enter list of waiting procs ??? */ 10017232Sjoerg splx(sps); 1011393Ssos return; 1021393Ssos } 10317232Sjoerg splx(sps); 10417232Sjoerg disable_intr(); 1051393Ssos outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */ 1061393Ssos outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */ 10717232Sjoerg enable_intr(); 1084Srgrimes 1094Srgrimes /* turn the speaker on */ 1101393Ssos outb(IO_PPI, inb(IO_PPI) | PPI_SPKR); 1114Srgrimes 1124Srgrimes /* 1134Srgrimes * Set timeout to endtone function, then give up the timeslice. 1144Srgrimes * This is so other processes can execute while the tone is being 1154Srgrimes * emitted. 1164Srgrimes */ 1176152Sache if (ticks > 0) 1186152Sache tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks); 1191393Ssos outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR); 12017232Sjoerg sps = splclock(); 1211393Ssos release_timer2(); 12217232Sjoerg splx(sps); 1234Srgrimes} 1244Srgrimes 1254Srgrimes/* rest for given number of ticks */ 12617232Sjoergstatic void 12717232Sjoergrest(ticks) 12817232Sjoerg int ticks; 1294Srgrimes{ 1304Srgrimes /* 1314Srgrimes * Set timeout to endrest function, then give up the timeslice. 1324Srgrimes * This is so other processes can execute while the rest is being 1334Srgrimes * waited out. 1344Srgrimes */ 1354Srgrimes#ifdef DEBUG 136738Sache (void) printf("rest: %d\n", ticks); 1374Srgrimes#endif /* DEBUG */ 1386152Sache if (ticks > 0) 1396152Sache tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks); 1404Srgrimes} 1414Srgrimes 1424Srgrimes/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 1434Srgrimes * 1444Srgrimes * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 145738Sache * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- 146738Sache * tracking facility are added. 1474Srgrimes * Requires tone(), rest(), and endtone(). String play is not interruptible 1484Srgrimes * except possibly at physical block boundaries. 1494Srgrimes */ 1504Srgrimes 1514Srgrimestypedef int bool; 1524Srgrimes#define TRUE 1 1534Srgrimes#define FALSE 0 1544Srgrimes 1554Srgrimes#define dtoi(c) ((c) - '0') 1564Srgrimes 1574Srgrimesstatic int octave; /* currently selected octave */ 1584Srgrimesstatic int whole; /* whole-note time at current tempo, in ticks */ 1594Srgrimesstatic int value; /* whole divisor for note time, quarter note = 1 */ 1604Srgrimesstatic int fill; /* controls spacing of notes */ 1614Srgrimesstatic bool octtrack; /* octave-tracking on? */ 1624Srgrimesstatic bool octprefix; /* override current octave-tracking state? */ 1634Srgrimes 1644Srgrimes/* 1654Srgrimes * Magic number avoidance... 1664Srgrimes */ 1674Srgrimes#define SECS_PER_MIN 60 /* seconds per minute */ 1684Srgrimes#define WHOLE_NOTE 4 /* quarter notes per whole note */ 1694Srgrimes#define MIN_VALUE 64 /* the most we can divide a note by */ 1704Srgrimes#define DFLT_VALUE 4 /* default value (quarter-note) */ 1714Srgrimes#define FILLTIME 8 /* for articulation, break note in parts */ 1724Srgrimes#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 1734Srgrimes#define NORMAL 7 /* 7/8ths of note interval is filled */ 1744Srgrimes#define LEGATO 8 /* all of note interval is filled */ 1754Srgrimes#define DFLT_OCTAVE 4 /* default octave */ 1764Srgrimes#define MIN_TEMPO 32 /* minimum tempo */ 1774Srgrimes#define DFLT_TEMPO 120 /* default tempo */ 1784Srgrimes#define MAX_TEMPO 255 /* max tempo */ 1794Srgrimes#define NUM_MULT 3 /* numerator of dot multiplier */ 1804Srgrimes#define DENOM_MULT 2 /* denominator of dot multiplier */ 1814Srgrimes 1824Srgrimes/* letter to half-tone: A B C D E F G */ 1834Srgrimesstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 1844Srgrimes 1854Srgrimes/* 1864Srgrimes * This is the American Standard A440 Equal-Tempered scale with frequencies 1874Srgrimes * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 1884Srgrimes * our octave 0 is standard octave 2. 1894Srgrimes */ 1904Srgrimes#define OCTAVE_NOTES 12 /* semitones per octave */ 1914Srgrimesstatic int pitchtab[] = 1924Srgrimes{ 1934Srgrimes/* C C# D D# E F F# G G# A A# B*/ 1944Srgrimes/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 1954Srgrimes/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 1964Srgrimes/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 1974Srgrimes/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1984Srgrimes/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 1994Srgrimes/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 2004Srgrimes/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 2014Srgrimes}; 2024Srgrimes 20317232Sjoergstatic void 20417232Sjoergplayinit() 2054Srgrimes{ 2064Srgrimes octave = DFLT_OCTAVE; 207766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 2084Srgrimes fill = NORMAL; 2094Srgrimes value = DFLT_VALUE; 2104Srgrimes octtrack = FALSE; 2114Srgrimes octprefix = TRUE; /* act as though there was an initial O(n) */ 2124Srgrimes} 2134Srgrimes 2144Srgrimes/* play tone of proper duration for current rhythm signature */ 21517232Sjoergstatic void 21617232Sjoergplaytone(pitch, value, sustain) 21717232Sjoerg int pitch, value, sustain; 2184Srgrimes{ 2194Srgrimes register int sound, silence, snum = 1, sdenom = 1; 2204Srgrimes 2214Srgrimes /* this weirdness avoids floating-point arithmetic */ 2224Srgrimes for (; sustain; sustain--) 2234Srgrimes { 224738Sache /* See the BUGS section in the man page for discussion */ 2254Srgrimes snum *= NUM_MULT; 2264Srgrimes sdenom *= DENOM_MULT; 2274Srgrimes } 2284Srgrimes 2298288Sdg if (value == 0 || sdenom == 0) 2308288Sdg return; 2318288Sdg 2324Srgrimes if (pitch == -1) 2331016Sache rest(whole * snum / (value * sdenom)); 2344Srgrimes else 2354Srgrimes { 2364Srgrimes sound = (whole * snum) / (value * sdenom) 2374Srgrimes - (whole * (FILLTIME - fill)) / (value * FILLTIME); 2384Srgrimes silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 2394Srgrimes 2404Srgrimes#ifdef DEBUG 241738Sache (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 2424Srgrimes pitch, sound, silence); 2434Srgrimes#endif /* DEBUG */ 2444Srgrimes 2451016Sache tone(pitchtab[pitch], sound); 2464Srgrimes if (fill != LEGATO) 2471016Sache rest(silence); 2484Srgrimes } 2494Srgrimes} 2504Srgrimes 25117232Sjoergstatic int 25217232Sjoergabs(n) 25317232Sjoerg int n; 2544Srgrimes{ 2554Srgrimes if (n < 0) 2564Srgrimes return(-n); 2574Srgrimes else 2584Srgrimes return(n); 2594Srgrimes} 2604Srgrimes 2614Srgrimes/* interpret and play an item from a notation string */ 26217232Sjoergstatic void 26317232Sjoergplaystring(cp, slen) 26417232Sjoerg char *cp; 26517232Sjoerg size_t slen; 2664Srgrimes{ 267738Sache int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 2684Srgrimes 2694Srgrimes#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 2704Srgrimes {v = v * 10 + (*++cp - '0'); slen--;} 2714Srgrimes for (; slen--; cp++) 2724Srgrimes { 2734Srgrimes int sustain, timeval, tempo; 2744Srgrimes register char c = toupper(*cp); 2754Srgrimes 2764Srgrimes#ifdef DEBUG 277738Sache (void) printf("playstring: %c (%x)\n", c, c); 2784Srgrimes#endif /* DEBUG */ 2794Srgrimes 2804Srgrimes switch (c) 2814Srgrimes { 2824Srgrimes case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 2834Srgrimes 2844Srgrimes /* compute pitch */ 2854Srgrimes pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 2864Srgrimes 2874Srgrimes /* this may be followed by an accidental sign */ 2884Srgrimes if (cp[1] == '#' || cp[1] == '+') 2894Srgrimes { 2904Srgrimes ++pitch; 2914Srgrimes ++cp; 2924Srgrimes slen--; 2934Srgrimes } 2944Srgrimes else if (cp[1] == '-') 2954Srgrimes { 2964Srgrimes --pitch; 2974Srgrimes ++cp; 2984Srgrimes slen--; 2994Srgrimes } 3004Srgrimes 3014Srgrimes /* 3024Srgrimes * If octave-tracking mode is on, and there has been no octave- 3034Srgrimes * setting prefix, find the version of the current letter note 3044Srgrimes * closest to the last regardless of octave. 3054Srgrimes */ 3064Srgrimes if (octtrack && !octprefix) 3074Srgrimes { 3084Srgrimes if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 3094Srgrimes { 3104Srgrimes ++octave; 3114Srgrimes pitch += OCTAVE_NOTES; 3124Srgrimes } 3134Srgrimes 3144Srgrimes if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 3154Srgrimes { 3164Srgrimes --octave; 3174Srgrimes pitch -= OCTAVE_NOTES; 3184Srgrimes } 3194Srgrimes } 3204Srgrimes octprefix = FALSE; 3214Srgrimes lastpitch = pitch; 3224Srgrimes 3234Srgrimes /* ...which may in turn be followed by an override time value */ 3244Srgrimes GETNUM(cp, timeval); 3254Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 3264Srgrimes timeval = value; 3274Srgrimes 3284Srgrimes /* ...and/or sustain dots */ 3294Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3304Srgrimes { 3314Srgrimes slen--; 3324Srgrimes sustain++; 3334Srgrimes } 3344Srgrimes 335738Sache /* ...and/or a slur mark */ 336738Sache oldfill = fill; 337738Sache if (cp[1] == '_') 338738Sache { 339738Sache fill = LEGATO; 340738Sache ++cp; 341738Sache slen--; 342738Sache } 343738Sache 3444Srgrimes /* time to emit the actual tone */ 3451016Sache playtone(pitch, timeval, sustain); 346738Sache 347738Sache fill = oldfill; 3484Srgrimes break; 3494Srgrimes 3504Srgrimes case 'O': 3514Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 3524Srgrimes { 3534Srgrimes octprefix = octtrack = FALSE; 3544Srgrimes ++cp; 3554Srgrimes slen--; 3564Srgrimes } 3574Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 3584Srgrimes { 3594Srgrimes octtrack = TRUE; 3604Srgrimes ++cp; 3614Srgrimes slen--; 3624Srgrimes } 3634Srgrimes else 3644Srgrimes { 3654Srgrimes GETNUM(cp, octave); 3663593Sache if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES) 3674Srgrimes octave = DFLT_OCTAVE; 3684Srgrimes octprefix = TRUE; 3694Srgrimes } 3704Srgrimes break; 3714Srgrimes 3724Srgrimes case '>': 3733593Sache if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1) 3744Srgrimes octave++; 3754Srgrimes octprefix = TRUE; 3764Srgrimes break; 3774Srgrimes 3784Srgrimes case '<': 3794Srgrimes if (octave > 0) 3804Srgrimes octave--; 3814Srgrimes octprefix = TRUE; 3824Srgrimes break; 3834Srgrimes 3844Srgrimes case 'N': 3854Srgrimes GETNUM(cp, pitch); 3864Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3874Srgrimes { 3884Srgrimes slen--; 3894Srgrimes sustain++; 3904Srgrimes } 391738Sache oldfill = fill; 392738Sache if (cp[1] == '_') 393738Sache { 394738Sache fill = LEGATO; 395738Sache ++cp; 396738Sache slen--; 397738Sache } 3981016Sache playtone(pitch - 1, value, sustain); 399738Sache fill = oldfill; 4004Srgrimes break; 4014Srgrimes 4024Srgrimes case 'L': 4034Srgrimes GETNUM(cp, value); 4044Srgrimes if (value <= 0 || value > MIN_VALUE) 4054Srgrimes value = DFLT_VALUE; 4064Srgrimes break; 4074Srgrimes 4084Srgrimes case 'P': 4094Srgrimes case '~': 4104Srgrimes /* this may be followed by an override time value */ 4114Srgrimes GETNUM(cp, timeval); 4124Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 4134Srgrimes timeval = value; 4144Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 4154Srgrimes { 4164Srgrimes slen--; 4174Srgrimes sustain++; 4184Srgrimes } 4191016Sache playtone(-1, timeval, sustain); 4204Srgrimes break; 4214Srgrimes 4224Srgrimes case 'T': 4234Srgrimes GETNUM(cp, tempo); 4244Srgrimes if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 4254Srgrimes tempo = DFLT_TEMPO; 426766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; 4274Srgrimes break; 4284Srgrimes 4294Srgrimes case 'M': 4304Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 4314Srgrimes { 4324Srgrimes fill = NORMAL; 4334Srgrimes ++cp; 4344Srgrimes slen--; 4354Srgrimes } 4364Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 4374Srgrimes { 4384Srgrimes fill = LEGATO; 4394Srgrimes ++cp; 4404Srgrimes slen--; 4414Srgrimes } 4424Srgrimes else if (cp[1] == 'S' || cp[1] == 's') 4434Srgrimes { 4444Srgrimes fill = STACCATO; 4454Srgrimes ++cp; 4464Srgrimes slen--; 4474Srgrimes } 4484Srgrimes break; 4494Srgrimes } 4504Srgrimes } 4514Srgrimes} 4524Srgrimes 4534Srgrimes/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 4544Srgrimes * 4554Srgrimes * This section implements driver hooks to run playstring() and the tone(), 4564Srgrimes * endtone(), and rest() functions defined above. 4574Srgrimes */ 4584Srgrimes 459738Sachestatic int spkr_active = FALSE; /* exclusion flag */ 46060038Sphkstatic char *spkr_inbuf; /* incoming buf */ 4614Srgrimes 46217232Sjoergint 46383366Sjulianspkropen(dev, flags, fmt, td) 46417232Sjoerg dev_t dev; 46517232Sjoerg int flags; 46617232Sjoerg int fmt; 46783366Sjulian struct thread *td; 4684Srgrimes{ 4694Srgrimes#ifdef DEBUG 47049982Sbillf (void) printf("spkropen: entering with dev = %s\n", devtoname(dev)); 4714Srgrimes#endif /* DEBUG */ 4724Srgrimes 4734Srgrimes if (minor(dev) != 0) 4744Srgrimes return(ENXIO); 4754Srgrimes else if (spkr_active) 4764Srgrimes return(EBUSY); 4774Srgrimes else 4784Srgrimes { 479738Sache#ifdef DEBUG 480738Sache (void) printf("spkropen: about to perform play initialization\n"); 481738Sache#endif /* DEBUG */ 4824Srgrimes playinit(); 48360038Sphk spkr_inbuf = malloc(DEV_BSIZE, M_SPKR, M_WAITOK); 484738Sache spkr_active = TRUE; 485738Sache return(0); 4864Srgrimes } 4874Srgrimes} 4884Srgrimes 48917232Sjoergint 49017232Sjoergspkrwrite(dev, uio, ioflag) 49117232Sjoerg dev_t dev; 49217232Sjoerg struct uio *uio; 49317232Sjoerg int ioflag; 4944Srgrimes{ 4954Srgrimes#ifdef DEBUG 49649982Sbillf printf("spkrwrite: entering with dev = %s, count = %d\n", 49749982Sbillf devtoname(dev), uio->uio_resid); 4984Srgrimes#endif /* DEBUG */ 4994Srgrimes 5004Srgrimes if (minor(dev) != 0) 5014Srgrimes return(ENXIO); 50217803Speter else if (uio->uio_resid > (DEV_BSIZE - 1)) /* prevent system crashes */ 503738Sache return(E2BIG); 5044Srgrimes else 5054Srgrimes { 506738Sache unsigned n; 507738Sache char *cp; 508738Sache int error; 509738Sache 510738Sache n = uio->uio_resid; 51160038Sphk cp = spkr_inbuf; 51217803Speter error = uiomove(cp, n, uio); 51317803Speter if (!error) { 51417803Speter cp[n] = '\0'; 5151016Sache playstring(cp, n); 51617803Speter } 5174Srgrimes return(error); 5184Srgrimes } 5194Srgrimes} 5204Srgrimes 52117232Sjoergint 52283366Sjulianspkrclose(dev, flags, fmt, td) 52317232Sjoerg dev_t dev; 52417232Sjoerg int flags; 52517232Sjoerg int fmt; 52683366Sjulian struct thread *td; 5274Srgrimes{ 5284Srgrimes#ifdef DEBUG 52949982Sbillf (void) printf("spkrclose: entering with dev = %s\n", devtoname(dev)); 5304Srgrimes#endif /* DEBUG */ 5314Srgrimes 5324Srgrimes if (minor(dev) != 0) 5334Srgrimes return(ENXIO); 5344Srgrimes else 5354Srgrimes { 536766Sache wakeup((caddr_t)&endtone); 537766Sache wakeup((caddr_t)&endrest); 53860038Sphk free(spkr_inbuf, M_SPKR); 539738Sache spkr_active = FALSE; 540738Sache return(0); 5414Srgrimes } 5424Srgrimes} 5434Srgrimes 54417232Sjoergint 54583366Sjulianspkrioctl(dev, cmd, cmdarg, flags, td) 54617232Sjoerg dev_t dev; 54738505Sbde unsigned long cmd; 54817232Sjoerg caddr_t cmdarg; 54917232Sjoerg int flags; 55083366Sjulian struct thread *td; 5514Srgrimes{ 5524Srgrimes#ifdef DEBUG 55350253Sbde (void) printf("spkrioctl: entering with dev = %s, cmd = %lx\n", 55450253Sbde devtoname(dev), cmd); 5554Srgrimes#endif /* DEBUG */ 5564Srgrimes 5574Srgrimes if (minor(dev) != 0) 5584Srgrimes return(ENXIO); 5594Srgrimes else if (cmd == SPKRTONE) 5604Srgrimes { 5614Srgrimes tone_t *tp = (tone_t *)cmdarg; 5624Srgrimes 5634Srgrimes if (tp->frequency == 0) 5641016Sache rest(tp->duration); 5654Srgrimes else 5661016Sache tone(tp->frequency, tp->duration); 5671016Sache return 0; 5684Srgrimes } 5694Srgrimes else if (cmd == SPKRTUNE) 5704Srgrimes { 5714Srgrimes tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 5724Srgrimes tone_t ttp; 5734Srgrimes int error; 5744Srgrimes 5754Srgrimes for (; ; tp++) { 5764Srgrimes error = copyin(tp, &ttp, sizeof(tone_t)); 5774Srgrimes if (error) 5784Srgrimes return(error); 5794Srgrimes if (ttp.duration == 0) 5804Srgrimes break; 5814Srgrimes if (ttp.frequency == 0) 5821016Sache rest(ttp.duration); 5834Srgrimes else 5841016Sache tone(ttp.frequency, ttp.duration); 5854Srgrimes } 586738Sache return(0); 5874Srgrimes } 588738Sache return(EINVAL); 5894Srgrimes} 5904Srgrimes 59117232Sjoergstatic void 59217232Sjoergspkr_drvinit(void *unused) 59312502Sjulian{ 59450254Sphk make_dev(&spkr_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "speaker"); 59512502Sjulian} 59612517Sjulian 59712517SjulianSYSINIT(spkrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,spkr_drvinit,NULL) 59812517Sjulian 59961994Smsmith/* 60061994Smsmith * Install placeholder to claim the resources owned by the 60161994Smsmith * AT tone generator. 60261994Smsmith */ 60361994Smsmithstatic struct isa_pnp_id atspeaker_ids[] = { 60461994Smsmith { 0x0008d041 /* PNP0800 */, "AT speaker" }, 60561994Smsmith { 0 } 60661994Smsmith}; 60712517Sjulian 60861994Smsmithstatic int 60961994Smsmithatspeaker_probe(device_t dev) 61061994Smsmith{ 61161994Smsmith return(ISA_PNP_PROBE(device_get_parent(dev), dev, atspeaker_ids)); 61261994Smsmith} 61361994Smsmith 61461994Smsmithstatic int 61561994Smsmithatspeaker_attach(device_t dev) 61661994Smsmith{ 61761994Smsmith return(0); 61861994Smsmith} 61961994Smsmith 62061994Smsmithstatic device_method_t atspeaker_methods[] = { 62161994Smsmith /* Device interface */ 62261994Smsmith DEVMETHOD(device_probe, atspeaker_probe), 62361994Smsmith DEVMETHOD(device_attach, atspeaker_attach), 62461994Smsmith DEVMETHOD(device_detach, bus_generic_detach), 62561994Smsmith DEVMETHOD(device_shutdown, bus_generic_shutdown), 62661994Smsmith DEVMETHOD(device_suspend, bus_generic_suspend), 62761994Smsmith DEVMETHOD(device_resume, bus_generic_resume), 62861994Smsmith { 0, 0 } 62961994Smsmith}; 63061994Smsmith 63161994Smsmithstatic driver_t atspeaker_driver = { 63261994Smsmith "atspeaker", 63361994Smsmith atspeaker_methods, 63461994Smsmith 1, /* no softc */ 63561994Smsmith}; 63661994Smsmith 63761994Smsmithstatic devclass_t atspeaker_devclass; 63861994Smsmith 63961994SmsmithDRIVER_MODULE(atspeaker, isa, atspeaker_driver, atspeaker_devclass, 0, 0); 64082555SmsmithDRIVER_MODULE(atspeaker, acpi, atspeaker_driver, atspeaker_devclass, 0, 0); 64161994Smsmith 6424Srgrimes/* spkr.c ends here */ 643