spkr.c revision 17232
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 * 717232Sjoerg * $Id: spkr.c,v 1.24 1996/03/27 19:07:33 bde 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 91766Sache/* emit tone of frequency thz for given number of ticks */ 9217232Sjoergstatic void 9317232Sjoergtone(thz, ticks) 9417232Sjoerg unsigned int thz, ticks; 954Srgrimes{ 968288Sdg unsigned int divisor; 971016Sache int sps; 984Srgrimes 998288Sdg if (thz <= 0) 1008288Sdg return; 1018288Sdg 1028288Sdg divisor = TIMER_CLK / thz; 1038288Sdg 1044Srgrimes#ifdef DEBUG 105766Sache (void) printf("tone: thz=%d ticks=%d\n", thz, ticks); 1064Srgrimes#endif /* DEBUG */ 1074Srgrimes 1084Srgrimes /* set timer to generate clicks at given frequency in Hertz */ 10917232Sjoerg sps = splclock(); 1101393Ssos 1111393Ssos if (acquire_timer2(PIT_MODE)) { 1121393Ssos /* enter list of waiting procs ??? */ 11317232Sjoerg splx(sps); 1141393Ssos return; 1151393Ssos } 11617232Sjoerg splx(sps); 11717232Sjoerg disable_intr(); 1181393Ssos outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */ 1191393Ssos outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */ 12017232Sjoerg enable_intr(); 1214Srgrimes 1224Srgrimes /* turn the speaker on */ 1231393Ssos outb(IO_PPI, inb(IO_PPI) | PPI_SPKR); 1244Srgrimes 1254Srgrimes /* 1264Srgrimes * Set timeout to endtone function, then give up the timeslice. 1274Srgrimes * This is so other processes can execute while the tone is being 1284Srgrimes * emitted. 1294Srgrimes */ 1306152Sache if (ticks > 0) 1316152Sache tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks); 1321393Ssos outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR); 13317232Sjoerg sps = splclock(); 1341393Ssos release_timer2(); 13517232Sjoerg splx(sps); 1364Srgrimes} 1374Srgrimes 1384Srgrimes/* rest for given number of ticks */ 13917232Sjoergstatic void 14017232Sjoergrest(ticks) 14117232Sjoerg int ticks; 1424Srgrimes{ 1434Srgrimes /* 1444Srgrimes * Set timeout to endrest function, then give up the timeslice. 1454Srgrimes * This is so other processes can execute while the rest is being 1464Srgrimes * waited out. 1474Srgrimes */ 1484Srgrimes#ifdef DEBUG 149738Sache (void) printf("rest: %d\n", ticks); 1504Srgrimes#endif /* DEBUG */ 1516152Sache if (ticks > 0) 1526152Sache tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks); 1534Srgrimes} 1544Srgrimes 1554Srgrimes/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 1564Srgrimes * 1574Srgrimes * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 158738Sache * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- 159738Sache * tracking facility are added. 1604Srgrimes * Requires tone(), rest(), and endtone(). String play is not interruptible 1614Srgrimes * except possibly at physical block boundaries. 1624Srgrimes */ 1634Srgrimes 1644Srgrimestypedef int bool; 1654Srgrimes#define TRUE 1 1664Srgrimes#define FALSE 0 1674Srgrimes 1684Srgrimes#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) 1694Srgrimes#define isdigit(c) (((c) >= '0') && ((c) <= '9')) 1704Srgrimes#define dtoi(c) ((c) - '0') 1714Srgrimes 1724Srgrimesstatic int octave; /* currently selected octave */ 1734Srgrimesstatic int whole; /* whole-note time at current tempo, in ticks */ 1744Srgrimesstatic int value; /* whole divisor for note time, quarter note = 1 */ 1754Srgrimesstatic int fill; /* controls spacing of notes */ 1764Srgrimesstatic bool octtrack; /* octave-tracking on? */ 1774Srgrimesstatic bool octprefix; /* override current octave-tracking state? */ 1784Srgrimes 1794Srgrimes/* 1804Srgrimes * Magic number avoidance... 1814Srgrimes */ 1824Srgrimes#define SECS_PER_MIN 60 /* seconds per minute */ 1834Srgrimes#define WHOLE_NOTE 4 /* quarter notes per whole note */ 1844Srgrimes#define MIN_VALUE 64 /* the most we can divide a note by */ 1854Srgrimes#define DFLT_VALUE 4 /* default value (quarter-note) */ 1864Srgrimes#define FILLTIME 8 /* for articulation, break note in parts */ 1874Srgrimes#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 1884Srgrimes#define NORMAL 7 /* 7/8ths of note interval is filled */ 1894Srgrimes#define LEGATO 8 /* all of note interval is filled */ 1904Srgrimes#define DFLT_OCTAVE 4 /* default octave */ 1914Srgrimes#define MIN_TEMPO 32 /* minimum tempo */ 1924Srgrimes#define DFLT_TEMPO 120 /* default tempo */ 1934Srgrimes#define MAX_TEMPO 255 /* max tempo */ 1944Srgrimes#define NUM_MULT 3 /* numerator of dot multiplier */ 1954Srgrimes#define DENOM_MULT 2 /* denominator of dot multiplier */ 1964Srgrimes 1974Srgrimes/* letter to half-tone: A B C D E F G */ 1984Srgrimesstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 1994Srgrimes 2004Srgrimes/* 2014Srgrimes * This is the American Standard A440 Equal-Tempered scale with frequencies 2024Srgrimes * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 2034Srgrimes * our octave 0 is standard octave 2. 2044Srgrimes */ 2054Srgrimes#define OCTAVE_NOTES 12 /* semitones per octave */ 2064Srgrimesstatic int pitchtab[] = 2074Srgrimes{ 2084Srgrimes/* C C# D D# E F F# G G# A A# B*/ 2094Srgrimes/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 2104Srgrimes/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 2114Srgrimes/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 2124Srgrimes/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 2134Srgrimes/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 2144Srgrimes/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 2154Srgrimes/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 2164Srgrimes}; 2174Srgrimes 21817232Sjoergstatic void 21917232Sjoergplayinit() 2204Srgrimes{ 2214Srgrimes octave = DFLT_OCTAVE; 222766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 2234Srgrimes fill = NORMAL; 2244Srgrimes value = DFLT_VALUE; 2254Srgrimes octtrack = FALSE; 2264Srgrimes octprefix = TRUE; /* act as though there was an initial O(n) */ 2274Srgrimes} 2284Srgrimes 2294Srgrimes/* play tone of proper duration for current rhythm signature */ 23017232Sjoergstatic void 23117232Sjoergplaytone(pitch, value, sustain) 23217232Sjoerg int pitch, value, sustain; 2334Srgrimes{ 2344Srgrimes register int sound, silence, snum = 1, sdenom = 1; 2354Srgrimes 2364Srgrimes /* this weirdness avoids floating-point arithmetic */ 2374Srgrimes for (; sustain; sustain--) 2384Srgrimes { 239738Sache /* See the BUGS section in the man page for discussion */ 2404Srgrimes snum *= NUM_MULT; 2414Srgrimes sdenom *= DENOM_MULT; 2424Srgrimes } 2434Srgrimes 2448288Sdg if (value == 0 || sdenom == 0) 2458288Sdg return; 2468288Sdg 2474Srgrimes if (pitch == -1) 2481016Sache rest(whole * snum / (value * sdenom)); 2494Srgrimes else 2504Srgrimes { 2514Srgrimes sound = (whole * snum) / (value * sdenom) 2524Srgrimes - (whole * (FILLTIME - fill)) / (value * FILLTIME); 2534Srgrimes silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 2544Srgrimes 2554Srgrimes#ifdef DEBUG 256738Sache (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 2574Srgrimes pitch, sound, silence); 2584Srgrimes#endif /* DEBUG */ 2594Srgrimes 2601016Sache tone(pitchtab[pitch], sound); 2614Srgrimes if (fill != LEGATO) 2621016Sache rest(silence); 2634Srgrimes } 2644Srgrimes} 2654Srgrimes 26617232Sjoergstatic int 26717232Sjoergabs(n) 26817232Sjoerg int n; 2694Srgrimes{ 2704Srgrimes if (n < 0) 2714Srgrimes return(-n); 2724Srgrimes else 2734Srgrimes return(n); 2744Srgrimes} 2754Srgrimes 2764Srgrimes/* interpret and play an item from a notation string */ 27717232Sjoergstatic void 27817232Sjoergplaystring(cp, slen) 27917232Sjoerg char *cp; 28017232Sjoerg size_t slen; 2814Srgrimes{ 282738Sache int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 2834Srgrimes 2844Srgrimes#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 2854Srgrimes {v = v * 10 + (*++cp - '0'); slen--;} 2864Srgrimes for (; slen--; cp++) 2874Srgrimes { 2884Srgrimes int sustain, timeval, tempo; 2894Srgrimes register char c = toupper(*cp); 2904Srgrimes 2914Srgrimes#ifdef DEBUG 292738Sache (void) printf("playstring: %c (%x)\n", c, c); 2934Srgrimes#endif /* DEBUG */ 2944Srgrimes 2954Srgrimes switch (c) 2964Srgrimes { 2974Srgrimes case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 2984Srgrimes 2994Srgrimes /* compute pitch */ 3004Srgrimes pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 3014Srgrimes 3024Srgrimes /* this may be followed by an accidental sign */ 3034Srgrimes if (cp[1] == '#' || cp[1] == '+') 3044Srgrimes { 3054Srgrimes ++pitch; 3064Srgrimes ++cp; 3074Srgrimes slen--; 3084Srgrimes } 3094Srgrimes else if (cp[1] == '-') 3104Srgrimes { 3114Srgrimes --pitch; 3124Srgrimes ++cp; 3134Srgrimes slen--; 3144Srgrimes } 3154Srgrimes 3164Srgrimes /* 3174Srgrimes * If octave-tracking mode is on, and there has been no octave- 3184Srgrimes * setting prefix, find the version of the current letter note 3194Srgrimes * closest to the last regardless of octave. 3204Srgrimes */ 3214Srgrimes if (octtrack && !octprefix) 3224Srgrimes { 3234Srgrimes if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 3244Srgrimes { 3254Srgrimes ++octave; 3264Srgrimes pitch += OCTAVE_NOTES; 3274Srgrimes } 3284Srgrimes 3294Srgrimes if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 3304Srgrimes { 3314Srgrimes --octave; 3324Srgrimes pitch -= OCTAVE_NOTES; 3334Srgrimes } 3344Srgrimes } 3354Srgrimes octprefix = FALSE; 3364Srgrimes lastpitch = pitch; 3374Srgrimes 3384Srgrimes /* ...which may in turn be followed by an override time value */ 3394Srgrimes GETNUM(cp, timeval); 3404Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 3414Srgrimes timeval = value; 3424Srgrimes 3434Srgrimes /* ...and/or sustain dots */ 3444Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 3454Srgrimes { 3464Srgrimes slen--; 3474Srgrimes sustain++; 3484Srgrimes } 3494Srgrimes 350738Sache /* ...and/or a slur mark */ 351738Sache oldfill = fill; 352738Sache if (cp[1] == '_') 353738Sache { 354738Sache fill = LEGATO; 355738Sache ++cp; 356738Sache slen--; 357738Sache } 358738Sache 3594Srgrimes /* time to emit the actual tone */ 3601016Sache playtone(pitch, timeval, sustain); 361738Sache 362738Sache fill = oldfill; 3634Srgrimes break; 3644Srgrimes 3654Srgrimes case 'O': 3664Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 3674Srgrimes { 3684Srgrimes octprefix = octtrack = FALSE; 3694Srgrimes ++cp; 3704Srgrimes slen--; 3714Srgrimes } 3724Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 3734Srgrimes { 3744Srgrimes octtrack = TRUE; 3754Srgrimes ++cp; 3764Srgrimes slen--; 3774Srgrimes } 3784Srgrimes else 3794Srgrimes { 3804Srgrimes GETNUM(cp, octave); 3813593Sache if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES) 3824Srgrimes octave = DFLT_OCTAVE; 3834Srgrimes octprefix = TRUE; 3844Srgrimes } 3854Srgrimes break; 3864Srgrimes 3874Srgrimes case '>': 3883593Sache if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1) 3894Srgrimes octave++; 3904Srgrimes octprefix = TRUE; 3914Srgrimes break; 3924Srgrimes 3934Srgrimes case '<': 3944Srgrimes if (octave > 0) 3954Srgrimes octave--; 3964Srgrimes octprefix = TRUE; 3974Srgrimes break; 3984Srgrimes 3994Srgrimes case 'N': 4004Srgrimes GETNUM(cp, pitch); 4014Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 4024Srgrimes { 4034Srgrimes slen--; 4044Srgrimes sustain++; 4054Srgrimes } 406738Sache oldfill = fill; 407738Sache if (cp[1] == '_') 408738Sache { 409738Sache fill = LEGATO; 410738Sache ++cp; 411738Sache slen--; 412738Sache } 4131016Sache playtone(pitch - 1, value, sustain); 414738Sache fill = oldfill; 4154Srgrimes break; 4164Srgrimes 4174Srgrimes case 'L': 4184Srgrimes GETNUM(cp, value); 4194Srgrimes if (value <= 0 || value > MIN_VALUE) 4204Srgrimes value = DFLT_VALUE; 4214Srgrimes break; 4224Srgrimes 4234Srgrimes case 'P': 4244Srgrimes case '~': 4254Srgrimes /* this may be followed by an override time value */ 4264Srgrimes GETNUM(cp, timeval); 4274Srgrimes if (timeval <= 0 || timeval > MIN_VALUE) 4284Srgrimes timeval = value; 4294Srgrimes for (sustain = 0; cp[1] == '.'; cp++) 4304Srgrimes { 4314Srgrimes slen--; 4324Srgrimes sustain++; 4334Srgrimes } 4341016Sache playtone(-1, timeval, sustain); 4354Srgrimes break; 4364Srgrimes 4374Srgrimes case 'T': 4384Srgrimes GETNUM(cp, tempo); 4394Srgrimes if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 4404Srgrimes tempo = DFLT_TEMPO; 441766Sache whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; 4424Srgrimes break; 4434Srgrimes 4444Srgrimes case 'M': 4454Srgrimes if (cp[1] == 'N' || cp[1] == 'n') 4464Srgrimes { 4474Srgrimes fill = NORMAL; 4484Srgrimes ++cp; 4494Srgrimes slen--; 4504Srgrimes } 4514Srgrimes else if (cp[1] == 'L' || cp[1] == 'l') 4524Srgrimes { 4534Srgrimes fill = LEGATO; 4544Srgrimes ++cp; 4554Srgrimes slen--; 4564Srgrimes } 4574Srgrimes else if (cp[1] == 'S' || cp[1] == 's') 4584Srgrimes { 4594Srgrimes fill = STACCATO; 4604Srgrimes ++cp; 4614Srgrimes slen--; 4624Srgrimes } 4634Srgrimes break; 4644Srgrimes } 4654Srgrimes } 4664Srgrimes} 4674Srgrimes 4684Srgrimes/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 4694Srgrimes * 4704Srgrimes * This section implements driver hooks to run playstring() and the tone(), 4714Srgrimes * endtone(), and rest() functions defined above. 4724Srgrimes */ 4734Srgrimes 474738Sachestatic int spkr_active = FALSE; /* exclusion flag */ 475738Sachestatic struct buf *spkr_inbuf; /* incoming buf */ 4764Srgrimes 47717232Sjoergint 47817232Sjoergspkropen(dev, flags, fmt, p) 47917232Sjoerg dev_t dev; 48017232Sjoerg int flags; 48117232Sjoerg int fmt; 48217232Sjoerg struct proc *p; 4834Srgrimes{ 4844Srgrimes#ifdef DEBUG 485738Sache (void) printf("spkropen: entering with dev = %x\n", dev); 4864Srgrimes#endif /* DEBUG */ 4874Srgrimes 4884Srgrimes if (minor(dev) != 0) 4894Srgrimes return(ENXIO); 4904Srgrimes else if (spkr_active) 4914Srgrimes return(EBUSY); 4924Srgrimes else 4934Srgrimes { 494738Sache#ifdef DEBUG 495738Sache (void) printf("spkropen: about to perform play initialization\n"); 496738Sache#endif /* DEBUG */ 4974Srgrimes playinit(); 4984Srgrimes spkr_inbuf = geteblk(DEV_BSIZE); 499738Sache spkr_active = TRUE; 500738Sache return(0); 5014Srgrimes } 5024Srgrimes} 5034Srgrimes 50417232Sjoergint 50517232Sjoergspkrwrite(dev, uio, ioflag) 50617232Sjoerg dev_t dev; 50717232Sjoerg struct uio *uio; 50817232Sjoerg int ioflag; 5094Srgrimes{ 5104Srgrimes#ifdef DEBUG 5114Srgrimes printf("spkrwrite: entering with dev = %x, count = %d\n", 5124Srgrimes dev, uio->uio_resid); 5134Srgrimes#endif /* DEBUG */ 5144Srgrimes 5154Srgrimes if (minor(dev) != 0) 5164Srgrimes return(ENXIO); 517738Sache else if (uio->uio_resid > DEV_BSIZE) /* prevent system crashes */ 518738Sache return(E2BIG); 5194Srgrimes else 5204Srgrimes { 521738Sache unsigned n; 522738Sache char *cp; 523738Sache int error; 524738Sache 525738Sache n = uio->uio_resid; 5264Srgrimes cp = spkr_inbuf->b_un.b_addr; 527738Sache if (!(error = uiomove(cp, n, uio))) 5281016Sache playstring(cp, n); 5294Srgrimes return(error); 5304Srgrimes } 5314Srgrimes} 5324Srgrimes 53317232Sjoergint 53417232Sjoergspkrclose(dev, flags, fmt, p) 53517232Sjoerg dev_t dev; 53617232Sjoerg int flags; 53717232Sjoerg int fmt; 53817232Sjoerg struct proc *p; 5394Srgrimes{ 5404Srgrimes#ifdef DEBUG 541738Sache (void) printf("spkrclose: entering with dev = %x\n", dev); 5424Srgrimes#endif /* DEBUG */ 5434Srgrimes 5444Srgrimes if (minor(dev) != 0) 5454Srgrimes return(ENXIO); 5464Srgrimes else 5474Srgrimes { 548766Sache wakeup((caddr_t)&endtone); 549766Sache wakeup((caddr_t)&endrest); 5504Srgrimes brelse(spkr_inbuf); 551738Sache spkr_active = FALSE; 552738Sache return(0); 5534Srgrimes } 5544Srgrimes} 5554Srgrimes 55617232Sjoergint 55717232Sjoergspkrioctl(dev, cmd, cmdarg, flags, p) 55817232Sjoerg dev_t dev; 55917232Sjoerg int cmd; 56017232Sjoerg caddr_t cmdarg; 56117232Sjoerg int flags; 56217232Sjoerg struct proc *p; 5634Srgrimes{ 5644Srgrimes#ifdef DEBUG 565738Sache (void) printf("spkrioctl: entering with dev = %x, cmd = %x\n"); 5664Srgrimes#endif /* DEBUG */ 5674Srgrimes 5684Srgrimes if (minor(dev) != 0) 5694Srgrimes return(ENXIO); 5704Srgrimes else if (cmd == SPKRTONE) 5714Srgrimes { 5724Srgrimes tone_t *tp = (tone_t *)cmdarg; 5734Srgrimes 5744Srgrimes if (tp->frequency == 0) 5751016Sache rest(tp->duration); 5764Srgrimes else 5771016Sache tone(tp->frequency, tp->duration); 5781016Sache return 0; 5794Srgrimes } 5804Srgrimes else if (cmd == SPKRTUNE) 5814Srgrimes { 5824Srgrimes tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 5834Srgrimes tone_t ttp; 5844Srgrimes int error; 5854Srgrimes 5864Srgrimes for (; ; tp++) { 5874Srgrimes error = copyin(tp, &ttp, sizeof(tone_t)); 5884Srgrimes if (error) 5894Srgrimes return(error); 5904Srgrimes if (ttp.duration == 0) 5914Srgrimes break; 5924Srgrimes if (ttp.frequency == 0) 5931016Sache rest(ttp.duration); 5944Srgrimes else 5951016Sache tone(ttp.frequency, ttp.duration); 5964Srgrimes } 597738Sache return(0); 5984Srgrimes } 599738Sache return(EINVAL); 6004Srgrimes} 6014Srgrimes 60212502Sjulian 60312502Sjulianstatic spkr_devsw_installed = 0; 60412502Sjulian 60517232Sjoergstatic void 60617232Sjoergspkr_drvinit(void *unused) 60712502Sjulian{ 60812517Sjulian dev_t dev; 60912517Sjulian 61012502Sjulian if( ! spkr_devsw_installed ) { 61112675Sjulian dev = makedev(CDEV_MAJOR, 0); 61212675Sjulian cdevsw_add(&dev,&spkr_cdevsw, NULL); 61312502Sjulian spkr_devsw_installed = 1; 61412517Sjulian#ifdef DEVFS 61514847Sbde devfs_token = devfs_add_devswf(&spkr_cdevsw, 0, DV_CHR, 61614847Sbde UID_ROOT, GID_WHEEL, 0600, 61714847Sbde "speaker"); 61812521Sjulian#endif 61912517Sjulian } 62012502Sjulian} 62112517Sjulian 62212517SjulianSYSINIT(spkrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,spkr_drvinit,NULL) 62312517Sjulian 62412517Sjulian 6254Srgrimes#endif /* NSPEAKER > 0 */ 6264Srgrimes/* spkr.c ends here */ 627