opmbell.c revision 1.1 1 /* $NetBSD: opmbell.c,v 1.1 1996/05/05 12:17:08 oki Exp $ */
2
3 /*
4 * Copyright (c) 1995 MINOURA Makoto, Takuya Harakawa.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by MINOURA Makoto,
18 * Takuya Harakawa.
19 * 4. Neither the name of the authors may be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37 /*
38 * bell device driver
39 */
40
41 #include "bell.h"
42 #if NBELL > 0
43
44 #if NBELL > 1
45 #undef NBELL
46 #define NBELL 1
47 #endif
48
49 #include <sys/param.h>
50 #include <sys/errno.h>
51 #include <sys/uio.h>
52 #include <sys/device.h>
53 #include <sys/malloc.h>
54 #include <sys/file.h>
55 #include <sys/systm.h>
56
57 #include <x68k/x68k/iodevice.h>
58 #include <machine/opmbellio.h>
59 #include <x68k/dev/opmreg.h>
60 #include <x68k/dev/opmbellvar.h>
61
62 static u_int bell_pitchtokey __P((u_int));
63 static void bell_timeout();
64
65 struct bell_softc {
66 int sc_flags;
67 u_char ch;
68 u_char volume;
69 u_int pitch;
70 u_int msec;
71 u_int key;
72 };
73
74 struct bell_softc *bell_softc;
75
76 static struct opm_voice vtab[NBELL];
77
78 /* sc_flags values */
79 #define BELLF_READ 0x01
80 #define BELLF_WRITE 0x02
81 #define BELLF_ALIVE 0x04
82 #define BELLF_OPEN 0x08
83 #define BELLF_OUT 0x10
84 #define BELLF_ON 0x20
85
86 #define UNIT(x) minor(x)
87
88 int
89 bellattach(num)
90 int num;
91 {
92 char *mem;
93 register u_long size;
94 register struct bell_softc *sc;
95 int unit;
96
97 if (num <= 0)
98 return;
99 size = num * sizeof(struct bell_softc);
100 mem = malloc(size, M_DEVBUF, M_NOWAIT);
101 if (mem == NULL) {
102 printf("WARNING: no memory for opm bell\n");
103 return;
104 }
105 bzero(mem, size);
106 bell_softc = (struct bell_softc *)mem;
107
108 for (unit = 0; unit < num; unit++) {
109 sc = &bell_softc[unit];
110 sc->sc_flags = BELLF_ALIVE;
111 sc->ch = BELL_CHANNEL;
112 sc->volume = BELL_VOLUME;
113 sc->pitch = BELL_PITCH;
114 sc->msec = BELL_DURATION;
115 sc->key = bell_pitchtokey(sc->pitch);
116
117 /* setup initial voice parameter */
118 bcopy(&bell_voice, &vtab[unit], sizeof(bell_voice));
119 opm_set_voice(sc->ch, &vtab[unit]);
120
121 printf("bell%d: YM2151 OPM bell emulation.\n", unit);
122 }
123 }
124
125 int
126 bellopen(dev, flags)
127 dev_t dev;
128 int flags;
129 {
130 register int unit = UNIT(dev);
131 register struct bell_softc *sc = &bell_softc[unit];
132
133 if (unit >= NBELL || !(sc->sc_flags & BELLF_ALIVE))
134 return ENXIO;
135
136 if (sc->sc_flags & BELLF_OPEN)
137 return EBUSY;
138
139 sc->sc_flags |= BELLF_OPEN;
140 sc->sc_flags |= (flags & (FREAD | FWRITE));
141
142 return 0;
143 }
144
145 void
146 bellclose(dev, flags)
147 dev_t dev;
148 int flags;
149 {
150 int unit = UNIT(dev);
151 struct bell_softc *sc = &bell_softc[unit];
152
153 sc->sc_flags &= ~BELLF_OPEN;
154 }
155
156 int
157 bellioctl(dev, cmd, addr, flag, p)
158 dev_t dev;
159 u_long cmd;
160 caddr_t addr;
161 int flag;
162 struct proc *p;
163 {
164 int unit = UNIT(dev);
165 struct bell_softc *sc = &bell_softc[unit];
166
167 switch (cmd) {
168 case BELLIOCGPARAM:
169 {
170 struct bell_info *bp = (struct bell_info *)addr;
171 if (!(sc->sc_flags & FREAD))
172 return EBADF;
173
174 bp->volume = sc->volume;
175 bp->pitch = sc->pitch;
176 bp->msec = sc->msec;
177 break;
178 }
179
180 case BELLIOCSPARAM:
181 {
182 struct bell_info *bp = (struct bell_info *)addr;
183
184 if (!(sc->sc_flags & FWRITE))
185 return EBADF;
186
187 return opm_bell_setup(bp);
188 }
189
190 case BELLIOCGVOICE:
191 if (!(sc->sc_flags & FREAD))
192 return EBADF;
193
194 if (addr == NULL)
195 return EFAULT;
196
197 bcopy(&vtab[unit], addr, sizeof(struct opm_voice));
198 break;
199
200 case BELLIOCSVOICE:
201 if (!(sc->sc_flags & FWRITE))
202 return EBADF;
203
204 if (addr == NULL)
205 return EFAULT;
206
207 bcopy(addr, &vtab[unit], sizeof(struct opm_voice));
208 opm_set_voice(sc->ch, &vtab[unit]);
209 break;
210
211 default:
212 return EINVAL;
213 }
214 return 0;
215 }
216
217 /*
218 * The next table is used for calculating KeyCode/KeyFraction pair
219 * from frequency.
220 */
221
222 static u_int note[] = {
223 0x0800, 0x0808, 0x0810, 0x081c,
224 0x0824, 0x0830, 0x0838, 0x0844,
225 0x084c, 0x0858, 0x0860, 0x086c,
226 0x0874, 0x0880, 0x0888, 0x0890,
227 0x089c, 0x08a4, 0x08b0, 0x08b8,
228 0x08c4, 0x08cc, 0x08d8, 0x08e0,
229 0x08ec, 0x08f4, 0x0900, 0x0908,
230 0x0910, 0x091c, 0x0924, 0x092c,
231 0x0938, 0x0940, 0x0948, 0x0954,
232 0x095c, 0x0968, 0x0970, 0x0978,
233 0x0984, 0x098c, 0x0994, 0x09a0,
234 0x09a8, 0x09b4, 0x09bc, 0x09c4,
235 0x09d0, 0x09d8, 0x09e0, 0x09ec,
236 0x09f4, 0x0a00, 0x0a08, 0x0a10,
237 0x0a18, 0x0a20, 0x0a28, 0x0a30,
238 0x0a38, 0x0a44, 0x0a4c, 0x0a54,
239 0x0a5c, 0x0a64, 0x0a6c, 0x0a74,
240 0x0a80, 0x0a88, 0x0a90, 0x0a98,
241 0x0aa0, 0x0aa8, 0x0ab0, 0x0ab8,
242 0x0ac4, 0x0acc, 0x0ad4, 0x0adc,
243 0x0ae4, 0x0aec, 0x0af4, 0x0c00,
244 0x0c08, 0x0c10, 0x0c18, 0x0c20,
245 0x0c28, 0x0c30, 0x0c38, 0x0c40,
246 0x0c48, 0x0c50, 0x0c58, 0x0c60,
247 0x0c68, 0x0c70, 0x0c78, 0x0c84,
248 0x0c8c, 0x0c94, 0x0c9c, 0x0ca4,
249 0x0cac, 0x0cb4, 0x0cbc, 0x0cc4,
250 0x0ccc, 0x0cd4, 0x0cdc, 0x0ce4,
251 0x0cec, 0x0cf4, 0x0d00, 0x0d04,
252 0x0d0c, 0x0d14, 0x0d1c, 0x0d24,
253 0x0d2c, 0x0d34, 0x0d3c, 0x0d44,
254 0x0d4c, 0x0d54, 0x0d5c, 0x0d64,
255 0x0d6c, 0x0d74, 0x0d7c, 0x0d80,
256 0x0d88, 0x0d90, 0x0d98, 0x0da0,
257 0x0da8, 0x0db0, 0x0db8, 0x0dc0,
258 0x0dc8, 0x0dd0, 0x0dd8, 0x0de0,
259 0x0de8, 0x0df0, 0x0df8, 0x0e00,
260 0x0e04, 0x0e0c, 0x0e14, 0x0e1c,
261 0x0e24, 0x0e28, 0x0e30, 0x0e38,
262 0x0e40, 0x0e48, 0x0e50, 0x0e54,
263 0x0e5c, 0x0e64, 0x0e6c, 0x0e74,
264 0x0e7c, 0x0e80, 0x0e88, 0x0e90,
265 0x0e98, 0x0ea0, 0x0ea8, 0x0eac,
266 0x0eb4, 0x0ebc, 0x0ec4, 0x0ecc,
267 0x0ed4, 0x0ed8, 0x0ee0, 0x0ee8,
268 0x0ef0, 0x0ef8, 0x1000, 0x1004,
269 0x100c, 0x1014, 0x1018, 0x1020,
270 0x1028, 0x1030, 0x1034, 0x103c,
271 0x1044, 0x104c, 0x1050, 0x1058,
272 0x1060, 0x1064, 0x106c, 0x1074,
273 0x107c, 0x1080, 0x1088, 0x1090,
274 0x1098, 0x109c, 0x10a4, 0x10ac,
275 0x10b0, 0x10b8, 0x10c0, 0x10c8,
276 0x10cc, 0x10d4, 0x10dc, 0x10e4,
277 0x10e8, 0x10f0, 0x10f8, 0x1100,
278 0x1104, 0x110c, 0x1110, 0x1118,
279 0x1120, 0x1124, 0x112c, 0x1134,
280 0x1138, 0x1140, 0x1148, 0x114c,
281 0x1154, 0x1158, 0x1160, 0x1168,
282 0x116c, 0x1174, 0x117c, 0x1180,
283 0x1188, 0x1190, 0x1194, 0x119c,
284 0x11a4, 0x11a8, 0x11b0, 0x11b4,
285 0x11bc, 0x11c4, 0x11c8, 0x11d0,
286 0x11d8, 0x11dc, 0x11e4, 0x11ec,
287 0x11f0, 0x11f8, 0x1200, 0x1204,
288 0x120c, 0x1210, 0x1218, 0x121c,
289 0x1224, 0x1228, 0x1230, 0x1238,
290 0x123c, 0x1244, 0x1248, 0x1250,
291 0x1254, 0x125c, 0x1260, 0x1268,
292 0x1270, 0x1274, 0x127c, 0x1280,
293 0x1288, 0x128c, 0x1294, 0x129c,
294 0x12a0, 0x12a8, 0x12ac, 0x12b4,
295 0x12b8, 0x12c0, 0x12c4, 0x12cc,
296 0x12d4, 0x12d8, 0x12e0, 0x12e4,
297 0x12ec, 0x12f0, 0x12f8, 0x1400,
298 0x1404, 0x1408, 0x1410, 0x1414,
299 0x141c, 0x1420, 0x1428, 0x142c,
300 0x1434, 0x1438, 0x1440, 0x1444,
301 0x1448, 0x1450, 0x1454, 0x145c,
302 0x1460, 0x1468, 0x146c, 0x1474,
303 0x1478, 0x1480, 0x1484, 0x1488,
304 0x1490, 0x1494, 0x149c, 0x14a0,
305 0x14a8, 0x14ac, 0x14b4, 0x14b8,
306 0x14c0, 0x14c4, 0x14c8, 0x14d0,
307 0x14d4, 0x14dc, 0x14e0, 0x14e8,
308 0x14ec, 0x14f4, 0x14f8, 0x1500,
309 0x1504, 0x1508, 0x1510, 0x1514,
310 0x1518, 0x1520, 0x1524, 0x1528,
311 0x1530, 0x1534, 0x1538, 0x1540,
312 0x1544, 0x154c, 0x1550, 0x1554,
313 0x155c, 0x1560, 0x1564, 0x156c,
314 0x1570, 0x1574, 0x157c, 0x1580,
315 0x1588, 0x158c, 0x1590, 0x1598,
316 0x159c, 0x15a0, 0x15a8, 0x15ac,
317 0x15b0, 0x15b8, 0x15bc, 0x15c4,
318 0x15c8, 0x15cc, 0x15d4, 0x15d8,
319 0x15dc, 0x15e4, 0x15e8, 0x15ec,
320 0x15f4, 0x15f8, 0x1600, 0x1604,
321 0x1608, 0x160c, 0x1614, 0x1618,
322 0x161c, 0x1620, 0x1628, 0x162c,
323 0x1630, 0x1638, 0x163c, 0x1640,
324 0x1644, 0x164c, 0x1650, 0x1654,
325 0x165c, 0x1660, 0x1664, 0x1668,
326 0x1670, 0x1674, 0x1678, 0x1680,
327 0x1684, 0x1688, 0x168c, 0x1694,
328 0x1698, 0x169c, 0x16a0, 0x16a8,
329 0x16ac, 0x16b0, 0x16b8, 0x16bc,
330 0x16c0, 0x16c4, 0x16cc, 0x16d0,
331 0x16d4, 0x16dc, 0x16e0, 0x16e4,
332 0x16e8, 0x16f0, 0x16f4, 0x16f8,
333 };
334
335 static u_int
336 bell_pitchtokey(pitch)
337 u_int pitch;
338 {
339 int i, oct;
340 u_int key;
341
342 i = 16 * pitch / 440;
343 for (oct = -1; i > 0; i >>= 1, oct++)
344 ;
345
346 i = (pitch * 16 - (440 * (1 << oct))) / (1 << oct);
347 key = (oct << 12) + note[i];
348
349 return key;
350 }
351
352 /*
353 * The next table is a little trikcy table of volume factors.
354 * Its values have been calculated as table[i] = -15 * log10(i/100)
355 * with an obvious exception for i = 0; This log-table converts a linear
356 * volume-scaling (0...100) to a logarithmic scaling as present in the
357 * OPM chips. so: Volume 50% = 6 db.
358 */
359
360 static u_char vol_table[] = {
361 0x7f, 0x35, 0x2d, 0x28, 0x25, 0x22, 0x20, 0x1e,
362 0x1d, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15,
363 0x15, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11,
364 0x10, 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d,
365 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0a,
366 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x08, 0x08,
367 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
368 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05,
369 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
370 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
371 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
372 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
373 0x00, 0x00, 0x00, 0x00, 0x00,
374 };
375
376 void
377 bell_on(sc)
378 register struct bell_softc *sc;
379 {
380 int sps;
381
382 sps = spltty();
383 opm_set_volume(sc->ch, vol_table[sc->volume]);
384 opm_set_key(sc->ch, sc->key);
385 splx(sps);
386
387 opm_key_on(sc->ch);
388 sc->sc_flags |= BELLF_ON;
389 }
390
391 void
392 bell_off(sc)
393 register struct bell_softc *sc;
394 {
395 if (sc->sc_flags & BELLF_ON) {
396 opm_key_off(sc->ch);
397 sc->sc_flags &= ~BELLF_ON;
398 }
399 }
400
401 void
402 opm_bell()
403 {
404 register struct bell_softc *sc = &bell_softc[0];
405 register int ticks;
406 int sps;
407
408 if (sc->msec != 0) {
409 if (sc->sc_flags & BELLF_OUT) {
410 bell_timeout();
411 } else if (sc->sc_flags & BELLF_ON)
412 return;
413
414 ticks = bellmstohz(sc->msec);
415
416 bell_on(sc);
417 sc->sc_flags |= BELLF_OUT;
418
419 timeout(bell_timeout, (caddr_t)NULL, ticks);
420 }
421 }
422
423 static void
424 bell_timeout()
425 {
426 struct bell_softc *sc = &bell_softc[0];
427
428 sc->sc_flags &= ~BELLF_OUT;
429 bell_off(sc);
430 untimeout(bell_timeout, (caddr_t)NULL);
431 }
432
433 void
434 opm_bell_on()
435 {
436 register struct bell_softc *sc = &bell_softc[0];
437
438 if (sc->sc_flags & BELLF_OUT)
439 bell_timeout();
440 if (sc->sc_flags & BELLF_ON)
441 return;
442
443 bell_on(sc);
444 }
445
446 void
447 opm_bell_off()
448 {
449 register struct bell_softc *sc = &bell_softc[0];
450
451 if (sc->sc_flags & BELLF_ON)
452 bell_off(sc);
453 }
454
455 int
456 opm_bell_setup(data)
457 struct bell_info *data;
458 {
459 register struct bell_softc *sc = &bell_softc[0];
460
461 /* bounds check */
462 if (data->pitch > MAXBPITCH || data->pitch < MINBPITCH ||
463 data->volume > MAXBVOLUME || data->msec > MAXBTIME) {
464 return EINVAL;
465 } else {
466 sc->volume = data->volume;
467 sc->pitch = data->pitch;
468 sc->msec = data->msec;
469
470 sc->key = bell_pitchtokey(data->pitch);
471 }
472 return 0;
473 }
474
475 int
476 bellmstohz(m)
477 int m;
478 {
479 extern int hz;
480 register int h = m;
481
482 if (h > 0) {
483 h = h * hz / 1000;
484 if (h == 0)
485 h = 1000 / hz;
486 }
487 return h;
488 }
489
490 #endif
491