spkr.c revision 49982
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 *
749982Sbillf *    $Id: spkr.c,v 1.37 1999/05/31 11:26:32 phk Exp $
84Srgrimes */
94Srgrimes
104Srgrimes#include "speaker.h"
114Srgrimes
124Srgrimes#if NSPEAKER > 0
134Srgrimes
1432726Seivind#include "opt_devfs.h"
1532726Seivind
162056Swollman#include <sys/param.h>
172056Swollman#include <sys/systm.h>
182056Swollman#include <sys/kernel.h>
192056Swollman#include <sys/buf.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
2710537Sjulian#ifdef	DEVFS
2810537Sjulian#include <sys/devfsext.h>
2933181Seivindstatic void	*devfs_token;
3012502Sjulian#endif
3110537Sjulian
3212675Sjulianstatic	d_open_t	spkropen;
3312675Sjulianstatic	d_close_t	spkrclose;
3412675Sjulianstatic	d_write_t	spkrwrite;
3512675Sjulianstatic	d_ioctl_t	spkrioctl;
3612502Sjulian
3712675Sjulian#define CDEV_MAJOR 26
3847625Sphkstatic struct cdevsw spkr_cdevsw = {
3947625Sphk	/* open */	spkropen,
4047625Sphk	/* close */	spkrclose,
4147625Sphk	/* read */	noread,
4247625Sphk	/* write */	spkrwrite,
4347625Sphk	/* ioctl */	spkrioctl,
4447625Sphk	/* stop */	nostop,
4547625Sphk	/* reset */	noreset,
4647625Sphk	/* devtotty */	nodevtotty,
4747625Sphk	/* poll */	nopoll,
4847625Sphk	/* mmap */	nommap,
4947625Sphk	/* strategy */	nostrategy,
5047625Sphk	/* name */	"spkr",
5147625Sphk	/* parms */	noparms,
5247625Sphk	/* maj */	CDEV_MAJOR,
5347625Sphk	/* dump */	nodump,
5447625Sphk	/* psize */	nopsize,
5547625Sphk	/* flags */	0,
5647625Sphk	/* maxio */	0,
5747625Sphk	/* bmaj */	-1
5847625Sphk};
5912675Sjulian
604Srgrimes/**************** MACHINE DEPENDENT PART STARTS HERE *************************
614Srgrimes *
624Srgrimes * This section defines a function tone() which causes a tone of given
6319174Sbde * frequency and duration from the ISA console speaker.
644Srgrimes * Another function endtone() is defined to force sound off, and there is
654Srgrimes * also a rest() entry point to do pauses.
664Srgrimes *
674Srgrimes * Audible sound is generated using the Programmable Interval Timer (PIT) and
6819174Sbde * Programmable Peripheral Interface (PPI) attached to the ISA speaker. The
694Srgrimes * PPI controls whether sound is passed through at all; the PIT's channel 2 is
704Srgrimes * used to generate clicks (a square wave) of whatever frequency is desired.
714Srgrimes */
724Srgrimes
734Srgrimes/*
7419174Sbde * PPI control values.
7519174Sbde * XXX should be in a header and used in clock.c.
764Srgrimes */
774Srgrimes#define PPI_SPKR	0x03	/* turn these PPI bits on to pass sound */
784Srgrimes
79766Sache#define SPKRPRI PSOCK
80766Sachestatic char endtone, endrest;
814Srgrimes
8212854Sbdestatic void tone __P((unsigned int thz, unsigned int ticks));
8312854Sbdestatic void rest __P((int ticks));
8412854Sbdestatic void playinit __P((void));
8512854Sbdestatic void playtone __P((int pitch, int value, int sustain));
8612854Sbdestatic int abs __P((int n));
8712854Sbdestatic void playstring __P((char *cp, size_t slen));
8812854Sbde
89766Sache/* emit tone of frequency thz for given number of ticks */
9017232Sjoergstatic void
9117232Sjoergtone(thz, ticks)
9217232Sjoerg	unsigned int thz, ticks;
934Srgrimes{
948288Sdg    unsigned int divisor;
951016Sache    int sps;
964Srgrimes
978288Sdg    if (thz <= 0)
988288Sdg	return;
998288Sdg
10019174Sbde    divisor = timer_freq / thz;
1018288Sdg
1024Srgrimes#ifdef DEBUG
103766Sache    (void) printf("tone: thz=%d ticks=%d\n", thz, ticks);
1044Srgrimes#endif /* DEBUG */
1054Srgrimes
1064Srgrimes    /* set timer to generate clicks at given frequency in Hertz */
10717232Sjoerg    sps = splclock();
1081393Ssos
10919174Sbde    if (acquire_timer2(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT)) {
1101393Ssos	/* enter list of waiting procs ??? */
11117232Sjoerg	splx(sps);
1121393Ssos	return;
1131393Ssos    }
11417232Sjoerg    splx(sps);
11517232Sjoerg    disable_intr();
1161393Ssos    outb(TIMER_CNTR2, (divisor & 0xff));	/* send lo byte */
1171393Ssos    outb(TIMER_CNTR2, (divisor >> 8));	/* send hi byte */
11817232Sjoerg    enable_intr();
1194Srgrimes
1204Srgrimes    /* turn the speaker on */
1211393Ssos    outb(IO_PPI, inb(IO_PPI) | PPI_SPKR);
1224Srgrimes
1234Srgrimes    /*
1244Srgrimes     * Set timeout to endtone function, then give up the timeslice.
1254Srgrimes     * This is so other processes can execute while the tone is being
1264Srgrimes     * emitted.
1274Srgrimes     */
1286152Sache    if (ticks > 0)
1296152Sache	tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks);
1301393Ssos    outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR);
13117232Sjoerg    sps = splclock();
1321393Ssos    release_timer2();
13317232Sjoerg    splx(sps);
1344Srgrimes}
1354Srgrimes
1364Srgrimes/* rest for given number of ticks */
13717232Sjoergstatic void
13817232Sjoergrest(ticks)
13917232Sjoerg	int	ticks;
1404Srgrimes{
1414Srgrimes    /*
1424Srgrimes     * Set timeout to endrest function, then give up the timeslice.
1434Srgrimes     * This is so other processes can execute while the rest is being
1444Srgrimes     * waited out.
1454Srgrimes     */
1464Srgrimes#ifdef DEBUG
147738Sache    (void) printf("rest: %d\n", ticks);
1484Srgrimes#endif /* DEBUG */
1496152Sache    if (ticks > 0)
1506152Sache	tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks);
1514Srgrimes}
1524Srgrimes
1534Srgrimes/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
1544Srgrimes *
1554Srgrimes * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
156738Sache * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave-
157738Sache * tracking facility are added.
1584Srgrimes * Requires tone(), rest(), and endtone(). String play is not interruptible
1594Srgrimes * except possibly at physical block boundaries.
1604Srgrimes */
1614Srgrimes
1624Srgrimestypedef int	bool;
1634Srgrimes#define TRUE	1
1644Srgrimes#define FALSE	0
1654Srgrimes
1664Srgrimes#define toupper(c)	((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
1674Srgrimes#define isdigit(c)	(((c) >= '0') && ((c) <= '9'))
1684Srgrimes#define dtoi(c)		((c) - '0')
1694Srgrimes
1704Srgrimesstatic int octave;	/* currently selected octave */
1714Srgrimesstatic int whole;	/* whole-note time at current tempo, in ticks */
1724Srgrimesstatic int value;	/* whole divisor for note time, quarter note = 1 */
1734Srgrimesstatic int fill;	/* controls spacing of notes */
1744Srgrimesstatic bool octtrack;	/* octave-tracking on? */
1754Srgrimesstatic bool octprefix;	/* override current octave-tracking state? */
1764Srgrimes
1774Srgrimes/*
1784Srgrimes * Magic number avoidance...
1794Srgrimes */
1804Srgrimes#define SECS_PER_MIN	60	/* seconds per minute */
1814Srgrimes#define WHOLE_NOTE	4	/* quarter notes per whole note */
1824Srgrimes#define MIN_VALUE	64	/* the most we can divide a note by */
1834Srgrimes#define DFLT_VALUE	4	/* default value (quarter-note) */
1844Srgrimes#define FILLTIME	8	/* for articulation, break note in parts */
1854Srgrimes#define STACCATO	6	/* 6/8 = 3/4 of note is filled */
1864Srgrimes#define NORMAL		7	/* 7/8ths of note interval is filled */
1874Srgrimes#define LEGATO		8	/* all of note interval is filled */
1884Srgrimes#define DFLT_OCTAVE	4	/* default octave */
1894Srgrimes#define MIN_TEMPO	32	/* minimum tempo */
1904Srgrimes#define DFLT_TEMPO	120	/* default tempo */
1914Srgrimes#define MAX_TEMPO	255	/* max tempo */
1924Srgrimes#define NUM_MULT	3	/* numerator of dot multiplier */
1934Srgrimes#define DENOM_MULT	2	/* denominator of dot multiplier */
1944Srgrimes
1954Srgrimes/* letter to half-tone:  A   B  C  D  E  F  G */
1964Srgrimesstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
1974Srgrimes
1984Srgrimes/*
1994Srgrimes * This is the American Standard A440 Equal-Tempered scale with frequencies
2004Srgrimes * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
2014Srgrimes * our octave 0 is standard octave 2.
2024Srgrimes */
2034Srgrimes#define OCTAVE_NOTES	12	/* semitones per octave */
2044Srgrimesstatic int pitchtab[] =
2054Srgrimes{
2064Srgrimes/*        C     C#    D     D#    E     F     F#    G     G#    A     A#    B*/
2074Srgrimes/* 0 */   65,   69,   73,   78,   82,   87,   93,   98,  103,  110,  117,  123,
2084Srgrimes/* 1 */  131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
2094Srgrimes/* 2 */  262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,
2104Srgrimes/* 3 */  523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,
2114Srgrimes/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
2124Srgrimes/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
2134Srgrimes/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
2144Srgrimes};
2154Srgrimes
21617232Sjoergstatic void
21717232Sjoergplayinit()
2184Srgrimes{
2194Srgrimes    octave = DFLT_OCTAVE;
220766Sache    whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
2214Srgrimes    fill = NORMAL;
2224Srgrimes    value = DFLT_VALUE;
2234Srgrimes    octtrack = FALSE;
2244Srgrimes    octprefix = TRUE;	/* act as though there was an initial O(n) */
2254Srgrimes}
2264Srgrimes
2274Srgrimes/* play tone of proper duration for current rhythm signature */
22817232Sjoergstatic void
22917232Sjoergplaytone(pitch, value, sustain)
23017232Sjoerg	int	pitch, value, sustain;
2314Srgrimes{
2324Srgrimes    register int	sound, silence, snum = 1, sdenom = 1;
2334Srgrimes
2344Srgrimes    /* this weirdness avoids floating-point arithmetic */
2354Srgrimes    for (; sustain; sustain--)
2364Srgrimes    {
237738Sache	/* See the BUGS section in the man page for discussion */
2384Srgrimes	snum *= NUM_MULT;
2394Srgrimes	sdenom *= DENOM_MULT;
2404Srgrimes    }
2414Srgrimes
2428288Sdg    if (value == 0 || sdenom == 0)
2438288Sdg	return;
2448288Sdg
2454Srgrimes    if (pitch == -1)
2461016Sache	rest(whole * snum / (value * sdenom));
2474Srgrimes    else
2484Srgrimes    {
2494Srgrimes	sound = (whole * snum) / (value * sdenom)
2504Srgrimes		- (whole * (FILLTIME - fill)) / (value * FILLTIME);
2514Srgrimes	silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
2524Srgrimes
2534Srgrimes#ifdef DEBUG
254738Sache	(void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
2554Srgrimes			pitch, sound, silence);
2564Srgrimes#endif /* DEBUG */
2574Srgrimes
2581016Sache	tone(pitchtab[pitch], sound);
2594Srgrimes	if (fill != LEGATO)
2601016Sache	    rest(silence);
2614Srgrimes    }
2624Srgrimes}
2634Srgrimes
26417232Sjoergstatic int
26517232Sjoergabs(n)
26617232Sjoerg	int n;
2674Srgrimes{
2684Srgrimes    if (n < 0)
2694Srgrimes	return(-n);
2704Srgrimes    else
2714Srgrimes	return(n);
2724Srgrimes}
2734Srgrimes
2744Srgrimes/* interpret and play an item from a notation string */
27517232Sjoergstatic void
27617232Sjoergplaystring(cp, slen)
27717232Sjoerg	char	*cp;
27817232Sjoerg	size_t	slen;
2794Srgrimes{
280738Sache    int		pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
2814Srgrimes
2824Srgrimes#define GETNUM(cp, v)	for(v=0; isdigit(cp[1]) && slen > 0; ) \
2834Srgrimes				{v = v * 10 + (*++cp - '0'); slen--;}
2844Srgrimes    for (; slen--; cp++)
2854Srgrimes    {
2864Srgrimes	int		sustain, timeval, tempo;
2874Srgrimes	register char	c = toupper(*cp);
2884Srgrimes
2894Srgrimes#ifdef DEBUG
290738Sache	(void) printf("playstring: %c (%x)\n", c, c);
2914Srgrimes#endif /* DEBUG */
2924Srgrimes
2934Srgrimes	switch (c)
2944Srgrimes	{
2954Srgrimes	case 'A':  case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
2964Srgrimes
2974Srgrimes	    /* compute pitch */
2984Srgrimes	    pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
2994Srgrimes
3004Srgrimes	    /* this may be followed by an accidental sign */
3014Srgrimes	    if (cp[1] == '#' || cp[1] == '+')
3024Srgrimes	    {
3034Srgrimes		++pitch;
3044Srgrimes		++cp;
3054Srgrimes		slen--;
3064Srgrimes	    }
3074Srgrimes	    else if (cp[1] == '-')
3084Srgrimes	    {
3094Srgrimes		--pitch;
3104Srgrimes		++cp;
3114Srgrimes		slen--;
3124Srgrimes	    }
3134Srgrimes
3144Srgrimes	    /*
3154Srgrimes	     * If octave-tracking mode is on, and there has been no octave-
3164Srgrimes	     * setting prefix, find the version of the current letter note
3174Srgrimes	     * closest to the last regardless of octave.
3184Srgrimes	     */
3194Srgrimes	    if (octtrack && !octprefix)
3204Srgrimes	    {
3214Srgrimes		if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
3224Srgrimes		{
3234Srgrimes		    ++octave;
3244Srgrimes		    pitch += OCTAVE_NOTES;
3254Srgrimes		}
3264Srgrimes
3274Srgrimes		if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
3284Srgrimes		{
3294Srgrimes		    --octave;
3304Srgrimes		    pitch -= OCTAVE_NOTES;
3314Srgrimes		}
3324Srgrimes	    }
3334Srgrimes	    octprefix = FALSE;
3344Srgrimes	    lastpitch = pitch;
3354Srgrimes
3364Srgrimes	    /* ...which may in turn be followed by an override time value */
3374Srgrimes	    GETNUM(cp, timeval);
3384Srgrimes	    if (timeval <= 0 || timeval > MIN_VALUE)
3394Srgrimes		timeval = value;
3404Srgrimes
3414Srgrimes	    /* ...and/or sustain dots */
3424Srgrimes	    for (sustain = 0; cp[1] == '.'; cp++)
3434Srgrimes	    {
3444Srgrimes		slen--;
3454Srgrimes		sustain++;
3464Srgrimes	    }
3474Srgrimes
348738Sache	    /* ...and/or a slur mark */
349738Sache	    oldfill = fill;
350738Sache	    if (cp[1] == '_')
351738Sache	    {
352738Sache		fill = LEGATO;
353738Sache		++cp;
354738Sache		slen--;
355738Sache	    }
356738Sache
3574Srgrimes	    /* time to emit the actual tone */
3581016Sache	    playtone(pitch, timeval, sustain);
359738Sache
360738Sache	    fill = oldfill;
3614Srgrimes	    break;
3624Srgrimes
3634Srgrimes	case 'O':
3644Srgrimes	    if (cp[1] == 'N' || cp[1] == 'n')
3654Srgrimes	    {
3664Srgrimes		octprefix = octtrack = FALSE;
3674Srgrimes		++cp;
3684Srgrimes		slen--;
3694Srgrimes	    }
3704Srgrimes	    else if (cp[1] == 'L' || cp[1] == 'l')
3714Srgrimes	    {
3724Srgrimes		octtrack = TRUE;
3734Srgrimes		++cp;
3744Srgrimes		slen--;
3754Srgrimes	    }
3764Srgrimes	    else
3774Srgrimes	    {
3784Srgrimes		GETNUM(cp, octave);
3793593Sache		if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES)
3804Srgrimes		    octave = DFLT_OCTAVE;
3814Srgrimes		octprefix = TRUE;
3824Srgrimes	    }
3834Srgrimes	    break;
3844Srgrimes
3854Srgrimes	case '>':
3863593Sache	    if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1)
3874Srgrimes		octave++;
3884Srgrimes	    octprefix = TRUE;
3894Srgrimes	    break;
3904Srgrimes
3914Srgrimes	case '<':
3924Srgrimes	    if (octave > 0)
3934Srgrimes		octave--;
3944Srgrimes	    octprefix = TRUE;
3954Srgrimes	    break;
3964Srgrimes
3974Srgrimes	case 'N':
3984Srgrimes	    GETNUM(cp, pitch);
3994Srgrimes	    for (sustain = 0; cp[1] == '.'; cp++)
4004Srgrimes	    {
4014Srgrimes		slen--;
4024Srgrimes		sustain++;
4034Srgrimes	    }
404738Sache	    oldfill = fill;
405738Sache	    if (cp[1] == '_')
406738Sache	    {
407738Sache		fill = LEGATO;
408738Sache		++cp;
409738Sache		slen--;
410738Sache	    }
4111016Sache	    playtone(pitch - 1, value, sustain);
412738Sache	    fill = oldfill;
4134Srgrimes	    break;
4144Srgrimes
4154Srgrimes	case 'L':
4164Srgrimes	    GETNUM(cp, value);
4174Srgrimes	    if (value <= 0 || value > MIN_VALUE)
4184Srgrimes		value = DFLT_VALUE;
4194Srgrimes	    break;
4204Srgrimes
4214Srgrimes	case 'P':
4224Srgrimes	case '~':
4234Srgrimes	    /* this may be followed by an override time value */
4244Srgrimes	    GETNUM(cp, timeval);
4254Srgrimes	    if (timeval <= 0 || timeval > MIN_VALUE)
4264Srgrimes		timeval = value;
4274Srgrimes	    for (sustain = 0; cp[1] == '.'; cp++)
4284Srgrimes	    {
4294Srgrimes		slen--;
4304Srgrimes		sustain++;
4314Srgrimes	    }
4321016Sache	    playtone(-1, timeval, sustain);
4334Srgrimes	    break;
4344Srgrimes
4354Srgrimes	case 'T':
4364Srgrimes	    GETNUM(cp, tempo);
4374Srgrimes	    if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
4384Srgrimes		tempo = DFLT_TEMPO;
439766Sache	    whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
4404Srgrimes	    break;
4414Srgrimes
4424Srgrimes	case 'M':
4434Srgrimes	    if (cp[1] == 'N' || cp[1] == 'n')
4444Srgrimes	    {
4454Srgrimes		fill = NORMAL;
4464Srgrimes		++cp;
4474Srgrimes		slen--;
4484Srgrimes	    }
4494Srgrimes	    else if (cp[1] == 'L' || cp[1] == 'l')
4504Srgrimes	    {
4514Srgrimes		fill = LEGATO;
4524Srgrimes		++cp;
4534Srgrimes		slen--;
4544Srgrimes	    }
4554Srgrimes	    else if (cp[1] == 'S' || cp[1] == 's')
4564Srgrimes	    {
4574Srgrimes		fill = STACCATO;
4584Srgrimes		++cp;
4594Srgrimes		slen--;
4604Srgrimes	    }
4614Srgrimes	    break;
4624Srgrimes	}
4634Srgrimes    }
4644Srgrimes}
4654Srgrimes
4664Srgrimes/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
4674Srgrimes *
4684Srgrimes * This section implements driver hooks to run playstring() and the tone(),
4694Srgrimes * endtone(), and rest() functions defined above.
4704Srgrimes */
4714Srgrimes
472738Sachestatic int spkr_active = FALSE; /* exclusion flag */
473738Sachestatic struct buf *spkr_inbuf;  /* incoming buf */
4744Srgrimes
47517232Sjoergint
47617232Sjoergspkropen(dev, flags, fmt, p)
47717232Sjoerg	dev_t		dev;
47817232Sjoerg	int		flags;
47917232Sjoerg	int		fmt;
48017232Sjoerg	struct proc	*p;
4814Srgrimes{
4824Srgrimes#ifdef DEBUG
48349982Sbillf    (void) printf("spkropen: entering with dev = %s\n", devtoname(dev));
4844Srgrimes#endif /* DEBUG */
4854Srgrimes
4864Srgrimes    if (minor(dev) != 0)
4874Srgrimes	return(ENXIO);
4884Srgrimes    else if (spkr_active)
4894Srgrimes	return(EBUSY);
4904Srgrimes    else
4914Srgrimes    {
492738Sache#ifdef DEBUG
493738Sache	(void) printf("spkropen: about to perform play initialization\n");
494738Sache#endif /* DEBUG */
4954Srgrimes	playinit();
4964Srgrimes	spkr_inbuf = geteblk(DEV_BSIZE);
497738Sache	spkr_active = TRUE;
498738Sache	return(0);
4994Srgrimes    }
5004Srgrimes}
5014Srgrimes
50217232Sjoergint
50317232Sjoergspkrwrite(dev, uio, ioflag)
50417232Sjoerg	dev_t		dev;
50517232Sjoerg	struct uio	*uio;
50617232Sjoerg	int		ioflag;
5074Srgrimes{
5084Srgrimes#ifdef DEBUG
50949982Sbillf    printf("spkrwrite: entering with dev = %s, count = %d\n",
51049982Sbillf		devtoname(dev), uio->uio_resid);
5114Srgrimes#endif /* DEBUG */
5124Srgrimes
5134Srgrimes    if (minor(dev) != 0)
5144Srgrimes	return(ENXIO);
51517803Speter    else if (uio->uio_resid > (DEV_BSIZE - 1))     /* prevent system crashes */
516738Sache	return(E2BIG);
5174Srgrimes    else
5184Srgrimes    {
519738Sache	unsigned n;
520738Sache	char *cp;
521738Sache	int error;
522738Sache
523738Sache	n = uio->uio_resid;
52431493Sphk	cp = spkr_inbuf->b_data;
52517803Speter	error = uiomove(cp, n, uio);
52617803Speter	if (!error) {
52717803Speter		cp[n] = '\0';
5281016Sache		playstring(cp, n);
52917803Speter	}
5304Srgrimes	return(error);
5314Srgrimes    }
5324Srgrimes}
5334Srgrimes
53417232Sjoergint
53517232Sjoergspkrclose(dev, flags, fmt, p)
53617232Sjoerg	dev_t		dev;
53717232Sjoerg	int		flags;
53817232Sjoerg	int		fmt;
53917232Sjoerg	struct proc	*p;
5404Srgrimes{
5414Srgrimes#ifdef DEBUG
54249982Sbillf    (void) printf("spkrclose: entering with dev = %s\n", devtoname(dev));
5434Srgrimes#endif /* DEBUG */
5444Srgrimes
5454Srgrimes    if (minor(dev) != 0)
5464Srgrimes	return(ENXIO);
5474Srgrimes    else
5484Srgrimes    {
549766Sache	wakeup((caddr_t)&endtone);
550766Sache	wakeup((caddr_t)&endrest);
5514Srgrimes	brelse(spkr_inbuf);
552738Sache	spkr_active = FALSE;
553738Sache	return(0);
5544Srgrimes    }
5554Srgrimes}
5564Srgrimes
55717232Sjoergint
55817232Sjoergspkrioctl(dev, cmd, cmdarg, flags, p)
55917232Sjoerg	dev_t		dev;
56038505Sbde	unsigned long	cmd;
56117232Sjoerg	caddr_t		cmdarg;
56217232Sjoerg	int		flags;
56317232Sjoerg	struct proc	*p;
5644Srgrimes{
5654Srgrimes#ifdef DEBUG
56638505Sbde    (void) printf("spkrioctl: entering with dev = %lx, cmd = %lx\n",
56738505Sbde    	(unsigned long)dev, cmd);
5684Srgrimes#endif /* DEBUG */
5694Srgrimes
5704Srgrimes    if (minor(dev) != 0)
5714Srgrimes	return(ENXIO);
5724Srgrimes    else if (cmd == SPKRTONE)
5734Srgrimes    {
5744Srgrimes	tone_t	*tp = (tone_t *)cmdarg;
5754Srgrimes
5764Srgrimes	if (tp->frequency == 0)
5771016Sache	    rest(tp->duration);
5784Srgrimes	else
5791016Sache	    tone(tp->frequency, tp->duration);
5801016Sache	return 0;
5814Srgrimes    }
5824Srgrimes    else if (cmd == SPKRTUNE)
5834Srgrimes    {
5844Srgrimes	tone_t  *tp = (tone_t *)(*(caddr_t *)cmdarg);
5854Srgrimes	tone_t ttp;
5864Srgrimes	int error;
5874Srgrimes
5884Srgrimes	for (; ; tp++) {
5894Srgrimes	    error = copyin(tp, &ttp, sizeof(tone_t));
5904Srgrimes	    if (error)
5914Srgrimes		    return(error);
5924Srgrimes	    if (ttp.duration == 0)
5934Srgrimes		    break;
5944Srgrimes	    if (ttp.frequency == 0)
5951016Sache		 rest(ttp.duration);
5964Srgrimes	    else
5971016Sache		 tone(ttp.frequency, ttp.duration);
5984Srgrimes	}
599738Sache	return(0);
6004Srgrimes    }
601738Sache    return(EINVAL);
6024Srgrimes}
6034Srgrimes
60417232Sjoergstatic void
60517232Sjoergspkr_drvinit(void *unused)
60612502Sjulian{
60747640Sphk	cdevsw_add(&spkr_cdevsw);
60812517Sjulian#ifdef DEVFS
60947640Sphk	devfs_token = devfs_add_devswf(&spkr_cdevsw, 0, DV_CHR,
61047640Sphk				       UID_ROOT, GID_WHEEL, 0600, "speaker");
61112521Sjulian#endif
61212502Sjulian}
61312517Sjulian
61412517SjulianSYSINIT(spkrdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,spkr_drvinit,NULL)
61512517Sjulian
61612517Sjulian
6174Srgrimes#endif  /* NSPEAKER > 0 */
6184Srgrimes/* spkr.c ends here */
619