1 /* $NetBSD: cms.c,v 1.7 2002/10/02 03:10:46 thorpej 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.7 2002/10/02 03:10:46 thorpej 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 __P((struct device *, struct cfdata *, void *)); 79 void cms_attach __P((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 __P((midisyn *, int)); 85 void cms_close __P((midisyn *)); 86 void cms_on __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); 87 void cms_off __P((midisyn *, u_int32_t, u_int32_t, u_int32_t)); 88 89 struct midisyn_methods midi_cms_hw = { 90 cms_open, /* open */ 91 cms_close, /* close */ 92 0, /* ioctl */ 93 0, /* allocv */ 94 cms_on, /* noteon */ 95 cms_off, /* noteoff */ 96 0, /* keypres */ 97 0, /* ctlchg */ 98 0, /* pgmchg */ 99 0, /* chnpres */ 100 0, /* pitchb */ 101 0, /* sysex */ 102 }; 103 104 static void cms_reset __P((struct cms_softc *)); 105 106 static char cms_note_table[] = { 107 /* A */ 3, 108 /* A# */ 31, 109 /* B */ 58, 110 /* C */ 83, 111 /* C# */ 107, 112 /* D */ 130, 113 /* D# */ 151, 114 /* E */ 172, 115 /* F */ 191, 116 /* F# */ 209, 117 /* G */ 226, 118 /* G# */ 242, 119 }; 120 121 #define NOTE_TO_OCTAVE(note) (((note)-CMS_FIRST_NOTE)/12) 122 #define NOTE_TO_COUNT(note) cms_note_table[(((note)-CMS_FIRST_NOTE)%12)] 123 124 int 125 cms_probe(parent, match, aux) 126 struct device *parent; 127 struct cfdata *match; 128 void *aux; 129 { 130 struct isa_attach_args *ia = aux; 131 bus_space_tag_t iot; 132 bus_space_handle_t ioh; 133 int found = 0; 134 int i; 135 136 DPRINTF(("cms_probe():\n")); 137 138 iot = ia->ia_iot; 139 140 if (ia->ia_nio < 1) 141 return 0; 142 143 if (ISA_DIRECT_CONFIG(ia)) 144 return 0; 145 146 if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT) 147 return 0; 148 149 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) 150 return 0; 151 152 bus_space_write_1(iot, ioh, CMS_WREG, 0xaa); 153 if (bus_space_read_1(iot, ioh, CMS_RREG) != 0xaa) 154 goto out; 155 156 for (i = 0; i < 8; i++) { 157 if (bus_space_read_1(iot, ioh, CMS_MREG) != 0x7f) 158 goto out; 159 } 160 found = 1; 161 162 ia->ia_nio = 1; 163 ia->ia_io[0].ir_size = CMS_IOSIZE; 164 165 ia->ia_niomem = 0; 166 ia->ia_nirq = 0; 167 ia->ia_ndrq = 0; 168 169 out: 170 bus_space_unmap(iot, ioh, CMS_IOSIZE); 171 172 return found; 173 } 174 175 176 void 177 cms_attach(parent, self, aux) 178 struct device *parent, *self; 179 void *aux; 180 { 181 struct cms_softc *sc = (struct cms_softc *)self; 182 struct isa_attach_args *ia = aux; 183 bus_space_tag_t iot; 184 bus_space_handle_t ioh; 185 midisyn *ms; 186 struct audio_attach_args arg; 187 188 printf("\n"); 189 190 DPRINTF(("cms_attach():\n")); 191 192 iot = ia->ia_iot; 193 194 if (bus_space_map(iot, ia->ia_io[0].ir_addr, CMS_IOSIZE, 0, &ioh)) { 195 printf(": can't map i/o space\n"); 196 return; 197 } 198 199 sc->sc_iot = iot; 200 sc->sc_ioh = ioh; 201 202 /* now let's reset the chips */ 203 cms_reset(sc); 204 205 ms = &sc->sc_midisyn; 206 ms->mets = &midi_cms_hw; 207 strcpy(ms->name, "Creative Music System"); 208 ms->nvoice = CMS_NVOICES; 209 ms->flags = MS_DOALLOC; 210 ms->data = sc; 211 212 /* use the synthesiser */ 213 midisyn_attach(&sc->sc_mididev, ms); 214 215 /* now attach the midi device to the synthesiser */ 216 arg.type = AUDIODEV_TYPE_MIDI; 217 arg.hwif = sc->sc_mididev.hw_if; 218 arg.hdl = sc->sc_mididev.hw_hdl; 219 config_found((struct device *)&sc->sc_mididev, &arg, 0); 220 } 221 222 223 int 224 cms_open(ms,flag) 225 midisyn *ms; 226 int flag; 227 { 228 struct cms_softc *sc = (struct cms_softc *)ms->data; 229 230 cms_reset(sc); 231 232 return 0; 233 } 234 235 void 236 cms_close(ms) 237 midisyn *ms; 238 { 239 struct cms_softc *sc = (struct cms_softc *)ms->data; 240 241 cms_reset(sc); 242 } 243 244 void 245 cms_on(ms, chan, note, vel) 246 midisyn *ms; 247 u_int32_t chan; 248 u_int32_t note; 249 u_int32_t vel; 250 { 251 struct cms_softc *sc = (struct cms_softc *)ms->data; 252 int chip = CHAN_TO_CHIP(chan); 253 int voice = CHAN_TO_VOICE(chan); 254 u_int8_t octave; 255 u_int8_t count; 256 u_int8_t reg; 257 u_int8_t vol; 258 259 if (note < CMS_FIRST_NOTE) 260 return; 261 262 octave = NOTE_TO_OCTAVE(note); 263 count = NOTE_TO_COUNT(note); 264 265 DPRINTF(("chip=%d voice=%d octave=%d count=%d offset=%d shift=%d\n", 266 chip, voice, octave, count, OCTAVE_OFFSET(voice), 267 OCTAVE_SHIFT(voice))); 268 269 /* write the count */ 270 CMS_WRITE(sc, chip, CMS_IREG_FREQ0 + voice, count); 271 272 /* select the octave */ 273 reg = CMS_READ(sc, chip, CMS_IREG_OCTAVE_1_0 + OCTAVE_OFFSET(voice)); 274 reg &= ~(0x0f<<OCTAVE_SHIFT(voice)); 275 reg |= ((octave&0x7)<<OCTAVE_SHIFT(voice)); 276 CMS_WRITE(sc, chip, CMS_IREG_OCTAVE_1_0 + OCTAVE_OFFSET(voice), reg); 277 278 /* set the volume */ 279 vol = (vel>>3)&0x0f; 280 CMS_WRITE(sc, chip, CMS_IREG_VOL0 + voice, ((vol<<4)|vol)); 281 282 /* enable the voice */ 283 reg = CMS_READ(sc, chip, CMS_IREG_FREQ_CTL); 284 reg |= (1<<voice); 285 CMS_WRITE(sc, chip, CMS_IREG_FREQ_CTL, reg); 286 } 287 288 void 289 cms_off(ms, chan, note, vel) 290 midisyn *ms; 291 u_int32_t chan; 292 u_int32_t note; 293 u_int32_t vel; 294 { 295 struct cms_softc *sc = (struct cms_softc *)ms->data; 296 int chip = CHAN_TO_CHIP(chan); 297 int voice = CHAN_TO_VOICE(chan); 298 u_int8_t reg; 299 300 if (note < CMS_FIRST_NOTE) 301 return; 302 303 /* disable the channel */ 304 reg = CMS_READ(sc, chip, CMS_IREG_FREQ_CTL); 305 reg &= ~(1<<voice); 306 CMS_WRITE(sc, chip, CMS_IREG_FREQ_CTL, reg); 307 } 308 309 static void 310 cms_reset(sc) 311 struct cms_softc *sc; 312 { 313 int i; 314 315 DPRINTF(("cms_reset():\n")); 316 317 for (i = 0; i < 6; i++) { 318 CMS_WRITE(sc, 0, CMS_IREG_VOL0+i, 0x00); 319 CMS_WRITE(sc, 1, CMS_IREG_VOL0+i, 0x00); 320 321 CMS_WRITE(sc, 0, CMS_IREG_FREQ0+i, 0x00); 322 CMS_WRITE(sc, 1, CMS_IREG_FREQ0+i, 0x00); 323 } 324 325 for (i = 0; i < 3; i++) { 326 CMS_WRITE(sc, 0, CMS_IREG_OCTAVE_1_0+i, 0x00); 327 CMS_WRITE(sc, 1, CMS_IREG_OCTAVE_1_0+i, 0x00); 328 } 329 330 CMS_WRITE(sc, 0, CMS_IREG_FREQ_CTL, 0x00); 331 CMS_WRITE(sc, 1, CMS_IREG_FREQ_CTL, 0x00); 332 333 CMS_WRITE(sc, 0, CMS_IREG_NOISE_CTL, 0x00); 334 CMS_WRITE(sc, 1, CMS_IREG_NOISE_CTL, 0x00); 335 336 CMS_WRITE(sc, 0, CMS_IREG_NOISE_BW, 0x00); 337 CMS_WRITE(sc, 1, CMS_IREG_NOISE_BW, 0x00); 338 339 /* 340 * These registers don't appear to be useful, but must be 341 * cleared otherwise certain voices don't work properly 342 */ 343 CMS_WRITE(sc, 0, 0x18, 0x00); 344 CMS_WRITE(sc, 1, 0x18, 0x00); 345 CMS_WRITE(sc, 0, 0x19, 0x00); 346 CMS_WRITE(sc, 1, 0x19, 0x00); 347 348 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 349 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_RESET); 350 351 CMS_WRITE(sc, 0, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 352 CMS_WRITE(sc, 1, CMS_IREG_SYS_CTL, CMS_IREG_SYS_ENBL); 353 } 354