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