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