Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / x68k / dev / opmbell.c
blob30c956faf9d1d45534ae323772d9375a02f0acaf
1 /* $NetBSD: opmbell.c,v 1.22 2009/01/18 02:40:05 isaki Exp $ */
3 /*
4 * Copyright (c) 1995 MINOURA Makoto, Takuya Harakawa.
5 * All rights reserved.
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.
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.
38 * bell device driver
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: opmbell.c,v 1.22 2009/01/18 02:40:05 isaki Exp $");
44 #include "bell.h"
45 #if NBELL > 0
47 #if NBELL > 1
48 #undef NBELL
49 #define NBELL 1
50 #endif
52 #include <sys/param.h>
53 #include <sys/errno.h>
54 #include <sys/uio.h>
55 #include <sys/device.h>
56 #include <sys/malloc.h>
57 #include <sys/file.h>
58 #include <sys/systm.h>
59 #include <sys/callout.h>
60 #include <sys/conf.h>
61 #include <sys/event.h>
62 #include <sys/kernel.h>
64 #include <machine/opmbellio.h>
66 #include <x68k/dev/opmvar.h>
68 /* In opm.c. */
69 void opm_set_volume(int, int);
70 void opm_set_key(int, int);
71 void opm_set_voice(int, struct opm_voice *);
72 void opm_key_on(u_char);
73 void opm_key_off(u_char);
75 static u_int bell_pitchtokey(u_int);
76 static void bell_timeout(void *);
78 struct bell_softc {
79 int sc_flags;
80 u_char ch;
81 u_char volume;
82 u_int pitch;
83 u_int msec;
84 u_int key;
87 struct bell_softc *bell_softc;
89 callout_t bell_ch;
91 static struct opm_voice vtab[NBELL];
93 static struct opm_voice bell_voice = DEFAULT_BELL_VOICE;
95 /* sc_flags values */
96 #define BELLF_READ 0x01
97 #define BELLF_WRITE 0x02
98 #define BELLF_ALIVE 0x04
99 #define BELLF_OPEN 0x08
100 #define BELLF_OUT 0x10
101 #define BELLF_ON 0x20
103 #define UNIT(x) minor(x)
105 void bell_on(struct bell_softc *);
106 void bell_off(struct bell_softc *);
107 void opm_bell(void);
108 void opm_bell_on(void);
109 void opm_bell_off(void);
110 int opm_bell_setup(struct bell_info *);
111 int bellmstohz(int);
113 void bellattach(int);
115 dev_type_open(bellopen);
116 dev_type_close(bellclose);
117 dev_type_ioctl(bellioctl);
119 const struct cdevsw bell_cdevsw = {
120 bellopen, bellclose, noread, nowrite, bellioctl,
121 nostop, notty, nopoll, nommap, nokqfilter,
124 void
125 bellattach(int num)
127 u_long size;
128 struct bell_softc *sc;
129 int unit;
131 if (num <= 0)
132 return;
133 callout_init(&bell_ch, 0);
134 size = num * sizeof(struct bell_softc);
135 bell_softc = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO);
136 if (bell_softc == NULL) {
137 printf("WARNING: no memory for opm bell\n");
138 return;
141 for (unit = 0; unit < num; unit++) {
142 sc = &bell_softc[unit];
143 sc->sc_flags = BELLF_ALIVE;
144 sc->ch = BELL_CHANNEL;
145 sc->volume = BELL_VOLUME;
146 sc->pitch = BELL_PITCH;
147 sc->msec = BELL_DURATION;
148 sc->key = bell_pitchtokey(sc->pitch);
150 /* setup initial voice parameter */
151 memcpy(&vtab[unit], &bell_voice, sizeof(bell_voice));
152 opm_set_voice(sc->ch, &vtab[unit]);
154 printf("bell%d: YM2151 OPM bell emulation.\n", unit);
159 bellopen(dev_t dev, int flags, int mode, struct lwp *l)
161 int unit = UNIT(dev);
162 struct bell_softc *sc = &bell_softc[unit];
164 if (unit >= NBELL || !(sc->sc_flags & BELLF_ALIVE))
165 return ENXIO;
167 if (sc->sc_flags & BELLF_OPEN)
168 return EBUSY;
170 sc->sc_flags |= BELLF_OPEN;
171 sc->sc_flags |= (flags & (FREAD | FWRITE));
173 return 0;
177 bellclose(dev_t dev, int flags, int mode, struct lwp *l)
179 int unit = UNIT(dev);
180 struct bell_softc *sc = &bell_softc[unit];
182 sc->sc_flags &= ~BELLF_OPEN;
183 return 0;
187 bellioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
189 int unit = UNIT(dev);
190 struct bell_softc *sc = &bell_softc[unit];
192 switch (cmd) {
193 case BELLIOCGPARAM:
195 struct bell_info *bp = (struct bell_info *)addr;
196 if (!(sc->sc_flags & FREAD))
197 return EBADF;
199 bp->volume = sc->volume;
200 bp->pitch = sc->pitch;
201 bp->msec = sc->msec;
202 break;
205 case BELLIOCSPARAM:
207 struct bell_info *bp = (struct bell_info *)addr;
209 if (!(sc->sc_flags & FWRITE))
210 return EBADF;
212 return opm_bell_setup(bp);
215 case BELLIOCGVOICE:
216 if (!(sc->sc_flags & FREAD))
217 return EBADF;
219 if (addr == NULL)
220 return EFAULT;
222 memcpy(addr, &vtab[unit], sizeof(struct opm_voice));
223 break;
225 case BELLIOCSVOICE:
226 if (!(sc->sc_flags & FWRITE))
227 return EBADF;
229 if (addr == NULL)
230 return EFAULT;
232 memcpy(&vtab[unit], addr, sizeof(struct opm_voice));
233 opm_set_voice(sc->ch, &vtab[unit]);
234 break;
236 default:
237 return EINVAL;
239 return 0;
243 * The next table is used for calculating KeyCode/KeyFraction pair
244 * from frequency.
247 static u_int note[] = {
248 0x0800, 0x0808, 0x0810, 0x081c,
249 0x0824, 0x0830, 0x0838, 0x0844,
250 0x084c, 0x0858, 0x0860, 0x086c,
251 0x0874, 0x0880, 0x0888, 0x0890,
252 0x089c, 0x08a4, 0x08b0, 0x08b8,
253 0x08c4, 0x08cc, 0x08d8, 0x08e0,
254 0x08ec, 0x08f4, 0x0900, 0x0908,
255 0x0910, 0x091c, 0x0924, 0x092c,
256 0x0938, 0x0940, 0x0948, 0x0954,
257 0x095c, 0x0968, 0x0970, 0x0978,
258 0x0984, 0x098c, 0x0994, 0x09a0,
259 0x09a8, 0x09b4, 0x09bc, 0x09c4,
260 0x09d0, 0x09d8, 0x09e0, 0x09ec,
261 0x09f4, 0x0a00, 0x0a08, 0x0a10,
262 0x0a18, 0x0a20, 0x0a28, 0x0a30,
263 0x0a38, 0x0a44, 0x0a4c, 0x0a54,
264 0x0a5c, 0x0a64, 0x0a6c, 0x0a74,
265 0x0a80, 0x0a88, 0x0a90, 0x0a98,
266 0x0aa0, 0x0aa8, 0x0ab0, 0x0ab8,
267 0x0ac4, 0x0acc, 0x0ad4, 0x0adc,
268 0x0ae4, 0x0aec, 0x0af4, 0x0c00,
269 0x0c08, 0x0c10, 0x0c18, 0x0c20,
270 0x0c28, 0x0c30, 0x0c38, 0x0c40,
271 0x0c48, 0x0c50, 0x0c58, 0x0c60,
272 0x0c68, 0x0c70, 0x0c78, 0x0c84,
273 0x0c8c, 0x0c94, 0x0c9c, 0x0ca4,
274 0x0cac, 0x0cb4, 0x0cbc, 0x0cc4,
275 0x0ccc, 0x0cd4, 0x0cdc, 0x0ce4,
276 0x0cec, 0x0cf4, 0x0d00, 0x0d04,
277 0x0d0c, 0x0d14, 0x0d1c, 0x0d24,
278 0x0d2c, 0x0d34, 0x0d3c, 0x0d44,
279 0x0d4c, 0x0d54, 0x0d5c, 0x0d64,
280 0x0d6c, 0x0d74, 0x0d7c, 0x0d80,
281 0x0d88, 0x0d90, 0x0d98, 0x0da0,
282 0x0da8, 0x0db0, 0x0db8, 0x0dc0,
283 0x0dc8, 0x0dd0, 0x0dd8, 0x0de0,
284 0x0de8, 0x0df0, 0x0df8, 0x0e00,
285 0x0e04, 0x0e0c, 0x0e14, 0x0e1c,
286 0x0e24, 0x0e28, 0x0e30, 0x0e38,
287 0x0e40, 0x0e48, 0x0e50, 0x0e54,
288 0x0e5c, 0x0e64, 0x0e6c, 0x0e74,
289 0x0e7c, 0x0e80, 0x0e88, 0x0e90,
290 0x0e98, 0x0ea0, 0x0ea8, 0x0eac,
291 0x0eb4, 0x0ebc, 0x0ec4, 0x0ecc,
292 0x0ed4, 0x0ed8, 0x0ee0, 0x0ee8,
293 0x0ef0, 0x0ef8, 0x1000, 0x1004,
294 0x100c, 0x1014, 0x1018, 0x1020,
295 0x1028, 0x1030, 0x1034, 0x103c,
296 0x1044, 0x104c, 0x1050, 0x1058,
297 0x1060, 0x1064, 0x106c, 0x1074,
298 0x107c, 0x1080, 0x1088, 0x1090,
299 0x1098, 0x109c, 0x10a4, 0x10ac,
300 0x10b0, 0x10b8, 0x10c0, 0x10c8,
301 0x10cc, 0x10d4, 0x10dc, 0x10e4,
302 0x10e8, 0x10f0, 0x10f8, 0x1100,
303 0x1104, 0x110c, 0x1110, 0x1118,
304 0x1120, 0x1124, 0x112c, 0x1134,
305 0x1138, 0x1140, 0x1148, 0x114c,
306 0x1154, 0x1158, 0x1160, 0x1168,
307 0x116c, 0x1174, 0x117c, 0x1180,
308 0x1188, 0x1190, 0x1194, 0x119c,
309 0x11a4, 0x11a8, 0x11b0, 0x11b4,
310 0x11bc, 0x11c4, 0x11c8, 0x11d0,
311 0x11d8, 0x11dc, 0x11e4, 0x11ec,
312 0x11f0, 0x11f8, 0x1200, 0x1204,
313 0x120c, 0x1210, 0x1218, 0x121c,
314 0x1224, 0x1228, 0x1230, 0x1238,
315 0x123c, 0x1244, 0x1248, 0x1250,
316 0x1254, 0x125c, 0x1260, 0x1268,
317 0x1270, 0x1274, 0x127c, 0x1280,
318 0x1288, 0x128c, 0x1294, 0x129c,
319 0x12a0, 0x12a8, 0x12ac, 0x12b4,
320 0x12b8, 0x12c0, 0x12c4, 0x12cc,
321 0x12d4, 0x12d8, 0x12e0, 0x12e4,
322 0x12ec, 0x12f0, 0x12f8, 0x1400,
323 0x1404, 0x1408, 0x1410, 0x1414,
324 0x141c, 0x1420, 0x1428, 0x142c,
325 0x1434, 0x1438, 0x1440, 0x1444,
326 0x1448, 0x1450, 0x1454, 0x145c,
327 0x1460, 0x1468, 0x146c, 0x1474,
328 0x1478, 0x1480, 0x1484, 0x1488,
329 0x1490, 0x1494, 0x149c, 0x14a0,
330 0x14a8, 0x14ac, 0x14b4, 0x14b8,
331 0x14c0, 0x14c4, 0x14c8, 0x14d0,
332 0x14d4, 0x14dc, 0x14e0, 0x14e8,
333 0x14ec, 0x14f4, 0x14f8, 0x1500,
334 0x1504, 0x1508, 0x1510, 0x1514,
335 0x1518, 0x1520, 0x1524, 0x1528,
336 0x1530, 0x1534, 0x1538, 0x1540,
337 0x1544, 0x154c, 0x1550, 0x1554,
338 0x155c, 0x1560, 0x1564, 0x156c,
339 0x1570, 0x1574, 0x157c, 0x1580,
340 0x1588, 0x158c, 0x1590, 0x1598,
341 0x159c, 0x15a0, 0x15a8, 0x15ac,
342 0x15b0, 0x15b8, 0x15bc, 0x15c4,
343 0x15c8, 0x15cc, 0x15d4, 0x15d8,
344 0x15dc, 0x15e4, 0x15e8, 0x15ec,
345 0x15f4, 0x15f8, 0x1600, 0x1604,
346 0x1608, 0x160c, 0x1614, 0x1618,
347 0x161c, 0x1620, 0x1628, 0x162c,
348 0x1630, 0x1638, 0x163c, 0x1640,
349 0x1644, 0x164c, 0x1650, 0x1654,
350 0x165c, 0x1660, 0x1664, 0x1668,
351 0x1670, 0x1674, 0x1678, 0x1680,
352 0x1684, 0x1688, 0x168c, 0x1694,
353 0x1698, 0x169c, 0x16a0, 0x16a8,
354 0x16ac, 0x16b0, 0x16b8, 0x16bc,
355 0x16c0, 0x16c4, 0x16cc, 0x16d0,
356 0x16d4, 0x16dc, 0x16e0, 0x16e4,
357 0x16e8, 0x16f0, 0x16f4, 0x16f8,
360 static u_int
361 bell_pitchtokey(u_int pitch)
363 int i, oct;
364 u_int key;
366 i = 16 * pitch / 440;
367 for (oct = -1; i > 0; i >>= 1, oct++)
370 i = (pitch * 16 - (440 * (1 << oct))) / (1 << oct);
371 key = (oct << 12) + note[i];
373 return key;
377 * The next table is a little trikcy table of volume factors.
378 * Its values have been calculated as table[i] = -15 * log10(i/100)
379 * with an obvious exception for i = 0; This log-table converts a linear
380 * volume-scaling (0...100) to a logarithmic scaling as present in the
381 * OPM chips. so: Volume 50% = 6 db.
384 static u_char vol_table[] = {
385 0x7f, 0x35, 0x2d, 0x28, 0x25, 0x22, 0x20, 0x1e,
386 0x1d, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15,
387 0x15, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11,
388 0x10, 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d,
389 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0a,
390 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x08, 0x08,
391 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
392 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05,
393 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
394 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
395 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
396 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
397 0x00, 0x00, 0x00, 0x00, 0x00,
400 void
401 bell_on(struct bell_softc *sc)
403 int sps;
405 sps = spltty();
406 opm_set_volume(sc->ch, vol_table[sc->volume]);
407 opm_set_key(sc->ch, sc->key);
408 splx(sps);
410 opm_key_on(sc->ch);
411 sc->sc_flags |= BELLF_ON;
414 void
415 bell_off(struct bell_softc *sc)
417 if (sc->sc_flags & BELLF_ON) {
418 opm_key_off(sc->ch);
419 sc->sc_flags &= ~BELLF_ON;
423 void
424 opm_bell(void)
426 struct bell_softc *sc = &bell_softc[0];
427 int ticks;
429 if (sc->msec != 0) {
430 if (sc->sc_flags & BELLF_OUT) {
431 bell_timeout(0);
432 } else if (sc->sc_flags & BELLF_ON)
433 return;
435 ticks = bellmstohz(sc->msec);
437 bell_on(sc);
438 sc->sc_flags |= BELLF_OUT;
440 callout_reset(&bell_ch, ticks, bell_timeout, NULL);
444 static void
445 bell_timeout(void *arg)
447 struct bell_softc *sc = &bell_softc[0];
449 sc->sc_flags &= ~BELLF_OUT;
450 bell_off(sc);
451 callout_stop(&bell_ch);
454 void
455 opm_bell_on(void)
457 struct bell_softc *sc = &bell_softc[0];
459 if (sc->sc_flags & BELLF_OUT)
460 bell_timeout(0);
461 if (sc->sc_flags & BELLF_ON)
462 return;
464 bell_on(sc);
467 void
468 opm_bell_off(void)
470 struct bell_softc *sc = &bell_softc[0];
472 if (sc->sc_flags & BELLF_ON)
473 bell_off(sc);
477 opm_bell_setup(struct bell_info *data)
479 struct bell_softc *sc = &bell_softc[0];
481 /* bounds check */
482 if (data->pitch > MAXBPITCH || data->pitch < MINBPITCH ||
483 data->volume > MAXBVOLUME || data->msec > MAXBTIME) {
484 return EINVAL;
485 } else {
486 sc->volume = data->volume;
487 sc->pitch = data->pitch;
488 sc->msec = data->msec;
489 sc->key = bell_pitchtokey(data->pitch);
491 return 0;
495 bellmstohz(int m)
497 int h = m;
499 if (h > 0) {
500 h = h * hz / 1000;
501 if (h == 0)
502 h = 1000 / hz;
504 return h;
507 #endif