Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | // SPDX-License-Identifier: GPL-2.0 /* * Mac bong noise generator. Note - we ought to put a boingy noise * here 8) * * ---------------------------------------------------------------------- * 16.11.98: * rewrote some functions, added support for Enhanced ASC (Quadras) * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck * Juergen Mellinger (juergen.mellinger@t-online.de) */ #include <linux/sched.h> #include <linux/timer.h> #include <asm/macintosh.h> #include <asm/mac_asc.h> static int mac_asc_inited; /* * dumb triangular wave table */ static __u8 mac_asc_wave_tab[ 0x800 ]; /* * Alan's original sine table; needs interpolating to 0x800 * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric) */ static const signed char sine_data[] = { 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 }; /* * where the ASC hides ... */ static volatile __u8* mac_asc_regs = ( void* )0x50F14000; /* * sample rate; is this a good default value? */ static unsigned long mac_asc_samplespersec = 11050; static int mac_bell_duration; static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */ static unsigned long mac_bell_phasepersample; /* * some function protos */ static void mac_init_asc( void ); static void mac_nosound(struct timer_list *); static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int ); static void mac_quadra_ring_bell(struct timer_list *); static void mac_av_start_bell( unsigned int, unsigned int, unsigned int ); static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ); /* * our timer to start/continue/stop the bell */ static DEFINE_TIMER(mac_sound_timer, mac_nosound); /* * Sort of initialize the sound chip (called from mac_mksound on the first * beep). */ static void mac_init_asc( void ) { int i; /* * do some machine specific initialization * BTW: * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via * mac_asc_regs[ 0x800 ] & 0xF0 != 0 * this makes no sense here, because we have to set the default sample * rate anyway if we want correct frequencies */ switch ( macintosh_config->ident ) { case MAC_MODEL_IIFX: /* * The IIfx is always special ... */ mac_asc_regs = ( void* )0x50010000; break; /* * not sure about how correct this list is * machines with the EASC enhanced apple sound chip */ case MAC_MODEL_Q630: case MAC_MODEL_P475: mac_special_bell = mac_quadra_start_bell; mac_asc_samplespersec = 22150; break; case MAC_MODEL_C660: case MAC_MODEL_Q840: /* * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. * It appears to be similar to the "AWACS" custom ASIC in the Power Mac * [678]100. Because Singer and AWACS may have a similar hardware * interface, this would imply that the code in drivers/sound/dmasound.c * for AWACS could be used as a basis for Singer support. All we have to * do is figure out how to do DMA on the 660AV/840AV through the PSC and * figure out where the Singer hardware sits in memory. (I'd look in the * vicinity of the AWACS location in a Power Mac [678]100 first, or the * current location of the Apple Sound Chip--ASC--in other Macs.) The * Power Mac [678]100 info can be found in MkLinux Mach kernel sources. * * Quoted from Apple's Tech Info Library, article number 16405: * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power * Macintosh models have 16-bit audio input and output capability * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer * codec circuitry in the AVs. The Audio Waveform Amplifier and * Converter (AWAC) chip in the Power Macintosh performs the same * 16-bit I/O functionality. The PowerBook 500 series computers * support 16-bit stereo output, but only mono input." * * Technical Information Library (TIL) article number 16405. * http://support.apple.com/kb/TA32601 * * --David Kilzer */ mac_special_bell = mac_av_start_bell; break; case MAC_MODEL_Q650: case MAC_MODEL_Q700: case MAC_MODEL_Q800: case MAC_MODEL_Q900: case MAC_MODEL_Q950: /* * Currently not implemented! */ mac_special_bell = NULL; break; default: /* * Every switch needs a default */ mac_special_bell = NULL; break; } /* * init the wave table with a simple triangular wave * A sine wave would sure be nicer here ... */ for ( i = 0; i < 0x400; i++ ) { mac_asc_wave_tab[ i ] = i / 4; mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4; } mac_asc_inited = 1; } /* * Called to make noise; current single entry to the boing driver. * Does the job for simple ASC, calls other routines else. * XXX Fixme: * Should be split into asc_mksound, easc_mksound, av_mksound and * function pointer set in mac_init_asc which would be called at * init time. * _This_ is rather ugly ... */ void mac_mksound( unsigned int freq, unsigned int length ) { __u32 cfreq = ( freq << 5 ) / 468; unsigned long flags; int i; if ( mac_special_bell == NULL ) { /* Do nothing */ return; } if ( !mac_asc_inited ) mac_init_asc(); if ( mac_special_bell ) { mac_special_bell( freq, length, 128 ); return; } if ( freq < 20 || freq > 20000 || length == 0 ) { mac_nosound( 0 ); return; } local_irq_save(flags); del_timer( &mac_sound_timer ); for ( i = 0; i < 0x800; i++ ) mac_asc_regs[ i ] = 0; for ( i = 0; i < 0x800; i++ ) mac_asc_regs[ i ] = mac_asc_wave_tab[ i ]; for ( i = 0; i < 8; i++ ) *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq; mac_asc_regs[ 0x807 ] = 0; mac_asc_regs[ ASC_VOLUME ] = 128; mac_asc_regs[ 0x805 ] = 0; mac_asc_regs[ 0x80F ] = 0; mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE; mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE; mac_sound_timer.expires = jiffies + length; add_timer( &mac_sound_timer ); local_irq_restore(flags); } /* * regular ASC: stop whining .. */ static void mac_nosound(struct timer_list *unused) { mac_asc_regs[ ASC_ENABLE ] = 0; } /* * EASC entry; init EASC, don't load wavetable, schedule 'start whining'. */ static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) { unsigned long flags; /* if the bell is already ringing, ring longer */ if ( mac_bell_duration > 0 ) { mac_bell_duration += length; return; } mac_bell_duration = length; mac_bell_phase = 0; mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec; /* this is reasonably big for small frequencies */ local_irq_save(flags); /* set the volume */ mac_asc_regs[ 0x806 ] = volume; /* set up the ASC registers */ if ( mac_asc_regs[ 0x801 ] != 1 ) { /* select mono mode */ mac_asc_regs[ 0x807 ] = 0; /* select sampled sound mode */ mac_asc_regs[ 0x802 ] = 0; /* ??? */ mac_asc_regs[ 0x801 ] = 1; mac_asc_regs[ 0x803 ] |= 0x80; mac_asc_regs[ 0x803 ] &= 0x7F; } mac_sound_timer.function = mac_quadra_ring_bell; mac_sound_timer.expires = jiffies + 1; add_timer( &mac_sound_timer ); local_irq_restore(flags); } /* * EASC 'start/continue whining'; I'm not sure why the above function didn't * already load the wave table, or at least call this one... * This piece keeps reloading the wave table until done. */ static void mac_quadra_ring_bell(struct timer_list *unused) { int i, count = mac_asc_samplespersec / HZ; unsigned long flags; /* * we neither want a sound buffer overflow nor underflow, so we need to match * the number of samples per timer interrupt as exactly as possible. * using the asc interrupt will give better results in the future * ...and the possibility to use a real sample (a boingy noise, maybe...) */ local_irq_save(flags); del_timer( &mac_sound_timer ); if ( mac_bell_duration-- > 0 ) { for ( i = 0; i < count; i++ ) { mac_bell_phase += mac_bell_phasepersample; mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ]; } mac_sound_timer.expires = jiffies + 1; add_timer( &mac_sound_timer ); } else mac_asc_regs[ 0x801 ] = 0; local_irq_restore(flags); } /* * AV code - please fill in. */ static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) { } |