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