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