Home | History | Annotate | Line # | Download | only in dev
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