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