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