1 /* $NetBSD: cms.c,v 1.17 2008/03/16 22:30:31 cube Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the NetBSD 18 * Foundation, Inc. and its contributors. 19 * 4. Neither the name of The NetBSD Foundation nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: cms.c,v 1.17 2008/03/16 22:30:31 cube Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/device.h> 43 #include <sys/select.h> 44 45 #include <sys/bus.h> 46 47 #include <sys/audioio.h> 48 #include <dev/audio_if.h> 49 #include <dev/audiovar.h> 50 51 #include <sys/midiio.h> 52 #include <dev/midi_if.h> 53 #include <dev/midivar.h> 54 #include <dev/midisynvar.h> 55 56 #include <dev/isa/isareg.h> 57 #include <dev/isa/isavar.h> 58 #include <dev/isa/cmsreg.h> 59 60 #ifdef AUDIO_DEBUG 61 #define DPRINTF(x) if (cmsdebug) printf x 62 int cmsdebug = 0; 63 #else 64 #define DPRINTF(x) 65 #endif 66 67 struct cms_softc { 68 struct midi_softc sc_mididev; 69 70 bus_space_tag_t sc_iot; 71 bus_space_handle_t sc_ioh; 72 73 /* shadow registers for each chip */ 74 u_int8_t sc_shadowregs[32*2]; 75 midisyn sc_midisyn; 76 }; 77 78 int cms_probe(device_t, cfdata_t, void *); 79 void cms_attach(device_t, device_t, void *); 80 81 CFATTACH_DECL_NEW(cms, sizeof(struct cms_softc), 82 cms_probe, cms_attach, NULL, NULL); 83 84 int cms_open(midisyn *, int); 85 void cms_close(midisyn *); 86 void cms_on(midisyn *, uint_fast16_t, midipitch_t, int16_t); 87 void cms_off(midisyn *, uint_fast16_t, uint_fast8_t); 88 89 struct midisyn_methods midi_cms_hw = { 90 .open = cms_open, 91 .close = cms_close, 92 .attackv = cms_on, 93 .releasev = cms_off, 94 }; 95 96 static void cms_reset(struct cms_softc *); 97 98 static char cms_note_table[] = { 99 /* A */ 3, 100 /* A# */ 31, 101 /* B */ 58, 102 /* C */ 83, 103 /* C# */ 107, 104 /* D */ 130, 105 /* D# */ 151, 106 /* E */ 172, 107 /* F */ 191, 108 /* F# */ 209, 109 /* G */ 226, 110 /* G# */ 242, 111 }; 112 113 #define NOTE_TO_OCTAVE(note) (((note)-CMS_FIRST_NOTE)/12) 114 #define NOTE_TO_COUNT(note) cms_note_table[(((note)-CMS_FIRST_NOTE)%12)] 115 116 int 117 cms_probe(device_t parent, cfdata_t match, void *aux) 118 { 119 struct isa_attach_args *ia = aux; 120 bus_space_tag_t iot; 121 bus_space_handle_t ioh; 122 int found = 0; 123 int i; 124 125 DPRINTF(("cms_probe():\n")); 126 127 iot = ia->ia_iot; 128 129 if (ia->ia_nio < 1) 130 return 0; 131 132 if (ISA_DIRECT_CONFIG(ia)) 133 return 0; 134 135 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 136 return 0; 137 138 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) 139 return 0; 140 141 bus_space_write_1(iot, ioh, CMS_WREG, 0xaa); 142 if (bus_space_read_1(iot, ioh, CMS_RREG) != 0xaa) 143 goto out; 144 145 for (i = 0; i < 8; i++) { 146 if (bus_space_read_1(iot, ioh, CMS_MREG) != 0x7f) 147 goto out; 148 } 149 found = 1; 150 151 ia->ia_nio = 1; 152 ia->ia_io[0].ir_size = CMS_IOSIZE; 153 154 ia->ia_niomem = 0; 155 ia->ia_nirq = 0; 156 ia->ia_ndrq = 0; 157 158 out: 159 bus_space_unmap(iot, ioh, CMS_IOSIZE); 160 161 return found; 162 } 163 164 165 void 166 cms_attach(device_t parent, device_t self, void *aux) 167 { 168 struct cms_softc *sc = device_private(self); 169 struct isa_attach_args *ia = aux; 170 bus_space_tag_t iot; 171 bus_space_handle_t ioh; 172 midisyn *ms; 173 struct audio_attach_args arg; 174 175 sc->sc_mididev.dev = self; 176 177 aprint_normal("\n"); 178 179 DPRINTF(("cms_attach():\n")); 180 181 iot = ia->ia_iot; 182 183 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) { 184 aprint_error_dev(self, "can't map i/o space\n"); 185 return; 186 } 187 188 sc->sc_iot = iot; 189 sc->sc_ioh = ioh; 190 191 /* now let's reset the chips */ 192 cms_reset(sc); 193 194 ms = &sc->sc_midisyn; 195 ms->mets = &midi_cms_hw; 196 strcpy(ms->name, "Creative Music System"); 197 ms->nvoice = CMS_NVOICES; 198 ms->data = sc; 199 200 /* use the synthesiser */ 201 midisyn_attach(&sc->sc_mididev, ms); 202 203 /* now attach the midi device to the synthesiser */ 204 arg.type = AUDIODEV_TYPE_MIDI; 205 arg.hwif = sc->sc_mididev.hw_if; 206 arg.hdl = sc->sc_mididev.hw_hdl; 207 config_found(self, &arg, 0); 208 } 209 210 211 int 212 cms_open(midisyn *ms, int flag) 213 { 214 struct cms_softc *sc = (struct cms_softc *)ms->data; 215 216 cms_reset(sc); 217 218 return 0; 219 } 220 221 void 222 cms_close(midisyn *ms) 223 { 224 struct cms_softc *sc = (struct cms_softc *)ms->data; 225 226 cms_reset(sc); 227 } 228 229 void 230 cms_on(midisyn *ms, uint_fast16_t vidx, midipitch_t mp, int16_t level_cB) 231 { 232 struct cms_softc *sc = (struct cms_softc *)ms->data; 233 int chip = CHAN_TO_CHIP(vidx); 234 int voice = CHAN_TO_VOICE(vidx); 235 uint32_t note; 236 u_int8_t octave; 237 u_int8_t count; 238 u_int8_t reg; 239 u_int8_t vol; 240 241 /* 242 * The next line is a regrettable hack, because it drops all pitch 243 * adjustment midisyn has supplied in miditune, so this synth will 244 * not respond to tuning, pitchbend, etc. It seems it ought to be 245 * possible to DTRT if the formula that generated the cms_note_table 246 * can be found, but I've had no luck, and a plot of the numbers in 247 * the table clearly curves the wrong way to be derived any obvious 248 * way from the equal tempered scale. (Or maybe the table's wrong? 249 * Has this device been playing flat up the scale? I don't have 250 * access to one to try.) 251 */ 252 note = MIDIPITCH_TO_KEY(mp); 253 254 if (note < CMS_FIRST_NOTE) 255 return; 256 257 octave = NOTE_TO_OCTAVE(note); 258 count = NOTE_TO_COUNT(note); 259 260 DPRINTF(("chip=%d voice=%d octave=%d count=%d offset=%d shift=%d\n", 261 chip, voice, octave, count, OCTAVE_OFFSET(voice), 262 OCTAVE_SHIFT(voice))); 263 264 /* write the count */ 265 CMS_WRITE(sc, chip, CMS_IREG_FREQ0 + voice, count); 266 267 /* select the octave */ 268 reg = CMS_READ(sc, chip, CMS_IREG_OCTAVE_1_0 + OCTAVE_OFFSET(voice)); 269 reg &= ~(0x0f<<OCTAVE_SHIFT(voice)); 270 reg |= ((octave&0x7)<<OCTAVE_SHIFT(voice)); 271 CMS_WRITE(sc, chip, CMS_IREG_OCTAVE_1_0 + OCTAVE_OFFSET(voice), reg); 272 273 /* set the volume */ 274 /* this may be the wrong curve but will do something. no docs! */ 275 vol = 15 + (level_cB > -75) ? level_cB/5 : -15; 276 CMS_WRITE(sc, chip, CMS_IREG_VOL0 + voice, ((vol<<4)|vol)); 277 278 /* enable the voice */ 279 reg = CMS_READ(sc, chip, CMS_IREG_FREQ_CTL); 280 reg |= (1<<voice); 281 CMS_WRITE(sc, chip, CMS_IREG_FREQ_CTL, reg); 282 } 283 284 void 285 cms_off(midisyn *ms, uint_fast16_t vidx, uint_fast8_t vel) 286 { 287 struct cms_softc *sc = (struct cms_softc *)ms->data; 288 int chip = CHAN_TO_CHIP(vidx); 289 int voice = CHAN_TO_VOICE(vidx); 290 u_int8_t reg; 291 292 /* disable the channel */ 293 reg = CMS_READ(sc, chip, CMS_IREG_FREQ_CTL); 294 reg &= ~(1<<voice); 295 CMS_WRITE(sc, chip, CMS_IREG_FREQ_CTL, reg); 296 } 297 298 static void 299 cms_reset(struct cms_softc *sc) 300 { 301 int i; 302 303 DPRINTF(("cms_reset():\n")); 304 305 for (i = 0; i < 6; i++) { 306 CMS_WRITE(sc, 0, CMS_IREG_VOL0+i, 0x00); 307 CMS_WRITE(sc, 1, CMS_IREG_VOL0+i, 0x00); 308 309 CMS_WRITE(sc, 0, CMS_IREG_FREQ0+i, 0x00); 310 CMS_WRITE(sc, 1, CMS_IREG_FREQ0+i, 0x00); 311 } 312 313 for (i = 0; i < 3; i++) { 314 CMS_WRITE(sc, 0, CMS_IREG_OCTAVE_1_0+i, 0x00); 315 CMS_WRITE(sc, 1, CMS_IREG_OCTAVE_1_0+i, 0x00); 316 } 317 318 CMS_WRITE(sc, 0, CMS_IREG_FREQ_CTL, 0x00); 319 CMS_WRITE(sc, 1, CMS_IREG_FREQ_CTL, 0x00); 320 321 CMS_WRITE(sc, 0, CMS_IREG_NOISE_CTL, 0x00); 322 CMS_WRITE(sc, 1, CMS_IREG_NOISE_CTL, 0x00); 323 324 CMS_WRITE(sc, 0, CMS_IREG_NOISE_BW, 0x00); 325 CMS_WRITE(sc, 1, CMS_IREG_NOISE_BW, 0x00); 326 327 /* 328 * These registers don't appear to be useful, but must be 329 * cleared otherwise certain voices don't work properly 330 */ 331 CMS_WRITE(sc, 0, 0x18, 0x00); 332 CMS_WRITE(sc, 1, 0x18, 0x00); 333 CMS_WRITE(sc, 0, 0x19, 0x00); 334 CMS_WRITE(sc, 1, 0x19, 0x00); 335 336 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 337 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 338 339 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 340 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 341 } 342