diff options
Diffstat (limited to 'arch/m68k/mac/macboing.c')
-rw-r--r-- | arch/m68k/mac/macboing.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c new file mode 100644 index 000000000000..44c5cd2ad6a8 --- /dev/null +++ b/arch/m68k/mac/macboing.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * Mac bong noise generator. Note - we ought to put a boingy noise | ||
3 | * here 8) | ||
4 | * | ||
5 | * ---------------------------------------------------------------------- | ||
6 | * 16.11.98: | ||
7 | * rewrote some functions, added support for Enhanced ASC (Quadras) | ||
8 | * after the NetBSD asc.c console bell patch by Colin Wood/Frederick Bruck | ||
9 | * Juergen Mellinger (juergen.mellinger@t-online.de) | ||
10 | */ | ||
11 | |||
12 | #include <linux/sched.h> | ||
13 | #include <linux/timer.h> | ||
14 | |||
15 | #include <asm/macintosh.h> | ||
16 | #include <asm/mac_asc.h> | ||
17 | |||
18 | static int mac_asc_inited; | ||
19 | /* | ||
20 | * dumb triangular wave table | ||
21 | */ | ||
22 | static __u8 mac_asc_wave_tab[ 0x800 ]; | ||
23 | |||
24 | /* | ||
25 | * Alan's original sine table; needs interpolating to 0x800 | ||
26 | * (hint: interpolate or hardwire [0 -> Pi/2[, it's symmetric) | ||
27 | */ | ||
28 | static const signed char sine_data[] = { | ||
29 | 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, | ||
30 | 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * where the ASC hides ... | ||
35 | */ | ||
36 | static volatile __u8* mac_asc_regs = ( void* )0x50F14000; | ||
37 | |||
38 | /* | ||
39 | * sample rate; is this a good default value? | ||
40 | */ | ||
41 | static unsigned long mac_asc_samplespersec = 11050; | ||
42 | static int mac_bell_duration; | ||
43 | static unsigned long mac_bell_phase; /* 0..2*Pi -> 0..0x800 (wavetable size) */ | ||
44 | static unsigned long mac_bell_phasepersample; | ||
45 | |||
46 | /* | ||
47 | * some function protos | ||
48 | */ | ||
49 | static void mac_init_asc( void ); | ||
50 | static void mac_nosound( unsigned long ); | ||
51 | static void mac_quadra_start_bell( unsigned int, unsigned int, unsigned int ); | ||
52 | static void mac_quadra_ring_bell( unsigned long ); | ||
53 | static void mac_av_start_bell( unsigned int, unsigned int, unsigned int ); | ||
54 | static void ( *mac_special_bell )( unsigned int, unsigned int, unsigned int ); | ||
55 | |||
56 | /* | ||
57 | * our timer to start/continue/stop the bell | ||
58 | */ | ||
59 | static struct timer_list mac_sound_timer = | ||
60 | TIMER_INITIALIZER(mac_nosound, 0, 0); | ||
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 | * http://til.info.apple.com/techinfo.nsf/artnum/n16405 | ||
119 | * | ||
120 | * --David Kilzer | ||
121 | */ | ||
122 | mac_special_bell = mac_av_start_bell; | ||
123 | break; | ||
124 | case MAC_MODEL_Q650: | ||
125 | case MAC_MODEL_Q700: | ||
126 | case MAC_MODEL_Q800: | ||
127 | case MAC_MODEL_Q900: | ||
128 | case MAC_MODEL_Q950: | ||
129 | /* | ||
130 | * Currently not implemented! | ||
131 | */ | ||
132 | mac_special_bell = NULL; | ||
133 | break; | ||
134 | default: | ||
135 | /* | ||
136 | * Every switch needs a default | ||
137 | */ | ||
138 | mac_special_bell = NULL; | ||
139 | break; | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * init the wave table with a simple triangular wave | ||
144 | * A sine wave would sure be nicer here ... | ||
145 | */ | ||
146 | for ( i = 0; i < 0x400; i++ ) | ||
147 | { | ||
148 | mac_asc_wave_tab[ i ] = i / 4; | ||
149 | mac_asc_wave_tab[ i + 0x400 ] = 0xFF - i / 4; | ||
150 | } | ||
151 | mac_asc_inited = 1; | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * Called to make noise; current single entry to the boing driver. | ||
156 | * Does the job for simple ASC, calls other routines else. | ||
157 | * XXX Fixme: | ||
158 | * Should be split into asc_mksound, easc_mksound, av_mksound and | ||
159 | * function pointer set in mac_init_asc which would be called at | ||
160 | * init time. | ||
161 | * _This_ is rather ugly ... | ||
162 | */ | ||
163 | void mac_mksound( unsigned int freq, unsigned int length ) | ||
164 | { | ||
165 | __u32 cfreq = ( freq << 5 ) / 468; | ||
166 | __u32 flags; | ||
167 | int i; | ||
168 | |||
169 | if ( mac_special_bell == NULL ) | ||
170 | { | ||
171 | /* Do nothing */ | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | if ( !mac_asc_inited ) | ||
176 | mac_init_asc(); | ||
177 | |||
178 | if ( mac_special_bell ) | ||
179 | { | ||
180 | mac_special_bell( freq, length, 128 ); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | if ( freq < 20 || freq > 20000 || length == 0 ) | ||
185 | { | ||
186 | mac_nosound( 0 ); | ||
187 | return; | ||
188 | } | ||
189 | |||
190 | local_irq_save(flags); | ||
191 | |||
192 | del_timer( &mac_sound_timer ); | ||
193 | |||
194 | for ( i = 0; i < 0x800; i++ ) | ||
195 | mac_asc_regs[ i ] = 0; | ||
196 | for ( i = 0; i < 0x800; i++ ) | ||
197 | mac_asc_regs[ i ] = mac_asc_wave_tab[ i ]; | ||
198 | |||
199 | for ( i = 0; i < 8; i++ ) | ||
200 | *( __u32* )( ( __u32 )mac_asc_regs + ASC_CONTROL + 0x814 + 8 * i ) = cfreq; | ||
201 | |||
202 | mac_asc_regs[ 0x807 ] = 0; | ||
203 | mac_asc_regs[ ASC_VOLUME ] = 128; | ||
204 | mac_asc_regs[ 0x805 ] = 0; | ||
205 | mac_asc_regs[ 0x80F ] = 0; | ||
206 | mac_asc_regs[ ASC_MODE ] = ASC_MODE_SAMPLE; | ||
207 | mac_asc_regs[ ASC_ENABLE ] = ASC_ENABLE_SAMPLE; | ||
208 | |||
209 | mac_sound_timer.expires = jiffies + length; | ||
210 | add_timer( &mac_sound_timer ); | ||
211 | |||
212 | local_irq_restore(flags); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * regular ASC: stop whining .. | ||
217 | */ | ||
218 | static void mac_nosound( unsigned long ignored ) | ||
219 | { | ||
220 | mac_asc_regs[ ASC_ENABLE ] = 0; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * EASC entry; init EASC, don't load wavetable, schedule 'start whining'. | ||
225 | */ | ||
226 | static void mac_quadra_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) | ||
227 | { | ||
228 | __u32 flags; | ||
229 | |||
230 | /* if the bell is already ringing, ring longer */ | ||
231 | if ( mac_bell_duration > 0 ) | ||
232 | { | ||
233 | mac_bell_duration += length; | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | mac_bell_duration = length; | ||
238 | mac_bell_phase = 0; | ||
239 | mac_bell_phasepersample = ( freq * sizeof( mac_asc_wave_tab ) ) / mac_asc_samplespersec; | ||
240 | /* this is reasonably big for small frequencies */ | ||
241 | |||
242 | local_irq_save(flags); | ||
243 | |||
244 | /* set the volume */ | ||
245 | mac_asc_regs[ 0x806 ] = volume; | ||
246 | |||
247 | /* set up the ASC registers */ | ||
248 | if ( mac_asc_regs[ 0x801 ] != 1 ) | ||
249 | { | ||
250 | /* select mono mode */ | ||
251 | mac_asc_regs[ 0x807 ] = 0; | ||
252 | /* select sampled sound mode */ | ||
253 | mac_asc_regs[ 0x802 ] = 0; | ||
254 | /* ??? */ | ||
255 | mac_asc_regs[ 0x801 ] = 1; | ||
256 | mac_asc_regs[ 0x803 ] |= 0x80; | ||
257 | mac_asc_regs[ 0x803 ] &= 0x7F; | ||
258 | } | ||
259 | |||
260 | mac_sound_timer.function = mac_quadra_ring_bell; | ||
261 | mac_sound_timer.expires = jiffies + 1; | ||
262 | add_timer( &mac_sound_timer ); | ||
263 | |||
264 | local_irq_restore(flags); | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * EASC 'start/continue whining'; I'm not sure why the above function didn't | ||
269 | * already load the wave table, or at least call this one... | ||
270 | * This piece keeps reloading the wave table until done. | ||
271 | */ | ||
272 | static void mac_quadra_ring_bell( unsigned long ignored ) | ||
273 | { | ||
274 | int i, count = mac_asc_samplespersec / HZ; | ||
275 | __u32 flags; | ||
276 | |||
277 | /* | ||
278 | * we neither want a sound buffer overflow nor underflow, so we need to match | ||
279 | * the number of samples per timer interrupt as exactly as possible. | ||
280 | * using the asc interrupt will give better results in the future | ||
281 | * ...and the possibility to use a real sample (a boingy noise, maybe...) | ||
282 | */ | ||
283 | |||
284 | local_irq_save(flags); | ||
285 | |||
286 | del_timer( &mac_sound_timer ); | ||
287 | |||
288 | if ( mac_bell_duration-- > 0 ) | ||
289 | { | ||
290 | for ( i = 0; i < count; i++ ) | ||
291 | { | ||
292 | mac_bell_phase += mac_bell_phasepersample; | ||
293 | mac_asc_regs[ 0 ] = mac_asc_wave_tab[ mac_bell_phase & ( sizeof( mac_asc_wave_tab ) - 1 ) ]; | ||
294 | } | ||
295 | mac_sound_timer.expires = jiffies + 1; | ||
296 | add_timer( &mac_sound_timer ); | ||
297 | } | ||
298 | else | ||
299 | mac_asc_regs[ 0x801 ] = 0; | ||
300 | |||
301 | local_irq_restore(flags); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * AV code - please fill in. | ||
306 | */ | ||
307 | static void mac_av_start_bell( unsigned int freq, unsigned int length, unsigned int volume ) | ||
308 | { | ||
309 | } | ||