/*
btaudio - bt878 audio dma driver for linux 2.4.x
(c) 2000-2002 Gerd Knorr <kraxel@bytesex.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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.
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
#include <linux/slab.h>
#include <linux/kdev_t.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/* mmio access */
#define btwrite(dat,adr) writel((dat), (bta->mmio+(adr)))
#define btread(adr) readl(bta->mmio+(adr))
#define btand(dat,adr) btwrite((dat) & btread(adr), adr)
#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
/* registers (shifted because bta->mmio is long) */
#define REG_INT_STAT (0x100 >> 2)
#define REG_INT_MASK (0x104 >> 2)
#define REG_GPIO_DMA_CTL (0x10c >> 2)
#define REG_PACKET_LEN (0x110 >> 2)
#define REG_RISC_STRT_ADD (0x114 >> 2)
#define REG_RISC_COUNT (0x120 >> 2)
/* IRQ bits - REG_INT_(STAT|MASK) */
#define IRQ_SCERR (1 << 19)
#define IRQ_OCERR (1 << 18)
#define IRQ_PABORT (1 << 17)
#define IRQ_RIPERR (1 << 16)
#define IRQ_PPERR (1 << 15)
#define IRQ_FDSR (1 << 14)
#define IRQ_FTRGT (1 << 13)
#define IRQ_FBUS (1 << 12)
#define IRQ_RISCI (1 << 11)
#define IRQ_OFLOW (1 << 3)
#define IRQ_BTAUDIO (IRQ_SCERR | IRQ_OCERR | IRQ_PABORT | IRQ_RIPERR |\
IRQ_PPERR | IRQ_FDSR | IRQ_FTRGT | IRQ_FBUS |\
IRQ_RISCI)
/* REG_GPIO_DMA_CTL bits */
#define DMA_CTL_A_PWRDN (1 << 26)
#define DMA_CTL_DA_SBR (1 << 14)
#define DMA_CTL_DA_ES2 (1 << 13)
#define DMA_CTL_ACAP_EN (1 << 4)
#define DMA_CTL_RISC_EN (1 << 1)
#define DMA_CTL_FIFO_EN (1 << 0)
/* RISC instructions */
#define RISC_WRITE (0x01 << 28)
#define RISC_JUMP (0x07 << 28)
#define RISC_SYNC (0x08 << 28)
/* RISC bits */
#define RISC_WR_SOL (1 << 27)
#define RISC_WR_EOL (1 << 26)
#define RISC_IRQ (1 << 24)
#define RISC_SYNC_RESYNC (1 << 15)
#define RISC_SYNC_FM1 0x06
#define RISC_SYNC_VRO 0x0c
#define HWBASE_AD (448000)
/* -------------------------------------------------------------- */
struct btaudio {
/* linked list */
struct btaudio *next;
/* device info */
int dsp_digital;
int dsp_analog;
int mixer_dev;
struct pci_dev *pci;
unsigned int irq;
unsigned long mem;
unsigned long __iomem *mmio;
/* locking */
int users;
struct mutex lock;
/* risc instructions */
unsigned int risc_size;
unsigned long *risc_cpu;
dma_addr_t risc_dma;
/* audio data */
unsigned int buf_size;
unsigned char *buf_cpu;
dma_addr_t buf_dma;
/* buffer setup */
int line_bytes;
int line_count;
int block_bytes;
int block_count;
/* read fifo management */
int recording;
int dma_block;
int read_offset;
int read_count;
wait_queue_head_t readq;
/* settings */
int gain[3];
int source;
int bits;
int decimation;
int mixcount;
int sampleshift;
int channels;
int analog;
int rate;
};
struct cardinfo {
char *name;
int rate;
};
static struct btaudio *btaudios;
static unsigned int debug;
static unsigned int irq_debug;
/* -------------------------------------------------------------- */
#define BUF_DEFAULT 128*1024
#define BUF_MIN 8192
static int alloc_buffer(struct btaudio *bta)
{
if (NULL == bta->buf_cpu) {
for (bta->buf_size = BUF_DEFAULT; bta->buf_size >= BUF_MIN;
bta->buf_size = bta->buf_size >> 1) {
bta->buf_cpu = pci_alloc_consistent
(bta->pci, bta->buf_size, &bta->buf_dma);
if (NULL != bta->buf_cpu)
break;
}
if (NULL == bta->buf_cpu)
return -ENOMEM;
memset(bta->buf_cpu,0,bta->buf_size);
}
if (NULL == bta->risc_cpu) {
bta->risc_size = PAGE_SIZE;
bta->risc_cpu = pci_alloc_consistent
(bta->pci, bta