xref: /openbsd/sys/arch/luna88k/cbus/nec86.c (revision 73471bf0)
1 /*	$OpenBSD: nec86.c,v 1.3 2016/09/19 06:46:43 ratchov 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 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 	.speaker_ctl	= nec86hw_speaker_ctl,
83 	.setfd		= nec86hw_setfd,
84 	.set_port	= nec86hw_mixer_set_port,
85 	.get_port	= nec86hw_mixer_get_port,
86 	.query_devinfo	= nec86hw_mixer_query_devinfo,
87 	.allocm		= NULL,
88 	.freem		= NULL,
89 	.round_buffersize	= NULL,
90 	.get_props	= nec86_get_props,
91 	.trigger_output	= NULL,
92 	.trigger_input	= NULL
93 };
94 
95 /*
96  * YAMAHA YM2608(OPNA) register read/write functions
97  */
98 #define YM_INDEX	0
99 #define YM_DATA		2
100 
101 void nec86_ym_read(struct nec86_softc *, u_int8_t, u_int8_t *);
102 void nec86_ym_write(struct nec86_softc *, u_int8_t, u_int8_t);
103 
104 void
105 nec86_ym_read(struct nec86_softc *sc, u_int8_t index, u_int8_t *data) {
106 	bus_space_write_1(sc->sc_ym_iot,
107 	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_INDEX, index);
108 	delay(100);
109 	*data = bus_space_read_1(sc->sc_ym_iot,
110 	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_DATA);
111 	delay(100);
112 }
113 
114 void
115 nec86_ym_write(struct nec86_softc *sc, u_int8_t index, u_int8_t data) {
116 	bus_space_write_1(sc->sc_ym_iot,
117 	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_INDEX, index);
118 	delay(100);
119 	bus_space_write_1(sc->sc_ym_iot,
120 	    sc->sc_ym_iobase + sc->sc_ym_ioh, YM_DATA, data);
121 	delay(100);
122 }
123 
124 /*
125  * Probe for NEC PC-9801-86 SoundBoard hardware.
126  */
127 int
128 nec86_probesubr(bus_space_tag_t iot, bus_space_handle_t ioh,
129     bus_space_handle_t n86ioh)
130 {
131 	u_int8_t data;
132 
133 #ifdef	notyet
134 	if (nec86hw_probesubr(iot, ioh) != 0)
135 		return -1;
136 #endif	/* notyet */
137 
138 	if (n86ioh == 0)
139 		return -1;
140 
141 	data = bus_space_read_1(iot, n86ioh, NEC86_SOUND_ID);
142 
143 	switch (data & NEC_SCR_SIDMASK) {
144 #if 0	/* XXX -  PC-9801-73 not yet supported. */
145 	case 0x20:
146 	case 0x30:
147 		break;
148 #endif
149 	case 0x40:
150 	case 0x50:
151 		break;
152 	default:	/* No supported board found. */
153 		return -1;
154 		/*NOTREACHED*/
155 	}
156 
157 	return ((data & NEC_SCR_SIDMASK) >> 4) - 2;
158 }
159 
160 /*
161  * Attach hardware to driver, attach hardware driver to audio
162  * pseudo-device driver.
163  */
164 #define MODEL0_NAME	"PC-9801-73 soundboard"
165 #define MODEL1_NAME	"PC-9801-86 soundboard"
166 
167 void
168 nec86_attachsubr(struct nec86_softc *sc)
169 {
170 	struct nec86hw_softc *ysc = &sc->sc_nec86hw;
171 	bus_space_tag_t iot = sc->sc_n86iot;
172 	bus_space_handle_t n86ioh = sc->sc_n86ioh;
173 	char *boardname[] =
174 	    {MODEL0_NAME, MODEL0_NAME, MODEL1_NAME, MODEL1_NAME};
175 	u_int8_t data;
176 	int model;
177 
178 	if ((model = nec86_probesubr(iot, n86ioh, n86ioh)) < 0) {
179 		printf("%s: missing hardware\n", ysc->sc_dev.dv_xname);
180 		return;
181 	}
182 	ysc->model = model;
183 
184 	/* enable YM2608(ONPA) */
185 	data = bus_space_read_1(iot, n86ioh, NEC86_SOUND_ID);
186 	data &= ~NEC_SCR_MASK;
187 	data |= NEC_SCR_EXT_ENABLE;
188 	bus_space_write_1(iot, n86ioh, NEC86_SOUND_ID, data);
189 
190 	switch (ysc->model) {
191 	case 2:	/* base I/O port for YM2608(OPNA) is 0x188 */
192 		sc->sc_ym_ioh = OPNA_IOBASE1;
193 		break;
194 	case 3:	/* base I/O port for YM2608(OPNA) is 0x288 */
195 		sc->sc_ym_ioh = OPNA_IOBASE2;
196 		break;
197 	default:
198 		/* can not happen; set to factory default */
199 		sc->sc_ym_ioh = OPNA_IOBASE1;
200 		break;
201 	}
202 
203 	/* YM2608 I/O port set (IOA:input IOB:output) */
204 	nec86_ym_read(sc, 0x07, &data);
205 	data &= 0x3f;
206 	data |= 0x80;
207 	nec86_ym_write(sc, 0x07, data);
208 
209 	/* YM2608 register 0x0e has C-bus interrupt level information */
210 	nec86_ym_read(sc, 0x0e, &data);
211 	switch (data & 0xc0) {
212 	case 0x00:
213 		sc->sc_intlevel = 0;
214 		break;
215 	case 0x40:
216 		sc->sc_intlevel = 6;
217 		break;
218 	case 0x80:
219 		sc->sc_intlevel = 4;
220 		break;
221 	case 0xc0:
222 		sc->sc_intlevel = 5;	/* factory default setting */
223 		break;
224 	default:
225 		/* can not happen; set to factory default */
226 		sc->sc_intlevel = 5;
227 		break;
228 	}
229 
230 	/* reset YM2608 timer A and B: XXX need this? */
231 	data = 0x30;
232 	nec86_ym_write(sc, 0x27, data);
233 
234 	printf(" int %d", sc->sc_intlevel);
235 
236 	nec86hw_attach(ysc);
237 
238 	if (sc->sc_attached == 0) {
239 		printf(": %s\n", boardname[ysc->model]);
240 		audio_attach_mi(&nec86_hw_if, ysc, &ysc->sc_dev);
241 		sc->sc_attached = 1;
242 	}
243 }
244