/* Analog Devices 1889 audio driver
*
* This is a driver for the AD1889 PCI audio chipset found
* on the HP PA-RISC [BCJ]-xxx0 workstations.
*
* Copyright (C) 2004-2005, Kyle McMartin <kyle@parisc-linux.org>
* Copyright (C) 2005, Thibaut Varene <varenet@parisc-linux.org>
* Based on the OSS AD1889 driver by Randolph Chung <tausq@debian.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* TODO:
* Do we need to take care of CCS register?
* Maybe we could use finer grained locking (separate locks for pb/cap)?
* Wishlist:
* Control Interface (mixer) support
* Better AC97 support (VSR...)?
* PM support
* MIDI support
* Game Port support
* SG DMA support (this will need *alot* of work)
*/
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/ac97_codec.h>
#include <asm/io.h>
#include "ad1889.h"
#include "ac97/ac97_id.h"
#define AD1889_DRVVER "Version: 1.7"
MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>, Thibaut Varene <t-bone@parisc-linux.org>");
MODULE_DESCRIPTION("Analog Devices AD1889 ALSA sound driver");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1889}}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the AD1889 soundcard.");
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for the AD1889 soundcard.");
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable AD1889 soundcard.");
static char *ac97_quirk[SNDRV_CARDS];
module_param_array(ac97_quirk, charp, NULL, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
#define DEVNAME "ad1889"
#define PFX DEVNAME ": "
/* let's use the global sound debug interfaces */
#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg)
/* keep track of some hw registers */
struct ad1889_register_state {
u16 reg; /* reg setup */
u32 addr; /* dma base address */
unsigned long size; /* DMA buffer size */
};
struct snd_ad1889 {
struct snd_card *card;
struct pci_dev *pci;
int irq;
unsigned long bar;
void __iomem *iobase;
struct snd_ac97 *ac97;
struct snd_ac97_bus *ac97_bus;
struct snd_pcm *pcm;
struct snd_info_entry *proc;
struct snd_pcm_substream *psubs;
struct snd_pcm_substream *csubs;
/* playback register state */
struct ad1889_register_state wave;
struct ad1889_register_state ramc;
spinlock_t lock;
};
static inline u16
ad1889_readw(struct snd_ad1889 *chip, unsigned reg)
{
return readw(chip->iobase + reg);
}
static inline void
ad1889_writew(struct snd_ad1889 *chip, unsigned reg, u16 val)
{
writew(val, chip->iobase + reg);
}
static inline u32
ad1889_readl(struct snd_ad1889 *chip, unsigned reg)
{
return readl(chip->iobase + reg);
}
static inline void
ad1889_writel(struct snd_ad1889 *chip, unsigned reg, u32 val)
{
writel(val, chip->iobase + reg);
}
static inline void
ad1889_unmute(struct snd_ad1889 *chip)
{
u16 st;
st = ad1889_readw(chip, AD_DS_WADA) &
~(AD_DS_WADA_RWAM | AD_DS_WADA_LWAM);
ad1889_writew(chip, AD_DS_WADA, st);
ad1889_readw(chip, AD_DS_WADA);
}
static inline void
ad1889_mute(struct snd_ad1889 *chip)
{
u16 st;
st = ad1889_readw(chip, AD_DS_WADA) | AD_DS_WADA_RWAM | AD_DS_WADA_LWAM;
ad1889_writew(chip, AD_DS_WADA, st);
ad1889_readw(chip, AD_DS_WADA);
}
static inline void
ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address)
{
ad1889_writel(chip, AD_DMA_ADCBA, address);
ad1889_writel(chip, AD_DMA_ADCCA, address