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