18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Mac bong noise generator. Note - we ought to put a boingy noise 48c2ecf20Sopenharmony_ci * here 8) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * ---------------------------------------------------------------------- 78c2ecf20Sopenharmony_ci * 16.11.98: 88c2ecf20Sopenharmony_ci * rewrote some functions, added support for Enhanced ASC (Quadras) 98c2ecf20Sopenharmony_ci * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck 108c2ecf20Sopenharmony_ci * Juergen Mellinger (juergen.mellinger@t-online.de) 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/sched.h> 148c2ecf20Sopenharmony_ci#include <linux/timer.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/macintosh.h> 178c2ecf20Sopenharmony_ci#include <asm/mac_asc.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int mac_asc_inited; 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * dumb triangular wave table 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistatic __u8 mac_asc_wave_tab[ 0x800 ]; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * Alan's original sine table; needs interpolating to 0x800 278c2ecf20Sopenharmony_ci * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric) 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic const signed char sine_data[] = { 308c2ecf20Sopenharmony_ci 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, 318c2ecf20Sopenharmony_ci 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * where the ASC hides ... 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic volatile __u8* mac_asc_regs = ( void* )0x50F14000; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * sample rate; is this a good default value? 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cistatic unsigned long mac_asc_samplespersec = 11050; 438c2ecf20Sopenharmony_cistatic int mac_bell_duration; 448c2ecf20Sopenharmony_cistatic unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */ 458c2ecf20Sopenharmony_cistatic unsigned long mac_bell_phasepersample; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * some function protos 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_cistatic void mac_init_asc( void ); 518c2ecf20Sopenharmony_cistatic void mac_nosound(struct timer_list *); 528c2ecf20Sopenharmony_cistatic void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int ); 538c2ecf20Sopenharmony_cistatic void mac_quadra_ring_bell(struct timer_list *); 548c2ecf20Sopenharmony_cistatic void mac_av_start_bell( unsigned int, unsigned int, unsigned int ); 558c2ecf20Sopenharmony_cistatic void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * our timer to start/continue/stop the bell 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_cistatic DEFINE_TIMER(mac_sound_timer, mac_nosound); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * Sort of initialize the sound chip (called from mac_mksound on the first 648c2ecf20Sopenharmony_ci * beep). 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic void mac_init_asc( void ) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int i; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* 718c2ecf20Sopenharmony_ci * do some machine specific initialization 728c2ecf20Sopenharmony_ci * BTW: 738c2ecf20Sopenharmony_ci * the NetBSD Quadra patch identifies the Enhanced Apple Sound Chip via 748c2ecf20Sopenharmony_ci * mac_asc_regs[ 0x800 ] & 0xF0 != 0 758c2ecf20Sopenharmony_ci * this makes no sense here, because we have to set the default sample 768c2ecf20Sopenharmony_ci * rate anyway if we want correct frequencies 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci switch ( macintosh_config->ident ) 798c2ecf20Sopenharmony_ci { 808c2ecf20Sopenharmony_ci case MAC_MODEL_IIFX: 818c2ecf20Sopenharmony_ci /* 828c2ecf20Sopenharmony_ci * The IIfx is always special ... 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci mac_asc_regs = ( void* )0x50010000; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * not sure about how correct this list is 888c2ecf20Sopenharmony_ci * machines with the EASC enhanced apple sound chip 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci case MAC_MODEL_Q630: 918c2ecf20Sopenharmony_ci case MAC_MODEL_P475: 928c2ecf20Sopenharmony_ci mac_special_bell = mac_quadra_start_bell; 938c2ecf20Sopenharmony_ci mac_asc_samplespersec = 22150; 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci case MAC_MODEL_C660: 968c2ecf20Sopenharmony_ci case MAC_MODEL_Q840: 978c2ecf20Sopenharmony_ci /* 988c2ecf20Sopenharmony_ci * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O. 998c2ecf20Sopenharmony_ci * It appears to be similar to the "AWACS" custom ASIC in the Power Mac 1008c2ecf20Sopenharmony_ci * [678]100. Because Singer and AWACS may have a similar hardware 1018c2ecf20Sopenharmony_ci * interface, this would imply that the code in drivers/sound/dmasound.c 1028c2ecf20Sopenharmony_ci * for AWACS could be used as a basis for Singer support. All we have to 1038c2ecf20Sopenharmony_ci * do is figure out how to do DMA on the 660AV/840AV through the PSC and 1048c2ecf20Sopenharmony_ci * figure out where the Singer hardware sits in memory. (I'd look in the 1058c2ecf20Sopenharmony_ci * vicinity of the AWACS location in a Power Mac [678]100 first, or the 1068c2ecf20Sopenharmony_ci * current location of the Apple Sound Chip--ASC--in other Macs.) The 1078c2ecf20Sopenharmony_ci * Power Mac [678]100 info can be found in MkLinux Mach kernel sources. 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * Quoted from Apple's Tech Info Library, article number 16405: 1108c2ecf20Sopenharmony_ci * "Among desktop Macintosh computers, only the 660AV, 840AV, and Power 1118c2ecf20Sopenharmony_ci * Macintosh models have 16-bit audio input and output capability 1128c2ecf20Sopenharmony_ci * because of the AT&T DSP3210 hardware circuitry and the 16-bit Singer 1138c2ecf20Sopenharmony_ci * codec circuitry in the AVs. The Audio Waveform Amplifier and 1148c2ecf20Sopenharmony_ci * Converter (AWAC) chip in the Power Macintosh performs the same 1158c2ecf20Sopenharmony_ci * 16-bit I/O functionality. The PowerBook 500 series computers 1168c2ecf20Sopenharmony_ci * support 16-bit stereo output, but only mono input." 1178c2ecf20Sopenharmony_ci * 1188c2ecf20Sopenharmony_ci * Technical Information Library (TIL) article number 16405. 1198c2ecf20Sopenharmony_ci * https://support.apple.com/kb/TA32601 1208c2ecf20Sopenharmony_ci * 1218c2ecf20Sopenharmony_ci * --David Kilzer 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci mac_special_bell = mac_av_start_bell; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case MAC_MODEL_Q650: 1268c2ecf20Sopenharmony_ci case MAC_MODEL_Q700: 1278c2ecf20Sopenharmony_ci case MAC_MODEL_Q800: 1288c2ecf20Sopenharmony_ci case MAC_MODEL_Q900: 1298c2ecf20Sopenharmony_ci case MAC_MODEL_Q950: 1308c2ecf20Sopenharmony_ci /* 1318c2ecf20Sopenharmony_ci * Currently not implemented! 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci mac_special_bell = NULL; 1348c2ecf20Sopenharmony_ci break; 1358c2ecf20Sopenharmony_ci default: 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * Every switch needs a default 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci mac_special_bell = NULL; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * init the wave table with a simple triangular wave 1458c2ecf20Sopenharmony_ci * A sine wave would sure be nicer here ... 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci for ( i = 0; i < 0x400; i++ ) 1488c2ecf20Sopenharmony_ci { 1498c2ecf20Sopenharmony_ci mac_asc_wave_tab[ i ] = i / 4; 1508c2ecf20Sopenharmony_ci mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci mac_asc_inited = 1; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* 1568c2ecf20Sopenharmony_ci * Called to make noise; current single entry to the boing driver. 1578c2ecf20Sopenharmony_ci * Does the job for simple ASC, calls other routines else. 1588c2ecf20Sopenharmony_ci * XXX Fixme: 1598c2ecf20Sopenharmony_ci * Should be split into asc_mksound, easc_mksound, av_mksound and 1608c2ecf20Sopenharmony_ci * function pointer set in mac_init_asc which would be called at 1618c2ecf20Sopenharmony_ci * init time. 1628c2ecf20Sopenharmony_ci * _This_ is rather ugly ... 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_civoid mac_mksound( unsigned int freq, unsigned int length ) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci __u32 cfreq = ( freq << 5 ) / 468; 1678c2ecf20Sopenharmony_ci unsigned long flags; 1688c2ecf20Sopenharmony_ci int i; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if ( mac_special_bell == NULL ) 1718c2ecf20Sopenharmony_ci { 1728c2ecf20Sopenharmony_ci /* Do nothing */ 1738c2ecf20Sopenharmony_ci return; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if ( !mac_asc_inited ) 1778c2ecf20Sopenharmony_ci mac_init_asc(); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if ( mac_special_bell ) 1808c2ecf20Sopenharmony_ci { 1818c2ecf20Sopenharmony_ci mac_special_bell( freq, length, 128 ); 1828c2ecf20Sopenharmony_ci return; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if ( freq < 20 || freq > 20000 || length == 0 ) 1868c2ecf20Sopenharmony_ci { 1878c2ecf20Sopenharmony_ci mac_nosound( 0 ); 1888c2ecf20Sopenharmony_ci return; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci local_irq_save(flags); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci del_timer( &mac_sound_timer ); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for ( i = 0; i < 0x800; i++ ) 1968c2ecf20Sopenharmony_ci mac_asc_regs[ i ] = 0; 1978c2ecf20Sopenharmony_ci for ( i = 0; i < 0x800; i++ ) 1988c2ecf20Sopenharmony_ci mac_asc_regs[ i ] = mac_asc_wave_tab[ i ]; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci for ( i = 0; i < 8; i++ ) 2018c2ecf20Sopenharmony_ci *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci mac_asc_regs[ 0x807 ] = 0; 2048c2ecf20Sopenharmony_ci mac_asc_regs[ ASC_VOLUME ] = 128; 2058c2ecf20Sopenharmony_ci mac_asc_regs[ 0x805 ] = 0; 2068c2ecf20Sopenharmony_ci mac_asc_regs[ 0x80F ] = 0; 2078c2ecf20Sopenharmony_ci mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE; 2088c2ecf20Sopenharmony_ci mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci mac_sound_timer.expires = jiffies + length; 2118c2ecf20Sopenharmony_ci add_timer( &mac_sound_timer ); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci local_irq_restore(flags); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * regular ASC: stop whining .. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_cistatic void mac_nosound(struct timer_list *unused) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci mac_asc_regs[ ASC_ENABLE ] = 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* 2258c2ecf20Sopenharmony_ci * EASC entry; init EASC, don't load wavetable, schedule 'start whining'. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci unsigned long flags; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* if the bell is already ringing, ring longer */ 2328c2ecf20Sopenharmony_ci if ( mac_bell_duration > 0 ) 2338c2ecf20Sopenharmony_ci { 2348c2ecf20Sopenharmony_ci mac_bell_duration += length; 2358c2ecf20Sopenharmony_ci return; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci mac_bell_duration = length; 2398c2ecf20Sopenharmony_ci mac_bell_phase = 0; 2408c2ecf20Sopenharmony_ci mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec; 2418c2ecf20Sopenharmony_ci /* this is reasonably big for small frequencies */ 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci local_irq_save(flags); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* set the volume */ 2468c2ecf20Sopenharmony_ci mac_asc_regs[ 0x806 ] = volume; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* set up the ASC registers */ 2498c2ecf20Sopenharmony_ci if ( mac_asc_regs[ 0x801 ] != 1 ) 2508c2ecf20Sopenharmony_ci { 2518c2ecf20Sopenharmony_ci /* select mono mode */ 2528c2ecf20Sopenharmony_ci mac_asc_regs[ 0x807 ] = 0; 2538c2ecf20Sopenharmony_ci /* select sampled sound mode */ 2548c2ecf20Sopenharmony_ci mac_asc_regs[ 0x802 ] = 0; 2558c2ecf20Sopenharmony_ci /* ??? */ 2568c2ecf20Sopenharmony_ci mac_asc_regs[ 0x801 ] = 1; 2578c2ecf20Sopenharmony_ci mac_asc_regs[ 0x803 ] |= 0x80; 2588c2ecf20Sopenharmony_ci mac_asc_regs[ 0x803 ] &= 0x7F; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci mac_sound_timer.function = mac_quadra_ring_bell; 2628c2ecf20Sopenharmony_ci mac_sound_timer.expires = jiffies + 1; 2638c2ecf20Sopenharmony_ci add_timer( &mac_sound_timer ); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci local_irq_restore(flags); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* 2698c2ecf20Sopenharmony_ci * EASC 'start/continue whining'; I'm not sure why the above function didn't 2708c2ecf20Sopenharmony_ci * already load the wave table, or at least call this one... 2718c2ecf20Sopenharmony_ci * This piece keeps reloading the wave table until done. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cistatic void mac_quadra_ring_bell(struct timer_list *unused) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci int i, count = mac_asc_samplespersec / HZ; 2768c2ecf20Sopenharmony_ci unsigned long flags; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* 2798c2ecf20Sopenharmony_ci * we neither want a sound buffer overflow nor underflow, so we need to match 2808c2ecf20Sopenharmony_ci * the number of samples per timer interrupt as exactly as possible. 2818c2ecf20Sopenharmony_ci * using the asc interrupt will give better results in the future 2828c2ecf20Sopenharmony_ci * ...and the possibility to use a real sample (a boingy noise, maybe...) 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci local_irq_save(flags); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci del_timer( &mac_sound_timer ); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if ( mac_bell_duration-- > 0 ) 2908c2ecf20Sopenharmony_ci { 2918c2ecf20Sopenharmony_ci for ( i = 0; i < count; i++ ) 2928c2ecf20Sopenharmony_ci { 2938c2ecf20Sopenharmony_ci mac_bell_phase += mac_bell_phasepersample; 2948c2ecf20Sopenharmony_ci mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ]; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci mac_sound_timer.expires = jiffies + 1; 2978c2ecf20Sopenharmony_ci add_timer( &mac_sound_timer ); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci mac_asc_regs[ 0x801 ] = 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci local_irq_restore(flags); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* 3068c2ecf20Sopenharmony_ci * AV code - please fill in. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_cistatic void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci} 311