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