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