/*
* sound/oss/sb_audio.c
*
* Audio routines for Sound Blaster compatible cards.
*
*
* Copyright (C) by Hannu Savolainen 1993-1997
*
* OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*
* Changes
* Alan Cox : Formatting and clean ups
*
* Status
* Mostly working. Weird uart bug causing irq storms
*
* Daniel J. Rodriksson: Changes to make sb16 work full duplex.
* Maybe other 16 bit cards in this code could behave
* the same.
* Chris Rankin: Use spinlocks instead of CLI/STI
*/
#include <linux/spinlock.h>
#include "sound_config.h"
#include "sb_mixer.h"
#include "sb.h"
#include "sb_ess.h"
int sb_audio_open(int dev, int mode)
{
sb_devc *devc = audio_devs[dev]->devc;
unsigned long flags;
if (devc == NULL)
{
printk(KERN_ERR "Sound Blaster: incomplete initialization.\n");
return -ENXIO;
}
if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ)
{
if (mode == OPEN_READ)
return -EPERM;
}
spin_lock_irqsave(&devc->lock, flags);
if (devc->opened)
{
spin_unlock_irqrestore(&devc->lock, flags);
return -EBUSY;
}
if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
{
if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit"))
{
spin_unlock_irqrestore(&devc->lock, flags);
return -EBUSY;
}
}
devc->opened = mode;
spin_unlock_irqrestore(&devc->lock, flags);
devc->irq_mode = IMODE_NONE;
devc->irq_mode_16 = IMODE_NONE;
devc->fullduplex = devc->duplex &&
((mode & OPEN_READ) && (mode & OPEN_WRITE));
sb_dsp_reset(devc);
/* At first glance this check isn't enough, some ESS chips might not
* have a RECLEV. However if they don't common_mixer_set will refuse
* cause devc->iomap has no register mapping for RECLEV
*/
if (devc->model == MDL_ESS) ess_mixer_reload (devc, SOUND_MIXER_RECLEV);
/* The ALS007 seems to require that the DSP be removed from the output */
/* in order for recording to be activated properly. This is done by */
/* setting the appropriate bits of the output control register 4ch to */
/* zero. This code assumes that the output control registers are not */
/* used anywhere else and therefore the DSP bits are *always* ON for */
/* output and OFF for sampling. */
if (devc->submodel == SUBMDL_ALS007)
{
if (mode & OPEN_READ)
sb_setmixer(devc,ALS007_OUTPUT_CTRL2,
sb_getmixer(devc,ALS007_OUTPUT_CTRL2) & 0xf9);
else
sb_setmixer(devc,ALS007_OUTPUT_CTRL2,
sb_getmixer(devc,ALS007_OUTPUT_CTRL2) | 0x06);
}
return 0;
}
void sb_audio_close(int dev)
{
sb_devc *devc = audio_devs[dev]->devc;
/* fix things if mmap turned off fullduplex */
if(devc->duplex
&& !devc->fullduplex
&& (devc->opened & OPEN_READ) && (devc->opened & OPEN_WRITE))
{
struct dma_buffparms *dmap_temp;
dmap_temp = audio_devs[dev]->dmap_out;
audio_devs[dev]->dmap_out = audio_devs[dev]->dmap_in;
audio_devs[dev]->dmap_in = dmap_temp;
}
audio_devs[dev]->dmap_out->dma = devc->dma8;
audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ?
devc->dma16 : devc->dma8;
if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex)
sound_close_dma(devc->dma16);
/* For ALS007, turn DSP output back on if closing the device for read */
if ((devc->submodel == SUBMDL_ALS007) && (devc->opened & OPEN_READ))
{
sb_setmixer(devc,ALS007_OUTPUT_CTRL2,
sb_getmixer(devc,ALS007_OUTPUT_CTRL2