MFC: Bring /dev/speaker support to amd64.

This commit is contained in:
ru 2005-11-16 10:50:12 +00:00
parent b8108a4f96
commit 3b474f83c7
15 changed files with 23 additions and 932 deletions

View File

@ -56,6 +56,8 @@
..
smbus
..
speaker
..
usb
..
utopia

View File

@ -4,7 +4,7 @@
PROG= morse
MAN= morse.6
.if ${MACHINE_ARCH} == "i386"
.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64"
CFLAGS += -DSPEAKER=\"/dev/speaker\"
.endif

View File

@ -64,7 +64,7 @@ static const char rcsid[] =
#include <unistd.h>
#ifdef SPEAKER
#include <machine/speaker.h>
#include <dev/speaker/speaker.h>
#endif
struct morsetab {

View File

@ -38,7 +38,7 @@ LDIRS= bsm cam geom net net80211 netatalk netatm netgraph netinet netinet6 \
LSUBDIRS= cam/scsi \
dev/acpica dev/an dev/bktr dev/firewire dev/hwpmc \
dev/ic dev/iicbus ${_dev_ieee488} dev/ofw \
dev/pbio dev/ppbus dev/smbus dev/usb dev/wi dev/utopia \
dev/pbio dev/ppbus dev/smbus dev/speaker dev/usb dev/wi dev/utopia \
fs/devfs fs/fdescfs fs/fifofs fs/msdosfs fs/ntfs fs/nullfs \
fs/nwfs fs/portalfs fs/procfs fs/smbfs fs/udf fs/umapfs \
fs/unionfs \

View File

@ -300,6 +300,7 @@ MAN= aac.4 \
snd_vibes.4 \
snp.4 \
spic.4 \
${_spkr.4} \
splash.4 \
sppp.4 \
ste.4 \
@ -459,6 +460,7 @@ MLINKS+=sk.4 if_sk.4
MLINKS+=sl.4 if_sl.4
MLINKS+=smp.4 SMP.4
MLINKS+=sn.4 if_sn.4
MLINKS+=${_spkr.4} ${_speaker.4}
MLINKS+=splash.4 screensaver.4
MLINKS+=ste.4 if_ste.4
MLINKS+=stf.4 if_stf.4
@ -482,8 +484,10 @@ MLINKS+=xe.4 if_xe.4
MLINKS+=xl.4 if_xl.4
.if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386"
_nve.4= nve.4
_if_nve.4= if_nve.4
_nve.4= nve.4
_spkr.4= spkr.4
_speaker.4= speaker.4
.endif
.if exists(${.CURDIR}/man4.${MACHINE_ARCH})

View File

@ -44,7 +44,6 @@ MAN= acpi_asus.4 \
scd.4 \
smapi.4 \
snc.4 \
spkr.4 \
sr.4 \
streams.4 \
svr4.4 \
@ -58,7 +57,6 @@ MLINKS+=ndis.4 if_ndis.4
MLINKS+=oltr.4 if_oltr.4
MLINKS+=pae.4 PAE.4
MLINKS+=sbni.4 if_sbni.4
MLINKS+=spkr.4 speaker.4
MANSUBDIR=/i386

View File

@ -1,249 +0,0 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 7, 1993
.Dt SPKR 4 i386
.Os
.Sh NAME
.Nm speaker ,
.Nm spkr
.Nd console speaker device driver
.Sh SYNOPSIS
.Cd device speaker
.In machine/speaker.h
.Sh DESCRIPTION
The speaker device driver allows applications to control the PC console
speaker on an
.Tn IBM-PC Ns --compatible
machine running
.Fx .
.Pp
Only one process may have this device open at any given time;
.Xr open 2
and
.Xr close 2
are used to lock and relinquish it.
An attempt to open when
another process has the device locked will return -1 with an
.Er EBUSY
error
indication.
Writes to the device are interpreted as `play strings' in a
simple ASCII melody notation.
An
.Xr ioctl 2
request
for tone generation at arbitrary
frequencies is also supported.
.Pp
Sound-generation does not monopolize the processor; in fact, the driver
spends most of its time sleeping while the PC hardware is emitting
tones.
Other processes may emit beeps while the driver is running.
.Pp
Applications may call
.Xr ioctl 2
on a speaker file descriptor to control the
speaker driver directly; definitions for the
.Xr ioctl 2
interface are in
.In machine/speaker.h .
The
.Li tone_t
structure used in these calls has two fields,
specifying a frequency (in Hz) and a duration (in 1/100ths of a second).
A frequency of zero is interpreted as a rest.
.Pp
At present there are two such
.Xr ioctl 2
calls.
.Dv SPKRTONE
accepts a pointer to a
single tone structure as third argument and plays it.
.Dv SPKRTUNE
accepts a
pointer to the first of an array of tone structures and plays them in
continuous sequence; this array must be terminated by a final member with
a zero duration.
.Pp
The play-string language is modeled on the PLAY statement conventions of
.Tn IBM
Advanced BASIC 2.0.
The
.Li MB ,
.Li MF ,
and
.Li X
primitives of PLAY are not
useful in a timesharing environment and are omitted.
The `octave-tracking'
feature and the slur mark are new.
.Pp
There are 84 accessible notes numbered 1-84 in 7 octaves, each running from
C to B, numbered 0-6; the scale is equal-tempered A440 and octave 3 starts
with middle C.
By default, the play function emits half-second notes with the
last 1/16th second being `rest time'.
.Pp
Play strings are interpreted left to right as a series of play command groups;
letter case is ignored.
Play command groups are as follows:
.Bl -tag -width CDEFGABxx
.It Li CDEFGAB
Letters A through G cause the corresponding note to be played in the
current octave.
A note letter may optionally be followed by an
.Dq Em "accidental sign" ,
one of # + or -; the first two of these cause it to be sharped one
half-tone, the last causes it to be flatted one half-tone.
It may
also be followed by a time value number and by sustain dots (see
below).
Time values are interpreted as for the L command below.
.It Ns Li O Sy n
If
.Sy n
is numeric, this sets the current octave.
.Sy n
may also be one of
.Li L
or
.Li N
to enable or disable octave-tracking (it is disabled by default).
When octave-tracking is on, interpretation of a pair of letter notes
will change octaves if necessary in order to make the smallest
possible jump between notes.
Thus ``olbc'' will be played as
``olb>c'', and ``olcb'' as ``olc<b''.
Octave locking is disabled for
one letter note following >, < and O[0123456].
(The octave-locking
feature is not supported in
.Tn IBM
BASIC.)
.It Li >
Bump the current octave up one.
.It Li <
Drop the current octave down one.
.It Ns Li N Sy n
Play note
.Sy n ,
.Sy n
being 1 to 84 or 0 for a rest of current time value.
May be followed by sustain dots.
.It Ns Li L Sy n
Sets the current time value for notes.
The default is
.Li L4 ,
quarter or crotchet notes.
The lowest possible value is 1; values up
to 64 are accepted.
.Li L1
sets whole notes,
.Li L2
sets half notes,
.Li L4
sets quarter notes, etc.
.It Ns Li P Sy n
Pause (rest), with
.Sy n
interpreted as for
.Li L Sy n .
May be followed by
sustain dots.
May also be written
.Li ~ .
.It Ns Li T Sy n
Sets the number of quarter notes per minute; default is 120.
Musical
names for common tempi are:
.Bd -literal -offset indent
Tempo Beats Per Minute
very slow Larghissimo
Largo 40-60
Larghetto 60-66
Grave
Lento
Adagio 66-76
slow Adagietto
Andante 76-108
medium Andantino
Moderato 108-120
fast Allegretto
Allegro 120-168
Vivace
Veloce
Presto 168-208
very fast Prestissimo
.Ed
.It Li M[LNS]
Set articulation.
.Li MN
.Li ( N
for normal) is the default; the last 1/8th of
the note's value is rest time.
You can set
.Li ML
for legato (no rest space) or
.Li MS
for staccato (1/4 rest space).
.El
.Pp
Notes (that is,
.Li CDEFGAB
or
.Li N
command character groups) may be followed by
sustain dots.
Each dot causes the note's value to be lengthened by one-half
for each one.
Thus, a note dotted once is held for 3/2 of its undotted value;
dotted twice, it is held 9/4, and three times would give 27/8.
.Pp
A note and its sustain dots may also be followed by a slur mark (underscore).
This causes the normal micro-rest after the note to be filled in, slurring it
to the next one.
(The slur feature is not supported in
.Tn IBM
BASIC.)
.Pp
Whitespace in play strings is simply skipped and may be used to separate
melody sections.
.Sh FILES
.Bl -tag -width /dev/speakerxx
.It Pa /dev/speaker
speaker device file
.El
.Sh SEE ALSO
.Xr spkrtest 8
.Sh HISTORY
The
.Nm
device appeared in
.Fx 1.0 .
.Sh AUTHORS
.An Eric S. Raymond Aq esr@snark.thyrsus.com
June 1990
.Sh "PORTED BY"
.An Andrew A. Chernov Aq ache@astral.msk.su
.Sh BUGS
Due to roundoff in the pitch tables and slop in the tone-generation and timer
hardware (neither of which was designed for precision), neither pitch accuracy
nor timings will be mathematically exact.
There is no volume control.
.Pp
The action of two or more sustain dots does not reflect standard musical
notation, in which each dot adds half the value of the previous dot
modifier, not half the value of the note as modified.
Thus, a note dotted
once is held for 3/2 of its undotted value; dotted twice, it is held 7/4,
and three times would give 15/8.
The multiply-by-3/2 interpretation,
however, is specified in the
.Tn IBM
BASIC manual and has been retained for
compatibility.
.Pp
In play strings which are very long (longer than your system's physical I/O
blocks) note suffixes or numbers may occasionally be parsed incorrectly due
to crossing a block boundary.

View File

@ -107,6 +107,9 @@ options CLK_USE_I8254_CALIBRATION
#####################################################################
# MISCELLANEOUS DEVICES AND OPTIONS
device speaker #Play IBM BASIC-style noises out your speaker
hint.speaker.0.at="isa"
hint.speaker.0.port="0x61"
device gzip #Exec gzipped a.out's. REQUIRES COMPAT_AOUT!

View File

@ -173,6 +173,7 @@ dev/ppc/ppc.c optional ppc
dev/ppc/ppc_puc.c optional ppc puc
dev/sio/sio.c optional sio
dev/sio/sio_isa.c optional sio isa
dev/speaker/spkr.c optional speaker
dev/syscons/apm/apm_saver.c optional apm_saver apm
dev/syscons/schistory.c optional sc
dev/syscons/scmouse.c optional sc

View File

@ -207,6 +207,7 @@ dev/sbni/if_sbni_isa.c optional sbni isa
dev/sbni/if_sbni_pci.c optional sbni pci
dev/sio/sio.c optional sio
dev/sio/sio_isa.c optional sio isa
dev/speaker/spkr.c optional speaker
dev/sr/if_sr_isa.c optional sr isa
dev/syscons/apm/apm_saver.c optional apm_saver apm
dev/syscons/schistory.c optional sc
@ -336,7 +337,6 @@ i386/isa/pcvt/pcvt_vtf.c optional vt
i386/isa/pmtimer.c optional pmtimer
i386/isa/prof_machdep.c optional profiling-routine
i386/isa/spic.c optional spic
i386/isa/spkr.c optional speaker
i386/isa/vesa.c optional vga vesa
i386/linux/imgact_linux.c optional compat_linux
i386/linux/linux_dummy.c optional compat_linux

View File

@ -126,6 +126,7 @@ dev/snc/dp83932subr.c optional snc
dev/snc/if_snc.c optional snc
dev/snc/if_snc_cbus.c optional snc isa
dev/snc/if_snc_pccard.c optional snc pccard
dev/speaker/spkr.c optional speaker
dev/syscons/apm/apm_saver.c optional apm_saver apm
dev/syscons/schistory.c optional sc
dev/syscons/scmouse.c optional sc
@ -212,7 +213,6 @@ i386/isa/isa.c optional isa
i386/isa/npx.c optional npx
i386/isa/pmtimer.c optional pmtimer
i386/isa/prof_machdep.c optional profiling-routine
i386/isa/spkr.c optional speaker
i386/linux/imgact_linux.c optional compat_linux
i386/linux/linux_dummy.c optional compat_linux
i386/linux/linux_locore.s optional compat_linux \

View File

@ -1,29 +1,16 @@
/*
* speaker.h -- interface definitions for speaker ioctl()
*
* v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
* modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
*
* $FreeBSD$
*/
#ifndef _MACHINE_SPEAKER_H_
#define _MACHINE_SPEAKER_H_
#include <sys/ioccom.h>
#include <sys/cdefs.h>
#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */
#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/
#ifdef __CC_SUPPORTS_WARNING
#warning "machine/speaker.h is deprecated. Include dev/speaker/speaker.h instead."
#endif
typedef struct
{
int frequency; /* in hertz */
int duration; /* in 1/100ths of a second */
} tone_t;
/*
* Strings written to the speaker device are interpreted as tunes and played;
* see the spkr(4) man page for details.
*/
#include <dev/speaker/speaker.h>
#endif /* !_MACHINE_SPEAKER_H_ */

View File

@ -1,656 +0,0 @@
/*-
* spkr.c -- device driver for console speaker
*
* v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
* modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
* modified for PC98 by Kakefuda
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/uio.h>
#include <sys/conf.h>
#include <sys/ctype.h>
#include <sys/malloc.h>
#include <isa/isavar.h>
#include <machine/clock.h>
#include <machine/speaker.h>
#include <machine/ppireg.h>
#include <machine/timerreg.h>
static d_open_t spkropen;
static d_close_t spkrclose;
static d_write_t spkrwrite;
static d_ioctl_t spkrioctl;
static struct cdevsw spkr_cdevsw = {
.d_version = D_VERSION,
.d_flags = D_NEEDGIANT,
.d_open = spkropen,
.d_close = spkrclose,
.d_write = spkrwrite,
.d_ioctl = spkrioctl,
.d_name = "spkr",
};
static MALLOC_DEFINE(M_SPKR, "spkr", "Speaker buffer");
/**************** MACHINE DEPENDENT PART STARTS HERE *************************
*
* This section defines a function tone() which causes a tone of given
* frequency and duration from the ISA console speaker.
* Another function endtone() is defined to force sound off, and there is
* also a rest() entry point to do pauses.
*
* Audible sound is generated using the Programmable Interval Timer (PIT) and
* Programmable Peripheral Interface (PPI) attached to the ISA speaker. The
* PPI controls whether sound is passed through at all; the PIT's channel 2 is
* used to generate clicks (a square wave) of whatever frequency is desired.
*/
#ifdef PC98
#define SPKR_DESC "PC98 speaker"
#else
#define SPKR_DESC "PC speaker"
#endif
#define SPKRPRI PSOCK
static char endtone, endrest;
static void tone(unsigned int thz, unsigned int ticks);
static void rest(int ticks);
static void playinit(void);
static void playtone(int pitch, int value, int sustain);
static void playstring(char *cp, size_t slen);
/* emit tone of frequency thz for given number of ticks */
static void
tone(thz, ticks)
unsigned int thz, ticks;
{
unsigned int divisor;
int sps;
if (thz <= 0)
return;
divisor = timer_freq / thz;
#ifdef DEBUG
(void) printf("tone: thz=%d ticks=%d\n", thz, ticks);
#endif /* DEBUG */
/* set timer to generate clicks at given frequency in Hertz */
sps = splclock();
if (timer_spkr_acquire()) {
/* enter list of waiting procs ??? */
splx(sps);
return;
}
splx(sps);
disable_intr();
spkr_set_pitch(divisor);
enable_intr();
/* turn the speaker on */
ppi_spkr_on();
/*
* Set timeout to endtone function, then give up the timeslice.
* This is so other processes can execute while the tone is being
* emitted.
*/
if (ticks > 0)
tsleep(&endtone, SPKRPRI | PCATCH, "spkrtn", ticks);
ppi_spkr_off();
sps = splclock();
timer_spkr_release();
splx(sps);
}
/* rest for given number of ticks */
static void
rest(ticks)
int ticks;
{
/*
* Set timeout to endrest function, then give up the timeslice.
* This is so other processes can execute while the rest is being
* waited out.
*/
#ifdef DEBUG
(void) printf("rest: %d\n", ticks);
#endif /* DEBUG */
if (ticks > 0)
tsleep(&endrest, SPKRPRI | PCATCH, "spkrrs", ticks);
}
/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
*
* Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
* M[LNS] are missing; the ~ synonym and the _ slur mark and the octave-
* tracking facility are added.
* Requires tone(), rest(), and endtone(). String play is not interruptible
* except possibly at physical block boundaries.
*/
typedef int bool;
#define TRUE 1
#define FALSE 0
#define dtoi(c) ((c) - '0')
static int octave; /* currently selected octave */
static int whole; /* whole-note time at current tempo, in ticks */
static int value; /* whole divisor for note time, quarter note = 1 */
static int fill; /* controls spacing of notes */
static bool octtrack; /* octave-tracking on? */
static bool octprefix; /* override current octave-tracking state? */
/*
* Magic number avoidance...
*/
#define SECS_PER_MIN 60 /* seconds per minute */
#define WHOLE_NOTE 4 /* quarter notes per whole note */
#define MIN_VALUE 64 /* the most we can divide a note by */
#define DFLT_VALUE 4 /* default value (quarter-note) */
#define FILLTIME 8 /* for articulation, break note in parts */
#define STACCATO 6 /* 6/8 = 3/4 of note is filled */
#define NORMAL 7 /* 7/8ths of note interval is filled */
#define LEGATO 8 /* all of note interval is filled */
#define DFLT_OCTAVE 4 /* default octave */
#define MIN_TEMPO 32 /* minimum tempo */
#define DFLT_TEMPO 120 /* default tempo */
#define MAX_TEMPO 255 /* max tempo */
#define NUM_MULT 3 /* numerator of dot multiplier */
#define DENOM_MULT 2 /* denominator of dot multiplier */
/* letter to half-tone: A B C D E F G */
static int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
/*
* This is the American Standard A440 Equal-Tempered scale with frequencies
* rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
* our octave 0 is standard octave 2.
*/
#define OCTAVE_NOTES 12 /* semitones per octave */
static int pitchtab[] =
{
/* C C# D D# E F F# G G# A A# B*/
/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123,
/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247,
/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
};
static void
playinit()
{
octave = DFLT_OCTAVE;
whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
fill = NORMAL;
value = DFLT_VALUE;
octtrack = FALSE;
octprefix = TRUE; /* act as though there was an initial O(n) */
}
/* play tone of proper duration for current rhythm signature */
static void
playtone(pitch, value, sustain)
int pitch, value, sustain;
{
register int sound, silence, snum = 1, sdenom = 1;
/* this weirdness avoids floating-point arithmetic */
for (; sustain; sustain--)
{
/* See the BUGS section in the man page for discussion */
snum *= NUM_MULT;
sdenom *= DENOM_MULT;
}
if (value == 0 || sdenom == 0)
return;
if (pitch == -1)
rest(whole * snum / (value * sdenom));
else
{
sound = (whole * snum) / (value * sdenom)
- (whole * (FILLTIME - fill)) / (value * FILLTIME);
silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
#ifdef DEBUG
(void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
pitch, sound, silence);
#endif /* DEBUG */
tone(pitchtab[pitch], sound);
if (fill != LEGATO)
rest(silence);
}
}
/* interpret and play an item from a notation string */
static void
playstring(cp, slen)
char *cp;
size_t slen;
{
int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
{v = v * 10 + (*++cp - '0'); slen--;}
for (; slen--; cp++)
{
int sustain, timeval, tempo;
register char c = toupper(*cp);
#ifdef DEBUG
(void) printf("playstring: %c (%x)\n", c, c);
#endif /* DEBUG */
switch (c)
{
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
/* compute pitch */
pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
/* this may be followed by an accidental sign */
if (cp[1] == '#' || cp[1] == '+')
{
++pitch;
++cp;
slen--;
}
else if (cp[1] == '-')
{
--pitch;
++cp;
slen--;
}
/*
* If octave-tracking mode is on, and there has been no octave-
* setting prefix, find the version of the current letter note
* closest to the last regardless of octave.
*/
if (octtrack && !octprefix)
{
if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
{
++octave;
pitch += OCTAVE_NOTES;
}
if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
{
--octave;
pitch -= OCTAVE_NOTES;
}
}
octprefix = FALSE;
lastpitch = pitch;
/* ...which may in turn be followed by an override time value */
GETNUM(cp, timeval);
if (timeval <= 0 || timeval > MIN_VALUE)
timeval = value;
/* ...and/or sustain dots */
for (sustain = 0; cp[1] == '.'; cp++)
{
slen--;
sustain++;
}
/* ...and/or a slur mark */
oldfill = fill;
if (cp[1] == '_')
{
fill = LEGATO;
++cp;
slen--;
}
/* time to emit the actual tone */
playtone(pitch, timeval, sustain);
fill = oldfill;
break;
case 'O':
if (cp[1] == 'N' || cp[1] == 'n')
{
octprefix = octtrack = FALSE;
++cp;
slen--;
}
else if (cp[1] == 'L' || cp[1] == 'l')
{
octtrack = TRUE;
++cp;
slen--;
}
else
{
GETNUM(cp, octave);
if (octave >= sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES)
octave = DFLT_OCTAVE;
octprefix = TRUE;
}
break;
case '>':
if (octave < sizeof(pitchtab) / sizeof(pitchtab[0]) / OCTAVE_NOTES - 1)
octave++;
octprefix = TRUE;
break;
case '<':
if (octave > 0)
octave--;
octprefix = TRUE;
break;
case 'N':
GETNUM(cp, pitch);
for (sustain = 0; cp[1] == '.'; cp++)
{
slen--;
sustain++;
}
oldfill = fill;
if (cp[1] == '_')
{
fill = LEGATO;
++cp;
slen--;
}
playtone(pitch - 1, value, sustain);
fill = oldfill;
break;
case 'L':
GETNUM(cp, value);
if (value <= 0 || value > MIN_VALUE)
value = DFLT_VALUE;
break;
case 'P':
case '~':
/* this may be followed by an override time value */
GETNUM(cp, timeval);
if (timeval <= 0 || timeval > MIN_VALUE)
timeval = value;
for (sustain = 0; cp[1] == '.'; cp++)
{
slen--;
sustain++;
}
playtone(-1, timeval, sustain);
break;
case 'T':
GETNUM(cp, tempo);
if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
tempo = DFLT_TEMPO;
whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
break;
case 'M':
if (cp[1] == 'N' || cp[1] == 'n')
{
fill = NORMAL;
++cp;
slen--;
}
else if (cp[1] == 'L' || cp[1] == 'l')
{
fill = LEGATO;
++cp;
slen--;
}
else if (cp[1] == 'S' || cp[1] == 's')
{
fill = STACCATO;
++cp;
slen--;
}
break;
}
}
}
/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
*
* This section implements driver hooks to run playstring() and the tone(),
* endtone(), and rest() functions defined above.
*/
static int spkr_active = FALSE; /* exclusion flag */
static char *spkr_inbuf; /* incoming buf */
static int
spkropen(dev, flags, fmt, td)
struct cdev *dev;
int flags;
int fmt;
struct thread *td;
{
#ifdef DEBUG
(void) printf("spkropen: entering with dev = %s\n", devtoname(dev));
#endif /* DEBUG */
if (minor(dev) != 0)
return(ENXIO);
else if (spkr_active)
return(EBUSY);
else
{
#ifdef DEBUG
(void) printf("spkropen: about to perform play initialization\n");
#endif /* DEBUG */
playinit();
spkr_inbuf = malloc(DEV_BSIZE, M_SPKR, M_WAITOK);
spkr_active = TRUE;
return(0);
}
}
static int
spkrwrite(dev, uio, ioflag)
struct cdev *dev;
struct uio *uio;
int ioflag;
{
#ifdef DEBUG
printf("spkrwrite: entering with dev = %s, count = %d\n",
devtoname(dev), uio->uio_resid);
#endif /* DEBUG */
if (minor(dev) != 0)
return(ENXIO);
else if (uio->uio_resid > (DEV_BSIZE - 1)) /* prevent system crashes */
return(E2BIG);
else
{
unsigned n;
char *cp;
int error;
n = uio->uio_resid;
cp = spkr_inbuf;
error = uiomove(cp, n, uio);
if (!error) {
cp[n] = '\0';
playstring(cp, n);
}
return(error);
}
}
static int
spkrclose(dev, flags, fmt, td)
struct cdev *dev;
int flags;
int fmt;
struct thread *td;
{
#ifdef DEBUG
(void) printf("spkrclose: entering with dev = %s\n", devtoname(dev));
#endif /* DEBUG */
if (minor(dev) != 0)
return(ENXIO);
else
{
wakeup(&endtone);
wakeup(&endrest);
free(spkr_inbuf, M_SPKR);
spkr_active = FALSE;
return(0);
}
}
static int
spkrioctl(dev, cmd, cmdarg, flags, td)
struct cdev *dev;
unsigned long cmd;
caddr_t cmdarg;
int flags;
struct thread *td;
{
#ifdef DEBUG
(void) printf("spkrioctl: entering with dev = %s, cmd = %lx\n",
devtoname(dev), cmd);
#endif /* DEBUG */
if (minor(dev) != 0)
return(ENXIO);
else if (cmd == SPKRTONE)
{
tone_t *tp = (tone_t *)cmdarg;
if (tp->frequency == 0)
rest(tp->duration);
else
tone(tp->frequency, tp->duration);
return 0;
}
else if (cmd == SPKRTUNE)
{
tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg);
tone_t ttp;
int error;
for (; ; tp++) {
error = copyin(tp, &ttp, sizeof(tone_t));
if (error)
return(error);
if (ttp.duration == 0)
break;
if (ttp.frequency == 0)
rest(ttp.duration);
else
tone(ttp.frequency, ttp.duration);
}
return(0);
}
return(EINVAL);
}
/*
* Install placeholder to claim the resources owned by the
* AT tone generator.
*/
static struct isa_pnp_id speaker_ids[] = {
#ifndef PC98
{ 0x0008d041 /* PNP0800 */, SPKR_DESC },
#endif
{ 0 }
};
static struct cdev *speaker_dev;
static int
speaker_probe(device_t dev)
{
int error;
error = ISA_PNP_PROBE(device_get_parent(dev), dev, speaker_ids);
/* PnP match */
if (error == 0)
return (0);
/* No match */
if (error == ENXIO)
return (ENXIO);
/* Not configured by hints. */
if (strncmp(device_get_name(dev), "speaker", 9))
return (ENXIO);
device_set_desc(dev, SPKR_DESC);
return (0);
}
static int
speaker_attach(device_t dev)
{
if (speaker_dev) {
device_printf(dev, "Already attached!\n");
return (ENXIO);
}
speaker_dev = make_dev(&spkr_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
"speaker");
return (0);
}
static int
speaker_detach(device_t dev)
{
destroy_dev(speaker_dev);
return (0);
}
static device_method_t speaker_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, speaker_probe),
DEVMETHOD(device_attach, speaker_attach),
DEVMETHOD(device_detach, speaker_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
{ 0, 0 }
};
static driver_t speaker_driver = {
"speaker",
speaker_methods,
1, /* no softc */
};
static devclass_t speaker_devclass;
DRIVER_MODULE(speaker, isa, speaker_driver, speaker_devclass, 0, 0);
#ifndef PC98
DRIVER_MODULE(speaker, acpi, speaker_driver, speaker_devclass, 0, 0);
#endif
/* spkr.c ends here */

View File

@ -450,6 +450,7 @@ _safe= safe
_scsi_low= scsi_low
_smbfs= smbfs
_sound= sound
_speaker= speaker
_sppp= sppp
_twa= twa
.endif

View File

@ -1,6 +1,6 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../i386/isa
.PATH: ${.CURDIR}/../../dev/speaker
KMOD= speaker
SRCS= spkr.c