1 /* $NetBSD: cms.c,v 1.15 2007/10/19 12:00:15 ad 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.15 2007/10/19 12:00:15 ad 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(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(struct device *parent, struct cfdata *match, 118 void *aux) 119 { 120 struct isa_attach_args *ia = aux; 121 bus_space_tag_t iot; 122 bus_space_handle_t ioh; 123 int found = 0; 124 int i; 125 126 DPRINTF(("cms_probe():\n")); 127 128 iot = ia->ia_iot; 129 130 if (ia->ia_nio < 1) 131 return 0; 132 133 if (ISA_DIRECT_CONFIG(ia)) 134 return 0; 135 136 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT) 137 return 0; 138 139 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) 140 return 0; 141 142 bus_space_write_1(iot, ioh, CMS_WREG, 0xaa); 143 if (bus_space_read_1(iot, ioh, CMS_RREG) != 0xaa) 144 goto out; 145 146 for (i = 0; i < 8; i++) { 147 if (bus_space_read_1(iot, ioh, CMS_MREG) != 0x7f) 148 goto out; 149 } 150 found = 1; 151 152 ia->ia_nio = 1; 153 ia->ia_io[0].ir_size = CMS_IOSIZE; 154 155 ia->ia_niomem = 0; 156 ia->ia_nirq = 0; 157 ia->ia_ndrq = 0; 158 159 out: 160 bus_space_unmap(iot, ioh, CMS_IOSIZE); 161 162 return found; 163 } 164 165 166 void 167 cms_attach(struct device *parent, struct device *self, void *aux) 168 { 169 struct cms_softc *sc = (struct cms_softc *)self; 170 struct isa_attach_args *ia = aux; 171 bus_space_tag_t iot; 172 bus_space_handle_t ioh; 173 midisyn *ms; 174 struct audio_attach_args arg; 175 176 printf("\n"); 177 178 DPRINTF(("cms_attach():\n")); 179 180 iot = ia->ia_iot; 181 182 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) { 183 printf(": can't map i/o space\n"); 184 return; 185 } 186 187 sc->sc_iot = iot; 188 sc->sc_ioh = ioh; 189 190 /* now let's reset the chips */ 191 cms_reset(sc); 192 193 ms = &sc->sc_midisyn; 194 ms->mets = &midi_cms_hw; 195 strcpy(ms->name, "Creative Music System"); 196 ms->nvoice = CMS_NVOICES; 197 ms->data = sc; 198 199 /* use the synthesiser */ 200 midisyn_attach(&sc->sc_mididev, ms); 201 202 /* now attach the midi device to the synthesiser */ 203 arg.type = AUDIODEV_TYPE_MIDI; 204 arg.hwif = sc->sc_mididev.hw_if; 205 arg.hdl = sc->sc_mididev.hw_hdl; 206 config_found((struct device *)&sc->sc_mididev, &arg, 0); 207 } 208 209 210 int 211 cms_open(midisyn *ms, int flag) 212 { 213 struct cms_softc *sc = (struct cms_softc *)ms->data; 214 215 cms_reset(sc); 216 217 return 0; 218 } 219 220 void 221 cms_close(ms) 222 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(sc) 300 struct cms_softc *sc; 301 { 302 int i; 303 304 DPRINTF(("cms_reset():\n")); 305 306 for (i = 0; i < 6; i++) { 307 CMS_WRITE(sc, 0, CMS_IREG_VOL0+i, 0x00); 308 CMS_WRITE(sc, 1, CMS_IREG_VOL0+i, 0x00); 309 310 CMS_WRITE(sc, 0, CMS_IREG_FREQ0+i, 0x00); 311 CMS_WRITE(sc, 1, CMS_IREG_FREQ0+i, 0x00); 312 } 313 314 for (i = 0; i < 3; i++) { 315 CMS_WRITE(sc, 0, CMS_IREG_OCTAVE_1_0+i, 0x00); 316 CMS_WRITE(sc, 1, CMS_IREG_OCTAVE_1_0+i, 0x00); 317 } 318 319 CMS_WRITE(sc, 0, CMS_IREG_FREQ_CTL, 0x00); 320 CMS_WRITE(sc, 1, CMS_IREG_FREQ_CTL, 0x00); 321 322 CMS_WRITE(sc, 0, CMS_IREG_NOISE_CTL, 0x00); 323 CMS_WRITE(sc, 1, CMS_IREG_NOISE_CTL, 0x00); 324 325 CMS_WRITE(sc, 0, CMS_IREG_NOISE_BW, 0x00); 326 CMS_WRITE(sc, 1, CMS_IREG_NOISE_BW, 0x00); 327 328 /* 329 * These registers don't appear to be useful, but must be 330 * cleared otherwise certain voices don't work properly 331 */ 332 CMS_WRITE(sc, 0, 0x18, 0x00); 333 CMS_WRITE(sc, 1, 0x18, 0x00); 334 CMS_WRITE(sc, 0, 0x19, 0x00); 335 CMS_WRITE(sc, 1, 0x19, 0x00); 336 337 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 338 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 339 340 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 341 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 342 } 343