diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /drivers/sound/pas2_pcm.c | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'drivers/sound/pas2_pcm.c')
-rw-r--r-- | drivers/sound/pas2_pcm.c | 354 |
1 files changed, 197 insertions, 157 deletions
diff --git a/drivers/sound/pas2_pcm.c b/drivers/sound/pas2_pcm.c index e756431d6..63f6762a5 100644 --- a/drivers/sound/pas2_pcm.c +++ b/drivers/sound/pas2_pcm.c @@ -3,41 +3,16 @@ * sound/pas2_pcm.c * * The low level driver for the Pro Audio Spectrum ADC/DAC. - * - * Copyright by Hannu Savolainen 1993 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. 2. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * */ +#include <linux/config.h> #include "sound_config.h" -#ifdef CONFIGURE_SOUNDCARD +#if defined(CONFIG_PAS) && defined(CONFIG_AUDIO) -#include "pas.h" - -#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO) - -#define TRACE(WHAT) /* - * * * (WHAT) */ +#ifndef DEB +#define DEB(WHAT) +#endif #define PAS_PCM_INTRBITS (0x08) /* @@ -55,7 +30,9 @@ static unsigned char pcm_filter = 0; /* filter FLAG */ static unsigned char pcm_mode = PCM_NON; static unsigned long pcm_count = 0; static unsigned short pcm_bitsok = 8; /* mask of OK bits */ -static int my_devnum = 0; +static int pcm_busy = 0; +int pas_audiodev = 0; +static int open_mode = 0; int pcm_set_speed (int arg) @@ -63,55 +40,68 @@ pcm_set_speed (int arg) int foo, tmp; unsigned long flags; + if (arg == 0) + return pcm_speed; + if (arg > 44100) arg = 44100; if (arg < 5000) arg = 5000; - foo = (1193180 + (arg / 2)) / arg; - arg = 1193180 / foo; - if (pcm_channels & 2) - foo = foo >> 1; + { + foo = (596590 + (arg / 2)) / arg; + arg = 596590 / foo; + } + else + { + foo = (1193180 + (arg / 2)) / arg; + arg = 1193180 / foo; + } pcm_speed = arg; - tmp = pas_read (FILTER_FREQUENCY); + tmp = pas_read (0x0B8A); /* - * Set anti-aliasing filters according to sample rate. You really *NEED* - * to enable this feature for all normal recording unless you want to - * experiment with aliasing effects. - * These filters apply to the selected "recording" source. - * I (pfw) don't know the encoding of these 5 bits. The values shown - * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. -*/ + * Set anti-aliasing filters according to sample rate. You really *NEED* + * to enable this feature for all normal recording unless you want to + * experiment with aliasing effects. + * These filters apply to the selected "recording" source. + * I (pfw) don't know the encoding of these 5 bits. The values shown + * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. + * + * I cleared bit 5 of these values, since that bit controls the master + * mute flag. (Olav Wölfelschneider) + * + */ #if !defined NO_AUTO_FILTER_SET tmp &= 0xe0; if (pcm_speed >= 2 * 17897) - tmp |= 0x21; + tmp |= 0x01; else if (pcm_speed >= 2 * 15909) - tmp |= 0x22; + tmp |= 0x02; else if (pcm_speed >= 2 * 11931) - tmp |= 0x29; + tmp |= 0x09; else if (pcm_speed >= 2 * 8948) - tmp |= 0x31; + tmp |= 0x11; else if (pcm_speed >= 2 * 5965) - tmp |= 0x39; + tmp |= 0x19; else if (pcm_speed >= 2 * 2982) - tmp |= 0x24; + tmp |= 0x04; pcm_filter = tmp; #endif - DISABLE_INTR (flags); + save_flags (flags); + cli (); - pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (foo & 0xff, SAMPLE_RATE_TIMER); - pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER); - pas_write (tmp, FILTER_FREQUENCY); + pas_write (tmp & ~(0x40 | 0x80), 0x0B8A); + pas_write (0x00 | 0x30 | 0x04, 0x138B); + pas_write (foo & 0xff, 0x1388); + pas_write ((foo >> 8) & 0xff, 0x1388); + pas_write (tmp, 0x0B8A); - RESTORE_INTR (flags); + restore_flags (flags); return pcm_speed; } @@ -125,11 +115,11 @@ pcm_set_channels (int arg) if (arg != pcm_channels) { - pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL); + pas_write (pas_read (0xF8A) ^ 0x20, 0xF8A); pcm_channels = arg; - pcm_set_speed (pcm_speed);/* - * The speed must be reinitialized + pcm_set_speed (pcm_speed); /* + * The speed must be reinitialized */ } @@ -139,12 +129,15 @@ pcm_set_channels (int arg) int pcm_set_bits (int arg) { + if (arg == 0) + return pcm_bits; + if ((arg & pcm_bitsok) != arg) return pcm_bits; if (arg != pcm_bits) { - pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); + pas_write (pas_read (0x8389) ^ 0x04, 0x8389); pcm_bits = arg; } @@ -153,128 +146,144 @@ pcm_set_bits (int arg) } static int -pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +pas_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { - TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + int val; + + DEB (printk ("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) - return pcm_set_speed (arg); - return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg))); + return pcm_set_speed ((int) arg); + get_user (val, (int *) arg); + return ioctl_out (arg, pcm_set_speed (val)); break; case SOUND_PCM_READ_RATE: if (local) return pcm_speed; - return IOCTL_OUT (arg, pcm_speed); + return ioctl_out (arg, pcm_speed); break; case SNDCTL_DSP_STEREO: if (local) - return pcm_set_channels (arg + 1) - 1; - return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1); + return pcm_set_channels ((int) arg + 1) - 1; + get_user (val, (int *) arg); + return ioctl_out (arg, pcm_set_channels (val + 1) - 1); break; case SOUND_PCM_WRITE_CHANNELS: if (local) - return pcm_set_channels (arg); - return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg))); + return pcm_set_channels ((int) arg); + get_user (val, (int *) arg); + return ioctl_out (arg, pcm_set_channels (val)); break; case SOUND_PCM_READ_CHANNELS: if (local) return pcm_channels; - return IOCTL_OUT (arg, pcm_channels); + return ioctl_out (arg, pcm_channels); break; case SNDCTL_DSP_SETFMT: if (local) - return pcm_set_bits (arg); - return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg))); + return pcm_set_bits ((int) arg); + get_user (val, (int *) arg); + return ioctl_out (arg, pcm_set_bits (val)); break; case SOUND_PCM_READ_BITS: if (local) return pcm_bits; - return IOCTL_OUT (arg, pcm_bits); + return ioctl_out (arg, pcm_bits); case SOUND_PCM_WRITE_FILTER: /* * NOT YET IMPLEMENTED */ - if (IOCTL_IN (arg) > 1) - return IOCTL_OUT (arg, RET_ERROR (EINVAL)); + get_user (val, (int *) arg); + if (val > 1) + return -EINVAL; + pcm_filter = val; break; - pcm_filter = IOCTL_IN (arg); case SOUND_PCM_READ_FILTER: - return IOCTL_OUT (arg, pcm_filter); + return ioctl_out (arg, pcm_filter); break; default: - return RET_ERROR (EINVAL); + return -EINVAL; } - return RET_ERROR (EINVAL); + return -EINVAL; } static void -pas_pcm_reset (int dev) +pas_audio_reset (int dev) { - TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n")); + DEB (printk ("pas2_pcm.c: static void pas_audio_reset(void)\n")); - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); } static int -pas_pcm_open (int dev, int mode) +pas_audio_open (int dev, int mode) { int err; + unsigned long flags; + + DEB (printk ("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); - TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode)); + save_flags (flags); + cli (); + if (pcm_busy) + { + restore_flags (flags); + return -EBUSY; + } + + pcm_busy = 1; + restore_flags (flags); if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0) return err; - if (DMAbuf_open_dma (dev) < 0) - { - pas_remove_intr (PAS_PCM_INTRBITS); - return RET_ERROR (EBUSY); - } pcm_count = 0; + open_mode = mode; return 0; } static void -pas_pcm_close (int dev) +pas_audio_close (int dev) { unsigned long flags; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n")); + DEB (printk ("pas2_pcm.c: static void pas_audio_close(void)\n")); - DISABLE_INTR (flags); + save_flags (flags); + cli (); - pas_pcm_reset (dev); - DMAbuf_close_dma (dev); + pas_audio_reset (dev); pas_remove_intr (PAS_PCM_INTRBITS); pcm_mode = PCM_NON; - RESTORE_INTR (flags); + pcm_busy = 0; + restore_flags (flags); } static void -pas_pcm_output_block (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +pas_audio_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags, cnt; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count)); + DEB (printk ("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; - if (audio_devs[dev]->dmachan > 3) + if (audio_devs[dev]->dmachan1 > 3) cnt >>= 1; if (audio_devs[dev]->flags & DMA_AUTOMODE && @@ -284,133 +293,166 @@ pas_pcm_output_block (int dev, unsigned long buf, int count, * Auto mode on. No need to react */ - DISABLE_INTR (flags); + save_flags (flags); + cli (); - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, - PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, + 0xF8A); if (restart_dma) DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - if (audio_devs[dev]->dmachan > 3) + if (audio_devs[dev]->dmachan1 > 3) count >>= 1; if (count != pcm_count) { - pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); + pas_write (0x40 | 0x30 | 0x04, 0x138B); + pas_write (count & 0xff, 0x1389); + pas_write ((count >> 8) & 0xff, 0x1389); + pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); - pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); +#ifdef NO_TRIGGER + pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); +#endif pcm_mode = PCM_DAC; - RESTORE_INTR (flags); + restore_flags (flags); } static void -pas_pcm_start_input (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +pas_audio_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; int cnt; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count)); + DEB (printk ("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; - if (audio_devs[dev]->dmachan > 3) + if (audio_devs[dev]->dmachan1 > 3) cnt >>= 1; - if (audio_devs[my_devnum]->flags & DMA_AUTOMODE && + if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && intrflag && cnt == pcm_count) return; /* * Auto mode on. No need to react */ - DISABLE_INTR (flags); + save_flags (flags); + cli (); if (restart_dma) DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - if (audio_devs[dev]->dmachan > 3) + if (audio_devs[dev]->dmachan1 > 3) count >>= 1; if (count != pcm_count) { - pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); + pas_write (0x40 | 0x30 | 0x04, 0x138B); + pas_write (count & 0xff, 0x1389); + pas_write ((count >> 8) & 0xff, 0x1389); + pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); - pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); +#ifdef NO_TRIGGER + pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); +#endif pcm_mode = PCM_ADC; - RESTORE_INTR (flags); + restore_flags (flags); +} + +#ifndef NO_TRIGGER +static void +pas_audio_trigger (int dev, int state) +{ + unsigned long flags; + + save_flags (flags); + cli (); + state &= open_mode; + + if (state & PCM_ENABLE_OUTPUT) + pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); + else if (state & PCM_ENABLE_INPUT) + pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); + else + pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); + + restore_flags (flags); } +#endif static int -pas_pcm_prepare_for_input (int dev, int bsize, int bcount) +pas_audio_prepare_for_input (int dev, int bsize, int bcount) { return 0; } + static int -pas_pcm_prepare_for_output (int dev, int bsize, int bcount) +pas_audio_prepare_for_output (int dev, int bsize, int bcount) { return 0; } -static struct audio_operations pas_pcm_operations = +static struct audio_driver pas_audio_driver = +{ + pas_audio_open, + pas_audio_close, + pas_audio_output_block, + pas_audio_start_input, + pas_audio_ioctl, + pas_audio_prepare_for_input, + pas_audio_prepare_for_output, + pas_audio_reset, + pas_audio_reset, + NULL, + NULL, + NULL, + NULL, + pas_audio_trigger +}; + +static struct audio_operations pas_audio_operations = { "Pro Audio Spectrum", DMA_AUTOMODE, AFMT_U8 | AFMT_S16_LE, NULL, - pas_pcm_open, - pas_pcm_close, - pas_pcm_output_block, - pas_pcm_start_input, - pas_pcm_ioctl, - pas_pcm_prepare_for_input, - pas_pcm_prepare_for_output, - pas_pcm_reset, - pas_pcm_reset, - NULL, - NULL + &pas_audio_driver }; -long -pas_pcm_init (long mem_start, struct address_info *hw_config) +void +pas_pcm_init (struct address_info *hw_config) { - TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start)); + DEB (printk ("pas2_pcm.c: long pas_pcm_init()\n")); pcm_bitsok = 8; - if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE) + if (pas_read (0xEF8B) & 0x08) pcm_bitsok |= 16; pcm_set_speed (DSP_DEFAULT_SPEED); if (num_audiodevs < MAX_AUDIO_DEV) { - audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations; - audio_devs[my_devnum]->dmachan = hw_config->dma; - audio_devs[my_devnum]->buffcount = 1; - audio_devs[my_devnum]->buffsize = 2 * DSP_BUFFSIZE; + audio_devs[pas_audiodev = num_audiodevs++] = &pas_audio_operations; + audio_devs[pas_audiodev]->dmachan1 = hw_config->dma; + audio_devs[pas_audiodev]->buffsize = DSP_BUFFSIZE; } else printk ("PAS2: Too many PCM devices available\n"); - - return mem_start; } void @@ -425,21 +467,21 @@ pas_pcm_interrupt (unsigned char status, int cause) * block before the PCM chip proceeds to the next sample */ - if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE)) + if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) { - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, - PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, + 0xF8A); } switch (pcm_mode) { case PCM_DAC: - DMAbuf_outputintr (my_devnum, 1); + DMAbuf_outputintr (pas_audiodev, 1); break; case PCM_ADC: - DMAbuf_inputintr (my_devnum); + DMAbuf_inputintr (pas_audiodev); break; default: @@ -449,5 +491,3 @@ pas_pcm_interrupt (unsigned char status, int cause) } #endif - -#endif |