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