spkr.c revision 809
1264790Sbapt/* 2264790Sbapt * spkr.c -- device driver for console speaker 3264790Sbapt * 4264790Sbapt * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993 5264790Sbapt * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su> 6264790Sbapt * 7264790Sbapt * $Id: spkr.c,v 1.5 1993/11/15 01:33:11 ache Exp $ 8264790Sbapt */ 9264790Sbapt 10264790Sbapt#include "speaker.h" 11264790Sbapt 12264790Sbapt#if NSPEAKER > 0 13264790Sbapt 14264790Sbapt#include "param.h" 15264790Sbapt#include "systm.h" 16264790Sbapt#include "kernel.h" 17264790Sbapt#include "errno.h" 18264790Sbapt#include "buf.h" 19264790Sbapt#include "uio.h" 20264790Sbapt 21264790Sbapt#include "machine/speaker.h" 22264790Sbapt 23264790Sbapt/**************** MACHINE DEPENDENT PART STARTS HERE ************************* 24264790Sbapt * 25264790Sbapt * This section defines a function tone() which causes a tone of given 26264790Sbapt * frequency and duration from the 80x86's console speaker. 27264790Sbapt * Another function endtone() is defined to force sound off, and there is 28264790Sbapt * also a rest() entry point to do pauses. 29264790Sbapt * 30264790Sbapt * Audible sound is generated using the Programmable Interval Timer (PIT) and 31264790Sbapt * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The 32264790Sbapt * PPI controls whether sound is passed through at all; the PIT's channel 2 is 33264790Sbapt * used to generate clicks (a square wave) of whatever frequency is desired. 34264790Sbapt */ 35264790Sbapt 36264790Sbapt/* 37264790Sbapt * PIT and PPI port addresses and control values 38264790Sbapt * 39264790Sbapt * Most of the magic is hidden in the TIMER_PREP value, which selects PIT 40264790Sbapt * channel 2, frequency LSB first, square-wave mode and binary encoding. 41264790Sbapt * The encoding is as follows: 42264790Sbapt * 43264790Sbapt * +----------+----------+---------------+-----+ 44264790Sbapt * | 1 0 | 1 1 | 0 1 1 | 0 | 45264790Sbapt * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | 46264790Sbapt * +----------+----------+---------------+-----+ 47264790Sbapt * Counter Write Mode 3 Binary 48264790Sbapt * Channel 2 LSB first, (Square Wave) Encoding 49264790Sbapt * MSB second 50264790Sbapt */ 51264790Sbapt#define PPI 0x61 /* port of Programmable Peripheral Interface */ 52264790Sbapt#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ 53264790Sbapt#define PIT_CTRL 0x43 /* PIT control address */ 54264790Sbapt#define PIT_COUNT 0x42 /* PIT count address */ 55264790Sbapt#define PIT_MODE 0xB6 /* set timer mode for sound generation */ 56264790Sbapt 57264790Sbapt/* 58264790Sbapt * Magic numbers for timer control. 59264790Sbapt */ 60264790Sbapt#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ 61264790Sbapt 62264790Sbapt#define SPKRPRI PSOCK 63264790Sbaptstatic char endtone, endrest; 64264790Sbapt 65264790Sbaptstatic int tone(thz, ticks) 66264790Sbapt/* emit tone of frequency thz for given number of ticks */ 67264790Sbaptunsigned int thz, ticks; 68264790Sbapt{ 69264790Sbapt unsigned int divisor = TIMER_CLK / thz; 70264790Sbapt int sps, error; 71264790Sbapt 72264790Sbapt#ifdef DEBUG 73264790Sbapt (void) printf("tone: thz=%d ticks=%d\n", thz, ticks); 74264790Sbapt#endif /* DEBUG */ 75264790Sbapt 76264790Sbapt /* set timer to generate clicks at given frequency in Hertz */ 77264790Sbapt sps = spltty(); 78264790Sbapt outb(PIT_CTRL, PIT_MODE); /* prepare timer */ 79264790Sbapt outb(PIT_COUNT, (divisor & 0xff)); /* send lo byte */ 80264790Sbapt outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ 81264790Sbapt splx(sps); 82264790Sbapt 83264790Sbapt /* turn the speaker on */ 84264790Sbapt outb(PPI, inb(PPI) | PPI_SPKR); 85264790Sbapt 86264790Sbapt /* 87264790Sbapt * Set timeout to endtone function, then give up the timeslice. 88264790Sbapt * This is so other processes can execute while the tone is being 89264790Sbapt * emitted. 90264790Sbapt */ 91264790Sbapt while ((error = tsleep((caddr_t)&endtone, 92264790Sbapt SPKRPRI | PCATCH, "spkrtn", ticks)) == ERESTART) 93264790Sbapt ; 94264790Sbapt outb(PPI, inb(PPI) & ~PPI_SPKR); 95264790Sbapt 96264790Sbapt if (error == EWOULDBLOCK) 97264790Sbapt error = 0; 98264790Sbapt return error; 99264790Sbapt} 100264790Sbapt 101264790Sbaptstatic int rest(ticks) 102264790Sbapt/* rest for given number of ticks */ 103264790Sbaptint ticks; 104264790Sbapt{ 105264790Sbapt int error; 106264790Sbapt /* 107264790Sbapt * Set timeout to endrest function, then give up the timeslice. 108264790Sbapt * This is so other processes can execute while the rest is being 109264790Sbapt * waited out. 110264790Sbapt */ 111264790Sbapt#ifdef DEBUG 112264790Sbapt (void) printf("rest: %d\n", ticks); 113264790Sbapt#endif /* DEBUG */ 114264790Sbapt while ((error = tsleep((caddr_t)&endrest, 115264790Sbapt SPKRPRI | PCATCH, "spkrrs", ticks)) == ERESTART) 116264790Sbapt ; 117264790Sbapt if (error == EWOULDBLOCK) 118264790Sbapt error = 0; 119264790Sbapt return error; 120264790Sbapt} 121264790Sbapt 122264790Sbapt/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** 123264790Sbapt * 124264790Sbapt * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; 125264790Sbapt * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave- 126264790Sbapt * tracking facility are added. 127264790Sbapt * Requires tone(), rest(), and endtone(). String play is not interruptible 128264790Sbapt * except possibly at physical block boundaries. 129264790Sbapt */ 130264790Sbapt 131264790Sbapttypedef int bool; 132264790Sbapt#define TRUE 1 133264790Sbapt#define FALSE 0 134264790Sbapt 135264790Sbapt#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) 136264790Sbapt#define isdigit(c) (((c) >= '0') && ((c) <= '9')) 137264790Sbapt#define dtoi(c) ((c) - '0') 138264790Sbapt 139264790Sbaptstatic int octave; /* currently selected octave */ 140264790Sbaptstatic int whole; /* whole-note time at current tempo, in ticks */ 141264790Sbaptstatic int value; /* whole divisor for note time, quarter note = 1 */ 142264790Sbaptstatic int fill; /* controls spacing of notes */ 143264790Sbaptstatic bool octtrack; /* octave-tracking on? */ 144264790Sbaptstatic bool octprefix; /* override current octave-tracking state? */ 145264790Sbapt 146264790Sbapt/* 147264790Sbapt * Magic number avoidance... 148264790Sbapt */ 149264790Sbapt#define SECS_PER_MIN 60 /* seconds per minute */ 150264790Sbapt#define WHOLE_NOTE 4 /* quarter notes per whole note */ 151264790Sbapt#define MIN_VALUE 64 /* the most we can divide a note by */ 152264790Sbapt#define DFLT_VALUE 4 /* default value (quarter-note) */ 153264790Sbapt#define FILLTIME 8 /* for articulation, break note in parts */ 154264790Sbapt#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ 155264790Sbapt#define NORMAL 7 /* 7/8ths of note interval is filled */ 156264790Sbapt#define LEGATO 8 /* all of note interval is filled */ 157264790Sbapt#define DFLT_OCTAVE 4 /* default octave */ 158264790Sbapt#define MIN_TEMPO 32 /* minimum tempo */ 159264790Sbapt#define DFLT_TEMPO 120 /* default tempo */ 160264790Sbapt#define MAX_TEMPO 255 /* max tempo */ 161264790Sbapt#define NUM_MULT 3 /* numerator of dot multiplier */ 162264790Sbapt#define DENOM_MULT 2 /* denominator of dot multiplier */ 163264790Sbapt 164264790Sbapt/* letter to half-tone: A B C D E F G */ 165264790Sbaptstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; 166264790Sbapt 167264790Sbapt/* 168264790Sbapt * This is the American Standard A440 Equal-Tempered scale with frequencies 169264790Sbapt * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... 170264790Sbapt * our octave 0 is standard octave 2. 171264790Sbapt */ 172264790Sbapt#define OCTAVE_NOTES 12 /* semitones per octave */ 173264790Sbaptstatic int pitchtab[] = 174264790Sbapt{ 175264790Sbapt/* C C# D D# E F F# G G# A A# B*/ 176264790Sbapt/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, 177264790Sbapt/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, 178264790Sbapt/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, 179264790Sbapt/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 180264790Sbapt/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, 181264790Sbapt/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, 182264790Sbapt/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, 183264790Sbapt}; 184264790Sbapt 185264790Sbaptstatic void playinit() 186264790Sbapt{ 187264790Sbapt octave = DFLT_OCTAVE; 188264790Sbapt whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; 189264790Sbapt fill = NORMAL; 190264790Sbapt value = DFLT_VALUE; 191264790Sbapt octtrack = FALSE; 192264790Sbapt octprefix = TRUE; /* act as though there was an initial O(n) */ 193264790Sbapt} 194264790Sbapt 195264790Sbaptstatic int playtone(pitch, value, sustain) 196264790Sbapt/* play tone of proper duration for current rhythm signature */ 197264790Sbaptint pitch, value, sustain; 198264790Sbapt{ 199264790Sbapt register int sound, silence, snum = 1, sdenom = 1; 200264790Sbapt int error; 201264790Sbapt 202264790Sbapt /* this weirdness avoids floating-point arithmetic */ 203264790Sbapt for (; sustain; sustain--) 204264790Sbapt { 205264790Sbapt /* See the BUGS section in the man page for discussion */ 206264790Sbapt snum *= NUM_MULT; 207264790Sbapt sdenom *= DENOM_MULT; 208264790Sbapt } 209264790Sbapt 210264790Sbapt if (pitch == -1) 211264790Sbapt error = rest(whole * snum / (value * sdenom)); 212264790Sbapt else 213264790Sbapt { 214264790Sbapt sound = (whole * snum) / (value * sdenom) 215264790Sbapt - (whole * (FILLTIME - fill)) / (value * FILLTIME); 216264790Sbapt silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); 217264790Sbapt 218264790Sbapt#ifdef DEBUG 219264790Sbapt (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", 220264790Sbapt pitch, sound, silence); 221264790Sbapt#endif /* DEBUG */ 222264790Sbapt 223264790Sbapt error = tone(pitchtab[pitch], sound); 224264790Sbapt if (error) return error; 225264790Sbapt if (fill != LEGATO) 226264790Sbapt error = rest(silence); 227264790Sbapt } 228264790Sbapt return error; 229264790Sbapt} 230264790Sbapt 231264790Sbaptstatic int abs(n) 232264790Sbaptint n; 233264790Sbapt{ 234264790Sbapt if (n < 0) 235264790Sbapt return(-n); 236264790Sbapt else 237264790Sbapt return(n); 238264790Sbapt} 239264790Sbapt 240264790Sbaptstatic int playstring(cp, slen) 241264790Sbapt/* interpret and play an item from a notation string */ 242264790Sbaptchar *cp; 243264790Sbaptsize_t slen; 244264790Sbapt{ 245264790Sbapt int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; 246264790Sbapt int error; 247264790Sbapt 248264790Sbapt#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ 249264790Sbapt {v = v * 10 + (*++cp - '0'); slen--;} 250264790Sbapt for (; slen--; cp++) 251264790Sbapt { 252264790Sbapt int sustain, timeval, tempo; 253264790Sbapt register char c = toupper(*cp); 254264790Sbapt 255264790Sbapt#ifdef DEBUG 256264790Sbapt (void) printf("playstring: %c (%x)\n", c, c); 257264790Sbapt#endif /* DEBUG */ 258264790Sbapt 259264790Sbapt switch (c) 260264790Sbapt { 261264790Sbapt case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': 262264790Sbapt 263264790Sbapt /* compute pitch */ 264264790Sbapt pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; 265264790Sbapt 266264790Sbapt /* this may be followed by an accidental sign */ 267264790Sbapt if (cp[1] == '#' || cp[1] == '+') 268264790Sbapt { 269264790Sbapt ++pitch; 270264790Sbapt ++cp; 271264790Sbapt slen--; 272264790Sbapt } 273264790Sbapt else if (cp[1] == '-') 274264790Sbapt { 275264790Sbapt --pitch; 276264790Sbapt ++cp; 277264790Sbapt slen--; 278264790Sbapt } 279264790Sbapt 280264790Sbapt /* 281264790Sbapt * If octave-tracking mode is on, and there has been no octave- 282264790Sbapt * setting prefix, find the version of the current letter note 283264790Sbapt * closest to the last regardless of octave. 284264790Sbapt */ 285264790Sbapt if (octtrack && !octprefix) 286264790Sbapt { 287264790Sbapt if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) 288264790Sbapt { 289264790Sbapt ++octave; 290264790Sbapt pitch += OCTAVE_NOTES; 291264790Sbapt } 292264790Sbapt 293264790Sbapt if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) 294264790Sbapt { 295264790Sbapt --octave; 296264790Sbapt pitch -= OCTAVE_NOTES; 297264790Sbapt } 298264790Sbapt } 299264790Sbapt octprefix = FALSE; 300264790Sbapt lastpitch = pitch; 301264790Sbapt 302264790Sbapt /* ...which may in turn be followed by an override time value */ 303264790Sbapt GETNUM(cp, timeval); 304264790Sbapt if (timeval <= 0 || timeval > MIN_VALUE) 305264790Sbapt timeval = value; 306264790Sbapt 307264790Sbapt /* ...and/or sustain dots */ 308264790Sbapt for (sustain = 0; cp[1] == '.'; cp++) 309264790Sbapt { 310264790Sbapt slen--; 311264790Sbapt sustain++; 312264790Sbapt } 313264790Sbapt 314264790Sbapt /* ...and/or a slur mark */ 315264790Sbapt oldfill = fill; 316264790Sbapt if (cp[1] == '_') 317264790Sbapt { 318264790Sbapt fill = LEGATO; 319264790Sbapt ++cp; 320264790Sbapt slen--; 321264790Sbapt } 322264790Sbapt 323264790Sbapt /* time to emit the actual tone */ 324264790Sbapt error = playtone(pitch, timeval, sustain); 325264790Sbapt 326264790Sbapt fill = oldfill; 327264790Sbapt if (error) return error; 328264790Sbapt break; 329264790Sbapt 330264790Sbapt case 'O': 331264790Sbapt if (cp[1] == 'N' || cp[1] == 'n') 332264790Sbapt { 333264790Sbapt octprefix = octtrack = FALSE; 334264790Sbapt ++cp; 335264790Sbapt slen--; 336264790Sbapt } 337264790Sbapt else if (cp[1] == 'L' || cp[1] == 'l') 338264790Sbapt { 339264790Sbapt octtrack = TRUE; 340264790Sbapt ++cp; 341264790Sbapt slen--; 342264790Sbapt } 343264790Sbapt else 344264790Sbapt { 345264790Sbapt GETNUM(cp, octave); 346264790Sbapt if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) 347264790Sbapt octave = DFLT_OCTAVE; 348264790Sbapt octprefix = TRUE; 349264790Sbapt } 350264790Sbapt break; 351264790Sbapt 352264790Sbapt case '>': 353264790Sbapt if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) 354264790Sbapt octave++; 355264790Sbapt octprefix = TRUE; 356264790Sbapt break; 357264790Sbapt 358264790Sbapt case '<': 359264790Sbapt if (octave > 0) 360264790Sbapt octave--; 361264790Sbapt octprefix = TRUE; 362264790Sbapt break; 363264790Sbapt 364264790Sbapt case 'N': 365264790Sbapt GETNUM(cp, pitch); 366264790Sbapt for (sustain = 0; cp[1] == '.'; cp++) 367264790Sbapt { 368264790Sbapt slen--; 369264790Sbapt sustain++; 370264790Sbapt } 371264790Sbapt oldfill = fill; 372264790Sbapt if (cp[1] == '_') 373264790Sbapt { 374264790Sbapt fill = LEGATO; 375264790Sbapt ++cp; 376264790Sbapt slen--; 377264790Sbapt } 378264790Sbapt error = playtone(pitch - 1, value, sustain); 379264790Sbapt fill = oldfill; 380264790Sbapt if (error) return error; 381264790Sbapt break; 382264790Sbapt 383264790Sbapt case 'L': 384264790Sbapt GETNUM(cp, value); 385264790Sbapt if (value <= 0 || value > MIN_VALUE) 386264790Sbapt value = DFLT_VALUE; 387264790Sbapt break; 388264790Sbapt 389264790Sbapt case 'P': 390264790Sbapt case '~': 391264790Sbapt /* this may be followed by an override time value */ 392264790Sbapt GETNUM(cp, timeval); 393264790Sbapt if (timeval <= 0 || timeval > MIN_VALUE) 394264790Sbapt timeval = value; 395264790Sbapt for (sustain = 0; cp[1] == '.'; cp++) 396264790Sbapt { 397264790Sbapt slen--; 398264790Sbapt sustain++; 399264790Sbapt } 400264790Sbapt error = playtone(-1, timeval, sustain); 401264790Sbapt if (error) return error; 402264790Sbapt break; 403264790Sbapt 404264790Sbapt case 'T': 405264790Sbapt GETNUM(cp, tempo); 406264790Sbapt if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) 407264790Sbapt tempo = DFLT_TEMPO; 408264790Sbapt whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo; 409264790Sbapt break; 410264790Sbapt 411264790Sbapt case 'M': 412264790Sbapt if (cp[1] == 'N' || cp[1] == 'n') 413264790Sbapt { 414264790Sbapt fill = NORMAL; 415264790Sbapt ++cp; 416264790Sbapt slen--; 417264790Sbapt } 418264790Sbapt else if (cp[1] == 'L' || cp[1] == 'l') 419264790Sbapt { 420264790Sbapt fill = LEGATO; 421264790Sbapt ++cp; 422264790Sbapt slen--; 423264790Sbapt } 424264790Sbapt else if (cp[1] == 'S' || cp[1] == 's') 425264790Sbapt { 426264790Sbapt fill = STACCATO; 427264790Sbapt ++cp; 428264790Sbapt slen--; 429264790Sbapt } 430264790Sbapt break; 431264790Sbapt } 432264790Sbapt } 433264790Sbapt return 0; 434264790Sbapt} 435264790Sbapt 436264790Sbapt/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** 437264790Sbapt * 438264790Sbapt * This section implements driver hooks to run playstring() and the tone(), 439264790Sbapt * endtone(), and rest() functions defined above. 440264790Sbapt */ 441264790Sbapt 442264790Sbaptstatic int spkr_active = FALSE; /* exclusion flag */ 443264790Sbaptstatic struct buf *spkr_inbuf; /* incoming buf */ 444264790Sbapt 445264790Sbaptint spkropen(dev) 446264790Sbaptdev_t dev; 447264790Sbapt{ 448264790Sbapt#ifdef DEBUG 449264790Sbapt (void) printf("spkropen: entering with dev = %x\n", dev); 450264790Sbapt#endif /* DEBUG */ 451264790Sbapt 452264790Sbapt if (minor(dev) != 0) 453264790Sbapt return(ENXIO); 454264790Sbapt else if (spkr_active) 455264790Sbapt return(EBUSY); 456264790Sbapt else 457264790Sbapt { 458264790Sbapt#ifdef DEBUG 459264790Sbapt (void) printf("spkropen: about to perform play initialization\n"); 460264790Sbapt#endif /* DEBUG */ 461264790Sbapt playinit(); 462264790Sbapt spkr_inbuf = geteblk(DEV_BSIZE); 463264790Sbapt spkr_active = TRUE; 464264790Sbapt return(0); 465264790Sbapt } 466264790Sbapt} 467264790Sbapt 468264790Sbaptint spkrwrite(dev, uio) 469264790Sbaptdev_t dev; 470264790Sbaptstruct uio *uio; 471264790Sbapt{ 472264790Sbapt#ifdef DEBUG 473264790Sbapt printf("spkrwrite: entering with dev = %x, count = %d\n", 474264790Sbapt dev, uio->uio_resid); 475264790Sbapt#endif /* DEBUG */ 476264790Sbapt 477264790Sbapt if (minor(dev) != 0) 478264790Sbapt return(ENXIO); 479264790Sbapt else if (uio->uio_resid > DEV_BSIZE) /* prevent system crashes */ 480264790Sbapt return(E2BIG); 481264790Sbapt else 482264790Sbapt { 483264790Sbapt unsigned n; 484264790Sbapt char *cp; 485264790Sbapt int error; 486264790Sbapt 487264790Sbapt n = uio->uio_resid; 488264790Sbapt cp = spkr_inbuf->b_un.b_addr; 489264790Sbapt if (!(error = uiomove(cp, n, uio))) 490264790Sbapt error = playstring(cp, n); 491264790Sbapt return(error); 492264790Sbapt } 493264790Sbapt} 494264790Sbapt 495264790Sbaptint spkrclose(dev) 496264790Sbaptdev_t dev; 497264790Sbapt{ 498264790Sbapt#ifdef DEBUG 499264790Sbapt (void) printf("spkrclose: entering with dev = %x\n", dev); 500264790Sbapt#endif /* DEBUG */ 501264790Sbapt 502264790Sbapt if (minor(dev) != 0) 503264790Sbapt return(ENXIO); 504264790Sbapt else 505264790Sbapt { 506264790Sbapt wakeup((caddr_t)&endtone); 507264790Sbapt wakeup((caddr_t)&endrest); 508264790Sbapt brelse(spkr_inbuf); 509264790Sbapt spkr_active = FALSE; 510264790Sbapt return(0); 511264790Sbapt } 512264790Sbapt} 513264790Sbapt 514264790Sbaptint spkrioctl(dev, cmd, cmdarg) 515264790Sbaptdev_t dev; 516264790Sbaptint cmd; 517264790Sbaptcaddr_t cmdarg; 518264790Sbapt{ 519264790Sbapt#ifdef DEBUG 520264790Sbapt (void) printf("spkrioctl: entering with dev = %x, cmd = %x\n"); 521264790Sbapt#endif /* DEBUG */ 522264790Sbapt 523264790Sbapt if (minor(dev) != 0) 524264790Sbapt return(ENXIO); 525264790Sbapt else if (cmd == SPKRTONE) 526264790Sbapt { 527264790Sbapt tone_t *tp = (tone_t *)cmdarg; 528264790Sbapt 529264790Sbapt if (tp->frequency == 0) 530264790Sbapt return rest(tp->duration); 531264790Sbapt else 532264790Sbapt return tone(tp->frequency, tp->duration); 533264790Sbapt } 534264790Sbapt else if (cmd == SPKRTUNE) 535264790Sbapt { 536264790Sbapt tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); 537264790Sbapt tone_t ttp; 538264790Sbapt int error; 539264790Sbapt 540264790Sbapt for (; ; tp++) { 541264790Sbapt error = copyin(tp, &ttp, sizeof(tone_t)); 542264790Sbapt if (error) 543264790Sbapt return(error); 544264790Sbapt if (ttp.duration == 0) 545264790Sbapt break; 546264790Sbapt if (ttp.frequency == 0) 547264790Sbapt error = rest(ttp.duration); 548264790Sbapt else 549264790Sbapt error = tone(ttp.frequency, ttp.duration); 550264790Sbapt if (error) 551264790Sbapt return(error); 552264790Sbapt } 553264790Sbapt return(0); 554264790Sbapt } 555264790Sbapt return(EINVAL); 556264790Sbapt} 557264790Sbapt 558264790Sbapt#endif /* NSPEAKER > 0 */ 559264790Sbapt/* spkr.c ends here */ 560264790Sbapt