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