Home | History | Annotate | Line # | Download | only in dev
opmbell.c revision 1.8
      1 /*	$NetBSD: opmbell.c,v 1.8 2001/12/27 02:23:25 wiz 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 cdev_decl(bell);
    100 void bell_on __P((struct bell_softc *sc));
    101 void bell_off __P((struct bell_softc *sc));
    102 void opm_bell __P((void));
    103 void opm_bell_on __P((void));
    104 void opm_bell_off __P((void));
    105 int opm_bell_setup __P((struct bell_info *));
    106 int bellmstohz __P((int));
    107 
    108 void bellattach __P((int));
    109 
    110 void
    111 bellattach(num)
    112 	int num;
    113 {
    114 	char *mem;
    115 	register u_long size;
    116 	register struct bell_softc *sc;
    117 	int unit;
    118 
    119 	if (num <= 0)
    120 		return;
    121 	size = num * sizeof(struct bell_softc);
    122 	mem = malloc(size, M_DEVBUF, M_NOWAIT);
    123 	if (mem == NULL) {
    124 		printf("WARNING: no memory for opm bell\n");
    125 		return;
    126 	}
    127 	memset(mem, 0, size);
    128 	bell_softc = (struct bell_softc *)mem;
    129 
    130 	for (unit = 0; unit < num; unit++) {
    131 		sc = &bell_softc[unit];
    132 		sc->sc_flags = BELLF_ALIVE;
    133 		sc->ch = BELL_CHANNEL;
    134 		sc->volume = BELL_VOLUME;
    135 		sc->pitch = BELL_PITCH;
    136 		sc->msec = BELL_DURATION;
    137 		sc->key = bell_pitchtokey(sc->pitch);
    138 
    139 		/* setup initial voice parameter */
    140 		memcpy(&vtab[unit], &bell_voice, sizeof(bell_voice));
    141 		opm_set_voice(sc->ch, &vtab[unit]);
    142 
    143 		printf("bell%d: YM2151 OPM bell emulation.\n", unit);
    144 	}
    145 }
    146 
    147 int
    148 bellopen(dev, flags, mode, p)
    149 	dev_t dev;
    150 	int flags, mode;
    151 	struct proc *p;
    152 {
    153 	register int unit = UNIT(dev);
    154 	register struct bell_softc *sc = &bell_softc[unit];
    155 
    156 	if (unit >= NBELL || !(sc->sc_flags & BELLF_ALIVE))
    157 		return ENXIO;
    158 
    159 	if (sc->sc_flags & BELLF_OPEN)
    160 		return EBUSY;
    161 
    162 	sc->sc_flags |= BELLF_OPEN;
    163 	sc->sc_flags |= (flags & (FREAD | FWRITE));
    164 
    165 	return 0;
    166 }
    167 
    168 int
    169 bellclose(dev, flags, mode, p)
    170 	dev_t dev;
    171 	int flags, mode;
    172 	struct proc *p;
    173 {
    174 	int unit = UNIT(dev);
    175 	struct bell_softc *sc = &bell_softc[unit];
    176 
    177 	sc->sc_flags &= ~BELLF_OPEN;
    178 	return 0;
    179 }
    180 
    181 int
    182 bellioctl(dev, cmd, addr, flag, p)
    183 	dev_t dev;
    184 	u_long cmd;
    185 	caddr_t addr;
    186 	int flag;
    187 	struct proc *p;
    188 {
    189 	int unit = UNIT(dev);
    190 	struct bell_softc *sc = &bell_softc[unit];
    191 
    192 	switch (cmd) {
    193 	case BELLIOCGPARAM:
    194 	  {
    195 	      struct bell_info *bp = (struct bell_info *)addr;
    196 	      if (!(sc->sc_flags & FREAD))
    197 		  return EBADF;
    198 
    199 	      bp->volume = sc->volume;
    200 	      bp->pitch = sc->pitch;
    201 	      bp->msec = sc->msec;
    202 	      break;
    203 	  }
    204 
    205 	case BELLIOCSPARAM:
    206 	  {
    207 	      struct bell_info *bp = (struct bell_info *)addr;
    208 
    209 	      if (!(sc->sc_flags & FWRITE))
    210 		  return EBADF;
    211 
    212 	      return opm_bell_setup(bp);
    213 	  }
    214 
    215 	case BELLIOCGVOICE:
    216 	    if (!(sc->sc_flags & FREAD))
    217 		return EBADF;
    218 
    219 	    if (addr == NULL)
    220 		return EFAULT;
    221 
    222 	    memcpy(addr, &vtab[unit], sizeof(struct opm_voice));
    223 	    break;
    224 
    225 	case BELLIOCSVOICE:
    226 	    if (!(sc->sc_flags & FWRITE))
    227 		return EBADF;
    228 
    229 	    if (addr == NULL)
    230 		return EFAULT;
    231 
    232 	    memcpy(&vtab[unit], addr, sizeof(struct opm_voice));
    233 	    opm_set_voice(sc->ch, &vtab[unit]);
    234 	    break;
    235 
    236 	default:
    237 	    return EINVAL;
    238 	}
    239 	return 0;
    240 }
    241 
    242 /*
    243  * The next table is used for calculating KeyCode/KeyFraction pair
    244  * from frequency.
    245  */
    246 
    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,
    358 };
    359 
    360 static u_int
    361 bell_pitchtokey(pitch)
    362 	u_int pitch;
    363 {
    364     int i, oct;
    365     u_int key;
    366 
    367     i = 16 * pitch / 440;
    368     for (oct = -1; i > 0; i >>= 1, oct++)
    369 	;
    370 
    371     i  = (pitch * 16 - (440 * (1 << oct))) / (1 << oct);
    372     key = (oct << 12) + note[i];
    373 
    374     return key;
    375 }
    376 
    377 /*
    378  * The next table is a little trikcy table of volume factors.
    379  * Its values have been calculated as table[i] = -15 * log10(i/100)
    380  * with an obvious exception for i = 0; This log-table converts a linear
    381  * volume-scaling (0...100) to a logarithmic scaling as present in the
    382  * OPM chips. so: Volume 50% = 6 db.
    383  */
    384 
    385 static u_char vol_table[] = {
    386     0x7f, 0x35, 0x2d, 0x28, 0x25, 0x22, 0x20, 0x1e,
    387     0x1d, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15,
    388     0x15, 0x14, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11,
    389     0x10, 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0d,
    390     0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0a,
    391     0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x08, 0x08,
    392     0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
    393     0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05,
    394     0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
    395     0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02,
    396     0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
    397     0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
    398     0x00, 0x00, 0x00, 0x00, 0x00,
    399 };
    400 
    401 void
    402 bell_on(sc)
    403 	register struct bell_softc *sc;
    404 {
    405     int sps;
    406 
    407     sps = spltty();
    408     opm_set_volume(sc->ch, vol_table[sc->volume]);
    409     opm_set_key(sc->ch, sc->key);
    410     splx(sps);
    411 
    412     opm_key_on(sc->ch);
    413     sc->sc_flags |= BELLF_ON;
    414 }
    415 
    416 void
    417 bell_off(sc)
    418 	register struct bell_softc *sc;
    419 {
    420     if (sc->sc_flags & BELLF_ON) {
    421 	opm_key_off(sc->ch);
    422 	sc->sc_flags &= ~BELLF_ON;
    423     }
    424 }
    425 
    426 void
    427 opm_bell()
    428 {
    429     register struct bell_softc *sc = &bell_softc[0];
    430     register int ticks;
    431 
    432     if (sc->msec != 0) {
    433 	if (sc->sc_flags & BELLF_OUT) {
    434 	    bell_timeout(0);
    435 	} else if (sc->sc_flags & BELLF_ON)
    436 	    return;
    437 
    438 	ticks = bellmstohz(sc->msec);
    439 
    440 	bell_on(sc);
    441 	sc->sc_flags |= BELLF_OUT;
    442 
    443 	callout_reset(&bell_ch, ticks, bell_timeout, NULL);
    444     }
    445 }
    446 
    447 static void
    448 bell_timeout(arg)
    449 	void *arg;
    450 {
    451     struct bell_softc *sc = &bell_softc[0];
    452 
    453     sc->sc_flags &= ~BELLF_OUT;
    454     bell_off(sc);
    455     callout_stop(&bell_ch);
    456 }
    457 
    458 void
    459 opm_bell_on()
    460 {
    461     register struct bell_softc *sc = &bell_softc[0];
    462 
    463     if (sc->sc_flags & BELLF_OUT)
    464 	bell_timeout(0);
    465     if (sc->sc_flags & BELLF_ON)
    466 	return;
    467 
    468     bell_on(sc);
    469 }
    470 
    471 void
    472 opm_bell_off()
    473 {
    474     register struct bell_softc *sc = &bell_softc[0];
    475 
    476     if (sc->sc_flags & BELLF_ON)
    477 	bell_off(sc);
    478 }
    479 
    480 int
    481 opm_bell_setup(data)
    482 	struct bell_info *data;
    483 {
    484     register struct bell_softc *sc = &bell_softc[0];
    485 
    486     /* bounds check */
    487     if (data->pitch > MAXBPITCH || data->pitch < MINBPITCH ||
    488 	data->volume > MAXBVOLUME || data->msec > MAXBTIME) {
    489 	return EINVAL;
    490     } else {
    491 	sc->volume = data->volume;
    492 	sc->pitch = data->pitch;
    493 	sc->msec = data->msec;
    494 
    495 	sc->key = bell_pitchtokey(data->pitch);
    496     }
    497     return 0;
    498 }
    499 
    500 int
    501 bellmstohz(m)
    502 	int m;
    503 {
    504     extern int hz;
    505     register int h = m;
    506 
    507     if (h > 0) {
    508 	h = h * hz / 1000;
    509 	if (h == 0)
    510 	    h = 1000 / hz;
    511     }
    512     return h;
    513 }
    514 
    515 #endif
    516