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