1 /* $OpenBSD: nec86.c,v 1.9 2022/11/02 10:41:34 kn Exp $ */
2 /* $NecBSD: nec86.c,v 1.11 1999/07/23 11:04:39 honda Exp $ */
3 /* $NetBSD$ */
4
5 /*
6 * [NetBSD for NEC PC-98 series]
7 * Copyright (c) 1996, 1997, 1998
8 * NetBSD/pc98 porting staff. All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * nec86.c
36 *
37 * NEC PC-9801-86 SoundBoard PCM driver for NetBSD/pc98.
38 * Written by NAGAO Tadaaki, Feb 10, 1996.
39 *
40 * Modified by N. Honda, Mar 7, 1998
41 */
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/errno.h>
46 #include <sys/ioctl.h>
47 #include <sys/syslog.h>
48 #include <sys/device.h>
49 #include <sys/proc.h>
50
51 #include <machine/board.h> /* PC_BASE */
52 #include <machine/bus.h>
53 #include <machine/cpu.h>
54
55 #include <sys/audioio.h>
56 #include <dev/audio_if.h>
57
58 #include <luna88k/cbus/nec86reg.h>
59 #include <luna88k/cbus/nec86hwvar.h>
60 #include <luna88k/cbus/nec86var.h>
61
62 #define NEC_SCR_SIDMASK 0xf0
63 #define NEC_SCR_MASK 0x0f
64 #define NEC_SCR_EXT_ENABLE 0x01
65
66 /*
67 * Define our interface to the higher level audio driver.
68 */
69
70 const struct audio_hw_if nec86_hw_if = {
71 .open = nec86hw_open,
72 .close = nec86hw_close,
73 .set_params = nec86hw_set_params,
74 .round_blocksize = nec86hw_round_blocksize,
75 .commit_settings = nec86hw_commit_settings,
76 .init_output = nec86hw_pdma_init_output,
77 .init_input = nec86hw_pdma_init_input,
78 .start_output = nec86hw_pdma_output,
79 .start_input = nec86hw_pdma_input,
80 .halt_output = nec86hw_halt_pdma,
81 .halt_input = nec86hw_halt_pdma,
82 .set_port = nec86hw_mixer_set_port,
83 .get_port = nec86hw_mixer_get_port,
84 .query_devinfo = nec86hw_mixer_query_devinfo,
85 };
86
87 /*
88 * YAMAHA YM2608(OPNA) register read/write functions
89 */
90 #define YM_INDEX 0
91 #define YM_DATA 2
92
93 void nec86_ym_read(struct nec86_softc *, u_int8_t, u_int8_t *);
94 void nec86_ym_write(struct nec86_softc *, u_int8_t, u_int8_t);
95
96 void
nec86_ym_read(struct nec86_softc * sc,u_int8_t index,u_int8_t * data)97 nec86_ym_read(struct nec86_softc *sc, u_int8_t index, u_int8_t *data) {
98 bus_space_write_1(sc->sc_ym_iot,
99 sc->sc_ym_iobase + sc->sc_ym_ioh, YM_INDEX, index);
100 delay(100);
101 *data = bus_space_read_1(sc->sc_ym_iot,
102 sc->sc_ym_iobase + sc->sc_ym_ioh, YM_DATA);
103 delay(100);
104 }
105
106 void
nec86_ym_write(struct nec86_softc * sc,u_int8_t index,u_int8_t data)107 nec86_ym_write(struct nec86_softc *sc, u_int8_t index, u_int8_t data) {
108 bus_space_write_1(sc->sc_ym_iot,
109 sc->sc_ym_iobase + sc->sc_ym_ioh, YM_INDEX, index);
110 delay(100);
111 bus_space_write_1(sc->sc_ym_iot,
112 sc->sc_ym_iobase + sc->sc_ym_ioh, YM_DATA, data);
113 delay(100);
114 }
115
116 /*
117 * Probe for NEC PC-9801-86 SoundBoard hardware.
118 */
119 int
nec86_probesubr(bus_space_tag_t iot,bus_space_handle_t ioh,bus_space_handle_t n86ioh)120 nec86_probesubr(bus_space_tag_t iot, bus_space_handle_t ioh,
121 bus_space_handle_t n86ioh)
122 {
123 u_int8_t data;
124
125 #ifdef notyet
126 if (nec86hw_probesubr(iot, ioh) != 0)
127 return -1;
128 #endif /* notyet */
129
130 if (n86ioh == 0)
131 return -1;
132
133 data = bus_space_read_1(iot, n86ioh, NEC86_SOUND_ID);
134
135 switch (data & NEC_SCR_SIDMASK) {
136 #if 0 /* XXX - PC-9801-73 not yet supported. */
137 case 0x20:
138 case 0x30:
139 break;
140 #endif
141 case 0x40:
142 case 0x50:
143 break;
144 default: /* No supported board found. */
145 return -1;
146 /*NOTREACHED*/
147 }
148
149 return ((data & NEC_SCR_SIDMASK) >> 4) - 2;
150 }
151
152 /*
153 * Attach hardware to driver, attach hardware driver to audio
154 * pseudo-device driver.
155 */
156 #define MODEL0_NAME "PC-9801-73 soundboard"
157 #define MODEL1_NAME "PC-9801-86 soundboard"
158
159 void
nec86_attachsubr(struct nec86_softc * sc)160 nec86_attachsubr(struct nec86_softc *sc)
161 {
162 struct nec86hw_softc *ysc = &sc->sc_nec86hw;
163 bus_space_tag_t iot = sc->sc_n86iot;
164 bus_space_handle_t n86ioh = sc->sc_n86ioh;
165 char *boardname[] =
166 {MODEL0_NAME, MODEL0_NAME, MODEL1_NAME, MODEL1_NAME};
167 u_int8_t data;
168 int model;
169
170 if ((model = nec86_probesubr(iot, n86ioh, n86ioh)) < 0) {
171 printf("%s: missing hardware\n", ysc->sc_dev.dv_xname);
172 return;
173 }
174 ysc->model = model;
175
176 /* enable YM2608(ONPA) */
177 data = bus_space_read_1(iot, n86ioh, NEC86_SOUND_ID);
178 data &= ~NEC_SCR_MASK;
179 data |= NEC_SCR_EXT_ENABLE;
180 bus_space_write_1(iot, n86ioh, NEC86_SOUND_ID, data);
181
182 switch (ysc->model) {
183 case 2: /* base I/O port for YM2608(OPNA) is 0x188 */
184 sc->sc_ym_ioh = OPNA_IOBASE1;
185 break;
186 case 3: /* base I/O port for YM2608(OPNA) is 0x288 */
187 sc->sc_ym_ioh = OPNA_IOBASE2;
188 break;
189 default:
190 /* can not happen; set to factory default */
191 sc->sc_ym_ioh = OPNA_IOBASE1;
192 break;
193 }
194
195 /* YM2608 I/O port set (IOA:input IOB:output) */
196 nec86_ym_read(sc, 0x07, &data);
197 data &= 0x3f;
198 data |= 0x80;
199 nec86_ym_write(sc, 0x07, data);
200
201 /* YM2608 register 0x0e has C-bus interrupt level information */
202 nec86_ym_read(sc, 0x0e, &data);
203 switch (data & 0xc0) {
204 case 0x00:
205 sc->sc_intlevel = 0;
206 break;
207 case 0x40:
208 sc->sc_intlevel = 6;
209 break;
210 case 0x80:
211 sc->sc_intlevel = 4;
212 break;
213 case 0xc0:
214 sc->sc_intlevel = 5; /* factory default setting */
215 break;
216 default:
217 /* can not happen; set to factory default */
218 sc->sc_intlevel = 5;
219 break;
220 }
221
222 /* reset YM2608 timer A and B: XXX need this? */
223 data = 0x30;
224 nec86_ym_write(sc, 0x27, data);
225
226 printf(" int %d", sc->sc_intlevel);
227
228 nec86hw_attach(ysc);
229
230 if (sc->sc_attached == 0) {
231 printf(": %s\n", boardname[ysc->model]);
232 audio_attach_mi(&nec86_hw_if, ysc, NULL, &ysc->sc_dev);
233 sc->sc_attached = 1;
234 }
235 }
236