summaryrefslogtreecommitdiffstats
path: root/drivers/sound
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
commit46e045034336a2cc90c1798cd7cc07af744ddfd6 (patch)
tree3b9b51fc482e729f663d25333e77fbed9aaa939a /drivers/sound
parent31dc59d503a02e84c4de98826452acaeb56dc15a (diff)
Merge with Linux 2.3.99-pre4.
Diffstat (limited to 'drivers/sound')
-rw-r--r--drivers/sound/Makefile16
-rw-r--r--drivers/sound/ad1816.c3
-rw-r--r--drivers/sound/aedsp16.c1
-rw-r--r--drivers/sound/dev_table.c39
-rw-r--r--drivers/sound/dev_table.h16
-rw-r--r--drivers/sound/dmasound.c5821
-rw-r--r--drivers/sound/dmasound.h36
-rw-r--r--drivers/sound/dmasound/.cvsignore5
-rw-r--r--drivers/sound/dmasound/Config.in27
-rw-r--r--drivers/sound/dmasound/Makefile38
-rw-r--r--drivers/sound/dmasound/dmasound.h246
-rw-r--r--drivers/sound/dmasound/dmasound_atari.c1560
-rw-r--r--drivers/sound/dmasound/dmasound_awacs.c2113
-rw-r--r--drivers/sound/dmasound/dmasound_core.c1313
-rw-r--r--drivers/sound/dmasound/dmasound_paula.c690
-rw-r--r--drivers/sound/dmasound/dmasound_q40.c587
-rw-r--r--drivers/sound/mad16.c2
-rw-r--r--drivers/sound/sb.h15
-rw-r--r--drivers/sound/sb_card.c47
-rw-r--r--drivers/sound/sb_common.c20
-rw-r--r--drivers/sound/sb_ess.c14
-rw-r--r--drivers/sound/sb_mixer.c3
-rw-r--r--drivers/sound/sound_calls.h7
-rw-r--r--drivers/sound/sound_core.c20
-rw-r--r--drivers/sound/soundcard.c163
-rw-r--r--drivers/sound/trix.c2
-rw-r--r--drivers/sound/via82cxxx_audio.c2
27 files changed, 6726 insertions, 6080 deletions
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 046379d37..876daf485 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -35,7 +35,6 @@ obj- :=
# Each configuration option enables a list of files.
obj-$(CONFIG_SOUND) += soundcore.o
-obj-$(CONFIG_DMASOUND) += dmasound.o
obj-$(CONFIG_SOUND_OSS) += sound.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
@@ -81,6 +80,17 @@ obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
+ifeq ($(CONFIG_DMASOUND),y)
+ SUB_DIRS += dmasound
+ MOD_SUB_DIRS += dmasound
+ obj-y += dmasound/dmasound.o
+else
+ ifeq ($(CONFIG_DMASOUND),m)
+ MOD_SUB_DIRS += dmasound
+ endif
+endif
+
+
# Declare multi-part drivers.
list-multi := sound.o gus.o pas2.o sb.o sb_lib.o softoss2.o vidc_mod.o \
@@ -138,10 +148,6 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m)))
MIX_OBJS := $(sort $(filter $(export-objs), $(int-m)))
-ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
- O_OBJS += lowlevel/lowlevel.o
-endif
-
include $(TOPDIR)/Rules.make
diff --git a/drivers/sound/ad1816.c b/drivers/sound/ad1816.c
index e91d71909..bdab8a85b 100644
--- a/drivers/sound/ad1816.c
+++ b/drivers/sound/ad1816.c
@@ -1266,8 +1266,7 @@ static int __initdata dma = -1;
static int __initdata dma2 = -1;
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
-struct pci_dev *ad1816_dev = NULL,
- *mpu_dev = NULL;
+struct pci_dev *ad1816_dev = NULL;
static int activated = 1;
diff --git a/drivers/sound/aedsp16.c b/drivers/sound/aedsp16.c
index 74b961521..6ea812a38 100644
--- a/drivers/sound/aedsp16.c
+++ b/drivers/sound/aedsp16.c
@@ -1383,6 +1383,7 @@ static int __init setup_aedsp16(char *str)
mss_base = ints[4];
mpu_base = ints[5];
mpu_irq = ints[6];
+ return 1;
}
__setup("aedsp16=", setup_aedsp16);
diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c
index 0a1e2981c..4a1a39506 100644
--- a/drivers/sound/dev_table.c
+++ b/drivers/sound/dev_table.c
@@ -26,15 +26,13 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
struct audio_operations *op;
int l, num;
- if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver))
- {
+ if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) {
printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name);
return -(EINVAL);
}
num = sound_alloc_audiodev();
- if (num == -1)
- {
+ if (num == -1) {
printk(KERN_ERR "sound: Too many audio drivers\n");
return -(EBUSY);
}
@@ -47,8 +45,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
if (sound_nblocks < 1024)
sound_nblocks++;
- if (d == NULL || op == NULL)
- {
+ if (d == NULL || op == NULL) {
printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name);
sound_unload_audiodev(num);
return -(ENOMEM);
@@ -91,14 +88,12 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
int n = sound_alloc_mixerdev();
- if (n == -1)
- {
+ if (n == -1) {
printk(KERN_ERR "Sound: Too many mixer drivers\n");
return -EBUSY;
}
if (vers != MIXER_DRIVER_VERSION ||
- driver_size > sizeof(struct mixer_operations))
- {
+ driver_size > sizeof(struct mixer_operations)) {
printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name);
return -EINVAL;
}
@@ -110,8 +105,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
if (sound_nblocks < 1024)
sound_nblocks++;
- if (op == NULL)
- {
+ if (op == NULL) {
printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name);
return -ENOMEM;
}
@@ -131,8 +125,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
void sound_unload_audiodev(int dev)
{
- if (dev != -1)
- {
+ if (dev != -1) {
DMAbuf_deinit(dev);
audio_devs[dev] = NULL;
unregister_sound_dsp((dev<<4)+3);
@@ -165,10 +158,8 @@ int sound_alloc_synthdev(void)
{
int i;
- for (i = 0; i < MAX_SYNTH_DEV; i++)
- {
- if (synth_devs[i] == NULL)
- {
+ for (i = 0; i < MAX_SYNTH_DEV; i++) {
+ if (synth_devs[i] == NULL) {
if (i >= num_synths)
num_synths++;
return i;
@@ -192,10 +183,8 @@ int sound_alloc_timerdev(void)
{
int i;
- for (i = 0; i < MAX_TIMER_DEV; i++)
- {
- if (sound_timer_devs[i] == NULL)
- {
+ for (i = 0; i < MAX_TIMER_DEV; i++) {
+ if (sound_timer_devs[i] == NULL) {
if (i >= num_sound_timers)
num_sound_timers++;
return i;
@@ -206,8 +195,7 @@ int sound_alloc_timerdev(void)
void sound_unload_mixerdev(int dev)
{
- if (dev != -1)
- {
+ if (dev != -1) {
mixer_devs[dev] = NULL;
unregister_sound_mixer(dev<<4);
num_mixers--;
@@ -216,8 +204,7 @@ void sound_unload_mixerdev(int dev)
void sound_unload_mididev(int dev)
{
- if (dev != -1)
- {
+ if (dev != -1) {
midi_devs[dev] = NULL;
unregister_sound_midi((dev<<4)+2);
}
diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h
index a5525a4bf..4c71c1265 100644
--- a/drivers/sound/dev_table.h
+++ b/drivers/sound/dev_table.h
@@ -133,9 +133,6 @@ struct dma_buffparms
char neutral_byte;
int dma; /* DMA channel */
-#ifdef OS_DMA_PARMS
- OS_DMA_PARMS
-#endif
int applic_profile; /* Application profile (APF_*) */
/* Interrupt callback stuff */
void (*audio_callback) (int dev, int parm);
@@ -347,7 +344,6 @@ struct sound_timer_operations
};
#ifdef _DEV_TABLE_C_
-
struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL};
int num_audiodevs = 0;
struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL};
@@ -356,21 +352,13 @@ struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL};
int num_synths = 0;
struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL};
int num_midis = 0;
-#ifndef EXCLUDE_TIMERS
+
extern struct sound_timer_operations default_sound_timer;
struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
&default_sound_timer, NULL
};
int num_sound_timers = 1;
#else
-struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
- NULL
-};
-int num_sound_timers = 0;
-#endif
-
-
-#else
extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
extern int num_audiodevs;
extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
@@ -384,8 +372,6 @@ extern int num_sound_timers;
#endif /* _DEV_TABLE_C_ */
extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
-int sndtable_probe (int unit, struct address_info *hw_config);
-int sndtable_start_card (int unit, struct address_info *hw_config);
void sound_timer_init (struct sound_lowlev_timer *t, char *name);
void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan);
diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c
deleted file mode 100644
index b6298ca83..000000000
--- a/drivers/sound/dmasound.c
+++ /dev/null
@@ -1,5821 +0,0 @@
-
-/* linux/drivers/sound/dmasound.c */
-
-/*
-
-OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for Linux/m68k
-Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
-
-(c) 1995 by Michael Schlueter & Michael Marte
-
-Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
-interface and the u-law to signed byte conversion.
-
-Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
-/dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
-to thank:
-Michael Schlueter for initial ideas and documentation on the MFP and
-the DMA sound hardware.
-Therapy? for their CD 'Troublegum' which really made me rock.
-
-/dev/sndstat is based on code by Hannu Savolainen, the author of the
-VoxWare family of drivers.
-
-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.
-
-History:
-1995/8/25 first release
-
-1995/9/02 ++roman: fixed atari_stram_alloc() call, the timer programming
- and several race conditions
-
-1995/9/14 ++roman: After some discussion with Michael Schlueter, revised
- the interrupt disabling
- Slightly speeded up U8->S8 translation by using long
- operations where possible
- Added 4:3 interpolation for /dev/audio
-
-1995/9/20 ++TeSche: Fixed a bug in sq_write and changed /dev/audio
- converting to play at 12517Hz instead of 6258Hz.
-
-1995/9/23 ++TeSche: Changed sq_interrupt() and sq_play() to pre-program
- the DMA for another frame while there's still one
- running. This allows the IRQ response to be
- arbitrarily delayed and playing will still continue.
-
-1995/10/14 ++Guenther_Kelleter@ac3.maus.de, ++TeSche: better support for
- Falcon audio (the Falcon doesn't raise an IRQ at the
- end of a frame, but at the beginning instead!). uses
- 'if (codec_dma)' in lots of places to simply switch
- between Falcon and TT code.
-
-1995/11/06 ++TeSche: started introducing a hardware abstraction scheme
- (may perhaps also serve for Amigas?), can now play
- samples at almost all frequencies by means of a more
- generalized expand routine, takes a good deal of care
- to cut data only at sample sizes, buffer size is now
- a kernel runtime option, implemented fsync() & several
- minor improvements
- ++Guenther: useful hints and bug fixes, cross-checked it for
- Falcons
-
-1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian.
- Unification to drivers/sound/dmasound.c.
-
-1996/4/6 ++Martin Mitchell: updated to 1.3 kernel.
-
-1996/6/13 ++topi: fixed things that were broken (mainly the amiga
- 14-bit routines), /dev/sndstat shows now the real
- hardware frequency, the lowpass filter is disabled
- by default now.
-
-1996/9/25 ++geert: modularization
-
-1998-06-10 ++andreas: converted to use sound_core
-
-*/
-
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/config.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-#include <asm/setup.h>
-#endif
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_ATARI
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stram.h>
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/dbdma.h>
-#include <asm/feature.h>
-#include "awacs_defs.h"
-#include <linux/nvram.h>
-#include <linux/vt_kern.h>
-#endif /* CONFIG_PPC */
-
-#include "dmasound.h"
-#include <linux/soundcard.h>
-
-#define HAS_8BIT_TABLES
-
-#ifdef MODULE
-static int sq_unit = -1;
-static int mixer_unit = -1;
-static int state_unit = -1;
-static int irq_installed = 0;
-#endif /* MODULE */
-static char **sound_buffers = NULL;
-#ifdef CONFIG_PPC
-static char **sound_read_buffers = NULL;
-#endif
-
-#ifdef CONFIG_ATARI
-extern void atari_microwire_cmd(int cmd);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
- /*
- * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern volatile u_short amiga_audio_min_period;
-
-
- /*
- * amiga_mksound() should be able to restore the period after beeping
- * (Imported from arch/m68k/amiga/amisound.c)
- */
-
-extern u_short amiga_audio_period;
-
-
- /*
- * Audio DMA masks
- */
-
-#define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
-#define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
-#define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
-
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-/*
- * Interrupt numbers and addresses, obtained from the device tree.
- */
-static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
-static volatile struct awacs_regs *awacs;
-static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
-static int awacs_rate_index;
-static int awacs_subframe;
-static int awacs_spkr_vol;
-static struct device_node* awacs_node;
-
-static int awacs_revision;
-#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
-
-/*
- * Space for the DBDMA command blocks.
- */
-static void *awacs_tx_cmd_space;
-static volatile struct dbdma_cmd *awacs_tx_cmds;
-
-static void *awacs_rx_cmd_space;
-static volatile struct dbdma_cmd *awacs_rx_cmds;
-
-/*
- * Cached values of AWACS registers (we can't read them).
- * Except on the burgundy. XXX
- */
-int awacs_reg[5];
-
-#define HAS_16BIT_TABLES
-#undef HAS_8BIT_TABLES
-
-/*
- * Stuff for outputting a beep. The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
- 0, 40, 79, 117, 153, 187, 218, 245,
- 269, 288, 304, 316, 323, 327, 327, 324,
- 318, 310, 299, 288, 275, 262, 249, 236,
- 224, 213, 204, 196, 190, 186, 183, 182,
- 182, 183, 186, 189, 192, 196, 200, 203,
- 206, 208, 209, 209, 209, 207, 204, 201,
- 197, 193, 188, 183, 179, 174, 170, 166,
- 163, 161, 160, 159, 159, 160, 161, 162,
- 164, 166, 168, 169, 171, 171, 171, 170,
- 169, 167, 163, 159, 155, 150, 144, 139,
- 133, 128, 122, 117, 113, 110, 107, 105,
- 103, 103, 103, 103, 104, 104, 105, 105,
- 105, 103, 101, 97, 92, 86, 78, 68,
- 58, 45, 32, 18, 3, -11, -26, -41,
- -55, -68, -79, -88, -95, -100, -102, -102,
- -99, -93, -85, -75, -62, -48, -33, -16,
- 0, 16, 33, 48, 62, 75, 85, 93,
- 99, 102, 102, 100, 95, 88, 79, 68,
- 55, 41, 26, 11, -3, -18, -32, -45,
- -58, -68, -78, -86, -92, -97, -101, -103,
- -105, -105, -105, -104, -104, -103, -103, -103,
- -103, -105, -107, -110, -113, -117, -122, -128,
- -133, -139, -144, -150, -155, -159, -163, -167,
- -169, -170, -171, -171, -171, -169, -168, -166,
- -164, -162, -161, -160, -159, -159, -160, -161,
- -163, -166, -170, -174, -179, -183, -188, -193,
- -197, -201, -204, -207, -209, -209, -209, -208,
- -206, -203, -200, -196, -192, -189, -186, -183,
- -182, -182, -183, -186, -190, -196, -204, -213,
- -224, -236, -249, -262, -275, -288, -299, -310,
- -318, -324, -327, -327, -323, -316, -304, -288,
- -269, -245, -218, -187, -153, -117, -79, -40,
-};
-
-#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
-#define BEEP_BUFLEN 512
-#define BEEP_VOLUME 15 /* 0 - 100 */
-
-static int beep_volume = BEEP_VOLUME;
-static int beep_playing = 0;
-static int awacs_beep_state = 0;
-static short *beep_buf;
-static volatile struct dbdma_cmd *beep_dbdma_cmd;
-static void (*orig_mksound)(unsigned int, unsigned int);
-static int is_pbook_3400;
-static unsigned char *latch_base;
-static int is_pbook_G3;
-static unsigned char *macio_base;
-
-/* Burgundy functions */
-static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
-static unsigned awacs_burgundy_rcw(unsigned addr);
-static void awacs_burgundy_write_volume(unsigned address, int volume);
-static int awacs_burgundy_read_volume(unsigned address);
-static void awacs_burgundy_write_mvolume(unsigned address, int volume);
-static int awacs_burgundy_read_mvolume(unsigned address);
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Stuff for restoring after a sleep.
- */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
-struct pmu_sleep_notifier awacs_sleep_notifier = {
- awacs_sleep_notify, SLEEP_LEVEL_SOUND,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-#endif /* CONFIG_PPC */
-
-/*** Some declarations *******************************************************/
-
-
-#define DMASND_TT 1
-#define DMASND_FALCON 2
-#define DMASND_AMIGA 3
-#define DMASND_AWACS 4
-
-#define MAX_CATCH_RADIUS 10
-#define MIN_BUFFERS 4
-#define MIN_BUFSIZE 4
-#define MAX_BUFSIZE 128 /* Limit for Amiga */
-
-static int catchRadius = 0;
-static int numBufs = 4, bufSize = 32;
-#ifdef CONFIG_PPC
-static int numReadBufs = 4, readbufSize = 32;
-#endif
-
-MODULE_PARM(catchRadius, "i");
-MODULE_PARM(numBufs, "i");
-MODULE_PARM(bufSize, "i");
-MODULE_PARM(numReadBufs, "i");
-MODULE_PARM(readbufSize, "i");
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-#define min(x, y) ((x) < (y) ? (x) : (y))
-#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
- } while (0)
-#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
-
-
-/*** Some low level helpers **************************************************/
-
-#ifdef HAS_8BIT_TABLES
-/* 8 bit mu-law */
-
-static char ulaw2dma8[] = {
- -126, -122, -118, -114, -110, -106, -102, -98,
- -94, -90, -86, -82, -78, -74, -70, -66,
- -63, -61, -59, -57, -55, -53, -51, -49,
- -47, -45, -43, -41, -39, -37, -35, -33,
- -31, -30, -29, -28, -27, -26, -25, -24,
- -23, -22, -21, -20, -19, -18, -17, -16,
- -16, -15, -15, -14, -14, -13, -13, -12,
- -12, -11, -11, -10, -10, -9, -9, -8,
- -8, -8, -7, -7, -7, -7, -6, -6,
- -6, -6, -5, -5, -5, -5, -4, -4,
- -4, -4, -4, -4, -3, -3, -3, -3,
- -3, -3, -3, -3, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, 0,
- 125, 121, 117, 113, 109, 105, 101, 97,
- 93, 89, 85, 81, 77, 73, 69, 65,
- 62, 60, 58, 56, 54, 52, 50, 48,
- 46, 44, 42, 40, 38, 36, 34, 32,
- 30, 29, 28, 27, 26, 25, 24, 23,
- 22, 21, 20, 19, 18, 17, 16, 15,
- 15, 14, 14, 13, 13, 12, 12, 11,
- 11, 10, 10, 9, 9, 8, 8, 7,
- 7, 7, 6, 6, 6, 6, 5, 5,
- 5, 5, 4, 4, 4, 4, 3, 3,
- 3, 3, 3, 3, 2, 2, 2, 2,
- 2, 2, 2, 2, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* 8 bit A-law */
-
-static char alaw2dma8[] = {
- -22, -21, -24, -23, -18, -17, -20, -19,
- -30, -29, -32, -31, -26, -25, -28, -27,
- -11, -11, -12, -12, -9, -9, -10, -10,
- -15, -15, -16, -16, -13, -13, -14, -14,
- -86, -82, -94, -90, -70, -66, -78, -74,
- -118, -114, -126, -122, -102, -98, -110, -106,
- -43, -41, -47, -45, -35, -33, -39, -37,
- -59, -57, -63, -61, -51, -49, -55, -53,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -2, -2, -2, -2, -2, -2, -2, -2,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -6, -6, -6, -6, -5, -5, -5, -5,
- -8, -8, -8, -8, -7, -7, -7, -7,
- -3, -3, -3, -3, -3, -3, -3, -3,
- -4, -4, -4, -4, -4, -4, -4, -4,
- 21, 20, 23, 22, 17, 16, 19, 18,
- 29, 28, 31, 30, 25, 24, 27, 26,
- 10, 10, 11, 11, 8, 8, 9, 9,
- 14, 14, 15, 15, 12, 12, 13, 13,
- 86, 82, 94, 90, 70, 66, 78, 74,
- 118, 114, 126, 122, 102, 98, 110, 106,
- 43, 41, 47, 45, 35, 33, 39, 37,
- 59, 57, 63, 61, 51, 49, 55, 53,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 5, 5, 5, 5, 4, 4, 4, 4,
- 7, 7, 7, 7, 6, 6, 6, 6,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3
-};
-#endif /* HAS_8BIT_TABLES */
-
-#ifdef HAS_16BIT_TABLES
-
-/* 16 bit mu-law */
-
-static short ulaw2dma16[] = {
- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
- -876, -844, -812, -780, -748, -716, -684, -652,
- -620, -588, -556, -524, -492, -460, -428, -396,
- -372, -356, -340, -324, -308, -292, -276, -260,
- -244, -228, -212, -196, -180, -164, -148, -132,
- -120, -112, -104, -96, -88, -80, -72, -64,
- -56, -48, -40, -32, -24, -16, -8, 0,
- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
- 876, 844, 812, 780, 748, 716, 684, 652,
- 620, 588, 556, 524, 492, 460, 428, 396,
- 372, 356, 340, 324, 308, 292, 276, 260,
- 244, 228, 212, 196, 180, 164, 148, 132,
- 120, 112, 104, 96, 88, 80, 72, 64,
- 56, 48, 40, 32, 24, 16, 8, 0,
-};
-
-/* 16 bit A-law */
-
-static short alaw2dma16[] = {
- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
- -344, -328, -376, -360, -280, -264, -312, -296,
- -472, -456, -504, -488, -408, -392, -440, -424,
- -88, -72, -120, -104, -24, -8, -56, -40,
- -216, -200, -248, -232, -152, -136, -184, -168,
- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
- -688, -656, -752, -720, -560, -528, -624, -592,
- -944, -912, -1008, -976, -816, -784, -880, -848,
- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
- 344, 328, 376, 360, 280, 264, 312, 296,
- 472, 456, 504, 488, 408, 392, 440, 424,
- 88, 72, 120, 104, 24, 8, 56, 40,
- 216, 200, 248, 232, 152, 136, 184, 168,
- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
- 688, 656, 752, 720, 560, 528, 624, 592,
- 944, 912, 1008, 976, 816, 784, 880, 848,
-};
-#endif /* HAS_16BIT_TABLES */
-
-
-#ifdef HAS_14BIT_TABLES
-
-/* 14 bit mu-law (LSB) */
-
-static char alaw2dma14l[] = {
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 33, 33,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 49, 17, 49, 17, 49, 17, 49, 17,
- 49, 17, 49, 17, 49, 17, 49, 17,
- 41, 57, 9, 25, 41, 57, 9, 25,
- 41, 57, 9, 25, 41, 57, 9, 25,
- 37, 45, 53, 61, 5, 13, 21, 29,
- 37, 45, 53, 61, 5, 13, 21, 29,
- 35, 39, 43, 47, 51, 55, 59, 63,
- 3, 7, 11, 15, 19, 23, 27, 31,
- 34, 36, 38, 40, 42, 44, 46, 48,
- 50, 52, 54, 56, 58, 60, 62, 0,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 15, 47, 15, 47, 15, 47, 15, 47,
- 15, 47, 15, 47, 15, 47, 15, 47,
- 23, 7, 55, 39, 23, 7, 55, 39,
- 23, 7, 55, 39, 23, 7, 55, 39,
- 27, 19, 11, 3, 59, 51, 43, 35,
- 27, 19, 11, 3, 59, 51, 43, 35,
- 29, 25, 21, 17, 13, 9, 5, 1,
- 61, 57, 53, 49, 45, 41, 37, 33,
- 30, 28, 26, 24, 22, 20, 18, 16,
- 14, 12, 10, 8, 6, 4, 2, 0
-};
-
-/* 14 bit A-law (LSB) */
-
-static char alaw2dma14l[] = {
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 16, 48, 16, 48, 16, 48, 16, 48,
- 16, 48, 16, 48, 16, 48, 16, 48,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 42, 46, 34, 38, 58, 62, 50, 54,
- 10, 14, 2, 6, 26, 30, 18, 22,
- 42, 46, 34, 38, 58, 62, 50, 54,
- 10, 14, 2, 6, 26, 30, 18, 22,
- 40, 56, 8, 24, 40, 56, 8, 24,
- 40, 56, 8, 24, 40, 56, 8, 24,
- 20, 28, 4, 12, 52, 60, 36, 44,
- 20, 28, 4, 12, 52, 60, 36, 44,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 48, 16, 48, 16, 48, 16, 48, 16,
- 48, 16, 48, 16, 48, 16, 48, 16,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 22, 18, 30, 26, 6, 2, 14, 10,
- 54, 50, 62, 58, 38, 34, 46, 42,
- 22, 18, 30, 26, 6, 2, 14, 10,
- 54, 50, 62, 58, 38, 34, 46, 42,
- 24, 8, 56, 40, 24, 8, 56, 40,
- 24, 8, 56, 40, 24, 8, 56, 40,
- 44, 36, 60, 52, 12, 4, 28, 20,
- 44, 36, 60, 52, 12, 4, 28, 20
-};
-#endif /* HAS_14BIT_TABLES */
-
-
-/*** Translations ************************************************************/
-
-
-#ifdef CONFIG_ATARI
-static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif /* CONFIG_PPC */
-
-/*** Machine definitions *****************************************************/
-
-
-typedef struct {
- int type;
- void *(*dma_alloc)(unsigned int, int);
- void (*dma_free)(void *, unsigned int);
- int (*irqinit)(void);
-#ifdef MODULE
- void (*irqcleanup)(void);
-#endif /* MODULE */
- void (*init)(void);
- void (*silence)(void);
- int (*setFormat)(int);
- int (*setVolume)(int);
- int (*setBass)(int);
- int (*setTreble)(int);
- int (*setGain)(int);
- void (*play)(void);
-} MACHINE;
-
-
-/*** Low level stuff *********************************************************/
-
-
-typedef struct {
- int format; /* AFMT_* */
- int stereo; /* 0 = mono, 1 = stereo */
- int size; /* 8/16 bit*/
- int speed; /* speed */
-} SETTINGS;
-
-typedef struct {
- ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-} TRANS;
-
-struct sound_settings {
- MACHINE mach; /* machine dependent things */
- SETTINGS hard; /* hardware settings */
- SETTINGS soft; /* software settings */
- SETTINGS dsp; /* /dev/dsp default settings */
- TRANS *trans; /* supported translations */
-#if defined(CONFIG_PPC)
- TRANS *read_trans; /* supported translations */
-#endif
- int volume_left; /* volume (range is machine dependent) */
- int volume_right;
- int bass; /* tone (range is machine dependent) */
- int treble;
- int gain;
- int minDev; /* minor device number currently open */
-#if defined(CONFIG_ATARI) || defined(CONFIG_PPC)
- int bal; /* balance factor for expanding (not volume!) */
- u_long data; /* data for expanding */
-#endif /* CONFIG_ATARI */
-};
-
-static struct sound_settings sound;
-
-
-#ifdef CONFIG_ATARI
-static void *AtaAlloc(unsigned int size, int flags);
-static void AtaFree(void *, unsigned int size);
-static int AtaIrqInit(void);
-#ifdef MODULE
-static void AtaIrqCleanUp(void);
-#endif /* MODULE */
-static int AtaSetBass(int bass);
-static int AtaSetTreble(int treble);
-static void TTSilence(void);
-static void TTInit(void);
-static int TTSetFormat(int format);
-static int TTSetVolume(int volume);
-static int TTSetGain(int gain);
-static void FalconSilence(void);
-static void FalconInit(void);
-static int FalconSetFormat(int format);
-static int FalconSetVolume(int volume);
-static void ata_sq_play_next_frame(int index);
-static void AtaPlay(void);
-static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static void *AmiAlloc(unsigned int size, int flags);
-static void AmiFree(void *, unsigned int);
-static int AmiIrqInit(void);
-#ifdef MODULE
-static void AmiIrqCleanUp(void);
-#endif /* MODULE */
-static void AmiSilence(void);
-static void AmiInit(void);
-static int AmiSetFormat(int format);
-static int AmiSetVolume(int volume);
-static int AmiSetTreble(int treble);
-static void ami_sq_play_next_frame(int index);
-static void AmiPlay(void);
-static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp);
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static void *PMacAlloc(unsigned int size, int flags);
-static void PMacFree(void *ptr, unsigned int size);
-static int PMacIrqInit(void);
-#ifdef MODULE
-static void PMacIrqCleanup(void);
-#endif /* MODULE */
-static void PMacSilence(void);
-static void PMacInit(void);
-static void PMacPlay(void);
-static void PMacRecord(void);
-static int PMacSetFormat(int format);
-static int PMacSetVolume(int volume);
-static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
-static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
-static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
-static void awacs_write(int val);
-static int awacs_get_volume(int reg, int lshift);
-static int awacs_volume_setter(int volume, int n, int mute, int lshift);
-static void awacs_mksound(unsigned int hz, unsigned int ticks);
-static void awacs_nosound(unsigned long xx);
-#endif /* CONFIG_PPC */
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-#ifdef CONFIG_ATARI
-static int sound_set_bass(int bass);
-#endif /* CONFIG_ATARI */
-#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
-static int sound_set_treble(int treble);
-#endif /* CONFIG_ATARI || CONFIG_AMIGA */
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#ifdef CONFIG_PPC
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-#endif
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
- int busy;
- int modify_counter;
-};
-
-static struct sound_mixer mixer;
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-struct sound_queue {
- int max_count, block_size;
- char **buffers;
- int max_active;
-
- /* it shouldn't be necessary to declare any of these volatile */
- int front, rear, count;
- int rear_size;
- /*
- * The use of the playing field depends on the hardware
- *
- * Atari, PMac: The number of frames that are loaded/playing
- *
- * Amiga: Bit 0 is set: a frame is loaded
- * Bit 1 is set: a frame is playing
- */
- int active;
- wait_queue_head_t action_queue, open_queue, sync_queue;
- int open_mode;
- int busy, syncing;
-#ifdef CONFIG_ATARI
- int ignore_int; /* ++TeSche: used for Falcon */
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- int block_size_half, block_size_quarter;
-#endif /* CONFIG_AMIGA */
-};
-
-static struct sound_queue sq;
-#ifdef CONFIG_PPC
-static struct sound_queue read_sq;
-#endif
-
-#define sq_block_address(i) (sq.buffers[i])
-#define SIGNAL_RECEIVED (signal_pending(current))
-#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK)
-#define ONE_SECOND HZ /* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT 0xffffffff
-#define SLEEP(queue, time_limit) \
- interruptible_sleep_on_timeout(&queue, (time_limit));
-#define WAKE_UP(queue) (wake_up_interruptible(&queue))
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
- int busy;
- char buf[512];
- int len, ptr;
-};
-
-static struct sound_state state;
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig);
-static inline int ioctl_return(int *addr, int value)
-{
- if (value < 0)
- return(value);
-
- return put_user(value, addr);
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-void dmasound_init(void);
-static int dmasound_setup(char *str);
-
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-#ifdef CONFIG_ATARI
-static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- ssize_t count, used;
- u_char *p = &frame[*frameUsed];
-
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = table[data];
- count--;
- }
- *frameUsed += used;
- return used;
-}
-
-
-static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- void *p = &frame[*frameUsed];
-
- count = min(userCount, frameLeft);
- if (sound.soft.stereo)
- count &= ~1;
- used = count;
- if (copy_from_user(p, userPtr, count))
- return -EFAULT;
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft);
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = data ^ 0x80;
- count--;
- }
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *p++ = data ^ 0x8080;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- void *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft) & ~3;
- used = count;
- if (copy_from_user(p, userPtr, count))
- return -EFAULT;
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count*4;
- while (count > 0) {
- u_long data;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- *p++ = data ^ 0x80008000;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- count = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *p++ = data;
- *p++ = data;
- count--;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count*4;
- while (count > 0) {
- u_long data;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data);
- *p++ = data;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
-
- count = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>1;
- used = count*2;
- while (count > 0) {
- u_short data;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *p++ = data;
- *p++ = data;
- }
- *frameUsed += used*2;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- count = min(userCount, frameLeft)>>2;
- used = count;
- while (count > 0) {
- u_long data;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data) ^ 0x80008000;
- *p++ = data;
- count--;
- }
- *frameUsed += used;
- }
- return(used);
-}
-
-
-static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- u_char data = sound.data;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (!userCount)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c];
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 2) {
- u_char c;
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c] << 8;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data |= table[c];
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- u_char data = sound.data;
- while (frameLeft) {
- if (bal < 0) {
- if (!userCount)
- break;
- if (get_user(data, userPtr++))
- return -EFAULT;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 2) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- u_char data = sound.data;
- while (frameLeft) {
- if (bal < 0) {
- if (!userCount)
- break;
- if (get_user(data, userPtr++))
- return -EFAULT;
- data ^= 0x80;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 2) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8080;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 2;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data ^= 0x80008000;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data);
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-
-
-static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- /* this should help gcc to stuff everything into registers */
- long bal = sound.bal;
- long hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- ssize_t used, usedf;
-
- used = userCount;
- usedf = frameLeft;
- if (!sound.soft.stereo) {
- u_short *p = (u_short *)&frame[*frameUsed];
- u_short data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 2)
- break;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- userCount -= 2;
- bal += hSpeed;
- }
- *p++ = data;
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- } else {
- u_long *p = (u_long *)&frame[*frameUsed];
- u_long data = sound.data;
- while (frameLeft >= 4) {
- if (bal < 0) {
- if (userCount < 4)
- break;
- if (get_user(data, ((u_int *)userPtr)++))
- return -EFAULT;
- data = le2be16dbl(data) ^ 0x80008000;
- userCount -= 4;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft -= 4;
- bal -= sSpeed;
- }
- sound.data = data;
- }
- sound.bal = bal;
- used -= userCount;
- *frameUsed += usedf-frameLeft;
- return(used);
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-static ssize_t ami_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- char *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma8 : alaw2dma8;
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- u_char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = table[data];
- count--;
- }
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *left++ = table[data];
- if (get_user(data, userPtr++))
- return -EFAULT;
- *right++ = table[data];
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- void *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- if (copy_from_user(p, userPtr, count))
- return -EFAULT;
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(*left++, userPtr++)
- || get_user(*right++, userPtr++))
- return -EFAULT;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
-{
- ssize_t count, used;
-
- if (!sound.soft.stereo) {
- char *p = &frame[*frameUsed];
- count = min(userCount, frameLeft) & ~1;
- used = count;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *p++ = data ^ 0x80;
- count--;
- }
- } else {
- u_char *left = &frame[*frameUsed>>1];
- u_char *right = left+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *left++ = data ^ 0x80;
- if (get_user(data, userPtr++))
- return -EFAULT;
- *right++ = data ^ 0x80;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_s16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_u16be(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data ^= 0x8000;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_s16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data);
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-
-
-static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- u_short data;
-
- if (!sound.soft.stereo) {
- u_char *high = &frame[*frameUsed>>1];
- u_char *low = high+sq.block_size_half;
- count = min(userCount, frameLeft)>>1 & ~1;
- used = count*2;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *high++ = data>>8;
- *low++ = (data>>2) & 0x3f;
- count--;
- }
- } else {
- u_char *lefth = &frame[*frameUsed>>2];
- u_char *leftl = lefth+sq.block_size_quarter;
- u_char *righth = lefth+sq.block_size_half;
- u_char *rightl = righth+sq.block_size_quarter;
- count = min(userCount, frameLeft)>>2 & ~1;
- used = count*4;
- while (count > 0) {
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *lefth++ = data>>8;
- *leftl++ = (data>>2) & 0x3f;
- if (get_user(data, ((u_short *)userPtr)++))
- return -EFAULT;
- data = le2be16(data) ^ 0x8000;
- *righth++ = data>>8;
- *rightl++ = (data>>2) & 0x3f;
- count--;
- }
- }
- *frameUsed += used;
- return(used);
-}
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- if (get_user(data, up++))
- return -EFAULT;
- *fp++ = data;
- *fp++ = data;
- count--;
- }
- } else {
- if (copy_from_user(fp, userPtr, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- *fp++ = data;
- if (stereo) {
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- }
- *fp++ = data;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned short *table = (unsigned short *)
- (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
- unsigned int data = sound.data;
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int utotal, ftotal;
- int stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c];
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + table[c];
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = c << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + (c << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (c ^ 0x80) << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + ((c ^ 0x80) << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + c;
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = sound.data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = sound.bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + (c ^ mask);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- sound.bal = bal;
- sound.data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- data = *fp;
- if (put_user(data, up++))
- return -EFAULT;
- fp+=2;
- count--;
- }
- } else {
- if (copy_to_user((u_char *)userPtr, fp, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
-
- data = *fp++;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- if (stereo) {
- data = *fp;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- }
- fp++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-
-#endif /* CONFIG_PPC */
-
-
-#ifdef CONFIG_ATARI
-static TRANS transTTNormal = {
- ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8, NULL, NULL, NULL, NULL
-};
-
-static TRANS transTTExpanding = {
- ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8, NULL, NULL, NULL, NULL
-};
-
-static TRANS transFalconNormal = {
- ata_ct_law, ata_ct_law, ata_ct_s8, ata_ct_u8,
- ata_ct_s16be, ata_ct_u16be, ata_ct_s16le, ata_ct_u16le
-};
-
-static TRANS transFalconExpanding = {
- ata_ctx_law, ata_ctx_law, ata_ctx_s8, ata_ctx_u8,
- ata_ctx_s16be, ata_ctx_u16be, ata_ctx_s16le, ata_ctx_u16le
-};
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static TRANS transAmiga = {
- ami_ct_law, ami_ct_law, ami_ct_s8, ami_ct_u8,
- ami_ct_s16be, ami_ct_u16be, ami_ct_s16le, ami_ct_u16le
-};
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static TRANS transAwacsNormal = {
- pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8,
- pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16
-};
-
-static TRANS transAwacsExpand = {
- pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
- pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
-};
-
-static TRANS transAwacsNormalRead = {
- NULL, NULL, pmac_ct_s8_read, pmac_ct_u8_read,
- pmac_ct_s16_read, pmac_ct_u16_read, pmac_ct_s16_read, pmac_ct_u16_read
-};
-#endif /* CONFIG_PPC */
-
-/*** Low level stuff *********************************************************/
-
-
-#ifdef CONFIG_ATARI
-
-/*
- * Atari (TT/Falcon)
- */
-
-static void *AtaAlloc(unsigned int size, int flags)
-{
- return( atari_stram_alloc( size, NULL, "dmasound" ));
-}
-
-static void AtaFree(void *obj, unsigned int size)
-{
- atari_stram_free( obj );
-}
-
-static int __init AtaIrqInit(void)
-{
- /* Set up timer A. Timer A
- will receive a signal upon end of playing from the sound
- hardware. Furthermore Timer A is able to count events
- and will cause an interrupt after a programmed number
- of events. So all we need to keep the music playing is
- to provide the sound hardware with new data upon
- an interrupt from timer A. */
- mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
- mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
- mfp.tim_ct_a = 8; /* Turn on event counting. */
- /* Register interrupt handler. */
- request_irq(IRQ_MFP_TIMA, ata_sq_interrupt, IRQ_TYPE_SLOW,
- "DMA sound", ata_sq_interrupt);
- mfp.int_en_a |= 0x20; /* Turn interrupt on. */
- mfp.int_mk_a |= 0x20;
- return(1);
-}
-
-#ifdef MODULE
-static void AtaIrqCleanUp(void)
-{
- mfp.tim_ct_a = 0; /* stop timer */
- mfp.int_en_a &= ~0x20; /* turn interrupt off */
- free_irq(IRQ_MFP_TIMA, ata_sq_interrupt);
-}
-#endif /* MODULE */
-
-
-#define TONE_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
-#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
-
-
-static int AtaSetBass(int bass)
-{
- sound.bass = TONE_VOXWARE_TO_DB(bass);
- atari_microwire_cmd(MW_LM1992_BASS(sound.bass));
- return(TONE_DB_TO_VOXWARE(sound.bass));
-}
-
-
-static int AtaSetTreble(int treble)
-{
- sound.treble = TONE_VOXWARE_TO_DB(treble);
- atari_microwire_cmd(MW_LM1992_TREBLE(sound.treble));
- return(TONE_DB_TO_VOXWARE(sound.treble));
-}
-
-
-
-/*
- * TT
- */
-
-
-static void TTSilence(void)
-{
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
-}
-
-
-static void TTInit(void)
-{
- int mode, i, idx;
- const int freq[4] = {50066, 25033, 12517, 6258};
-
- /* search a frequency that fits into the allowed error range */
-
- idx = -1;
- for (i = 0; i < arraysize(freq); i++)
- /* this isn't as much useful for a TT than for a Falcon, but
- * then it doesn't hurt very much to implement it for a TT too.
- */
- if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
- idx = i;
- if (idx > -1) {
- sound.soft.speed = freq[idx];
- sound.trans = &transTTNormal;
- } else
- sound.trans = &transTTExpanding;
-
- TTSilence();
- sound.hard = sound.soft;
-
- if (sound.hard.speed > 50066) {
- /* we would need to squeeze the sound, but we won't do that */
- sound.hard.speed = 50066;
- mode = DMASND_MODE_50KHZ;
- sound.trans = &transTTNormal;
- } else if (sound.hard.speed > 25033) {
- sound.hard.speed = 50066;
- mode = DMASND_MODE_50KHZ;
- } else if (sound.hard.speed > 12517) {
- sound.hard.speed = 25033;
- mode = DMASND_MODE_25KHZ;
- } else if (sound.hard.speed > 6258) {
- sound.hard.speed = 12517;
- mode = DMASND_MODE_12KHZ;
- } else {
- sound.hard.speed = 6258;
- mode = DMASND_MODE_6KHZ;
- }
-
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- DMASND_MODE_8BIT | mode;
-
- sound.bal = -sound.soft.speed;
-}
-
-
-static int TTSetFormat(int format)
-{
- /* TT sound DMA supports only 8bit modes */
-
- switch (format) {
- case AFMT_QUERY:
- return(sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_S8:
- case AFMT_U8:
- break;
- default:
- format = AFMT_S8;
- }
-
- sound.soft.format = format;
- sound.soft.size = 8;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = 8;
- }
- TTInit();
-
- return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
-#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
-
-
-static int TTSetVolume(int volume)
-{
- sound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
- atari_microwire_cmd(MW_LM1992_BALLEFT(sound.volume_left));
- sound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
- atari_microwire_cmd(MW_LM1992_BALRIGHT(sound.volume_right));
- return(VOLUME_DB_TO_VOXWARE(sound.volume_left) |
- (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
-}
-
-
-#define GAIN_VOXWARE_TO_DB(v) \
- (((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
-#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)
-
-static int TTSetGain(int gain)
-{
- sound.gain = GAIN_VOXWARE_TO_DB(gain);
- atari_microwire_cmd(MW_LM1992_VOLUME(sound.gain));
- return GAIN_DB_TO_VOXWARE(sound.gain);
-}
-
-
-
-/*
- * Falcon
- */
-
-
-static void FalconSilence(void)
-{
- /* stop playback, set sample rate 50kHz for PSG sound */
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
- tt_dmasnd.int_div = 0; /* STE compatible divider */
- tt_dmasnd.int_ctrl = 0x0;
- tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
- tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
- tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
- tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
-}
-
-
-static void FalconInit(void)
-{
- int divider, i, idx;
- const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
-
- /* search a frequency that fits into the allowed error range */
-
- idx = -1;
- for (i = 0; i < arraysize(freq); i++)
- /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
- * be playable without expanding, but that now a kernel runtime
- * option
- */
- if ((100 * abs(sound.soft.speed - freq[i]) / freq[i]) < catchRadius)
- idx = i;
- if (idx > -1) {
- sound.soft.speed = freq[idx];
- sound.trans = &transFalconNormal;
- } else
- sound.trans = &transFalconExpanding;
-
- FalconSilence();
- sound.hard = sound.soft;
-
- if (sound.hard.size == 16) {
- /* the Falcon can play 16bit samples only in stereo */
- sound.hard.stereo = 1;
- }
-
- if (sound.hard.speed > 49170) {
- /* we would need to squeeze the sound, but we won't do that */
- sound.hard.speed = 49170;
- divider = 1;
- sound.trans = &transFalconNormal;
- } else if (sound.hard.speed > 32780) {
- sound.hard.speed = 49170;
- divider = 1;
- } else if (sound.hard.speed > 24585) {
- sound.hard.speed = 32780;
- divider = 2;
- } else if (sound.hard.speed > 19668) {
- sound.hard.speed = 24585;
- divider = 3;
- } else if (sound.hard.speed > 16390) {
- sound.hard.speed = 19668;
- divider = 4;
- } else if (sound.hard.speed > 12292) {
- sound.hard.speed = 16390;
- divider = 5;
- } else if (sound.hard.speed > 9834) {
- sound.hard.speed = 12292;
- divider = 7;
- } else if (sound.hard.speed > 8195) {
- sound.hard.speed = 9834;
- divider = 9;
- } else {
- sound.hard.speed = 8195;
- divider = 11;
- }
- tt_dmasnd.int_div = divider;
-
- /* Setup Falcon sound DMA for playback */
- tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
- tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
- tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
- tt_dmasnd.cbar_dst = 0x0000;
- tt_dmasnd.rec_track_select = 0;
- tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
- tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
-
- tt_dmasnd.mode = (sound.hard.stereo ?
- DMASND_MODE_STEREO : DMASND_MODE_MONO) |
- ((sound.hard.size == 8) ?
- DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
- DMASND_MODE_6KHZ;
-
- sound.bal = -sound.soft.speed;
-}
-
-
-static int FalconSetFormat(int format)
-{
- int size;
- /* Falcon sound DMA supports 8bit and 16bit modes */
-
- switch (format) {
- case AFMT_QUERY:
- return(sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- size = 8;
- format = AFMT_S8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = sound.soft.size;
- }
-
- FalconInit();
-
- return(format);
-}
-
-
-/* This is for the Falcon output *attenuation* in 1.5dB steps,
- * i.e. output level from 0 to -22.5dB in -1.5dB steps.
- */
-#define VOLUME_VOXWARE_TO_ATT(v) \
- ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
-#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
-
-
-static int FalconSetVolume(int volume)
-{
- sound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
- sound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
- tt_dmasnd.output_atten = sound.volume_left << 8 | sound.volume_right << 4;
- return(VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
- VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
-}
-
-
-static void ata_sq_play_next_frame(int index)
-{
- char *start, *end;
-
- /* used by AtaPlay() if all doubts whether there really is something
- * to be played are already wiped out.
- */
- start = sq_block_address(sq.front);
- end = start+((sq.count == index) ? sq.rear_size : sq.block_size);
- /* end might not be a legal virtual address. */
- DMASNDSetEnd(virt_to_phys(end - 1) + 1);
- DMASNDSetBase(virt_to_phys(start));
- /* Since only an even number of samples per frame can
- be played, we might lose one byte here. (TO DO) */
- sq.front = (sq.front+1) % sq.max_count;
- sq.active++;
- tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
-}
-
-
-static void AtaPlay(void)
-{
- /* ++TeSche: Note that sq.active is no longer just a flag but holds
- * the number of frames the DMA is currently programmed for instead,
- * may be 0, 1 (currently being played) or 2 (pre-programmed).
- *
- * Changes done to sq.count and sq.active are a bit more subtle again
- * so now I must admit I also prefer disabling the irq here rather
- * than considering all possible situations. But the point is that
- * disabling the irq doesn't have any bad influence on this version of
- * the driver as we benefit from having pre-programmed the DMA
- * wherever possible: There's no need to reload the DMA at the exact
- * time of an interrupt but only at some time while the pre-programmed
- * frame is playing!
- */
- atari_disable_irq(IRQ_MFP_TIMA);
-
- if (sq.active == 2 || /* DMA is 'full' */
- sq.count <= 0) { /* nothing to do */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
-
- if (sq.active == 0) {
- /* looks like there's nothing 'in' the DMA yet, so try
- * to put two frames into it (at least one is available).
- */
- if (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(1);
- if (sq.count == 1) {
- /* no more frames */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, there were two frames, but the second
- * one is not yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(2);
- } else {
- /* there's already a frame being played so we may only stuff
- * one new into the DMA, but even if this may be the last
- * frame existing the previous one is still on sq.count.
- */
- if (sq.count == 2 && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- atari_enable_irq(IRQ_MFP_TIMA);
- return;
- }
- ata_sq_play_next_frame(2);
- }
- atari_enable_irq(IRQ_MFP_TIMA);
-}
-
-
-static void ata_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
-#if 0
- /* ++TeSche: if you should want to test this... */
- static int cnt = 0;
- if (sq.active == 2)
- if (++cnt == 10) {
- /* simulate losing an interrupt */
- cnt = 0;
- return;
- }
-#endif
-
- if (sq.ignore_int && (sound.mach.type == DMASND_FALCON)) {
- /* ++TeSche: Falcon only: ignore first irq because it comes
- * immediately after starting a frame. after that, irqs come
- * (almost) like on the TT.
- */
- sq.ignore_int = 0;
- return;
- }
-
- if (!sq.active) {
- /* playing was interrupted and sq_reset() has already cleared
- * the sq variables, so better don't do anything here.
- */
- WAKE_UP(sq.sync_queue);
- return;
- }
-
- /* Probably ;) one frame is finished. Well, in fact it may be that a
- * pre-programmed one is also finished because there has been a long
- * delay in interrupt delivery and we've completely lost one, but
- * there's no way to detect such a situation. In such a case the last
- * frame will be played more than once and the situation will recover
- * as soon as the irq gets through.
- */
- sq.count--;
- sq.active--;
-
- if (!sq.active) {
- tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- sq.ignore_int = 1;
- }
-
- WAKE_UP(sq.action_queue);
- /* At least one block of the queue is free now
- so wake up a writing process blocked because
- of a full queue. */
-
- if ((sq.active != 1) || (sq.count != 1))
- /* We must be a bit carefully here: sq.count indicates the
- * number of buffers used and not the number of frames to
- * be played. If sq.count==1 and sq.active==1 that means
- * the only remaining frame was already programmed earlier
- * (and is currently running) so we mustn't call AtaPlay()
- * here, otherwise we'll play one frame too much.
- */
- AtaPlay();
-
- if (!sq.active) WAKE_UP(sq.sync_queue);
- /* We are not playing after AtaPlay(), so there
- is nothing to play any more. Wake up a process
- waiting for audio output to drain. */
-}
-#endif /* CONFIG_ATARI */
-
-
-#ifdef CONFIG_AMIGA
-
-/*
- * Amiga
- */
-
-#define StopDMA() custom.aud[0].audvol = custom.aud[1].audvol = 0; \
- custom.aud[2].audvol = custom.aud[3].audvol = 0; \
- custom.dmacon = AMI_AUDIO_OFF;
-
-static void *AmiAlloc(unsigned int size, int flags)
-{
- return amiga_chip_alloc((long)size, "dmasound");
-}
-
-static void AmiFree(void *obj, unsigned int size)
-{
- amiga_chip_free (obj);
-}
-
-static int __init AmiIrqInit(void)
-{
- /* turn off DMA for audio channels */
- StopDMA();
-
- /* Register interrupt handler. */
- if (request_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt, 0,
- "DMA sound", ami_sq_interrupt))
- return(0);
- return(1);
-}
-
-#ifdef MODULE
-static void AmiIrqCleanUp(void)
-{
- /* turn off DMA for audio channels */
- StopDMA();
- /* release the interrupt */
- free_irq(IRQ_AMIGA_AUD0, ami_sq_interrupt);
-}
-#endif /* MODULE */
-
-static void AmiSilence(void)
-{
- /* turn off DMA for audio channels */
- StopDMA();
-}
-
-
-static void AmiInit(void)
-{
- int period, i;
-
- AmiSilence();
-
- if (sound.soft.speed)
- period = amiga_colorclock/sound.soft.speed-1;
- else
- period = amiga_audio_min_period;
- sound.hard = sound.soft;
- sound.trans = &transAmiga;
-
- if (period < amiga_audio_min_period) {
- /* we would need to squeeze the sound, but we won't do that */
- period = amiga_audio_min_period;
- } else if (period > 65535) {
- period = 65535;
- }
- sound.hard.speed = amiga_colorclock/(period+1);
-
- for (i = 0; i < 4; i++)
- custom.aud[i].audper = period;
- amiga_audio_period = period;
-
- AmiSetTreble(50); /* recommended for newer amiga models */
-}
-
-
-static int AmiSetFormat(int format)
-{
- int size;
-
- /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
-
- switch (format) {
- case AFMT_QUERY:
- return(sound.soft.format);
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- size = 8;
- format = AFMT_S8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = sound.soft.size;
- }
- AmiInit();
-
- return(format);
-}
-
-
-#define VOLUME_VOXWARE_TO_AMI(v) \
- (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
-#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
-
-static int AmiSetVolume(int volume)
-{
- sound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
- custom.aud[0].audvol = sound.volume_left;
- sound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
- custom.aud[1].audvol = sound.volume_right;
- if (sound.hard.size == 16) {
- if (sound.volume_left == 64 && sound.volume_right == 64) {
- custom.aud[2].audvol = 1;
- custom.aud[3].audvol = 1;
- } else {
- custom.aud[2].audvol = 0;
- custom.aud[3].audvol = 0;
- }
- }
- return(VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
- (VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8));
-}
-
-static int AmiSetTreble(int treble)
-{
- sound.treble = treble;
- if (treble < 50)
- ciaa.pra &= ~0x02;
- else
- ciaa.pra |= 0x02;
- return(treble);
-}
-
-
-#define AMI_PLAY_LOADED 1
-#define AMI_PLAY_PLAYING 2
-#define AMI_PLAY_MASK 3
-
-
-static void ami_sq_play_next_frame(int index)
-{
- u_char *start, *ch0, *ch1, *ch2, *ch3;
- u_long size;
-
- /* used by AmiPlay() if all doubts whether there really is something
- * to be played are already wiped out.
- */
- start = sq_block_address(sq.front);
- size = (sq.count == index ? sq.rear_size : sq.block_size)>>1;
-
- if (sound.hard.stereo) {
- ch0 = start;
- ch1 = start+sq.block_size_half;
- size >>= 1;
- } else {
- ch0 = start;
- ch1 = start;
- }
-
- custom.aud[0].audvol = sound.volume_left;
- custom.aud[1].audvol = sound.volume_right;
- if (sound.hard.size == 8) {
- custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
- custom.aud[0].audlen = size;
- custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
- custom.aud[1].audlen = size;
- custom.dmacon = AMI_AUDIO_8;
- } else {
- size >>= 1;
- custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
- custom.aud[0].audlen = size;
- custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
- custom.aud[1].audlen = size;
- if (sound.volume_left == 64 && sound.volume_right == 64) {
- /* We can play pseudo 14-bit only with the maximum volume */
- ch3 = ch0+sq.block_size_quarter;
- ch2 = ch1+sq.block_size_quarter;
- custom.aud[2].audvol = 1; /* we are being affected by the beeps */
- custom.aud[3].audvol = 1; /* restoring volume here helps a bit */
- custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
- custom.aud[2].audlen = size;
- custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
- custom.aud[3].audlen = size;
- custom.dmacon = AMI_AUDIO_14;
- } else {
- custom.aud[2].audvol = 0;
- custom.aud[3].audvol = 0;
- custom.dmacon = AMI_AUDIO_8;
- }
- }
- sq.front = (sq.front+1) % sq.max_count;
- sq.active |= AMI_PLAY_LOADED;
-}
-
-
-static void AmiPlay(void)
-{
- int minframes = 1;
-
- custom.intena = IF_AUD0;
-
- if (sq.active & AMI_PLAY_LOADED) {
- /* There's already a frame loaded */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
-
- if (sq.active & AMI_PLAY_PLAYING)
- /* Increase threshold: frame 1 is already being played */
- minframes = 2;
-
- if (sq.count < minframes) {
- /* Nothing to do */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
-
- if (sq.count <= minframes && sq.rear_size < sq.block_size && !sq.syncing) {
- /* hmmm, the only existing frame is not
- * yet filled and we're not syncing?
- */
- custom.intena = IF_SETCLR | IF_AUD0;
- return;
- }
-
- ami_sq_play_next_frame(minframes);
-
- custom.intena = IF_SETCLR | IF_AUD0;
-}
-
-
-static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
- int minframes = 1;
-
- custom.intena = IF_AUD0;
-
- if (!sq.active) {
- /* Playing was interrupted and sq_reset() has already cleared
- * the sq variables, so better don't do anything here.
- */
- WAKE_UP(sq.sync_queue);
- return;
- }
-
- if (sq.active & AMI_PLAY_PLAYING) {
- /* We've just finished a frame */
- sq.count--;
- WAKE_UP(sq.action_queue);
- }
-
- if (sq.active & AMI_PLAY_LOADED)
- /* Increase threshold: frame 1 is already being played */
- minframes = 2;
-
- /* Shift the flags */
- sq.active = (sq.active<<1) & AMI_PLAY_MASK;
-
- if (!sq.active)
- /* No frame is playing, disable audio DMA */
- StopDMA();
-
- custom.intena = IF_SETCLR | IF_AUD0;
-
- if (sq.count >= minframes)
- /* Try to play the next frame */
- AmiPlay();
-
- if (!sq.active)
- /* Nothing to play anymore.
- Wake up a process waiting for audio output to drain. */
- WAKE_UP(sq.sync_queue);
-}
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-
-/*
- * PCI PowerMac, with AWACS and DBDMA.
- */
-
-static void *PMacAlloc(unsigned int size, int flags)
-{
- return kmalloc(size, flags);
-}
-
-static void PMacFree(void *ptr, unsigned int size)
-{
- kfree(ptr);
-}
-
-static int __init PMacIrqInit(void)
-{
- if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
- || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
- || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
- return 0;
- return 1;
-}
-
-#ifdef MODULE
-static void PMacIrqCleanup(void)
-{
- /* turn off output dma */
- out_le32(&awacs_txdma->control, RUN<<16);
- /* disable interrupts from awacs interface */
- out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
-#ifdef CONFIG_PMAC_PBOOK
- if (is_pbook_G3) {
- feature_clear(awacs_node, FEATURE_Sound_power);
- feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
- }
-#endif
- free_irq(awacs_irq, 0);
- free_irq(awacs_tx_irq, 0);
- free_irq(awacs_rx_irq, 0);
- kfree(awacs_tx_cmd_space);
- if (awacs_rx_cmd_space)
- kfree(awacs_rx_cmd_space);
- if (beep_buf)
- kfree(beep_buf);
- kd_mksound = orig_mksound;
-#ifdef CONFIG_PMAC_PBOOK
- pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
-#endif
-}
-#endif /* MODULE */
-
-static void PMacSilence(void)
-{
- /* turn off output dma */
- out_le32(&awacs_txdma->control, RUN<<16);
-}
-
-static int awacs_freqs[8] = {
- 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
-};
-static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-static void PMacInit(void)
-{
- int i, tolerance;
-
- switch (sound.soft.format) {
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- sound.hard.format = AFMT_S16_LE;
- break;
- default:
- sound.hard.format = AFMT_S16_BE;
- break;
- }
- sound.hard.stereo = 1;
- sound.hard.size = 16;
-
- /*
- * If we have a sample rate which is within catchRadius percent
- * of the requested value, we don't have to expand the samples.
- * Otherwise choose the next higher rate.
- * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
- */
- i = 8;
- do {
- tolerance = catchRadius * awacs_freqs[--i] / 100;
- if (awacs_freqs_ok[i]
- && sound.soft.speed <= awacs_freqs[i] + tolerance)
- break;
- } while (i > 0);
- if (sound.soft.speed >= awacs_freqs[i] - tolerance)
- sound.trans = &transAwacsNormal;
- else
- sound.trans = &transAwacsExpand;
- sound.read_trans = &transAwacsNormalRead;
- sound.hard.speed = awacs_freqs[i];
- awacs_rate_index = i;
-
- /* XXX disable error interrupt on burgundy for now */
- out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
- | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
- awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
-
- /* We really want to execute a DMA stop command, after the AWACS
- * is initialized.
- * For reasons I don't understand, it stops the hissing noise
- * common to many PowerBook G3 systems (like mine :-).
- */
- out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
- st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- out_le32(&awacs_txdma->control, RUN | (RUN << 16));
-
- sound.bal = -sound.soft.speed;
-}
-
-static int PMacSetFormat(int format)
-{
- int size;
-
- switch (format) {
- case AFMT_QUERY:
- return sound.soft.format;
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
- format);
- size = 8;
- format = AFMT_U8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = size;
- }
-
- PMacInit();
-
- return format;
-}
-
-#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))
-#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))
-
-static int awacs_get_volume(int reg, int lshift)
-{
- int volume;
-
- volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
- volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
- return volume;
-}
-
-static int awacs_volume_setter(int volume, int n, int mute, int lshift)
-{
- int r1, rn;
-
- if (mute && volume == 0) {
- r1 = awacs_reg[1] | mute;
- } else {
- r1 = awacs_reg[1] & ~mute;
- rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
- rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
- rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
- awacs_reg[n] = rn;
- awacs_write((n << 12) | rn);
- volume = awacs_get_volume(rn, lshift);
- }
- if (r1 != awacs_reg[1]) {
- awacs_reg[1] = r1;
- awacs_write(r1 | MASK_ADDR1);
- }
- return volume;
-}
-
-static int PMacSetVolume(int volume)
-{
- return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
-}
-
-static void PMacPlay(void)
-{
- volatile struct dbdma_cmd *cp;
- int i, count;
- unsigned long flags;
-
- save_flags(flags); cli();
- if (awacs_beep_state) {
- /* sound takes precedence over beeps */
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (awacs_rate_index << 8));
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
-
- beep_playing = 0;
- awacs_beep_state = 0;
- }
- i = sq.front + sq.active;
- if (i >= sq.max_count)
- i -= sq.max_count;
- while (sq.active < 2 && sq.active < sq.count) {
- count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
- if (count < sq.block_size && !sq.syncing)
- /* last block not yet filled, and we're not syncing. */
- break;
- cp = &awacs_tx_cmds[i];
- st_le16(&cp->req_count, count);
- st_le16(&cp->xfer_status, 0);
- if (++i >= sq.max_count)
- i = 0;
- out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
- out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
- if (sq.active == 0)
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
- out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- ++sq.active;
- }
- restore_flags(flags);
-}
-
-
-static void PMacRecord(void)
-{
- unsigned long flags;
-
- if (read_sq.active)
- return;
-
- save_flags(flags); cli();
-
- /* This is all we have to do......Just start it up.
- */
- out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
- read_sq.active = 1;
-
- restore_flags(flags);
-}
-
-
-static void
-pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
-{
- int i = sq.front;
- int stat;
- volatile struct dbdma_cmd *cp;
-
- while (sq.active > 0) {
- cp = &awacs_tx_cmds[i];
- stat = ld_le16(&cp->xfer_status);
- if ((stat & ACTIVE) == 0)
- break; /* this frame is still going */
- --sq.count;
- --sq.active;
- if (++i >= sq.max_count)
- i = 0;
- }
- if (i != sq.front)
- WAKE_UP(sq.action_queue);
- sq.front = i;
-
- PMacPlay();
-
- if (!sq.active)
- WAKE_UP(sq.sync_queue);
-}
-
-
-static void
-pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
-{
-
- /* For some reason on my PowerBook G3, I get one interrupt
- * when the interrupt vector is installed (like something is
- * pending). This happens before the dbdma is initialize by
- * us, so I just check the command pointer and if it is zero,
- * just blow it off.
- */
- if (in_le32(&awacs_rxdma->cmdptr) == 0)
- return;
-
- /* We also want to blow 'em off when shutting down.
- */
- if (read_sq.active == 0)
- return;
-
- /* Check multiple buffers in case we were held off from
- * interrupt processing for a long time. Geeze, I really hope
- * this doesn't happen.
- */
- while (awacs_rx_cmds[read_sq.rear].xfer_status) {
-
- /* Clear status and move on to next buffer.
- */
- awacs_rx_cmds[read_sq.rear].xfer_status = 0;
- read_sq.rear++;
-
- /* Wrap the buffer ring.
- */
- if (read_sq.rear >= read_sq.max_active)
- read_sq.rear = 0;
-
- /* If we have caught up to the front buffer, bump it.
- * This will cause weird (but not fatal) results if the
- * read loop is currently using this buffer. The user is
- * behind in this case anyway, so weird things are going
- * to happen.
- */
- if (read_sq.rear == read_sq.front) {
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
-
- WAKE_UP(read_sq.action_queue);
-}
-
-
-static void
-pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
-{
- int ctrl = in_le32(&awacs->control);
-
- if (ctrl & MASK_PORTCHG) {
- /* do something when headphone is plugged/unplugged? */
- }
- if (ctrl & MASK_CNTLERR) {
- int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
- if (err != 0 && awacs_revision < AWACS_BURGUNDY)
- printk(KERN_ERR "AWACS: error %x\n", err);
- }
- /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
- out_le32(&awacs->control, ctrl);
-}
-
-static void
-awacs_write(int val)
-{
- if (awacs_revision >= AWACS_BURGUNDY)
- return;
- while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
- ; /* XXX should have timeout */
- out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
-}
-
-static void awacs_nosound(unsigned long xx)
-{
- unsigned long flags;
-
- save_flags(flags); cli();
- if (beep_playing) {
- st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (awacs_rate_index << 8));
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- beep_playing = 0;
- }
- restore_flags(flags);
-}
-
-static struct timer_list beep_timer = {
- NULL, NULL, 0, 0, awacs_nosound
-};
-
-static void awacs_mksound(unsigned int hz, unsigned int ticks)
-{
- unsigned long flags;
- int beep_speed = 0;
- int srate;
- int period, ncycles, nsamples;
- int i, j, f;
- short *p;
- static int beep_hz_cache;
- static int beep_nsamples_cache;
- static int beep_volume_cache;
-
- for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
- if (awacs_freqs_ok[i])
- beep_speed = i;
- srate = awacs_freqs[beep_speed];
-
- if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
-#if 1
- /* this is a hack for broken X server code */
- hz = 750;
- ticks = 12;
-#else
- /* cancel beep currently playing */
- awacs_nosound(0);
- return;
-#endif
- }
- save_flags(flags); cli();
- del_timer(&beep_timer);
- if (ticks) {
- beep_timer.expires = jiffies + ticks;
- add_timer(&beep_timer);
- }
- if (beep_playing || sq.active || beep_buf == NULL) {
- restore_flags(flags);
- return; /* too hard, sorry :-( */
- }
- beep_playing = 1;
- st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
- restore_flags(flags);
-
- if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
- nsamples = beep_nsamples_cache;
- } else {
- period = srate * 256 / hz; /* fixed point */
- ncycles = BEEP_BUFLEN * 256 / period;
- nsamples = (period * ncycles) >> 8;
- f = ncycles * 65536 / nsamples;
- j = 0;
- p = beep_buf;
- for (i = 0; i < nsamples; ++i, p += 2) {
- p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
- j = (j + f) & 0xffff;
- }
- beep_hz_cache = hz;
- beep_volume_cache = beep_volume;
- beep_nsamples_cache = nsamples;
- }
-
- st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
- st_le16(&beep_dbdma_cmd->xfer_status, 0);
- st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
- st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
- awacs_beep_state = 1;
-
- save_flags(flags); cli();
- if (beep_playing) { /* i.e. haven't been terminated already */
- out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (beep_speed << 8));
- out_le32(&awacs->byteswap, 0);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- out_le32(&awacs_txdma->control, RUN | (RUN << 16));
- }
- restore_flags(flags);
-}
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save state when going to sleep, restore it afterwards.
- */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
- switch (when) {
- case PBOOK_SLEEP_NOW:
- /* XXX we should stop any dma in progress when going to sleep
- and restart it when we wake. */
- PMacSilence();
- disable_irq(awacs_irq);
- disable_irq(awacs_tx_irq);
- if (is_pbook_G3) {
- feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
- feature_clear(awacs_node, FEATURE_Sound_power);
- }
- break;
- case PBOOK_WAKE:
- /* There is still a problem on wake. Sound seems to work fine
- if I launch mpg123 and resumes fine if mpg123 was playing,
- but the console beep is dead until I do something with the
- mixer. Probably yet another timing issue */
- if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
- || !feature_test(awacs_node, FEATURE_Sound_power)) {
- /* these aren't present on the 3400 AFAIK -- paulus */
- feature_set(awacs_node, FEATURE_Sound_CLK_enable);
- feature_set(awacs_node, FEATURE_Sound_power);
- mdelay(1000);
- }
- out_le32(&awacs->control, MASK_IEPC
- | (awacs_rate_index << 8) | 0x11
- | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- awacs_write(awacs_reg[2] | MASK_ADDR2);
- awacs_write(awacs_reg[4] | MASK_ADDR4);
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- enable_irq(awacs_irq);
- enable_irq(awacs_tx_irq);
- if (awacs_revision == 3) {
- mdelay(100);
- awacs_write(0x6000);
- mdelay(2);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- }
- /* enable CD sound input */
- if (macio_base && is_pbook_G3) {
- out_8(macio_base + 0x37, 3);
- } else if (is_pbook_3400) {
- feature_set(awacs_node, FEATURE_IOBUS_enable);
- udelay(10);
- in_8(latch_base + 0x190);
- }
- /* Resume pending sounds. */
- PMacPlay();
- }
- return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-
-/* All the burgundy functions: */
-
-/* Waits for busy flag to clear */
-inline static void
-awacs_burgundy_busy_wait(void)
-{
- while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
- ;
-}
-
-inline static void
-awacs_burgundy_extend_wait(void)
-{
- while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND))
- ;
- while (in_le32(&awacs->codec_stat) & MASK_EXTEND)
- ;
-}
-
-static void
-awacs_burgundy_wcw(unsigned addr, unsigned val)
-{
- out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
- awacs_burgundy_busy_wait();
- out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
- awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcw(unsigned addr)
-{
- unsigned val = 0;
- unsigned long flags;
-
- /* should have timeouts here */
- save_flags(flags); cli();
-
- out_le32(&awacs->codec_ctrl, addr + 0x100000);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100100);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100200);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16;
-
- out_le32(&awacs->codec_ctrl, addr + 0x100300);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
-
- restore_flags(flags);
-
- return val;
-}
-
-
-static void
-awacs_burgundy_wcb(unsigned addr, unsigned val)
-{
- out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
- awacs_burgundy_busy_wait();
-}
-
-static unsigned
-awacs_burgundy_rcb(unsigned addr)
-{
- unsigned val = 0;
- unsigned long flags;
-
- /* should have timeouts here */
- save_flags(flags); cli();
-
- out_le32(&awacs->codec_ctrl, addr + 0x100000);
- awacs_burgundy_busy_wait();
- awacs_burgundy_extend_wait();
- val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
-
- restore_flags(flags);
-
- return val;
-}
-
-static int
-awacs_burgundy_check(void)
-{
- /* Checks to see the chip is alive and kicking */
- int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE;
-
- return error == 0xf0000;
-}
-
-static int
-awacs_burgundy_init(void)
-{
- if (awacs_burgundy_check()) {
- printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n");
- return 1;
- }
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES,
- DEF_BURGUNDY_OUTPUTENABLES);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- DEF_BURGUNDY_MORE_OUTPUTENABLES);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
- DEF_BURGUNDY_OUTPUTSELECTS);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21,
- DEF_BURGUNDY_INPSEL21);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3,
- DEF_BURGUNDY_INPSEL3);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD,
- DEF_BURGUNDY_GAINCD);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE,
- DEF_BURGUNDY_GAINLINE);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC,
- DEF_BURGUNDY_GAINMIC);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM,
- DEF_BURGUNDY_GAINMODEM);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER,
- DEF_BURGUNDY_ATTENSPEAKER);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT,
- DEF_BURGUNDY_ATTENLINEOUT);
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP,
- DEF_BURGUNDY_ATTENHP);
-
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME,
- DEF_BURGUNDY_MASTER_VOLUME);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD,
- DEF_BURGUNDY_VOLCD);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE,
- DEF_BURGUNDY_VOLLINE);
- awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC,
- DEF_BURGUNDY_VOLMIC);
- return 0;
-}
-
-static void
-awacs_burgundy_write_volume(unsigned address, int volume)
-{
- int hardvolume,lvolume,rvolume;
-
- lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0;
- rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0;
-
- hardvolume = lvolume + (rvolume << 16);
-
- awacs_burgundy_wcw(address, hardvolume);
-}
-
-static int
-awacs_burgundy_read_volume(unsigned address)
-{
- int softvolume,wvolume;
-
- wvolume = awacs_burgundy_rcw(address);
-
- softvolume = (wvolume & 0xff) - 155;
- softvolume += (((wvolume >> 16) & 0xff) - 155)<<8;
-
- return softvolume > 0 ? softvolume : 0;
-}
-
-
-
-
-static int
-awacs_burgundy_read_mvolume(unsigned address)
-{
- int lvolume,rvolume,wvolume;
-
- wvolume = awacs_burgundy_rcw(address);
-
- wvolume &= 0xffff;
-
- rvolume = (wvolume & 0xff) - 155;
- lvolume = ((wvolume & 0xff00)>>8) - 155;
-
- return lvolume + (rvolume << 8);
-}
-
-
-static void
-awacs_burgundy_write_mvolume(unsigned address, int volume)
-{
- int lvolume,rvolume,hardvolume;
-
- lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0;
- rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0;
-
- hardvolume = lvolume + (rvolume << 8);
- hardvolume += (hardvolume << 16);
-
- awacs_burgundy_wcw(address, hardvolume);
-}
-
-/* End burgundy functions */
-
-
-
-
-
-/* Turn on sound output, needed on G3 desktop powermacs */
-static void
-awacs_enable_amp(int spkr_vol)
-{
- struct adb_request req;
-
- awacs_spkr_vol = spkr_vol;
- if (sys_ctrler != SYS_CTRLER_CUDA)
- return;
-
- /* turn on headphones */
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 4, 0);
- while (!req.complete) cuda_poll();
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 6, 0);
- while (!req.complete) cuda_poll();
-
- /* turn on speaker */
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
- while (!req.complete) cuda_poll();
- cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
- 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
- while (!req.complete) cuda_poll();
-
- cuda_request(&req, NULL, 5, CUDA_PACKET,
- CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
- while (!req.complete) cuda_poll();
-}
-
-#endif /* CONFIG_PPC */
-
-/*** Machine definitions *****************************************************/
-
-
-#ifdef CONFIG_ATARI
-static MACHINE machTT = {
- DMASND_TT, AtaAlloc, AtaFree, AtaIrqInit,
-#ifdef MODULE
- AtaIrqCleanUp,
-#endif /* MODULE */
- TTInit, TTSilence, TTSetFormat, TTSetVolume,
- AtaSetBass, AtaSetTreble, TTSetGain,
- AtaPlay
-};
-
-static MACHINE machFalcon = {
- DMASND_FALCON, AtaAlloc, AtaFree, AtaIrqInit,
-#ifdef MODULE
- AtaIrqCleanUp,
-#endif /* MODULE */
- FalconInit, FalconSilence, FalconSetFormat, FalconSetVolume,
- AtaSetBass, AtaSetTreble, NULL,
- AtaPlay
-};
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
-static MACHINE machAmiga = {
- DMASND_AMIGA, AmiAlloc, AmiFree, AmiIrqInit,
-#ifdef MODULE
- AmiIrqCleanUp,
-#endif /* MODULE */
- AmiInit, AmiSilence, AmiSetFormat, AmiSetVolume,
- NULL, AmiSetTreble, NULL,
- AmiPlay
-};
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
-static MACHINE machPMac = {
- DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit,
-#ifdef MODULE
- PMacIrqCleanup,
-#endif /* MODULE */
- PMacInit, PMacSilence, PMacSetFormat, PMacSetVolume,
- NULL, NULL, NULL, /* bass, treble, gain */
- PMacPlay
-};
-#endif /* CONFIG_AMIGA */
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
- /* update hardware settings one more */
- (*sound.mach.init)();
-
- (*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
- (*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
- return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int speed)
-{
- if (speed < 0)
- return(sound.soft.speed);
-
- sound.soft.speed = speed;
- (*sound.mach.init)();
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.speed = sound.soft.speed;
-
- return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
- if (stereo < 0)
- return(sound.soft.stereo);
-
- stereo = !!stereo; /* should be 0 or 1 now */
-
- sound.soft.stereo = stereo;
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.stereo = stereo;
- (*sound.mach.init)();
-
- return(stereo);
-}
-
-
-static int sound_set_volume(int volume)
-{
- return(*sound.mach.setVolume)(volume);
-}
-
-
-#ifdef CONFIG_ATARI
-static int sound_set_bass(int bass)
-{
- return(sound.mach.setBass ? (*sound.mach.setBass)(bass) : 50);
-}
-
-static int sound_set_gain(int gain)
-{
- return sound.mach.setGain ? sound.mach.setGain(gain) : 100;
-}
-#endif /* CONFIG_ATARI */
-
-#if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA)
-static int sound_set_treble(int treble)
-{
- return(sound.mach.setTreble ? (*sound.mach.setTreble)(treble) : 50);
-}
-#endif /* CONFIG_ATARI || CONFIG_AMIGA */
-
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.trans->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.trans->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.trans->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.trans->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.trans->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.trans->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.trans->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.trans->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-
-#ifdef CONFIG_PPC
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.read_trans->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.read_trans->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.read_trans->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.read_trans->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.read_trans->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.read_trans->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.read_trans->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.read_trans->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-#endif
-
-
-/*
- * /dev/mixer abstraction
- */
-
-
-#define RECLEVEL_VOXWARE_TO_GAIN(v) \
- ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
-
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
- MOD_INC_USE_COUNT;
- mixer.busy = 1;
- return 0;
-}
-
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
- mixer.busy = 0;
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- int data;
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- mixer.modify_counter++;
- if (cmd == OSS_GETVERSION)
- return IOCTL_OUT(arg, SOUND_VERSION);
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_FALCON:
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "FALCON", sizeof(info.id));
- strncpy(info.name, "FALCON", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
- case SOUND_MIXER_READ_RECMASK:
- return IOCTL_OUT(arg, SOUND_MASK_MIC);
- case SOUND_MIXER_READ_STEREODEVS:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg,
- VOLUME_ATT_TO_VOXWARE(sound.volume_left) |
- VOLUME_ATT_TO_VOXWARE(sound.volume_right) << 8);
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- tt_dmasnd.input_gain =
- RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
- RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
- /* fall thru, return set value */
- case SOUND_MIXER_READ_MIC:
- return IOCTL_OUT(arg,
- RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
- RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
- case SOUND_MIXER_READ_SPEAKER:
- {
- int porta;
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = sound_ym.rd_data_reg_sel;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_WRITE_SPEAKER:
- {
- int porta;
- IOCTL_IN(arg, data);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (data < 50 ? 0x40 : 0);
- sound_ym.wd_data = porta;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- }
- break;
-
- case DMASND_TT:
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "TT", sizeof(info.id));
- strncpy(info.name, "TT", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- return IOCTL_OUT(arg,
- SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
- (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
- case SOUND_MIXER_READ_RECMASK:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_STEREODEVS:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg,
- VOLUME_DB_TO_VOXWARE(sound.volume_left) |
- (VOLUME_DB_TO_VOXWARE(sound.volume_right) << 8));
- case SOUND_MIXER_READ_BASS:
- return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.bass));
- case SOUND_MIXER_READ_TREBLE:
- return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(sound.treble));
- case SOUND_MIXER_READ_OGAIN:
- return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(sound.gain));
- case SOUND_MIXER_READ_SPEAKER:
- {
- int porta;
- if (MACH_IS_TT) {
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = sound_ym.rd_data_reg_sel;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- }
- break;
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_WRITE_BASS:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_bass(data));
- case SOUND_MIXER_WRITE_TREBLE:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_treble(data));
- case SOUND_MIXER_WRITE_OGAIN:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_gain(data));
- case SOUND_MIXER_WRITE_SPEAKER:
- if (MACH_IS_TT) {
- int porta;
- IOCTL_IN(arg, data);
- cli();
- sound_ym.rd_data_reg_sel = 14;
- porta = (sound_ym.rd_data_reg_sel & ~0x40) |
- (data < 50 ? 0x40 : 0);
- sound_ym.wd_data = porta;
- sti();
- return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
- }
- }
- break;
-#endif /* CONFIG_ATARI */
-
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "AMIGA", sizeof(info.id));
- strncpy(info.name, "AMIGA", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
- case SOUND_MIXER_READ_RECMASK:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_STEREODEVS:
- return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg,
- VOLUME_AMI_TO_VOXWARE(sound.volume_left) |
- VOLUME_AMI_TO_VOXWARE(sound.volume_right) << 8);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_READ_TREBLE:
- return IOCTL_OUT(arg, sound.treble);
- case SOUND_MIXER_WRITE_TREBLE:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_treble(data));
- }
- break;
-#endif /* CONFIG_AMIGA */
-
-#ifdef CONFIG_PPC
- case DMASND_AWACS:
- /* Different IOCTLS for burgundy*/
- if (awacs_revision < AWACS_BURGUNDY) {
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "AWACS", sizeof(info.id));
- strncpy(info.name, "AWACS", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info,
- sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_LINE | SOUND_MASK_MIC
- | SOUND_MASK_CD | SOUND_MASK_RECLEV
- | SOUND_MASK_ALTPCM
- | SOUND_MASK_MONITOR;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC
- | SOUND_MASK_CD;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECSRC:
- data = 0;
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- if (awacs_reg[0] & MASK_MUX_CD)
- data |= SOUND_MASK_CD;
- if (awacs_reg[1] & MASK_LOOPTHRU)
- data |= SOUND_MASK_MONITOR;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_CD
- | SOUND_MASK_MONITOR);
- awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
- | MASK_MUX_AUDIN);
- awacs_reg[1] &= ~MASK_LOOPTHRU;
- if (data & SOUND_MASK_LINE)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- if (data & SOUND_MASK_MIC)
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data & SOUND_MASK_CD)
- awacs_reg[0] |= MASK_MUX_CD;
- if (data & SOUND_MASK_MONITOR)
- awacs_reg[1] |= MASK_LOOPTHRU;
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- awacs_write(awacs_reg[1] | MASK_ADDR1);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_RECLEV;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_VOLUME:
- data = (awacs_reg[1] & MASK_AMUTE)? 0:
- awacs_get_volume(awacs_reg[2], 6);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_READ_SPEAKER:
- if (awacs_revision == 3
- && sys_ctrler == SYS_CTRLER_CUDA)
- data = awacs_spkr_vol;
- else
- data = (awacs_reg[1] & MASK_CMUTE)? 0:
- awacs_get_volume(awacs_reg[4], 6);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_SPEAKER:
- IOCTL_IN(arg, data);
- if (awacs_revision == 3
- && sys_ctrler == SYS_CTRLER_CUDA)
- awacs_enable_amp(data);
- else
- data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_volume = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- return IOCTL_OUT(arg, beep_volume);
- case SOUND_MIXER_WRITE_LINE:
- IOCTL_IN(arg, data);
- awacs_reg[0] &= ~MASK_MUX_AUDIN;
- if ((data & 0xff) >= 50)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
- /* fall through */
- case SOUND_MIXER_READ_LINE:
- data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- data &= 0xff;
- awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
- if (data >= 25) {
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data >= 75)
- awacs_reg[0] |= MASK_GAINLINE;
- }
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
- /* fall through */
- case SOUND_MIXER_READ_MIC:
- data = (awacs_reg[0] & MASK_MUX_MIC)?
- (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_CD:
- IOCTL_IN(arg, data);
- awacs_reg[0] &= ~MASK_MUX_CD;
- if ((data & 0xff) >= 50)
- awacs_reg[0] |= MASK_MUX_CD;
- awacs_write(MASK_ADDR0 | awacs_reg[0]);
- /* fall through */
- case SOUND_MIXER_READ_CD:
- data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- data = awacs_volume_setter(data, 0, 0, 4);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECLEV:
- data = awacs_get_volume(awacs_reg[0], 4);
- return IOCTL_OUT(arg, data);
- }
- break;
- } else {
- /* We are, we are, we are... Burgundy or better */
- switch(cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strncpy(info.id, "AWACS", sizeof(info.id));
- strncpy(info.name, "AWACS", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- copy_to_user_ret((int *)arg, &info,
- sizeof(info), -EFAULT);
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_MIC |
- SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC
- | SOUND_MASK_CD;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECSRC:
- data = 0;
- if (awacs_reg[0] & MASK_MUX_AUDIN)
- data |= SOUND_MASK_LINE;
- if (awacs_reg[0] & MASK_MUX_MIC)
- data |= SOUND_MASK_MIC;
- if (awacs_reg[0] & MASK_MUX_CD)
- data |= SOUND_MASK_CD;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_CD);
- awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
- | MASK_MUX_AUDIN);
- if (data & SOUND_MASK_LINE)
- awacs_reg[0] |= MASK_MUX_AUDIN;
- if (data & SOUND_MASK_MIC)
- awacs_reg[0] |= MASK_MUX_MIC;
- if (data & SOUND_MASK_CD)
- awacs_reg[0] |= MASK_MUX_CD;
- awacs_write(awacs_reg[0] | MASK_ADDR0);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
- | SOUND_MASK_RECLEV | SOUND_MASK_CD
- | SOUND_MASK_LINE;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
- /* Fall through */
- case SOUND_MIXER_READ_VOLUME:
- return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
- case SOUND_MIXER_WRITE_SPEAKER:
- IOCTL_IN(arg, data);
-
- if (!(data & 0xff)) {
- /* Mute the left speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);
- } else {
- /* Unmute the left speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);
- }
- if (!(data & 0xff00)) {
- /* Mute the right speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);
- } else {
- /* Unmute the right speaker */
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
- awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);
- }
-
- data = (((data&0xff)*16)/100 > 0xf ? 0xf :
- (((data&0xff)*16)/100)) +
- ((((data>>8)*16)/100 > 0xf ? 0xf :
- ((((data>>8)*16)/100)))<<4);
-
- awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);
- /* Fall through */
- case SOUND_MIXER_READ_SPEAKER:
- data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
- data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
- return IOCTL_OUT(arg, ~data);
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_volume = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- return IOCTL_OUT(arg, beep_volume);
- case SOUND_MIXER_WRITE_LINE:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
-
- /* fall through */
- case SOUND_MIXER_READ_LINE:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_MIC:
- IOCTL_IN(arg, data);
- /* Mic is mono device */
- data = (data << 8) + (data << 24);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
- /* fall through */
- case SOUND_MIXER_READ_MIC:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);
- data <<= 24;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_CD:
- IOCTL_IN(arg, data);
- awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
- /* fall through */
- case SOUND_MIXER_READ_CD:
- data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- data = awacs_volume_setter(data, 0, 0, 4);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECLEV:
- data = awacs_get_volume(awacs_reg[0], 4);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_OUTMASK:
- break;
- case SOUND_MIXER_OUTSRC:
- break;
- }
- break;
- }
-#endif
- }
-
- return -EINVAL;
-}
-
-
-static struct file_operations mixer_fops =
-{
- llseek: sound_lseek,
- ioctl: mixer_ioctl,
- open: mixer_open,
- release: mixer_release,
-};
-
-
-static void __init mixer_init(void)
-{
-#ifndef MODULE
- int mixer_unit;
-#endif
- mixer_unit = register_sound_mixer(&mixer_fops, -1);
- if (mixer_unit < 0)
- return;
-
- mixer.busy = 0;
- sound.treble = 0;
- sound.bass = 0;
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- atari_microwire_cmd(MW_LM1992_VOLUME(0));
- sound.volume_left = 0;
- atari_microwire_cmd(MW_LM1992_BALLEFT(0));
- sound.volume_right = 0;
- atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
- atari_microwire_cmd(MW_LM1992_TREBLE(0));
- atari_microwire_cmd(MW_LM1992_BASS(0));
- break;
- case DMASND_FALCON:
- sound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
- sound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- sound.volume_left = 64;
- sound.volume_right = 64;
- custom.aud[0].audvol = sound.volume_left;
- custom.aud[3].audvol = 1; /* For pseudo 14bit */
- custom.aud[1].audvol = sound.volume_right;
- custom.aud[2].audvol = 1; /* For pseudo 14bit */
- sound.treble = 50;
- break;
-#endif /* CONFIG_AMIGA */
- }
-}
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-static int sq_allocate_buffers(void)
-{
- int i;
-
- if (sound_buffers)
- return 0;
- sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
- if (!sound_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-
-static void sq_release_buffers(void)
-{
- int i;
-
- if (sound_buffers) {
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- }
-}
-
-
-#ifdef CONFIG_PPC
-static int sq_allocate_read_buffers(void)
-{
- int i;
- int j;
-
- if (sound_read_buffers)
- return 0;
- sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_read_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
- GFP_KERNEL);
- if (!sound_read_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_read_buffers[i],
- readbufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- return -ENOMEM;
- }
- /* XXXX debugging code */
- for (j=0; j<readbufSize; j++) {
- sound_read_buffers[i][j] = 0xef;
- }
- }
- return 0;
-}
-
-static void sq_release_read_buffers(void)
-{
- int i;
- volatile struct dbdma_cmd *cp;
-
-
- if (sound_read_buffers) {
- cp = awacs_rx_cmds;
- for (i = 0; i < numReadBufs; i++,cp++) {
- st_le16(&cp->command, DBDMA_STOP);
- }
- /* We should probably wait for the thing to stop before we
- release the memory */
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free (sound_read_buffers[i],
- bufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- }
-}
-#endif
-
-
-static void sq_setup(int numBufs, int bufSize, char **write_buffers)
-{
-#ifdef CONFIG_PPC
- int i;
- volatile struct dbdma_cmd *cp;
-#endif /* CONFIG_PPC */
-
- sq.max_count = numBufs;
- sq.max_active = numBufs;
- sq.block_size = bufSize;
- sq.buffers = write_buffers;
-
- sq.front = sq.count = 0;
- sq.rear = -1;
- sq.syncing = 0;
- sq.active = 0;
-
-#ifdef CONFIG_ATARI
- sq.ignore_int = 0;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- sq.block_size_half = sq.block_size>>1;
- sq.block_size_quarter = sq.block_size_half>>1;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
- cp = awacs_tx_cmds;
- memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
- for (i = 0; i < numBufs; ++i, ++cp) {
- st_le32(&cp->phy_addr, virt_to_bus(write_buffers[i]));
- }
- st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
- st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
-#endif /* CONFIG_PPC */
-}
-
-#ifdef CONFIG_PPC
-static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
-{
- int i;
- volatile struct dbdma_cmd *cp;
-
- read_sq.max_count = numBufs;
- read_sq.max_active = numBufs;
- read_sq.block_size = bufSize;
- read_sq.buffers = read_buffers;
-
- read_sq.front = read_sq.count = 0;
- read_sq.rear = 0;
- read_sq.rear_size = 0;
- read_sq.syncing = 0;
- read_sq.active = 0;
-
- cp = awacs_rx_cmds;
- memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
-
- /* Set dma buffers up in a loop */
- for (i = 0; i < numBufs; i++,cp++) {
- st_le32(&cp->phy_addr, virt_to_bus(read_buffers[i]));
- st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
- st_le16(&cp->req_count, read_sq.block_size);
- st_le16(&cp->xfer_status, 0);
- }
-
- /* The next two lines make the thing loop around.
- */
- st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
- st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
-
- /* Don't start until the first read is done.
- * This will also abort any operations in progress if the DMA
- * happens to be running (and it shouldn't).
- */
- out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
-
-}
-#endif /* CONFIG_PPC */
-
-
-static void sq_play(void)
-{
- (*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
- loff_t *ppos)
-{
- ssize_t uWritten = 0;
- u_char *dest;
- ssize_t uUsed, bUsed, bLeft;
-
- /* ++TeSche: Is something like this necessary?
- * Hey, that's an honest question! Or does any other part of the
- * filesystem already checks this situation? I really don't know.
- */
- if (uLeft == 0)
- return 0;
-
- /* The interrupt doesn't start to play the last, incomplete frame.
- * Thus we can append to it without disabling the interrupts! (Note
- * also that sq.rear isn't affected by the interrupt.)
- */
-
- if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
- dest = sq_block_address(sq.rear);
- bUsed = sq.rear_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- sq.rear_size = bUsed;
- }
-
- do {
- while (sq.count == sq.max_active) {
- sq_play();
- if (NON_BLOCKING(sq.open_mode))
- return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(sq.action_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- return uWritten > 0 ? uWritten : -EINTR;
- }
-
- /* Here, we can avoid disabling the interrupt by first
- * copying and translating the data, and then updating
- * the sq variables. Until this is done, the interrupt
- * won't see the new frame and we can work on it
- * undisturbed.
- */
-
- dest = sq_block_address((sq.rear+1) % sq.max_count);
- bUsed = 0;
- bLeft = sq.block_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- break;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- if (bUsed) {
- sq.rear = (sq.rear+1) % sq.max_count;
- sq.rear_size = bUsed;
- sq.count++;
- }
- } while (bUsed); /* uUsed may have been 0 */
-
- sq_play();
-
- return uUsed < 0? uUsed: uWritten;
-}
-
-
-/***********/
-
-#ifdef CONFIG_PPC
-
-/* Here is how the values are used for reading.
- * The value 'active' simply indicates the DMA is running. This is
- * done so the driver semantics are DMA starts when the first read is
- * posted. The value 'front' indicates the buffer we should next
- * send to the user. The value 'rear' indicates the buffer the DMA is
- * currently filling. When 'front' == 'rear' the buffer "ring" is
- * empty (we always have an empty available). The 'rear_size' is used
- * to track partial offsets into the current buffer. Right now, I just keep
- * the DMA running. If the reader can't keep up, the interrupt tosses
- * the oldest buffer. We could also shut down the DMA in this case.
- */
-static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
- loff_t *ppos)
-{
-
- ssize_t uRead, bLeft, bUsed, uUsed;
-
- if (uLeft == 0)
- return 0;
-
- if (!read_sq.active)
- PMacRecord(); /* Kick off the record process. */
-
- uRead = 0;
-
- /* Move what the user requests, depending upon other options.
- */
- while (uLeft > 0) {
-
- /* When front == rear, the DMA is not done yet.
- */
- while (read_sq.front == read_sq.rear) {
- if (NON_BLOCKING(read_sq.open_mode)) {
- return uRead > 0 ? uRead : -EAGAIN;
- }
- SLEEP(read_sq.action_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- return uRead > 0 ? uRead : -EINTR;
- }
-
- /* The amount we move is either what is left in the
- * current buffer or what the user wants.
- */
- bLeft = read_sq.block_size - read_sq.rear_size;
- bUsed = read_sq.rear_size;
- uUsed = sound_copy_translate_read(dst, uLeft,
- read_sq.buffers[read_sq.front], &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- dst += uUsed;
- uRead += uUsed;
- uLeft -= uUsed;
- read_sq.rear_size += bUsed;
- if (read_sq.rear_size >= read_sq.block_size) {
- read_sq.rear_size = 0;
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
- return uRead;
-}
-#endif
-
-static int sq_open(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- MOD_INC_USE_COUNT;
- if (file->f_mode & FMODE_WRITE) {
- if (sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (sq.busy) {
- SLEEP(sq.open_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- }
- sq.busy = 1; /* Let's play spot-the-race-condition */
-
- if (sq_allocate_buffers()) goto err_out_nobusy;
-
- sq_setup(numBufs, bufSize<<10,sound_buffers);
- sq.open_mode = file->f_mode;
- }
-
-
-#ifdef CONFIG_PPC
- if (file->f_mode & FMODE_READ) {
- if (read_sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (read_sq.busy) {
- SLEEP(read_sq.open_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- rc = 0;
- }
- read_sq.busy = 1;
- if (sq_allocate_read_buffers()) goto err_out_nobusy;
-
- read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
- read_sq.open_mode = file->f_mode;
- }
-#endif
-
-#ifdef CONFIG_ATARI
- sq.ignore_int = 1;
-#endif /* CONFIG_ATARI */
- sound.minDev = MINOR(inode->i_rdev) & 0x0f;
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_init();
- if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
- sound_set_speed(8000);
- sound_set_stereo(0);
- sound_set_format(AFMT_MU_LAW);
- }
-
-#if 0
- if (file->f_mode == FMODE_READ) {
- /* Start dma'ing straight away */
- PMacRecord();
- }
-#endif
-
- return 0;
-
-err_out_nobusy:
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
-#ifdef CONFIG_PPC
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-#endif
-err_out:
- MOD_DEC_USE_COUNT;
- return rc;
-}
-
-
-static void sq_reset(void)
-{
- sound_silence();
- sq.active = 0;
- sq.count = 0;
- sq.front = (sq.rear+1) % sq.max_count;
-}
-
-
-static int sq_fsync(struct file *filp, struct dentry *dentry)
-{
- int rc = 0;
-
- sq.syncing = 1;
- sq_play(); /* there may be an incomplete frame waiting */
-
- while (sq.active) {
- SLEEP(sq.sync_queue, ONE_SECOND);
- if (SIGNAL_RECEIVED) {
- /* While waiting for audio output to drain, an
- * interrupt occurred. Stop audio output immediately
- * and clear the queue. */
- sq_reset();
- rc = -EINTR;
- break;
- }
- }
-
- sq.syncing = 0;
- return rc;
-}
-
-static int sq_release(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- if (sq.busy)
- rc = sq_fsync(file, file->f_dentry);
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_silence();
-
-#ifdef CONFIG_PPC
- sq_release_read_buffers();
-#endif
- sq_release_buffers();
- MOD_DEC_USE_COUNT;
-
- /* There is probably a DOS atack here. They change the mode flag. */
- /* XXX add check here */
-#ifdef CONFIG_PPC
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-#endif
-
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
-
- /* Wake up a process waiting for the queue being released.
- * Note: There may be several processes waiting for a call
- * to open() returning. */
-
- return rc;
-}
-
-
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- u_long fmt;
- int data;
- int size, nbufs;
- audio_buf_info info;
-
- switch (cmd) {
- case SNDCTL_DSP_RESET:
- sq_reset();
- return 0;
- case SNDCTL_DSP_POST:
- case SNDCTL_DSP_SYNC:
- return sq_fsync(file, file->f_dentry);
-
- /* ++TeSche: before changing any of these it's
- * probably wise to wait until sound playing has
- * settled down. */
- case SNDCTL_DSP_SPEED:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_speed(data));
- case SNDCTL_DSP_STEREO:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data));
- case SOUND_PCM_WRITE_CHANNELS:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
- case SNDCTL_DSP_SETFMT:
- sq_fsync(file, file->f_dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_format(data));
- case SNDCTL_DSP_GETFMTS:
- fmt = 0;
- if (sound.trans) {
- if (sound.trans->ct_ulaw)
- fmt |= AFMT_MU_LAW;
- if (sound.trans->ct_alaw)
- fmt |= AFMT_A_LAW;
- if (sound.trans->ct_s8)
- fmt |= AFMT_S8;
- if (sound.trans->ct_u8)
- fmt |= AFMT_U8;
- if (sound.trans->ct_s16be)
- fmt |= AFMT_S16_BE;
- if (sound.trans->ct_u16be)
- fmt |= AFMT_U16_BE;
- if (sound.trans->ct_s16le)
- fmt |= AFMT_S16_LE;
- if (sound.trans->ct_u16le)
- fmt |= AFMT_U16_LE;
- }
- return IOCTL_OUT(arg, fmt);
- case SNDCTL_DSP_GETBLKSIZE:
- size = sq.block_size
- * sound.soft.size * (sound.soft.stereo + 1)
- / (sound.hard.size * (sound.hard.stereo + 1));
- return IOCTL_OUT(arg, size);
- case SNDCTL_DSP_SUBDIVIDE:
- break;
- case SNDCTL_DSP_SETFRAGMENT:
- if (sq.count || sq.active || sq.syncing)
- return -EINVAL;
- IOCTL_IN(arg, size);
- nbufs = size >> 16;
- if (nbufs < 2 || nbufs > numBufs)
- nbufs = numBufs;
- size &= 0xffff;
- if (size >= 8 && size <= 29) {
- size = 1 << size;
- size *= sound.hard.size * (sound.hard.stereo + 1);
- size /= sound.soft.size * (sound.soft.stereo + 1);
- if (size > (bufSize << 10))
- size = bufSize << 10;
- } else
- size = bufSize << 10;
- sq_setup(numBufs, size, sound_buffers);
- sq.max_active = nbufs;
- return 0;
- case SNDCTL_DSP_GETOSPACE:
- info.fragments = sq.max_active - sq.count;
- info.fragstotal = sq.max_active;
- info.fragsize = sq.block_size;
- info.bytes = info.fragments * info.fragsize;
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
-
- default:
- return mixer_ioctl(inode, file, cmd, arg);
- }
- return -EINVAL;
-}
-
-
-
-static struct file_operations sq_fops =
-{
- llseek: sound_lseek,
- write: sq_write,
- ioctl: sq_ioctl,
- open: sq_open,
- release: sq_release,
-#ifdef CONFIG_PPC
- read: sq_read, /* sq_read */
-#endif
-};
-
-
-static void __init sq_init(void)
-{
-#ifndef MODULE
- int sq_unit;
-#endif
- sq_unit = register_sound_dsp(&sq_fops, -1);
- if (sq_unit < 0)
- return;
-
- init_waitqueue_head(&sq.action_queue);
- init_waitqueue_head(&sq.open_queue);
- init_waitqueue_head(&sq.sync_queue);
-
-#ifdef CONFIG_PPC
- init_waitqueue_head(&read_sq.action_queue);
- init_waitqueue_head(&read_sq.open_queue);
- init_waitqueue_head(&read_sq.sync_queue);
-#endif
-
- sq.busy = 0;
-#ifdef CONFIG_PPC
- read_sq.busy = 0;
-#endif
-
- /* whatever you like as startup mode for /dev/dsp,
- * (/dev/audio hasn't got a startup mode). note that
- * once changed a new open() will *not* restore these!
- */
- sound.dsp.format = AFMT_U8;
- sound.dsp.stereo = 0;
- sound.dsp.size = 8;
-
- /* set minimum rate possible without expanding */
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- sound.dsp.speed = 6258;
- break;
- case DMASND_FALCON:
- sound.dsp.speed = 8195;
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- sound.dsp.speed = 8000;
- break;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
- case DMASND_AWACS:
- sound.dsp.speed = 8000;
- break;
-#endif /* CONFIG_PPC */
- }
-
- /* before the first open to /dev/dsp this wouldn't be set */
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
-
- sound_silence();
-}
-
-/*
- * /dev/sndstat
- */
-
-
-/* state.buf should not overflow! */
-
-static int state_open(struct inode *inode, struct file *file)
-{
- char *buffer = state.buf, *mach = "";
-#ifdef CONFIG_PPC
- char awacs_buf[64];
-#endif
- int len = 0;
-
- if (state.busy)
- return -EBUSY;
-
- MOD_INC_USE_COUNT;
- state.ptr = 0;
- state.busy = 1;
-
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- case DMASND_FALCON:
- mach = "Atari ";
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- mach = "Amiga ";
- break;
-#endif /* CONFIG_AMIGA */
-#ifdef CONFIG_PPC
- case DMASND_AWACS:
- sprintf(awacs_buf, "PowerMac (AWACS rev %d) ", awacs_revision);
- mach = awacs_buf;
- break;
-#endif /* CONFIG_PPC */
- }
- len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
- len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- len += sprintf(buffer+len, " (mu-law)");
- break;
- case AFMT_A_LAW:
- len += sprintf(buffer+len, " (A-law)");
- break;
- case AFMT_U8:
- len += sprintf(buffer+len, " (unsigned 8 bit)");
- break;
- case AFMT_S8:
- len += sprintf(buffer+len, " (signed 8 bit)");
- break;
- case AFMT_S16_BE:
- len += sprintf(buffer+len, " (signed 16 bit big)");
- break;
- case AFMT_U16_BE:
- len += sprintf(buffer+len, " (unsigned 16 bit big)");
- break;
- case AFMT_S16_LE:
- len += sprintf(buffer+len, " (signed 16 bit little)");
- break;
- case AFMT_U16_LE:
- len += sprintf(buffer+len, " (unsigned 16 bit little)");
- break;
- }
- len += sprintf(buffer+len, "\n");
- len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
- sound.soft.speed, sound.hard.speed);
- len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
- sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
- switch (sound.mach.type) {
-#ifdef CONFIG_ATARI
- case DMASND_TT:
- len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
- sound.volume_right);
- len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
- sound.bass);
- len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
- sound.treble);
- break;
- case DMASND_FALCON:
- len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
- sound.volume_right);
- break;
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case DMASND_AMIGA:
- len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
- sound.volume_left);
- len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
- sound.volume_right);
- break;
-#endif /* CONFIG_AMIGA */
- }
- len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
- " sq.max_active = %d\n",
- sq.block_size, sq.max_count, sq.max_active);
- len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
- sq.rear_size);
- len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
- sq.active, sq.syncing);
- state.len = len;
- return 0;
-}
-
-
-static int state_release(struct inode *inode, struct file *file)
-{
- state.busy = 0;
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-
-static ssize_t state_read(struct file *file, char *buf, size_t count,
- loff_t *ppos)
-{
- int n = state.len - state.ptr;
- if (n > count)
- n = count;
- if (n <= 0)
- return 0;
- if (copy_to_user(buf, &state.buf[state.ptr], n))
- return -EFAULT;
- state.ptr += n;
- return n;
-}
-
-
-static struct file_operations state_fops =
-{
- llseek: sound_lseek,
- read: state_read,
- open: state_open,
- release: state_release,
-};
-
-
-static void __init state_init(void)
-{
-#ifndef MODULE
- int state_unit;
-#endif
- state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
- if (state_unit < 0)
- return;
- state.busy = 0;
-}
-
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
- return -ESPIPE;
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-void __init dmasound_init(void)
-{
- int has_sound = 0;
-#ifdef CONFIG_PPC
- struct device_node *np;
-#endif
-
-#if defined(__mc68000__) || defined(CONFIG_APUS)
- switch (m68k_machtype) {
-#ifdef CONFIG_ATARI
- case MACH_ATARI:
- if (ATARIHW_PRESENT(PCM_8BIT)) {
- if (ATARIHW_PRESENT(CODEC))
- sound.mach = machFalcon;
- else if (ATARIHW_PRESENT(MICROWIRE))
- sound.mach = machTT;
- else
- break;
- if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
- has_sound = 1;
- else
- printk("DMA sound driver: Timer A interrupt already in use\n");
- }
- break;
-
-#endif /* CONFIG_ATARI */
-#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
- if (AMIGAHW_PRESENT(AMI_AUDIO)) {
- sound.mach = machAmiga;
- has_sound = 1;
- }
- break;
-#endif /* CONFIG_AMIGA */
- }
-#endif /* __mc68000__||CONFIG_APUS */
-
-#ifdef CONFIG_PPC
- awacs_subframe = 0;
- awacs_revision = 0;
- np = find_devices("awacs");
- if (np == 0) {
- /*
- * powermac G3 models have a node called "davbus"
- * with a child called "sound".
- */
- struct device_node *sound;
- np = find_devices("davbus");
- sound = find_devices("sound");
- if (sound != 0 && sound->parent == np) {
- unsigned int *prop, l, i;
- prop = (unsigned int *)
- get_property(sound, "sub-frame", 0);
- if (prop != 0 && *prop >= 0 && *prop < 16)
- awacs_subframe = *prop;
- if (device_is_compatible(sound, "burgundy"))
- awacs_revision = AWACS_BURGUNDY;
-
- /* look for a property saying what sample rates
- are available */
- for (i = 0; i < 8; ++i)
- awacs_freqs_ok[i] = 0;
- prop = (unsigned int *) get_property
- (sound, "sample-rates", &l);
- if (prop == 0)
- prop = (unsigned int *) get_property
- (sound, "output-frame-rates", &l);
- if (prop != 0) {
- for (l /= sizeof(int); l > 0; --l) {
- /* sometimes the rate is in the
- high-order 16 bits (?) */
- unsigned int r = *prop++;
- if (r >= 0x10000)
- r >>= 16;
- for (i = 0; i < 8; ++i) {
- if (r == awacs_freqs[i]) {
- awacs_freqs_ok[i] = 1;
- break;
- }
- }
- }
- } else {
- /* assume just 44.1k is OK */
- awacs_freqs_ok[0] = 1;
- }
- }
- }
- if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
- int vol;
- sound.mach = machPMac;
- has_sound = 1;
-
- awacs = (volatile struct awacs_regs *)
- ioremap(np->addrs[0].address, 0x80);
- awacs_txdma = (volatile struct dbdma_regs *)
- ioremap(np->addrs[1].address, 0x100);
- awacs_rxdma = (volatile struct dbdma_regs *)
- ioremap(np->addrs[2].address, 0x100);
-
- awacs_irq = np->intrs[0].line;
- awacs_tx_irq = np->intrs[1].line;
- awacs_rx_irq = np->intrs[2].line;
-
- awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
- GFP_KERNEL);
- if (awacs_tx_cmd_space == NULL) {
- printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
- return;
- }
- awacs_node = np;
-#ifdef CONFIG_PMAC_PBOOK
- if (machine_is_compatible("PowerBook1,1")
- || machine_is_compatible("AAPL,PowerBook1998")) {
- feature_set(np, FEATURE_Sound_CLK_enable);
- feature_set(np, FEATURE_Sound_power);
- /* Shorter delay will not work */
- mdelay(1000);
- }
-#endif
- awacs_tx_cmds = (volatile struct dbdma_cmd *)
- DBDMA_ALIGN(awacs_tx_cmd_space);
-
-
- awacs_rx_cmd_space = kmalloc((numReadBufs + 4) * sizeof(struct dbdma_cmd),
- GFP_KERNEL);
- if (awacs_rx_cmd_space == NULL) {
- printk("DMA sound driver: No memory for input");
- }
- awacs_rx_cmds = (volatile struct dbdma_cmd *)
- DBDMA_ALIGN(awacs_rx_cmd_space);
-
-
-
- awacs_reg[0] = MASK_MUX_CD;
- awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
- /* get default volume from nvram */
- vol = (~nvram_read_byte(0x1308) & 7) << 1;
- awacs_reg[2] = vol + (vol << 6);
- awacs_reg[4] = vol + (vol << 6);
- out_le32(&awacs->control, 0x11);
- awacs_write(awacs_reg[0] + MASK_ADDR0);
- awacs_write(awacs_reg[1] + MASK_ADDR1);
- awacs_write(awacs_reg[2] + MASK_ADDR2);
- awacs_write(awacs_reg[4] + MASK_ADDR4);
-
- /* Initialize recent versions of the awacs */
- if (awacs_revision == 0) {
- awacs_revision =
- (in_le32(&awacs->codec_stat) >> 12) & 0xf;
- if (awacs_revision == 3) {
- mdelay(100);
- awacs_write(0x6000);
- mdelay(2);
- awacs_write(awacs_reg[1] + MASK_ADDR1);
- awacs_enable_amp(100 * 0x101);
- }
- }
- if (awacs_revision >= AWACS_BURGUNDY)
- awacs_burgundy_init();
-
- /* Initialize beep stuff */
- beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1);
- orig_mksound = kd_mksound;
- kd_mksound = awacs_mksound;
- beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
- if (beep_buf == NULL)
- printk(KERN_WARNING "dmasound: no memory for "
- "beep buffer\n");
-#ifdef CONFIG_PMAC_PBOOK
- pmu_register_sleep_notifier(&awacs_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-
- /* Powerbooks have odd ways of enabling inputs such as
- an expansion-bay CD or sound from an internal modem
- or a PC-card modem. */
- if (machine_is_compatible("AAPL,3400/2400")
- || machine_is_compatible("AAPL,3500")) {
- is_pbook_3400 = 1;
- /*
- * Enable CD and PC-card sound inputs.
- * This is done by reading from address
- * f301a000, + 0x10 to enable the expansion-bay
- * CD sound input, + 0x80 to enable the PC-card
- * sound input. The 0x100 enables the SCSI bus
- * terminator power.
- */
- latch_base = (unsigned char *) ioremap
- (0xf301a000, 0x1000);
- in_8(latch_base + 0x190);
- } else if (machine_is_compatible("PowerBook1,1")
- || machine_is_compatible("AAPL,PowerBook1998")) {
- struct device_node* mio;
- macio_base = 0;
- is_pbook_G3 = 1;
- for (mio = np->parent; mio; mio = mio->parent) {
- if (strcmp(mio->name, "mac-io") == 0
- && mio->n_addrs > 0) {
- macio_base = (unsigned char *) ioremap
- (mio->addrs[0].address, 0x40);
- break;
- }
- }
- /* enable CD sound input */
- if (macio_base)
- out_8(macio_base + 0x37, 3);
- }
- }
-#endif /* CONFIG_PPC */
-
- if (!has_sound)
- return;
-
- /* Set up sound queue, /dev/audio and /dev/dsp. */
-
- /* Set default settings. */
- sq_init();
-
- /* Set up /dev/sndstat. */
- state_init();
-
- /* Set up /dev/mixer. */
- mixer_init();
-
- if (!sound.mach.irqinit()) {
- printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
- return;
- }
-#ifdef MODULE
- irq_installed = 1;
-#endif
-
- printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
- numBufs, bufSize);
-
- return;
-}
-
-
-static int __init dmasound_setup(char *str)
-{
- int ints[6];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- /* check the bootstrap parameter for "dmasound=" */
-
- switch (ints[0]) {
- case 3:
- if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
- printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
- else
- catchRadius = ints[3];
- /* fall through */
- case 2:
- if (ints[1] < MIN_BUFFERS)
- printk("dmasound_setup: illegal number of buffers, using default = %d\n", numBufs);
- else
- numBufs = ints[1];
- if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
- printk("dmasound_setup: illegal buffer size, using default = %d\n", bufSize);
- else
- bufSize = ints[2];
- break;
- case 0:
- break;
- default:
- printk("dmasound_setup: illegal number of arguments\n");
- return 0;
- }
-
- return 1;
-}
-
-__setup("dmasound=", dmasound_setup);
-
-
-#ifdef MODULE
-
-int init_module(void)
-{
- dmasound_init();
- return 0;
-}
-
-
-void cleanup_module(void)
-{
- if (irq_installed) {
- sound_silence();
- sound.mach.irqcleanup();
- }
-
-#ifdef CONFIG_PPC
- sq_release_read_buffers();
-#endif
- sq_release_buffers();
-
- if (mixer_unit >= 0)
- unregister_sound_mixer(mixer_unit);
- if (state_unit >= 0)
- unregister_sound_special(state_unit);
- if (sq_unit >= 0)
- unregister_sound_dsp(sq_unit);
-}
-
-#endif /* MODULE */
diff --git a/drivers/sound/dmasound.h b/drivers/sound/dmasound.h
deleted file mode 100644
index fec3ad84e..000000000
--- a/drivers/sound/dmasound.h
+++ /dev/null
@@ -1,36 +0,0 @@
-
-/* linux/drivers/sound/dmasound.h */
-
-/*
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-
-#define SND_NDEVS 256 /* Number of supported devices */
-#define SND_DEV_CTL 0 /* Control port /dev/mixer */
-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
- synthesizer and MIDI output) */
-#define SND_DEV_MIDIN 2 /* Raw midi access */
-#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6 /* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS SND_DEV_SNDPROC
-
-#define DSP_DEFAULT_SPEED 8000
-
-#define ON 1
-#define OFF 0
-
-#define MAX_AUDIO_DEV 5
-#define MAX_MIXER_DEV 2
-#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 6
-#define MAX_TIMER_DEV 3
diff --git a/drivers/sound/dmasound/.cvsignore b/drivers/sound/dmasound/.cvsignore
new file mode 100644
index 000000000..88fff7fc4
--- /dev/null
+++ b/drivers/sound/dmasound/.cvsignore
@@ -0,0 +1,5 @@
+.depend
+.*.flags
+.defines
+local.h
+configure
diff --git a/drivers/sound/dmasound/Config.in b/drivers/sound/dmasound/Config.in
new file mode 100644
index 000000000..c5f4c3c53
--- /dev/null
+++ b/drivers/sound/dmasound/Config.in
@@ -0,0 +1,27 @@
+# drivers/sound/dmasound/Config.in
+
+if [ "$CONFIG_ATARI" = "y" ]; then
+ dep_tristate ' Atari DMA sound support' CONFIG_DMASOUND_ATARI $CONFIG_SOUND
+fi
+if [ "$CONFIG_ALL_PPC" = "y" ]; then
+ dep_tristate ' PowerMac DMA sound support' CONFIG_DMASOUND_AWACS $CONFIG_SOUND
+fi
+if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_APUS" = "y" ]; then
+ dep_tristate ' Amiga DMA sound support' CONFIG_DMASOUND_PAULA $CONFIG_SOUND
+fi
+if [ "$CONFIG_Q40" = "y" ]; then
+ dep_tristate ' Q40 sound support' CONFIG_DMASOUND_Q40 $CONFIG_SOUND
+fi
+if [ "$CONFIG_DMASOUND_ATARI" = "y" -o \
+ "$CONFIG_DMASOUND_AWACS" = "y" -o \
+ "$CONFIG_DMASOUND_PAULA" = "y" -o \
+ "$CONFIG_DMASOUND_Q40" = "y" ]; then
+ define_tristate CONFIG_DMASOUND y
+else
+ if [ "$CONFIG_DMASOUND_ATARI" = "m" -o \
+ "$CONFIG_DMASOUND_AWACS" = "m" -o \
+ "$CONFIG_DMASOUND_PAULA" = "m" -o \
+ "$CONFIG_DMASOUND_Q40" = "m" ]; then
+ define_tristate CONFIG_DMASOUND m
+ fi
+fi
diff --git a/drivers/sound/dmasound/Makefile b/drivers/sound/dmasound/Makefile
new file mode 100644
index 000000000..535146de2
--- /dev/null
+++ b/drivers/sound/dmasound/Makefile
@@ -0,0 +1,38 @@
+#
+# Makefile for the DMA sound driver
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET :=
+O_OBJS :=
+OX_OBJS :=
+M_OBJS :=
+MX_OBJS :=
+
+export-objs := dmasound_core.o
+
+obj-$(CONFIG_DMASOUND_ATARI) += dmasound_core.o dmasound_atari.o
+obj-$(CONFIG_DMASOUND_AWACS) += dmasound_core.o dmasound_awacs.o
+obj-$(CONFIG_DMASOUND_PAULA) += dmasound_core.o dmasound_paula.o
+obj-$(CONFIG_DMASOUND_Q40) += dmasound_core.o dmasound_q40.o
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(filter-out $(export-objs), $(obj-y))
+OX_OBJS := $(filter $(export-objs), $(obj-y))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+
+ifeq ($(CONFIG_DMASOUND),y)
+ O_TARGET = dmasound.o
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/sound/dmasound/dmasound.h b/drivers/sound/dmasound/dmasound.h
new file mode 100644
index 000000000..985785e74
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound.h
@@ -0,0 +1,246 @@
+
+/*
+ * linux/drivers/sound/dmasound.h
+ *
+ *
+ * Minor numbers for the sound driver.
+ *
+ * Unfortunately Creative called the codec chip of SB as a DSP. For this
+ * reason the /dev/dsp is reserved for digitized audio use. There is a
+ * device for true DSP processors but it will be called something else.
+ * In v3.0 it's /dev/sndproc but this could be a temporary solution.
+ */
+
+
+#include <linux/config.h>
+
+
+#define SND_NDEVS 256 /* Number of supported devices */
+#define SND_DEV_CTL 0 /* Control port /dev/mixer */
+#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
+ synthesizer and MIDI output) */
+#define SND_DEV_MIDIN 2 /* Raw midi access */
+#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
+#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
+#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
+#define SND_DEV_STATUS 6 /* /dev/sndstat */
+/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
+#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
+#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
+#define SND_DEV_PSS SND_DEV_SNDPROC
+
+#define DSP_DEFAULT_SPEED 8000
+
+#define ON 1
+#define OFF 0
+
+#define MAX_AUDIO_DEV 5
+#define MAX_MIXER_DEV 2
+#define MAX_SYNTH_DEV 3
+#define MAX_MIDI_DEV 6
+#define MAX_TIMER_DEV 3
+
+
+#define MAX_CATCH_RADIUS 10
+#define MIN_BUFFERS 4
+#define MIN_BUFSIZE 4 /* in KB */
+#define MAX_BUFSIZE 128 /* Limit for Amiga in KB */
+
+
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
+#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
+
+#define IOCTL_IN(arg, ret) \
+ do { int error = get_user(ret, (int *)(arg)); \
+ if (error) return error; \
+ } while (0)
+#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
+
+static inline int ioctl_return(int *addr, int value)
+{
+ return value < 0 ? value : put_user(value, addr);
+}
+
+
+ /*
+ * Configuration
+ */
+
+#undef HAS_8BIT_TABLES
+#undef HAS_14BIT_TABLES
+#undef HAS_16BIT_TABLES
+#undef HAS_RECORD
+
+#if defined(CONFIG_DMASOUND_ATARI) || defined(CONFIG_DMASOUND_ATARI_MODULE) ||\
+ defined(CONFIG_DMASOUND_PAULA) || defined(CONFIG_DMASOUND_PAULA_MODULE) ||\
+ defined(CONFIG_DMASOUND_Q40) || defined(CONFIG_DMASOUND_Q40_MODULE)
+#define HAS_8BIT_TABLES
+#endif
+#if defined(CONFIG_DMASOUND_AWACS) || defined(CONFIG_DMASOUND_AWACS_MODULE)
+#define HAS_16BIT_TABLES
+#define HAS_RECORD
+#endif
+
+
+ /*
+ * Initialization
+ */
+
+extern int dmasound_init(void);
+extern void dmasound_deinit(void);
+
+
+ /*
+ * Machine definitions
+ */
+
+typedef struct {
+ const char *name;
+ const char *name2;
+ void (*open)(void);
+ void (*release)(void);
+ void *(*dma_alloc)(unsigned int, int);
+ void (*dma_free)(void *, unsigned int);
+ int (*irqinit)(void);
+#ifdef MODULE
+ void (*irqcleanup)(void);
+#endif /* MODULE */
+ void (*init)(void);
+ void (*silence)(void);
+ int (*setFormat)(int);
+ int (*setVolume)(int);
+ int (*setBass)(int);
+ int (*setTreble)(int);
+ int (*setGain)(int);
+ void (*play)(void);
+ void (*record)(void); /* optional */
+ void (*mixer_init)(void); /* optional */
+ int (*mixer_ioctl)(u_int, u_long); /* optional */
+ void (*write_sq_setup)(void); /* optional */
+ void (*read_sq_setup)(void); /* optional */
+ void (*sq_open)(void); /* optional */
+ int (*state_info)(char *); /* optional */
+ void (*abort_read)(void); /* optional */
+ int min_dsp_speed;
+} MACHINE;
+
+
+ /*
+ * Low level stuff
+ */
+
+typedef struct {
+ int format; /* AFMT_* */
+ int stereo; /* 0 = mono, 1 = stereo */
+ int size; /* 8/16 bit*/
+ int speed; /* speed */
+} SETTINGS;
+
+typedef struct {
+ ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+ ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+} TRANS;
+
+struct sound_settings {
+ MACHINE mach; /* machine dependent things */
+ SETTINGS hard; /* hardware settings */
+ SETTINGS soft; /* software settings */
+ SETTINGS dsp; /* /dev/dsp default settings */
+ TRANS *trans_write; /* supported translations */
+#ifdef HAS_RECORD
+ TRANS *trans_read; /* supported translations */
+#endif
+ int volume_left; /* volume (range is machine dependent) */
+ int volume_right;
+ int bass; /* tone (range is machine dependent) */
+ int treble;
+ int gain;
+ int minDev; /* minor device number currently open */
+};
+
+extern struct sound_settings dmasound;
+
+extern char dmasound_ulaw2dma8[];
+extern char dmasound_alaw2dma8[];
+extern short dmasound_ulaw2dma16[];
+extern short dmasound_alaw2dma16[];
+
+
+ /*
+ * Mid level stuff
+ */
+
+static inline int dmasound_set_volume(int volume)
+{
+ return dmasound.mach.setVolume(volume);
+}
+
+static inline int dmasound_set_bass(int bass)
+{
+ return dmasound.mach.setBass ? dmasound.mach.setBass(bass) : 50;
+}
+
+static inline int dmasound_set_treble(int treble)
+{
+ return dmasound.mach.setTreble ? dmasound.mach.setTreble(treble) : 50;
+}
+
+static inline int dmasound_set_gain(int gain)
+{
+ return dmasound.mach.setGain ? dmasound.mach.setGain(gain) : 100;
+}
+
+
+ /*
+ * Sound queue stuff, the heart of the driver
+ */
+
+struct sound_queue {
+ /* buffers allocated for this queue */
+ int numBufs;
+ int bufSize; /* in bytes */
+ char **buffers;
+
+ /* current parameters */
+ int max_count;
+ int block_size; /* in bytes */
+ int max_active;
+
+ /* it shouldn't be necessary to declare any of these volatile */
+ int front, rear, count;
+ int rear_size;
+ /*
+ * The use of the playing field depends on the hardware
+ *
+ * Atari, PMac: The number of frames that are loaded/playing
+ *
+ * Amiga: Bit 0 is set: a frame is loaded
+ * Bit 1 is set: a frame is playing
+ */
+ int active;
+ wait_queue_head_t action_queue, open_queue, sync_queue;
+ int open_mode;
+ int busy, syncing;
+};
+
+#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ)
+#define WAKE_UP(queue) (wake_up_interruptible(&queue))
+
+extern struct sound_queue dmasound_write_sq;
+extern struct sound_queue dmasound_read_sq;
+
+#define write_sq dmasound_write_sq
+#define read_sq dmasound_read_sq
+
+extern int dmasound_catchRadius;
+
+#define catchRadius dmasound_catchRadius
+
diff --git a/drivers/sound/dmasound/dmasound_atari.c b/drivers/sound/dmasound/dmasound_atari.c
new file mode 100644
index 000000000..ca6f07cbb
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_atari.c
@@ -0,0 +1,1560 @@
+
+/*
+ * linux/drivers/sound/dmasound_atari.c
+ *
+ * Atari DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/soundcard.h>
+#include <linux/mm.h>
+
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/atariints.h>
+#include <asm/atari_stram.h>
+
+#include "dmasound.h"
+
+
+extern void atari_microwire_cmd(int cmd);
+
+
+static int is_falcon;
+static int write_sq_ignore_int = 0; /* ++TeSche: used for Falcon */
+
+static int expand_bal; /* Balance factor for expanding (not volume!) */
+static int expand_data; /* Data for expanding */
+
+
+/*** Translations ************************************************************/
+
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void AtaOpen(void);
+static void AtaRelease(void);
+static void *AtaAlloc(unsigned int size, int flags);
+static void AtaFree(void *, unsigned int size);
+static int AtaIrqInit(void);
+#ifdef MODULE
+static void AtaIrqCleanUp(void);
+#endif /* MODULE */
+static int AtaSetBass(int bass);
+static int AtaSetTreble(int treble);
+static void TTSilence(void);
+static void TTInit(void);
+static int TTSetFormat(int format);
+static int TTSetVolume(int volume);
+static int TTSetGain(int gain);
+static void FalconSilence(void);
+static void FalconInit(void);
+static int FalconSetFormat(int format);
+static int FalconSetVolume(int volume);
+static void AtaPlayNextFrame(int index);
+static void AtaPlay(void);
+static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp);
+
+/*** Mid level stuff *********************************************************/
+
+static void TTMixerInit(void);
+static void FalconMixerInit(void);
+static int AtaMixerIoctl(u_int cmd, u_long arg);
+static int TTMixerIoctl(u_int cmd, u_long arg);
+static int FalconMixerIoctl(u_int cmd, u_long arg);
+static void AtaWriteSqSetup(void);
+static void AtaSqOpen(void);
+static int TTStateInfo(char *buffer);
+static int FalconStateInfo(char *buffer);
+
+
+/*** Translations ************************************************************/
+
+
+static ssize_t ata_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
+ : dmasound_alaw2dma8;
+ ssize_t count, used;
+ u_char *p = &frame[*frameUsed];
+
+ count = min(userCount, frameLeft);
+ if (dmasound.soft.stereo)
+ count &= ~1;
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = table[data];
+ count--;
+ }
+ *frameUsed += used;
+ return used;
+}
+
+
+static ssize_t ata_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ void *p = &frame[*frameUsed];
+
+ count = min(userCount, frameLeft);
+ if (dmasound.soft.stereo)
+ count &= ~1;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ *frameUsed += used;
+ return used;
+}
+
+
+static ssize_t ata_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft);
+ used = count;
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ *p++ = data ^ 0x80;
+ count--;
+ }
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *p++ = data ^ 0x8080;
+ count--;
+ }
+ }
+ *frameUsed += used;
+ return used;
+}
+
+
+static ssize_t ata_ct_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ void *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~3;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ct_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count*4;
+ while (count > 0) {
+ u_long data;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ *p++ = data ^ 0x80008000;
+ count--;
+ }
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ct_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ count = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ *p++ = data;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count*4;
+ while (count > 0) {
+ u_long data;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data);
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ct_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ count = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>1;
+ used = count*2;
+ while (count > 0) {
+ u_short data;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ *p++ = data;
+ *p++ = data;
+ }
+ *frameUsed += used*2;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ count = min(userCount, frameLeft)>>2;
+ used = count;
+ while (count > 0) {
+ u_long data;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data) ^ 0x80008000;
+ *p++ = data;
+ count--;
+ }
+ *frameUsed += used;
+ }
+ return used;
+}
+
+
+static ssize_t ata_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8
+ : dmasound_alaw2dma8;
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ u_char data = expand_data;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 2) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c] << 8;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data |= table[c];
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ u_char data = expand_data;
+ while (frameLeft) {
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 2) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_char *p = &frame[*frameUsed];
+ u_char data = expand_data;
+ while (frameLeft) {
+ if (bal < 0) {
+ if (!userCount)
+ break;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ data ^= 0x80;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 2) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8080;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 2;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_s16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_u16be(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x8000;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data ^= 0x80008000;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_s16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data);
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data);
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static ssize_t ata_ctx_u16le(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ /* this should help gcc to stuff everything into registers */
+ long bal = expand_bal;
+ long hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ ssize_t used, usedf;
+
+ used = userCount;
+ usedf = frameLeft;
+ if (!dmasound.soft.stereo) {
+ u_short *p = (u_short *)&frame[*frameUsed];
+ u_short data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 2)
+ break;
+ if (get_user(data, ((u_short *)userPtr)++))
+ return -EFAULT;
+ data = le2be16(data) ^ 0x8000;
+ userCount -= 2;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ } else {
+ u_long *p = (u_long *)&frame[*frameUsed];
+ u_long data = expand_data;
+ while (frameLeft >= 4) {
+ if (bal < 0) {
+ if (userCount < 4)
+ break;
+ if (get_user(data, ((u_int *)userPtr)++))
+ return -EFAULT;
+ data = le2be16dbl(data) ^ 0x80008000;
+ userCount -= 4;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft -= 4;
+ bal -= sSpeed;
+ }
+ expand_data = data;
+ }
+ expand_bal = bal;
+ used -= userCount;
+ *frameUsed += usedf-frameLeft;
+ return used;
+}
+
+
+static TRANS transTTNormal = {
+ ct_ulaw: ata_ct_law,
+ ct_alaw: ata_ct_law,
+ ct_s8: ata_ct_s8,
+ ct_u8: ata_ct_u8,
+};
+
+static TRANS transTTExpanding = {
+ ct_ulaw: ata_ctx_law,
+ ct_alaw: ata_ctx_law,
+ ct_s8: ata_ctx_s8,
+ ct_u8: ata_ctx_u8,
+};
+
+static TRANS transFalconNormal = {
+ ct_ulaw: ata_ct_law,
+ ct_alaw: ata_ct_law,
+ ct_s8: ata_ct_s8,
+ ct_u8: ata_ct_u8,
+ ct_s16be: ata_ct_s16be,
+ ct_u16be: ata_ct_u16be,
+ ct_s16le: ata_ct_s16le,
+ ct_u16le: ata_ct_u16le
+};
+
+static TRANS transFalconExpanding = {
+ ct_ulaw: ata_ctx_law,
+ ct_alaw: ata_ctx_law,
+ ct_s8: ata_ctx_s8,
+ ct_u8: ata_ctx_u8,
+ ct_s16be: ata_ctx_s16be,
+ ct_u16be: ata_ctx_u16be,
+ ct_s16le: ata_ctx_s16le,
+ ct_u16le: ata_ctx_u16le,
+};
+
+
+/*** Low level stuff *********************************************************/
+
+
+
+/*
+ * Atari (TT/Falcon)
+ */
+
+static void AtaOpen(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void AtaRelease(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static void *AtaAlloc(unsigned int size, int flags)
+{
+ return atari_stram_alloc( size, NULL, "dmasound" );
+}
+
+static void AtaFree(void *obj, unsigned int size)
+{
+ atari_stram_free( obj );
+}
+
+static int __init AtaIrqInit(void)
+{
+ /* Set up timer A. Timer A
+ will receive a signal upon end of playing from the sound
+ hardware. Furthermore Timer A is able to count events
+ and will cause an interrupt after a programmed number
+ of events. So all we need to keep the music playing is
+ to provide the sound hardware with new data upon
+ an interrupt from timer A. */
+ mfp.tim_ct_a = 0; /* ++roman: Stop timer before programming! */
+ mfp.tim_dt_a = 1; /* Cause interrupt after first event. */
+ mfp.tim_ct_a = 8; /* Turn on event counting. */
+ /* Register interrupt handler. */
+ request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
+ AtaInterrupt);
+ mfp.int_en_a |= 0x20; /* Turn interrupt on. */
+ mfp.int_mk_a |= 0x20;
+ return 1;
+}
+
+#ifdef MODULE
+static void AtaIrqCleanUp(void)
+{
+ mfp.tim_ct_a = 0; /* stop timer */
+ mfp.int_en_a &= ~0x20; /* turn interrupt off */
+ free_irq(IRQ_MFP_TIMA, AtaInterrupt);
+}
+#endif /* MODULE */
+
+
+#define TONE_VOXWARE_TO_DB(v) \
+ (((v) < 0) ? -12 : ((v) > 100) ? 12 : ((v) - 50) * 6 / 25)
+#define TONE_DB_TO_VOXWARE(v) (((v) * 25 + ((v) > 0 ? 5 : -5)) / 6 + 50)
+
+
+static int AtaSetBass(int bass)
+{
+ dmasound.bass = TONE_VOXWARE_TO_DB(bass);
+ atari_microwire_cmd(MW_LM1992_BASS(dmasound.bass));
+ return TONE_DB_TO_VOXWARE(dmasound.bass);
+}
+
+
+static int AtaSetTreble(int treble)
+{
+ dmasound.treble = TONE_VOXWARE_TO_DB(treble);
+ atari_microwire_cmd(MW_LM1992_TREBLE(dmasound.treble));
+ return TONE_DB_TO_VOXWARE(dmasound.treble);
+}
+
+
+
+/*
+ * TT
+ */
+
+
+static void TTSilence(void)
+{
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ atari_microwire_cmd(MW_LM1992_PSG_HIGH); /* mix in PSG signal 1:1 */
+}
+
+
+static void TTInit(void)
+{
+ int mode, i, idx;
+ const int freq[4] = {50066, 25033, 12517, 6258};
+
+ /* search a frequency that fits into the allowed error range */
+
+ idx = -1;
+ for (i = 0; i < arraysize(freq); i++)
+ /* this isn't as much useful for a TT than for a Falcon, but
+ * then it doesn't hurt very much to implement it for a TT too.
+ */
+ if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+ idx = i;
+ if (idx > -1) {
+ dmasound.soft.speed = freq[idx];
+ dmasound.trans_write = &transTTNormal;
+ } else
+ dmasound.trans_write = &transTTExpanding;
+
+ TTSilence();
+ dmasound.hard = dmasound.soft;
+
+ if (dmasound.hard.speed > 50066) {
+ /* we would need to squeeze the sound, but we won't do that */
+ dmasound.hard.speed = 50066;
+ mode = DMASND_MODE_50KHZ;
+ dmasound.trans_write = &transTTNormal;
+ } else if (dmasound.hard.speed > 25033) {
+ dmasound.hard.speed = 50066;
+ mode = DMASND_MODE_50KHZ;
+ } else if (dmasound.hard.speed > 12517) {
+ dmasound.hard.speed = 25033;
+ mode = DMASND_MODE_25KHZ;
+ } else if (dmasound.hard.speed > 6258) {
+ dmasound.hard.speed = 12517;
+ mode = DMASND_MODE_12KHZ;
+ } else {
+ dmasound.hard.speed = 6258;
+ mode = DMASND_MODE_6KHZ;
+ }
+
+ tt_dmasnd.mode = (dmasound.hard.stereo ?
+ DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+ DMASND_MODE_8BIT | mode;
+
+ expand_bal = -dmasound.soft.speed;
+}
+
+
+static int TTSetFormat(int format)
+{
+ /* TT sound DMA supports only 8bit modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_S8:
+ case AFMT_U8:
+ break;
+ default:
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = 8;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = 8;
+ }
+ TTInit();
+
+ return format;
+}
+
+
+#define VOLUME_VOXWARE_TO_DB(v) \
+ (((v) < 0) ? -40 : ((v) > 100) ? 0 : ((v) * 2) / 5 - 40)
+#define VOLUME_DB_TO_VOXWARE(v) ((((v) + 40) * 5 + 1) / 2)
+
+
+static int TTSetVolume(int volume)
+{
+ dmasound.volume_left = VOLUME_VOXWARE_TO_DB(volume & 0xff);
+ atari_microwire_cmd(MW_LM1992_BALLEFT(dmasound.volume_left));
+ dmasound.volume_right = VOLUME_VOXWARE_TO_DB((volume & 0xff00) >> 8);
+ atari_microwire_cmd(MW_LM1992_BALRIGHT(dmasound.volume_right));
+ return VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
+ (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8);
+}
+
+
+#define GAIN_VOXWARE_TO_DB(v) \
+ (((v) < 0) ? -80 : ((v) > 100) ? 0 : ((v) * 4) / 5 - 80)
+#define GAIN_DB_TO_VOXWARE(v) ((((v) + 80) * 5 + 1) / 4)
+
+static int TTSetGain(int gain)
+{
+ dmasound.gain = GAIN_VOXWARE_TO_DB(gain);
+ atari_microwire_cmd(MW_LM1992_VOLUME(dmasound.gain));
+ return GAIN_DB_TO_VOXWARE(dmasound.gain);
+}
+
+
+
+/*
+ * Falcon
+ */
+
+
+static void FalconSilence(void)
+{
+ /* stop playback, set sample rate 50kHz for PSG sound */
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ tt_dmasnd.mode = DMASND_MODE_50KHZ | DMASND_MODE_STEREO | DMASND_MODE_8BIT;
+ tt_dmasnd.int_div = 0; /* STE compatible divider */
+ tt_dmasnd.int_ctrl = 0x0;
+ tt_dmasnd.cbar_src = 0x0000; /* no matrix inputs */
+ tt_dmasnd.cbar_dst = 0x0000; /* no matrix outputs */
+ tt_dmasnd.dac_src = 1; /* connect ADC to DAC, disconnect matrix */
+ tt_dmasnd.adc_src = 3; /* ADC Input = PSG */
+}
+
+
+static void FalconInit(void)
+{
+ int divider, i, idx;
+ const int freq[8] = {49170, 32780, 24585, 19668, 16390, 12292, 9834, 8195};
+
+ /* search a frequency that fits into the allowed error range */
+
+ idx = -1;
+ for (i = 0; i < arraysize(freq); i++)
+ /* if we will tolerate 3% error 8000Hz->8195Hz (2.38%) would
+ * be playable without expanding, but that now a kernel runtime
+ * option
+ */
+ if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) < catchRadius)
+ idx = i;
+ if (idx > -1) {
+ dmasound.soft.speed = freq[idx];
+ dmasound.trans_write = &transFalconNormal;
+ } else
+ dmasound.trans_write = &transFalconExpanding;
+
+ FalconSilence();
+ dmasound.hard = dmasound.soft;
+
+ if (dmasound.hard.size == 16) {
+ /* the Falcon can play 16bit samples only in stereo */
+ dmasound.hard.stereo = 1;
+ }
+
+ if (dmasound.hard.speed > 49170) {
+ /* we would need to squeeze the sound, but we won't do that */
+ dmasound.hard.speed = 49170;
+ divider = 1;
+ dmasound.trans_write = &transFalconNormal;
+ } else if (dmasound.hard.speed > 32780) {
+ dmasound.hard.speed = 49170;
+ divider = 1;
+ } else if (dmasound.hard.speed > 24585) {
+ dmasound.hard.speed = 32780;
+ divider = 2;
+ } else if (dmasound.hard.speed > 19668) {
+ dmasound.hard.speed = 24585;
+ divider = 3;
+ } else if (dmasound.hard.speed > 16390) {
+ dmasound.hard.speed = 19668;
+ divider = 4;
+ } else if (dmasound.hard.speed > 12292) {
+ dmasound.hard.speed = 16390;
+ divider = 5;
+ } else if (dmasound.hard.speed > 9834) {
+ dmasound.hard.speed = 12292;
+ divider = 7;
+ } else if (dmasound.hard.speed > 8195) {
+ dmasound.hard.speed = 9834;
+ divider = 9;
+ } else {
+ dmasound.hard.speed = 8195;
+ divider = 11;
+ }
+ tt_dmasnd.int_div = divider;
+
+ /* Setup Falcon sound DMA for playback */
+ tt_dmasnd.int_ctrl = 0x4; /* Timer A int at play end */
+ tt_dmasnd.track_select = 0x0; /* play 1 track, track 1 */
+ tt_dmasnd.cbar_src = 0x0001; /* DMA(25MHz) --> DAC */
+ tt_dmasnd.cbar_dst = 0x0000;
+ tt_dmasnd.rec_track_select = 0;
+ tt_dmasnd.dac_src = 2; /* connect matrix to DAC */
+ tt_dmasnd.adc_src = 0; /* ADC Input = Mic */
+
+ tt_dmasnd.mode = (dmasound.hard.stereo ?
+ DMASND_MODE_STEREO : DMASND_MODE_MONO) |
+ ((dmasound.hard.size == 8) ?
+ DMASND_MODE_8BIT : DMASND_MODE_16BIT) |
+ DMASND_MODE_6KHZ;
+
+ expand_bal = -dmasound.soft.speed;
+}
+
+
+static int FalconSetFormat(int format)
+{
+ int size;
+ /* Falcon sound DMA supports 8bit and 16bit modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ size = 8;
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = size;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = dmasound.soft.size;
+ }
+
+ FalconInit();
+
+ return format;
+}
+
+
+/* This is for the Falcon output *attenuation* in 1.5dB steps,
+ * i.e. output level from 0 to -22.5dB in -1.5dB steps.
+ */
+#define VOLUME_VOXWARE_TO_ATT(v) \
+ ((v) < 0 ? 15 : (v) > 100 ? 0 : 15 - (v) * 3 / 20)
+#define VOLUME_ATT_TO_VOXWARE(v) (100 - (v) * 20 / 3)
+
+
+static int FalconSetVolume(int volume)
+{
+ dmasound.volume_left = VOLUME_VOXWARE_TO_ATT(volume & 0xff);
+ dmasound.volume_right = VOLUME_VOXWARE_TO_ATT((volume & 0xff00) >> 8);
+ tt_dmasnd.output_atten = dmasound.volume_left << 8 | dmasound.volume_right << 4;
+ return VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
+ VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8;
+}
+
+
+static void AtaPlayNextFrame(int index)
+{
+ char *start, *end;
+
+ /* used by AtaPlay() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = write_sq.buffers[write_sq.front];
+ end = start+((write_sq.count == index) ? write_sq.rear_size
+ : write_sq.block_size);
+ /* end might not be a legal virtual address. */
+ DMASNDSetEnd(virt_to_phys(end - 1) + 1);
+ DMASNDSetBase(virt_to_phys(start));
+ /* Since only an even number of samples per frame can
+ be played, we might lose one byte here. (TO DO) */
+ write_sq.front = (write_sq.front+1) % write_sq.max_count;
+ write_sq.active++;
+ tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
+}
+
+
+static void AtaPlay(void)
+{
+ /* ++TeSche: Note that write_sq.active is no longer just a flag but
+ * holds the number of frames the DMA is currently programmed for
+ * instead, may be 0, 1 (currently being played) or 2 (pre-programmed).
+ *
+ * Changes done to write_sq.count and write_sq.active are a bit more
+ * subtle again so now I must admit I also prefer disabling the irq
+ * here rather than considering all possible situations. But the point
+ * is that disabling the irq doesn't have any bad influence on this
+ * version of the driver as we benefit from having pre-programmed the
+ * DMA wherever possible: There's no need to reload the DMA at the
+ * exact time of an interrupt but only at some time while the
+ * pre-programmed frame is playing!
+ */
+ atari_disable_irq(IRQ_MFP_TIMA);
+
+ if (write_sq.active == 2 || /* DMA is 'full' */
+ write_sq.count <= 0) { /* nothing to do */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+
+ if (write_sq.active == 0) {
+ /* looks like there's nothing 'in' the DMA yet, so try
+ * to put two frames into it (at least one is available).
+ */
+ if (write_sq.count == 1 &&
+ write_sq.rear_size < write_sq.block_size &&
+ !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ AtaPlayNextFrame(1);
+ if (write_sq.count == 1) {
+ /* no more frames */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ if (write_sq.count == 2 &&
+ write_sq.rear_size < write_sq.block_size &&
+ !write_sq.syncing) {
+ /* hmmm, there were two frames, but the second
+ * one is not yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ AtaPlayNextFrame(2);
+ } else {
+ /* there's already a frame being played so we may only stuff
+ * one new into the DMA, but even if this may be the last
+ * frame existing the previous one is still on write_sq.count.
+ */
+ if (write_sq.count == 2 &&
+ write_sq.rear_size < write_sq.block_size &&
+ !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ atari_enable_irq(IRQ_MFP_TIMA);
+ return;
+ }
+ AtaPlayNextFrame(2);
+ }
+ atari_enable_irq(IRQ_MFP_TIMA);
+}
+
+
+static void AtaInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+#if 0
+ /* ++TeSche: if you should want to test this... */
+ static int cnt = 0;
+ if (write_sq.active == 2)
+ if (++cnt == 10) {
+ /* simulate losing an interrupt */
+ cnt = 0;
+ return;
+ }
+#endif
+
+ if (write_sq_ignore_int && is_falcon) {
+ /* ++TeSche: Falcon only: ignore first irq because it comes
+ * immediately after starting a frame. after that, irqs come
+ * (almost) like on the TT.
+ */
+ write_sq_ignore_int = 0;
+ return;
+ }
+
+ if (!write_sq.active) {
+ /* playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(write_sq.sync_queue);
+ return;
+ }
+
+ /* Probably ;) one frame is finished. Well, in fact it may be that a
+ * pre-programmed one is also finished because there has been a long
+ * delay in interrupt delivery and we've completely lost one, but
+ * there's no way to detect such a situation. In such a case the last
+ * frame will be played more than once and the situation will recover
+ * as soon as the irq gets through.
+ */
+ write_sq.count--;
+ write_sq.active--;
+
+ if (!write_sq.active) {
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+ write_sq_ignore_int = 1;
+ }
+
+ WAKE_UP(write_sq.action_queue);
+ /* At least one block of the queue is free now
+ so wake up a writing process blocked because
+ of a full queue. */
+
+ if ((write_sq.active != 1) || (write_sq.count != 1))
+ /* We must be a bit carefully here: write_sq.count indicates the
+ * number of buffers used and not the number of frames to be
+ * played. If write_sq.count==1 and write_sq.active==1 that
+ * means the only remaining frame was already programmed
+ * earlier (and is currently running) so we mustn't call
+ * AtaPlay() here, otherwise we'll play one frame too much.
+ */
+ AtaPlay();
+
+ if (!write_sq.active) WAKE_UP(write_sq.sync_queue);
+ /* We are not playing after AtaPlay(), so there
+ is nothing to play any more. Wake up a process
+ waiting for audio output to drain. */
+}
+
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+#define RECLEVEL_VOXWARE_TO_GAIN(v) \
+ ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
+#define RECLEVEL_GAIN_TO_VOXWARE(v) (((v) * 20 + 2) / 3)
+
+
+static void __init TTMixerInit(void)
+{
+ atari_microwire_cmd(MW_LM1992_VOLUME(0));
+ dmasound.volume_left = 0;
+ atari_microwire_cmd(MW_LM1992_BALLEFT(0));
+ dmasound.volume_right = 0;
+ atari_microwire_cmd(MW_LM1992_BALRIGHT(0));
+ atari_microwire_cmd(MW_LM1992_TREBLE(0));
+ atari_microwire_cmd(MW_LM1992_BASS(0));
+}
+
+static void __init FalconMixerInit(void)
+{
+ dmasound.volume_left = (tt_dmasnd.output_atten & 0xf00) >> 8;
+ dmasound.volume_right = (tt_dmasnd.output_atten & 0xf0) >> 4;
+}
+
+static int AtaMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_SPEAKER:
+ if (is_falcon || MACH_IS_TT) {
+ int porta;
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = sound_ym.rd_data_reg_sel;
+ sti();
+ return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+ }
+ break;
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_volume(data));
+ case SOUND_MIXER_WRITE_SPEAKER:
+ if (is_falcon || MACH_IS_TT) {
+ int porta;
+ IOCTL_IN(arg, data);
+ cli();
+ sound_ym.rd_data_reg_sel = 14;
+ porta = (sound_ym.rd_data_reg_sel & ~0x40) |
+ (data < 50 ? 0x40 : 0);
+ sound_ym.wd_data = porta;
+ sti();
+ return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
+ }
+ }
+ return -EINVAL;
+}
+
+
+static int TTMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_RECMASK:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_READ_DEVMASK:
+ return IOCTL_OUT(arg,
+ SOUND_MASK_VOLUME | SOUND_MASK_TREBLE | SOUND_MASK_BASS |
+ (MACH_IS_TT ? SOUND_MASK_SPEAKER : 0));
+ case SOUND_MIXER_READ_STEREODEVS:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg,
+ VOLUME_DB_TO_VOXWARE(dmasound.volume_left) |
+ (VOLUME_DB_TO_VOXWARE(dmasound.volume_right) << 8));
+ case SOUND_MIXER_READ_BASS:
+ return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.bass));
+ case SOUND_MIXER_READ_TREBLE:
+ return IOCTL_OUT(arg, TONE_DB_TO_VOXWARE(dmasound.treble));
+ case SOUND_MIXER_READ_OGAIN:
+ return IOCTL_OUT(arg, GAIN_DB_TO_VOXWARE(dmasound.gain));
+ case SOUND_MIXER_WRITE_BASS:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_bass(data));
+ case SOUND_MIXER_WRITE_TREBLE:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_treble(data));
+ case SOUND_MIXER_WRITE_OGAIN:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_gain(data));
+ }
+ return AtaMixerIoctl(cmd, arg);
+}
+
+static int FalconMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_RECMASK:
+ return IOCTL_OUT(arg, SOUND_MASK_MIC);
+ case SOUND_MIXER_READ_DEVMASK:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_SPEAKER);
+ case SOUND_MIXER_READ_STEREODEVS:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC);
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg,
+ VOLUME_ATT_TO_VOXWARE(dmasound.volume_left) |
+ VOLUME_ATT_TO_VOXWARE(dmasound.volume_right) << 8);
+ case SOUND_MIXER_READ_CAPS:
+ return IOCTL_OUT(arg, SOUND_CAP_EXCL_INPUT);
+ case SOUND_MIXER_WRITE_MIC:
+ IOCTL_IN(arg, data);
+ tt_dmasnd.input_gain =
+ RECLEVEL_VOXWARE_TO_GAIN(data & 0xff) << 4 |
+ RECLEVEL_VOXWARE_TO_GAIN(data >> 8 & 0xff);
+ /* fall thru, return set value */
+ case SOUND_MIXER_READ_MIC:
+ return IOCTL_OUT(arg,
+ RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain >> 4 & 0xf) |
+ RECLEVEL_GAIN_TO_VOXWARE(tt_dmasnd.input_gain & 0xf) << 8);
+ }
+ return AtaMixerIoctl(cmd, arg);
+}
+
+static void AtaWriteSqSetup(void)
+{
+ write_sq_ignore_int = 0;
+}
+
+static void AtaSqOpen(void)
+{
+ write_sq_ignore_int = 1;
+}
+
+static int TTStateInfo(char *buffer)
+{
+ int len = 0;
+ len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-40...0]\n",
+ dmasound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-40...0]\n",
+ dmasound.volume_right);
+ len += sprintf(buffer+len, "\tsound.bass = %ddB [-12...+12]\n",
+ dmasound.bass);
+ len += sprintf(buffer+len, "\tsound.treble = %ddB [-12...+12]\n",
+ dmasound.treble);
+ return len;
+}
+
+static int FalconStateInfo(char *buffer)
+{
+ int len = 0;
+ len += sprintf(buffer+len, "\tsound.volume_left = %ddB [-22.5...0]\n",
+ dmasound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %ddB [-22.5...0]\n",
+ dmasound.volume_right);
+ return len;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machTT = {
+ name: "Atari",
+ name2: "TT",
+ open: AtaOpen,
+ release: AtaRelease,
+ dma_alloc: AtaAlloc,
+ dma_free: AtaFree,
+ irqinit: AtaIrqInit,
+#ifdef MODULE
+ irqcleanup: AtaIrqCleanUp,
+#endif /* MODULE */
+ init: TTInit,
+ silence: TTSilence,
+ setFormat: TTSetFormat,
+ setVolume: TTSetVolume,
+ setBass: AtaSetBass,
+ setTreble: AtaSetTreble,
+ setGain: TTSetGain,
+ play: AtaPlay,
+ mixer_init: TTMixerInit,
+ mixer_ioctl: TTMixerIoctl,
+ write_sq_setup: AtaWriteSqSetup,
+ sq_open: AtaSqOpen,
+ state_info: TTStateInfo,
+ min_dsp_speed: 6258,
+};
+
+static MACHINE machFalcon = {
+ name: "Atari",
+ name2: "FALCON",
+ dma_alloc: AtaAlloc,
+ dma_free: AtaFree,
+ irqinit: AtaIrqInit,
+#ifdef MODULE
+ irqcleanup: AtaIrqCleanUp,
+#endif /* MODULE */
+ init: FalconInit,
+ silence: FalconSilence,
+ setFormat: FalconSetFormat,
+ setVolume: FalconSetVolume,
+ setBass: AtaSetBass,
+ setTreble: AtaSetTreble,
+ play: AtaPlay,
+ mixer_init: FalconMixerInit,
+ mixer_ioctl: FalconMixerIoctl,
+ write_sq_setup: AtaWriteSqSetup,
+ sq_open: AtaSqOpen,
+ state_info: FalconStateInfo,
+ min_dsp_speed: 8195,
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+static int __init dmasound_atari_init(void)
+{
+ if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) {
+ if (ATARIHW_PRESENT(CODEC)) {
+ dmasound.mach = machFalcon;
+ is_falcon = 1;
+ } else if (ATARIHW_PRESENT(MICROWIRE)) {
+ dmasound.mach = machTT;
+ is_falcon = 0;
+ } else
+ return -ENODEV;
+ if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+ return dmasound_init();
+ else {
+ printk("DMA sound driver: Timer A interrupt already in use\n");
+ return -EBUSY;
+ }
+ }
+ return -ENODEV;
+}
+
+static void __exit dmasound_atari_cleanup(void)
+{
+ dmasound_deinit();
+}
+
+module_init(dmasound_atari_init);
+module_exit(dmasound_atari_cleanup);
diff --git a/drivers/sound/dmasound/dmasound_awacs.c b/drivers/sound/dmasound/dmasound_awacs.c
new file mode 100644
index 000000000..55669c65c
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_awacs.c
@@ -0,0 +1,2113 @@
+
+/*
+ * linux/drivers/sound/dmasound_awacs.c
+ *
+ * PowerMac DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/soundcard.h>
+#include <linux/adb.h>
+#include <linux/nvram.h>
+#include <linux/vt_kern.h>
+#include <linux/cuda.h>
+
+#include <asm/uaccess.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+
+#include "awacs_defs.h"
+#include "dmasound.h"
+
+
+/*
+ * Interrupt numbers and addresses, obtained from the device tree.
+ */
+static int awacs_irq, awacs_tx_irq, awacs_rx_irq;
+static volatile struct awacs_regs *awacs;
+static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma;
+static int awacs_rate_index;
+static int awacs_subframe;
+static int awacs_spkr_vol;
+static struct device_node* awacs_node;
+
+static char awacs_name[64];
+static int awacs_revision;
+#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
+
+/*
+ * Space for the DBDMA command blocks.
+ */
+static void *awacs_tx_cmd_space;
+static volatile struct dbdma_cmd *awacs_tx_cmds;
+
+static void *awacs_rx_cmd_space;
+static volatile struct dbdma_cmd *awacs_rx_cmds;
+
+/*
+ * Cached values of AWACS registers (we can't read them).
+ * Except on the burgundy. XXX
+ */
+int awacs_reg[5];
+
+#define HAS_16BIT_TABLES
+#undef HAS_8BIT_TABLES
+
+/*
+ * Stuff for outputting a beep. The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+ 0, 40, 79, 117, 153, 187, 218, 245,
+ 269, 288, 304, 316, 323, 327, 327, 324,
+ 318, 310, 299, 288, 275, 262, 249, 236,
+ 224, 213, 204, 196, 190, 186, 183, 182,
+ 182, 183, 186, 189, 192, 196, 200, 203,
+ 206, 208, 209, 209, 209, 207, 204, 201,
+ 197, 193, 188, 183, 179, 174, 170, 166,
+ 163, 161, 160, 159, 159, 160, 161, 162,
+ 164, 166, 168, 169, 171, 171, 171, 170,
+ 169, 167, 163, 159, 155, 150, 144, 139,
+ 133, 128, 122, 117, 113, 110, 107, 105,
+ 103, 103, 103, 103, 104, 104, 105, 105,
+ 105, 103, 101, 97, 92, 86, 78, 68,
+ 58, 45, 32, 18, 3, -11, -26, -41,
+ -55, -68, -79, -88, -95, -100, -102, -102,
+ -99, -93, -85, -75, -62, -48, -33, -16,
+ 0, 16, 33, 48, 62, 75, 85, 93,
+ 99, 102, 102, 100, 95, 88, 79, 68,
+ 55, 41, 26, 11, -3, -18, -32, -45,
+ -58, -68, -78, -86, -92, -97, -101, -103,
+ -105, -105, -105, -104, -104, -103, -103, -103,
+ -103, -105, -107, -110, -113, -117, -122, -128,
+ -133, -139, -144, -150, -155, -159, -163, -167,
+ -169, -170, -171, -171, -171, -169, -168, -166,
+ -164, -162, -161, -160, -159, -159, -160, -161,
+ -163, -166, -170, -174, -179, -183, -188, -193,
+ -197, -201, -204, -207, -209, -209, -209, -208,
+ -206, -203, -200, -196, -192, -189, -186, -183,
+ -182, -182, -183, -186, -190, -196, -204, -213,
+ -224, -236, -249, -262, -275, -288, -299, -310,
+ -318, -324, -327, -327, -323, -316, -304, -288,
+ -269, -245, -218, -187, -153, -117, -79, -40,
+};
+
+#define BEEP_SRATE 22050 /* 22050 Hz sample rate */
+#define BEEP_BUFLEN 512
+#define BEEP_VOLUME 15 /* 0 - 100 */
+
+static int beep_volume = BEEP_VOLUME;
+static int beep_playing = 0;
+static int awacs_beep_state = 0;
+static short *beep_buf;
+static volatile struct dbdma_cmd *beep_dbdma_cmd;
+static void (*orig_mksound)(unsigned int, unsigned int);
+static int is_pbook_3400;
+static unsigned char *latch_base;
+static int is_pbook_G3;
+static unsigned char *macio_base;
+
+/* Burgundy functions */
+static void awacs_burgundy_wcw(unsigned addr,unsigned newval);
+static unsigned awacs_burgundy_rcw(unsigned addr);
+static void awacs_burgundy_write_volume(unsigned address, int volume);
+static int awacs_burgundy_read_volume(unsigned address);
+static void awacs_burgundy_write_mvolume(unsigned address, int volume);
+static int awacs_burgundy_read_mvolume(unsigned address);
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Stuff for restoring after a sleep.
+ */
+static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
+struct pmu_sleep_notifier awacs_sleep_notifier = {
+ awacs_sleep_notify, SLEEP_LEVEL_SOUND,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+static int expand_bal; /* Balance factor for expanding (not volume!) */
+static int expand_data; /* Data for expanding */
+
+
+/*** Translations ************************************************************/
+
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft);
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void PMacOpen(void);
+static void PMacRelease(void);
+static void *PMacAlloc(unsigned int size, int flags);
+static void PMacFree(void *ptr, unsigned int size);
+static int PMacIrqInit(void);
+#ifdef MODULE
+static void PMacIrqCleanup(void);
+#endif
+static void PMacSilence(void);
+static void PMacInit(void);
+static int PMacSetFormat(int format);
+static int PMacSetVolume(int volume);
+static void PMacPlay(void);
+static void PMacRecord(void);
+static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
+static void awacs_write(int val);
+static int awacs_get_volume(int reg, int lshift);
+static int awacs_volume_setter(int volume, int n, int mute, int lshift);
+static void awacs_mksound(unsigned int hz, unsigned int ticks);
+static void awacs_nosound(unsigned long xx);
+
+
+/*** Mid level stuff **********************************************************/
+
+
+static int PMacMixerIoctl(u_int cmd, u_long arg);
+static void PMacWriteSqSetup(void);
+static void PMacReadSqSetup(void);
+static void PMacAbortRead(void);
+
+
+/*** Translations ************************************************************/
+
+
+static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ short *table = dmasound.soft.format == AFMT_MU_LAW
+ ? dmasound_ulaw2dma16 : dmasound_alaw2dma16;
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data];
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data];
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data << 8;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data << 8;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = (data ^ 0x80) << 8;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = (data ^ 0x80) << 8;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ if (!stereo) {
+ short *up = (short *) userPtr;
+ while (count > 0) {
+ short data;
+ if (get_user(data, up++))
+ return -EFAULT;
+ *fp++ = data;
+ *fp++ = data;
+ count--;
+ }
+ } else {
+ if (copy_from_user(fp, userPtr, count * 4))
+ return -EFAULT;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+ short *up = (short *) userPtr;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ int data;
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ *fp++ = data;
+ if (stereo) {
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ }
+ *fp++ = data;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+
+static ssize_t pmac_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned short *table = (unsigned short *)
+ (dmasound.soft.format == AFMT_MU_LAW
+ ? dmasound_ulaw2dma16 : dmasound_alaw2dma16);
+ unsigned int data = expand_data;
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+ int stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + table[c];
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = c << 8;
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + (c << 8);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (c ^ 0x80) << 8;
+ if (stereo) {
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = (data << 16) + ((c ^ 0x80) << 8);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 2: utotal;
+}
+
+
+static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ unsigned short *up = (unsigned short *) userPtr;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ unsigned short c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(data, up++))
+ return -EFAULT;
+ if (stereo) {
+ if (get_user(c, up++))
+ return -EFAULT;
+ data = (data << 16) + c;
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 4: utotal * 2;
+}
+
+
+static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ unsigned int *p = (unsigned int *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ unsigned short *up = (unsigned short *) userPtr;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int stereo = dmasound.soft.stereo;
+ int utotal, ftotal;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ unsigned short c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(data, up++))
+ return -EFAULT;
+ data ^= mask;
+ if (stereo) {
+ if (get_user(c, up++))
+ return -EFAULT;
+ data = (data << 16) + (c ^ mask);
+ } else
+ data = (data << 16) + data;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) * 4;
+ utotal -= userCount;
+ return stereo? utotal * 4: utotal * 2;
+}
+
+static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+
+ val = *p++;
+ data = val >> 8;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ if (stereo) {
+ val = *p;
+ data = val >> 8;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ }
+ p++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ short *p = (short *) &frame[*frameUsed];
+ int val, stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 2;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+
+ val = *p++;
+ data = (val >> 8) ^ 0x80;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ if (stereo) {
+ val = *p;
+ data = (val >> 8) ^ 0x80;
+ if (put_user(data, (u_char *)userPtr++))
+ return -EFAULT;
+ }
+ p++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ if (!stereo) {
+ short *up = (short *) userPtr;
+ while (count > 0) {
+ short data;
+ data = *fp;
+ if (put_user(data, up++))
+ return -EFAULT;
+ fp+=2;
+ count--;
+ }
+ } else {
+ if (copy_to_user((u_char *)userPtr, fp, count * 4))
+ return -EFAULT;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ int mask = (dmasound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+ int stereo = dmasound.soft.stereo;
+ short *fp = (short *) &frame[*frameUsed];
+ short *up = (short *) userPtr;
+
+ frameLeft >>= 2;
+ userCount >>= (stereo? 2: 1);
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ int data;
+
+ data = *fp++;
+ data ^= mask;
+ if (put_user(data, up++))
+ return -EFAULT;
+ if (stereo) {
+ data = *fp;
+ data ^= mask;
+ if (put_user(data, up++))
+ return -EFAULT;
+ }
+ fp++;
+ count--;
+ }
+ *frameUsed += used * 4;
+ return stereo? used * 4: used * 2;
+}
+
+
+static TRANS transAwacsNormal = {
+ ct_ulaw: pmac_ct_law,
+ ct_alaw: pmac_ct_law,
+ ct_s8: pmac_ct_s8,
+ ct_u8: pmac_ct_u8,
+ ct_s16be: pmac_ct_s16,
+ ct_u16be: pmac_ct_u16,
+ ct_s16le: pmac_ct_s16,
+ ct_u16le: pmac_ct_u16,
+};
+
+static TRANS transAwacsExpand = {
+ ct_ulaw: pmac_ctx_law,
+ ct_alaw: pmac_ctx_law,
+ ct_s8: pmac_ctx_s8,
+ ct_u8: pmac_ctx_u8,
+ ct_s16be: pmac_ctx_s16,
+ ct_u16be: pmac_ctx_u16,
+ ct_s16le: pmac_ctx_s16,
+ ct_u16le: pmac_ctx_u16,
+};
+
+static TRANS transAwacsNormalRead = {
+ ct_s8: pmac_ct_s8_read,
+ ct_u8: pmac_ct_u8_read,
+ ct_s16be: pmac_ct_s16_read,
+ ct_u16be: pmac_ct_u16_read,
+ ct_s16le: pmac_ct_s16_read,
+ ct_u16le: pmac_ct_u16_read,
+};
+
+/*** Low level stuff *********************************************************/
+
+
+
+/*
+ * PCI PowerMac, with AWACS and DBDMA.
+ */
+
+static void PMacOpen(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void PMacRelease(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static void *PMacAlloc(unsigned int size, int flags)
+{
+ return kmalloc(size, flags);
+}
+
+static void PMacFree(void *ptr, unsigned int size)
+{
+ kfree(ptr);
+}
+
+static int __init PMacIrqInit(void)
+{
+ if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
+ || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
+ || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
+ return 0;
+ return 1;
+}
+
+#ifdef MODULE
+static void PMacIrqCleanup(void)
+{
+ /* turn off output dma */
+ out_le32(&awacs_txdma->control, RUN<<16);
+ /* disable interrupts from awacs interface */
+ out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
+#ifdef CONFIG_PMAC_PBOOK
+ if (is_pbook_G3) {
+ feature_clear(awacs_node, FEATURE_Sound_power);
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ }
+#endif
+ free_irq(awacs_irq, 0);
+ free_irq(awacs_tx_irq, 0);
+ free_irq(awacs_rx_irq, 0);
+ kfree(awacs_tx_cmd_space);
+ if (awacs_rx_cmd_space)
+ kfree(awacs_rx_cmd_space);
+ if (beep_buf)
+ kfree(beep_buf);
+ kd_mksound = orig_mksound;
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
+#endif
+}
+#endif /* MODULE */
+
+static void PMacSilence(void)
+{
+ /* turn off output dma */
+ out_le32(&awacs_txdma->control, RUN<<16);
+}
+
+static int awacs_freqs[8] = {
+ 44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
+};
+static int awacs_freqs_ok[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static void PMacInit(void)
+{
+ int i, tolerance;
+
+ switch (dmasound.soft.format) {
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ dmasound.hard.format = AFMT_S16_LE;
+ break;
+ default:
+ dmasound.hard.format = AFMT_S16_BE;
+ break;
+ }
+ dmasound.hard.stereo = 1;
+ dmasound.hard.size = 16;
+
+ /*
+ * If we have a sample rate which is within catchRadius percent
+ * of the requested value, we don't have to expand the samples.
+ * Otherwise choose the next higher rate.
+ * N.B.: burgundy awacs (iMac and later) only works at 44100 Hz.
+ */
+ i = 8;
+ do {
+ tolerance = catchRadius * awacs_freqs[--i] / 100;
+ if (awacs_freqs_ok[i]
+ && dmasound.soft.speed <= awacs_freqs[i] + tolerance)
+ break;
+ } while (i > 0);
+ if (dmasound.soft.speed >= awacs_freqs[i] - tolerance)
+ dmasound.trans_write = &transAwacsNormal;
+ else
+ dmasound.trans_write = &transAwacsExpand;
+ dmasound.trans_read = &transAwacsNormalRead;
+ dmasound.hard.speed = awacs_freqs[i];
+ awacs_rate_index = i;
+
+ /* XXX disable error interrupt on burgundy for now */
+ out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
+ | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
+ awacs_reg[1] = (awacs_reg[1] & ~MASK_SAMPLERATE) | (i << 3);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+
+ /* We really want to execute a DMA stop command, after the AWACS
+ * is initialized.
+ * For reasons I don't understand, it stops the hissing noise
+ * common to many PowerBook G3 systems (like mine :-).
+ */
+ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+ st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+ out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+
+ expand_bal = -dmasound.soft.speed;
+}
+
+static int PMacSetFormat(int format)
+{
+ int size;
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
+ format);
+ size = 8;
+ format = AFMT_U8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = size;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = size;
+ }
+
+ PMacInit();
+
+ return format;
+}
+
+#define AWACS_VOLUME_TO_MASK(x) (15 - ((((x) - 1) * 15) / 99))
+#define AWACS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 15))
+
+static int awacs_get_volume(int reg, int lshift)
+{
+ int volume;
+
+ volume = AWACS_MASK_TO_VOLUME((reg >> lshift) & 0xf);
+ volume |= AWACS_MASK_TO_VOLUME(reg & 0xf) << 8;
+ return volume;
+}
+
+static int awacs_volume_setter(int volume, int n, int mute, int lshift)
+{
+ int r1, rn;
+
+ if (mute && volume == 0) {
+ r1 = awacs_reg[1] | mute;
+ } else {
+ r1 = awacs_reg[1] & ~mute;
+ rn = awacs_reg[n] & ~(0xf | (0xf << lshift));
+ rn |= ((AWACS_VOLUME_TO_MASK(volume & 0xff) & 0xf) << lshift);
+ rn |= AWACS_VOLUME_TO_MASK((volume >> 8) & 0xff) & 0xf;
+ awacs_reg[n] = rn;
+ awacs_write((n << 12) | rn);
+ volume = awacs_get_volume(rn, lshift);
+ }
+ if (r1 != awacs_reg[1]) {
+ awacs_reg[1] = r1;
+ awacs_write(r1 | MASK_ADDR1);
+ }
+ return volume;
+}
+
+static int PMacSetVolume(int volume)
+{
+ return awacs_volume_setter(volume, 2, MASK_AMUTE, 6);
+}
+
+static void PMacPlay(void)
+{
+ volatile struct dbdma_cmd *cp;
+ int i, count;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (awacs_beep_state) {
+ /* sound takes precedence over beeps */
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (awacs_rate_index << 8));
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(write_sq.front+write_sq.active) % write_sq.max_count])));
+
+ beep_playing = 0;
+ awacs_beep_state = 0;
+ }
+ i = write_sq.front + write_sq.active;
+ if (i >= write_sq.max_count)
+ i -= write_sq.max_count;
+ while (write_sq.active < 2 && write_sq.active < write_sq.count) {
+ count = (write_sq.count == write_sq.active + 1)?write_sq.rear_size:write_sq.block_size;
+ if (count < write_sq.block_size && !write_sq.syncing)
+ /* last block not yet filled, and we're not syncing. */
+ break;
+ cp = &awacs_tx_cmds[i];
+ st_le16(&cp->req_count, count);
+ st_le16(&cp->xfer_status, 0);
+ if (++i >= write_sq.max_count)
+ i = 0;
+ out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
+ out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
+ if (write_sq.active == 0)
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
+ out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+ ++write_sq.active;
+ }
+ restore_flags(flags);
+}
+
+
+static void PMacRecord(void)
+{
+ unsigned long flags;
+
+ if (read_sq.active)
+ return;
+
+ save_flags(flags); cli();
+
+ /* This is all we have to do......Just start it up.
+ */
+ out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+ read_sq.active = 1;
+
+ restore_flags(flags);
+}
+
+
+static void
+pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ int i = write_sq.front;
+ int stat;
+ volatile struct dbdma_cmd *cp;
+
+ while (write_sq.active > 0) {
+ cp = &awacs_tx_cmds[i];
+ stat = ld_le16(&cp->xfer_status);
+ if ((stat & ACTIVE) == 0)
+ break; /* this frame is still going */
+ --write_sq.count;
+ --write_sq.active;
+ if (++i >= write_sq.max_count)
+ i = 0;
+ }
+ if (i != write_sq.front)
+ WAKE_UP(write_sq.action_queue);
+ write_sq.front = i;
+
+ PMacPlay();
+
+ if (!write_sq.active)
+ WAKE_UP(write_sq.sync_queue);
+}
+
+
+static void
+pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+
+ /* For some reason on my PowerBook G3, I get one interrupt
+ * when the interrupt vector is installed (like something is
+ * pending). This happens before the dbdma is initialize by
+ * us, so I just check the command pointer and if it is zero,
+ * just blow it off.
+ */
+ if (in_le32(&awacs_rxdma->cmdptr) == 0)
+ return;
+
+ /* We also want to blow 'em off when shutting down.
+ */
+ if (read_sq.active == 0)
+ return;
+
+ /* Check multiple buffers in case we were held off from
+ * interrupt processing for a long time. Geeze, I really hope
+ * this doesn't happen.
+ */
+ while (awacs_rx_cmds[read_sq.rear].xfer_status) {
+
+ /* Clear status and move on to next buffer.
+ */
+ awacs_rx_cmds[read_sq.rear].xfer_status = 0;
+ read_sq.rear++;
+
+ /* Wrap the buffer ring.
+ */
+ if (read_sq.rear >= read_sq.max_active)
+ read_sq.rear = 0;
+
+ /* If we have caught up to the front buffer, bump it.
+ * This will cause weird (but not fatal) results if the
+ * read loop is currently using this buffer. The user is
+ * behind in this case anyway, so weird things are going
+ * to happen.
+ */
+ if (read_sq.rear == read_sq.front) {
+ read_sq.front++;
+ if (read_sq.front >= read_sq.max_active)
+ read_sq.front = 0;
+ }
+ }
+
+ WAKE_UP(read_sq.action_queue);
+}
+
+
+static void
+pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
+{
+ int ctrl = in_le32(&awacs->control);
+
+ if (ctrl & MASK_PORTCHG) {
+ /* do something when headphone is plugged/unplugged? */
+ }
+ if (ctrl & MASK_CNTLERR) {
+ int err = (in_le32(&awacs->codec_stat) & MASK_ERRCODE) >> 16;
+ if (err != 0 && awacs_revision < AWACS_BURGUNDY)
+ printk(KERN_ERR "AWACS: error %x\n", err);
+ }
+ /* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
+ out_le32(&awacs->control, ctrl);
+}
+
+static void
+awacs_write(int val)
+{
+ if (awacs_revision >= AWACS_BURGUNDY)
+ return;
+ while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+ ; /* XXX should have timeout */
+ out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22));
+}
+
+static void awacs_nosound(unsigned long xx)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (beep_playing) {
+ st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (awacs_rate_index << 8));
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+ beep_playing = 0;
+ }
+ restore_flags(flags);
+}
+
+static struct timer_list beep_timer = {
+ NULL, NULL, 0, 0, awacs_nosound
+};
+
+static void awacs_mksound(unsigned int hz, unsigned int ticks)
+{
+ unsigned long flags;
+ int beep_speed = 0;
+ int srate;
+ int period, ncycles, nsamples;
+ int i, j, f;
+ short *p;
+ static int beep_hz_cache;
+ static int beep_nsamples_cache;
+ static int beep_volume_cache;
+
+ for (i = 0; i < 8 && awacs_freqs[i] >= BEEP_SRATE; ++i)
+ if (awacs_freqs_ok[i])
+ beep_speed = i;
+ srate = awacs_freqs[beep_speed];
+
+ if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
+#if 1
+ /* this is a hack for broken X server code */
+ hz = 750;
+ ticks = 12;
+#else
+ /* cancel beep currently playing */
+ awacs_nosound(0);
+ return;
+#endif
+ }
+ save_flags(flags); cli();
+ del_timer(&beep_timer);
+ if (ticks) {
+ beep_timer.expires = jiffies + ticks;
+ add_timer(&beep_timer);
+ }
+ if (beep_playing || write_sq.active || beep_buf == NULL) {
+ restore_flags(flags);
+ return; /* too hard, sorry :-( */
+ }
+ beep_playing = 1;
+ st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
+ restore_flags(flags);
+
+ if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
+ nsamples = beep_nsamples_cache;
+ } else {
+ period = srate * 256 / hz; /* fixed point */
+ ncycles = BEEP_BUFLEN * 256 / period;
+ nsamples = (period * ncycles) >> 8;
+ f = ncycles * 65536 / nsamples;
+ j = 0;
+ p = beep_buf;
+ for (i = 0; i < nsamples; ++i, p += 2) {
+ p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
+ j = (j + f) & 0xffff;
+ }
+ beep_hz_cache = hz;
+ beep_volume_cache = beep_volume;
+ beep_nsamples_cache = nsamples;
+ }
+
+ st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
+ st_le16(&beep_dbdma_cmd->xfer_status, 0);
+ st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
+ st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+ awacs_beep_state = 1;
+
+ save_flags(flags); cli();
+ if (beep_playing) { /* i.e. haven't been terminated already */
+ out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+ out_le32(&awacs->control,
+ (in_le32(&awacs->control) & ~0x1f00)
+ | (beep_speed << 8));
+ out_le32(&awacs->byteswap, 0);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+ out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+ }
+ restore_flags(flags);
+}
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * Save state when going to sleep, restore it afterwards.
+ */
+static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+ switch (when) {
+ case PBOOK_SLEEP_NOW:
+ /* XXX we should stop any dma in progress when going to sleep
+ and restart it when we wake. */
+ PMacSilence();
+ disable_irq(awacs_irq);
+ disable_irq(awacs_tx_irq);
+ if (is_pbook_G3) {
+ feature_clear(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_clear(awacs_node, FEATURE_Sound_power);
+ }
+ break;
+ case PBOOK_WAKE:
+ /* There is still a problem on wake. Sound seems to work fine
+ if I launch mpg123 and resumes fine if mpg123 was playing,
+ but the console beep is dead until I do something with the
+ mixer. Probably yet another timing issue */
+ if (!feature_test(awacs_node, FEATURE_Sound_CLK_enable)
+ || !feature_test(awacs_node, FEATURE_Sound_power)) {
+ /* these aren't present on the 3400 AFAIK -- paulus */
+ feature_set(awacs_node, FEATURE_Sound_CLK_enable);
+ feature_set(awacs_node, FEATURE_Sound_power);
+ mdelay(1000);
+ }
+ out_le32(&awacs->control, MASK_IEPC
+ | (awacs_rate_index << 8) | 0x11
+ | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ awacs_write(awacs_reg[2] | MASK_ADDR2);
+ awacs_write(awacs_reg[4] | MASK_ADDR4);
+ out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE);
+ enable_irq(awacs_irq);
+ enable_irq(awacs_tx_irq);
+ if (awacs_revision == 3) {
+ mdelay(100);
+ awacs_write(0x6000);
+ mdelay(2);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ }
+ /* enable CD sound input */
+ if (macio_base && is_pbook_G3) {
+ out_8(macio_base + 0x37, 3);
+ } else if (is_pbook_3400) {
+ feature_set(awacs_node, FEATURE_IOBUS_enable);
+ udelay(10);
+ in_8(latch_base + 0x190);
+ }
+ /* Resume pending sounds. */
+ PMacPlay();
+ }
+ return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+
+/* All the burgundy functions: */
+
+/* Waits for busy flag to clear */
+inline static void
+awacs_burgundy_busy_wait(void)
+{
+ while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD)
+ ;
+}
+
+inline static void
+awacs_burgundy_extend_wait(void)
+{
+ while (!(in_le32(&awacs->codec_stat) & MASK_EXTEND))
+ ;
+ while (in_le32(&awacs->codec_stat) & MASK_EXTEND)
+ ;
+}
+
+static void
+awacs_burgundy_wcw(unsigned addr, unsigned val)
+{
+ out_le32(&awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
+ awacs_burgundy_busy_wait();
+ out_le32(&awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
+ awacs_burgundy_busy_wait();
+ out_le32(&awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
+ awacs_burgundy_busy_wait();
+ out_le32(&awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
+ awacs_burgundy_busy_wait();
+}
+
+static unsigned
+awacs_burgundy_rcw(unsigned addr)
+{
+ unsigned val = 0;
+ unsigned long flags;
+
+ /* should have timeouts here */
+ save_flags(flags); cli();
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100000);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100100);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<8;
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100200);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<16;
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100300);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
+
+ restore_flags(flags);
+
+ return val;
+}
+
+
+static void
+awacs_burgundy_wcb(unsigned addr, unsigned val)
+{
+ out_le32(&awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
+ awacs_burgundy_busy_wait();
+}
+
+static unsigned
+awacs_burgundy_rcb(unsigned addr)
+{
+ unsigned val = 0;
+ unsigned long flags;
+
+ /* should have timeouts here */
+ save_flags(flags); cli();
+
+ out_le32(&awacs->codec_ctrl, addr + 0x100000);
+ awacs_burgundy_busy_wait();
+ awacs_burgundy_extend_wait();
+ val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
+
+ restore_flags(flags);
+
+ return val;
+}
+
+static int
+awacs_burgundy_check(void)
+{
+ /* Checks to see the chip is alive and kicking */
+ int error = in_le32(&awacs->codec_ctrl) & MASK_ERRCODE;
+
+ return error == 0xf0000;
+}
+
+static int
+awacs_burgundy_init(void)
+{
+ if (awacs_burgundy_check()) {
+ printk(KERN_WARNING "AWACS: disabled by MacOS :-(\n");
+ return 1;
+ }
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_OUTPUTENABLES,
+ DEF_BURGUNDY_OUTPUTENABLES);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ DEF_BURGUNDY_MORE_OUTPUTENABLES);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
+ DEF_BURGUNDY_OUTPUTSELECTS);
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL21,
+ DEF_BURGUNDY_INPSEL21);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_INPSEL3,
+ DEF_BURGUNDY_INPSEL3);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINCD,
+ DEF_BURGUNDY_GAINCD);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINLINE,
+ DEF_BURGUNDY_GAINLINE);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMIC,
+ DEF_BURGUNDY_GAINMIC);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_GAINMODEM,
+ DEF_BURGUNDY_GAINMODEM);
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER,
+ DEF_BURGUNDY_ATTENSPEAKER);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENLINEOUT,
+ DEF_BURGUNDY_ATTENLINEOUT);
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENHP,
+ DEF_BURGUNDY_ATTENHP);
+
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_MASTER_VOLUME,
+ DEF_BURGUNDY_MASTER_VOLUME);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLCD,
+ DEF_BURGUNDY_VOLCD);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLLINE,
+ DEF_BURGUNDY_VOLLINE);
+ awacs_burgundy_wcw(MASK_ADDR_BURGUNDY_VOLMIC,
+ DEF_BURGUNDY_VOLMIC);
+ return 0;
+}
+
+static void
+awacs_burgundy_write_volume(unsigned address, int volume)
+{
+ int hardvolume,lvolume,rvolume;
+
+ lvolume = (volume & 0xff) ? (volume & 0xff) + 155 : 0;
+ rvolume = ((volume >>8)&0xff) ? ((volume >> 8)&0xff ) + 155 : 0;
+
+ hardvolume = lvolume + (rvolume << 16);
+
+ awacs_burgundy_wcw(address, hardvolume);
+}
+
+static int
+awacs_burgundy_read_volume(unsigned address)
+{
+ int softvolume,wvolume;
+
+ wvolume = awacs_burgundy_rcw(address);
+
+ softvolume = (wvolume & 0xff) - 155;
+ softvolume += (((wvolume >> 16) & 0xff) - 155)<<8;
+
+ return softvolume > 0 ? softvolume : 0;
+}
+
+
+
+
+static int
+awacs_burgundy_read_mvolume(unsigned address)
+{
+ int lvolume,rvolume,wvolume;
+
+ wvolume = awacs_burgundy_rcw(address);
+
+ wvolume &= 0xffff;
+
+ rvolume = (wvolume & 0xff) - 155;
+ lvolume = ((wvolume & 0xff00)>>8) - 155;
+
+ return lvolume + (rvolume << 8);
+}
+
+
+static void
+awacs_burgundy_write_mvolume(unsigned address, int volume)
+{
+ int lvolume,rvolume,hardvolume;
+
+ lvolume = (volume &0xff) ? (volume & 0xff) + 155 :0;
+ rvolume = ((volume >>8) & 0xff) ? (volume >> 8) + 155 :0;
+
+ hardvolume = lvolume + (rvolume << 8);
+ hardvolume += (hardvolume << 16);
+
+ awacs_burgundy_wcw(address, hardvolume);
+}
+
+/* End burgundy functions */
+
+
+
+
+
+/* Turn on sound output, needed on G3 desktop powermacs */
+static void
+awacs_enable_amp(int spkr_vol)
+{
+ struct adb_request req;
+
+ awacs_spkr_vol = spkr_vol;
+ if (sys_ctrler != SYS_CTRLER_CUDA)
+ return;
+
+ /* turn on headphones */
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 4, 0);
+ while (!req.complete) cuda_poll();
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 6, 0);
+ while (!req.complete) cuda_poll();
+
+ /* turn on speaker */
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100);
+ while (!req.complete) cuda_poll();
+ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+ 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100);
+ while (!req.complete) cuda_poll();
+
+ cuda_request(&req, NULL, 5, CUDA_PACKET,
+ CUDA_GET_SET_IIC, 0x8a, 1, 0x29);
+ while (!req.complete) cuda_poll();
+}
+
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+static int PMacMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ /* Different IOCTLS for burgundy*/
+ if (awacs_revision < AWACS_BURGUNDY) {
+ switch (cmd) {
+ case SOUND_MIXER_READ_DEVMASK:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD | SOUND_MASK_RECLEV
+ | SOUND_MASK_ALTPCM
+ | SOUND_MASK_MONITOR;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECMASK:
+ data = SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECSRC:
+ data = 0;
+ if (awacs_reg[0] & MASK_MUX_AUDIN)
+ data |= SOUND_MASK_LINE;
+ if (awacs_reg[0] & MASK_MUX_MIC)
+ data |= SOUND_MASK_MIC;
+ if (awacs_reg[0] & MASK_MUX_CD)
+ data |= SOUND_MASK_CD;
+ if (awacs_reg[1] & MASK_LOOPTHRU)
+ data |= SOUND_MASK_MONITOR;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECSRC:
+ IOCTL_IN(arg, data);
+ data &= (SOUND_MASK_LINE
+ | SOUND_MASK_MIC | SOUND_MASK_CD
+ | SOUND_MASK_MONITOR);
+ awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+ | MASK_MUX_AUDIN);
+ awacs_reg[1] &= ~MASK_LOOPTHRU;
+ if (data & SOUND_MASK_LINE)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ if (data & SOUND_MASK_MIC)
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data & SOUND_MASK_CD)
+ awacs_reg[0] |= MASK_MUX_CD;
+ if (data & SOUND_MASK_MONITOR)
+ awacs_reg[1] |= MASK_LOOPTHRU;
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ awacs_write(awacs_reg[1] | MASK_ADDR1);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_STEREODEVS:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_RECLEV;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_CAPS:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_READ_VOLUME:
+ data = (awacs_reg[1] & MASK_AMUTE)? 0:
+ awacs_get_volume(awacs_reg[2], 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_volume(data));
+ case SOUND_MIXER_READ_SPEAKER:
+ if (awacs_revision == 3
+ && sys_ctrler == SYS_CTRLER_CUDA)
+ data = awacs_spkr_vol;
+ else
+ data = (awacs_reg[1] & MASK_CMUTE)? 0:
+ awacs_get_volume(awacs_reg[4], 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_SPEAKER:
+ IOCTL_IN(arg, data);
+ if (awacs_revision == 3
+ && sys_ctrler == SYS_CTRLER_CUDA)
+ awacs_enable_amp(data);
+ else
+ data = awacs_volume_setter(data, 4, MASK_CMUTE, 6);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
+ IOCTL_IN(arg, data);
+ beep_volume = data & 0xff;
+ /* fall through */
+ case SOUND_MIXER_READ_ALTPCM:
+ return IOCTL_OUT(arg, beep_volume);
+ case SOUND_MIXER_WRITE_LINE:
+ IOCTL_IN(arg, data);
+ awacs_reg[0] &= ~MASK_MUX_AUDIN;
+ if ((data & 0xff) >= 50)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_LINE:
+ data = (awacs_reg[0] & MASK_MUX_AUDIN)? 100: 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_MIC:
+ IOCTL_IN(arg, data);
+ data &= 0xff;
+ awacs_reg[0] &= ~(MASK_MUX_MIC | MASK_GAINLINE);
+ if (data >= 25) {
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data >= 75)
+ awacs_reg[0] |= MASK_GAINLINE;
+ }
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_MIC:
+ data = (awacs_reg[0] & MASK_MUX_MIC)?
+ (awacs_reg[0] & MASK_GAINLINE? 100: 50): 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_CD:
+ IOCTL_IN(arg, data);
+ awacs_reg[0] &= ~MASK_MUX_CD;
+ if ((data & 0xff) >= 50)
+ awacs_reg[0] |= MASK_MUX_CD;
+ awacs_write(MASK_ADDR0 | awacs_reg[0]);
+ /* fall through */
+ case SOUND_MIXER_READ_CD:
+ data = (awacs_reg[0] & MASK_MUX_CD)? 100: 0;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECLEV:
+ IOCTL_IN(arg, data);
+ data = awacs_volume_setter(data, 0, 0, 4);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECLEV:
+ data = awacs_get_volume(awacs_reg[0], 4);
+ return IOCTL_OUT(arg, data);
+ }
+ } else {
+ /* We are, we are, we are... Burgundy or better */
+ switch(cmd) {
+ case SOUND_MIXER_READ_DEVMASK:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_CD |
+ SOUND_MASK_LINE | SOUND_MASK_MIC |
+ SOUND_MASK_SPEAKER | SOUND_MASK_ALTPCM;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECMASK:
+ data = SOUND_MASK_LINE | SOUND_MASK_MIC
+ | SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECSRC:
+ data = 0;
+ if (awacs_reg[0] & MASK_MUX_AUDIN)
+ data |= SOUND_MASK_LINE;
+ if (awacs_reg[0] & MASK_MUX_MIC)
+ data |= SOUND_MASK_MIC;
+ if (awacs_reg[0] & MASK_MUX_CD)
+ data |= SOUND_MASK_CD;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECSRC:
+ IOCTL_IN(arg, data);
+ data &= (SOUND_MASK_LINE
+ | SOUND_MASK_MIC | SOUND_MASK_CD);
+ awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
+ | MASK_MUX_AUDIN);
+ if (data & SOUND_MASK_LINE)
+ awacs_reg[0] |= MASK_MUX_AUDIN;
+ if (data & SOUND_MASK_MIC)
+ awacs_reg[0] |= MASK_MUX_MIC;
+ if (data & SOUND_MASK_CD)
+ awacs_reg[0] |= MASK_MUX_CD;
+ awacs_write(awacs_reg[0] | MASK_ADDR0);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_STEREODEVS:
+ data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
+ | SOUND_MASK_RECLEV | SOUND_MASK_CD
+ | SOUND_MASK_LINE;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_CAPS:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ awacs_burgundy_write_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME, data);
+ /* Fall through */
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg, awacs_burgundy_read_mvolume(MASK_ADDR_BURGUNDY_MASTER_VOLUME));
+ case SOUND_MIXER_WRITE_SPEAKER:
+ IOCTL_IN(arg, data);
+
+ if (!(data & 0xff)) {
+ /* Mute the left speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x2);
+ } else {
+ /* Unmute the left speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x2);
+ }
+ if (!(data & 0xff00)) {
+ /* Mute the right speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) & ~0x4);
+ } else {
+ /* Unmute the right speaker */
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
+ awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES) | 0x4);
+ }
+
+ data = (((data&0xff)*16)/100 > 0xf ? 0xf :
+ (((data&0xff)*16)/100)) +
+ ((((data>>8)*16)/100 > 0xf ? 0xf :
+ ((((data>>8)*16)/100)))<<4);
+
+ awacs_burgundy_wcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER, ~data);
+ /* Fall through */
+ case SOUND_MIXER_READ_SPEAKER:
+ data = awacs_burgundy_rcb(MASK_ADDR_BURGUNDY_ATTENSPEAKER);
+ data = (((data & 0xf)*100)/16) + ((((data>>4)*100)/16)<<8);
+ return IOCTL_OUT(arg, ~data);
+ case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
+ IOCTL_IN(arg, data);
+ beep_volume = data & 0xff;
+ /* fall through */
+ case SOUND_MIXER_READ_ALTPCM:
+ return IOCTL_OUT(arg, beep_volume);
+ case SOUND_MIXER_WRITE_LINE:
+ IOCTL_IN(arg, data);
+ awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLLINE, data);
+
+ /* fall through */
+ case SOUND_MIXER_READ_LINE:
+ data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLLINE);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_MIC:
+ IOCTL_IN(arg, data);
+ /* Mic is mono device */
+ data = (data << 8) + (data << 24);
+ awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLMIC, data);
+ /* fall through */
+ case SOUND_MIXER_READ_MIC:
+ data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLMIC);
+ data <<= 24;
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_CD:
+ IOCTL_IN(arg, data);
+ awacs_burgundy_write_volume(MASK_ADDR_BURGUNDY_VOLCD, data);
+ /* fall through */
+ case SOUND_MIXER_READ_CD:
+ data = awacs_burgundy_read_volume(MASK_ADDR_BURGUNDY_VOLCD);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_WRITE_RECLEV:
+ IOCTL_IN(arg, data);
+ data = awacs_volume_setter(data, 0, 0, 4);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_READ_RECLEV:
+ data = awacs_get_volume(awacs_reg[0], 4);
+ return IOCTL_OUT(arg, data);
+ case SOUND_MIXER_OUTMASK:
+ break;
+ case SOUND_MIXER_OUTSRC:
+ break;
+ }
+ }
+ return -EINVAL;
+}
+
+
+static void PMacWriteSqSetup(void)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+ cp = awacs_tx_cmds;
+ memset((void *)cp, 0, (write_sq.numBufs+1) * sizeof(struct dbdma_cmd));
+ for (i = 0; i < write_sq.numBufs; ++i, ++cp) {
+ st_le32(&cp->phy_addr, virt_to_bus(write_sq.buffers[i]));
+ }
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
+ out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds));
+}
+
+static void PMacReadSqSetup(void)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+ cp = awacs_rx_cmds;
+ memset((void *)cp, 0, (read_sq.numBufs+1) * sizeof(struct dbdma_cmd));
+
+ /* Set dma buffers up in a loop */
+ for (i = 0; i < read_sq.numBufs; i++,cp++) {
+ st_le32(&cp->phy_addr, virt_to_bus(read_sq.buffers[i]));
+ st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
+ st_le16(&cp->req_count, read_sq.block_size);
+ st_le16(&cp->xfer_status, 0);
+ }
+
+ /* The next two lines make the thing loop around.
+ */
+ st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+ st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
+
+ /* Don't start until the first read is done.
+ * This will also abort any operations in progress if the DMA
+ * happens to be running (and it shouldn't).
+ */
+ out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+ out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
+
+}
+
+static void PMacAbortRead(void)
+{
+ int i;
+ volatile struct dbdma_cmd *cp;
+
+ cp = awacs_rx_cmds;
+ for (i = 0; i < read_sq.numBufs; i++,cp++)
+ st_le16(&cp->command, DBDMA_STOP);
+ /*
+ * We should probably wait for the thing to stop before we
+ * release the memory
+ */
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machPMac = {
+ name: awacs_name,
+ name2: "AWACS",
+ open: PMacOpen,
+ release: PMacRelease,
+ dma_alloc: PMacAlloc,
+ dma_free: PMacFree,
+ irqinit: PMacIrqInit,
+#ifdef MODULE
+ irqcleanup: PMacIrqCleanup,
+#endif /* MODULE */
+ init: PMacInit,
+ silence: PMacSilence,
+ setFormat: PMacSetFormat,
+ setVolume: PMacSetVolume,
+ play: PMacPlay,
+ record: PMacRecord,
+ mixer_ioctl: PMacMixerIoctl,
+ write_sq_setup: PMacWriteSqSetup,
+ read_sq_setup: PMacReadSqSetup,
+ abort_read: PMacAbortRead,
+ min_dsp_speed: 8000
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_awacs_init(void)
+{
+ struct device_node *np;
+
+ if (_machine != _MACH_Pmac)
+ return -ENODEV;
+
+ awacs_subframe = 0;
+ awacs_revision = 0;
+ np = find_devices("awacs");
+ if (np == 0) {
+ /*
+ * powermac G3 models have a node called "davbus"
+ * with a child called "sound".
+ */
+ struct device_node *sound;
+ np = find_devices("davbus");
+ sound = find_devices("sound");
+ if (sound != 0 && sound->parent == np) {
+ unsigned int *prop, l, i;
+ prop = (unsigned int *)
+ get_property(sound, "sub-frame", 0);
+ if (prop != 0 && *prop >= 0 && *prop < 16)
+ awacs_subframe = *prop;
+ if (device_is_compatible(sound, "burgundy"))
+ awacs_revision = AWACS_BURGUNDY;
+
+ /* look for a property saying what sample rates
+ are available */
+ for (i = 0; i < 8; ++i)
+ awacs_freqs_ok[i] = 0;
+ prop = (unsigned int *) get_property
+ (sound, "sample-rates", &l);
+ if (prop == 0)
+ prop = (unsigned int *) get_property
+ (sound, "output-frame-rates", &l);
+ if (prop != 0) {
+ for (l /= sizeof(int); l > 0; --l) {
+ /* sometimes the rate is in the
+ high-order 16 bits (?) */
+ unsigned int r = *prop++;
+ if (r >= 0x10000)
+ r >>= 16;
+ for (i = 0; i < 8; ++i) {
+ if (r == awacs_freqs[i]) {
+ awacs_freqs_ok[i] = 1;
+ break;
+ }
+ }
+ }
+ } else {
+ /* assume just 44.1k is OK */
+ awacs_freqs_ok[0] = 1;
+ }
+ }
+ }
+ if (np != NULL && np->n_addrs >= 3 && np->n_intrs >= 3) {
+ int vol;
+ dmasound.mach = machPMac;
+
+ awacs = (volatile struct awacs_regs *)
+ ioremap(np->addrs[0].address, 0x80);
+ awacs_txdma = (volatile struct dbdma_regs *)
+ ioremap(np->addrs[1].address, 0x100);
+ awacs_rxdma = (volatile struct dbdma_regs *)
+ ioremap(np->addrs[2].address, 0x100);
+
+ awacs_irq = np->intrs[0].line;
+ awacs_tx_irq = np->intrs[1].line;
+ awacs_rx_irq = np->intrs[2].line;
+
+ awacs_tx_cmd_space = kmalloc((write_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
+ GFP_KERNEL);
+ if (awacs_tx_cmd_space == NULL) {
+ printk(KERN_ERR "DMA sound driver: Not enough buffer memory, driver disabled!\n");
+ return -ENOMEM;
+ }
+ awacs_node = np;
+#ifdef CONFIG_PMAC_PBOOK
+ if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ feature_set(np, FEATURE_Sound_CLK_enable);
+ feature_set(np, FEATURE_Sound_power);
+ /* Shorter delay will not work */
+ mdelay(1000);
+ }
+#endif
+ awacs_tx_cmds = (volatile struct dbdma_cmd *)
+ DBDMA_ALIGN(awacs_tx_cmd_space);
+
+
+ awacs_rx_cmd_space = kmalloc((read_sq.numBufs + 4) * sizeof(struct dbdma_cmd),
+ GFP_KERNEL);
+ if (awacs_rx_cmd_space == NULL) {
+ printk("DMA sound driver: No memory for input");
+ }
+ awacs_rx_cmds = (volatile struct dbdma_cmd *)
+ DBDMA_ALIGN(awacs_rx_cmd_space);
+
+
+
+ awacs_reg[0] = MASK_MUX_CD;
+ awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+ /* get default volume from nvram */
+ vol = (~nvram_read_byte(0x1308) & 7) << 1;
+ awacs_reg[2] = vol + (vol << 6);
+ awacs_reg[4] = vol + (vol << 6);
+ out_le32(&awacs->control, 0x11);
+ awacs_write(awacs_reg[0] + MASK_ADDR0);
+ awacs_write(awacs_reg[1] + MASK_ADDR1);
+ awacs_write(awacs_reg[2] + MASK_ADDR2);
+ awacs_write(awacs_reg[4] + MASK_ADDR4);
+
+ /* Initialize recent versions of the awacs */
+ if (awacs_revision == 0) {
+ awacs_revision =
+ (in_le32(&awacs->codec_stat) >> 12) & 0xf;
+ if (awacs_revision == 3) {
+ mdelay(100);
+ awacs_write(0x6000);
+ mdelay(2);
+ awacs_write(awacs_reg[1] + MASK_ADDR1);
+ awacs_enable_amp(100 * 0x101);
+ }
+ }
+ if (awacs_revision >= AWACS_BURGUNDY)
+ awacs_burgundy_init();
+
+ /* Initialize beep stuff */
+ beep_dbdma_cmd = awacs_tx_cmds + (write_sq.numBufs + 1);
+ orig_mksound = kd_mksound;
+ kd_mksound = awacs_mksound;
+ beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+ if (beep_buf == NULL)
+ printk(KERN_WARNING "dmasound: no memory for "
+ "beep buffer\n");
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&awacs_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+ /* Powerbooks have odd ways of enabling inputs such as
+ an expansion-bay CD or sound from an internal modem
+ or a PC-card modem. */
+ if (machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500")) {
+ is_pbook_3400 = 1;
+ /*
+ * Enable CD and PC-card sound inputs.
+ * This is done by reading from address
+ * f301a000, + 0x10 to enable the expansion-bay
+ * CD sound input, + 0x80 to enable the PC-card
+ * sound input. The 0x100 enables the SCSI bus
+ * terminator power.
+ */
+ latch_base = (unsigned char *) ioremap
+ (0xf301a000, 0x1000);
+ in_8(latch_base + 0x190);
+ } else if (machine_is_compatible("PowerBook1,1")
+ || machine_is_compatible("AAPL,PowerBook1998")) {
+ struct device_node* mio;
+ macio_base = 0;
+ is_pbook_G3 = 1;
+ for (mio = np->parent; mio; mio = mio->parent) {
+ if (strcmp(mio->name, "mac-io") == 0
+ && mio->n_addrs > 0) {
+ macio_base = (unsigned char *) ioremap
+ (mio->addrs[0].address, 0x40);
+ break;
+ }
+ }
+ /* enable CD sound input */
+ if (macio_base)
+ out_8(macio_base + 0x37, 3);
+ }
+ sprintf(awacs_name, "PowerMac (AWACS rev %d) ",
+ awacs_revision);
+ return dmasound_init();
+ }
+ return -ENODEV;
+}
+
+static void __exit dmasound_awacs_cleanup(void)
+{
+ dmasound_deinit();
+}
+
+module_init(dmasound_awacs_init);
+module_exit(dmasound_awacs_cleanup);
diff --git a/drivers/sound/dmasound/dmasound_core.c b/drivers/sound/dmasound/dmasound_core.c
new file mode 100644
index 000000000..594ee925c
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_core.c
@@ -0,0 +1,1313 @@
+
+/*
+ * linux/drivers/sound/dmasound.c
+ *
+ *
+ * OSS/Free compatible Atari TT/Falcon and Amiga DMA sound driver for
+ * Linux/m68k
+ * Extended to support Power Macintosh for Linux/ppc by Paul Mackerras
+ *
+ * (c) 1995 by Michael Schlueter & Michael Marte
+ *
+ * Michael Schlueter (michael@duck.syd.de) did the basic structure of the VFS
+ * interface and the u-law to signed byte conversion.
+ *
+ * Michael Marte (marte@informatik.uni-muenchen.de) did the sound queue,
+ * /dev/mixer, /dev/sndstat and complemented the VFS interface. He would like
+ * to thank:
+ * - Michael Schlueter for initial ideas and documentation on the MFP and
+ * the DMA sound hardware.
+ * - Therapy? for their CD 'Troublegum' which really made me rock.
+ *
+ * /dev/sndstat is based on code by Hannu Savolainen, the author of the
+ * VoxWare family of drivers.
+ *
+ * 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.
+ *
+ * History:
+ *
+ * 1995/8/25 First release
+ *
+ * 1995/9/02 Roman Hodek:
+ * - Fixed atari_stram_alloc() call, the timer
+ * programming and several race conditions
+ * 1995/9/14 Roman Hodek:
+ * - After some discussion with Michael Schlueter,
+ * revised the interrupt disabling
+ * - Slightly speeded up U8->S8 translation by using
+ * long operations where possible
+ * - Added 4:3 interpolation for /dev/audio
+ *
+ * 1995/9/20 Torsten Scherer:
+ * - Fixed a bug in sq_write and changed /dev/audio
+ * converting to play at 12517Hz instead of 6258Hz.
+ *
+ * 1995/9/23 Torsten Scherer:
+ * - Changed sq_interrupt() and sq_play() to pre-program
+ * the DMA for another frame while there's still one
+ * running. This allows the IRQ response to be
+ * arbitrarily delayed and playing will still continue.
+ *
+ * 1995/10/14 Guenther Kelleter, Torsten Scherer:
+ * - Better support for Falcon audio (the Falcon doesn't
+ * raise an IRQ at the end of a frame, but at the
+ * beginning instead!). uses 'if (codec_dma)' in lots
+ * of places to simply switch between Falcon and TT
+ * code.
+ *
+ * 1995/11/06 Torsten Scherer:
+ * - Started introducing a hardware abstraction scheme
+ * (may perhaps also serve for Amigas?)
+ * - Can now play samples at almost all frequencies by
+ * means of a more generalized expand routine
+ * - Takes a good deal of care to cut data only at
+ * sample sizes
+ * - Buffer size is now a kernel runtime option
+ * - Implemented fsync() & several minor improvements
+ * Guenther Kelleter:
+ * - Useful hints and bug fixes
+ * - Cross-checked it for Falcons
+ *
+ * 1996/3/9 Geert Uytterhoeven:
+ * - Support added for Amiga, A-law, 16-bit little
+ * endian.
+ * - Unification to drivers/sound/dmasound.c.
+ *
+ * 1996/4/6 Martin Mitchell:
+ * - Updated to 1.3 kernel.
+ *
+ * 1996/6/13 Topi Kanerva:
+ * - Fixed things that were broken (mainly the amiga
+ * 14-bit routines)
+ * - /dev/sndstat shows now the real hardware frequency
+ * - The lowpass filter is disabled by default now
+ *
+ * 1996/9/25 Geert Uytterhoeven:
+ * - Modularization
+ *
+ * 1998/6/10 Andreas Schwab:
+ * - Converted to use sound_core
+ *
+ * 1999/12/28 Richard Zidlicky:
+ * - Added support for Q40
+ *
+ * 2000/2/27 Geert Uytterhoeven:
+ * - Clean up and split the code into 4 parts:
+ * o dmasound_core: machine-independent code
+ * o dmasound_atari: Atari TT and Falcon support
+ * o dmasound_awacs: Apple PowerMac support
+ * o dmasound_paula: Amiga support
+ *
+ * 2000/3/25 Geert Uytterhoeven:
+ * - Integration of dmasound_q40
+ * - Small clean ups
+ */
+
+
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/sound.h>
+#include <linux/init.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+
+#include "dmasound.h"
+
+
+ /*
+ * Declarations
+ */
+
+int dmasound_catchRadius = 0;
+static unsigned int numWriteBufs = 4;
+static unsigned int writeBufSize = 32; /* in KB! */
+#ifdef HAS_RECORD
+static unsigned int numReadBufs = 4;
+static unsigned int readBufSize = 32; /* in KB! */
+#endif
+
+MODULE_PARM(dmasound_catchRadius, "i");
+MODULE_PARM(numWriteBufs, "i");
+MODULE_PARM(writeBufSize, "i");
+MODULE_PARM(numReadBufs, "i");
+MODULE_PARM(readBufSize, "i");
+
+#ifdef MODULE
+static int sq_unit = -1;
+static int mixer_unit = -1;
+static int state_unit = -1;
+static int irq_installed = 0;
+#endif /* MODULE */
+
+
+ /*
+ * Conversion tables
+ */
+
+#ifdef HAS_8BIT_TABLES
+/* 8 bit mu-law */
+
+char dmasound_ulaw2dma8[] = {
+ -126, -122, -118, -114, -110, -106, -102, -98,
+ -94, -90, -86, -82, -78, -74, -70, -66,
+ -63, -61, -59, -57, -55, -53, -51, -49,
+ -47, -45, -43, -41, -39, -37, -35, -33,
+ -31, -30, -29, -28, -27, -26, -25, -24,
+ -23, -22, -21, -20, -19, -18, -17, -16,
+ -16, -15, -15, -14, -14, -13, -13, -12,
+ -12, -11, -11, -10, -10, -9, -9, -8,
+ -8, -8, -7, -7, -7, -7, -6, -6,
+ -6, -6, -5, -5, -5, -5, -4, -4,
+ -4, -4, -4, -4, -3, -3, -3, -3,
+ -3, -3, -3, -3, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 0,
+ 125, 121, 117, 113, 109, 105, 101, 97,
+ 93, 89, 85, 81, 77, 73, 69, 65,
+ 62, 60, 58, 56, 54, 52, 50, 48,
+ 46, 44, 42, 40, 38, 36, 34, 32,
+ 30, 29, 28, 27, 26, 25, 24, 23,
+ 22, 21, 20, 19, 18, 17, 16, 15,
+ 15, 14, 14, 13, 13, 12, 12, 11,
+ 11, 10, 10, 9, 9, 8, 8, 7,
+ 7, 7, 6, 6, 6, 6, 5, 5,
+ 5, 5, 4, 4, 4, 4, 3, 3,
+ 3, 3, 3, 3, 2, 2, 2, 2,
+ 2, 2, 2, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* 8 bit A-law */
+
+char dmasound_alaw2dma8[] = {
+ -22, -21, -24, -23, -18, -17, -20, -19,
+ -30, -29, -32, -31, -26, -25, -28, -27,
+ -11, -11, -12, -12, -9, -9, -10, -10,
+ -15, -15, -16, -16, -13, -13, -14, -14,
+ -86, -82, -94, -90, -70, -66, -78, -74,
+ -118, -114, -126, -122, -102, -98, -110, -106,
+ -43, -41, -47, -45, -35, -33, -39, -37,
+ -59, -57, -63, -61, -51, -49, -55, -53,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -2, -2, -2, -2, -2, -2, -2, -2,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -6, -6, -6, -6, -5, -5, -5, -5,
+ -8, -8, -8, -8, -7, -7, -7, -7,
+ -3, -3, -3, -3, -3, -3, -3, -3,
+ -4, -4, -4, -4, -4, -4, -4, -4,
+ 21, 20, 23, 22, 17, 16, 19, 18,
+ 29, 28, 31, 30, 25, 24, 27, 26,
+ 10, 10, 11, 11, 8, 8, 9, 9,
+ 14, 14, 15, 15, 12, 12, 13, 13,
+ 86, 82, 94, 90, 70, 66, 78, 74,
+ 118, 114, 126, 122, 102, 98, 110, 106,
+ 43, 41, 47, 45, 35, 33, 39, 37,
+ 59, 57, 63, 61, 51, 49, 55, 53,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 4, 4, 4, 4,
+ 7, 7, 7, 7, 6, 6, 6, 6,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3
+};
+#endif /* HAS_8BIT_TABLES */
+
+#ifdef HAS_16BIT_TABLES
+
+/* 16 bit mu-law */
+
+short dmasound_ulaw2dma16[] = {
+ -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+ -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+ -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+ -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
+ -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+ -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+ -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+ -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+ -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+ -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
+ -876, -844, -812, -780, -748, -716, -684, -652,
+ -620, -588, -556, -524, -492, -460, -428, -396,
+ -372, -356, -340, -324, -308, -292, -276, -260,
+ -244, -228, -212, -196, -180, -164, -148, -132,
+ -120, -112, -104, -96, -88, -80, -72, -64,
+ -56, -48, -40, -32, -24, -16, -8, 0,
+ 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+ 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+ 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+ 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
+ 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
+ 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
+ 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
+ 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
+ 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
+ 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
+ 876, 844, 812, 780, 748, 716, 684, 652,
+ 620, 588, 556, 524, 492, 460, 428, 396,
+ 372, 356, 340, 324, 308, 292, 276, 260,
+ 244, 228, 212, 196, 180, 164, 148, 132,
+ 120, 112, 104, 96, 88, 80, 72, 64,
+ 56, 48, 40, 32, 24, 16, 8, 0,
+};
+
+/* 16 bit A-law */
+
+short dmasound_alaw2dma16[] = {
+ -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+ -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+ -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+ -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+ -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+ -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+ -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
+ -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+ -344, -328, -376, -360, -280, -264, -312, -296,
+ -472, -456, -504, -488, -408, -392, -440, -424,
+ -88, -72, -120, -104, -24, -8, -56, -40,
+ -216, -200, -248, -232, -152, -136, -184, -168,
+ -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+ -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+ -688, -656, -752, -720, -560, -528, -624, -592,
+ -944, -912, -1008, -976, -816, -784, -880, -848,
+ 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
+ 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
+ 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
+ 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
+ 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+ 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+ 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
+ 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+ 344, 328, 376, 360, 280, 264, 312, 296,
+ 472, 456, 504, 488, 408, 392, 440, 424,
+ 88, 72, 120, 104, 24, 8, 56, 40,
+ 216, 200, 248, 232, 152, 136, 184, 168,
+ 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
+ 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
+ 688, 656, 752, 720, 560, 528, 624, 592,
+ 944, 912, 1008, 976, 816, 784, 880, 848,
+};
+#endif /* HAS_16BIT_TABLES */
+
+
+#ifdef HAS_14BIT_TABLES
+
+ /*
+ * Unused for now. Where are the MSB parts anyway??
+ */
+
+/* 14 bit mu-law (LSB) */
+
+char dmasound_ulaw2dma14l[] = {
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 49, 17, 49, 17, 49, 17, 49, 17,
+ 49, 17, 49, 17, 49, 17, 49, 17,
+ 41, 57, 9, 25, 41, 57, 9, 25,
+ 41, 57, 9, 25, 41, 57, 9, 25,
+ 37, 45, 53, 61, 5, 13, 21, 29,
+ 37, 45, 53, 61, 5, 13, 21, 29,
+ 35, 39, 43, 47, 51, 55, 59, 63,
+ 3, 7, 11, 15, 19, 23, 27, 31,
+ 34, 36, 38, 40, 42, 44, 46, 48,
+ 50, 52, 54, 56, 58, 60, 62, 0,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ 15, 47, 15, 47, 15, 47, 15, 47,
+ 15, 47, 15, 47, 15, 47, 15, 47,
+ 23, 7, 55, 39, 23, 7, 55, 39,
+ 23, 7, 55, 39, 23, 7, 55, 39,
+ 27, 19, 11, 3, 59, 51, 43, 35,
+ 27, 19, 11, 3, 59, 51, 43, 35,
+ 29, 25, 21, 17, 13, 9, 5, 1,
+ 61, 57, 53, 49, 45, 41, 37, 33,
+ 30, 28, 26, 24, 22, 20, 18, 16,
+ 14, 12, 10, 8, 6, 4, 2, 0
+};
+
+/* 14 bit A-law (LSB) */
+
+char dmasound_alaw2dma14l[] = {
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 16, 48, 16, 48, 16, 48, 16, 48,
+ 16, 48, 16, 48, 16, 48, 16, 48,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 42, 46, 34, 38, 58, 62, 50, 54,
+ 10, 14, 2, 6, 26, 30, 18, 22,
+ 42, 46, 34, 38, 58, 62, 50, 54,
+ 10, 14, 2, 6, 26, 30, 18, 22,
+ 40, 56, 8, 24, 40, 56, 8, 24,
+ 40, 56, 8, 24, 40, 56, 8, 24,
+ 20, 28, 4, 12, 52, 60, 36, 44,
+ 20, 28, 4, 12, 52, 60, 36, 44,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,
+ 48, 16, 48, 16, 48, 16, 48, 16,
+ 48, 16, 48, 16, 48, 16, 48, 16,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 22, 18, 30, 26, 6, 2, 14, 10,
+ 54, 50, 62, 58, 38, 34, 46, 42,
+ 22, 18, 30, 26, 6, 2, 14, 10,
+ 54, 50, 62, 58, 38, 34, 46, 42,
+ 24, 8, 56, 40, 24, 8, 56, 40,
+ 24, 8, 56, 40, 24, 8, 56, 40,
+ 44, 36, 60, 52, 12, 4, 28, 20,
+ 44, 36, 60, 52, 12, 4, 28, 20
+};
+#endif /* HAS_14BIT_TABLES */
+
+
+ /*
+ * Common stuff
+ */
+
+static long long sound_lseek(struct file *file, long long offset, int orig)
+{
+ return -ESPIPE;
+}
+
+
+ /*
+ * Mid level stuff
+ */
+
+struct sound_settings dmasound;
+
+static inline void sound_silence(void)
+{
+ /* update hardware settings one more */
+ dmasound.mach.init();
+
+ dmasound.mach.silence();
+}
+
+static inline void sound_init(void)
+{
+ dmasound.mach.init();
+}
+
+static inline int sound_set_format(int format)
+{
+ return dmasound.mach.setFormat(format);
+}
+
+static int sound_set_speed(int speed)
+{
+ if (speed < 0)
+ return dmasound.soft.speed;
+
+ dmasound.soft.speed = speed;
+ dmasound.mach.init();
+ if (dmasound.minDev == SND_DEV_DSP)
+ dmasound.dsp.speed = dmasound.soft.speed;
+
+ return dmasound.soft.speed;
+}
+
+static int sound_set_stereo(int stereo)
+{
+ if (stereo < 0)
+ return dmasound.soft.stereo;
+
+ stereo = !!stereo; /* should be 0 or 1 now */
+
+ dmasound.soft.stereo = stereo;
+ if (dmasound.minDev == SND_DEV_DSP)
+ dmasound.dsp.stereo = stereo;
+ dmasound.mach.init();
+
+ return stereo;
+}
+
+static ssize_t sound_copy_translate(TRANS *trans, const u_char *userPtr,
+ size_t userCount, u_char frame[],
+ ssize_t *frameUsed, ssize_t frameLeft)
+{
+ ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+
+ switch (dmasound.soft.format) {
+ case AFMT_MU_LAW:
+ ct_func = trans->ct_ulaw;
+ break;
+ case AFMT_A_LAW:
+ ct_func = trans->ct_alaw;
+ break;
+ case AFMT_S8:
+ ct_func = trans->ct_s8;
+ break;
+ case AFMT_U8:
+ ct_func = trans->ct_u8;
+ break;
+ case AFMT_S16_BE:
+ ct_func = trans->ct_s16be;
+ break;
+ case AFMT_U16_BE:
+ ct_func = trans->ct_u16be;
+ break;
+ case AFMT_S16_LE:
+ ct_func = trans->ct_s16le;
+ break;
+ case AFMT_U16_LE:
+ ct_func = trans->ct_u16le;
+ break;
+ default:
+ return 0;
+ }
+ return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
+}
+
+
+ /*
+ * /dev/mixer abstraction
+ */
+
+static struct {
+ int busy;
+ int modify_counter;
+} mixer;
+
+static int mixer_open(struct inode *inode, struct file *file)
+{
+ MOD_INC_USE_COUNT;
+ dmasound.mach.open();
+ mixer.busy = 1;
+ return 0;
+}
+
+static int mixer_release(struct inode *inode, struct file *file)
+{
+ mixer.busy = 0;
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg)
+{
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+ mixer.modify_counter++;
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return IOCTL_OUT(arg, SOUND_VERSION);
+ case SOUND_MIXER_INFO:
+ {
+ mixer_info info;
+ strncpy(info.id, dmasound.mach.name2, sizeof(info.id));
+ strncpy(info.name, dmasound.mach.name2, sizeof(info.name));
+ info.name[sizeof(info.name)-1] = 0;
+ info.modify_counter = mixer.modify_counter;
+ copy_to_user_ret((int *)arg, &info, sizeof(info), -EFAULT);
+ return 0;
+ }
+ }
+ if (dmasound.mach.mixer_ioctl)
+ return dmasound.mach.mixer_ioctl(cmd, arg);
+ return -EINVAL;
+}
+
+static struct file_operations mixer_fops =
+{
+ llseek: sound_lseek,
+ ioctl: mixer_ioctl,
+ open: mixer_open,
+ release: mixer_release,
+};
+
+static void __init mixer_init(void)
+{
+#ifndef MODULE
+ int mixer_unit;
+#endif
+ mixer_unit = register_sound_mixer(&mixer_fops, -1);
+ if (mixer_unit < 0)
+ return;
+
+ mixer.busy = 0;
+ dmasound.treble = 0;
+ dmasound.bass = 0;
+ if (dmasound.mach.mixer_init)
+ dmasound.mach.mixer_init();
+}
+
+
+ /*
+ * Sound queue stuff, the heart of the driver
+ */
+
+struct sound_queue dmasound_write_sq;
+#ifdef HAS_RECORD
+struct sound_queue dmasound_read_sq;
+#endif
+
+static int sq_allocate_buffers(struct sound_queue *sq, int num, int size)
+{
+ int i;
+
+ if (sq->buffers)
+ return 0;
+ sq->numBufs = num;
+ sq->bufSize = size;
+ sq->buffers = kmalloc (num * sizeof(char *), GFP_KERNEL);
+ if (!sq->buffers)
+ return -ENOMEM;
+ for (i = 0; i < num; i++) {
+ sq->buffers[i] = dmasound.mach.dma_alloc(size, GFP_KERNEL);
+ if (!sq->buffers[i]) {
+ while (i--)
+ dmasound.mach.dma_free(sq->buffers[i], size);
+ kfree(sq->buffers);
+ sq->buffers = 0;
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static void sq_release_buffers(struct sound_queue *sq)
+{
+ int i;
+
+ if (sq->buffers) {
+ if (sq != &write_sq && dmasound.mach.abort_read)
+ dmasound.mach.abort_read();
+ for (i = 0; i < sq->numBufs; i++)
+ dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);
+ kfree(sq->buffers);
+ sq->buffers = NULL;
+ }
+}
+
+static void sq_setup(struct sound_queue *sq, int max_count, int max_active,
+ int block_size)
+{
+ void (*setup_func)(void);
+
+ sq->max_count = max_count;
+ sq->max_active = max_active;
+ sq->block_size = block_size;
+
+ sq->front = sq->count = sq->rear_size = 0;
+ sq->syncing = 0;
+ sq->active = 0;
+
+ if (sq == &write_sq) {
+ sq->rear = -1;
+ setup_func = dmasound.mach.write_sq_setup;
+ } else {
+ sq->rear = 0;
+ setup_func = dmasound.mach.read_sq_setup;
+ }
+ if (setup_func)
+ setup_func();
+}
+
+static inline void sq_play(void)
+{
+ dmasound.mach.play();
+}
+
+static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
+ loff_t *ppos)
+{
+ ssize_t uWritten = 0;
+ u_char *dest;
+ ssize_t uUsed, bUsed, bLeft;
+
+ /* ++TeSche: Is something like this necessary?
+ * Hey, that's an honest question! Or does any other part of the
+ * filesystem already checks this situation? I really don't know.
+ */
+ if (uLeft == 0)
+ return 0;
+
+ /* The interrupt doesn't start to play the last, incomplete frame.
+ * Thus we can append to it without disabling the interrupts! (Note
+ * also that write_sq.rear isn't affected by the interrupt.)
+ */
+
+ if (write_sq.count > 0 &&
+ (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
+ dest = write_sq.buffers[write_sq.rear];
+ bUsed = write_sq.rear_size;
+ uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
+ dest, &bUsed, bLeft);
+ if (uUsed <= 0)
+ return uUsed;
+ src += uUsed;
+ uWritten += uUsed;
+ uLeft -= uUsed;
+ write_sq.rear_size = bUsed;
+ }
+
+ do {
+ while (write_sq.count == write_sq.max_active) {
+ sq_play();
+ if (write_sq.open_mode & O_NONBLOCK)
+ return uWritten > 0 ? uWritten : -EAGAIN;
+ SLEEP(write_sq.action_queue);
+ if (signal_pending(current))
+ return uWritten > 0 ? uWritten : -EINTR;
+ }
+
+ /* Here, we can avoid disabling the interrupt by first
+ * copying and translating the data, and then updating
+ * the write_sq variables. Until this is done, the interrupt
+ * won't see the new frame and we can work on it
+ * undisturbed.
+ */
+
+ dest = write_sq.buffers[(write_sq.rear+1) % write_sq.max_count];
+ bUsed = 0;
+ bLeft = write_sq.block_size;
+ uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
+ dest, &bUsed, bLeft);
+ if (uUsed <= 0)
+ break;
+ src += uUsed;
+ uWritten += uUsed;
+ uLeft -= uUsed;
+ if (bUsed) {
+ write_sq.rear = (write_sq.rear+1) % write_sq.max_count;
+ write_sq.rear_size = bUsed;
+ write_sq.count++;
+ }
+ } while (bUsed); /* uUsed may have been 0 */
+
+ sq_play();
+
+ return uUsed < 0? uUsed: uWritten;
+}
+
+#ifdef HAS_RECORD
+ /*
+ * Here is how the values are used for reading.
+ * The value 'active' simply indicates the DMA is running. This is done
+ * so the driver semantics are DMA starts when the first read is posted.
+ * The value 'front' indicates the buffer we should next send to the user.
+ * The value 'rear' indicates the buffer the DMA is currently filling.
+ * When 'front' == 'rear' the buffer "ring" is empty (we always have an
+ * empty available). The 'rear_size' is used to track partial offsets
+ * into the current buffer. Right now, I just keep the DMA running. If
+ * the reader can't keep up, the interrupt tosses the oldest buffer. We
+ * could also shut down the DMA in this case.
+ */
+
+static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
+ loff_t *ppos)
+{
+
+ ssize_t uRead, bLeft, bUsed, uUsed;
+
+ if (uLeft == 0)
+ return 0;
+
+ if (!read_sq.active && dmasound.mach.record)
+ dmasound.mach.record(); /* Kick off the record process. */
+
+ uRead = 0;
+
+ /* Move what the user requests, depending upon other options.
+ */
+ while (uLeft > 0) {
+
+ /* When front == rear, the DMA is not done yet.
+ */
+ while (read_sq.front == read_sq.rear) {
+ if (read_sq.open_mode & O_NONBLOCK) {
+ return uRead > 0 ? uRead : -EAGAIN;
+ }
+ SLEEP(read_sq.action_queue);
+ if (signal_pending(current))
+ return uRead > 0 ? uRead : -EINTR;
+ }
+
+ /* The amount we move is either what is left in the
+ * current buffer or what the user wants.
+ */
+ bLeft = read_sq.block_size - read_sq.rear_size;
+ bUsed = read_sq.rear_size;
+ uUsed = sound_copy_translate(dmasound.trans_read, dst, uLeft,
+ read_sq.buffers[read_sq.front],
+ &bUsed, bLeft);
+ if (uUsed <= 0)
+ return uUsed;
+ dst += uUsed;
+ uRead += uUsed;
+ uLeft -= uUsed;
+ read_sq.rear_size += bUsed;
+ if (read_sq.rear_size >= read_sq.block_size) {
+ read_sq.rear_size = 0;
+ read_sq.front++;
+ if (read_sq.front >= read_sq.max_active)
+ read_sq.front = 0;
+ }
+ }
+ return uRead;
+}
+#endif /* HAS_RECORD */
+
+static inline void sq_init_waitqueue(struct sound_queue *sq)
+{
+ init_waitqueue_head(&sq->action_queue);
+ init_waitqueue_head(&sq->open_queue);
+ init_waitqueue_head(&sq->sync_queue);
+ sq->busy = 0;
+}
+
+static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
+ mode_t mode)
+{
+ if (file->f_mode & mode) {
+ sq->busy = 0;
+ WAKE_UP(sq->open_queue);
+ }
+}
+
+static int sq_open2(struct sound_queue *sq, struct file *file, mode_t mode,
+ int numbufs, int bufsize)
+{
+ int rc = 0;
+
+ if (file->f_mode & mode) {
+ if (sq->busy) {
+ rc = -EBUSY;
+ if (file->f_flags & O_NONBLOCK)
+ return rc;
+ rc = -EINTR;
+ while (sq->busy) {
+ SLEEP(sq->open_queue);
+ if (signal_pending(current))
+ return rc;
+ }
+ rc = 0;
+ }
+ sq->busy = 1; /* Let's play spot-the-race-condition */
+
+ if (sq_allocate_buffers(sq, numbufs, bufsize)) {
+ sq_wake_up(sq, file, mode);
+ return rc;
+ }
+
+ sq_setup(sq, numbufs, numbufs, bufsize);
+ sq->open_mode = file->f_mode;
+ }
+ return rc;
+}
+
+#define write_sq_init_waitqueue() sq_init_waitqueue(&write_sq)
+#define write_sq_wake_up(file) sq_wake_up(&write_sq, file, FMODE_WRITE)
+#define write_sq_release_buffers() sq_release_buffers(&write_sq)
+#define write_sq_open(file) \
+ sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize << 10)
+
+#ifdef HAS_RECORD
+#define read_sq_init_waitqueue() sq_init_waitqueue(&read_sq)
+#define read_sq_wake_up(file) sq_wake_up(&read_sq, file, FMODE_READ)
+#define read_sq_release_buffers() sq_release_buffers(&read_sq)
+#define read_sq_open(file) \
+ sq_open2(&read_sq, file, FMODE_READ, numReadBufs, readBufSize << 10)
+#else /* !HAS_RECORD */
+#define read_sq_init_waitqueue() do {} while (0)
+#define read_sq_wake_up(file) do {} while (0)
+#define read_sq_release_buffers() do {} while (0)
+#define read_sq_open(file) (0)
+#endif /* !HAS_RECORD */
+
+static int sq_open(struct inode *inode, struct file *file)
+{
+ int rc;
+
+ MOD_INC_USE_COUNT;
+ dmasound.mach.open();
+ if ((rc = write_sq_open(file)) || (rc = read_sq_open(file))) {
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+ return rc;
+ }
+
+ if (dmasound.mach.sq_open)
+ dmasound.mach.sq_open();
+ dmasound.minDev = MINOR(inode->i_rdev) & 0x0f;
+ dmasound.soft = dmasound.dsp;
+ dmasound.hard = dmasound.dsp;
+ sound_init();
+ if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+ sound_set_speed(8000);
+ sound_set_stereo(0);
+ sound_set_format(AFMT_MU_LAW);
+ }
+
+#if 0
+ if (file->f_mode == FMODE_READ && dmasound.mach.record) {
+ /* Start dma'ing straight away */
+ dmasound.mach.record();
+ }
+#endif
+
+ return 0;
+}
+
+static void sq_reset(void)
+{
+ sound_silence();
+ write_sq.active = 0;
+ write_sq.count = 0;
+ write_sq.front = (write_sq.rear+1) % write_sq.max_count;
+}
+
+static int sq_fsync(struct file *filp, struct dentry *dentry)
+{
+ int rc = 0;
+
+ write_sq.syncing = 1;
+ sq_play(); /* there may be an incomplete frame waiting */
+
+ while (write_sq.active) {
+ SLEEP(write_sq.sync_queue);
+ if (signal_pending(current)) {
+ /* While waiting for audio output to drain, an
+ * interrupt occurred. Stop audio output immediately
+ * and clear the queue. */
+ sq_reset();
+ rc = -EINTR;
+ break;
+ }
+ }
+
+ write_sq.syncing = 0;
+ return rc;
+}
+
+static int sq_release(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+
+ if (write_sq.busy)
+ rc = sq_fsync(file, file->f_dentry);
+ dmasound.soft = dmasound.dsp;
+ dmasound.hard = dmasound.dsp;
+ sound_silence();
+
+ write_sq_release_buffers();
+ read_sq_release_buffers();
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+
+ /* There is probably a DOS atack here. They change the mode flag. */
+ /* XXX add check here */
+ read_sq_wake_up(file);
+ write_sq_wake_up(file);
+
+ /* Wake up a process waiting for the queue being released.
+ * Note: There may be several processes waiting for a call
+ * to open() returning. */
+
+ return rc;
+}
+
+static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg)
+{
+ u_long fmt;
+ int data;
+ int size, nbufs;
+ audio_buf_info info;
+
+ switch (cmd) {
+ case SNDCTL_DSP_RESET:
+ sq_reset();
+ return 0;
+ case SNDCTL_DSP_POST:
+ case SNDCTL_DSP_SYNC:
+ return sq_fsync(file, file->f_dentry);
+
+ /* ++TeSche: before changing any of these it's
+ * probably wise to wait until sound playing has
+ * settled down. */
+ case SNDCTL_DSP_SPEED:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_speed(data));
+ case SNDCTL_DSP_STEREO:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_stereo(data));
+ case SOUND_PCM_WRITE_CHANNELS:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
+ case SNDCTL_DSP_SETFMT:
+ sq_fsync(file, file->f_dentry);
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, sound_set_format(data));
+ case SNDCTL_DSP_GETFMTS:
+ fmt = 0;
+ if (dmasound.trans_write) {
+ if (dmasound.trans_write->ct_ulaw)
+ fmt |= AFMT_MU_LAW;
+ if (dmasound.trans_write->ct_alaw)
+ fmt |= AFMT_A_LAW;
+ if (dmasound.trans_write->ct_s8)
+ fmt |= AFMT_S8;
+ if (dmasound.trans_write->ct_u8)
+ fmt |= AFMT_U8;
+ if (dmasound.trans_write->ct_s16be)
+ fmt |= AFMT_S16_BE;
+ if (dmasound.trans_write->ct_u16be)
+ fmt |= AFMT_U16_BE;
+ if (dmasound.trans_write->ct_s16le)
+ fmt |= AFMT_S16_LE;
+ if (dmasound.trans_write->ct_u16le)
+ fmt |= AFMT_U16_LE;
+ }
+ return IOCTL_OUT(arg, fmt);
+ case SNDCTL_DSP_GETBLKSIZE:
+ size = write_sq.block_size
+ * dmasound.soft.size * (dmasound.soft.stereo + 1)
+ / (dmasound.hard.size * (dmasound.hard.stereo + 1));
+ return IOCTL_OUT(arg, size);
+ case SNDCTL_DSP_SUBDIVIDE:
+ break;
+ case SNDCTL_DSP_SETFRAGMENT:
+ if (write_sq.count || write_sq.active || write_sq.syncing)
+ return -EINVAL;
+ IOCTL_IN(arg, size);
+ nbufs = size >> 16;
+ if (nbufs < 2 || nbufs > write_sq.numBufs)
+ nbufs = write_sq.numBufs;
+ size &= 0xffff;
+ if (size >= 8 && size <= 29) {
+ size = 1 << size;
+ size *= dmasound.hard.size * (dmasound.hard.stereo + 1);
+ size /= dmasound.soft.size * (dmasound.soft.stereo + 1);
+ if (size > write_sq.bufSize)
+ size = write_sq.bufSize;
+ } else
+ size = write_sq.bufSize;
+ sq_setup(&write_sq, write_sq.numBufs, nbufs, size);
+ return 0;
+ case SNDCTL_DSP_GETOSPACE:
+ info.fragments = write_sq.max_active - write_sq.count;
+ info.fragstotal = write_sq.max_active;
+ info.fragsize = write_sq.block_size;
+ info.bytes = info.fragments * info.fragsize;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+
+ default:
+ return mixer_ioctl(inode, file, cmd, arg);
+ }
+ return -EINVAL;
+}
+
+static struct file_operations sq_fops =
+{
+ llseek: sound_lseek,
+ write: sq_write,
+ ioctl: sq_ioctl,
+ open: sq_open,
+ release: sq_release,
+#ifdef HAS_RECORD
+ read: sq_read,
+#endif
+};
+
+static void __init sq_init(void)
+{
+#ifndef MODULE
+ int sq_unit;
+#endif
+ sq_unit = register_sound_dsp(&sq_fops, -1);
+ if (sq_unit < 0)
+ return;
+
+ write_sq_init_waitqueue();
+ read_sq_init_waitqueue();
+
+ /* whatever you like as startup mode for /dev/dsp,
+ * (/dev/audio hasn't got a startup mode). note that
+ * once changed a new open() will *not* restore these!
+ */
+ dmasound.dsp.format = AFMT_U8;
+ dmasound.dsp.stereo = 0;
+ dmasound.dsp.size = 8;
+
+ /* set minimum rate possible without expanding */
+ dmasound.dsp.speed = dmasound.mach.min_dsp_speed;
+
+ /* before the first open to /dev/dsp this wouldn't be set */
+ dmasound.soft = dmasound.dsp;
+ dmasound.hard = dmasound.dsp;
+
+ sound_silence();
+}
+
+
+ /*
+ * /dev/sndstat
+ */
+
+static struct {
+ int busy;
+ char buf[512]; /* state.buf should not overflow! */
+ int len, ptr;
+} state;
+
+static int state_open(struct inode *inode, struct file *file)
+{
+ char *buffer = state.buf;
+ int len = 0;
+
+ if (state.busy)
+ return -EBUSY;
+
+ MOD_INC_USE_COUNT;
+ dmasound.mach.open();
+ state.ptr = 0;
+ state.busy = 1;
+
+ len += sprintf(buffer+len, "%sDMA sound driver:\n", dmasound.mach.name);
+
+ len += sprintf(buffer+len, "\tsound.format = 0x%x",
+ dmasound.soft.format);
+ switch (dmasound.soft.format) {
+ case AFMT_MU_LAW:
+ len += sprintf(buffer+len, " (mu-law)");
+ break;
+ case AFMT_A_LAW:
+ len += sprintf(buffer+len, " (A-law)");
+ break;
+ case AFMT_U8:
+ len += sprintf(buffer+len, " (unsigned 8 bit)");
+ break;
+ case AFMT_S8:
+ len += sprintf(buffer+len, " (signed 8 bit)");
+ break;
+ case AFMT_S16_BE:
+ len += sprintf(buffer+len, " (signed 16 bit big)");
+ break;
+ case AFMT_U16_BE:
+ len += sprintf(buffer+len, " (unsigned 16 bit big)");
+ break;
+ case AFMT_S16_LE:
+ len += sprintf(buffer+len, " (signed 16 bit little)");
+ break;
+ case AFMT_U16_LE:
+ len += sprintf(buffer+len, " (unsigned 16 bit little)");
+ break;
+ }
+ len += sprintf(buffer+len, "\n");
+ len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+ dmasound.soft.speed, dmasound.hard.speed);
+ len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+ dmasound.soft.stereo,
+ dmasound.soft.stereo ? "stereo" : "mono");
+ if (dmasound.mach.state_info)
+ len += dmasound.mach.state_info(buffer);
+ len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
+ " sq.max_active = %d\n",
+ write_sq.block_size, write_sq.max_count,
+ write_sq.max_active);
+ len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n",
+ write_sq.count, write_sq.rear_size);
+ len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
+ write_sq.active, write_sq.syncing);
+ state.len = len;
+ return 0;
+}
+
+static int state_release(struct inode *inode, struct file *file)
+{
+ state.busy = 0;
+ dmasound.mach.release();
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static ssize_t state_read(struct file *file, char *buf, size_t count,
+ loff_t *ppos)
+{
+ int n = state.len - state.ptr;
+ if (n > count)
+ n = count;
+ if (n <= 0)
+ return 0;
+ if (copy_to_user(buf, &state.buf[state.ptr], n))
+ return -EFAULT;
+ state.ptr += n;
+ return n;
+}
+
+static struct file_operations state_fops =
+{
+ llseek: sound_lseek,
+ read: state_read,
+ open: state_open,
+ release: state_release,
+};
+
+static void __init state_init(void)
+{
+#ifndef MODULE
+ int state_unit;
+#endif
+ state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
+ if (state_unit < 0)
+ return;
+ state.busy = 0;
+}
+
+
+ /*
+ * Config & Setup
+ *
+ * This function is called by _one_ chipset-specific driver
+ */
+
+int __init dmasound_init(void)
+{
+ if (irq_installed)
+ return -EBUSY;
+
+ /* Set up sound queue, /dev/audio and /dev/dsp. */
+
+ /* Set default settings. */
+ sq_init();
+
+ /* Set up /dev/sndstat. */
+ state_init();
+
+ /* Set up /dev/mixer. */
+ mixer_init();
+
+ if (!dmasound.mach.irqinit()) {
+ printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
+ return -ENODEV;
+ }
+#ifdef MODULE
+ irq_installed = 1;
+#endif
+
+ printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
+ numWriteBufs, writeBufSize);
+
+ return 0;
+}
+
+#ifdef MODULE
+
+void dmasound_deinit(void)
+{
+ if (irq_installed) {
+ sound_silence();
+ dmasound.mach.irqcleanup();
+ }
+
+ write_sq_release_buffers();
+ read_sq_release_buffers();
+
+ if (mixer_unit >= 0)
+ unregister_sound_mixer(mixer_unit);
+ if (state_unit >= 0)
+ unregister_sound_special(state_unit);
+ if (sq_unit >= 0)
+ unregister_sound_dsp(sq_unit);
+}
+
+#else /* !MODULE */
+
+static int __init dmasound_setup(char *str)
+{
+ int ints[6];
+
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+
+ /* check the bootstrap parameter for "dmasound=" */
+
+ switch (ints[0]) {
+ case 3:
+ if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
+ printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+ else
+ catchRadius = ints[3];
+ /* fall through */
+ case 2:
+ if (ints[1] < MIN_BUFFERS)
+ printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs);
+ else
+ numWriteBufs = ints[1];
+ if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
+ printk("dmasound_setup: illegal buffer size, using default = %dK\n", writeBufSize);
+ else
+ writeBufSize = ints[2];
+ break;
+ case 0:
+ break;
+ default:
+ printk("dmasound_setup: illegal number of arguments\n");
+ return 0;
+ }
+ return 1;
+}
+
+__setup("dmasound=", dmasound_setup);
+
+#endif /* !MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(dmasound);
+EXPORT_SYMBOL(dmasound_init);
+#ifdef MODULE
+EXPORT_SYMBOL(dmasound_deinit);
+#endif
+EXPORT_SYMBOL(dmasound_write_sq);
+#ifdef HAS_RECORD
+EXPORT_SYMBOL(dmasound_read_sq);
+#endif
+EXPORT_SYMBOL(dmasound_catchRadius);
+#ifdef HAS_8BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma8);
+EXPORT_SYMBOL(dmasound_alaw2dma8);
+#endif
+#ifdef HAS_16BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma16);
+EXPORT_SYMBOL(dmasound_alaw2dma16);
+#endif
+#ifdef HAS_14BIT_TABLES
+EXPORT_SYMBOL(dmasound_ulaw2dma14l);
+EXPORT_SYMBOL(dmasound_ulaw2dma14h);
+EXPORT_SYMBOL(dmasound_alaw2dma14l);
+EXPORT_SYMBOL(dmasound_alaw2dma14h);
+#endif
+
diff --git a/drivers/sound/dmasound/dmasound_paula.c b/drivers/sound/dmasound/dmasound_paula.c
new file mode 100644
index 000000000..97e9e6cf8
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_paula.c
@@ -0,0 +1,690 @@
+
+/*
+ * linux/drivers/sound/dmasound_paula.c
+ *
+ * Amiga DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+
+#include "dmasound.h"
+
+
+ /*
+ * The minimum period for audio depends on htotal (for OCS/ECS/AGA)
+ * (Imported from arch/m68k/amiga/amisound.c)
+ *
+ * FIXME: if amifb is not used, there should be a method to change htotal
+ */
+
+extern volatile u_short amiga_audio_min_period;
+
+
+ /*
+ * amiga_mksound() should be able to restore the period after beeping
+ * (Imported from arch/m68k/amiga/amisound.c)
+ */
+
+extern u_short amiga_audio_period;
+
+
+ /*
+ * Audio DMA masks
+ */
+
+#define AMI_AUDIO_OFF (DMAF_AUD0 | DMAF_AUD1 | DMAF_AUD2 | DMAF_AUD3)
+#define AMI_AUDIO_8 (DMAF_SETCLR | DMAF_MASTER | DMAF_AUD0 | DMAF_AUD1)
+#define AMI_AUDIO_14 (AMI_AUDIO_8 | DMAF_AUD2 | DMAF_AUD3)
+
+
+ /*
+ * Helper pointers for 16(14)-bit sound
+ */
+
+static int write_sq_block_size_half, write_sq_block_size_quarter;
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void AmiOpen(void);
+static void AmiRelease(void);
+static void *AmiAlloc(unsigned int size, int flags);
+static void AmiFree(void *obj, unsigned int size);
+static int AmiIrqInit(void);
+#ifdef MODULE
+static void AmiIrqCleanUp(void);
+#endif
+static void AmiSilence(void);
+static void AmiInit(void);
+static int AmiSetFormat(int format);
+static int AmiSetVolume(int volume);
+static int AmiSetTreble(int treble);
+static void AmiPlayNextFrame(int index);
+static void AmiPlay(void);
+static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);
+
+
+/*** Mid level stuff *********************************************************/
+
+static void AmiMixerInit(void);
+static int AmiMixerIoctl(u_int cmd, u_long arg);
+static void AmiWriteSqSetup(void);
+static int AmiStateInfo(char *buffer);
+
+
+/*** Translations ************************************************************/
+
+/* ++TeSche: radically changed for new expanding purposes...
+ *
+ * These two routines now deal with copying/expanding/translating the samples
+ * from user space into our buffer at the right frequency. They take care about
+ * how much data there's actually to read, how much buffer space there is and
+ * to convert samples into the right frequency/encoding. They will only work on
+ * complete samples so it may happen they leave some bytes in the input stream
+ * if the user didn't write a multiple of the current sample size. They both
+ * return the number of bytes they've used from both streams so you may detect
+ * such a situation. Luckily all programs should be able to cope with that.
+ *
+ * I think I've optimized anything as far as one can do in plain C, all
+ * variables should fit in registers and the loops are really short. There's
+ * one loop for every possible situation. Writing a more generalized and thus
+ * parameterized loop would only produce slower code. Feel free to optimize
+ * this in assembler if you like. :)
+ *
+ * I think these routines belong here because they're not yet really hardware
+ * independent, especially the fact that the Falcon can play 16bit samples
+ * only in stereo is hardcoded in both of them!
+ *
+ * ++geert: split in even more functions (one per format)
+ */
+
+
+ /*
+ * Native format
+ */
+
+static ssize_t ami_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed, ssize_t frameLeft)
+{
+ ssize_t count, used;
+
+ if (!dmasound.soft.stereo) {
+ void *p = &frame[*frameUsed];
+ count = min(userCount, frameLeft) & ~1;
+ used = count;
+ if (copy_from_user(p, userPtr, count))
+ return -EFAULT;
+ } else {
+ u_char *left = &frame[*frameUsed>>1];
+ u_char *right = left+write_sq_block_size_half;
+ count = min(userCount, frameLeft)>>1 & ~1;
+ used = count*2;
+ while (count > 0) {
+ if (get_user(*left++, userPtr++)
+ || get_user(*right++, userPtr++))
+ return -EFAULT;
+ count--;
+ }
+ }
+ *frameUsed += used;
+ return used;
+}
+
+
+ /*
+ * Copy and convert 8 bit data
+ */
+
+#define GENERATE_AMI_CT8(funcname, convsample) \
+static ssize_t funcname(const u_char *userPtr, size_t userCount, \
+ u_char frame[], ssize_t *frameUsed, \
+ ssize_t frameLeft) \
+{ \
+ ssize_t count, used; \
+ \
+ if (!dmasound.soft.stereo) { \
+ u_char *p = &frame[*frameUsed]; \
+ count = min(userCount, frameLeft) & ~1; \
+ used = count; \
+ while (count > 0) { \
+ u_char data; \
+ if (get_user(data, userPtr++)) \
+ return -EFAULT; \
+ *p++ = convsample(data); \
+ count--; \
+ } \
+ } else { \
+ u_char *left = &frame[*frameUsed>>1]; \
+ u_char *right = left+write_sq_block_size_half; \
+ count = min(userCount, frameLeft)>>1 & ~1; \
+ used = count*2; \
+ while (count > 0) { \
+ u_char data; \
+ if (get_user(data, userPtr++)) \
+ return -EFAULT; \
+ *left++ = convsample(data); \
+ if (get_user(data, userPtr++)) \
+ return -EFAULT; \
+ *right++ = convsample(data); \
+ count--; \
+ } \
+ } \
+ *frameUsed += used; \
+ return used; \
+}
+
+#define AMI_CT_ULAW(x) (dmasound_ulaw2dma8[(x)])
+#define AMI_CT_ALAW(x) (dmasound_alaw2dma8[(x)])
+#define AMI_CT_U8(x) ((x) ^ 0x80)
+
+GENERATE_AMI_CT8(ami_ct_ulaw, AMI_CT_ULAW)
+GENERATE_AMI_CT8(ami_ct_alaw, AMI_CT_ALAW)
+GENERATE_AMI_CT8(ami_ct_u8, AMI_CT_U8)
+
+
+ /*
+ * Copy and convert 16 bit data
+ */
+
+#define GENERATE_AMI_CT_16(funcname, convsample) \
+static ssize_t funcname(const u_char *userPtr, size_t userCount, \
+ u_char frame[], ssize_t *frameUsed, \
+ ssize_t frameLeft) \
+{ \
+ ssize_t count, used; \
+ u_short data; \
+ \
+ if (!dmasound.soft.stereo) { \
+ u_char *high = &frame[*frameUsed>>1]; \
+ u_char *low = high+write_sq_block_size_half; \
+ count = min(userCount, frameLeft)>>1 & ~1; \
+ used = count*2; \
+ while (count > 0) { \
+ if (get_user(data, ((u_short *)userPtr)++)) \
+ return -EFAULT; \
+ data = convsample(data); \
+ *high++ = data>>8; \
+ *low++ = (data>>2) & 0x3f; \
+ count--; \
+ } \
+ } else { \
+ u_char *lefth = &frame[*frameUsed>>2]; \
+ u_char *leftl = lefth+write_sq_block_size_quarter; \
+ u_char *righth = lefth+write_sq_block_size_half; \
+ u_char *rightl = righth+write_sq_block_size_quarter; \
+ count = min(userCount, frameLeft)>>2 & ~1; \
+ used = count*4; \
+ while (count > 0) { \
+ if (get_user(data, ((u_short *)userPtr)++)) \
+ return -EFAULT; \
+ data = convsample(data); \
+ *lefth++ = data>>8; \
+ *leftl++ = (data>>2) & 0x3f; \
+ if (get_user(data, ((u_short *)userPtr)++)) \
+ return -EFAULT; \
+ data = convsample(data); \
+ *righth++ = data>>8; \
+ *rightl++ = (data>>2) & 0x3f; \
+ count--; \
+ } \
+ } \
+ *frameUsed += used; \
+ return used; \
+}
+
+#define AMI_CT_S16BE(x) (x)
+#define AMI_CT_U16BE(x) ((x) ^ 0x8000)
+#define AMI_CT_S16LE(x) (le2be16((x)))
+#define AMI_CT_U16LE(x) (le2be16((x)) ^ 0x8000)
+
+GENERATE_AMI_CT_16(ami_ct_s16be, AMI_CT_S16BE)
+GENERATE_AMI_CT_16(ami_ct_u16be, AMI_CT_U16BE)
+GENERATE_AMI_CT_16(ami_ct_s16le, AMI_CT_S16LE)
+GENERATE_AMI_CT_16(ami_ct_u16le, AMI_CT_U16LE)
+
+
+static TRANS transAmiga = {
+ ct_ulaw: ami_ct_ulaw,
+ ct_alaw: ami_ct_alaw,
+ ct_s8: ami_ct_s8,
+ ct_u8: ami_ct_u8,
+ ct_s16be: ami_ct_s16be,
+ ct_u16be: ami_ct_u16be,
+ ct_s16le: ami_ct_s16le,
+ ct_u16le: ami_ct_u16le,
+};
+
+/*** Low level stuff *********************************************************/
+
+
+static void AmiOpen(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void AmiRelease(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static inline void StopDMA(void)
+{
+ custom.aud[0].audvol = custom.aud[1].audvol = 0;
+ custom.aud[2].audvol = custom.aud[3].audvol = 0;
+ custom.dmacon = AMI_AUDIO_OFF;
+}
+
+static void *AmiAlloc(unsigned int size, int flags)
+{
+ return amiga_chip_alloc((long)size, "dmasound [Paula]");
+}
+
+static void AmiFree(void *obj, unsigned int size)
+{
+ amiga_chip_free (obj);
+}
+
+static int __init AmiIrqInit(void)
+{
+ /* turn off DMA for audio channels */
+ StopDMA();
+
+ /* Register interrupt handler. */
+ if (request_irq(IRQ_AMIGA_AUD0, AmiInterrupt, 0, "DMA sound",
+ AmiInterrupt))
+ return 0;
+ return 1;
+}
+
+#ifdef MODULE
+static void AmiIrqCleanUp(void)
+{
+ /* turn off DMA for audio channels */
+ StopDMA();
+ /* release the interrupt */
+ free_irq(IRQ_AMIGA_AUD0, AmiInterrupt);
+}
+#endif /* MODULE */
+
+static void AmiSilence(void)
+{
+ /* turn off DMA for audio channels */
+ StopDMA();
+}
+
+
+static void AmiInit(void)
+{
+ int period, i;
+
+ AmiSilence();
+
+ if (dmasound.soft.speed)
+ period = amiga_colorclock/dmasound.soft.speed-1;
+ else
+ period = amiga_audio_min_period;
+ dmasound.hard = dmasound.soft;
+ dmasound.trans_write = &transAmiga;
+
+ if (period < amiga_audio_min_period) {
+ /* we would need to squeeze the sound, but we won't do that */
+ period = amiga_audio_min_period;
+ } else if (period > 65535) {
+ period = 65535;
+ }
+ dmasound.hard.speed = amiga_colorclock/(period+1);
+
+ for (i = 0; i < 4; i++)
+ custom.aud[i].audper = period;
+ amiga_audio_period = period;
+
+ AmiSetTreble(50); /* recommended for newer amiga models */
+}
+
+
+static int AmiSetFormat(int format)
+{
+ int size;
+
+ /* Amiga sound DMA supports 8bit and 16bit (pseudo 14 bit) modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return dmasound.soft.format;
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_U8:
+ case AFMT_S8:
+ size = 8;
+ break;
+ case AFMT_S16_BE:
+ case AFMT_U16_BE:
+ case AFMT_S16_LE:
+ case AFMT_U16_LE:
+ size = 16;
+ break;
+ default: /* :-) */
+ size = 8;
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = size;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = dmasound.soft.size;
+ }
+ AmiInit();
+
+ return format;
+}
+
+
+#define VOLUME_VOXWARE_TO_AMI(v) \
+ (((v) < 0) ? 0 : ((v) > 100) ? 64 : ((v) * 64)/100)
+#define VOLUME_AMI_TO_VOXWARE(v) ((v)*100/64)
+
+static int AmiSetVolume(int volume)
+{
+ dmasound.volume_left = VOLUME_VOXWARE_TO_AMI(volume & 0xff);
+ custom.aud[0].audvol = dmasound.volume_left;
+ dmasound.volume_right = VOLUME_VOXWARE_TO_AMI((volume & 0xff00) >> 8);
+ custom.aud[1].audvol = dmasound.volume_right;
+ if (dmasound.hard.size == 16) {
+ if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
+ custom.aud[2].audvol = 1;
+ custom.aud[3].audvol = 1;
+ } else {
+ custom.aud[2].audvol = 0;
+ custom.aud[3].audvol = 0;
+ }
+ }
+ return VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
+ (VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
+}
+
+static int AmiSetTreble(int treble)
+{
+ dmasound.treble = treble;
+ if (treble < 50)
+ ciaa.pra &= ~0x02;
+ else
+ ciaa.pra |= 0x02;
+ return treble;
+}
+
+
+#define AMI_PLAY_LOADED 1
+#define AMI_PLAY_PLAYING 2
+#define AMI_PLAY_MASK 3
+
+
+static void AmiPlayNextFrame(int index)
+{
+ u_char *start, *ch0, *ch1, *ch2, *ch3;
+ u_long size;
+
+ /* used by AmiPlay() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = write_sq.buffers[write_sq.front];
+ size = (write_sq.count == index ? write_sq.rear_size
+ : write_sq.block_size)>>1;
+
+ if (dmasound.hard.stereo) {
+ ch0 = start;
+ ch1 = start+write_sq_block_size_half;
+ size >>= 1;
+ } else {
+ ch0 = start;
+ ch1 = start;
+ }
+
+ custom.aud[0].audvol = dmasound.volume_left;
+ custom.aud[1].audvol = dmasound.volume_right;
+ if (dmasound.hard.size == 8) {
+ custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+ custom.aud[0].audlen = size;
+ custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+ custom.aud[1].audlen = size;
+ custom.dmacon = AMI_AUDIO_8;
+ } else {
+ size >>= 1;
+ custom.aud[0].audlc = (u_short *)ZTWO_PADDR(ch0);
+ custom.aud[0].audlen = size;
+ custom.aud[1].audlc = (u_short *)ZTWO_PADDR(ch1);
+ custom.aud[1].audlen = size;
+ if (dmasound.volume_left == 64 && dmasound.volume_right == 64) {
+ /* We can play pseudo 14-bit only with the maximum volume */
+ ch3 = ch0+write_sq_block_size_quarter;
+ ch2 = ch1+write_sq_block_size_quarter;
+ custom.aud[2].audvol = 1; /* we are being affected by the beeps */
+ custom.aud[3].audvol = 1; /* restoring volume here helps a bit */
+ custom.aud[2].audlc = (u_short *)ZTWO_PADDR(ch2);
+ custom.aud[2].audlen = size;
+ custom.aud[3].audlc = (u_short *)ZTWO_PADDR(ch3);
+ custom.aud[3].audlen = size;
+ custom.dmacon = AMI_AUDIO_14;
+ } else {
+ custom.aud[2].audvol = 0;
+ custom.aud[3].audvol = 0;
+ custom.dmacon = AMI_AUDIO_8;
+ }
+ }
+ write_sq.front = (write_sq.front+1) % write_sq.max_count;
+ write_sq.active |= AMI_PLAY_LOADED;
+}
+
+
+static void AmiPlay(void)
+{
+ int minframes = 1;
+
+ custom.intena = IF_AUD0;
+
+ if (write_sq.active & AMI_PLAY_LOADED) {
+ /* There's already a frame loaded */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
+
+ if (write_sq.active & AMI_PLAY_PLAYING)
+ /* Increase threshold: frame 1 is already being played */
+ minframes = 2;
+
+ if (write_sq.count < minframes) {
+ /* Nothing to do */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
+
+ if (write_sq.count <= minframes &&
+ write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ custom.intena = IF_SETCLR | IF_AUD0;
+ return;
+ }
+
+ AmiPlayNextFrame(minframes);
+
+ custom.intena = IF_SETCLR | IF_AUD0;
+}
+
+
+static void AmiInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ int minframes = 1;
+
+ custom.intena = IF_AUD0;
+
+ if (!write_sq.active) {
+ /* Playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(write_sq.sync_queue);
+ return;
+ }
+
+ if (write_sq.active & AMI_PLAY_PLAYING) {
+ /* We've just finished a frame */
+ write_sq.count--;
+ WAKE_UP(write_sq.action_queue);
+ }
+
+ if (write_sq.active & AMI_PLAY_LOADED)
+ /* Increase threshold: frame 1 is already being played */
+ minframes = 2;
+
+ /* Shift the flags */
+ write_sq.active = (write_sq.active<<1) & AMI_PLAY_MASK;
+
+ if (!write_sq.active)
+ /* No frame is playing, disable audio DMA */
+ StopDMA();
+
+ custom.intena = IF_SETCLR | IF_AUD0;
+
+ if (write_sq.count >= minframes)
+ /* Try to play the next frame */
+ AmiPlay();
+
+ if (!write_sq.active)
+ /* Nothing to play anymore.
+ Wake up a process waiting for audio output to drain. */
+ WAKE_UP(write_sq.sync_queue);
+}
+
+/*** Mid level stuff *********************************************************/
+
+
+/*
+ * /dev/mixer abstraction
+ */
+
+static void __init AmiMixerInit(void)
+{
+ dmasound.volume_left = 64;
+ dmasound.volume_right = 64;
+ custom.aud[0].audvol = dmasound.volume_left;
+ custom.aud[3].audvol = 1; /* For pseudo 14bit */
+ custom.aud[1].audvol = dmasound.volume_right;
+ custom.aud[2].audvol = 1; /* For pseudo 14bit */
+ dmasound.treble = 50;
+}
+
+static int AmiMixerIoctl(u_int cmd, u_long arg)
+{
+ int data;
+ switch (cmd) {
+ case SOUND_MIXER_READ_DEVMASK:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_TREBLE);
+ case SOUND_MIXER_READ_RECMASK:
+ return IOCTL_OUT(arg, 0);
+ case SOUND_MIXER_READ_STEREODEVS:
+ return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+ case SOUND_MIXER_READ_VOLUME:
+ return IOCTL_OUT(arg,
+ VOLUME_AMI_TO_VOXWARE(dmasound.volume_left) |
+ VOLUME_AMI_TO_VOXWARE(dmasound.volume_right) << 8);
+ case SOUND_MIXER_WRITE_VOLUME:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_volume(data));
+ case SOUND_MIXER_READ_TREBLE:
+ return IOCTL_OUT(arg, dmasound.treble);
+ case SOUND_MIXER_WRITE_TREBLE:
+ IOCTL_IN(arg, data);
+ return IOCTL_OUT(arg, dmasound_set_treble(data));
+ }
+ return -EINVAL;
+}
+
+
+static void AmiWriteSqSetup(void)
+{
+ write_sq_block_size_half = write_sq.block_size>>1;
+ write_sq_block_size_quarter = write_sq_block_size_half>>1;
+}
+
+
+static int AmiStateInfo(char *buffer)
+{
+ int len = 0;
+ len += sprintf(buffer+len, "\tsound.volume_left = %d [0...64]\n",
+ dmasound.volume_left);
+ len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n",
+ dmasound.volume_right);
+ return len;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machAmiga = {
+ name: "Amiga",
+ name2: "AMIGA",
+ open: AmiOpen,
+ release: AmiRelease,
+ dma_alloc: AmiAlloc,
+ dma_free: AmiFree,
+ irqinit: AmiIrqInit,
+#ifdef MODULE
+ irqcleanup: AmiIrqCleanUp,
+#endif /* MODULE */
+ init: AmiInit,
+ silence: AmiSilence,
+ setFormat: AmiSetFormat,
+ setVolume: AmiSetVolume,
+ setTreble: AmiSetTreble,
+ play: AmiPlay,
+ mixer_init: AmiMixerInit,
+ mixer_ioctl: AmiMixerIoctl,
+ write_sq_setup: AmiWriteSqSetup,
+ state_info: AmiStateInfo,
+ min_dsp_speed: 8000
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_paula_init(void)
+{
+ int err;
+
+ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) {
+ if (!request_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40,
+ "dmasound [Paula]"))
+ return -EBUSY;
+ dmasound.mach = machAmiga;
+ err = dmasound_init();
+ if (err)
+ release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
+ return err;
+ } else
+ return -ENODEV;
+}
+
+static void __exit dmasound_paula_cleanup(void)
+{
+ dmasound_deinit();
+ release_mem_region(CUSTOM_PHYSADDR+0xa0, 0x40);
+}
+
+module_init(dmasound_paula_init);
+module_exit(dmasound_paula_cleanup);
diff --git a/drivers/sound/dmasound/dmasound_q40.c b/drivers/sound/dmasound/dmasound_q40.c
new file mode 100644
index 000000000..1c4d43d94
--- /dev/null
+++ b/drivers/sound/dmasound/dmasound_q40.c
@@ -0,0 +1,587 @@
+
+/*
+ * linux/drivers/sound/dmasound_q40.c
+ *
+ * Q40 DMA Sound Driver
+ *
+ * See linux/drivers/sound/dmasound_core.c for copyright and credits
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+
+#include <asm/uaccess.h>
+#include <asm/q40_master.h>
+
+#include "dmasound.h"
+
+
+static int expand_bal; /* Balance factor for expanding (not volume!) */
+static int expand_data; /* Data for expanding */
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void Q40Open(void);
+static void Q40Release(void);
+static void *Q40Alloc(unsigned int size, int flags);
+static void Q40Free(void *, unsigned int);
+static int Q40IrqInit(void);
+#ifdef MODULE
+static void Q40IrqCleanUp(void);
+#endif
+static void Q40Silence(void);
+static void Q40Init(void);
+static int Q40SetFormat(int format);
+static int Q40SetVolume(int volume);
+static void Q40PlayNextFrame(int index);
+static void Q40Play(void);
+static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static void Q40Interrupt(void);
+
+
+/*** Mid level stuff *********************************************************/
+
+
+#if 1
+/* userCount, frameUsed, frameLeft == byte counts */
+static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+
+ used = count = min(userCount, frameLeft);
+ if (copy_from_user(p,userPtr,count))
+ return -EFAULT;
+ while (count > 0) {
+ *p = table[*p]+128;
+ p++;
+ count--;
+ }
+ *frameUsed += used ;
+ return used;
+}
+#else
+static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ u_char val;
+ int stereo = sound.soft.stereo;
+
+
+ frameLeft >>= 1;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data]+128;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = table[data]+128;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 2;
+ return stereo? used * 2: used;
+}
+#endif
+
+#if 1
+static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+
+ used = count = min(userCount, frameLeft);
+ if (copy_from_user(p,userPtr,count))
+ return -EFAULT;
+ while (count > 0) {
+ *p = *p + 128;
+ p++;
+ count--;
+ }
+ *frameUsed += used;
+ return used;
+}
+#else
+static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ u_char val;
+ int stereo = dmasound.soft.stereo;
+
+ frameLeft >>= 1;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data + 128;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data + 128;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 2;
+ return stereo? used * 2: used;
+}
+#endif
+
+#if 1
+static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+
+ used = count = min(userCount, frameLeft);
+ if (copy_from_user(p,userPtr,count))
+ return -EFAULT;
+ *frameUsed += used;
+ return used;
+}
+#else
+static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ ssize_t count, used;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ u_char val;
+ int stereo = dmasound.soft.stereo;
+
+
+ frameLeft >>= 1;
+ if (stereo)
+ userCount >>= 1;
+ used = count = min(userCount, frameLeft);
+ while (count > 0) {
+ u_char data;
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data;
+ *p++ = val;
+ if (stereo) {
+ if (get_user(data, userPtr++))
+ return -EFAULT;
+ val = data;
+ }
+ *p++ = val;
+ count--;
+ }
+ *frameUsed += used * 2;
+ return stereo? used * 2: used;
+}
+#endif
+
+/* a bit too complicated to optimise right now ..*/
+static ssize_t q40_ctx_law(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ unsigned char *table = (unsigned char *)
+ (dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
+ unsigned int data = expand_data;
+ u_char *p = (u_char *) &frame[*frameUsed];
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = table[c];
+ data += 0x80;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft);
+ utotal -= userCount;
+ return utotal;
+}
+
+
+static ssize_t q40_ctx_s8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ u_char *p = (u_char *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+
+
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = c ;
+ data += 0x80;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft);
+ utotal -= userCount;
+ return utotal;
+}
+
+
+static ssize_t q40_ctx_u8(const u_char *userPtr, size_t userCount,
+ u_char frame[], ssize_t *frameUsed,
+ ssize_t frameLeft)
+{
+ u_char *p = (u_char *) &frame[*frameUsed];
+ unsigned int data = expand_data;
+ int bal = expand_bal;
+ int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
+ int utotal, ftotal;
+
+ ftotal = frameLeft;
+ utotal = userCount;
+ while (frameLeft) {
+ u_char c;
+ if (bal < 0) {
+ if (userCount == 0)
+ break;
+ if (get_user(c, userPtr++))
+ return -EFAULT;
+ data = c ;
+ userCount--;
+ bal += hSpeed;
+ }
+ *p++ = data;
+ frameLeft--;
+ bal -= sSpeed;
+ }
+ expand_bal = bal;
+ expand_data = data;
+ *frameUsed += (ftotal - frameLeft) ;
+ utotal -= userCount;
+ return utotal;
+}
+
+
+static TRANS transQ40Normal = {
+ q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL
+};
+
+static TRANS transQ40Expanding = {
+ q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL
+};
+
+
+/*** Low level stuff *********************************************************/
+
+
+static void Q40Open(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void Q40Release(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+
+static void *Q40Alloc(unsigned int size, int flags)
+{
+ return kmalloc(size, flags); /* change to vmalloc */
+}
+
+static void Q40Free(void *ptr, unsigned int size)
+{
+ kfree(ptr);
+}
+
+static int __init Q40IrqInit(void)
+{
+ /* Register interrupt handler. */
+ request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+ "DMA sound", Q40Interrupt);
+
+ return(1);
+}
+
+
+#ifdef MODULE
+static void Q40IrqCleanUp(void)
+{
+ master_outb(0,SAMPLE_ENABLE_REG);
+ free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
+}
+#endif /* MODULE */
+
+
+static void Q40Silence(void)
+{
+ master_outb(0,SAMPLE_ENABLE_REG);
+ *DAC_LEFT=*DAC_RIGHT=0;
+}
+
+static char *q40_pp=NULL;
+static unsigned int q40_sc=0;
+
+static void Q40PlayNextFrame(int index)
+{
+ u_char *start;
+ u_long size;
+ u_char speed;
+
+ /* used by Q40Play() if all doubts whether there really is something
+ * to be played are already wiped out.
+ */
+ start = write_sq.buffers[write_sq.front];
+ size = (write_sq.count == index ? write_sq.rear_size : write_sq.block_size);
+
+ q40_pp=start;
+ q40_sc=size;
+
+ write_sq.front = (write_sq.front+1) % write_sq.max_count;
+ write_sq.active++;
+
+ speed=(dmasound.hard.speed==10000 ? 0 : 1);
+
+ master_outb( 0,SAMPLE_ENABLE_REG);
+ free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
+ if (dmasound.soft.stereo)
+ request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
+ "Q40 sound", Q40Interrupt);
+ else
+ request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
+ "Q40 sound", Q40Interrupt);
+
+ master_outb( speed, SAMPLE_RATE_REG);
+ master_outb( 1,SAMPLE_CLEAR_REG);
+ master_outb( 1,SAMPLE_ENABLE_REG);
+}
+
+static void Q40Play(void)
+{
+ unsigned long flags;
+
+ if (write_sq.active || write_sq.count<=0 ) {
+ /* There's already a frame loaded */
+ return;
+ }
+
+ /* nothing in the queue */
+ if (write_sq.count <= 1 && write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
+ /* hmmm, the only existing frame is not
+ * yet filled and we're not syncing?
+ */
+ return;
+ }
+ save_flags(flags); cli();
+ Q40PlayNextFrame(1);
+ restore_flags(flags);
+}
+
+static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ if (q40_sc>1){
+ *DAC_LEFT=*q40_pp++;
+ *DAC_RIGHT=*q40_pp++;
+ q40_sc -=2;
+ master_outb(1,SAMPLE_CLEAR_REG);
+ }else Q40Interrupt();
+}
+static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ if (q40_sc>0){
+ *DAC_LEFT=*q40_pp;
+ *DAC_RIGHT=*q40_pp++;
+ q40_sc --;
+ master_outb(1,SAMPLE_CLEAR_REG);
+ }else Q40Interrupt();
+}
+static void Q40Interrupt(void)
+{
+ if (!write_sq.active) {
+ /* playing was interrupted and sq_reset() has already cleared
+ * the sq variables, so better don't do anything here.
+ */
+ WAKE_UP(write_sq.sync_queue);
+ master_outb(0,SAMPLE_ENABLE_REG); /* better safe */
+ goto exit;
+ } else write_sq.active=0;
+ write_sq.count--;
+ Q40Play();
+
+ if (q40_sc<2)
+ { /* there was nothing to play, disable irq */
+ master_outb(0,SAMPLE_ENABLE_REG);
+ *DAC_LEFT=*DAC_RIGHT=0;
+ }
+ WAKE_UP(write_sq.action_queue);
+
+ exit:
+ master_outb(1,SAMPLE_CLEAR_REG);
+}
+
+
+static void Q40Init(void)
+{
+ int i, idx;
+ const int freq[] = {10000, 20000};
+
+ /* search a frequency that fits into the allowed error range */
+
+ idx = -1;
+ for (i = 0; i < 2; i++)
+ if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) <= catchRadius)
+ idx = i;
+
+ dmasound.hard = dmasound.soft;
+ /*sound.hard.stereo=1;*/ /* no longer true */
+ dmasound.hard.size=8;
+
+ if (idx > -1) {
+ dmasound.soft.speed = freq[idx];
+ dmasound.trans_write = &transQ40Normal;
+ } else
+ dmasound.trans_write = &transQ40Expanding;
+
+ Q40Silence();
+
+ if (dmasound.hard.speed > 20000) {
+ /* we would need to squeeze the sound, but we won't do that */
+ dmasound.hard.speed = 20000;
+ dmasound.trans_write = &transQ40Normal;
+ } else if (dmasound.hard.speed > 10000) {
+ dmasound.hard.speed = 20000;
+ } else {
+ dmasound.hard.speed = 10000;
+ }
+ expand_bal = -dmasound.soft.speed;
+}
+
+
+static int Q40SetFormat(int format)
+{
+ /* Q40 sound supports only 8bit modes */
+
+ switch (format) {
+ case AFMT_QUERY:
+ return(dmasound.soft.format);
+ case AFMT_MU_LAW:
+ case AFMT_A_LAW:
+ case AFMT_S8:
+ case AFMT_U8:
+ break;
+ default:
+ format = AFMT_S8;
+ }
+
+ dmasound.soft.format = format;
+ dmasound.soft.size = 8;
+ if (dmasound.minDev == SND_DEV_DSP) {
+ dmasound.dsp.format = format;
+ dmasound.dsp.size = 8;
+ }
+ Q40Init();
+
+ return(format);
+}
+
+static int Q40SetVolume(int volume)
+{
+ return 0;
+}
+
+
+/*** Machine definitions *****************************************************/
+
+
+static MACHINE machQ40 = {
+ name: "Q40",
+ name2: "Q40",
+ open: Q40Open,
+ release: Q40Release,
+ dma_alloc: Q40Alloc,
+ dma_free: Q40Free,
+ irqinit: Q40IrqInit,
+#ifdef MODULE
+ irqcleanup: Q40IrqCleanUp,
+#endif /* MODULE */
+ init: Q40Init,
+ silence: Q40Silence,
+ setFormat: Q40SetFormat,
+ setVolume: Q40SetVolume,
+ play: Q40Play
+};
+
+
+/*** Config & Setup **********************************************************/
+
+
+int __init dmasound_q40_init(void)
+{
+ if (MACH_IS_Q40) {
+ dmasound.mach = machQ40;
+ return dmasound_init();
+ } else
+ return -ENODEV;
+}
+
+static void __exit dmasound_q40_cleanup(void)
+{
+ dmasound_deinit();
+}
+
+module_init(dmasound_q40_init);
+module_exit(dmasound_q40_cleanup);
diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c
index bf605dbca..5ba9236a3 100644
--- a/drivers/sound/mad16.c
+++ b/drivers/sound/mad16.c
@@ -791,7 +791,7 @@ static int __init probe_mad16_mpu(struct address_info *hw_config)
mad_write(MC3_PORT, tmp | 0x04);
hw_config->driver_use_1 = SB_MIDI_ONLY;
- return sb_dsp_detect(hw_config, 0, 0);
+ return sb_dsp_detect(hw_config, 0, 0, NULL);
#else
/* assuming all later Mozart cards are identified as
* either 82C928 or Mozart. If so, following code attempts
diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h
index 6e24d6e89..f0afbe177 100644
--- a/drivers/sound/sb.h
+++ b/drivers/sound/sb.h
@@ -70,6 +70,13 @@ struct mixer_def {
typedef struct mixer_def mixer_tab[32][2];
typedef struct mixer_def mixer_ent;
+struct sb_module_options
+{
+ int esstype; /* ESS chip type */
+ int acer; /* Do acer notebook init? */
+ int sm_games; /* Logitech soundman games? */
+};
+
typedef struct sb_devc {
int dev;
@@ -128,7 +135,10 @@ typedef struct sb_devc {
int input_opened;
int midi_broken;
void (*midi_input_intr) (int dev, unsigned char data);
- void *midi_irq_cookie; /* IRQ cookie for the midi */
+ void *midi_irq_cookie; /* IRQ cookie for the midi */
+
+ struct sb_module_options sbmo; /* Module options */
+
} sb_devc;
/*
@@ -147,7 +157,7 @@ int sb_dsp_get_byte(sb_devc * devc);
int sb_dsp_reset (sb_devc *devc);
void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value);
unsigned int sb_getmixer (sb_devc *devc, unsigned int port);
-int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio);
+int sb_dsp_detect (struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo);
int sb_dsp_init (struct address_info *hw_config);
void sb_dsp_unload(struct address_info *hw_config, int sbmpu);
int sb_mixer_init(sb_devc *devc);
@@ -163,7 +173,6 @@ int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right);
int sb_audio_open(int dev, int mode);
void sb_audio_close(int dev);
-extern int acer;
extern sb_devc *last_sb;
/* From sb_common.c */
diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c
index 557a971a4..513e6aa24 100644
--- a/drivers/sound/sb_card.c
+++ b/drivers/sound/sb_card.c
@@ -32,6 +32,10 @@
* 13-03-2000 Added some more cards, thanks to Torsten Werner.
* Removed joystick and wavetable code, there are better places for them.
* Code cleanup plus some fixes.
+ * Alessandro Zummo <azummo@ita.flashnet.it>
+ *
+ * 26-03-2000 Fixed acer, esstype and sm_games module options.
+ * Alessandro Zummo <azummo@ita.flashnet.it>
*
*/
@@ -51,6 +55,22 @@ static int sbmpu = 0;
extern void *smw_free;
+/*
+ * Note DMA2 of -1 has the right meaning in the SB16 driver as well
+ * as here. It will cause either an error if it is needed or a fallback
+ * to the 8bit channel.
+ */
+
+static int __initdata mpu_io = 0;
+static int __initdata io = -1;
+static int __initdata irq = -1;
+static int __initdata dma = -1;
+static int __initdata dma16 = -1; /* Set this for modules that need it */
+static int __initdata type = 0; /* Can set this to a specific card type */
+static int __initdata esstype = 0; /* ESS chip type */
+static int __initdata acer = 0; /* Do acer notebook init? */
+static int __initdata sm_games = 0; /* Logitech soundman games? */
+
static void __init attach_sb_card(struct address_info *hw_config)
{
if(!sb_dsp_init(hw_config))
@@ -60,6 +80,8 @@ static void __init attach_sb_card(struct address_info *hw_config)
static int __init probe_sb(struct address_info *hw_config)
{
+ struct sb_module_options sbmo;
+
if (hw_config->io_base == -1 || hw_config->dma == -1 || hw_config->irq == -1)
{
printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n");
@@ -127,14 +149,21 @@ iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n",
}
#endif
- /* This is useless since is done by sb_dsp_detect - azummo */
+ /* This is useless since it is done by sb_dsp_detect - azummo */
if (check_region(hw_config->io_base, 16))
{
printk(KERN_ERR "sb_card: I/O port 0x%x is already in use\n\n", hw_config->io_base);
return 0;
}
- return sb_dsp_detect(hw_config, 0, 0);
+
+ /* Setup extra module options */
+
+ sbmo.acer = acer;
+ sbmo.sm_games = sm_games;
+ sbmo.esstype = esstype;
+
+ return sb_dsp_detect(hw_config, 0, 0, &sbmo);
}
static void __exit unload_sb(struct address_info *hw_config)
@@ -143,25 +172,11 @@ static void __exit unload_sb(struct address_info *hw_config)
sb_dsp_unload(hw_config, sbmpu);
}
-extern int esstype; /* ESS chip type */
-
static struct address_info cfg;
static struct address_info cfg_mpu;
struct pci_dev *sb_dev = NULL,
*mpu_dev = NULL;
-/*
- * Note DMA2 of -1 has the right meaning in the SB16 driver as well
- * as here. It will cause either an error if it is needed or a fallback
- * to the 8bit channel.
- */
-
-static int __initdata mpu_io = 0;
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1; /* Set this for modules that need it */
-static int __initdata type = 0; /* Can set this to a specific card type */
#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE
diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c
index 80c282a5d..ad9808049 100644
--- a/drivers/sound/sb_common.c
+++ b/drivers/sound/sb_common.c
@@ -53,14 +53,6 @@ static unsigned char jazz_dma_bits[] = {
0, 1, 0, 2, 0, 3, 0, 4
};
-/* Do acer notebook init? */
-int acer = 0;
-
-/* soundman games? */
-int sm_games = 0;
-
-extern int esstype;
-
void *smw_free = NULL;
/*
@@ -503,12 +495,16 @@ static void relocate_ess1688(sb_devc * devc)
#endif
}
-int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio)
+int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio, struct sb_module_options *sbmo)
{
sb_devc sb_info;
sb_devc *devc = &sb_info;
memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */
+
+ /* Copy module options in place */
+ if(sbmo) memcpy(&devc->sbmo, sbmo, sizeof(struct sb_module_options));
+
sb_info.my_mididev = -1;
sb_info.my_mixerdev = -1;
sb_info.dev = -1;
@@ -553,7 +549,7 @@ int sb_dsp_detect(struct address_info *hw_config, int pci, int pciio)
printk("Yamaha PCI mode.\n");
}
- if (acer)
+ if (devc->sbmo.acer)
{
cli();
inb(devc->base + 0x09);
@@ -1295,10 +1291,6 @@ void unload_sbmpu(struct address_info *hw_config)
unload_uart401(hw_config);
}
-MODULE_PARM(acer, "i");
-MODULE_PARM(sm_games, "i");
-MODULE_PARM(esstype, "i");
-
EXPORT_SYMBOL(sb_dsp_init);
EXPORT_SYMBOL(sb_dsp_detect);
EXPORT_SYMBOL(sb_dsp_unload);
diff --git a/drivers/sound/sb_ess.c b/drivers/sound/sb_ess.c
index b6c9f0aee..dfb59016b 100644
--- a/drivers/sound/sb_ess.c
+++ b/drivers/sound/sb_ess.c
@@ -196,8 +196,6 @@
#define ESSTYPE_LIKE20 -1 /* Mimic 2.0 behaviour */
#define ESSTYPE_DETECT 0 /* Mimic 2.0 behaviour */
-int esstype = ESSTYPE_DETECT; /* module parameter in sb_card.c */
-
#define SUBMDL_ES1788 0x10 /* Subtype ES1788 for specific handling */
#define SUBMDL_ES1868 0x11 /* Subtype ES1868 for specific handling */
#define SUBMDL_ES1869 0x12 /* Subtype ES1869 for specific handling */
@@ -1066,7 +1064,7 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
char *chip = NULL;
int submodel = -1;
- switch (esstype) {
+ switch (devc->sbmo.esstype) {
case ESSTYPE_DETECT:
case ESSTYPE_LIKE20:
break;
@@ -1098,12 +1096,12 @@ int ess_init(sb_devc * devc, struct address_info *hw_config)
submodel = SUBMDL_ES1888;
break;
default:
- printk (KERN_ERR "Invalid esstype=%d specified\n", esstype);
+ printk (KERN_ERR "Invalid esstype=%d specified\n", devc->sbmo.esstype);
return 0;
};
if (submodel != -1) {
devc->submodel = submodel;
- sprintf (modelname, "ES%d", esstype);
+ sprintf (modelname, "ES%d", devc->sbmo.esstype);
chip = modelname;
};
if (chip == NULL && (ess_minor & 0x0f) < 8) {
@@ -1116,7 +1114,7 @@ FKS_test (devc);
* If Nothing detected yet, and we want 2.0 behaviour...
* Then let's assume it's ES1688.
*/
- if (chip == NULL && esstype == ESSTYPE_LIKE20) {
+ if (chip == NULL && devc->sbmo.esstype == ESSTYPE_LIKE20) {
chip = "ES1688";
};
@@ -1185,11 +1183,11 @@ FKS_test (devc);
printk ( KERN_INFO "ESS chip %s %s%s\n"
, chip
- , ( esstype == ESSTYPE_DETECT || esstype == ESSTYPE_LIKE20
+ , ( devc->sbmo.esstype == ESSTYPE_DETECT || devc->sbmo.esstype == ESSTYPE_LIKE20
? "detected"
: "specified"
)
- , ( esstype == ESSTYPE_LIKE20
+ , ( devc->sbmo.esstype == ESSTYPE_LIKE20
? " (kernel 2.0 compatible)"
: ""
)
diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c
index a955db7e3..5a5487b16 100644
--- a/drivers/sound/sb_mixer.c
+++ b/drivers/sound/sb_mixer.c
@@ -642,11 +642,10 @@ static void sb_mixer_reset(sb_devc * devc)
{
char name[32];
int i;
- extern int sm_games;
sprintf(name, "SB_%d", devc->sbmixnum);
- if (sm_games)
+ if (devc->sbmo.sm_games)
devc->levels = load_mixer_volumes(name, smg_default_levels, 1);
else
devc->levels = load_mixer_volumes(name, sb_default_levels, 1);
diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h
index 8d450ca66..ffa0c1caf 100644
--- a/drivers/sound/sound_calls.h
+++ b/drivers/sound/sound_calls.h
@@ -89,10 +89,3 @@ void sound_timer_syncinterval(unsigned int new_usecs);
/* From midi_synth.c */
void do_midi_msg (int synthno, unsigned char *msg, int mlen);
-
-#ifdef FIXED_LOWLEVEL_SOUND
-/* From aedsp16.c */
-int InitAEDSP16_SBPRO(struct address_info *hw_config);
-int InitAEDSP16_MSS(struct address_info *hw_config);
-int InitAEDSP16_MPU401(struct address_info *hw_config);
-#endif
diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c
index 217bdb605..c0d6dd06a 100644
--- a/drivers/sound/sound_core.c
+++ b/drivers/sound/sound_core.c
@@ -218,7 +218,7 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
static struct sound_unit *chains[16];
/**
- * register_sound_special
+ * register_sound_special - register a special sound node
* @fops: File operations for the driver
* @unit: Unit number to allocate
*
@@ -288,7 +288,7 @@ int register_sound_special(struct file_operations *fops, int unit)
EXPORT_SYMBOL(register_sound_special);
/**
- * register_sound_mixer
+ * register_sound_mixer - register a mixer device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -306,7 +306,7 @@ int register_sound_mixer(struct file_operations *fops, int dev)
EXPORT_SYMBOL(register_sound_mixer);
/**
- * register_sound_midi
+ * register_sound_midi - register a midi device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -329,7 +329,7 @@ EXPORT_SYMBOL(register_sound_midi);
*/
/**
- * register_sound_dsp
+ * register_sound_dsp - register a DSP device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -350,7 +350,7 @@ int register_sound_dsp(struct file_operations *fops, int dev)
EXPORT_SYMBOL(register_sound_dsp);
/**
- * register_sound_synth
+ * register_sound_synth - register a synth device
* @fops: File operations for the driver
* @dev: Unit number to allocate
*
@@ -369,7 +369,7 @@ int register_sound_synth(struct file_operations *fops, int dev)
EXPORT_SYMBOL(register_sound_synth);
/**
- * unregister_sound_special
+ * unregister_sound_special - unregister a special sound device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_special.
@@ -385,7 +385,7 @@ void unregister_sound_special(int unit)
EXPORT_SYMBOL(unregister_sound_special);
/**
- * unregister_sound_mixer
+ * unregister_sound_mixer - unregister a mixer
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_mixer.
@@ -400,7 +400,7 @@ void unregister_sound_mixer(int unit)
EXPORT_SYMBOL(unregister_sound_mixer);
/**
- * unregister_sound_midi
+ * unregister_sound_midi - unregister a midi device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_midi.
@@ -415,7 +415,7 @@ void unregister_sound_midi(int unit)
EXPORT_SYMBOL(unregister_sound_midi);
/**
- * unregister_sound_dsp
+ * unregister_sound_dsp - unregister a DSP device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_dsp.
@@ -433,7 +433,7 @@ void unregister_sound_dsp(int unit)
EXPORT_SYMBOL(unregister_sound_dsp);
/**
- * unregister_sound_synth
+ * unregister_sound_synth - unregister a synth device
* @unit: Unit number to allocate
*
* Release a sound device that was allocated with register_sound_synth.
diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c
index f3b008f0c..f222592ea 100644
--- a/drivers/sound/soundcard.c
+++ b/drivers/sound/soundcard.c
@@ -46,14 +46,6 @@
#include "soundmodule.h"
-#if defined(CONFIG_LOWLEVEL_SOUND) && !defined MODULE
-extern void sound_preinit_lowlevel_drivers(void);
-extern void sound_init_lowlevel_drivers(void);
-#endif
-
-/* From obsolete legacy.h */
-#define SELECTED_SOUND_OPTIONS 0x0
-
struct notifier_block *sound_locker=(struct notifier_block *)0;
static int lock_depth = 0;
@@ -65,7 +57,6 @@ static int lock_depth = 0;
#endif
static int chrdev_registered = 0;
-static int is_unloading = 0;
/*
* Table for permanently allocated memory (used when unloading the module)
@@ -80,7 +71,6 @@ int sound_dmap_flag = 1;
int sound_dmap_flag = 0;
#endif
-static int soundcard_configured = 0;
static char dma_alloc_map[MAX_DMA_CHANNELS] = {0};
#define DMA_MAP_UNAVAIL 0
@@ -101,17 +91,14 @@ int *load_mixer_volumes(char *name, int *levels, int present)
{
int i, n;
- for (i = 0; i < num_mixer_volumes; i++)
- {
- if (strcmp(name, mixer_vols[i].name) == 0)
- {
+ for (i = 0; i < num_mixer_volumes; i++) {
+ if (strcmp(name, mixer_vols[i].name) == 0) {
if (present)
mixer_vols[i].num = i;
return mixer_vols[i].levels;
}
}
- if (num_mixer_volumes >= MAX_MIXER_DEV)
- {
+ if (num_mixer_volumes >= MAX_MIXER_DEV) {
printk(KERN_ERR "Sound: Too many mixers (%s)\n", name);
return levels;
}
@@ -229,26 +216,15 @@ static long long sound_lseek(struct file *file, long long offset, int orig)
static int sound_open(struct inode *inode, struct file *file)
{
- int dev, retval;
+ int dev = MINOR(inode->i_rdev);
+ int retval;
- if (is_unloading) {
- /* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/
- return -EBUSY;
- }
- dev = MINOR(inode->i_rdev);
- if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) {
- /* printk("SoundCard Error: The sound system has not been configured\n");*/
- return -ENXIO;
- }
DEB(printk("sound_open(dev=%d)\n", dev));
if ((dev >= SND_NDEVS) || (dev < 0)) {
/* printk(KERN_ERR "Invalid minor device %d\n", dev);*/
return -ENXIO;
}
switch (dev & 0x0f) {
- case SND_DEV_STATUS:
- break;
-
case SND_DEV_CTL:
dev >>= 4;
if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
@@ -296,7 +272,6 @@ static int sound_release(struct inode *inode, struct file *file)
DEB(printk("sound_release(dev=%d)\n", dev));
switch (dev & 0x0f) {
- case SND_DEV_STATUS:
case SND_DEV_CTL:
break;
@@ -470,45 +445,38 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma)
dev_class = dev & 0x0f;
dev >>= 4;
- if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO)
- {
-/* printk("Sound: mmap() not supported for other than audio devices\n");*/
+ if (dev_class != SND_DEV_DSP && dev_class != SND_DEV_DSP16 && dev_class != SND_DEV_AUDIO) {
+ printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n");
return -EINVAL;
}
if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */
dmap = audio_devs[dev]->dmap_out;
else if (vma->vm_flags & VM_READ)
dmap = audio_devs[dev]->dmap_in;
- else
- {
-/* printk("Sound: Undefined mmap() access\n");*/
+ else {
+ printk(KERN_ERR "Sound: Undefined mmap() access\n");
return -EINVAL;
}
- if (dmap == NULL)
- {
-/* printk("Sound: mmap() error. dmap == NULL\n");*/
+ if (dmap == NULL) {
+ printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n");
return -EIO;
}
- if (dmap->raw_buf == NULL)
- {
-/* printk("Sound: mmap() called when raw_buf == NULL\n");*/
+ if (dmap->raw_buf == NULL) {
+ printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n");
return -EIO;
}
- if (dmap->mapping_flags)
- {
-/* printk("Sound: mmap() called twice for the same DMA buffer\n");*/
+ if (dmap->mapping_flags) {
+ printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n");
return -EIO;
}
- if (vma->vm_pgoff != 0)
- {
-/* printk("Sound: mmap() offset must be 0.\n");*/
+ if (vma->vm_pgoff != 0) {
+ printk(KERN_ERR "Sound: mmap() offset must be 0.\n");
return -EINVAL;
}
size = vma->vm_end - vma->vm_start;
- if (size != dmap->bytes_in_use)
- {
+ if (size != dmap->bytes_in_use) {
printk(KERN_WARNING "Sound: mmap() size = %ld. Should be %d\n", size, dmap->bytes_in_use);
}
if (remap_page_range(vma->vm_start, virt_to_phys(dmap->raw_buf),
@@ -546,19 +514,14 @@ struct file_operations oss_sound_fops =
static int create_special_devices(void)
{
int seq1,seq2;
- int sndstat=register_sound_special(&oss_sound_fops, 6);
- if(sndstat==-1)
- goto bad1;
seq1=register_sound_special(&oss_sound_fops, 1);
if(seq1==-1)
- goto bad2;
+ goto bad;
seq2=register_sound_special(&oss_sound_fops, 8);
if(seq2!=-1)
return 0;
unregister_sound_special(1);
-bad2:
- unregister_sound_special(6);
-bad1:
+bad:
return -1;
}
@@ -594,30 +557,27 @@ soundcard_make_name(char *buf, char *name, int idx) {
/* Register/unregister audio entries */
static void soundcard_register_devfs (int do_register)
{
- char name_buf[32];
- int i, j, num;
-
- for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++)
- {
- num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num;
- for (j = 0; j < num || j == 0; j++)
- {
- soundcard_make_name (name_buf, dev_list[i].name, j);
- if (do_register)
- devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
- SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
- S_IFCHR | dev_list[i].mode, 0, 0,
- &oss_sound_fops, NULL);
- else
- {
- devfs_handle_t de;
-
- de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
+ char name_buf[32];
+ int i, j, num;
+
+ for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) {
+ num = (dev_list[i].num == NULL) ? 0 : *dev_list[i].num;
+ for (j = 0; j < num || j == 0; j++) {
+ soundcard_make_name (name_buf, dev_list[i].name, j);
+ if (do_register)
+ devfs_register (NULL, name_buf, 0, DEVFS_FL_NONE,
+ SOUND_MAJOR, dev_list[i].minor+ (j* 0x10),
+ S_IFCHR | dev_list[i].mode, 0, 0,
+ &oss_sound_fops, NULL);
+ else {
+ devfs_handle_t de;
+
+ de = devfs_find_handle (NULL, name_buf, 0, 0, 0,
DEVFS_SPECIAL_CHR, 0);
- devfs_unregister (de);
- }
+ devfs_unregister (de);
+ }
+ }
}
- }
}
#ifdef MODULE
@@ -638,10 +598,6 @@ soundcard_init(void)
chrdev_registered = 1;
#endif
- soundcard_configured = 1;
-
- audio_init_devices();
-
soundcard_register_devfs(1); /* register after we know # of devices */
}
@@ -650,14 +606,9 @@ soundcard_init(void)
static void destroy_special_devices(void)
{
unregister_sound_special(6);
- unregister_sound_special(1);
unregister_sound_special(8);
}
-static int sound[20] = {
- 0
-};
-
static int dmabuf = 0;
static int dmabug = 0;
@@ -668,12 +619,12 @@ int init_module(void)
{
int err;
+#ifdef CONFIG_PCI
if(dmabug)
isa_dma_bridge_buggy = dmabug;
-
+#endif
err = create_special_devices();
- if (err)
- {
+ if (err) {
printk(KERN_ERR "sound: driver already loaded/included in kernel\n");
return err;
}
@@ -695,10 +646,8 @@ void cleanup_module(void)
int i;
if (MOD_IN_USE)
- {
return;
- }
- remove_proc_entry("sound", NULL);
+
soundcard_register_devfs (0);
if (chrdev_registered)
destroy_special_devices();
@@ -708,17 +657,13 @@ void cleanup_module(void)
sequencer_unload();
for (i = 0; i < MAX_DMA_CHANNELS; i++)
- {
- if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
- {
+ if (dma_alloc_map[i] != DMA_MAP_UNAVAIL) {
printk(KERN_ERR "Sound: Hmm, DMA%d was left allocated - fixed\n", i);
sound_free_dma(i);
}
- }
+
for (i = 0; i < sound_nblocks; i++)
- {
vfree(sound_mem_blocks[i]);
- }
}
#endif
@@ -739,16 +684,14 @@ int sound_open_dma(int chn, char *deviceID)
{
unsigned long flags;
- if (!valid_dma(chn))
- {
+ if (!valid_dma(chn)) {
printk(KERN_ERR "sound_open_dma: Invalid DMA channel %d\n", chn);
return 1;
}
save_flags(flags);
cli();
- if (dma_alloc_map[chn] != DMA_MAP_FREE)
- {
+ if (dma_alloc_map[chn] != DMA_MAP_FREE) {
printk("sound_open_dma: DMA channel %d busy or not allocated (%d)\n", chn, dma_alloc_map[chn]);
restore_flags(flags);
return 1;
@@ -760,8 +703,7 @@ int sound_open_dma(int chn, char *deviceID)
void sound_free_dma(int chn)
{
- if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL)
- {
+ if (dma_alloc_map[chn] == DMA_MAP_UNAVAIL) {
/* printk( "sound_free_dma: Bad access to DMA channel %d\n", chn); */
return;
}
@@ -776,8 +718,7 @@ void sound_close_dma(int chn)
save_flags(flags);
cli();
- if (dma_alloc_map[chn] != DMA_MAP_BUSY)
- {
+ if (dma_alloc_map[chn] != DMA_MAP_BUSY) {
printk(KERN_ERR "sound_close_dma: Bad access to DMA channel %d\n", chn);
restore_flags(flags);
return;
@@ -799,8 +740,7 @@ void request_sound_timer(int count)
{
extern unsigned long seq_time;
- if (count < 0)
- {
+ if (count < 0) {
seq_timer.expires = (-count) + jiffies;
add_timer(&seq_timer);
return;
@@ -879,8 +819,7 @@ void sound_notifier_chain_register(struct notifier_block *bl)
* Normalise the lock count by calling the entry directly. We
* have to call the module as it owns its own use counter
*/
- while(ct<lock_depth)
- {
+ while(ct<lock_depth) {
bl->notifier_call(bl, 1, 0);
ct++;
}
diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c
index d36da3f9c..986544401 100644
--- a/drivers/sound/trix.c
+++ b/drivers/sound/trix.c
@@ -318,7 +318,7 @@ static int __init probe_trix_sb(struct address_info *hw_config)
sb_initialized = 1;
hw_config->name = "AudioTrix SB";
- return sb_dsp_detect(hw_config, 0, 0);
+ return sb_dsp_detect(hw_config, 0, 0, NULL);
}
static void __init attach_trix_sb(struct address_info *hw_config)
diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c
index 5745a9037..7f88b8177 100644
--- a/drivers/sound/via82cxxx_audio.c
+++ b/drivers/sound/via82cxxx_audio.c
@@ -486,7 +486,7 @@ static int __init via_probe_sb(struct address_info *hw_config)
return 0;
}
DPRINTK("EXIT after sb_dsp_detect\n");
- return sb_dsp_detect(hw_config, 0, 0);
+ return sb_dsp_detect(hw_config, 0, 0, NULL);
}