xref: /openbsd/sys/arch/luna88k/cbus/nec86.c (revision c8819f5d)
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