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 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 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 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 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