162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Mac bong noise generator. Note - we ought to put a boingy noise 462306a36Sopenharmony_ci * here 8) 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * ---------------------------------------------------------------------- 762306a36Sopenharmony_ci * 16.11.98: 862306a36Sopenharmony_ci * rewrote some functions, added support for Enhanced ASC (Quadras) 962306a36Sopenharmony_ci * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck 1062306a36Sopenharmony_ci * Juergen Mellinger (juergen.mellinger@t-online.de) 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/timer.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/macintosh.h> 1762306a36Sopenharmony_ci#include <asm/mac_asc.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int mac_asc_inited; 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * dumb triangular wave table 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistatic __u8 mac_asc_wave_tab[ 0x800 ]; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Alan's original sine table; needs interpolating to 0x800 2762306a36Sopenharmony_ci * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric) 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic const signed char sine_data[] = { 3062306a36Sopenharmony_ci 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, 3162306a36Sopenharmony_ci 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * where the ASC hides ... 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic volatile __u8* mac_asc_regs = ( void* )0x50F14000; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * sample rate; is this a good default value? 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic unsigned long mac_asc_samplespersec = 11050; 4362306a36Sopenharmony_cistatic int mac_bell_duration; 4462306a36Sopenharmony_cistatic unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */ 4562306a36Sopenharmony_cistatic unsigned long mac_bell_phasepersample; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * some function protos 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic void mac_init_asc( void ); 5162306a36Sopenharmony_cistatic void mac_nosound(struct timer_list *); 5262306a36Sopenharmony_cistatic void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int ); 5362306a36Sopenharmony_cistatic void mac_quadra_ring_bell(struct timer_list *); 5462306a36Sopenharmony_cistatic void mac_av_start_bell( unsigned int, unsigned int, unsigned int ); 5562306a36Sopenharmony_cistatic void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * our timer to start/continue/stop the bell 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic DEFINE_TIMER(mac_sound_timer, mac_nosound); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * Sort of initialize the sound chip (called from mac_mksound on the first 6462306a36Sopenharmony_ci * beep). 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic void mac_init_asc( void ) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci int i; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * do some machine specific initialization 7262306a36Sopenharmony_ci * BTW: 7362306a36Sopenharmony_ci * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via 7462306a36Sopenharmony_ci * mac_asc_regs[ 0x800 ] & 0xF0 != 0 7562306a36Sopenharmony_ci * this makes no sense here, because we have to set the default sample 7662306a36Sopenharmony_ci * rate anyway if we want correct frequencies 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci switch ( macintosh_config->ident ) 7962306a36Sopenharmony_ci { 8062306a36Sopenharmony_ci case MAC_MODEL_IIFX: 8162306a36Sopenharmony_ci /* 8262306a36Sopenharmony_ci * The IIfx is always special ... 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci mac_asc_regs = ( void* )0x50010000; 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * not sure about how correct this list is 8862306a36Sopenharmony_ci * machines with the EASC enhanced apple sound chip 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci case MAC_MODEL_Q630: 9162306a36Sopenharmony_ci case MAC_MODEL_P475: 9262306a36Sopenharmony_ci mac_special_bell = mac_quadra_start_bell; 9362306a36Sopenharmony_ci mac_asc_samplespersec = 22150; 9462306a36Sopenharmony_ci break; 9562306a36Sopenharmony_ci case MAC_MODEL_C660: 9662306a36Sopenharmony_ci case MAC_MODEL_Q840: 9762306a36Sopenharmony_ci /* 9862306a36Sopenharmony_ci * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. 9962306a36Sopenharmony_ci * It appears to be similar to the "AWACS" custom ASIC in the Power Mac 10062306a36Sopenharmony_ci * [678]100. Because Singer and AWACS may have a similar hardware 10162306a36Sopenharmony_ci * interface, this would imply that the code in drivers/sound/dmasound.c 10262306a36Sopenharmony_ci * for AWACS could be used as a basis for Singer support. All we have to 10362306a36Sopenharmony_ci * do is figure out how to do DMA on the 660AV/840AV through the PSC and 10462306a36Sopenharmony_ci * figure out where the Singer hardware sits in memory. (I'd look in the 10562306a36Sopenharmony_ci * vicinity of the AWACS location in a Power Mac [678]100 first, or the 10662306a36Sopenharmony_ci * current location of the Apple Sound Chip--ASC--in other Macs.) The 10762306a36Sopenharmony_ci * Power Mac [678]100 info can be found in MkLinux Mach kernel sources. 10862306a36Sopenharmony_ci * 10962306a36Sopenharmony_ci * Quoted from Apple's Tech Info Library, article number 16405: 11062306a36Sopenharmony_ci * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power 11162306a36Sopenharmony_ci * Macintosh models have 16-bit audio input and output capability 11262306a36Sopenharmony_ci * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer 11362306a36Sopenharmony_ci * codec circuitry in the AVs. The Audio Waveform Amplifier and 11462306a36Sopenharmony_ci * Converter (AWAC) chip in the Power Macintosh performs the same 11562306a36Sopenharmony_ci * 16-bit I/O functionality. The PowerBook 500 series computers 11662306a36Sopenharmony_ci * support 16-bit stereo output, but only mono input." 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * Technical Information Library (TIL) article number 16405. 11962306a36Sopenharmony_ci * https://support.apple.com/kb/TA32601 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * --David Kilzer 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci mac_special_bell = mac_av_start_bell; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case MAC_MODEL_Q650: 12662306a36Sopenharmony_ci case MAC_MODEL_Q700: 12762306a36Sopenharmony_ci case MAC_MODEL_Q800: 12862306a36Sopenharmony_ci case MAC_MODEL_Q900: 12962306a36Sopenharmony_ci case MAC_MODEL_Q950: 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * Currently not implemented! 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci mac_special_bell = NULL; 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci default: 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * Every switch needs a default 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci mac_special_bell = NULL; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * init the wave table with a simple triangular wave 14562306a36Sopenharmony_ci * A sine wave would sure be nicer here ... 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci for ( i = 0; i < 0x400; i++ ) 14862306a36Sopenharmony_ci { 14962306a36Sopenharmony_ci mac_asc_wave_tab[ i ] = i / 4; 15062306a36Sopenharmony_ci mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci mac_asc_inited = 1; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* 15662306a36Sopenharmony_ci * Called to make noise; current single entry to the boing driver. 15762306a36Sopenharmony_ci * Does the job for simple ASC, calls other routines else. 15862306a36Sopenharmony_ci * XXX Fixme: 15962306a36Sopenharmony_ci * Should be split into asc_mksound, easc_mksound, av_mksound and 16062306a36Sopenharmony_ci * function pointer set in mac_init_asc which would be called at 16162306a36Sopenharmony_ci * init time. 16262306a36Sopenharmony_ci * _This_ is rather ugly ... 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_civoid mac_mksound( unsigned int freq, unsigned int length ) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci __u32 cfreq = ( freq << 5 ) / 468; 16762306a36Sopenharmony_ci unsigned long flags; 16862306a36Sopenharmony_ci int i; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if ( mac_special_bell == NULL ) 17162306a36Sopenharmony_ci { 17262306a36Sopenharmony_ci /* Do nothing */ 17362306a36Sopenharmony_ci return; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if ( !mac_asc_inited ) 17762306a36Sopenharmony_ci mac_init_asc(); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if ( mac_special_bell ) 18062306a36Sopenharmony_ci { 18162306a36Sopenharmony_ci mac_special_bell( freq, length, 128 ); 18262306a36Sopenharmony_ci return; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if ( freq < 20 || freq > 20000 || length == 0 ) 18662306a36Sopenharmony_ci { 18762306a36Sopenharmony_ci mac_nosound( 0 ); 18862306a36Sopenharmony_ci return; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci local_irq_save(flags); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci del_timer( &mac_sound_timer ); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci for ( i = 0; i < 0x800; i++ ) 19662306a36Sopenharmony_ci mac_asc_regs[ i ] = 0; 19762306a36Sopenharmony_ci for ( i = 0; i < 0x800; i++ ) 19862306a36Sopenharmony_ci mac_asc_regs[ i ] = mac_asc_wave_tab[ i ]; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci for ( i = 0; i < 8; i++ ) 20162306a36Sopenharmony_ci *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci mac_asc_regs[ 0x807 ] = 0; 20462306a36Sopenharmony_ci mac_asc_regs[ ASC_VOLUME ] = 128; 20562306a36Sopenharmony_ci mac_asc_regs[ 0x805 ] = 0; 20662306a36Sopenharmony_ci mac_asc_regs[ 0x80F ] = 0; 20762306a36Sopenharmony_ci mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE; 20862306a36Sopenharmony_ci mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci mac_sound_timer.expires = jiffies + length; 21162306a36Sopenharmony_ci add_timer( &mac_sound_timer ); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci local_irq_restore(flags); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* 21762306a36Sopenharmony_ci * regular ASC: stop whining .. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistatic void mac_nosound(struct timer_list *unused) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci mac_asc_regs[ ASC_ENABLE ] = 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/* 22562306a36Sopenharmony_ci * EASC entry; init EASC, don't load wavetable, schedule 'start whining'. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_cistatic void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci unsigned long flags; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* if the bell is already ringing, ring longer */ 23262306a36Sopenharmony_ci if ( mac_bell_duration > 0 ) 23362306a36Sopenharmony_ci { 23462306a36Sopenharmony_ci mac_bell_duration += length; 23562306a36Sopenharmony_ci return; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci mac_bell_duration = length; 23962306a36Sopenharmony_ci mac_bell_phase = 0; 24062306a36Sopenharmony_ci mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec; 24162306a36Sopenharmony_ci /* this is reasonably big for small frequencies */ 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci local_irq_save(flags); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* set the volume */ 24662306a36Sopenharmony_ci mac_asc_regs[ 0x806 ] = volume; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* set up the ASC registers */ 24962306a36Sopenharmony_ci if ( mac_asc_regs[ 0x801 ] != 1 ) 25062306a36Sopenharmony_ci { 25162306a36Sopenharmony_ci /* select mono mode */ 25262306a36Sopenharmony_ci mac_asc_regs[ 0x807 ] = 0; 25362306a36Sopenharmony_ci /* select sampled sound mode */ 25462306a36Sopenharmony_ci mac_asc_regs[ 0x802 ] = 0; 25562306a36Sopenharmony_ci /* ??? */ 25662306a36Sopenharmony_ci mac_asc_regs[ 0x801 ] = 1; 25762306a36Sopenharmony_ci mac_asc_regs[ 0x803 ] |= 0x80; 25862306a36Sopenharmony_ci mac_asc_regs[ 0x803 ] &= 0x7F; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci mac_sound_timer.function = mac_quadra_ring_bell; 26262306a36Sopenharmony_ci mac_sound_timer.expires = jiffies + 1; 26362306a36Sopenharmony_ci add_timer( &mac_sound_timer ); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci local_irq_restore(flags); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* 26962306a36Sopenharmony_ci * EASC 'start/continue whining'; I'm not sure why the above function didn't 27062306a36Sopenharmony_ci * already load the wave table, or at least call this one... 27162306a36Sopenharmony_ci * This piece keeps reloading the wave table until done. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_cistatic void mac_quadra_ring_bell(struct timer_list *unused) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci int i, count = mac_asc_samplespersec / HZ; 27662306a36Sopenharmony_ci unsigned long flags; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * we neither want a sound buffer overflow nor underflow, so we need to match 28062306a36Sopenharmony_ci * the number of samples per timer interrupt as exactly as possible. 28162306a36Sopenharmony_ci * using the asc interrupt will give better results in the future 28262306a36Sopenharmony_ci * ...and the possibility to use a real sample (a boingy noise, maybe...) 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci local_irq_save(flags); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci del_timer( &mac_sound_timer ); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if ( mac_bell_duration-- > 0 ) 29062306a36Sopenharmony_ci { 29162306a36Sopenharmony_ci for ( i = 0; i < count; i++ ) 29262306a36Sopenharmony_ci { 29362306a36Sopenharmony_ci mac_bell_phase += mac_bell_phasepersample; 29462306a36Sopenharmony_ci mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ]; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci mac_sound_timer.expires = jiffies + 1; 29762306a36Sopenharmony_ci add_timer( &mac_sound_timer ); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci else 30062306a36Sopenharmony_ci mac_asc_regs[ 0x801 ] = 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci local_irq_restore(flags); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* 30662306a36Sopenharmony_ci * AV code - please fill in. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_cistatic void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci} 311