xref: /netbsd-src/sys/arch/x68k/dev/opmbell.c (revision d47bcd296c8b39243dd81e9cc75ea86330d4eeaf)
1*d47bcd29Schs /*	$NetBSD: opmbell.c,v 1.28 2019/11/10 21:16:33 chs Exp $	*/
2320e7320Soki 
3320e7320Soki /*
4320e7320Soki  * Copyright (c) 1995 MINOURA Makoto, Takuya Harakawa.
5320e7320Soki  * All rights reserved.
6320e7320Soki  *
7320e7320Soki  * Redistribution and use in source and binary forms, with or without
8320e7320Soki  * modification, are permitted provided that the following conditions
9320e7320Soki  * are met:
10320e7320Soki  * 1. Redistributions of source code must retain the above copyright
11320e7320Soki  *    notice, this list of conditions and the following disclaimer.
12320e7320Soki  * 2. Redistributions in binary form must reproduce the above copyright
13320e7320Soki  *    notice, this list of conditions and the following disclaimer in the
14320e7320Soki  *    documentation and/or other materials provided with the distribution.
15320e7320Soki  * 3. All advertising materials mentioning features or use of this software
16320e7320Soki  *    must display the following acknowledgement:
17320e7320Soki  *	This product includes software developed by MINOURA Makoto,
18320e7320Soki  *	Takuya Harakawa.
19320e7320Soki  * 4. Neither the name of the authors may be used to endorse or promote
20320e7320Soki  *    products derived from this software without specific prior written
21320e7320Soki  *    permission.
22320e7320Soki  *
23320e7320Soki  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24320e7320Soki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25320e7320Soki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26320e7320Soki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27320e7320Soki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28320e7320Soki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29320e7320Soki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30320e7320Soki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31320e7320Soki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32320e7320Soki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33320e7320Soki  * SUCH DAMAGE.
34320e7320Soki  *
35320e7320Soki  */
36320e7320Soki 
37320e7320Soki /*
38320e7320Soki  * bell device driver
39320e7320Soki  */
40320e7320Soki 
41ab48a212Slukem #include <sys/cdefs.h>
42*d47bcd29Schs __KERNEL_RCSID(0, "$NetBSD: opmbell.c,v 1.28 2019/11/10 21:16:33 chs Exp $");
43ab48a212Slukem 
44320e7320Soki #include "bell.h"
45320e7320Soki #if NBELL > 0
46320e7320Soki 
47320e7320Soki #if NBELL > 1
48320e7320Soki #undef NBELL
49320e7320Soki #define NBELL 1
50320e7320Soki #endif
51320e7320Soki 
52320e7320Soki #include <sys/param.h>
53320e7320Soki #include <sys/errno.h>
54320e7320Soki #include <sys/uio.h>
55320e7320Soki #include <sys/device.h>
56320e7320Soki #include <sys/malloc.h>
57320e7320Soki #include <sys/file.h>
58320e7320Soki #include <sys/systm.h>
597b918b40Sthorpej #include <sys/callout.h>
60fd9fae64Soki #include <sys/conf.h>
61e0cc03a0Sjdolecek #include <sys/event.h>
62e1947f9eSisaki #include <sys/kernel.h>
63320e7320Soki 
64320e7320Soki #include <machine/opmbellio.h>
6569153277Sminoura 
6669153277Sminoura #include <x68k/dev/opmvar.h>
67320e7320Soki 
68586ab731Schristos #include "ioconf.h"
69e7ae23fdSchristos 
70a76b0b1bSminoura /* In opm.c. */
71d57ca0cfSchs void opm_set_volume(int, int);
72d57ca0cfSchs void opm_set_key(int, int);
73d57ca0cfSchs void opm_set_voice(int, struct opm_voice *);
74d57ca0cfSchs void opm_key_on(u_char);
75d57ca0cfSchs void opm_key_off(u_char);
76a76b0b1bSminoura 
77d57ca0cfSchs static u_int bell_pitchtokey(u_int);
78d57ca0cfSchs static void bell_timeout(void *);
79320e7320Soki 
80320e7320Soki struct bell_softc {
81320e7320Soki 	int sc_flags;
82320e7320Soki 	u_char ch;
83320e7320Soki 	u_char volume;
84320e7320Soki 	u_int pitch;
85320e7320Soki 	u_int msec;
86320e7320Soki 	u_int key;
87320e7320Soki };
88320e7320Soki 
89320e7320Soki struct bell_softc *bell_softc;
90320e7320Soki 
9188ab7da9Sad callout_t bell_ch;
927b918b40Sthorpej 
93320e7320Soki static struct opm_voice vtab[NBELL];
94320e7320Soki 
9569153277Sminoura static struct opm_voice bell_voice = DEFAULT_BELL_VOICE;
9669153277Sminoura 
97320e7320Soki /* sc_flags values */
98320e7320Soki #define	BELLF_READ	0x01
99320e7320Soki #define	BELLF_WRITE	0x02
100320e7320Soki #define	BELLF_ALIVE	0x04
101320e7320Soki #define	BELLF_OPEN	0x08
102320e7320Soki #define BELLF_OUT	0x10
103320e7320Soki #define BELLF_ON	0x20
104320e7320Soki 
105320e7320Soki #define UNIT(x)		minor(x)
106320e7320Soki 
107d57ca0cfSchs void bell_on(struct bell_softc *);
108d57ca0cfSchs void bell_off(struct bell_softc *);
109d57ca0cfSchs void opm_bell(void);
110d57ca0cfSchs void opm_bell_on(void);
111d57ca0cfSchs void opm_bell_off(void);
112d57ca0cfSchs int opm_bell_setup(struct bell_info *);
113d57ca0cfSchs int bellmstohz(int);
114fd9fae64Soki 
11577a6b82bSgehenna dev_type_open(bellopen);
11677a6b82bSgehenna dev_type_close(bellclose);
11777a6b82bSgehenna dev_type_ioctl(bellioctl);
11877a6b82bSgehenna 
11977a6b82bSgehenna const struct cdevsw bell_cdevsw = {
120a68f9396Sdholland 	.d_open = bellopen,
121a68f9396Sdholland 	.d_close = bellclose,
122a68f9396Sdholland 	.d_read = noread,
123a68f9396Sdholland 	.d_write = nowrite,
124a68f9396Sdholland 	.d_ioctl = bellioctl,
125a68f9396Sdholland 	.d_stop = nostop,
126a68f9396Sdholland 	.d_tty = notty,
127a68f9396Sdholland 	.d_poll = nopoll,
128a68f9396Sdholland 	.d_mmap = nommap,
129a68f9396Sdholland 	.d_kqfilter = nokqfilter,
130f9228f42Sdholland 	.d_discard = nodiscard,
131a68f9396Sdholland 	.d_flag = 0
13277a6b82bSgehenna };
13377a6b82bSgehenna 
13430ec7d2cSoki void
bellattach(int num)135d57ca0cfSchs bellattach(int num)
136320e7320Soki {
137d57ca0cfSchs 	u_long size;
138d57ca0cfSchs 	struct bell_softc *sc;
139320e7320Soki 	int unit;
140320e7320Soki 
141320e7320Soki 	if (num <= 0)
142320e7320Soki 		return;
14388ab7da9Sad 	callout_init(&bell_ch, 0);
144320e7320Soki 	size = num * sizeof(struct bell_softc);
145*d47bcd29Schs 	bell_softc = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
146320e7320Soki 	for (unit = 0; unit < num; unit++) {
147320e7320Soki 		sc = &bell_softc[unit];
148320e7320Soki 		sc->sc_flags = BELLF_ALIVE;
149320e7320Soki 		sc->ch = BELL_CHANNEL;
150320e7320Soki 		sc->volume = BELL_VOLUME;
151320e7320Soki 		sc->pitch = BELL_PITCH;
152320e7320Soki 		sc->msec = BELL_DURATION;
153320e7320Soki 		sc->key = bell_pitchtokey(sc->pitch);
154320e7320Soki 
155320e7320Soki 		/* setup initial voice parameter */
1565514d0b1Swiz 		memcpy(&vtab[unit], &bell_voice, sizeof(bell_voice));
157320e7320Soki 		opm_set_voice(sc->ch, &vtab[unit]);
158320e7320Soki 
159e37692f0Schristos 		printf("bell%d: YM2151 OPM bell emulation.\n", unit);
160320e7320Soki 	}
161320e7320Soki }
162320e7320Soki 
163320e7320Soki int
bellopen(dev_t dev,int flags,int mode,struct lwp * l)16495e1ffb1Schristos bellopen(dev_t dev, int flags, int mode, struct lwp *l)
165320e7320Soki {
166d57ca0cfSchs 	int unit = UNIT(dev);
167d57ca0cfSchs 	struct bell_softc *sc = &bell_softc[unit];
168320e7320Soki 
169320e7320Soki 	if (unit >= NBELL || !(sc->sc_flags & BELLF_ALIVE))
170320e7320Soki 		return ENXIO;
171320e7320Soki 
172320e7320Soki 	if (sc->sc_flags & BELLF_OPEN)
173320e7320Soki 		return EBUSY;
174320e7320Soki 
175320e7320Soki 	sc->sc_flags |= BELLF_OPEN;
176320e7320Soki 	sc->sc_flags |= (flags & (FREAD | FWRITE));
177320e7320Soki 
178320e7320Soki 	return 0;
179320e7320Soki }
180320e7320Soki 
181fd9fae64Soki int
bellclose(dev_t dev,int flags,int mode,struct lwp * l)18295e1ffb1Schristos bellclose(dev_t dev, int flags, int mode, struct lwp *l)
183320e7320Soki {
184320e7320Soki 	int unit = UNIT(dev);
185320e7320Soki 	struct bell_softc *sc = &bell_softc[unit];
186320e7320Soki 
187320e7320Soki 	sc->sc_flags &= ~BELLF_OPEN;
188fd9fae64Soki 	return 0;
189320e7320Soki }
190320e7320Soki 
191320e7320Soki int
bellioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)19253524e44Schristos bellioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
193320e7320Soki {
194320e7320Soki 	int unit = UNIT(dev);
195320e7320Soki 	struct bell_softc *sc = &bell_softc[unit];
196320e7320Soki 
197320e7320Soki 	switch (cmd) {
198320e7320Soki 	case BELLIOCGPARAM:
199320e7320Soki 	  {
200320e7320Soki 		struct bell_info *bp = (struct bell_info *)addr;
201320e7320Soki 		if (!(sc->sc_flags & FREAD))
202320e7320Soki 			return EBADF;
203320e7320Soki 
204320e7320Soki 		bp->volume = sc->volume;
205320e7320Soki 		bp->pitch = sc->pitch;
206320e7320Soki 		bp->msec = sc->msec;
207320e7320Soki 		break;
208320e7320Soki 	  }
209320e7320Soki 
210320e7320Soki 	case BELLIOCSPARAM:
211320e7320Soki 	  {
212320e7320Soki 		struct bell_info *bp = (struct bell_info *)addr;
213320e7320Soki 
214320e7320Soki 		if (!(sc->sc_flags & FWRITE))
215320e7320Soki 			return EBADF;
216320e7320Soki 
217320e7320Soki 		return opm_bell_setup(bp);
218320e7320Soki 	  }
219320e7320Soki 
220320e7320Soki 	case BELLIOCGVOICE:
221320e7320Soki 		if (!(sc->sc_flags & FREAD))
222320e7320Soki 			return EBADF;
223320e7320Soki 
224320e7320Soki 		if (addr == NULL)
225320e7320Soki 			return EFAULT;
226320e7320Soki 
2275514d0b1Swiz 		memcpy(addr, &vtab[unit], sizeof(struct opm_voice));
228320e7320Soki 		break;
229320e7320Soki 
230320e7320Soki 	case BELLIOCSVOICE:
231320e7320Soki 		if (!(sc->sc_flags & FWRITE))
232320e7320Soki 			return EBADF;
233320e7320Soki 
234320e7320Soki 		if (addr == NULL)
235320e7320Soki 			return EFAULT;
236320e7320Soki 
2375514d0b1Swiz 		memcpy(&vtab[unit], addr, sizeof(struct opm_voice));
238320e7320Soki 		opm_set_voice(sc->ch, &vtab[unit]);
239320e7320Soki 		break;
240320e7320Soki 
241320e7320Soki 	default:
242320e7320Soki 		return EINVAL;
243320e7320Soki 	}
244320e7320Soki 	return 0;
245320e7320Soki }
246320e7320Soki 
247320e7320Soki /*
248320e7320Soki  * The next table is used for calculating KeyCode/KeyFraction pair
249320e7320Soki  * from frequency.
250320e7320Soki  */
251320e7320Soki 
252320e7320Soki static u_int note[] = {
253320e7320Soki 	0x0800, 0x0808, 0x0810, 0x081c,
254320e7320Soki 	0x0824, 0x0830, 0x0838, 0x0844,
255320e7320Soki 	0x084c, 0x0858, 0x0860, 0x086c,
256320e7320Soki 	0x0874, 0x0880, 0x0888, 0x0890,
257320e7320Soki 	0x089c, 0x08a4, 0x08b0, 0x08b8,
258320e7320Soki 	0x08c4, 0x08cc, 0x08d8, 0x08e0,
259320e7320Soki 	0x08ec, 0x08f4, 0x0900, 0x0908,
260320e7320Soki 	0x0910, 0x091c, 0x0924, 0x092c,
261320e7320Soki 	0x0938, 0x0940, 0x0948, 0x0954,
262320e7320Soki 	0x095c, 0x0968, 0x0970, 0x0978,
263320e7320Soki 	0x0984, 0x098c, 0x0994, 0x09a0,
264320e7320Soki 	0x09a8, 0x09b4, 0x09bc, 0x09c4,
265320e7320Soki 	0x09d0, 0x09d8, 0x09e0, 0x09ec,
266320e7320Soki 	0x09f4, 0x0a00, 0x0a08, 0x0a10,
267320e7320Soki 	0x0a18, 0x0a20, 0x0a28, 0x0a30,
268320e7320Soki 	0x0a38, 0x0a44, 0x0a4c, 0x0a54,
269320e7320Soki 	0x0a5c, 0x0a64, 0x0a6c, 0x0a74,
270320e7320Soki 	0x0a80, 0x0a88, 0x0a90, 0x0a98,
271320e7320Soki 	0x0aa0, 0x0aa8, 0x0ab0, 0x0ab8,
272320e7320Soki 	0x0ac4, 0x0acc, 0x0ad4, 0x0adc,
273320e7320Soki 	0x0ae4, 0x0aec, 0x0af4, 0x0c00,
274320e7320Soki 	0x0c08, 0x0c10, 0x0c18, 0x0c20,
275320e7320Soki 	0x0c28, 0x0c30, 0x0c38, 0x0c40,
276320e7320Soki 	0x0c48, 0x0c50, 0x0c58, 0x0c60,
277320e7320Soki 	0x0c68, 0x0c70, 0x0c78, 0x0c84,
278320e7320Soki 	0x0c8c, 0x0c94, 0x0c9c, 0x0ca4,
279320e7320Soki 	0x0cac, 0x0cb4, 0x0cbc, 0x0cc4,
280320e7320Soki 	0x0ccc, 0x0cd4, 0x0cdc, 0x0ce4,
281320e7320Soki 	0x0cec, 0x0cf4, 0x0d00, 0x0d04,
282320e7320Soki 	0x0d0c, 0x0d14, 0x0d1c, 0x0d24,
283320e7320Soki 	0x0d2c, 0x0d34, 0x0d3c, 0x0d44,
284320e7320Soki 	0x0d4c, 0x0d54, 0x0d5c, 0x0d64,
285320e7320Soki 	0x0d6c, 0x0d74, 0x0d7c, 0x0d80,
286320e7320Soki 	0x0d88, 0x0d90, 0x0d98, 0x0da0,
287320e7320Soki 	0x0da8, 0x0db0, 0x0db8, 0x0dc0,
288320e7320Soki 	0x0dc8, 0x0dd0, 0x0dd8, 0x0de0,
289320e7320Soki 	0x0de8, 0x0df0, 0x0df8, 0x0e00,
290320e7320Soki 	0x0e04, 0x0e0c, 0x0e14, 0x0e1c,
291320e7320Soki 	0x0e24, 0x0e28, 0x0e30, 0x0e38,
292320e7320Soki 	0x0e40, 0x0e48, 0x0e50, 0x0e54,
293320e7320Soki 	0x0e5c, 0x0e64, 0x0e6c, 0x0e74,
294320e7320Soki 	0x0e7c, 0x0e80, 0x0e88, 0x0e90,
295320e7320Soki 	0x0e98, 0x0ea0, 0x0ea8, 0x0eac,
296320e7320Soki 	0x0eb4, 0x0ebc, 0x0ec4, 0x0ecc,
297320e7320Soki 	0x0ed4, 0x0ed8, 0x0ee0, 0x0ee8,
298320e7320Soki 	0x0ef0, 0x0ef8, 0x1000, 0x1004,
299320e7320Soki 	0x100c, 0x1014, 0x1018, 0x1020,
300320e7320Soki 	0x1028, 0x1030, 0x1034, 0x103c,
301320e7320Soki 	0x1044, 0x104c, 0x1050, 0x1058,
302320e7320Soki 	0x1060, 0x1064, 0x106c, 0x1074,
303320e7320Soki 	0x107c, 0x1080, 0x1088, 0x1090,
304320e7320Soki 	0x1098, 0x109c, 0x10a4, 0x10ac,
305320e7320Soki 	0x10b0, 0x10b8, 0x10c0, 0x10c8,
306320e7320Soki 	0x10cc, 0x10d4, 0x10dc, 0x10e4,
307320e7320Soki 	0x10e8, 0x10f0, 0x10f8, 0x1100,
308320e7320Soki 	0x1104, 0x110c, 0x1110, 0x1118,
309320e7320Soki 	0x1120, 0x1124, 0x112c, 0x1134,
310320e7320Soki 	0x1138, 0x1140, 0x1148, 0x114c,
311320e7320Soki 	0x1154, 0x1158, 0x1160, 0x1168,
312320e7320Soki 	0x116c, 0x1174, 0x117c, 0x1180,
313320e7320Soki 	0x1188, 0x1190, 0x1194, 0x119c,
314320e7320Soki 	0x11a4, 0x11a8, 0x11b0, 0x11b4,
315320e7320Soki 	0x11bc, 0x11c4, 0x11c8, 0x11d0,
316320e7320Soki 	0x11d8, 0x11dc, 0x11e4, 0x11ec,
317320e7320Soki 	0x11f0, 0x11f8, 0x1200, 0x1204,
318320e7320Soki 	0x120c, 0x1210, 0x1218, 0x121c,
319320e7320Soki 	0x1224, 0x1228, 0x1230, 0x1238,
320320e7320Soki 	0x123c, 0x1244, 0x1248, 0x1250,
321320e7320Soki 	0x1254, 0x125c, 0x1260, 0x1268,
322320e7320Soki 	0x1270, 0x1274, 0x127c, 0x1280,
323320e7320Soki 	0x1288, 0x128c, 0x1294, 0x129c,
324320e7320Soki 	0x12a0, 0x12a8, 0x12ac, 0x12b4,
325320e7320Soki 	0x12b8, 0x12c0, 0x12c4, 0x12cc,
326320e7320Soki 	0x12d4, 0x12d8, 0x12e0, 0x12e4,
327320e7320Soki 	0x12ec, 0x12f0, 0x12f8, 0x1400,
328320e7320Soki 	0x1404, 0x1408, 0x1410, 0x1414,
329320e7320Soki 	0x141c, 0x1420, 0x1428, 0x142c,
330320e7320Soki 	0x1434, 0x1438, 0x1440, 0x1444,
331320e7320Soki 	0x1448, 0x1450, 0x1454, 0x145c,
332320e7320Soki 	0x1460, 0x1468, 0x146c, 0x1474,
333320e7320Soki 	0x1478, 0x1480, 0x1484, 0x1488,
334320e7320Soki 	0x1490, 0x1494, 0x149c, 0x14a0,
335320e7320Soki 	0x14a8, 0x14ac, 0x14b4, 0x14b8,
336320e7320Soki 	0x14c0, 0x14c4, 0x14c8, 0x14d0,
337320e7320Soki 	0x14d4, 0x14dc, 0x14e0, 0x14e8,
338320e7320Soki 	0x14ec, 0x14f4, 0x14f8, 0x1500,
339320e7320Soki 	0x1504, 0x1508, 0x1510, 0x1514,
340320e7320Soki 	0x1518, 0x1520, 0x1524, 0x1528,
341320e7320Soki 	0x1530, 0x1534, 0x1538, 0x1540,
342320e7320Soki 	0x1544, 0x154c, 0x1550, 0x1554,
343320e7320Soki 	0x155c, 0x1560, 0x1564, 0x156c,
344320e7320Soki 	0x1570, 0x1574, 0x157c, 0x1580,
345320e7320Soki 	0x1588, 0x158c, 0x1590, 0x1598,
346320e7320Soki 	0x159c, 0x15a0, 0x15a8, 0x15ac,
347320e7320Soki 	0x15b0, 0x15b8, 0x15bc, 0x15c4,
348320e7320Soki 	0x15c8, 0x15cc, 0x15d4, 0x15d8,
349320e7320Soki 	0x15dc, 0x15e4, 0x15e8, 0x15ec,
350320e7320Soki 	0x15f4, 0x15f8, 0x1600, 0x1604,
351320e7320Soki 	0x1608, 0x160c, 0x1614, 0x1618,
352320e7320Soki 	0x161c, 0x1620, 0x1628, 0x162c,
353320e7320Soki 	0x1630, 0x1638, 0x163c, 0x1640,
354320e7320Soki 	0x1644, 0x164c, 0x1650, 0x1654,
355320e7320Soki 	0x165c, 0x1660, 0x1664, 0x1668,
356320e7320Soki 	0x1670, 0x1674, 0x1678, 0x1680,
357320e7320Soki 	0x1684, 0x1688, 0x168c, 0x1694,
358320e7320Soki 	0x1698, 0x169c, 0x16a0, 0x16a8,
359320e7320Soki 	0x16ac, 0x16b0, 0x16b8, 0x16bc,
360320e7320Soki 	0x16c0, 0x16c4, 0x16cc, 0x16d0,
361320e7320Soki 	0x16d4, 0x16dc, 0x16e0, 0x16e4,
362320e7320Soki 	0x16e8, 0x16f0, 0x16f4, 0x16f8,
363320e7320Soki };
364320e7320Soki 
365320e7320Soki static u_int
bell_pitchtokey(u_int pitch)366d57ca0cfSchs bell_pitchtokey(u_int pitch)
367320e7320Soki {
368320e7320Soki 	int i, oct;
369320e7320Soki 	u_int key;
370320e7320Soki 
371320e7320Soki 	i = 16 * pitch / 440;
372320e7320Soki 	for (oct = -1; i > 0; i >>= 1, oct++)
373320e7320Soki 		;
374320e7320Soki 
375320e7320Soki 	i  = (pitch * 16 - (440 * (1 << oct))) / (1 << oct);
376320e7320Soki 	key = (oct << 12) + note[i];
377320e7320Soki 
378320e7320Soki 	return key;
379320e7320Soki }
380320e7320Soki 
381320e7320Soki /*
382320e7320Soki  * The next table is a little trikcy table of volume factors.
383320e7320Soki  * Its values have been calculated as table[i] = -15 * log10(i/100)
384320e7320Soki  * with an obvious exception for i = 0; This log-table converts a linear
385320e7320Soki  * volume-scaling (0...100) to a logarithmic scaling as present in the
386320e7320Soki  * OPM chips. so: Volume 50% = 6 db.
387320e7320Soki  */
388320e7320Soki 
389320e7320Soki static u_char vol_table[] = {
390320e7320Soki 	0x7f, 0x35, 0x2d, 0x28, 0x25, 0x22, 0x20, 0x1e,
391320e7320Soki 	0x1d, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15,
392320e7320Soki 	0x15, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11,
393320e7320Soki 	0x10, 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d,
394320e7320Soki 	0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0a,
395320e7320Soki 	0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x08, 0x08,
396320e7320Soki 	0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
397320e7320Soki 	0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05,
398320e7320Soki 	0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
399320e7320Soki 	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
400320e7320Soki 	0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
401320e7320Soki 	0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
402320e7320Soki 	0x00, 0x00, 0x00, 0x00, 0x00,
403320e7320Soki };
404320e7320Soki 
405320e7320Soki void
bell_on(struct bell_softc * sc)406d57ca0cfSchs bell_on(struct bell_softc *sc)
407320e7320Soki {
408320e7320Soki 	int sps;
409320e7320Soki 
410320e7320Soki 	sps = spltty();
411320e7320Soki 	opm_set_volume(sc->ch, vol_table[sc->volume]);
412320e7320Soki 	opm_set_key(sc->ch, sc->key);
413320e7320Soki 	splx(sps);
414320e7320Soki 
415320e7320Soki 	opm_key_on(sc->ch);
416320e7320Soki 	sc->sc_flags |= BELLF_ON;
417320e7320Soki }
418320e7320Soki 
419320e7320Soki void
bell_off(struct bell_softc * sc)420d57ca0cfSchs bell_off(struct bell_softc *sc)
421320e7320Soki {
422320e7320Soki 	if (sc->sc_flags & BELLF_ON) {
423320e7320Soki 		opm_key_off(sc->ch);
424320e7320Soki 		sc->sc_flags &= ~BELLF_ON;
425320e7320Soki 	}
426320e7320Soki }
427320e7320Soki 
428320e7320Soki void
opm_bell(void)429d57ca0cfSchs opm_bell(void)
430320e7320Soki {
431d57ca0cfSchs 	struct bell_softc *sc = &bell_softc[0];
432d57ca0cfSchs 	int ticks;
433320e7320Soki 
434320e7320Soki 	if (sc->msec != 0) {
435320e7320Soki 		if (sc->sc_flags & BELLF_OUT) {
436fd9fae64Soki 			bell_timeout(0);
437320e7320Soki 		} else if (sc->sc_flags & BELLF_ON)
438320e7320Soki 			return;
439320e7320Soki 
440320e7320Soki 		ticks = bellmstohz(sc->msec);
441320e7320Soki 
442320e7320Soki 		bell_on(sc);
443320e7320Soki 		sc->sc_flags |= BELLF_OUT;
444320e7320Soki 
4457b918b40Sthorpej 		callout_reset(&bell_ch, ticks, bell_timeout, NULL);
446320e7320Soki 	}
447320e7320Soki }
448320e7320Soki 
449320e7320Soki static void
bell_timeout(void * arg)450d57ca0cfSchs bell_timeout(void *arg)
451320e7320Soki {
452320e7320Soki 	struct bell_softc *sc = &bell_softc[0];
453320e7320Soki 
454320e7320Soki 	sc->sc_flags &= ~BELLF_OUT;
455320e7320Soki 	bell_off(sc);
4567b918b40Sthorpej 	callout_stop(&bell_ch);
457320e7320Soki }
458320e7320Soki 
459320e7320Soki void
opm_bell_on(void)460d57ca0cfSchs opm_bell_on(void)
461320e7320Soki {
462d57ca0cfSchs 	struct bell_softc *sc = &bell_softc[0];
463320e7320Soki 
464320e7320Soki 	if (sc->sc_flags & BELLF_OUT)
465fd9fae64Soki 		bell_timeout(0);
466320e7320Soki 	if (sc->sc_flags & BELLF_ON)
467320e7320Soki 		return;
468320e7320Soki 
469320e7320Soki 	bell_on(sc);
470320e7320Soki }
471320e7320Soki 
472320e7320Soki void
opm_bell_off(void)473d57ca0cfSchs opm_bell_off(void)
474320e7320Soki {
475d57ca0cfSchs 	struct bell_softc *sc = &bell_softc[0];
476320e7320Soki 
477320e7320Soki 	if (sc->sc_flags & BELLF_ON)
478320e7320Soki 		bell_off(sc);
479320e7320Soki }
480320e7320Soki 
481320e7320Soki int
opm_bell_setup(struct bell_info * data)482d57ca0cfSchs opm_bell_setup(struct bell_info *data)
483320e7320Soki {
484d57ca0cfSchs 	struct bell_softc *sc = &bell_softc[0];
485320e7320Soki 
486320e7320Soki 	/* bounds check */
487320e7320Soki 	if (data->pitch > MAXBPITCH || data->pitch < MINBPITCH ||
488320e7320Soki 	    data->volume > MAXBVOLUME || data->msec > MAXBTIME) {
489320e7320Soki 		return EINVAL;
490320e7320Soki 	} else {
491320e7320Soki 		sc->volume = data->volume;
492320e7320Soki 		sc->pitch = data->pitch;
493320e7320Soki 		sc->msec = data->msec;
494320e7320Soki 		sc->key = bell_pitchtokey(data->pitch);
495320e7320Soki 	}
496320e7320Soki 	return 0;
497320e7320Soki }
498320e7320Soki 
499320e7320Soki int
bellmstohz(int m)500d57ca0cfSchs bellmstohz(int m)
501320e7320Soki {
502d57ca0cfSchs 	int h = m;
503320e7320Soki 
504320e7320Soki 	if (h > 0) {
505320e7320Soki 		h = h * hz / 1000;
506320e7320Soki 		if (h == 0)
507320e7320Soki 			h = 1000 / hz;
508320e7320Soki 	}
509320e7320Soki 	return h;
510320e7320Soki }
511320e7320Soki 
512320e7320Soki #endif
513