summaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac/macboing.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/mac/macboing.c')
-rw-r--r--arch/m68k/mac/macboing.c357
1 files changed, 260 insertions, 97 deletions
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
index 95078a384..1731c929c 100644
--- a/arch/m68k/mac/macboing.c
+++ b/arch/m68k/mac/macboing.c
@@ -1,6 +1,12 @@
/*
* 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>
@@ -9,124 +15,281 @@
#include <asm/macintosh.h>
#include <asm/mac_asc.h>
+static int mac_asc_inited = 0;
+/*
+ * 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
};
-#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0]))
-static void nosound( unsigned long ignored );
-static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound };
+/*
+ * where the ASC hides ...
+ */
+static volatile __u8* mac_asc_regs = ( void* )0x50F14000;
-static volatile unsigned char *asc_base=(void *)0x50F14000;
+/*
+ * sample rate; is this a good default value?
+ */
+static unsigned long mac_asc_samplespersec = 11050;
+static int mac_bell_duration = 0;
+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( unsigned long );
+static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int );
+static void mac_quadra_ring_bell( unsigned long );
+static void mac_av_start_bell( unsigned int, unsigned int, unsigned int );
+static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ) = NULL;
+/*
+ * our timer to start/continue/stop the bell
+ */
+static struct timer_list mac_sound_timer = { NULL, NULL, 0, 0, mac_nosound };
-void mac_mksound( unsigned int hz, unsigned int ticks )
+/*
+ * Sort of initialize the sound chip (called from mac_mksound on the first
+ * beep).
+ */
+static void mac_init_asc( void )
{
- static int inited = 0;
- unsigned long flags;
- int samples=512;
+ int i;
- if (macintosh_config->ident == MAC_MODEL_C660
- || macintosh_config->ident == MAC_MODEL_Q840)
+ /*
+ * 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 )
{
- /*
- * 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."
- *
- * http://til.info.apple.com/techinfo.nsf/artnum/n16405
- *
- * --David Kilzer
- */
+ 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_Q650:
+ case MAC_MODEL_Q700:
+ case MAC_MODEL_Q800:
+ case MAC_MODEL_Q900:
+ case MAC_MODEL_Q950:
+ /*
+ * Currently not implemented!
+ */
+ /*
+ * 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."
+ *
+ * http://til.info.apple.com/techinfo.nsf/artnum/n16405
+ *
+ * --David Kilzer
+ */
+ mac_special_bell = mac_av_start_bell;
+ 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;
+ __u32 flags;
+ int i;
+
+ if ( !mac_asc_inited )
+ mac_init_asc();
+
+ if ( mac_special_bell )
+ {
+ mac_special_bell( freq, length, 128 );
return;
}
-
- if(!inited)
+
+ if ( freq < 20 || freq > 20000 || length == 0 )
{
- int i=0;
- int j=0;
- int k=0;
- int l=0;
-
- /*
- * The IIfx strikes again!
- */
-
- if(macintosh_config->ident==MAC_MODEL_IIFX)
- asc_base=(void *)0x50010000;
-
- for(i=0;i<samples;i++)
- {
- asc_base[i]=sine_data[j];
- asc_base[i+512]=sine_data[j];
- asc_base[i+1024]=sine_data[j];
- asc_base[i+1536]=sine_data[j];
- j++;
- if(j==DATA_SIZE)
- j=0;
- if(i&1)
- k++;
- if(k==DATA_SIZE)
- k=0;
- if((i&3)==3)
- l++;
- if(l==DATA_SIZE)
- l=0;
- }
- inited=1;
+ mac_nosound( 0 );
+ return;
}
- save_flags(flags);
+
+ save_flags( flags );
cli();
- del_timer( &sound_timer );
- if (hz > 20 && hz < 32767) {
- int i;
- u_long asc_pulses=((hz<<5)*samples)/468;
- for(i=0;i<4;i++)
+ 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 );
+
+ restore_flags( flags );
+}
+
+/*
+ * regular ASC: stop whining ..
+ */
+static void mac_nosound( unsigned long ignored )
+{
+ 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 )
+{
+ __u32 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 */
+
+ save_flags( flags );
+ cli();
+
+ /* 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 );
+
+ restore_flags( 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( unsigned long ignored )
+{
+ int i, count = mac_asc_samplespersec / HZ;
+ __u32 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...)
+ */
+
+ save_flags( flags );
+ cli();
+
+ del_timer( &mac_sound_timer );
+
+ if ( mac_bell_duration-- > 0 )
+ {
+ for ( i = 0; i < count; i++ )
{
- asc_base[ASC_FREQ(i,0)]=0x00;
- asc_base[ASC_FREQ(i,1)]=20;
- asc_base[ASC_FREQ(i,2)]=0x00;
- asc_base[ASC_FREQ(i,3)]=20;
- asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF;
- asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF;
- asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF;
- asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF;
+ mac_bell_phase += mac_bell_phasepersample;
+ mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ];
}
- asc_base[ASC_CHAN]=0x03;
- asc_base[ASC_VOLUME]=128;
- asc_base[ASC_MODE]=ASC_MODE_SAMPLE;
- asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE;
- if (ticks) {
- sound_timer.expires = jiffies + ticks;
- add_timer( &sound_timer );
- }
- } else {
- nosound( 0 );
+ mac_sound_timer.expires = jiffies + 1;
+ add_timer( &mac_sound_timer );
}
- restore_flags(flags);
+ else
+ mac_asc_regs[ 0x801 ] = 0;
+
+ restore_flags( flags );
}
-
-static void nosound( unsigned long ignored )
+/*
+ * AV code - please fill in.
+ */
+static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume )
{
- asc_base[ASC_ENABLE]=0;
-}
+}