| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: spkr.c,v 1.7 2017/06/01 09:44:30 pgoyette Exp $ */ | | 1 | /* $NetBSD: spkr.c,v 1.7.2.1 2023/08/01 13:05:57 martin 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 |
| @@ -33,27 +33,27 @@ | | | @@ -33,27 +33,27 @@ |
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.7 2017/06/01 09:44:30 pgoyette Exp $"); | | 46 | __KERNEL_RCSID(0, "$NetBSD: spkr.c,v 1.7.2.1 2023/08/01 13:05:57 martin Exp $"); |
47 | | | 47 | |
48 | #include <sys/param.h> | | 48 | #include <sys/param.h> |
49 | #include <sys/systm.h> | | 49 | #include <sys/systm.h> |
50 | #include <sys/kernel.h> | | 50 | #include <sys/kernel.h> |
51 | #include <sys/errno.h> | | 51 | #include <sys/errno.h> |
52 | #include <sys/device.h> | | 52 | #include <sys/device.h> |
53 | #include <sys/malloc.h> | | 53 | #include <sys/malloc.h> |
54 | #include <sys/module.h> | | 54 | #include <sys/module.h> |
55 | #include <sys/uio.h> | | 55 | #include <sys/uio.h> |
56 | #include <sys/proc.h> | | 56 | #include <sys/proc.h> |
57 | #include <sys/ioctl.h> | | 57 | #include <sys/ioctl.h> |
58 | #include <sys/conf.h> | | 58 | #include <sys/conf.h> |
59 | | | 59 | |
| @@ -154,51 +154,56 @@ playtone(struct spkr_softc *sc, int pitc | | | @@ -154,51 +154,56 @@ playtone(struct spkr_softc *sc, int pitc |
154 | int sound, silence, snum = 1, sdenom = 1; | | 154 | int sound, silence, snum = 1, sdenom = 1; |
155 | | | 155 | |
156 | /* this weirdness avoids floating-point arithmetic */ | | 156 | /* this weirdness avoids floating-point arithmetic */ |
157 | for (; sustain; sustain--) { | | 157 | for (; sustain; sustain--) { |
158 | snum *= NUM_MULT; | | 158 | snum *= NUM_MULT; |
159 | sdenom *= DENOM_MULT; | | 159 | sdenom *= DENOM_MULT; |
160 | } | | 160 | } |
161 | | | 161 | |
162 | if (pitch == -1) { | | 162 | if (pitch == -1) { |
163 | (*sc->sc_rest)(sc->sc_dev, sc->sc_whole | | 163 | (*sc->sc_rest)(sc->sc_dev, sc->sc_whole |
164 | * snum / (val * sdenom)); | | 164 | * snum / (val * sdenom)); |
165 | return; | | 165 | return; |
166 | } | | 166 | } |
| | | 167 | KASSERTMSG(pitch < __arraycount(pitchtab), "pitch=%d", pitch); |
167 | | | 168 | |
168 | int fac = sc->sc_whole * (FILLTIME - sc->sc_fill); | | 169 | int fac = sc->sc_whole * (FILLTIME - sc->sc_fill); |
169 | int fval = FILLTIME * val; | | 170 | int fval = FILLTIME * val; |
170 | sound = (sc->sc_whole * snum) / (val * sdenom) - fac / fval; | | 171 | sound = (sc->sc_whole * snum) / (val * sdenom) - fac / fval; |
171 | silence = fac * snum / (fval * sdenom); | | 172 | silence = fac * snum / (fval * sdenom); |
172 | | | 173 | |
173 | #ifdef SPKRDEBUG | | 174 | #ifdef SPKRDEBUG |
174 | aprint_debug_dev(sc->sc_dev, | | 175 | aprint_debug_dev(sc->sc_dev, |
175 | "%s: pitch %d for %d ticks, rest for %d ticks\n", __func__, | | 176 | "%s: pitch %d for %d ticks, rest for %d ticks\n", __func__, |
176 | pitch, sound, silence); | | 177 | pitch, sound, silence); |
177 | #endif /* SPKRDEBUG */ | | 178 | #endif /* SPKRDEBUG */ |
178 | | | 179 | |
179 | (*sc->sc_tone)(sc->sc_dev, pitchtab[pitch], sound); | | 180 | (*sc->sc_tone)(sc->sc_dev, pitchtab[pitch], sound); |
180 | if (sc->sc_fill != LEGATO) | | 181 | if (sc->sc_fill != LEGATO) |
181 | (*sc->sc_rest)(sc->sc_dev, silence); | | 182 | (*sc->sc_rest)(sc->sc_dev, silence); |
182 | } | | 183 | } |
183 | | | 184 | |
184 | /* interpret and play an item from a notation string */ | | 185 | /* interpret and play an item from a notation string */ |
185 | static void | | 186 | static void |
186 | playstring(struct spkr_softc *sc, const char *cp, size_t slen) | | 187 | playstring(struct spkr_softc *sc, const char *cp, size_t slen) |
187 | { | | 188 | { |
188 | int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; | | 189 | int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; |
189 | | | 190 | |
190 | #define GETNUM(cp, v) \ | | 191 | #define GETNUM(cp, v) \ |
191 | for (v = 0; slen > 0 && isdigit((unsigned char)cp[1]); ) { \ | | 192 | for (v = 0; slen > 0 && isdigit((unsigned char)cp[1]); ) { \ |
| | | 193 | if (v > INT_MAX/10 - (cp[1] - '0')) { \ |
| | | 194 | v = INT_MAX; \ |
| | | 195 | continue; \ |
| | | 196 | } \ |
192 | v = v * 10 + (*++cp - '0'); \ | | 197 | v = v * 10 + (*++cp - '0'); \ |
193 | slen--; \ | | 198 | slen--; \ |
194 | } | | 199 | } |
195 | | | 200 | |
196 | for (; slen--; cp++) { | | 201 | for (; slen--; cp++) { |
197 | int sustain, timeval, tempo; | | 202 | int sustain, timeval, tempo; |
198 | char c = toupper((unsigned char)*cp); | | 203 | char c = toupper((unsigned char)*cp); |
199 | | | 204 | |
200 | #ifdef SPKRDEBUG | | 205 | #ifdef SPKRDEBUG |
201 | aprint_debug_dev(sc->sc_dev, "%s: %c (%x)\n", __func__, c, c); | | 206 | aprint_debug_dev(sc->sc_dev, "%s: %c (%x)\n", __func__, c, c); |
202 | #endif /* SPKRDEBUG */ | | 207 | #endif /* SPKRDEBUG */ |
203 | | | 208 | |
204 | switch (c) { | | 209 | switch (c) { |
| @@ -262,46 +267,51 @@ playstring(struct spkr_softc *sc, const | | | @@ -262,46 +267,51 @@ playstring(struct spkr_softc *sc, const |
262 | break; | | 267 | break; |
263 | | | 268 | |
264 | case 'O': | | 269 | case 'O': |
265 | if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) { | | 270 | if (slen > 0 && (cp[1] == 'N' || cp[1] == 'n')) { |
266 | sc->sc_octprefix = sc->sc_octtrack = false; | | 271 | sc->sc_octprefix = sc->sc_octtrack = false; |
267 | ++cp; | | 272 | ++cp; |
268 | slen--; | | 273 | slen--; |
269 | } else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) { | | 274 | } else if (slen > 0 && (cp[1] == 'L' || cp[1] == 'l')) { |
270 | sc->sc_octtrack = true; | | 275 | sc->sc_octtrack = true; |
271 | ++cp; | | 276 | ++cp; |
272 | slen--; | | 277 | slen--; |
273 | } else { | | 278 | } else { |
274 | GETNUM(cp, sc->sc_octave); | | 279 | GETNUM(cp, sc->sc_octave); |
| | | 280 | KASSERTMSG(sc->sc_octave >= 0, "%d", |
| | | 281 | sc->sc_octave); |
275 | if (sc->sc_octave >= NOCTAVES) | | 282 | if (sc->sc_octave >= NOCTAVES) |
276 | sc->sc_octave = DFLT_OCTAVE; | | 283 | sc->sc_octave = DFLT_OCTAVE; |
277 | sc->sc_octprefix = true; | | 284 | sc->sc_octprefix = true; |
278 | } | | 285 | } |
279 | break; | | 286 | break; |
280 | | | 287 | |
281 | case '>': | | 288 | case '>': |
282 | if (sc->sc_octave < NOCTAVES - 1) | | 289 | if (sc->sc_octave < NOCTAVES - 1) |
283 | sc->sc_octave++; | | 290 | sc->sc_octave++; |
284 | sc->sc_octprefix = true; | | 291 | sc->sc_octprefix = true; |
285 | break; | | 292 | break; |
286 | | | 293 | |
287 | case '<': | | 294 | case '<': |
288 | if (sc->sc_octave > 0) | | 295 | if (sc->sc_octave > 0) |
289 | sc->sc_octave--; | | 296 | sc->sc_octave--; |
290 | sc->sc_octprefix = true; | | 297 | sc->sc_octprefix = true; |
291 | break; | | 298 | break; |
292 | | | 299 | |
293 | case 'N': | | 300 | case 'N': |
294 | GETNUM(cp, pitch); | | 301 | GETNUM(cp, pitch); |
| | | 302 | KASSERTMSG(pitch >= 0, "pitch=%d", pitch); |
| | | 303 | if (pitch >= __arraycount(pitchtab)) |
| | | 304 | break; |
295 | for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) { | | 305 | for (sustain = 0; slen > 0 && cp[1] == '.'; cp++) { |
296 | slen--; | | 306 | slen--; |
297 | sustain++; | | 307 | sustain++; |
298 | } | | 308 | } |
299 | playtone(sc, pitch - 1, sc->sc_value, sustain); | | 309 | playtone(sc, pitch - 1, sc->sc_value, sustain); |
300 | break; | | 310 | break; |
301 | | | 311 | |
302 | case 'L': | | 312 | case 'L': |
303 | GETNUM(cp, sc->sc_value); | | 313 | GETNUM(cp, sc->sc_value); |
304 | if (sc->sc_value <= 0 || sc->sc_value > MIN_VALUE) | | 314 | if (sc->sc_value <= 0 || sc->sc_value > MIN_VALUE) |
305 | sc->sc_value = DFLT_VALUE; | | 315 | sc->sc_value = DFLT_VALUE; |
306 | break; | | 316 | break; |
307 | | | 317 | |