amisound.c 2.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * linux/arch/m68k/amiga/amisound.c
 *
 * amiga sound driver for Linux/m68k
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file COPYING in the main directory of this archive
 * for more details.
 */

#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/string.h>
15
#include <linux/module.h>
L
Linus Torvalds 已提交
16 17 18 19 20 21 22 23

#include <asm/amigahw.h>

static unsigned short *snd_data;
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
};
24
#define DATA_SIZE	ARRAY_SIZE(sine_data)
L
Linus Torvalds 已提交
25

26 27
#define custom amiga_custom

L
Linus Torvalds 已提交
28 29 30 31 32 33
    /*
     * The minimum period for audio may be modified by the frame buffer
     * device since it depends on htotal (for OCS/ECS/AGA)
     */

volatile unsigned short amiga_audio_min_period = 124; /* Default for pre-OCS */
34
EXPORT_SYMBOL(amiga_audio_min_period);
L
Linus Torvalds 已提交
35 36 37 38 39 40 41 42 43

#define MAX_PERIOD	(65535)


    /*
     *	Current period (set by dmasound.c)
     */

unsigned short amiga_audio_period = MAX_PERIOD;
44
EXPORT_SYMBOL(amiga_audio_period);
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53

static unsigned long clock_constant;

void __init amiga_init_sound(void)
{
	static struct resource beep_res = { .name = "Beep" };

	snd_data = amiga_chip_alloc_res(sizeof(sine_data), &beep_res);
	if (!snd_data) {
54
		pr_crit("amiga init_sound: failed to allocate chipmem\n");
L
Linus Torvalds 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68
		return;
	}
	memcpy (snd_data, sine_data, sizeof(sine_data));

	/* setup divisor */
	clock_constant = (amiga_colorclock+DATA_SIZE/2)/DATA_SIZE;

	/* without amifb, turn video off and enable high quality sound */
#ifndef CONFIG_FB_AMIGA
	amifb_video_off();
#endif
}

static void nosound( unsigned long ignored );
69
static DEFINE_TIMER(sound_timer, nosound);
L
Linus Torvalds 已提交
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

void amiga_mksound( unsigned int hz, unsigned int ticks )
{
	unsigned long flags;

	if (!snd_data)
		return;

	local_irq_save(flags);
	del_timer( &sound_timer );

	if (hz > 20 && hz < 32767) {
		unsigned long period = (clock_constant / hz);

		if (period < amiga_audio_min_period)
			period = amiga_audio_min_period;
		if (period > MAX_PERIOD)
			period = MAX_PERIOD;

		/* setup pointer to data, period, length and volume */
		custom.aud[2].audlc = snd_data;
		custom.aud[2].audlen = sizeof(sine_data)/2;
		custom.aud[2].audper = (unsigned short)period;
		custom.aud[2].audvol = 32; /* 50% of maxvol */

		if (ticks) {
			sound_timer.expires = jiffies + ticks;
			add_timer( &sound_timer );
		}

		/* turn on DMA for audio channel 2 */
		custom.dmacon = DMAF_SETCLR | DMAF_AUD2;

	} else
		nosound( 0 );

	local_irq_restore(flags);
}


static void nosound( unsigned long ignored )
{
	/* turn off DMA for audio channel 2 */
	custom.dmacon = DMAF_AUD2;
	/* restore period to previous value after beeping */
	custom.aud[2].audper = amiga_audio_period;
}