xref: /netbsd-src/sys/arch/x68k/dev/opm.c (revision 4c3cdcf09915b87083b36b6a6a38ba3f91f27d39)
1*4c3cdcf0Schristos /*	$NetBSD: opm.c,v 1.20 2014/03/26 08:17:59 christos Exp $	*/
2320e7320Soki 
3320e7320Soki /*
4320e7320Soki  * Copyright (c) 1995 Masanobu Saitoh, Takuya Harakawa.
5320e7320Soki  * All rights reserved.
6320e7320Soki  *
7320e7320Soki  * Redistribution and use in source and binary forms, with or without
8320e7320Soki  * modification, are permitted provided that the following conditions
9320e7320Soki  * are met:
10320e7320Soki  * 1. Redistributions of source code must retain the above copyright
11320e7320Soki  *    notice, this list of conditions and the following disclaimer.
12320e7320Soki  * 2. Redistributions in binary form must reproduce the above copyright
13320e7320Soki  *    notice, this list of conditions and the following disclaimer in the
14320e7320Soki  *    documentation and/or other materials provided with the distribution.
15320e7320Soki  * 3. All advertising materials mentioning features or use of this software
16320e7320Soki  *    must display the following acknowledgement:
17320e7320Soki  *	This product includes software developed by Masanobu Saitoh.
18320e7320Soki  * 4. Neither the name of the University nor of the Laboratory may be used
19320e7320Soki  *    to endorse or promote products derived from this software without
20320e7320Soki  *    specific prior written permission.
21320e7320Soki  *
22320e7320Soki  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23320e7320Soki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24320e7320Soki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25320e7320Soki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26320e7320Soki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27320e7320Soki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28320e7320Soki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29320e7320Soki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30320e7320Soki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31320e7320Soki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32320e7320Soki  * SUCH DAMAGE.
33320e7320Soki  */
34320e7320Soki 
35ba80d2c6Sminoura /*
36ba80d2c6Sminoura  * Temporary implementation: not fully bus.h'fied.
37ba80d2c6Sminoura  */
38320e7320Soki 
39ab48a212Slukem #include <sys/cdefs.h>
40*4c3cdcf0Schristos __KERNEL_RCSID(0, "$NetBSD: opm.c,v 1.20 2014/03/26 08:17:59 christos Exp $");
41ab48a212Slukem 
42320e7320Soki #include <sys/param.h>
43320e7320Soki #include <sys/systm.h>
44ba80d2c6Sminoura #include <sys/device.h>
45320e7320Soki 
46ba80d2c6Sminoura #include <machine/bus.h>
47ba80d2c6Sminoura #include <machine/cpu.h>
48ba80d2c6Sminoura 
4969153277Sminoura #include <machine/opmreg.h>
5069153277Sminoura #include <arch/x68k/dev/opmvar.h>
51ba80d2c6Sminoura #include <arch/x68k/dev/intiovar.h>
52ba80d2c6Sminoura 
53ba80d2c6Sminoura struct opm_softc {
54ba80d2c6Sminoura 	bus_space_tag_t		sc_bst;
55ba80d2c6Sminoura 	bus_space_handle_t	sc_bht;
56ba80d2c6Sminoura 	u_int8_t		sc_regs[0x100];
57ba80d2c6Sminoura 	struct opm_voice	sc_vdata[8];
58ba80d2c6Sminoura };
59ba80d2c6Sminoura 
60ba80d2c6Sminoura struct opm_softc	*opm0;	/* XXX */
61ba80d2c6Sminoura 
622830b81aSisaki static int opm_match(device_t, cfdata_t, void *);
632830b81aSisaki static void opm_attach(device_t, device_t, void *);
64ba80d2c6Sminoura 
652830b81aSisaki CFATTACH_DECL_NEW(opm, sizeof(struct opm_softc),
664bf871a7Sthorpej     opm_match, opm_attach, NULL, NULL);
67ba80d2c6Sminoura 
68ba80d2c6Sminoura static int
opm_match(device_t parent,cfdata_t cf,void * aux)692830b81aSisaki opm_match(device_t parent, cfdata_t cf, void *aux)
70ba80d2c6Sminoura {
71ba80d2c6Sminoura 	struct intio_attach_args *ia = aux;
72ba80d2c6Sminoura 
73ba80d2c6Sminoura 	if (strcmp(ia->ia_name, "opm") != 0)
74ba80d2c6Sminoura 		return 0;
75ba80d2c6Sminoura 
76ba80d2c6Sminoura 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
77ba80d2c6Sminoura 		ia->ia_addr = 0xe90000;
78ba80d2c6Sminoura 	ia->ia_size = 0x2000;
79ba80d2c6Sminoura 	if (intio_map_allocate_region(parent, ia, INTIO_MAP_TESTONLY))
80ba80d2c6Sminoura 		return 0;
81ba80d2c6Sminoura 
82ba80d2c6Sminoura 	return 1;
83ba80d2c6Sminoura }
84ba80d2c6Sminoura 
85ba80d2c6Sminoura static void
opm_attach(device_t parent,device_t self,void * aux)862830b81aSisaki opm_attach(device_t parent, device_t self, void *aux)
87ba80d2c6Sminoura {
882830b81aSisaki 	struct opm_softc *sc = device_private(self);
89ba80d2c6Sminoura 	struct intio_attach_args *ia = aux;
90*4c3cdcf0Schristos 	int r __diagused;
91ba80d2c6Sminoura 
922830b81aSisaki 	aprint_normal("\n");
93ba80d2c6Sminoura 	ia->ia_size = 0x2000;
94ba80d2c6Sminoura 	r = intio_map_allocate_region(parent, ia, INTIO_MAP_ALLOCATE);
95ba80d2c6Sminoura #ifdef DIAGNOSTIC
96ba80d2c6Sminoura 	if (r)
97ba80d2c6Sminoura 		panic("IO map for OPM corruption??");
98ba80d2c6Sminoura #endif
99ba80d2c6Sminoura 
100ba80d2c6Sminoura 	sc->sc_bst = ia->ia_bst;
101ba80d2c6Sminoura 	r = bus_space_map(sc->sc_bst,
102ba80d2c6Sminoura 			   ia->ia_addr, ia->ia_size,
103ba80d2c6Sminoura 			   BUS_SPACE_MAP_SHIFTED,
104ba80d2c6Sminoura 			   &sc->sc_bht);
105ba80d2c6Sminoura #ifdef DIAGNOSTIC
106ba80d2c6Sminoura 	if (r)
107ba80d2c6Sminoura 		panic("Cannot map IO space for OPM.");
108ba80d2c6Sminoura #endif
109ba80d2c6Sminoura 
11039cd836eSthorpej 	/* XXX device_unit() abuse */
1112830b81aSisaki 	if (device_unit(self) == 0)
112ba80d2c6Sminoura 		opm0 = sc;	/* XXX */
113ba80d2c6Sminoura 
114ba80d2c6Sminoura 	return;
115ba80d2c6Sminoura }
116320e7320Soki 
117d57ca0cfSchs void opm_set_volume(int, int);
118d57ca0cfSchs void opm_set_key(int, int);
119d57ca0cfSchs void opm_set_voice(int, struct opm_voice *);
120d57ca0cfSchs void opm_set_voice_sub(int, struct opm_operator *);
1215f1c88d7Sperry inline static void writeopm(int, int);
1225f1c88d7Sperry inline static int readopm(int);
123d57ca0cfSchs void opm_key_on(u_char);
124d57ca0cfSchs void opm_key_off(u_char);
125d57ca0cfSchs int opmopen(dev_t, int, int);
126d57ca0cfSchs int opmclose(dev_t);
127320e7320Soki 
1285f1c88d7Sperry inline static void
writeopm(int reg,int dat)129d57ca0cfSchs writeopm(int reg, int dat)
130320e7320Soki {
131ba80d2c6Sminoura 	while (bus_space_read_1(opm0->sc_bst, opm0->sc_bht, OPM_DATA) & 0x80);
132ba80d2c6Sminoura 	bus_space_write_1(opm0->sc_bst, opm0->sc_bht, OPM_REG, reg);
133ba80d2c6Sminoura 	while (bus_space_read_1(opm0->sc_bst, opm0->sc_bht, OPM_DATA) & 0x80);
134ba80d2c6Sminoura 	bus_space_write_1(opm0->sc_bst, opm0->sc_bht, OPM_DATA, dat);
135ba80d2c6Sminoura 	opm0->sc_regs[reg] = dat;
136320e7320Soki }
137320e7320Soki 
1385f1c88d7Sperry inline static int
readopm(int reg)139d57ca0cfSchs readopm(int reg)
140320e7320Soki {
141ba80d2c6Sminoura 	return opm0->sc_regs[reg];
142320e7320Soki }
143320e7320Soki 
144ba80d2c6Sminoura #include "fd.h"
145b2cec368Sminoura #include "vs.h"
146ba80d2c6Sminoura #include "bell.h"
147ba80d2c6Sminoura 
148b2cec368Sminoura #if NVS > 0
149320e7320Soki void
adpcm_chgclk(u_char clk)150d57ca0cfSchs adpcm_chgclk(u_char clk)
151320e7320Soki {
152b2cec368Sminoura 	writeopm(0x1b, (readopm(0x1b) & ~OPM1B_CT1MSK) | clk);
153320e7320Soki }
154ba80d2c6Sminoura #endif
155320e7320Soki 
156ba80d2c6Sminoura #if NFD > 0
157320e7320Soki void
fdc_force_ready(u_char rdy)158d57ca0cfSchs fdc_force_ready(u_char rdy)
159320e7320Soki {
160a76b0b1bSminoura 	writeopm(0x1b, (readopm(0x1b) & ~OPM1B_CT2MSK) | rdy);
161320e7320Soki }
162ba80d2c6Sminoura #endif
163320e7320Soki 
164ba80d2c6Sminoura #if NBELL > 0
165320e7320Soki void
opm_key_on(u_char channel)166d57ca0cfSchs opm_key_on(u_char channel)
167320e7320Soki {
168ba80d2c6Sminoura 	writeopm(0x08, opm0->sc_vdata[channel].sm << 3 | channel);
169320e7320Soki }
170320e7320Soki 
171320e7320Soki void
opm_key_off(u_char channel)172d57ca0cfSchs opm_key_off(u_char channel)
173320e7320Soki {
174320e7320Soki 	writeopm(0x08, channel);
175320e7320Soki }
176320e7320Soki 
177320e7320Soki void
opm_set_voice(int channel,struct opm_voice * voice)178d57ca0cfSchs opm_set_voice(int channel, struct opm_voice *voice)
179320e7320Soki {
1805514d0b1Swiz 	memcpy(&opm0->sc_vdata[channel], voice, sizeof(struct opm_voice));
181320e7320Soki 
182320e7320Soki 	opm_set_voice_sub(0x40 + channel, &voice->m1);
183320e7320Soki 	opm_set_voice_sub(0x48 + channel, &voice->m2);
184320e7320Soki 	opm_set_voice_sub(0x50 + channel, &voice->c1);
185320e7320Soki 	opm_set_voice_sub(0x58 + channel, &voice->c2);
186d57ca0cfSchs 	writeopm(0x20 + channel, 0xc0 | (voice->fb & 0x7) << 3 |
187d57ca0cfSchs 		 (voice->con & 0x7));
188320e7320Soki }
189320e7320Soki 
190320e7320Soki void
opm_set_voice_sub(int reg,struct opm_operator * op)191d57ca0cfSchs opm_set_voice_sub(int reg, struct opm_operator *op)
192320e7320Soki {
193320e7320Soki 	/* DT1/MUL */
194320e7320Soki 	writeopm(reg, (op->dt1 & 0x7) << 3 | (op->mul & 0x7));
195320e7320Soki 
196320e7320Soki 	/* TL */
197320e7320Soki 	writeopm(reg + 0x20, op->tl & 0x7f);
198320e7320Soki 
199320e7320Soki 	/* KS/AR */
200320e7320Soki 	writeopm(reg + 0x40, (op->ks & 0x3) << 6 | (op->ar & 0x1f));
201320e7320Soki 
202320e7320Soki 	/* AMS/D1R */
203320e7320Soki 	writeopm(reg + 0x60, (op->ame & 0x1) << 7 | (op->d1r & 0x1f));
204320e7320Soki 
205320e7320Soki 	/* DT2/D2R */
206320e7320Soki 	writeopm(reg + 0x80, (op->dt2 & 0x3) << 6 | (op->d2r & 0x1f));
207320e7320Soki 
208320e7320Soki 	/* D1L/RR */
209320e7320Soki 	writeopm(reg + 0xa0, (op->d1l & 0xf) << 4 | (op->rr & 0xf));
210320e7320Soki }
211320e7320Soki 
212320e7320Soki void
opm_set_volume(int channel,int volume)213d57ca0cfSchs opm_set_volume(int channel, int volume)
214320e7320Soki {
215320e7320Soki 	int value;
216320e7320Soki 
217ba80d2c6Sminoura 	switch (opm0->sc_vdata[channel].con) {
218320e7320Soki 	case 7:
219ba80d2c6Sminoura 		value = opm0->sc_vdata[channel].m1.tl + volume;
220320e7320Soki 		writeopm(0x60 + channel, ((value > 0x7f) ? 0x7f : value));
221320e7320Soki 	case 6:
222320e7320Soki 	case 5:
223ba80d2c6Sminoura 		value = opm0->sc_vdata[channel].m2.tl + volume;
224320e7320Soki 		writeopm(0x68 + channel, ((value > 0x7f) ? 0x7f : value));
225320e7320Soki 	case 4:
226ba80d2c6Sminoura 		value = opm0->sc_vdata[channel].c1.tl + volume;
227320e7320Soki 		writeopm(0x70 + channel, ((value > 0x7f) ? 0x7f : value));
228320e7320Soki 	case 3:
229320e7320Soki 	case 2:
230320e7320Soki 	case 1:
231320e7320Soki 	case 0:
232ba80d2c6Sminoura 		value = opm0->sc_vdata[channel].c2.tl + volume;
233320e7320Soki 		writeopm(0x78 + channel, ((value > 0x7f) ? 0x7f : value));
234320e7320Soki 	}
235320e7320Soki }
236320e7320Soki 
237320e7320Soki void
opm_set_key(int channel,int tone)238d57ca0cfSchs opm_set_key(int channel, int tone)
239320e7320Soki {
240320e7320Soki 	writeopm(0x28 + channel, tone >> 8);
241320e7320Soki 	writeopm(0x30 + channel, tone & 0xff);
242320e7320Soki }
243320e7320Soki 
244320e7320Soki /*ARGSUSED*/
245320e7320Soki int
opmopen(dev_t dev,int flag,int mode)246d57ca0cfSchs opmopen(dev_t dev, int flag, int mode)
247320e7320Soki {
24830ec7d2cSoki 	return 0;
249320e7320Soki }
250320e7320Soki 
251320e7320Soki /*ARGSUSED*/
252320e7320Soki int
opmclose(dev_t dev)253d57ca0cfSchs opmclose(dev_t dev)
254320e7320Soki {
25530ec7d2cSoki 	return 0;
256320e7320Soki }
257320e7320Soki 
258320e7320Soki #endif
259