1 /* $NetBSD: cms.c,v 1.12 2006/06/30 13:56:25 chap 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.12 2006/06/30 13:56:25 chap 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 <machine/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(struct device *, struct cfdata *, void *); 79 void cms_attach(struct device *, struct device *, void *); 80 81 CFATTACH_DECL(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(parent, match, aux) 118 struct device *parent; 119 struct cfdata *match; 120 void *aux; 121 { 122 struct isa_attach_args *ia = aux; 123 bus_space_tag_t iot; 124 bus_space_handle_t ioh; 125 int found = 0; 126 int i; 127 128 DPRINTF(("cms_probe():\n")); 129 130 iot = ia->ia_iot; 131 132 if (ia->ia_nio < 1) 133 return 0; 134 135 if (ISA_DIRECT_CONFIG(ia)) 136 return 0; 137 138 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 139 return 0; 140 141 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) 142 return 0; 143 144 bus_space_write_1(iot, ioh, CMS_WREG, 0xaa); 145 if (bus_space_read_1(iot, ioh, CMS_RREG) != 0xaa) 146 goto out; 147 148 for (i = 0; i < 8; i++) { 149 if (bus_space_read_1(iot, ioh, CMS_MREG) != 0x7f) 150 goto out; 151 } 152 found = 1; 153 154 ia->ia_nio = 1; 155 ia->ia_io[0].ir_size = CMS_IOSIZE; 156 157 ia->ia_niomem = 0; 158 ia->ia_nirq = 0; 159 ia->ia_ndrq = 0; 160 161 out: 162 bus_space_unmap(iot, ioh, CMS_IOSIZE); 163 164 return found; 165 } 166 167 168 void 169 cms_attach(parent, self, aux) 170 struct device *parent, *self; 171 void *aux; 172 { 173 struct cms_softc *sc = (struct cms_softc *)self; 174 struct isa_attach_args *ia = aux; 175 bus_space_tag_t iot; 176 bus_space_handle_t ioh; 177 midisyn *ms; 178 struct audio_attach_args arg; 179 180 printf("\n"); 181 182 DPRINTF(("cms_attach():\n")); 183 184 iot = ia->ia_iot; 185 186 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) { 187 printf(": can't map i/o space\n"); 188 return; 189 } 190 191 sc->sc_iot = iot; 192 sc->sc_ioh = ioh; 193 194 /* now let's reset the chips */ 195 cms_reset(sc); 196 197 ms = &sc->sc_midisyn; 198 ms->mets = &midi_cms_hw; 199 strcpy(ms->name, "Creative Music System"); 200 ms->nvoice = CMS_NVOICES; 201 ms->data = sc; 202 203 /* use the synthesiser */ 204 midisyn_attach(&sc->sc_mididev, ms); 205 206 /* now attach the midi device to the synthesiser */ 207 arg.type = AUDIODEV_TYPE_MIDI; 208 arg.hwif = sc->sc_mididev.hw_if; 209 arg.hdl = sc->sc_mididev.hw_hdl; 210 config_found((struct device *)&sc->sc_mididev, &arg, 0); 211 } 212 213 214 int 215 cms_open(ms,flag) 216 midisyn *ms; 217 int flag; 218 { 219 struct cms_softc *sc = (struct cms_softc *)ms->data; 220 221 cms_reset(sc); 222 223 return 0; 224 } 225 226 void 227 cms_close(ms) 228 midisyn *ms; 229 { 230 struct cms_softc *sc = (struct cms_softc *)ms->data; 231 232 cms_reset(sc); 233 } 234 235 void 236 cms_on(midisyn *ms, uint_fast16_t vidx, midipitch_t mp, int16_t level_cB) 237 { 238 struct cms_softc *sc = (struct cms_softc *)ms->data; 239 int chip = CHAN_TO_CHIP(vidx); 240 int voice = CHAN_TO_VOICE(vidx); 241 uint32_t note; 242 u_int8_t octave; 243 u_int8_t count; 244 u_int8_t reg; 245 u_int8_t vol; 246 247 /* 248 * The next line is a regrettable hack, because it drops all pitch 249 * adjustment midisyn has supplied in miditune, so this synth will 250 * not respond to tuning, pitchbend, etc. It seems it ought to be 251 * possible to DTRT if the formula that generated the cms_note_table 252 * can be found, but I've had no luck, and a plot of the numbers in 253 * the table clearly curves the wrong way to be derived any obvious 254 * way from the equal tempered scale. (Or maybe the table's wrong? 255 * Has this device been playing flat up the scale? I don't have 256 * access to one to try.) 257 */ 258 note = MIDIPITCH_TO_KEY(mp); 259 260 if (note < CMS_FIRST_NOTE) 261 return; 262 263 octave = NOTE_TO_OCTAVE(note); 264 count = NOTE_TO_COUNT(note); 265 266 DPRINTF(("chip=%d voice=%d octave=%d count=%d offset=%d shift=%d\n", 267 chip, voice, octave, count, OCTAVE_OFFSET(voice), 268 OCTAVE_SHIFT(voice))); 269 270 /* write the count */ 271 CMS_WRITE(sc, chip, CMS_IREG_FREQ0 + voice, count); 272 273 /* select the octave */ 274 reg = CMS_READ(sc, chip, CMS_IREG_OCTAVE_1_0 + OCTAVE_OFFSET(voice)); 275 reg &= ~(0x0f<<OCTAVE_SHIFT(voice)); 276 reg |= ((octave&0x7)<<OCTAVE_SHIFT(voice)); 277 CMS_WRITE(sc, chip, CMS_IREG_OCTAVE_1_0 + OCTAVE_OFFSET(voice), reg); 278 279 /* set the volume */ 280 /* this may be the wrong curve but will do something. no docs! */ 281 vol = 15 + (level_cB > -75) ? level_cB/5 : -15; 282 CMS_WRITE(sc, chip, CMS_IREG_VOL0 + voice, ((vol<<4)|vol)); 283 284 /* enable the voice */ 285 reg = CMS_READ(sc, chip, CMS_IREG_FREQ_CTL); 286 reg |= (1<<voice); 287 CMS_WRITE(sc, chip, CMS_IREG_FREQ_CTL, reg); 288 } 289 290 void 291 cms_off(midisyn *ms, uint_fast16_t vidx, uint_fast8_t vel) 292 { 293 struct cms_softc *sc = (struct cms_softc *)ms->data; 294 int chip = CHAN_TO_CHIP(vidx); 295 int voice = CHAN_TO_VOICE(vidx); 296 u_int8_t reg; 297 298 /* disable the channel */ 299 reg = CMS_READ(sc, chip, CMS_IREG_FREQ_CTL); 300 reg &= ~(1<<voice); 301 CMS_WRITE(sc, chip, CMS_IREG_FREQ_CTL, reg); 302 } 303 304 static void 305 cms_reset(sc) 306 struct cms_softc *sc; 307 { 308 int i; 309 310 DPRINTF(("cms_reset():\n")); 311 312 for (i = 0; i < 6; i++) { 313 CMS_WRITE(sc, 0, CMS_IREG_VOL0+i, 0x00); 314 CMS_WRITE(sc, 1, CMS_IREG_VOL0+i, 0x00); 315 316 CMS_WRITE(sc, 0, CMS_IREG_FREQ0+i, 0x00); 317 CMS_WRITE(sc, 1, CMS_IREG_FREQ0+i, 0x00); 318 } 319 320 for (i = 0; i < 3; i++) { 321 CMS_WRITE(sc, 0, CMS_IREG_OCTAVE_1_0+i, 0x00); 322 CMS_WRITE(sc, 1, CMS_IREG_OCTAVE_1_0+i, 0x00); 323 } 324 325 CMS_WRITE(sc, 0, CMS_IREG_FREQ_CTL, 0x00); 326 CMS_WRITE(sc, 1, CMS_IREG_FREQ_CTL, 0x00); 327 328 CMS_WRITE(sc, 0, CMS_IREG_NOISE_CTL, 0x00); 329 CMS_WRITE(sc, 1, CMS_IREG_NOISE_CTL, 0x00); 330 331 CMS_WRITE(sc, 0, CMS_IREG_NOISE_BW, 0x00); 332 CMS_WRITE(sc, 1, CMS_IREG_NOISE_BW, 0x00); 333 334 /* 335 * These registers don't appear to be useful, but must be 336 * cleared otherwise certain voices don't work properly 337 */ 338 CMS_WRITE(sc, 0, 0x18, 0x00); 339 CMS_WRITE(sc, 1, 0x18, 0x00); 340 CMS_WRITE(sc, 0, 0x19, 0x00); 341 CMS_WRITE(sc, 1, 0x19, 0x00); 342 343 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 344 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 345 346 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 347 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 348 } 349