Home | History | Annotate | Line # | Download | only in dev
spkr.c revision 1.2
      1  1.2  christos /*	$NetBSD: spkr.c,v 1.2 2016/12/09 04:46:39 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (c) 1990 Eric S. Raymond (esr (at) snark.thyrsus.com)
      5  1.1  christos  * Copyright (c) 1990 Andrew A. Chernov (ache (at) astral.msk.su)
      6  1.1  christos  * Copyright (c) 1990 Lennart Augustsson (lennart (at) augustsson.net)
      7  1.1  christos  * All rights reserved.
      8  1.1  christos  *
      9  1.1  christos  * Redistribution and use in source and binary forms, with or without
     10  1.1  christos  * modification, are permitted provided that the following conditions
     11  1.1  christos  * are met:
     12  1.1  christos  * 1. Redistributions of source code must retain the above copyright
     13  1.1  christos  *    notice, this list of conditions and the following disclaimer.
     14  1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     15  1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     16  1.1  christos  *    documentation and/or other materials provided with the distribution.
     17  1.1  christos  * 3. All advertising materials mentioning features or use of this software
     18  1.1  christos  *    must display the following acknowledgement:
     19  1.1  christos  *	This product includes software developed by Eric S. Raymond
     20  1.1  christos  * 4. The name of the author may not be used to endorse or promote products
     21  1.1  christos  *    derived from this software without specific prior written permission.
     22  1.1  christos  *
     23  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24  1.1  christos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     25  1.1  christos  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     26  1.1  christos  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     27  1.1  christos  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     28  1.1  christos  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     29  1.1  christos  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     31  1.1  christos  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     32  1.1  christos  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     33  1.1  christos  * POSSIBILITY OF SUCH DAMAGE.
     34  1.1  christos  */
     35  1.1  christos 
     36  1.1  christos /*
     37  1.1  christos  * spkr.c -- device driver for console speaker on 80386
     38  1.1  christos  *
     39  1.1  christos  * v1.1 by Eric S. Raymond (esr (at) snark.thyrsus.com) Feb 1990
     40  1.1  christos  *      modified for 386bsd by Andrew A. Chernov <ache (at) astral.msk.su>
     41  1.1  christos  *      386bsd only clean version, all SYSV stuff removed
     42  1.1  christos  *      use hz value from param.c
     43  1.1  christos  */
     44  1.1  christos 
     45  1.1  christos #include <sys/cdefs.h>
     46  1.2  christos __KERNEL_RCSID(0, "$NetBSD: spkr.c,v 1.2 2016/12/09 04:46:39 christos Exp $");
     47  1.1  christos 
     48  1.1  christos #include <sys/param.h>
     49  1.1  christos #include <sys/systm.h>
     50  1.1  christos #include <sys/kernel.h>
     51  1.1  christos #include <sys/errno.h>
     52  1.1  christos #include <sys/device.h>
     53  1.1  christos #include <sys/malloc.h>
     54  1.1  christos #include <sys/module.h>
     55  1.1  christos #include <sys/uio.h>
     56  1.1  christos #include <sys/proc.h>
     57  1.1  christos #include <sys/ioctl.h>
     58  1.1  christos #include <sys/conf.h>
     59  1.1  christos 
     60  1.1  christos #include <sys/bus.h>
     61  1.1  christos 
     62  1.1  christos #include <dev/spkrio.h>
     63  1.2  christos #include <dev/spkrvar.h>
     64  1.1  christos 
     65  1.1  christos dev_type_open(spkropen);
     66  1.1  christos dev_type_close(spkrclose);
     67  1.1  christos dev_type_write(spkrwrite);
     68  1.1  christos dev_type_ioctl(spkrioctl);
     69  1.1  christos 
     70  1.1  christos const struct cdevsw spkr_cdevsw = {
     71  1.1  christos 	.d_open = spkropen,
     72  1.1  christos 	.d_close = spkrclose,
     73  1.1  christos 	.d_read = noread,
     74  1.1  christos 	.d_write = spkrwrite,
     75  1.1  christos 	.d_ioctl = spkrioctl,
     76  1.1  christos 	.d_stop = nostop,
     77  1.1  christos 	.d_tty = notty,
     78  1.1  christos 	.d_poll = nopoll,
     79  1.1  christos 	.d_mmap = nommap,
     80  1.1  christos 	.d_kqfilter = nokqfilter,
     81  1.1  christos 	.d_discard = nodiscard,
     82  1.1  christos 	.d_flag = D_OTHER
     83  1.1  christos };
     84  1.1  christos 
     85  1.1  christos static void playinit(void);
     86  1.1  christos static void playtone(int, int, int);
     87  1.1  christos static void playstring(char *, int);
     88  1.1  christos 
     89  1.1  christos /**************** PLAY STRING INTERPRETER BEGINS HERE **********************
     90  1.1  christos  *
     91  1.1  christos  * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
     92  1.1  christos  * M[LNS] are missing and the ~ synonym and octave-tracking facility is added.
     93  1.1  christos  * Requires spkr_tone(), spkr_rest(). String play is not interruptible
     94  1.1  christos  * except possibly at physical block boundaries.
     95  1.1  christos  */
     96  1.1  christos 
     97  1.1  christos #define dtoi(c)		((c) - '0')
     98  1.1  christos 
     99  1.1  christos static int octave;	/* currently selected octave */
    100  1.1  christos static int whole;	/* whole-note time at current tempo, in ticks */
    101  1.1  christos static int value;	/* whole divisor for note time, quarter note = 1 */
    102  1.1  christos static int fill;	/* controls spacing of notes */
    103  1.1  christos static bool octtrack;	/* octave-tracking on? */
    104  1.1  christos static bool octprefix;	/* override current octave-tracking state? */
    105  1.1  christos 
    106  1.1  christos /*
    107  1.1  christos  * Magic number avoidance...
    108  1.1  christos  */
    109  1.1  christos #define SECS_PER_MIN	60	/* seconds per minute */
    110  1.1  christos #define WHOLE_NOTE	4	/* quarter notes per whole note */
    111  1.1  christos #define MIN_VALUE	64	/* the most we can divide a note by */
    112  1.1  christos #define DFLT_VALUE	4	/* default value (quarter-note) */
    113  1.1  christos #define FILLTIME	8	/* for articulation, break note in parts */
    114  1.1  christos #define STACCATO	6	/* 6/8 = 3/4 of note is filled */
    115  1.1  christos #define NORMAL		7	/* 7/8ths of note interval is filled */
    116  1.1  christos #define LEGATO		8	/* all of note interval is filled */
    117  1.1  christos #define DFLT_OCTAVE	4	/* default octave */
    118  1.1  christos #define MIN_TEMPO	32	/* minimum tempo */
    119  1.1  christos #define DFLT_TEMPO	120	/* default tempo */
    120  1.1  christos #define MAX_TEMPO	255	/* max tempo */
    121  1.1  christos #define NUM_MULT	3	/* numerator of dot multiplier */
    122  1.1  christos #define DENOM_MULT	2	/* denominator of dot multiplier */
    123  1.1  christos 
    124  1.1  christos /* letter to half-tone:  A   B  C  D  E  F  G */
    125  1.1  christos static const int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
    126  1.1  christos 
    127  1.1  christos /*
    128  1.1  christos  * This is the American Standard A440 Equal-Tempered scale with frequencies
    129  1.1  christos  * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
    130  1.1  christos  * our octave 0 is standard octave 2.
    131  1.1  christos  */
    132  1.1  christos #define OCTAVE_NOTES	12	/* semitones per octave */
    133  1.1  christos static const int pitchtab[] =
    134  1.1  christos {
    135  1.1  christos /*        C     C#    D     D#    E     F     F#    G     G#    A     A#    B*/
    136  1.1  christos /* 0 */   65,   69,   73,   78,   82,   87,   93,   98,  103,  110,  117,  123,
    137  1.1  christos /* 1 */  131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
    138  1.1  christos /* 2 */  262,  277,  294,  311,  330,  349,  370,  392,  415,  440,  466,  494,
    139  1.1  christos /* 3 */  523,  554,  587,  622,  659,  698,  740,  784,  831,  880,  932,  988,
    140  1.1  christos /* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
    141  1.1  christos /* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
    142  1.1  christos /* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
    143  1.1  christos };
    144  1.1  christos #define NOCTAVES (int)(__arraycount(pitchtab) / OCTAVE_NOTES)
    145  1.1  christos 
    146  1.1  christos static void
    147  1.1  christos playinit(void)
    148  1.1  christos {
    149  1.1  christos     octave = DFLT_OCTAVE;
    150  1.1  christos     whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
    151  1.1  christos     fill = NORMAL;
    152  1.1  christos     value = DFLT_VALUE;
    153  1.1  christos     octtrack = false;
    154  1.1  christos     octprefix = true;	/* act as though there was an initial O(n) */
    155  1.1  christos }
    156  1.1  christos 
    157  1.1  christos static void
    158  1.1  christos playtone(int pitch, int val, int sustain)
    159  1.1  christos /* play tone of proper duration for current rhythm signature */
    160  1.1  christos {
    161  1.1  christos     int	sound, silence, snum = 1, sdenom = 1;
    162  1.1  christos 
    163  1.1  christos     /* this weirdness avoids floating-point arithmetic */
    164  1.1  christos     for (; sustain; sustain--)
    165  1.1  christos     {
    166  1.1  christos 	snum *= NUM_MULT;
    167  1.1  christos 	sdenom *= DENOM_MULT;
    168  1.1  christos     }
    169  1.1  christos 
    170  1.1  christos     if (pitch == -1)
    171  1.1  christos 	spkr_rest(whole * snum / (val * sdenom));
    172  1.1  christos     else
    173  1.1  christos     {
    174  1.1  christos 	sound = (whole * snum) / (val * sdenom)
    175  1.1  christos 		- (whole * (FILLTIME - fill)) / (val * FILLTIME);
    176  1.1  christos 	silence = whole * (FILLTIME-fill) * snum / (FILLTIME * val * sdenom);
    177  1.1  christos 
    178  1.1  christos #ifdef SPKRDEBUG
    179  1.1  christos 	printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
    180  1.1  christos 	    pitch, sound, silence);
    181  1.1  christos #endif /* SPKRDEBUG */
    182  1.1  christos 
    183  1.1  christos 	spkr_tone(pitchtab[pitch], sound);
    184  1.1  christos 	if (fill != LEGATO)
    185  1.1  christos 	    spkr_rest(silence);
    186  1.1  christos     }
    187  1.1  christos }
    188  1.1  christos 
    189  1.1  christos static void
    190  1.1  christos playstring(char *cp, int slen)
    191  1.1  christos /* interpret and play an item from a notation string */
    192  1.1  christos {
    193  1.1  christos     int		pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
    194  1.1  christos 
    195  1.1  christos #define GETNUM(cp, v)	for(v=0; slen > 0 && isdigit(cp[1]); ) \
    196  1.1  christos 				{v = v * 10 + (*++cp - '0'); slen--;}
    197  1.1  christos     for (; slen--; cp++)
    198  1.1  christos     {
    199  1.1  christos 	int		sustain, timeval, tempo;
    200  1.1  christos 	char	c = toupper(*cp);
    201  1.1  christos 
    202  1.1  christos #ifdef SPKRDEBUG
    203  1.1  christos 	printf("playstring: %c (%x)\n", c, c);
    204  1.1  christos #endif /* SPKRDEBUG */
    205  1.1  christos 
    206  1.1  christos 	switch (c)
    207  1.1  christos 	{
    208  1.1  christos 	case 'A':  case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
    209  1.1  christos 
    210  1.1  christos 	    /* compute pitch */
    211  1.1  christos 	    pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
    212  1.1  christos 
    213  1.1  christos 	    /* this may be followed by an accidental sign */
    214  1.1  christos 	    if (slen > 0 && (cp[1] == '#' || cp[1] == '+'))
    215  1.1  christos 	    {
    216  1.1  christos 		++pitch;
    217  1.1  christos 		++cp;
    218  1.1  christos 		slen--;
    219  1.1  christos 	    }
    220  1.1  christos 	    else if (slen > 0 && cp[1] == '-')
    221  1.1  christos 	    {
    222  1.1  christos 		--pitch;
    223  1.1  christos 		++cp;
    224  1.1  christos 		slen--;
    225  1.1  christos 	    }
    226  1.1  christos 
    227  1.1  christos 	    /*
    228  1.1  christos 	     * If octave-tracking mode is on, and there has been no octave-
    229  1.1  christos 	     * setting prefix, find the version of the current letter note
    230  1.1  christos 	     * closest to the last regardless of octave.
    231  1.1  christos 	     */
    232  1.1  christos 	    if (octtrack && !octprefix)
    233  1.1  christos 	    {
    234  1.1  christos 		if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
    235  1.1  christos 		{
    236  1.1  christos 		    if (octave < NOCTAVES - 1) {
    237  1.1  christos 			++octave;
    238  1.1  christos 			pitch += OCTAVE_NOTES;
    239  1.1  christos 		    }
    240  1.1  christos 		}
    241  1.1  christos 
    242  1.1  christos 		if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
    243  1.1  christos 		{
    244  1.1  christos 		    if (octave > 0) {
    245  1.1  christos 			--octave;
    246  1.1  christos 			pitch -= OCTAVE_NOTES;
    247  1.1  christos 		    }
    248  1.1  christos 		}
    249  1.1  christos 	    }
    250  1.1  christos 	    octprefix = false;
    251  1.1  christos 	    lastpitch = pitch;
    252  1.1  christos 
    253  1.1  christos 	    /* ...which may in turn be followed by an override time value */
    254  1.1  christos 	    GETNUM(cp, timeval);
    255  1.1  christos 	    if (timeval <= 0 || timeval > MIN_VALUE)
    256  1.1  christos 		timeval = value;
    257  1.1  christos 
    258  1.1  christos 	    /* ...and/or sustain dots */
    259  1.1  christos 	    for (sustain = 0; slen > 0 && cp[1] == '.'; cp++)
    260  1.1  christos 	    {
    261  1.1  christos 		slen--;
    262  1.1  christos 		sustain++;
    263  1.1  christos 	    }
    264  1.1  christos 
    265  1.1  christos 	    /* time to emit the actual tone */
    266  1.1  christos 	    playtone(pitch, timeval, sustain);
    267  1.1  christos 	    break;
    268  1.1  christos 
    269  1.1  christos 	case 'O':
    270  1.1  christos 	    if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n'))
    271  1.1  christos 	    {
    272  1.1  christos 		octprefix = octtrack = false;
    273  1.1  christos 		++cp;
    274  1.1  christos 		slen--;
    275  1.1  christos 	    }
    276  1.1  christos 	    else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l'))
    277  1.1  christos 	    {
    278  1.1  christos 		octtrack = true;
    279  1.1  christos 		++cp;
    280  1.1  christos 		slen--;
    281  1.1  christos 	    }
    282  1.1  christos 	    else
    283  1.1  christos 	    {
    284  1.1  christos 		GETNUM(cp, octave);
    285  1.1  christos 		if (octave >= NOCTAVES)
    286  1.1  christos 		    octave = DFLT_OCTAVE;
    287  1.1  christos 		octprefix = true;
    288  1.1  christos 	    }
    289  1.1  christos 	    break;
    290  1.1  christos 
    291  1.1  christos 	case '>':
    292  1.1  christos 	    if (octave < NOCTAVES - 1)
    293  1.1  christos 		octave++;
    294  1.1  christos 	    octprefix = true;
    295  1.1  christos 	    break;
    296  1.1  christos 
    297  1.1  christos 	case '<':
    298  1.1  christos 	    if (octave > 0)
    299  1.1  christos 		octave--;
    300  1.1  christos 	    octprefix = true;
    301  1.1  christos 	    break;
    302  1.1  christos 
    303  1.1  christos 	case 'N':
    304  1.1  christos 	    GETNUM(cp, pitch);
    305  1.1  christos 	    for (sustain = 0; slen > 0 && cp[1] == '.'; cp++)
    306  1.1  christos 	    {
    307  1.1  christos 		slen--;
    308  1.1  christos 		sustain++;
    309  1.1  christos 	    }
    310  1.1  christos 	    playtone(pitch - 1, value, sustain);
    311  1.1  christos 	    break;
    312  1.1  christos 
    313  1.1  christos 	case 'L':
    314  1.1  christos 	    GETNUM(cp, value);
    315  1.1  christos 	    if (value <= 0 || value > MIN_VALUE)
    316  1.1  christos 		value = DFLT_VALUE;
    317  1.1  christos 	    break;
    318  1.1  christos 
    319  1.1  christos 	case 'P':
    320  1.1  christos 	case '~':
    321  1.1  christos 	    /* this may be followed by an override time value */
    322  1.1  christos 	    GETNUM(cp, timeval);
    323  1.1  christos 	    if (timeval <= 0 || timeval > MIN_VALUE)
    324  1.1  christos 		timeval = value;
    325  1.1  christos 	    for (sustain = 0; slen > 0 && cp[1] == '.'; cp++)
    326  1.1  christos 	    {
    327  1.1  christos 		slen--;
    328  1.1  christos 		sustain++;
    329  1.1  christos 	    }
    330  1.1  christos 	    playtone(-1, timeval, sustain);
    331  1.1  christos 	    break;
    332  1.1  christos 
    333  1.1  christos 	case 'T':
    334  1.1  christos 	    GETNUM(cp, tempo);
    335  1.1  christos 	    if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
    336  1.1  christos 		tempo = DFLT_TEMPO;
    337  1.1  christos 	    whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
    338  1.1  christos 	    break;
    339  1.1  christos 
    340  1.1  christos 	case 'M':
    341  1.1  christos 	    if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n'))
    342  1.1  christos 	    {
    343  1.1  christos 		fill = NORMAL;
    344  1.1  christos 		++cp;
    345  1.1  christos 		slen--;
    346  1.1  christos 	    }
    347  1.1  christos 	    else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l'))
    348  1.1  christos 	    {
    349  1.1  christos 		fill = LEGATO;
    350  1.1  christos 		++cp;
    351  1.1  christos 		slen--;
    352  1.1  christos 	    }
    353  1.1  christos 	    else if (slen > 0 && (cp[1] == 'S' || cp[1] == 's'))
    354  1.1  christos 	    {
    355  1.1  christos 		fill = STACCATO;
    356  1.1  christos 		++cp;
    357  1.1  christos 		slen--;
    358  1.1  christos 	    }
    359  1.1  christos 	    break;
    360  1.1  christos 	}
    361  1.1  christos     }
    362  1.1  christos }
    363  1.1  christos 
    364  1.1  christos /******************* UNIX DRIVER HOOKS BEGIN HERE **************************
    365  1.1  christos  *
    366  1.1  christos  * This section implements driver hooks to run playstring() and the spkr_tone()
    367  1.1  christos  * and spkr_rest() functions defined above.
    368  1.1  christos  */
    369  1.1  christos 
    370  1.1  christos static int spkr_active;	/* exclusion flag */
    371  1.1  christos int spkr_attached;
    372  1.1  christos static void *spkr_inbuf;
    373  1.1  christos 
    374  1.1  christos int
    375  1.1  christos spkr_probe(device_t parent, cfdata_t match, void *aux)
    376  1.1  christos {
    377  1.1  christos 	return (!spkr_attached);
    378  1.1  christos }
    379  1.1  christos 
    380  1.1  christos int
    381  1.1  christos spkropen(dev_t dev, int	flags, int mode, struct lwp *l)
    382  1.1  christos {
    383  1.1  christos #ifdef SPKRDEBUG
    384  1.1  christos     printf("spkropen: entering with dev = %"PRIx64"\n", dev);
    385  1.1  christos #endif /* SPKRDEBUG */
    386  1.1  christos 
    387  1.1  christos     if (minor(dev) != 0 || !spkr_attached)
    388  1.1  christos 	return(ENXIO);
    389  1.1  christos     else if (spkr_active)
    390  1.1  christos 	return(EBUSY);
    391  1.1  christos     else
    392  1.1  christos     {
    393  1.1  christos 	playinit();
    394  1.1  christos 	spkr_inbuf = malloc(DEV_BSIZE, M_DEVBUF, M_WAITOK);
    395  1.1  christos 	spkr_active = 1;
    396  1.1  christos     }
    397  1.1  christos     return(0);
    398  1.1  christos }
    399  1.1  christos 
    400  1.1  christos int
    401  1.1  christos spkrwrite(dev_t dev, struct uio *uio, int flags)
    402  1.1  christos {
    403  1.1  christos     int n;
    404  1.1  christos     int error;
    405  1.1  christos #ifdef SPKRDEBUG
    406  1.1  christos     printf("spkrwrite: entering with dev = %"PRIx64", count = %zu\n",
    407  1.1  christos 		dev, uio->uio_resid);
    408  1.1  christos #endif /* SPKRDEBUG */
    409  1.1  christos 
    410  1.1  christos     if (minor(dev) != 0)
    411  1.1  christos 	return(ENXIO);
    412  1.1  christos     else
    413  1.1  christos     {
    414  1.1  christos 	n = min(DEV_BSIZE, uio->uio_resid);
    415  1.1  christos 	error = uiomove(spkr_inbuf, n, uio);
    416  1.1  christos 	if (!error)
    417  1.1  christos 		playstring((char *)spkr_inbuf, n);
    418  1.1  christos 	return(error);
    419  1.1  christos     }
    420  1.1  christos }
    421  1.1  christos 
    422  1.1  christos int
    423  1.1  christos spkrclose(dev_t dev, int flags, int mode, struct lwp *l)
    424  1.1  christos {
    425  1.1  christos #ifdef SPKRDEBUG
    426  1.1  christos     printf("spkrclose: entering with dev = %"PRIx64"\n", dev);
    427  1.1  christos #endif /* SPKRDEBUG */
    428  1.1  christos 
    429  1.1  christos     if (minor(dev) != 0)
    430  1.1  christos 	return(ENXIO);
    431  1.1  christos     else
    432  1.1  christos     {
    433  1.1  christos 	spkr_tone(0, 0);
    434  1.1  christos 	free(spkr_inbuf, M_DEVBUF);
    435  1.1  christos 	spkr_active = 0;
    436  1.1  christos     }
    437  1.1  christos     return(0);
    438  1.1  christos }
    439  1.1  christos 
    440  1.1  christos int
    441  1.1  christos spkrioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    442  1.1  christos {
    443  1.1  christos #ifdef SPKRDEBUG
    444  1.1  christos     printf("spkrioctl: entering with dev = %"PRIx64", cmd = %lx\n", dev, cmd);
    445  1.1  christos #endif /* SPKRDEBUG */
    446  1.1  christos 
    447  1.1  christos     if (minor(dev) != 0)
    448  1.1  christos 	return(ENXIO);
    449  1.1  christos     else if (cmd == SPKRTONE)
    450  1.1  christos     {
    451  1.1  christos 	tone_t	*tp = (tone_t *)data;
    452  1.1  christos 
    453  1.1  christos 	if (tp->frequency == 0)
    454  1.1  christos 	    spkr_rest(tp->duration);
    455  1.1  christos 	else
    456  1.1  christos 	    spkr_tone(tp->frequency, tp->duration);
    457  1.1  christos     }
    458  1.1  christos     else if (cmd == SPKRTUNE)
    459  1.1  christos     {
    460  1.1  christos 	tone_t  *tp = (tone_t *)(*(void **)data);
    461  1.1  christos 	tone_t ttp;
    462  1.1  christos 	int error;
    463  1.1  christos 
    464  1.1  christos 	for (; ; tp++) {
    465  1.1  christos 	    error = copyin(tp, &ttp, sizeof(tone_t));
    466  1.1  christos 	    if (error)
    467  1.1  christos 		    return(error);
    468  1.1  christos 	    if (ttp.duration == 0)
    469  1.1  christos 		    break;
    470  1.1  christos 	    if (ttp.frequency == 0)
    471  1.1  christos 		spkr_rest(ttp.duration);
    472  1.1  christos 	    else
    473  1.1  christos 		spkr_tone(ttp.frequency, ttp.duration);
    474  1.1  christos 	}
    475  1.1  christos     }
    476  1.1  christos     else
    477  1.1  christos 	return(EINVAL);
    478  1.1  christos     return(0);
    479  1.1  christos }
    480  1.1  christos 
    481  1.1  christos int
    482  1.1  christos spkr__modcmd(modcmd_t cmd, void *arg)
    483  1.1  christos {
    484  1.1  christos #ifdef _MODULE
    485  1.1  christos 	devmajor_t bmajor, cmajor;
    486  1.1  christos #endif
    487  1.1  christos 	int error = 0;
    488  1.1  christos 
    489  1.1  christos #ifdef _MODULE
    490  1.1  christos 	switch(cmd) {
    491  1.1  christos 	case MODULE_CMD_INIT:
    492  1.1  christos 		bmajor = cmajor = -1;
    493  1.1  christos 		error = devsw_attach(spkr_cd.cd_name, NULL, &bmajor,
    494  1.1  christos 		    &spkr_cdevsw, &cmajor);
    495  1.1  christos 		if (error)
    496  1.1  christos 			break;
    497  1.1  christos 
    498  1.1  christos 		error = config_init_component(cfdriver_ioconf_spkr,
    499  1.1  christos 			cfattach_ioconf_spkr, cfdata_ioconf_spkr);
    500  1.1  christos 		if (error) {
    501  1.1  christos 			devsw_detach(NULL, &spkr_cdevsw);
    502  1.1  christos 		}
    503  1.1  christos 		break;
    504  1.1  christos 
    505  1.1  christos 	case MODULE_CMD_FINI:
    506  1.1  christos 		if (spkr_active)
    507  1.1  christos 			return EBUSY;
    508  1.1  christos 		error = config_fini_component(cfdriver_ioconf_spkr,
    509  1.1  christos 			cfattach_ioconf_spkr, cfdata_ioconf_spkr);
    510  1.1  christos 		devsw_detach(NULL, &spkr_cdevsw);
    511  1.1  christos 		break;
    512  1.1  christos 	default:
    513  1.1  christos 		error = ENOTTY;
    514  1.1  christos 		break;
    515  1.1  christos 	}
    516  1.1  christos #endif
    517  1.1  christos 
    518  1.1  christos 	return error;
    519  1.1  christos }
    520