/*
*
* device driver for philips saa7134 based TV cards
* oss dsp interface
*
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
* 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/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
#include "saa7134-reg.h"
#include "saa7134.h"
/* ------------------------------------------------------------------ */
static unsigned int oss_debug = 0;
module_param(oss_debug, int, 0644);
MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]");
static unsigned int oss_rate = 0;
module_param(oss_rate, int, 0444);
MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
#define dprintk(fmt, arg...) if (oss_debug) \
printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
/* ------------------------------------------------------------------ */
static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
{
if (blksize < 0x100)
blksize = 0x100;
if (blksize > 0x10000)
blksize = 0x10000;
if (blocks < 2)
blocks = 2;
if ((blksize * blocks) > 1024*1024)
blocks = 1024*1024 / blksize;
dev->oss.blocks = blocks;
dev->oss.blksize = blksize;
dev->oss.bufsize = blksize * blocks;
dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
blocks,blksize,blksize * blocks / 1024);
return 0;
}
static int dsp_buffer_init(struct saa7134_dev *dev)
{
int err;
if (!dev->oss.bufsize)
BUG();
videobuf_dma_init(&dev->oss.dma);
err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
(dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
if (0 != err)
return err;
return 0;
}
static int dsp_buffer_free(struct saa7134_dev *dev)
{
if (!dev->oss.blksize)
BUG();
videobuf_dma_free(&dev->oss.dma);
dev->oss.blocks = 0;
dev->oss.blksize = 0;
dev->oss.bufsize = 0;
return 0;
}
static void dsp_dma_start(struct saa7134_dev *dev)
{
dev->oss.dma_blk = 0;
dev->oss.dma_running = 1;
saa7134_set_dmabits(dev);
}
static void dsp_dma_stop(struct saa7134_dev *dev)
{
dev->oss.dma_blk = -1;
dev->oss.dma_running = 0;
saa7134_set_dmabits(dev);
}
static int dsp_rec_start(struct saa7134_dev *dev)
{
int err, bswap, sign;
u32 fmt, control;
unsigned long flags;
/* prepare buffer */
if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
return err;
if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt)))
goto fail1;
if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt,
dev->oss.dma.sglist,
dev->oss.dma.sglen,
0)))
goto fail2;
/* sample format */
switch (dev->oss.afmt) {
case AFMT_U8:
case AFMT_S8: fmt = 0x00; break;
case AFMT_U16_LE:
case AFMT_U16_BE:
case AFMT_S16_LE:
case AFMT_S16_BE: fmt = 0x01; break;
default:
err = -EINVAL;
goto fail2;
}
switch (dev->oss.afmt) {
case AFMT_S8:
case AFMT_S16_LE:
case AFMT_S16_BE: sign = 1; break;
default: sign = 0; break;
}
switch (dev->oss.afmt) {
case AFMT_U16_BE:
case AFMT_S16_BE: bswap = 1; break;
default: bswap = 0; break;
}
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7134:
if (1 == dev->oss.channels)
fmt |= (1 << 3);
if (2 == dev->oss.channels)
fmt |= (3 << 3);
if (sign)
fmt |= 0x04;
fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & <