File: /usr/src/linux/arch/m68k/amiga/amisound.c

1     /*
2      * linux/arch/m68k/amiga/amisound.c
3      *
4      * amiga sound driver for Linux/m68k
5      *
6      * This file is subject to the terms and conditions of the GNU General Public
7      * License.  See the file COPYING in the main directory of this archive
8      * for more details.
9      */
10     
11     #include <linux/config.h>
12     #include <linux/sched.h>
13     #include <linux/timer.h>
14     #include <linux/init.h>
15     
16     #include <asm/system.h>
17     #include <asm/amigahw.h>
18     
19     static unsigned short *snd_data = NULL;
20     static const signed char sine_data[] = {
21     	0,  39,  75,  103,  121,  127,  121,  103,  75,  39,
22     	0, -39, -75, -103, -121, -127, -121, -103, -75, -39
23     };
24     #define DATA_SIZE	(sizeof(sine_data)/sizeof(sine_data[0]))
25     
26         /*
27          * The minimum period for audio may be modified by the frame buffer
28          * device since it depends on htotal (for OCS/ECS/AGA)
29          */
30     
31     volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */
32     
33     #define MAX_PERIOD	(65535)
34     
35     
36         /*
37          *	Current period (set by dmasound.c)
38          */
39     
40     unsigned short amiga_audio_period = MAX_PERIOD;
41     
42     static unsigned long clock_constant;
43     
44     void __init amiga_init_sound(void)
45     {
46     	static struct resource beep_res = { "Beep" };
47     
48     	snd_data = amiga_chip_alloc_res(sizeof(sine_data), &beep_res);
49     	if (!snd_data) {
50     		printk (KERN_CRIT "amiga init_sound: failed to allocate chipmem\n");
51     		return;
52     	}
53     	memcpy (snd_data, sine_data, sizeof(sine_data));
54     
55     	/* setup divisor */
56     	clock_constant = (amiga_colorclock+DATA_SIZE/2)/DATA_SIZE;
57     
58     	/* without amifb, turn video off and enable high quality sound */
59     #ifndef CONFIG_FB_AMIGA
60     	amifb_video_off();
61     #endif
62     }
63     
64     static void nosound( unsigned long ignored );
65     static struct timer_list sound_timer = { function: nosound };
66     
67     void amiga_mksound( unsigned int hz, unsigned int ticks )
68     {
69     	unsigned long flags;
70     
71     	if (!snd_data)
72     		return;
73     
74     	save_flags(flags);
75     	cli();
76     	del_timer( &sound_timer );
77     
78     	if (hz > 20 && hz < 32767) {
79     		unsigned long period = (clock_constant / hz);
80     
81     		if (period < amiga_audio_min_period)
82     			period = amiga_audio_min_period;
83     		if (period > MAX_PERIOD)
84     			period = MAX_PERIOD;
85     
86     		/* setup pointer to data, period, length and volume */
87     		custom.aud[2].audlc = snd_data;
88     		custom.aud[2].audlen = sizeof(sine_data)/2;
89     		custom.aud[2].audper = (unsigned short)period;
90     		custom.aud[2].audvol = 32; /* 50% of maxvol */
91     	
92     		if (ticks) {
93     			sound_timer.expires = jiffies + ticks;
94     			add_timer( &sound_timer );
95     		}
96     
97     		/* turn on DMA for audio channel 2 */
98     		custom.dmacon = DMAF_SETCLR | DMAF_AUD2;
99     
100     	} else
101     		nosound( 0 );
102     
103     	restore_flags(flags);
104     }
105     
106     
107     static void nosound( unsigned long ignored )
108     {
109     	/* turn off DMA for audio channel 2 */
110     	custom.dmacon = DMAF_AUD2;
111     	/* restore period to previous value after beeping */
112     	custom.aud[2].audper = amiga_audio_period;
113     }
114