mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
93
drivers/media/pci/cx88/Kconfig
Normal file
93
drivers/media/pci/cx88/Kconfig
Normal file
|
@ -0,0 +1,93 @@
|
|||
config VIDEO_CX88
|
||||
tristate "Conexant 2388x (bt878 successor) support"
|
||||
depends on VIDEO_DEV && PCI && I2C && RC_CORE
|
||||
select I2C_ALGOBIT
|
||||
select VIDEO_BTCX
|
||||
select VIDEOBUF_DMA_SG
|
||||
select VIDEO_TUNER
|
||||
select VIDEO_TVEEPROM
|
||||
select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT
|
||||
---help---
|
||||
This is a video4linux driver for Conexant 2388x based
|
||||
TV cards.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cx8800
|
||||
|
||||
config VIDEO_CX88_ALSA
|
||||
tristate "Conexant 2388x DMA audio support"
|
||||
depends on VIDEO_CX88 && SND
|
||||
select SND_PCM
|
||||
---help---
|
||||
This is a video4linux driver for direct (DMA) audio on
|
||||
Conexant 2388x based TV cards using ALSA.
|
||||
|
||||
It only works with boards with function 01 enabled.
|
||||
To check if your board supports, use lspci -n.
|
||||
If supported, you should see 14f1:8801 or 14f1:8811
|
||||
PCI device.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cx88-alsa.
|
||||
|
||||
config VIDEO_CX88_BLACKBIRD
|
||||
tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
|
||||
depends on VIDEO_CX88
|
||||
select VIDEO_CX2341X
|
||||
---help---
|
||||
This adds support for MPEG encoder cards based on the
|
||||
Blackbird reference design, using the Conexant 2388x
|
||||
and 23416 chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cx88-blackbird.
|
||||
|
||||
config VIDEO_CX88_DVB
|
||||
tristate "DVB/ATSC Support for cx2388x based TV cards"
|
||||
depends on VIDEO_CX88 && DVB_CORE
|
||||
select VIDEOBUF_DVB
|
||||
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_OR51132 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT
|
||||
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
|
||||
---help---
|
||||
This adds support for DVB/ATSC cards based on the
|
||||
Conexant 2388x chip.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cx88-dvb.
|
||||
|
||||
config VIDEO_CX88_ENABLE_VP3054
|
||||
bool "VP-3054 Secondary I2C Bus Support"
|
||||
default y
|
||||
depends on VIDEO_CX88_DVB && DVB_MT352
|
||||
---help---
|
||||
This adds DVB-T support for cards based on the
|
||||
Conexant 2388x chip and the MT352 demodulator,
|
||||
which also require support for the VP-3054
|
||||
Secondary I2C bus, such at DNTV Live! DVB-T Pro.
|
||||
|
||||
config VIDEO_CX88_VP3054
|
||||
tristate
|
||||
depends on VIDEO_CX88_DVB && VIDEO_CX88_ENABLE_VP3054
|
||||
default y
|
||||
|
||||
config VIDEO_CX88_MPEG
|
||||
tristate
|
||||
depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
|
||||
default y
|
17
drivers/media/pci/cx88/Makefile
Normal file
17
drivers/media/pci/cx88/Makefile
Normal file
|
@ -0,0 +1,17 @@
|
|||
cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
|
||||
cx88-dsp.o cx88-input.o
|
||||
cx8800-objs := cx88-video.o cx88-vbi.o
|
||||
cx8802-objs := cx88-mpeg.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o
|
||||
obj-$(CONFIG_VIDEO_CX88_MPEG) += cx8802.o
|
||||
obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
|
||||
obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
|
||||
obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
|
||||
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
|
||||
|
||||
ccflags-y += -Idrivers/media/i2c
|
||||
ccflags-y += -Idrivers/media/common
|
||||
ccflags-y += -Idrivers/media/tuners
|
||||
ccflags-y += -Idrivers/media/dvb-core
|
||||
ccflags-y += -Idrivers/media/dvb-frontends
|
950
drivers/media/pci/cx88/cx88-alsa.c
Normal file
950
drivers/media/pci/cx88/cx88-alsa.c
Normal file
|
@ -0,0 +1,950 @@
|
|||
/*
|
||||
*
|
||||
* Support for audio capture
|
||||
* PCI function #1 of the cx2388x.
|
||||
*
|
||||
* (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
|
||||
* (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
|
||||
* (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
* Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
|
||||
* Based on dummy.c by Jaroslav Kysela <perex@perex.cz>
|
||||
*
|
||||
* 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/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/delay.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <media/wm8775.h>
|
||||
|
||||
#include "cx88.h"
|
||||
#include "cx88-reg.h"
|
||||
|
||||
#define dprintk(level, fmt, arg...) do { \
|
||||
if (debug + 1 > level) \
|
||||
printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg);\
|
||||
} while(0)
|
||||
|
||||
#define dprintk_core(level, fmt, arg...) do { \
|
||||
if (debug + 1 > level) \
|
||||
printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg);\
|
||||
} while(0)
|
||||
|
||||
/****************************************************************************
|
||||
Data type declarations - Can be moded to a header file later
|
||||
****************************************************************************/
|
||||
|
||||
struct cx88_audio_buffer {
|
||||
unsigned int bpl;
|
||||
struct btcx_riscmem risc;
|
||||
struct videobuf_dmabuf dma;
|
||||
};
|
||||
|
||||
struct cx88_audio_dev {
|
||||
struct cx88_core *core;
|
||||
struct cx88_dmaqueue q;
|
||||
|
||||
/* pci i/o */
|
||||
struct pci_dev *pci;
|
||||
|
||||
/* audio controls */
|
||||
int irq;
|
||||
|
||||
struct snd_card *card;
|
||||
|
||||
spinlock_t reg_lock;
|
||||
atomic_t count;
|
||||
|
||||
unsigned int dma_size;
|
||||
unsigned int period_size;
|
||||
unsigned int num_periods;
|
||||
|
||||
struct videobuf_dmabuf *dma_risc;
|
||||
|
||||
struct cx88_audio_buffer *buf;
|
||||
|
||||
struct snd_pcm_substream *substream;
|
||||
};
|
||||
typedef struct cx88_audio_dev snd_cx88_card_t;
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Module global static vars
|
||||
****************************************************************************/
|
||||
|
||||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
||||
static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
||||
static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
|
||||
|
||||
module_param_array(enable, bool, NULL, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Module macros
|
||||
****************************************************************************/
|
||||
|
||||
MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
|
||||
MODULE_AUTHOR("Ricardo Cerqueira");
|
||||
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(CX88_VERSION);
|
||||
|
||||
MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
|
||||
"{{Conexant,23882},"
|
||||
"{{Conexant,23883}");
|
||||
static unsigned int debug;
|
||||
module_param(debug,int,0644);
|
||||
MODULE_PARM_DESC(debug,"enable debug messages");
|
||||
|
||||
/****************************************************************************
|
||||
Module specific funtions
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* BOARD Specific: Sets audio DMA
|
||||
*/
|
||||
|
||||
static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
|
||||
{
|
||||
struct cx88_audio_buffer *buf = chip->buf;
|
||||
struct cx88_core *core=chip->core;
|
||||
const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
|
||||
|
||||
/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
|
||||
cx_clear(MO_AUD_DMACNTRL, 0x11);
|
||||
|
||||
/* setup fifo + format - out channel */
|
||||
cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);
|
||||
|
||||
/* sets bpl size */
|
||||
cx_write(MO_AUDD_LNGTH, buf->bpl);
|
||||
|
||||
/* reset counter */
|
||||
cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
|
||||
atomic_set(&chip->count, 0);
|
||||
|
||||
dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
|
||||
"byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
|
||||
chip->num_periods, buf->bpl * chip->num_periods);
|
||||
|
||||
/* Enables corresponding bits at AUD_INT_STAT */
|
||||
cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
|
||||
AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
|
||||
|
||||
/* Clean any pending interrupt bits already set */
|
||||
cx_write(MO_AUD_INTSTAT, ~0);
|
||||
|
||||
/* enable audio irqs */
|
||||
cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);
|
||||
|
||||
/* start dma */
|
||||
cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
|
||||
cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
|
||||
|
||||
if (debug)
|
||||
cx88_sram_channel_dump(chip->core, audio_ch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* BOARD Specific: Resets audio DMA
|
||||
*/
|
||||
static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
|
||||
{
|
||||
struct cx88_core *core=chip->core;
|
||||
dprintk(1, "Stopping audio DMA\n");
|
||||
|
||||
/* stop dma */
|
||||
cx_clear(MO_AUD_DMACNTRL, 0x11);
|
||||
|
||||
/* disable irqs */
|
||||
cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
|
||||
cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
|
||||
AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
|
||||
|
||||
if (debug)
|
||||
cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_IRQ_LOOP 50
|
||||
|
||||
/*
|
||||
* BOARD Specific: IRQ dma bits
|
||||
*/
|
||||
static const char *cx88_aud_irqs[32] = {
|
||||
"dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
|
||||
NULL, /* reserved */
|
||||
"dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
|
||||
NULL, /* reserved */
|
||||
"dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */
|
||||
NULL, /* reserved */
|
||||
"dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */
|
||||
NULL, /* reserved */
|
||||
"opc_err", "par_err", "rip_err", /* 16-18 */
|
||||
"pci_abort", "ber_irq", "mchg_irq" /* 19-21 */
|
||||
};
|
||||
|
||||
/*
|
||||
* BOARD Specific: Threats IRQ audio specific calls
|
||||
*/
|
||||
static void cx8801_aud_irq(snd_cx88_card_t *chip)
|
||||
{
|
||||
struct cx88_core *core = chip->core;
|
||||
u32 status, mask;
|
||||
|
||||
status = cx_read(MO_AUD_INTSTAT);
|
||||
mask = cx_read(MO_AUD_INTMSK);
|
||||
if (0 == (status & mask))
|
||||
return;
|
||||
cx_write(MO_AUD_INTSTAT, status);
|
||||
if (debug > 1 || (status & mask & ~0xff))
|
||||
cx88_print_irqbits(core->name, "irq aud",
|
||||
cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
|
||||
status, mask);
|
||||
/* risc op code error */
|
||||
if (status & AUD_INT_OPC_ERR) {
|
||||
printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
|
||||
cx_clear(MO_AUD_DMACNTRL, 0x11);
|
||||
cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
|
||||
}
|
||||
if (status & AUD_INT_DN_SYNC) {
|
||||
dprintk(1, "Downstream sync error\n");
|
||||
cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
|
||||
return;
|
||||
}
|
||||
/* risc1 downstream */
|
||||
if (status & AUD_INT_DN_RISCI1) {
|
||||
atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
|
||||
snd_pcm_period_elapsed(chip->substream);
|
||||
}
|
||||
/* FIXME: Any other status should deserve a special handling? */
|
||||
}
|
||||
|
||||
/*
|
||||
* BOARD Specific: Handles IRQ calls
|
||||
*/
|
||||
static irqreturn_t cx8801_irq(int irq, void *dev_id)
|
||||
{
|
||||
snd_cx88_card_t *chip = dev_id;
|
||||
struct cx88_core *core = chip->core;
|
||||
u32 status;
|
||||
int loop, handled = 0;
|
||||
|
||||
for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
|
||||
status = cx_read(MO_PCI_INTSTAT) &
|
||||
(core->pci_irqmask | PCI_INT_AUDINT);
|
||||
if (0 == status)
|
||||
goto out;
|
||||
dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
|
||||
loop, MAX_IRQ_LOOP, status);
|
||||
handled = 1;
|
||||
cx_write(MO_PCI_INTSTAT, status);
|
||||
|
||||
if (status & core->pci_irqmask)
|
||||
cx88_core_irq(core, status);
|
||||
if (status & PCI_INT_AUDINT)
|
||||
cx8801_aud_irq(chip);
|
||||
}
|
||||
|
||||
if (MAX_IRQ_LOOP == loop) {
|
||||
printk(KERN_ERR
|
||||
"%s/1: IRQ loop detected, disabling interrupts\n",
|
||||
core->name);
|
||||
cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
|
||||
}
|
||||
|
||||
out:
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
||||
static int dsp_buffer_free(snd_cx88_card_t *chip)
|
||||
{
|
||||
BUG_ON(!chip->dma_size);
|
||||
|
||||
dprintk(2,"Freeing buffer\n");
|
||||
videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
|
||||
videobuf_dma_free(chip->dma_risc);
|
||||
btcx_riscmem_free(chip->pci,&chip->buf->risc);
|
||||
kfree(chip->buf);
|
||||
|
||||
chip->dma_risc = NULL;
|
||||
chip->dma_size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
ALSA PCM Interface
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Digital hardware definition
|
||||
*/
|
||||
#define DEFAULT_FIFO_SIZE 4096
|
||||
static const struct snd_pcm_hardware snd_cx88_digital_hw = {
|
||||
.info = SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
.rate_max = 48000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
/* Analog audio output will be full of clicks and pops if there
|
||||
are not exactly four lines in the SRAM FIFO buffer. */
|
||||
.period_bytes_min = DEFAULT_FIFO_SIZE/4,
|
||||
.period_bytes_max = DEFAULT_FIFO_SIZE/4,
|
||||
.periods_min = 1,
|
||||
.periods_max = 1024,
|
||||
.buffer_bytes_max = (1024*1024),
|
||||
};
|
||||
|
||||
/*
|
||||
* audio pcm capture open callback
|
||||
*/
|
||||
static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int err;
|
||||
|
||||
if (!chip) {
|
||||
printk(KERN_ERR "BUG: cx88 can't find device struct."
|
||||
" Can't proceed with open\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (err < 0)
|
||||
goto _error;
|
||||
|
||||
chip->substream = substream;
|
||||
|
||||
runtime->hw = snd_cx88_digital_hw;
|
||||
|
||||
if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
|
||||
unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
|
||||
bpl &= ~7; /* must be multiple of 8 */
|
||||
runtime->hw.period_bytes_min = bpl;
|
||||
runtime->hw.period_bytes_max = bpl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
_error:
|
||||
dprintk(1,"Error opening PCM!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* audio close callback
|
||||
*/
|
||||
static int snd_cx88_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* hw_params callback
|
||||
*/
|
||||
static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
|
||||
struct snd_pcm_hw_params * hw_params)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
|
||||
struct videobuf_dmabuf *dma;
|
||||
|
||||
struct cx88_audio_buffer *buf;
|
||||
int ret;
|
||||
|
||||
if (substream->runtime->dma_area) {
|
||||
dsp_buffer_free(chip);
|
||||
substream->runtime->dma_area = NULL;
|
||||
}
|
||||
|
||||
chip->period_size = params_period_bytes(hw_params);
|
||||
chip->num_periods = params_periods(hw_params);
|
||||
chip->dma_size = chip->period_size * params_periods(hw_params);
|
||||
|
||||
BUG_ON(!chip->dma_size);
|
||||
BUG_ON(chip->num_periods & (chip->num_periods-1));
|
||||
|
||||
buf = kzalloc(sizeof(*buf), GFP_KERNEL);
|
||||
if (NULL == buf)
|
||||
return -ENOMEM;
|
||||
|
||||
buf->bpl = chip->period_size;
|
||||
|
||||
dma = &buf->dma;
|
||||
videobuf_dma_init(dma);
|
||||
ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
|
||||
(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = videobuf_dma_map(&chip->pci->dev, dma);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
|
||||
chip->period_size, chip->num_periods, 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
/* Loop back to start of program */
|
||||
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
|
||||
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
|
||||
chip->buf = buf;
|
||||
chip->dma_risc = dma;
|
||||
|
||||
substream->runtime->dma_area = chip->dma_risc->vaddr;
|
||||
substream->runtime->dma_bytes = chip->dma_size;
|
||||
substream->runtime->dma_addr = 0;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* hw free callback
|
||||
*/
|
||||
static int snd_cx88_hw_free(struct snd_pcm_substream * substream)
|
||||
{
|
||||
|
||||
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
|
||||
|
||||
if (substream->runtime->dma_area) {
|
||||
dsp_buffer_free(chip);
|
||||
substream->runtime->dma_area = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* prepare callback
|
||||
*/
|
||||
static int snd_cx88_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* trigger callback
|
||||
*/
|
||||
static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
|
||||
int err;
|
||||
|
||||
/* Local interrupts are already disabled by ALSA */
|
||||
spin_lock(&chip->reg_lock);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
err=_cx88_start_audio_dma(chip);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
err=_cx88_stop_audio_dma(chip);
|
||||
break;
|
||||
default:
|
||||
err=-EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&chip->reg_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* pointer callback
|
||||
*/
|
||||
static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
u16 count;
|
||||
|
||||
count = atomic_read(&chip->count);
|
||||
|
||||
// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,
|
||||
// count, new, count & (runtime->periods-1),
|
||||
// runtime->period_size * (count & (runtime->periods-1)));
|
||||
return runtime->period_size * (count & (runtime->periods-1));
|
||||
}
|
||||
|
||||
/*
|
||||
* page callback (needed for mmap)
|
||||
*/
|
||||
static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
|
||||
unsigned long offset)
|
||||
{
|
||||
void *pageptr = substream->runtime->dma_area + offset;
|
||||
return vmalloc_to_page(pageptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* operators
|
||||
*/
|
||||
static struct snd_pcm_ops snd_cx88_pcm_ops = {
|
||||
.open = snd_cx88_pcm_open,
|
||||
.close = snd_cx88_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = snd_cx88_hw_params,
|
||||
.hw_free = snd_cx88_hw_free,
|
||||
.prepare = snd_cx88_prepare,
|
||||
.trigger = snd_cx88_card_trigger,
|
||||
.pointer = snd_cx88_pointer,
|
||||
.page = snd_cx88_page,
|
||||
};
|
||||
|
||||
/*
|
||||
* create a PCM device
|
||||
*/
|
||||
static int snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
|
||||
{
|
||||
int err;
|
||||
struct snd_pcm *pcm;
|
||||
|
||||
err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
pcm->private_data = chip;
|
||||
strcpy(pcm->name, name);
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
CONTROL INTERFACE
|
||||
****************************************************************************/
|
||||
static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *info)
|
||||
{
|
||||
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
info->count = 2;
|
||||
info->value.integer.min = 0;
|
||||
info->value.integer.max = 0x3f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
|
||||
struct cx88_core *core=chip->core;
|
||||
int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),
|
||||
bal = cx_read(AUD_BAL_CTL);
|
||||
|
||||
value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;
|
||||
vol -= (bal & 0x3f);
|
||||
value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
|
||||
struct cx88_core *core = chip->core;
|
||||
int left = value->value.integer.value[0];
|
||||
int right = value->value.integer.value[1];
|
||||
int v, b;
|
||||
|
||||
/* Pass volume & balance onto any WM8775 */
|
||||
if (left >= right) {
|
||||
v = left << 10;
|
||||
b = left ? (0x8000 * right) / left : 0x8000;
|
||||
} else {
|
||||
v = right << 10;
|
||||
b = right ? 0xffff - (0x8000 * left) / right : 0x8000;
|
||||
}
|
||||
wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v);
|
||||
wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b);
|
||||
}
|
||||
|
||||
/* OK - TODO: test it */
|
||||
static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
|
||||
struct cx88_core *core=chip->core;
|
||||
int left, right, v, b;
|
||||
int changed = 0;
|
||||
u32 old;
|
||||
|
||||
if (core->sd_wm8775)
|
||||
snd_cx88_wm8775_volume_put(kcontrol, value);
|
||||
|
||||
left = value->value.integer.value[0] & 0x3f;
|
||||
right = value->value.integer.value[1] & 0x3f;
|
||||
b = right - left;
|
||||
if (b < 0) {
|
||||
v = 0x3f - left;
|
||||
b = (-b) | 0x40;
|
||||
} else {
|
||||
v = 0x3f - right;
|
||||
}
|
||||
/* Do we really know this will always be called with IRQs on? */
|
||||
spin_lock_irq(&chip->reg_lock);
|
||||
old = cx_read(AUD_VOL_CTL);
|
||||
if (v != (old & 0x3f)) {
|
||||
cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
|
||||
changed = 1;
|
||||
}
|
||||
if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
|
||||
cx_write(AUD_BAL_CTL, b);
|
||||
changed = 1;
|
||||
}
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
|
||||
|
||||
static const struct snd_kcontrol_new snd_cx88_volume = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.name = "Analog-TV Volume",
|
||||
.info = snd_cx88_volume_info,
|
||||
.get = snd_cx88_volume_get,
|
||||
.put = snd_cx88_volume_put,
|
||||
.tlv.p = snd_cx88_db_scale,
|
||||
};
|
||||
|
||||
static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
|
||||
struct cx88_core *core = chip->core;
|
||||
u32 bit = kcontrol->private_value;
|
||||
|
||||
value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
|
||||
struct cx88_core *core = chip->core;
|
||||
u32 bit = kcontrol->private_value;
|
||||
int ret = 0;
|
||||
u32 vol;
|
||||
|
||||
spin_lock_irq(&chip->reg_lock);
|
||||
vol = cx_read(AUD_VOL_CTL);
|
||||
if (value->value.integer.value[0] != !(vol & bit)) {
|
||||
vol ^= bit;
|
||||
cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
|
||||
/* Pass mute onto any WM8775 */
|
||||
if (core->sd_wm8775 && ((1<<6) == bit))
|
||||
wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit));
|
||||
ret = 1;
|
||||
}
|
||||
spin_unlock_irq(&chip->reg_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new snd_cx88_dac_switch = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Audio-Out Switch",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = snd_cx88_switch_get,
|
||||
.put = snd_cx88_switch_put,
|
||||
.private_value = (1<<8),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new snd_cx88_source_switch = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog-TV Switch",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = snd_cx88_switch_get,
|
||||
.put = snd_cx88_switch_put,
|
||||
.private_value = (1<<6),
|
||||
};
|
||||
|
||||
static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
|
||||
struct cx88_core *core = chip->core;
|
||||
s32 val;
|
||||
|
||||
val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS);
|
||||
value->value.integer.value[0] = val ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *value)
|
||||
{
|
||||
snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
|
||||
struct cx88_core *core = chip->core;
|
||||
struct v4l2_control client_ctl;
|
||||
|
||||
memset(&client_ctl, 0, sizeof(client_ctl));
|
||||
client_ctl.value = 0 != value->value.integer.value[0];
|
||||
client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
|
||||
call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_kcontrol_new snd_cx88_alc_switch = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Line-In ALC Switch",
|
||||
.info = snd_ctl_boolean_mono_info,
|
||||
.get = snd_cx88_alc_get,
|
||||
.put = snd_cx88_alc_put,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
Basic Flow for Sound Devices
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio
|
||||
* Only boards with eeprom and byte 1 at eeprom=1 have it
|
||||
*/
|
||||
|
||||
static const struct pci_device_id cx88_audio_pci_tbl[] = {
|
||||
{0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
|
||||
{0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
|
||||
{0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
|
||||
|
||||
/*
|
||||
* Chip-specific destructor
|
||||
*/
|
||||
|
||||
static int snd_cx88_free(snd_cx88_card_t *chip)
|
||||
{
|
||||
|
||||
if (chip->irq >= 0)
|
||||
free_irq(chip->irq, chip);
|
||||
|
||||
cx88_core_put(chip->core,chip->pci);
|
||||
|
||||
pci_disable_device(chip->pci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Component Destructor
|
||||
*/
|
||||
static void snd_cx88_dev_free(struct snd_card * card)
|
||||
{
|
||||
snd_cx88_card_t *chip = card->private_data;
|
||||
|
||||
snd_cx88_free(chip);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Alsa Constructor - Component probe
|
||||
*/
|
||||
|
||||
static int devno;
|
||||
static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
|
||||
snd_cx88_card_t **rchip,
|
||||
struct cx88_core **core_ptr)
|
||||
{
|
||||
snd_cx88_card_t *chip;
|
||||
struct cx88_core *core;
|
||||
int err;
|
||||
unsigned char pci_lat;
|
||||
|
||||
*rchip = NULL;
|
||||
|
||||
err = pci_enable_device(pci);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
pci_set_master(pci);
|
||||
|
||||
chip = card->private_data;
|
||||
|
||||
core = cx88_core_get(pci);
|
||||
if (NULL == core) {
|
||||
err = -EINVAL;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) {
|
||||
dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
|
||||
err = -EIO;
|
||||
cx88_core_put(core, pci);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* pci init */
|
||||
chip->card = card;
|
||||
chip->pci = pci;
|
||||
chip->irq = -1;
|
||||
spin_lock_init(&chip->reg_lock);
|
||||
|
||||
chip->core = core;
|
||||
|
||||
/* get irq */
|
||||
err = request_irq(chip->pci->irq, cx8801_irq,
|
||||
IRQF_SHARED, chip->core->name, chip);
|
||||
if (err < 0) {
|
||||
dprintk(0, "%s: can't get IRQ %d\n",
|
||||
chip->core->name, chip->pci->irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* print pci info */
|
||||
pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);
|
||||
|
||||
dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
|
||||
"latency: %d, mmio: 0x%llx\n", core->name, devno,
|
||||
pci_name(pci), pci->revision, pci->irq,
|
||||
pci_lat, (unsigned long long)pci_resource_start(pci,0));
|
||||
|
||||
chip->irq = pci->irq;
|
||||
synchronize_irq(chip->irq);
|
||||
|
||||
*rchip = chip;
|
||||
*core_ptr = core;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx88_audio_initdev(struct pci_dev *pci,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
struct snd_card *card;
|
||||
snd_cx88_card_t *chip;
|
||||
struct cx88_core *core = NULL;
|
||||
int err;
|
||||
|
||||
if (devno >= SNDRV_CARDS)
|
||||
return (-ENODEV);
|
||||
|
||||
if (!enable[devno]) {
|
||||
++devno;
|
||||
return (-ENOENT);
|
||||
}
|
||||
|
||||
err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE,
|
||||
sizeof(snd_cx88_card_t), &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
card->private_free = snd_cx88_dev_free;
|
||||
|
||||
err = snd_cx88_create(card, pci, &chip, &core);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_cx88_pcm(chip, 0, "CX88 Digital");
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip));
|
||||
if (err < 0)
|
||||
goto error;
|
||||
err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip));
|
||||
if (err < 0)
|
||||
goto error;
|
||||
err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip));
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
/* If there's a wm8775 then add a Line-In ALC switch */
|
||||
if (core->sd_wm8775)
|
||||
snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip));
|
||||
|
||||
strcpy (card->driver, "CX88x");
|
||||
sprintf(card->shortname, "Conexant CX%x", pci->device);
|
||||
sprintf(card->longname, "%s at %#llx",
|
||||
card->shortname,(unsigned long long)pci_resource_start(pci, 0));
|
||||
strcpy (card->mixername, "CX88");
|
||||
|
||||
dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
|
||||
card->driver,devno);
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
pci_set_drvdata(pci,card);
|
||||
|
||||
devno++;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
snd_card_free(card);
|
||||
return err;
|
||||
}
|
||||
/*
|
||||
* ALSA destructor
|
||||
*/
|
||||
static void cx88_audio_finidev(struct pci_dev *pci)
|
||||
{
|
||||
struct snd_card *card = pci_get_drvdata(pci);
|
||||
|
||||
snd_card_free(card);
|
||||
|
||||
devno--;
|
||||
}
|
||||
|
||||
/*
|
||||
* PCI driver definition
|
||||
*/
|
||||
|
||||
static struct pci_driver cx88_audio_pci_driver = {
|
||||
.name = "cx88_audio",
|
||||
.id_table = cx88_audio_pci_tbl,
|
||||
.probe = cx88_audio_initdev,
|
||||
.remove = cx88_audio_finidev,
|
||||
};
|
||||
|
||||
module_pci_driver(cx88_audio_pci_driver);
|
1300
drivers/media/pci/cx88/cx88-blackbird.c
Normal file
1300
drivers/media/pci/cx88/cx88-blackbird.c
Normal file
File diff suppressed because it is too large
Load diff
3815
drivers/media/pci/cx88/cx88-cards.c
Normal file
3815
drivers/media/pci/cx88/cx88-cards.c
Normal file
File diff suppressed because it is too large
Load diff
1139
drivers/media/pci/cx88/cx88-core.c
Normal file
1139
drivers/media/pci/cx88/cx88-core.c
Normal file
File diff suppressed because it is too large
Load diff
322
drivers/media/pci/cx88/cx88-dsp.c
Normal file
322
drivers/media/pci/cx88/cx88-dsp.c
Normal file
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
*
|
||||
* Stereo and SAP detection for cx88
|
||||
*
|
||||
* Copyright (c) 2009 Marton Balint <cus@fazekas.hu>
|
||||
*
|
||||
* 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/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "cx88.h"
|
||||
#include "cx88-reg.h"
|
||||
|
||||
#define INT_PI ((s32)(3.141592653589 * 32768.0))
|
||||
|
||||
#define compat_remainder(a, b) \
|
||||
((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0)
|
||||
|
||||
#define baseband_freq(carrier, srate, tone) ((s32)( \
|
||||
(compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI))
|
||||
|
||||
/* We calculate the baseband frequencies of the carrier and the pilot tones
|
||||
* based on the the sampling rate of the audio rds fifo. */
|
||||
|
||||
#define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0)
|
||||
#define FREQ_A2_DUAL baseband_freq(54687.5, 2689.36, 274.1)
|
||||
#define FREQ_A2_STEREO baseband_freq(54687.5, 2689.36, 117.5)
|
||||
|
||||
/* The frequencies below are from the reference driver. They probably need
|
||||
* further adjustments, because they are not tested at all. You may even need
|
||||
* to play a bit with the registers of the chip to select the proper signal
|
||||
* for the input of the audio rds fifo, and measure it's sampling rate to
|
||||
* calculate the proper baseband frequencies... */
|
||||
|
||||
#define FREQ_A2M_CARRIER ((s32)(2.114516 * 32768.0))
|
||||
#define FREQ_A2M_DUAL ((s32)(2.754916 * 32768.0))
|
||||
#define FREQ_A2M_STEREO ((s32)(2.462326 * 32768.0))
|
||||
|
||||
#define FREQ_EIAJ_CARRIER ((s32)(1.963495 * 32768.0)) /* 5pi/8 */
|
||||
#define FREQ_EIAJ_DUAL ((s32)(2.562118 * 32768.0))
|
||||
#define FREQ_EIAJ_STEREO ((s32)(2.601053 * 32768.0))
|
||||
|
||||
#define FREQ_BTSC_DUAL ((s32)(1.963495 * 32768.0)) /* 5pi/8 */
|
||||
#define FREQ_BTSC_DUAL_REF ((s32)(1.374446 * 32768.0)) /* 7pi/16 */
|
||||
|
||||
#define FREQ_BTSC_SAP ((s32)(2.471532 * 32768.0))
|
||||
#define FREQ_BTSC_SAP_REF ((s32)(1.730072 * 32768.0))
|
||||
|
||||
/* The spectrum of the signal should be empty between these frequencies. */
|
||||
#define FREQ_NOISE_START ((s32)(0.100000 * 32768.0))
|
||||
#define FREQ_NOISE_END ((s32)(1.200000 * 32768.0))
|
||||
|
||||
static unsigned int dsp_debug;
|
||||
module_param(dsp_debug, int, 0644);
|
||||
MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages");
|
||||
|
||||
#define dprintk(level, fmt, arg...) if (dsp_debug >= level) \
|
||||
printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
|
||||
|
||||
static s32 int_cos(u32 x)
|
||||
{
|
||||
u32 t2, t4, t6, t8;
|
||||
s32 ret;
|
||||
u16 period = x / INT_PI;
|
||||
if (period % 2)
|
||||
return -int_cos(x - INT_PI);
|
||||
x = x % INT_PI;
|
||||
if (x > INT_PI/2)
|
||||
return -int_cos(INT_PI/2 - (x % (INT_PI/2)));
|
||||
/* Now x is between 0 and INT_PI/2.
|
||||
* To calculate cos(x) we use it's Taylor polinom. */
|
||||
t2 = x*x/32768/2;
|
||||
t4 = t2*x/32768*x/32768/3/4;
|
||||
t6 = t4*x/32768*x/32768/5/6;
|
||||
t8 = t6*x/32768*x/32768/7/8;
|
||||
ret = 32768-t2+t4-t6+t8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 int_goertzel(s16 x[], u32 N, u32 freq)
|
||||
{
|
||||
/* We use the Goertzel algorithm to determine the power of the
|
||||
* given frequency in the signal */
|
||||
s32 s_prev = 0;
|
||||
s32 s_prev2 = 0;
|
||||
s32 coeff = 2*int_cos(freq);
|
||||
u32 i;
|
||||
|
||||
u64 tmp;
|
||||
u32 divisor;
|
||||
|
||||
for (i = 0; i < N; i++) {
|
||||
s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2;
|
||||
s_prev2 = s_prev;
|
||||
s_prev = s;
|
||||
}
|
||||
|
||||
tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev -
|
||||
(s64)coeff * s_prev2 * s_prev / 32768;
|
||||
|
||||
/* XXX: N must be low enough so that N*N fits in s32.
|
||||
* Else we need two divisions. */
|
||||
divisor = N * N;
|
||||
do_div(tmp, divisor);
|
||||
|
||||
return (u32) tmp;
|
||||
}
|
||||
|
||||
static u32 freq_magnitude(s16 x[], u32 N, u32 freq)
|
||||
{
|
||||
u32 sum = int_goertzel(x, N, freq);
|
||||
return (u32)int_sqrt(sum);
|
||||
}
|
||||
|
||||
static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end)
|
||||
{
|
||||
int i;
|
||||
u32 sum = 0;
|
||||
u32 freq_step;
|
||||
int samples = 5;
|
||||
|
||||
if (N > 192) {
|
||||
/* The last 192 samples are enough for noise detection */
|
||||
x += (N-192);
|
||||
N = 192;
|
||||
}
|
||||
|
||||
freq_step = (freq_end - freq_start) / (samples - 1);
|
||||
|
||||
for (i = 0; i < samples; i++) {
|
||||
sum += int_goertzel(x, N, freq_start);
|
||||
freq_start += freq_step;
|
||||
}
|
||||
|
||||
return (u32)int_sqrt(sum / samples);
|
||||
}
|
||||
|
||||
static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N)
|
||||
{
|
||||
s32 carrier, stereo, dual, noise;
|
||||
s32 carrier_freq, stereo_freq, dual_freq;
|
||||
s32 ret;
|
||||
|
||||
switch (core->tvaudio) {
|
||||
case WW_BG:
|
||||
case WW_DK:
|
||||
carrier_freq = FREQ_A2_CARRIER;
|
||||
stereo_freq = FREQ_A2_STEREO;
|
||||
dual_freq = FREQ_A2_DUAL;
|
||||
break;
|
||||
case WW_M:
|
||||
carrier_freq = FREQ_A2M_CARRIER;
|
||||
stereo_freq = FREQ_A2M_STEREO;
|
||||
dual_freq = FREQ_A2M_DUAL;
|
||||
break;
|
||||
case WW_EIAJ:
|
||||
carrier_freq = FREQ_EIAJ_CARRIER;
|
||||
stereo_freq = FREQ_EIAJ_STEREO;
|
||||
dual_freq = FREQ_EIAJ_DUAL;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n",
|
||||
core->name, core->tvaudio, __func__);
|
||||
return UNSET;
|
||||
}
|
||||
|
||||
carrier = freq_magnitude(x, N, carrier_freq);
|
||||
stereo = freq_magnitude(x, N, stereo_freq);
|
||||
dual = freq_magnitude(x, N, dual_freq);
|
||||
noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END);
|
||||
|
||||
dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, "
|
||||
"noise=%d\n", carrier, stereo, dual, noise);
|
||||
|
||||
if (stereo > dual)
|
||||
ret = V4L2_TUNER_SUB_STEREO;
|
||||
else
|
||||
ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
|
||||
|
||||
if (core->tvaudio == WW_EIAJ) {
|
||||
/* EIAJ checks may need adjustments */
|
||||
if ((carrier > max(stereo, dual)*2) &&
|
||||
(carrier < max(stereo, dual)*6) &&
|
||||
(carrier > 20 && carrier < 200) &&
|
||||
(max(stereo, dual) > min(stereo, dual))) {
|
||||
/* For EIAJ the carrier is always present,
|
||||
so we probably don't need noise detection */
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
if ((carrier > max(stereo, dual)*2) &&
|
||||
(carrier < max(stereo, dual)*8) &&
|
||||
(carrier > 20 && carrier < 200) &&
|
||||
(noise < 10) &&
|
||||
(max(stereo, dual) > min(stereo, dual)*2)) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return V4L2_TUNER_SUB_MONO;
|
||||
}
|
||||
|
||||
static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N)
|
||||
{
|
||||
s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF);
|
||||
s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP);
|
||||
s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF);
|
||||
s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL);
|
||||
dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d"
|
||||
"\n", dual_ref, dual, sap_ref, sap);
|
||||
/* FIXME: Currently not supported */
|
||||
return UNSET;
|
||||
}
|
||||
|
||||
static s16 *read_rds_samples(struct cx88_core *core, u32 *N)
|
||||
{
|
||||
const struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
|
||||
s16 *samples;
|
||||
|
||||
unsigned int i;
|
||||
unsigned int bpl = srch->fifo_size/AUD_RDS_LINES;
|
||||
unsigned int spl = bpl/4;
|
||||
unsigned int sample_count = spl*(AUD_RDS_LINES-1);
|
||||
|
||||
u32 current_address = cx_read(srch->ptr1_reg);
|
||||
u32 offset = (current_address - srch->fifo_start + bpl);
|
||||
|
||||
dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), "
|
||||
"sample_count=%d, aud_intstat=%08x\n", current_address,
|
||||
current_address - srch->fifo_start, sample_count,
|
||||
cx_read(MO_AUD_INTSTAT));
|
||||
|
||||
samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL);
|
||||
if (!samples)
|
||||
return NULL;
|
||||
|
||||
*N = sample_count;
|
||||
|
||||
for (i = 0; i < sample_count; i++) {
|
||||
offset = offset % (AUD_RDS_LINES*bpl);
|
||||
samples[i] = cx_read(srch->fifo_start + offset);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
if (dsp_debug >= 2) {
|
||||
dprintk(2, "RDS samples dump: ");
|
||||
for (i = 0; i < sample_count; i++)
|
||||
printk("%hd ", samples[i]);
|
||||
printk(".\n");
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core)
|
||||
{
|
||||
s16 *samples;
|
||||
u32 N = 0;
|
||||
s32 ret = UNSET;
|
||||
|
||||
/* If audio RDS fifo is disabled, we can't read the samples */
|
||||
if (!(cx_read(MO_AUD_DMACNTRL) & 0x04))
|
||||
return ret;
|
||||
if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS))
|
||||
return ret;
|
||||
|
||||
/* Wait at least 500 ms after an audio standard change */
|
||||
if (time_before(jiffies, core->last_change + msecs_to_jiffies(500)))
|
||||
return ret;
|
||||
|
||||
samples = read_rds_samples(core, &N);
|
||||
|
||||
if (!samples)
|
||||
return ret;
|
||||
|
||||
switch (core->tvaudio) {
|
||||
case WW_BG:
|
||||
case WW_DK:
|
||||
case WW_EIAJ:
|
||||
case WW_M:
|
||||
ret = detect_a2_a2m_eiaj(core, samples, N);
|
||||
break;
|
||||
case WW_BTSC:
|
||||
ret = detect_btsc(core, samples, N);
|
||||
break;
|
||||
case WW_NONE:
|
||||
case WW_I:
|
||||
case WW_L:
|
||||
case WW_I2SPT:
|
||||
case WW_FM:
|
||||
case WW_I2SADC:
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(samples);
|
||||
|
||||
if (UNSET != ret)
|
||||
dprintk(1, "stereo/sap detection result:%s%s%s\n",
|
||||
(ret & V4L2_TUNER_SUB_MONO) ? " mono" : "",
|
||||
(ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "",
|
||||
(ret & V4L2_TUNER_SUB_LANG2) ? " dual" : "");
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap);
|
||||
|
1795
drivers/media/pci/cx88/cx88-dvb.c
Normal file
1795
drivers/media/pci/cx88/cx88-dvb.c
Normal file
File diff suppressed because it is too large
Load diff
183
drivers/media/pci/cx88/cx88-i2c.c
Normal file
183
drivers/media/pci/cx88/cx88-i2c.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
|
||||
/*
|
||||
|
||||
cx88-i2c.c -- all the i2c code is here
|
||||
|
||||
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
|
||||
& Marcus Metzler (mocm@thp.uni-koeln.de)
|
||||
(c) 2002 Yurij Sysoev <yurij@naturesoft.net>
|
||||
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
|
||||
|
||||
(c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
- Multituner support and i2c address binding
|
||||
|
||||
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/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "cx88.h"
|
||||
#include <media/v4l2-common.h>
|
||||
|
||||
static unsigned int i2c_debug;
|
||||
module_param(i2c_debug, int, 0644);
|
||||
MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
|
||||
|
||||
static unsigned int i2c_scan;
|
||||
module_param(i2c_scan, int, 0444);
|
||||
MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
|
||||
|
||||
static unsigned int i2c_udelay = 5;
|
||||
module_param(i2c_udelay, int, 0644);
|
||||
MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs "
|
||||
"(should be 5 or higher). Lower value means higher bus speed.");
|
||||
|
||||
#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \
|
||||
printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static void cx8800_bit_setscl(void *data, int state)
|
||||
{
|
||||
struct cx88_core *core = data;
|
||||
|
||||
if (state)
|
||||
core->i2c_state |= 0x02;
|
||||
else
|
||||
core->i2c_state &= ~0x02;
|
||||
cx_write(MO_I2C, core->i2c_state);
|
||||
cx_read(MO_I2C);
|
||||
}
|
||||
|
||||
static void cx8800_bit_setsda(void *data, int state)
|
||||
{
|
||||
struct cx88_core *core = data;
|
||||
|
||||
if (state)
|
||||
core->i2c_state |= 0x01;
|
||||
else
|
||||
core->i2c_state &= ~0x01;
|
||||
cx_write(MO_I2C, core->i2c_state);
|
||||
cx_read(MO_I2C);
|
||||
}
|
||||
|
||||
static int cx8800_bit_getscl(void *data)
|
||||
{
|
||||
struct cx88_core *core = data;
|
||||
u32 state;
|
||||
|
||||
state = cx_read(MO_I2C);
|
||||
return state & 0x02 ? 1 : 0;
|
||||
}
|
||||
|
||||
static int cx8800_bit_getsda(void *data)
|
||||
{
|
||||
struct cx88_core *core = data;
|
||||
u32 state;
|
||||
|
||||
state = cx_read(MO_I2C);
|
||||
return state & 0x01;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
|
||||
.setsda = cx8800_bit_setsda,
|
||||
.setscl = cx8800_bit_setscl,
|
||||
.getsda = cx8800_bit_getsda,
|
||||
.getscl = cx8800_bit_getscl,
|
||||
.udelay = 16,
|
||||
.timeout = 200,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const char * const i2c_devs[128] = {
|
||||
[ 0x1c >> 1 ] = "lgdt330x",
|
||||
[ 0x86 >> 1 ] = "tda9887/cx22702",
|
||||
[ 0xa0 >> 1 ] = "eeprom",
|
||||
[ 0xc0 >> 1 ] = "tuner (analog)",
|
||||
[ 0xc2 >> 1 ] = "tuner (analog/dvb)",
|
||||
[ 0xc8 >> 1 ] = "xc5000",
|
||||
};
|
||||
|
||||
static void do_i2c_scan(const char *name, struct i2c_client *c)
|
||||
{
|
||||
unsigned char buf;
|
||||
int i,rc;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
|
||||
c->addr = i;
|
||||
rc = i2c_master_recv(c,&buf,0);
|
||||
if (rc < 0)
|
||||
continue;
|
||||
printk("%s: i2c scan: found device @ 0x%x [%s]\n",
|
||||
name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
|
||||
}
|
||||
}
|
||||
|
||||
/* init + register i2c adapter */
|
||||
int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
|
||||
{
|
||||
/* Prevents usage of invalid delay values */
|
||||
if (i2c_udelay<5)
|
||||
i2c_udelay=5;
|
||||
|
||||
core->i2c_algo = cx8800_i2c_algo_template;
|
||||
|
||||
|
||||
core->i2c_adap.dev.parent = &pci->dev;
|
||||
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
|
||||
core->i2c_adap.owner = THIS_MODULE;
|
||||
core->i2c_algo.udelay = i2c_udelay;
|
||||
core->i2c_algo.data = core;
|
||||
i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
|
||||
core->i2c_adap.algo_data = &core->i2c_algo;
|
||||
core->i2c_client.adapter = &core->i2c_adap;
|
||||
strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
|
||||
|
||||
cx8800_bit_setscl(core,1);
|
||||
cx8800_bit_setsda(core,1);
|
||||
|
||||
core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap);
|
||||
if (0 == core->i2c_rc) {
|
||||
static u8 tuner_data[] =
|
||||
{ 0x0b, 0xdc, 0x86, 0x52 };
|
||||
static struct i2c_msg tuner_msg =
|
||||
{ .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 };
|
||||
|
||||
dprintk(1, "i2c register ok\n");
|
||||
switch( core->boardnr ) {
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1300:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000:
|
||||
printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n",
|
||||
core->name);
|
||||
i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (i2c_scan)
|
||||
do_i2c_scan(core->name,&core->i2c_client);
|
||||
} else
|
||||
printk("%s: i2c register FAILED\n", core->name);
|
||||
|
||||
return core->i2c_rc;
|
||||
}
|
653
drivers/media/pci/cx88/cx88-input.c
Normal file
653
drivers/media/pci/cx88/cx88-input.c
Normal file
|
@ -0,0 +1,653 @@
|
|||
/*
|
||||
*
|
||||
* Device driver for GPIO attached remote control interfaces
|
||||
* on Conexant 2388x based TV/DVB cards.
|
||||
*
|
||||
* Copyright (c) 2003 Pavel Machek
|
||||
* Copyright (c) 2004 Gerd Knorr
|
||||
* Copyright (c) 2004, 2005 Chris Pascoe
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "cx88.h"
|
||||
#include <media/rc-core.h>
|
||||
|
||||
#define MODULE_NAME "cx88xx"
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
struct cx88_IR {
|
||||
struct cx88_core *core;
|
||||
struct rc_dev *dev;
|
||||
|
||||
int users;
|
||||
|
||||
char name[32];
|
||||
char phys[32];
|
||||
|
||||
/* sample from gpio pin 16 */
|
||||
u32 sampling;
|
||||
|
||||
/* poll external decoder */
|
||||
int polling;
|
||||
struct hrtimer timer;
|
||||
u32 gpio_addr;
|
||||
u32 last_gpio;
|
||||
u32 mask_keycode;
|
||||
u32 mask_keydown;
|
||||
u32 mask_keyup;
|
||||
};
|
||||
|
||||
static unsigned ir_samplerate = 4;
|
||||
module_param(ir_samplerate, uint, 0444);
|
||||
MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4");
|
||||
|
||||
static int ir_debug;
|
||||
module_param(ir_debug, int, 0644); /* debug level [IR] */
|
||||
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
|
||||
|
||||
#define ir_dprintk(fmt, arg...) if (ir_debug) \
|
||||
printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg)
|
||||
|
||||
#define dprintk(fmt, arg...) if (ir_debug) \
|
||||
printk(KERN_DEBUG "cx88 IR: " fmt , ##arg)
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void cx88_ir_handle_key(struct cx88_IR *ir)
|
||||
{
|
||||
struct cx88_core *core = ir->core;
|
||||
u32 gpio, data, auxgpio;
|
||||
|
||||
/* read gpio value */
|
||||
gpio = cx_read(ir->gpio_addr);
|
||||
switch (core->boardnr) {
|
||||
case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
|
||||
/* This board apparently uses a combination of 2 GPIO
|
||||
to represent the keys. Additionally, the second GPIO
|
||||
can be used for parity.
|
||||
|
||||
Example:
|
||||
|
||||
for key "5"
|
||||
gpio = 0x758, auxgpio = 0xe5 or 0xf5
|
||||
for key "Power"
|
||||
gpio = 0x758, auxgpio = 0xed or 0xfd
|
||||
*/
|
||||
|
||||
auxgpio = cx_read(MO_GP1_IO);
|
||||
/* Take out the parity part */
|
||||
gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
|
||||
break;
|
||||
case CX88_BOARD_WINFAST_DTV1000:
|
||||
case CX88_BOARD_WINFAST_DTV1800H:
|
||||
case CX88_BOARD_WINFAST_DTV1800H_XC4000:
|
||||
case CX88_BOARD_WINFAST_DTV2000H_PLUS:
|
||||
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
|
||||
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
|
||||
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
|
||||
gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
|
||||
auxgpio = gpio;
|
||||
break;
|
||||
default:
|
||||
auxgpio = gpio;
|
||||
}
|
||||
if (ir->polling) {
|
||||
if (ir->last_gpio == auxgpio)
|
||||
return;
|
||||
ir->last_gpio = auxgpio;
|
||||
}
|
||||
|
||||
/* extract data */
|
||||
data = ir_extract_bits(gpio, ir->mask_keycode);
|
||||
ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
|
||||
gpio, data,
|
||||
ir->polling ? "poll" : "irq",
|
||||
(gpio & ir->mask_keydown) ? " down" : "",
|
||||
(gpio & ir->mask_keyup) ? " up" : "");
|
||||
|
||||
if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) {
|
||||
u32 gpio_key = cx_read(MO_GP0_IO);
|
||||
|
||||
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
|
||||
|
||||
rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0);
|
||||
|
||||
} else if (ir->core->boardnr == CX88_BOARD_PROLINK_PLAYTVPVR ||
|
||||
ir->core->boardnr == CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO) {
|
||||
/* bit cleared on keydown, NEC scancode, 0xAAAACC, A = 0x866b */
|
||||
u16 addr;
|
||||
u8 cmd;
|
||||
u32 scancode;
|
||||
|
||||
addr = (data >> 8) & 0xffff;
|
||||
cmd = (data >> 0) & 0x00ff;
|
||||
scancode = RC_SCANCODE_NECX(addr, cmd);
|
||||
|
||||
if (0 == (gpio & ir->mask_keyup))
|
||||
rc_keydown_notimeout(ir->dev, RC_TYPE_NEC, scancode, 0);
|
||||
else
|
||||
rc_keyup(ir->dev);
|
||||
|
||||
} else if (ir->mask_keydown) {
|
||||
/* bit set on keydown */
|
||||
if (gpio & ir->mask_keydown)
|
||||
rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
|
||||
else
|
||||
rc_keyup(ir->dev);
|
||||
|
||||
} else if (ir->mask_keyup) {
|
||||
/* bit cleared on keydown */
|
||||
if (0 == (gpio & ir->mask_keyup))
|
||||
rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
|
||||
else
|
||||
rc_keyup(ir->dev);
|
||||
|
||||
} else {
|
||||
/* can't distinguish keydown/up :-/ */
|
||||
rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
|
||||
rc_keyup(ir->dev);
|
||||
}
|
||||
}
|
||||
|
||||
static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer)
|
||||
{
|
||||
unsigned long missed;
|
||||
struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer);
|
||||
|
||||
cx88_ir_handle_key(ir);
|
||||
missed = hrtimer_forward_now(&ir->timer,
|
||||
ktime_set(0, ir->polling * 1000000));
|
||||
if (missed > 1)
|
||||
ir_dprintk("Missed ticks %ld\n", missed - 1);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
static int __cx88_ir_start(void *priv)
|
||||
{
|
||||
struct cx88_core *core = priv;
|
||||
struct cx88_IR *ir;
|
||||
|
||||
if (!core || !core->ir)
|
||||
return -EINVAL;
|
||||
|
||||
ir = core->ir;
|
||||
|
||||
if (ir->polling) {
|
||||
hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
ir->timer.function = cx88_ir_work;
|
||||
hrtimer_start(&ir->timer,
|
||||
ktime_set(0, ir->polling * 1000000),
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
if (ir->sampling) {
|
||||
core->pci_irqmask |= PCI_INT_IR_SMPINT;
|
||||
cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */
|
||||
cx_write(MO_DDSCFG_IO, 0x5); /* enable */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __cx88_ir_stop(void *priv)
|
||||
{
|
||||
struct cx88_core *core = priv;
|
||||
struct cx88_IR *ir;
|
||||
|
||||
if (!core || !core->ir)
|
||||
return;
|
||||
|
||||
ir = core->ir;
|
||||
if (ir->sampling) {
|
||||
cx_write(MO_DDSCFG_IO, 0x0);
|
||||
core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
|
||||
}
|
||||
|
||||
if (ir->polling)
|
||||
hrtimer_cancel(&ir->timer);
|
||||
}
|
||||
|
||||
int cx88_ir_start(struct cx88_core *core)
|
||||
{
|
||||
if (core->ir->users)
|
||||
return __cx88_ir_start(core);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cx88_ir_stop(struct cx88_core *core)
|
||||
{
|
||||
if (core->ir->users)
|
||||
__cx88_ir_stop(core);
|
||||
}
|
||||
|
||||
static int cx88_ir_open(struct rc_dev *rc)
|
||||
{
|
||||
struct cx88_core *core = rc->priv;
|
||||
|
||||
core->ir->users++;
|
||||
return __cx88_ir_start(core);
|
||||
}
|
||||
|
||||
static void cx88_ir_close(struct rc_dev *rc)
|
||||
{
|
||||
struct cx88_core *core = rc->priv;
|
||||
|
||||
core->ir->users--;
|
||||
if (!core->ir->users)
|
||||
__cx88_ir_stop(core);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
|
||||
{
|
||||
struct cx88_IR *ir;
|
||||
struct rc_dev *dev;
|
||||
char *ir_codes = NULL;
|
||||
u64 rc_type = RC_BIT_OTHER;
|
||||
int err = -ENOMEM;
|
||||
u32 hardware_mask = 0; /* For devices with a hardware mask, when
|
||||
* used with a full-code IR table
|
||||
*/
|
||||
|
||||
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
|
||||
dev = rc_allocate_device();
|
||||
if (!ir || !dev)
|
||||
goto err_out_free;
|
||||
|
||||
ir->dev = dev;
|
||||
|
||||
/* detect & configure */
|
||||
switch (core->boardnr) {
|
||||
case CX88_BOARD_DNTV_LIVE_DVB_T:
|
||||
case CX88_BOARD_KWORLD_DVB_T:
|
||||
case CX88_BOARD_KWORLD_DVB_T_CX22702:
|
||||
ir_codes = RC_MAP_DNTV_LIVE_DVB_T;
|
||||
ir->gpio_addr = MO_GP1_IO;
|
||||
ir->mask_keycode = 0x1f;
|
||||
ir->mask_keyup = 0x60;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
|
||||
ir_codes = RC_MAP_CINERGY_1400;
|
||||
ir->sampling = 0xeb04; /* address */
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE:
|
||||
case CX88_BOARD_HAUPPAUGE_DVB_T1:
|
||||
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
|
||||
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1100:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR3000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000:
|
||||
case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
|
||||
case CX88_BOARD_PCHDTV_HD3000:
|
||||
case CX88_BOARD_PCHDTV_HD5500:
|
||||
case CX88_BOARD_HAUPPAUGE_IRONLY:
|
||||
ir_codes = RC_MAP_HAUPPAUGE;
|
||||
ir->sampling = 1;
|
||||
break;
|
||||
case CX88_BOARD_WINFAST_DTV2000H:
|
||||
case CX88_BOARD_WINFAST_DTV2000H_J:
|
||||
case CX88_BOARD_WINFAST_DTV1800H:
|
||||
case CX88_BOARD_WINFAST_DTV1800H_XC4000:
|
||||
case CX88_BOARD_WINFAST_DTV2000H_PLUS:
|
||||
ir_codes = RC_MAP_WINFAST;
|
||||
ir->gpio_addr = MO_GP0_IO;
|
||||
ir->mask_keycode = 0x8f8;
|
||||
ir->mask_keyup = 0x100;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_WINFAST2000XP_EXPERT:
|
||||
case CX88_BOARD_WINFAST_DTV1000:
|
||||
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
|
||||
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36:
|
||||
case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43:
|
||||
ir_codes = RC_MAP_WINFAST;
|
||||
ir->gpio_addr = MO_GP0_IO;
|
||||
ir->mask_keycode = 0x8f8;
|
||||
ir->mask_keyup = 0x100;
|
||||
ir->polling = 1; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_IODATA_GVBCTV7E:
|
||||
ir_codes = RC_MAP_IODATA_BCTV7E;
|
||||
ir->gpio_addr = MO_GP0_IO;
|
||||
ir->mask_keycode = 0xfd;
|
||||
ir->mask_keydown = 0x02;
|
||||
ir->polling = 5; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_PROLINK_PLAYTVPVR:
|
||||
case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
|
||||
/*
|
||||
* It seems that this hardware is paired with NEC extended
|
||||
* address 0x866b. So, unfortunately, its usage with other
|
||||
* IR's with different address won't work. Still, there are
|
||||
* other IR's from the same manufacturer that works, like the
|
||||
* 002-T mini RC, provided with newer PV hardware
|
||||
*/
|
||||
ir_codes = RC_MAP_PIXELVIEW_MK12;
|
||||
rc_type = RC_BIT_NEC;
|
||||
ir->gpio_addr = MO_GP1_IO;
|
||||
ir->mask_keyup = 0x80;
|
||||
ir->polling = 10; /* ms */
|
||||
hardware_mask = 0x3f; /* Hardware returns only 6 bits from command part */
|
||||
break;
|
||||
case CX88_BOARD_PROLINK_PV_8000GT:
|
||||
case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME:
|
||||
ir_codes = RC_MAP_PIXELVIEW_NEW;
|
||||
ir->gpio_addr = MO_GP1_IO;
|
||||
ir->mask_keycode = 0x3f;
|
||||
ir->mask_keyup = 0x80;
|
||||
ir->polling = 1; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_KWORLD_LTV883:
|
||||
ir_codes = RC_MAP_PIXELVIEW;
|
||||
ir->gpio_addr = MO_GP1_IO;
|
||||
ir->mask_keycode = 0x1f;
|
||||
ir->mask_keyup = 0x60;
|
||||
ir->polling = 1; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_ADSTECH_DVB_T_PCI:
|
||||
ir_codes = RC_MAP_ADSTECH_DVB_T_PCI;
|
||||
ir->gpio_addr = MO_GP1_IO;
|
||||
ir->mask_keycode = 0xbf;
|
||||
ir->mask_keyup = 0x40;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_MSI_TVANYWHERE_MASTER:
|
||||
ir_codes = RC_MAP_MSI_TVANYWHERE;
|
||||
ir->gpio_addr = MO_GP1_IO;
|
||||
ir->mask_keycode = 0x1f;
|
||||
ir->mask_keyup = 0x40;
|
||||
ir->polling = 1; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_AVERTV_303:
|
||||
case CX88_BOARD_AVERTV_STUDIO_303:
|
||||
ir_codes = RC_MAP_AVERTV_303;
|
||||
ir->gpio_addr = MO_GP2_IO;
|
||||
ir->mask_keycode = 0xfb;
|
||||
ir->mask_keydown = 0x02;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_OMICOM_SS4_PCI:
|
||||
case CX88_BOARD_SATTRADE_ST4200:
|
||||
case CX88_BOARD_TBS_8920:
|
||||
case CX88_BOARD_TBS_8910:
|
||||
case CX88_BOARD_PROF_7300:
|
||||
case CX88_BOARD_PROF_7301:
|
||||
case CX88_BOARD_PROF_6200:
|
||||
ir_codes = RC_MAP_TBS_NEC;
|
||||
ir->sampling = 0xff00; /* address */
|
||||
break;
|
||||
case CX88_BOARD_TEVII_S464:
|
||||
case CX88_BOARD_TEVII_S460:
|
||||
case CX88_BOARD_TEVII_S420:
|
||||
ir_codes = RC_MAP_TEVII_NEC;
|
||||
ir->sampling = 0xff00; /* address */
|
||||
break;
|
||||
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
|
||||
ir_codes = RC_MAP_DNTV_LIVE_DVBT_PRO;
|
||||
ir->sampling = 0xff00; /* address */
|
||||
break;
|
||||
case CX88_BOARD_NORWOOD_MICRO:
|
||||
ir_codes = RC_MAP_NORWOOD;
|
||||
ir->gpio_addr = MO_GP1_IO;
|
||||
ir->mask_keycode = 0x0e;
|
||||
ir->mask_keyup = 0x80;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
|
||||
ir_codes = RC_MAP_NPGTECH;
|
||||
ir->gpio_addr = MO_GP0_IO;
|
||||
ir->mask_keycode = 0xfa;
|
||||
ir->polling = 50; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
|
||||
ir_codes = RC_MAP_PINNACLE_PCTV_HD;
|
||||
ir->sampling = 1;
|
||||
break;
|
||||
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
|
||||
ir_codes = RC_MAP_POWERCOLOR_REAL_ANGEL;
|
||||
ir->gpio_addr = MO_GP2_IO;
|
||||
ir->mask_keycode = 0x7e;
|
||||
ir->polling = 100; /* ms */
|
||||
break;
|
||||
case CX88_BOARD_TWINHAN_VP1027_DVBS:
|
||||
ir_codes = RC_MAP_TWINHAN_VP1027_DVBS;
|
||||
ir->sampling = 0xff00; /* address */
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ir_codes) {
|
||||
err = -ENODEV;
|
||||
goto err_out_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* The usage of mask_keycode were very convenient, due to several
|
||||
* reasons. Among others, the scancode tables were using the scancode
|
||||
* as the index elements. So, the less bits it was used, the smaller
|
||||
* the table were stored. After the input changes, the better is to use
|
||||
* the full scancodes, since it allows replacing the IR remote by
|
||||
* another one. Unfortunately, there are still some hardware, like
|
||||
* Pixelview Ultra Pro, where only part of the scancode is sent via
|
||||
* GPIO. So, there's no way to get the full scancode. Due to that,
|
||||
* hardware_mask were introduced here: it represents those hardware
|
||||
* that has such limits.
|
||||
*/
|
||||
if (hardware_mask && !ir->mask_keycode)
|
||||
ir->mask_keycode = hardware_mask;
|
||||
|
||||
/* init input device */
|
||||
snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
|
||||
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
|
||||
|
||||
dev->input_name = ir->name;
|
||||
dev->input_phys = ir->phys;
|
||||
dev->input_id.bustype = BUS_PCI;
|
||||
dev->input_id.version = 1;
|
||||
if (pci->subsystem_vendor) {
|
||||
dev->input_id.vendor = pci->subsystem_vendor;
|
||||
dev->input_id.product = pci->subsystem_device;
|
||||
} else {
|
||||
dev->input_id.vendor = pci->vendor;
|
||||
dev->input_id.product = pci->device;
|
||||
}
|
||||
dev->dev.parent = &pci->dev;
|
||||
dev->map_name = ir_codes;
|
||||
dev->driver_name = MODULE_NAME;
|
||||
dev->priv = core;
|
||||
dev->open = cx88_ir_open;
|
||||
dev->close = cx88_ir_close;
|
||||
dev->scancode_mask = hardware_mask;
|
||||
|
||||
if (ir->sampling) {
|
||||
dev->driver_type = RC_DRIVER_IR_RAW;
|
||||
dev->timeout = 10 * 1000 * 1000; /* 10 ms */
|
||||
} else {
|
||||
dev->driver_type = RC_DRIVER_SCANCODE;
|
||||
dev->allowed_protocols = rc_type;
|
||||
}
|
||||
|
||||
ir->core = core;
|
||||
core->ir = ir;
|
||||
|
||||
/* all done */
|
||||
err = rc_register_device(dev);
|
||||
if (err)
|
||||
goto err_out_free;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free:
|
||||
rc_free_device(dev);
|
||||
core->ir = NULL;
|
||||
kfree(ir);
|
||||
return err;
|
||||
}
|
||||
|
||||
int cx88_ir_fini(struct cx88_core *core)
|
||||
{
|
||||
struct cx88_IR *ir = core->ir;
|
||||
|
||||
/* skip detach on non attached boards */
|
||||
if (NULL == ir)
|
||||
return 0;
|
||||
|
||||
cx88_ir_stop(core);
|
||||
rc_unregister_device(ir->dev);
|
||||
kfree(ir);
|
||||
|
||||
/* done */
|
||||
core->ir = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void cx88_ir_irq(struct cx88_core *core)
|
||||
{
|
||||
struct cx88_IR *ir = core->ir;
|
||||
u32 samples;
|
||||
unsigned todo, bits;
|
||||
struct ir_raw_event ev;
|
||||
|
||||
if (!ir || !ir->sampling)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Samples are stored in a 32 bit register, oldest sample in
|
||||
* the msb. A set bit represents space and an unset bit
|
||||
* represents a pulse.
|
||||
*/
|
||||
samples = cx_read(MO_SAMPLE_IO);
|
||||
|
||||
if (samples == 0xff && ir->dev->idle)
|
||||
return;
|
||||
|
||||
init_ir_raw_event(&ev);
|
||||
for (todo = 32; todo > 0; todo -= bits) {
|
||||
ev.pulse = samples & 0x80000000 ? false : true;
|
||||
bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
|
||||
ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
|
||||
ir_raw_event_store_with_filter(ir->dev, &ev);
|
||||
samples <<= bits;
|
||||
}
|
||||
ir_raw_event_handle(ir->dev);
|
||||
}
|
||||
|
||||
static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol,
|
||||
u32 *scancode, u8 *toggle)
|
||||
{
|
||||
int flags, code;
|
||||
|
||||
/* poll IR chip */
|
||||
flags = i2c_smbus_read_byte_data(ir->c, 0x10);
|
||||
if (flags < 0) {
|
||||
dprintk("read error\n");
|
||||
return 0;
|
||||
}
|
||||
/* key pressed ? */
|
||||
if (0 == (flags & 0x80))
|
||||
return 0;
|
||||
|
||||
/* read actual key code */
|
||||
code = i2c_smbus_read_byte_data(ir->c, 0x00);
|
||||
if (code < 0) {
|
||||
dprintk("read error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dprintk("IR Key/Flags: (0x%02x/0x%02x)\n",
|
||||
code & 0xff, flags & 0xff);
|
||||
|
||||
*protocol = RC_TYPE_UNKNOWN;
|
||||
*scancode = code & 0xff;
|
||||
*toggle = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cx88_i2c_init_ir(struct cx88_core *core)
|
||||
{
|
||||
struct i2c_board_info info;
|
||||
const unsigned short default_addr_list[] = {
|
||||
0x18, 0x6b, 0x71,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
const unsigned short pvr2000_addr_list[] = {
|
||||
0x18, 0x1a,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
const unsigned short *addr_list = default_addr_list;
|
||||
const unsigned short *addrp;
|
||||
/* Instantiate the IR receiver device, if present */
|
||||
if (0 != core->i2c_rc)
|
||||
return;
|
||||
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
|
||||
|
||||
switch (core->boardnr) {
|
||||
case CX88_BOARD_LEADTEK_PVR2000:
|
||||
addr_list = pvr2000_addr_list;
|
||||
core->init_data.name = "cx88 Leadtek PVR 2000 remote";
|
||||
core->init_data.type = RC_BIT_UNKNOWN;
|
||||
core->init_data.get_key = get_key_pvr2000;
|
||||
core->init_data.ir_codes = RC_MAP_EMPTY;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can't call i2c_new_probed_device() because it uses
|
||||
* quick writes for probing and at least some RC receiver
|
||||
* devices only reply to reads.
|
||||
* Also, Hauppauge XVR needs to be specified, as address 0x71
|
||||
* conflicts with another remote type used with saa7134
|
||||
*/
|
||||
for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) {
|
||||
info.platform_data = NULL;
|
||||
memset(&core->init_data, 0, sizeof(core->init_data));
|
||||
|
||||
if (*addrp == 0x71) {
|
||||
/* Hauppauge XVR */
|
||||
core->init_data.name = "cx88 Hauppauge XVR remote";
|
||||
core->init_data.ir_codes = RC_MAP_HAUPPAUGE;
|
||||
core->init_data.type = RC_BIT_RC5;
|
||||
core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
|
||||
|
||||
info.platform_data = &core->init_data;
|
||||
}
|
||||
if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0,
|
||||
I2C_SMBUS_READ, 0,
|
||||
I2C_SMBUS_QUICK, NULL) >= 0) {
|
||||
info.addr = *addrp;
|
||||
i2c_new_device(&core->i2c_adap, &info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
|
||||
MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
|
||||
MODULE_LICENSE("GPL");
|
920
drivers/media/pci/cx88/cx88-mpeg.c
Normal file
920
drivers/media/pci/cx88/cx88-mpeg.c
Normal file
|
@ -0,0 +1,920 @@
|
|||
/*
|
||||
*
|
||||
* Support for the mpeg transport stream transfers
|
||||
* PCI function #2 of the cx2388x.
|
||||
*
|
||||
* (c) 2004 Jelle Foks <jelle@foks.us>
|
||||
* (c) 2004 Chris Pascoe <c.pascoe@itee.uq.edu.au>
|
||||
* (c) 2004 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/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/delay.h>
|
||||
|
||||
#include "cx88.h"
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards");
|
||||
MODULE_AUTHOR("Jelle Foks <jelle@foks.us>");
|
||||
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
|
||||
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(CX88_VERSION);
|
||||
|
||||
static unsigned int debug;
|
||||
module_param(debug,int,0644);
|
||||
MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
|
||||
|
||||
#define dprintk(level, fmt, arg...) do { \
|
||||
if (debug + 1 > level) \
|
||||
printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg); \
|
||||
} while(0)
|
||||
|
||||
#define mpeg_dbg(level, fmt, arg...) do { \
|
||||
if (debug + 1 > level) \
|
||||
printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg); \
|
||||
} while(0)
|
||||
|
||||
#if defined(CONFIG_MODULES) && defined(MODULE)
|
||||
static void request_module_async(struct work_struct *work)
|
||||
{
|
||||
struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk);
|
||||
|
||||
if (dev->core->board.mpeg & CX88_MPEG_DVB)
|
||||
request_module("cx88-dvb");
|
||||
if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD)
|
||||
request_module("cx88-blackbird");
|
||||
}
|
||||
|
||||
static void request_modules(struct cx8802_dev *dev)
|
||||
{
|
||||
INIT_WORK(&dev->request_module_wk, request_module_async);
|
||||
schedule_work(&dev->request_module_wk);
|
||||
}
|
||||
|
||||
static void flush_request_modules(struct cx8802_dev *dev)
|
||||
{
|
||||
flush_work(&dev->request_module_wk);
|
||||
}
|
||||
#else
|
||||
#define request_modules(dev)
|
||||
#define flush_request_modules(dev)
|
||||
#endif /* CONFIG_MODULES */
|
||||
|
||||
|
||||
static LIST_HEAD(cx8802_devlist);
|
||||
static DEFINE_MUTEX(cx8802_mutex);
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int cx8802_start_dma(struct cx8802_dev *dev,
|
||||
struct cx88_dmaqueue *q,
|
||||
struct cx88_buffer *buf)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
|
||||
dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n",
|
||||
buf->vb.width, buf->vb.height, buf->vb.field);
|
||||
|
||||
/* setup fifo + format */
|
||||
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
|
||||
dev->ts_packet_size, buf->risc.dma);
|
||||
|
||||
/* write TS length to chip */
|
||||
cx_write(MO_TS_LNGTH, buf->vb.width);
|
||||
|
||||
/* FIXME: this needs a review.
|
||||
* also: move to cx88-blackbird + cx88-dvb source files? */
|
||||
|
||||
dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
|
||||
|
||||
if ( (core->active_type_id == CX88_MPEG_DVB) &&
|
||||
(core->board.mpeg & CX88_MPEG_DVB) ) {
|
||||
|
||||
dprintk( 1, "cx8802_start_dma doing .dvb\n");
|
||||
/* negedge driven & software reset */
|
||||
cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
|
||||
udelay(100);
|
||||
cx_write(MO_PINMUX_IO, 0x00);
|
||||
cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01);
|
||||
switch (core->boardnr) {
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
|
||||
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
|
||||
case CX88_BOARD_PCHDTV_HD5500:
|
||||
cx_write(TS_SOP_STAT, 1<<13);
|
||||
break;
|
||||
case CX88_BOARD_SAMSUNG_SMT_7020:
|
||||
cx_write(TS_SOP_STAT, 0x00);
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
|
||||
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
|
||||
cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
|
||||
udelay(100);
|
||||
break;
|
||||
case CX88_BOARD_HAUPPAUGE_HVR1300:
|
||||
/* Enable MPEG parallel IO and video signal pins */
|
||||
cx_write(MO_PINMUX_IO, 0x88);
|
||||
cx_write(TS_SOP_STAT, 0);
|
||||
cx_write(TS_VALERR_CNTRL, 0);
|
||||
break;
|
||||
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
|
||||
/* Enable MPEG parallel IO and video signal pins */
|
||||
cx_write(MO_PINMUX_IO, 0x88);
|
||||
cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4));
|
||||
dev->ts_gen_cntrl = 5;
|
||||
cx_write(TS_SOP_STAT, 0);
|
||||
cx_write(TS_VALERR_CNTRL, 0);
|
||||
udelay(100);
|
||||
break;
|
||||
default:
|
||||
cx_write(TS_SOP_STAT, 0x00);
|
||||
break;
|
||||
}
|
||||
cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
|
||||
udelay(100);
|
||||
} else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
|
||||
(core->board.mpeg & CX88_MPEG_BLACKBIRD) ) {
|
||||
dprintk( 1, "cx8802_start_dma doing .blackbird\n");
|
||||
cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
|
||||
|
||||
cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
|
||||
udelay(100);
|
||||
|
||||
cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */
|
||||
cx_write(TS_VALERR_CNTRL, 0x2000);
|
||||
|
||||
cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
|
||||
udelay(100);
|
||||
} else {
|
||||
printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__,
|
||||
core->board.mpeg );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* reset counter */
|
||||
cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET);
|
||||
q->count = 1;
|
||||
|
||||
/* enable irqs */
|
||||
dprintk( 1, "setting the interrupt mask\n" );
|
||||
cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT);
|
||||
cx_set(MO_TS_INTMSK, 0x1f0011);
|
||||
|
||||
/* start dma */
|
||||
cx_set(MO_DEV_CNTRL2, (1<<5));
|
||||
cx_set(MO_TS_DMACNTRL, 0x11);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx8802_stop_dma(struct cx8802_dev *dev)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
dprintk( 1, "cx8802_stop_dma\n" );
|
||||
|
||||
/* stop dma */
|
||||
cx_clear(MO_TS_DMACNTRL, 0x11);
|
||||
|
||||
/* disable irqs */
|
||||
cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT);
|
||||
cx_clear(MO_TS_INTMSK, 0x1f0011);
|
||||
|
||||
/* Reset the controller */
|
||||
cx_write(TS_GEN_CNTRL, 0xcd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx8802_restart_queue(struct cx8802_dev *dev,
|
||||
struct cx88_dmaqueue *q)
|
||||
{
|
||||
struct cx88_buffer *buf;
|
||||
|
||||
dprintk( 1, "cx8802_restart_queue\n" );
|
||||
if (list_empty(&q->active))
|
||||
{
|
||||
struct cx88_buffer *prev;
|
||||
prev = NULL;
|
||||
|
||||
dprintk(1, "cx8802_restart_queue: queue is empty\n" );
|
||||
|
||||
for (;;) {
|
||||
if (list_empty(&q->queued))
|
||||
return 0;
|
||||
buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
|
||||
if (NULL == prev) {
|
||||
list_move_tail(&buf->vb.queue, &q->active);
|
||||
cx8802_start_dma(dev, q, buf);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
|
||||
dprintk(1,"[%p/%d] restart_queue - first active\n",
|
||||
buf,buf->vb.i);
|
||||
|
||||
} else if (prev->vb.width == buf->vb.width &&
|
||||
prev->vb.height == buf->vb.height &&
|
||||
prev->fmt == buf->fmt) {
|
||||
list_move_tail(&buf->vb.queue, &q->active);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
dprintk(1,"[%p/%d] restart_queue - move to active\n",
|
||||
buf,buf->vb.i);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
prev = buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
|
||||
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
|
||||
buf, buf->vb.i);
|
||||
cx8802_start_dma(dev, q, buf);
|
||||
list_for_each_entry(buf, &q->active, vb.queue)
|
||||
buf->count = q->count++;
|
||||
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
|
||||
struct cx88_buffer *buf, enum v4l2_field field)
|
||||
{
|
||||
int size = dev->ts_packet_size * dev->ts_packet_count;
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
int rc;
|
||||
|
||||
dprintk(1, "%s: %p\n", __func__, buf);
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < size)
|
||||
return -EINVAL;
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
buf->vb.width = dev->ts_packet_size;
|
||||
buf->vb.height = dev->ts_packet_count;
|
||||
buf->vb.size = size;
|
||||
buf->vb.field = field /*V4L2_FIELD_TOP*/;
|
||||
|
||||
if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
|
||||
goto fail;
|
||||
cx88_risc_databuffer(dev->pci, &buf->risc,
|
||||
dma->sglist,
|
||||
buf->vb.width, buf->vb.height, 0);
|
||||
}
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cx88_free_buffer(q,buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
|
||||
{
|
||||
struct cx88_buffer *prev;
|
||||
struct cx88_dmaqueue *cx88q = &dev->mpegq;
|
||||
|
||||
dprintk( 1, "cx8802_buf_queue\n" );
|
||||
/* add jump to stopper */
|
||||
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
|
||||
buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
|
||||
|
||||
if (list_empty(&cx88q->active)) {
|
||||
dprintk( 1, "queue is empty - first active\n" );
|
||||
list_add_tail(&buf->vb.queue,&cx88q->active);
|
||||
cx8802_start_dma(dev, cx88q, buf);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = cx88q->count++;
|
||||
mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
|
||||
dprintk(1,"[%p/%d] %s - first active\n",
|
||||
buf, buf->vb.i, __func__);
|
||||
|
||||
} else {
|
||||
dprintk( 1, "queue is not empty - append to active\n" );
|
||||
prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
|
||||
list_add_tail(&buf->vb.queue,&cx88q->active);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = cx88q->count++;
|
||||
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
dprintk( 1, "[%p/%d] %s - append to active\n",
|
||||
buf, buf->vb.i, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int restart)
|
||||
{
|
||||
struct cx88_dmaqueue *q = &dev->mpegq;
|
||||
struct cx88_buffer *buf;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->slock,flags);
|
||||
while (!list_empty(&q->active)) {
|
||||
buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
|
||||
list_del(&buf->vb.queue);
|
||||
buf->vb.state = VIDEOBUF_ERROR;
|
||||
wake_up(&buf->vb.done);
|
||||
dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
|
||||
buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
|
||||
}
|
||||
if (restart)
|
||||
{
|
||||
dprintk(1, "restarting queue\n" );
|
||||
cx8802_restart_queue(dev,q);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->slock,flags);
|
||||
}
|
||||
|
||||
void cx8802_cancel_buffers(struct cx8802_dev *dev)
|
||||
{
|
||||
struct cx88_dmaqueue *q = &dev->mpegq;
|
||||
|
||||
dprintk( 1, "cx8802_cancel_buffers" );
|
||||
del_timer_sync(&q->timeout);
|
||||
cx8802_stop_dma(dev);
|
||||
do_cancel_buffers(dev,"cancel",0);
|
||||
}
|
||||
|
||||
static void cx8802_timeout(unsigned long data)
|
||||
{
|
||||
struct cx8802_dev *dev = (struct cx8802_dev*)data;
|
||||
|
||||
dprintk(1, "%s\n",__func__);
|
||||
|
||||
if (debug)
|
||||
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
|
||||
cx8802_stop_dma(dev);
|
||||
do_cancel_buffers(dev,"timeout",1);
|
||||
}
|
||||
|
||||
static const char * cx88_mpeg_irqs[32] = {
|
||||
"ts_risci1", NULL, NULL, NULL,
|
||||
"ts_risci2", NULL, NULL, NULL,
|
||||
"ts_oflow", NULL, NULL, NULL,
|
||||
"ts_sync", NULL, NULL, NULL,
|
||||
"opc_err", "par_err", "rip_err", "pci_abort",
|
||||
"ts_err?",
|
||||
};
|
||||
|
||||
static void cx8802_mpeg_irq(struct cx8802_dev *dev)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
u32 status, mask, count;
|
||||
|
||||
dprintk( 1, "cx8802_mpeg_irq\n" );
|
||||
status = cx_read(MO_TS_INTSTAT);
|
||||
mask = cx_read(MO_TS_INTMSK);
|
||||
if (0 == (status & mask))
|
||||
return;
|
||||
|
||||
cx_write(MO_TS_INTSTAT, status);
|
||||
|
||||
if (debug || (status & mask & ~0xff))
|
||||
cx88_print_irqbits(core->name, "irq mpeg ",
|
||||
cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs),
|
||||
status, mask);
|
||||
|
||||
/* risc op code error */
|
||||
if (status & (1 << 16)) {
|
||||
printk(KERN_WARNING "%s: mpeg risc op code error\n",core->name);
|
||||
cx_clear(MO_TS_DMACNTRL, 0x11);
|
||||
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
|
||||
}
|
||||
|
||||
/* risc1 y */
|
||||
if (status & 0x01) {
|
||||
dprintk( 1, "wake up\n" );
|
||||
spin_lock(&dev->slock);
|
||||
count = cx_read(MO_TS_GPCNT);
|
||||
cx88_wakeup(dev->core, &dev->mpegq, count);
|
||||
spin_unlock(&dev->slock);
|
||||
}
|
||||
|
||||
/* risc2 y */
|
||||
if (status & 0x10) {
|
||||
spin_lock(&dev->slock);
|
||||
cx8802_restart_queue(dev,&dev->mpegq);
|
||||
spin_unlock(&dev->slock);
|
||||
}
|
||||
|
||||
/* other general errors */
|
||||
if (status & 0x1f0100) {
|
||||
dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
|
||||
spin_lock(&dev->slock);
|
||||
cx8802_stop_dma(dev);
|
||||
cx8802_restart_queue(dev,&dev->mpegq);
|
||||
spin_unlock(&dev->slock);
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_IRQ_LOOP 10
|
||||
|
||||
static irqreturn_t cx8802_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct cx8802_dev *dev = dev_id;
|
||||
struct cx88_core *core = dev->core;
|
||||
u32 status;
|
||||
int loop, handled = 0;
|
||||
|
||||
for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
|
||||
status = cx_read(MO_PCI_INTSTAT) &
|
||||
(core->pci_irqmask | PCI_INT_TSINT);
|
||||
if (0 == status)
|
||||
goto out;
|
||||
dprintk( 1, "cx8802_irq\n" );
|
||||
dprintk( 1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
|
||||
dprintk( 1, " status: %d\n", status );
|
||||
handled = 1;
|
||||
cx_write(MO_PCI_INTSTAT, status);
|
||||
|
||||
if (status & core->pci_irqmask)
|
||||
cx88_core_irq(core,status);
|
||||
if (status & PCI_INT_TSINT)
|
||||
cx8802_mpeg_irq(dev);
|
||||
}
|
||||
if (MAX_IRQ_LOOP == loop) {
|
||||
dprintk( 0, "clearing mask\n" );
|
||||
printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
|
||||
core->name);
|
||||
cx_write(MO_PCI_INTMSK,0);
|
||||
}
|
||||
|
||||
out:
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static int cx8802_init_common(struct cx8802_dev *dev)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
int err;
|
||||
|
||||
/* pci init */
|
||||
if (pci_enable_device(dev->pci))
|
||||
return -EIO;
|
||||
pci_set_master(dev->pci);
|
||||
if (!pci_dma_supported(dev->pci,DMA_BIT_MASK(32))) {
|
||||
printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dev->pci_rev = dev->pci->revision;
|
||||
pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat);
|
||||
printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
|
||||
"latency: %d, mmio: 0x%llx\n", dev->core->name,
|
||||
pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
|
||||
dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0));
|
||||
|
||||
/* initialize driver struct */
|
||||
spin_lock_init(&dev->slock);
|
||||
|
||||
/* init dma queue */
|
||||
INIT_LIST_HEAD(&dev->mpegq.active);
|
||||
INIT_LIST_HEAD(&dev->mpegq.queued);
|
||||
dev->mpegq.timeout.function = cx8802_timeout;
|
||||
dev->mpegq.timeout.data = (unsigned long)dev;
|
||||
init_timer(&dev->mpegq.timeout);
|
||||
cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
|
||||
MO_TS_DMACNTRL,0x11,0x00);
|
||||
|
||||
/* get irq */
|
||||
err = request_irq(dev->pci->irq, cx8802_irq,
|
||||
IRQF_SHARED, dev->core->name, dev);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "%s: can't get IRQ %d\n",
|
||||
dev->core->name, dev->pci->irq);
|
||||
return err;
|
||||
}
|
||||
cx_set(MO_PCI_INTMSK, core->pci_irqmask);
|
||||
|
||||
/* everything worked */
|
||||
pci_set_drvdata(dev->pci,dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx8802_fini_common(struct cx8802_dev *dev)
|
||||
{
|
||||
dprintk( 2, "cx8802_fini_common\n" );
|
||||
cx8802_stop_dma(dev);
|
||||
pci_disable_device(dev->pci);
|
||||
|
||||
/* unregister stuff */
|
||||
free_irq(dev->pci->irq, dev);
|
||||
|
||||
/* free memory */
|
||||
btcx_riscmem_free(dev->pci,&dev->mpegq.stopper);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
|
||||
{
|
||||
struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
|
||||
struct cx88_core *core = dev->core;
|
||||
unsigned long flags;
|
||||
|
||||
/* stop mpeg dma */
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
if (!list_empty(&dev->mpegq.active)) {
|
||||
dprintk( 2, "suspend\n" );
|
||||
printk("%s: suspend mpeg\n", core->name);
|
||||
cx8802_stop_dma(dev);
|
||||
del_timer(&dev->mpegq.timeout);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
|
||||
/* FIXME -- shutdown device */
|
||||
cx88_shutdown(dev->core);
|
||||
|
||||
pci_save_state(pci_dev);
|
||||
if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
|
||||
pci_disable_device(pci_dev);
|
||||
dev->state.disabled = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx8802_resume_common(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
|
||||
struct cx88_core *core = dev->core;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
if (dev->state.disabled) {
|
||||
err=pci_enable_device(pci_dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: can't enable device\n",
|
||||
dev->core->name);
|
||||
return err;
|
||||
}
|
||||
dev->state.disabled = 0;
|
||||
}
|
||||
err=pci_set_power_state(pci_dev, PCI_D0);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: can't enable device\n",
|
||||
dev->core->name);
|
||||
pci_disable_device(pci_dev);
|
||||
dev->state.disabled = 1;
|
||||
|
||||
return err;
|
||||
}
|
||||
pci_restore_state(pci_dev);
|
||||
|
||||
/* FIXME: re-initialize hardware */
|
||||
cx88_reset(dev->core);
|
||||
|
||||
/* restart video+vbi capture */
|
||||
spin_lock_irqsave(&dev->slock, flags);
|
||||
if (!list_empty(&dev->mpegq.active)) {
|
||||
printk("%s: resume mpeg\n", core->name);
|
||||
cx8802_restart_queue(dev,&dev->mpegq);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype)
|
||||
{
|
||||
struct cx8802_driver *d;
|
||||
|
||||
list_for_each_entry(d, &dev->drvlist, drvlist)
|
||||
if (d->type_id == btype)
|
||||
return d;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Driver asked for hardware access. */
|
||||
static int cx8802_request_acquire(struct cx8802_driver *drv)
|
||||
{
|
||||
struct cx88_core *core = drv->core;
|
||||
unsigned int i;
|
||||
|
||||
/* Fail a request for hardware if the device is busy. */
|
||||
if (core->active_type_id != CX88_BOARD_NONE &&
|
||||
core->active_type_id != drv->type_id)
|
||||
return -EBUSY;
|
||||
|
||||
if (drv->type_id == CX88_MPEG_DVB) {
|
||||
/* When switching to DVB, always set the input to the tuner */
|
||||
core->last_analog_input = core->input;
|
||||
core->input = 0;
|
||||
for (i = 0;
|
||||
i < (sizeof(core->board.input) / sizeof(struct cx88_input));
|
||||
i++) {
|
||||
if (core->board.input[i].type == CX88_VMUX_DVB) {
|
||||
core->input = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (drv->advise_acquire)
|
||||
{
|
||||
core->active_ref++;
|
||||
if (core->active_type_id == CX88_BOARD_NONE) {
|
||||
core->active_type_id = drv->type_id;
|
||||
drv->advise_acquire(drv);
|
||||
}
|
||||
|
||||
mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Driver asked to release hardware. */
|
||||
static int cx8802_request_release(struct cx8802_driver *drv)
|
||||
{
|
||||
struct cx88_core *core = drv->core;
|
||||
|
||||
if (drv->advise_release && --core->active_ref == 0)
|
||||
{
|
||||
if (drv->type_id == CX88_MPEG_DVB) {
|
||||
/* If the DVB driver is releasing, reset the input
|
||||
state to the last configured analog input */
|
||||
core->input = core->last_analog_input;
|
||||
}
|
||||
|
||||
drv->advise_release(drv);
|
||||
core->active_type_id = CX88_BOARD_NONE;
|
||||
mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx8802_check_driver(struct cx8802_driver *drv)
|
||||
{
|
||||
if (drv == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if ((drv->type_id != CX88_MPEG_DVB) &&
|
||||
(drv->type_id != CX88_MPEG_BLACKBIRD))
|
||||
return -EINVAL;
|
||||
|
||||
if ((drv->hw_access != CX8802_DRVCTL_SHARED) &&
|
||||
(drv->hw_access != CX8802_DRVCTL_EXCLUSIVE))
|
||||
return -EINVAL;
|
||||
|
||||
if ((drv->probe == NULL) ||
|
||||
(drv->remove == NULL) ||
|
||||
(drv->advise_acquire == NULL) ||
|
||||
(drv->advise_release == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx8802_register_driver(struct cx8802_driver *drv)
|
||||
{
|
||||
struct cx8802_dev *dev;
|
||||
struct cx8802_driver *driver;
|
||||
int err, i = 0;
|
||||
|
||||
printk(KERN_INFO
|
||||
"cx88/2: registering cx8802 driver, type: %s access: %s\n",
|
||||
drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
|
||||
drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
|
||||
|
||||
if ((err = cx8802_check_driver(drv)) != 0) {
|
||||
printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_lock(&cx8802_mutex);
|
||||
|
||||
list_for_each_entry(dev, &cx8802_devlist, devlist) {
|
||||
printk(KERN_INFO
|
||||
"%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
|
||||
dev->core->name, dev->pci->subsystem_vendor,
|
||||
dev->pci->subsystem_device, dev->core->board.name,
|
||||
dev->core->boardnr);
|
||||
|
||||
/* Bring up a new struct for each driver instance */
|
||||
driver = kzalloc(sizeof(*drv),GFP_KERNEL);
|
||||
if (driver == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Snapshot of the driver registration data */
|
||||
drv->core = dev->core;
|
||||
drv->suspend = cx8802_suspend_common;
|
||||
drv->resume = cx8802_resume_common;
|
||||
drv->request_acquire = cx8802_request_acquire;
|
||||
drv->request_release = cx8802_request_release;
|
||||
memcpy(driver, drv, sizeof(*driver));
|
||||
|
||||
mutex_lock(&drv->core->lock);
|
||||
err = drv->probe(driver);
|
||||
if (err == 0) {
|
||||
i++;
|
||||
list_add_tail(&driver->drvlist, &dev->drvlist);
|
||||
} else {
|
||||
printk(KERN_ERR
|
||||
"%s/2: cx8802 probe failed, err = %d\n",
|
||||
dev->core->name, err);
|
||||
}
|
||||
mutex_unlock(&drv->core->lock);
|
||||
}
|
||||
|
||||
err = i ? 0 : -ENODEV;
|
||||
out:
|
||||
mutex_unlock(&cx8802_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
int cx8802_unregister_driver(struct cx8802_driver *drv)
|
||||
{
|
||||
struct cx8802_dev *dev;
|
||||
struct cx8802_driver *d, *dtmp;
|
||||
int err = 0;
|
||||
|
||||
printk(KERN_INFO
|
||||
"cx88/2: unregistering cx8802 driver, type: %s access: %s\n",
|
||||
drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
|
||||
drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
|
||||
|
||||
mutex_lock(&cx8802_mutex);
|
||||
|
||||
list_for_each_entry(dev, &cx8802_devlist, devlist) {
|
||||
printk(KERN_INFO
|
||||
"%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
|
||||
dev->core->name, dev->pci->subsystem_vendor,
|
||||
dev->pci->subsystem_device, dev->core->board.name,
|
||||
dev->core->boardnr);
|
||||
|
||||
mutex_lock(&dev->core->lock);
|
||||
|
||||
list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) {
|
||||
/* only unregister the correct driver type */
|
||||
if (d->type_id != drv->type_id)
|
||||
continue;
|
||||
|
||||
err = d->remove(d);
|
||||
if (err == 0) {
|
||||
list_del(&d->drvlist);
|
||||
kfree(d);
|
||||
} else
|
||||
printk(KERN_ERR "%s/2: cx8802 driver remove "
|
||||
"failed (%d)\n", dev->core->name, err);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->core->lock);
|
||||
}
|
||||
|
||||
mutex_unlock(&cx8802_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
static int cx8802_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
struct cx8802_dev *dev;
|
||||
struct cx88_core *core;
|
||||
int err;
|
||||
|
||||
/* general setup */
|
||||
core = cx88_core_get(pci_dev);
|
||||
if (NULL == core)
|
||||
return -EINVAL;
|
||||
|
||||
printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
|
||||
|
||||
err = -ENODEV;
|
||||
if (!core->board.mpeg)
|
||||
goto fail_core;
|
||||
|
||||
err = -ENOMEM;
|
||||
dev = kzalloc(sizeof(*dev),GFP_KERNEL);
|
||||
if (NULL == dev)
|
||||
goto fail_core;
|
||||
dev->pci = pci_dev;
|
||||
dev->core = core;
|
||||
|
||||
/* Maintain a reference so cx88-video can query the 8802 device. */
|
||||
core->dvbdev = dev;
|
||||
|
||||
err = cx8802_init_common(dev);
|
||||
if (err != 0)
|
||||
goto fail_free;
|
||||
|
||||
INIT_LIST_HEAD(&dev->drvlist);
|
||||
mutex_lock(&cx8802_mutex);
|
||||
list_add_tail(&dev->devlist,&cx8802_devlist);
|
||||
mutex_unlock(&cx8802_mutex);
|
||||
|
||||
/* now autoload cx88-dvb or cx88-blackbird */
|
||||
request_modules(dev);
|
||||
return 0;
|
||||
|
||||
fail_free:
|
||||
kfree(dev);
|
||||
fail_core:
|
||||
core->dvbdev = NULL;
|
||||
cx88_core_put(core,pci_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void cx8802_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct cx8802_dev *dev;
|
||||
|
||||
dev = pci_get_drvdata(pci_dev);
|
||||
|
||||
dprintk( 1, "%s\n", __func__);
|
||||
|
||||
flush_request_modules(dev);
|
||||
|
||||
mutex_lock(&dev->core->lock);
|
||||
|
||||
if (!list_empty(&dev->drvlist)) {
|
||||
struct cx8802_driver *drv, *tmp;
|
||||
int err;
|
||||
|
||||
printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver "
|
||||
"while cx8802 sub-drivers still loaded?!\n",
|
||||
dev->core->name);
|
||||
|
||||
list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) {
|
||||
err = drv->remove(drv);
|
||||
if (err == 0) {
|
||||
list_del(&drv->drvlist);
|
||||
} else
|
||||
printk(KERN_ERR "%s/2: cx8802 driver remove "
|
||||
"failed (%d)\n", dev->core->name, err);
|
||||
kfree(drv);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->core->lock);
|
||||
|
||||
/* Destroy any 8802 reference. */
|
||||
dev->core->dvbdev = NULL;
|
||||
|
||||
/* common */
|
||||
cx8802_fini_common(dev);
|
||||
cx88_core_put(dev->core,dev->pci);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static const struct pci_device_id cx8802_pci_tbl[] = {
|
||||
{
|
||||
.vendor = 0x14f1,
|
||||
.device = 0x8802,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
},{
|
||||
/* --- end of list --- */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
|
||||
|
||||
static struct pci_driver cx8802_pci_driver = {
|
||||
.name = "cx88-mpeg driver manager",
|
||||
.id_table = cx8802_pci_tbl,
|
||||
.probe = cx8802_probe,
|
||||
.remove = cx8802_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(cx8802_pci_driver);
|
||||
|
||||
EXPORT_SYMBOL(cx8802_buf_prepare);
|
||||
EXPORT_SYMBOL(cx8802_buf_queue);
|
||||
EXPORT_SYMBOL(cx8802_cancel_buffers);
|
||||
|
||||
EXPORT_SYMBOL(cx8802_register_driver);
|
||||
EXPORT_SYMBOL(cx8802_unregister_driver);
|
||||
EXPORT_SYMBOL(cx8802_get_driver);
|
||||
/* ----------------------------------------------------------- */
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
* kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
|
||||
*/
|
836
drivers/media/pci/cx88/cx88-reg.h
Normal file
836
drivers/media/pci/cx88/cx88-reg.h
Normal file
|
@ -0,0 +1,836 @@
|
|||
/*
|
||||
|
||||
cx88x-hw.h - CX2388x register offsets
|
||||
|
||||
Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
|
||||
2001 Michael Eskin
|
||||
2002 Yurij Sysoev <yurij@naturesoft.net>
|
||||
2003 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.
|
||||
*/
|
||||
|
||||
#ifndef _CX88_REG_H_
|
||||
#define _CX88_REG_H_
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* PCI IDs and config space */
|
||||
|
||||
#ifndef PCI_VENDOR_ID_CONEXANT
|
||||
# define PCI_VENDOR_ID_CONEXANT 0x14F1
|
||||
#endif
|
||||
#ifndef PCI_DEVICE_ID_CX2300_VID
|
||||
# define PCI_DEVICE_ID_CX2300_VID 0x8800
|
||||
#endif
|
||||
|
||||
#define CX88X_DEVCTRL 0x40
|
||||
#define CX88X_EN_TBFX 0x02
|
||||
#define CX88X_EN_VSFX 0x04
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* PCI controller registers */
|
||||
|
||||
/* Command and Status Register */
|
||||
#define F0_CMD_STAT_MM 0x2f0004
|
||||
#define F1_CMD_STAT_MM 0x2f0104
|
||||
#define F2_CMD_STAT_MM 0x2f0204
|
||||
#define F3_CMD_STAT_MM 0x2f0304
|
||||
#define F4_CMD_STAT_MM 0x2f0404
|
||||
|
||||
/* Device Control #1 */
|
||||
#define F0_DEV_CNTRL1_MM 0x2f0040
|
||||
#define F1_DEV_CNTRL1_MM 0x2f0140
|
||||
#define F2_DEV_CNTRL1_MM 0x2f0240
|
||||
#define F3_DEV_CNTRL1_MM 0x2f0340
|
||||
#define F4_DEV_CNTRL1_MM 0x2f0440
|
||||
|
||||
/* Device Control #1 */
|
||||
#define F0_BAR0_MM 0x2f0010
|
||||
#define F1_BAR0_MM 0x2f0110
|
||||
#define F2_BAR0_MM 0x2f0210
|
||||
#define F3_BAR0_MM 0x2f0310
|
||||
#define F4_BAR0_MM 0x2f0410
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* DMA Controller registers */
|
||||
|
||||
#define MO_PDMA_STHRSH 0x200000 // Source threshold
|
||||
#define MO_PDMA_STADRS 0x200004 // Source target address
|
||||
#define MO_PDMA_SIADRS 0x200008 // Source internal address
|
||||
#define MO_PDMA_SCNTRL 0x20000C // Source control
|
||||
#define MO_PDMA_DTHRSH 0x200010 // Destination threshold
|
||||
#define MO_PDMA_DTADRS 0x200014 // Destination target address
|
||||
#define MO_PDMA_DIADRS 0x200018 // Destination internal address
|
||||
#define MO_PDMA_DCNTRL 0x20001C // Destination control
|
||||
#define MO_LD_SSID 0x200030 // Load subsystem ID
|
||||
#define MO_DEV_CNTRL2 0x200034 // Device control
|
||||
#define MO_PCI_INTMSK 0x200040 // PCI interrupt mask
|
||||
#define MO_PCI_INTSTAT 0x200044 // PCI interrupt status
|
||||
#define MO_PCI_INTMSTAT 0x200048 // PCI interrupt masked status
|
||||
#define MO_VID_INTMSK 0x200050 // Video interrupt mask
|
||||
#define MO_VID_INTSTAT 0x200054 // Video interrupt status
|
||||
#define MO_VID_INTMSTAT 0x200058 // Video interrupt masked status
|
||||
#define MO_VID_INTSSTAT 0x20005C // Video interrupt set status
|
||||
#define MO_AUD_INTMSK 0x200060 // Audio interrupt mask
|
||||
#define MO_AUD_INTSTAT 0x200064 // Audio interrupt status
|
||||
#define MO_AUD_INTMSTAT 0x200068 // Audio interrupt masked status
|
||||
#define MO_AUD_INTSSTAT 0x20006C // Audio interrupt set status
|
||||
#define MO_TS_INTMSK 0x200070 // Transport stream interrupt mask
|
||||
#define MO_TS_INTSTAT 0x200074 // Transport stream interrupt status
|
||||
#define MO_TS_INTMSTAT 0x200078 // Transport stream interrupt mask status
|
||||
#define MO_TS_INTSSTAT 0x20007C // Transport stream interrupt set status
|
||||
#define MO_VIP_INTMSK 0x200080 // VIP interrupt mask
|
||||
#define MO_VIP_INTSTAT 0x200084 // VIP interrupt status
|
||||
#define MO_VIP_INTMSTAT 0x200088 // VIP interrupt masked status
|
||||
#define MO_VIP_INTSSTAT 0x20008C // VIP interrupt set status
|
||||
#define MO_GPHST_INTMSK 0x200090 // Host interrupt mask
|
||||
#define MO_GPHST_INTSTAT 0x200094 // Host interrupt status
|
||||
#define MO_GPHST_INTMSTAT 0x200098 // Host interrupt masked status
|
||||
#define MO_GPHST_INTSSTAT 0x20009C // Host interrupt set status
|
||||
|
||||
// DMA Channels 1-6 belong to SPIPE
|
||||
#define MO_DMA7_PTR1 0x300018 // {24}RW* DMA Current Ptr : Ch#7
|
||||
#define MO_DMA8_PTR1 0x30001C // {24}RW* DMA Current Ptr : Ch#8
|
||||
|
||||
// DMA Channels 9-20 belong to SPIPE
|
||||
#define MO_DMA21_PTR1 0x300080 // {24}R0* DMA Current Ptr : Ch#21
|
||||
#define MO_DMA22_PTR1 0x300084 // {24}R0* DMA Current Ptr : Ch#22
|
||||
#define MO_DMA23_PTR1 0x300088 // {24}R0* DMA Current Ptr : Ch#23
|
||||
#define MO_DMA24_PTR1 0x30008C // {24}R0* DMA Current Ptr : Ch#24
|
||||
#define MO_DMA25_PTR1 0x300090 // {24}R0* DMA Current Ptr : Ch#25
|
||||
#define MO_DMA26_PTR1 0x300094 // {24}R0* DMA Current Ptr : Ch#26
|
||||
#define MO_DMA27_PTR1 0x300098 // {24}R0* DMA Current Ptr : Ch#27
|
||||
#define MO_DMA28_PTR1 0x30009C // {24}R0* DMA Current Ptr : Ch#28
|
||||
#define MO_DMA29_PTR1 0x3000A0 // {24}R0* DMA Current Ptr : Ch#29
|
||||
#define MO_DMA30_PTR1 0x3000A4 // {24}R0* DMA Current Ptr : Ch#30
|
||||
#define MO_DMA31_PTR1 0x3000A8 // {24}R0* DMA Current Ptr : Ch#31
|
||||
#define MO_DMA32_PTR1 0x3000AC // {24}R0* DMA Current Ptr : Ch#32
|
||||
|
||||
#define MO_DMA21_PTR2 0x3000C0 // {24}RW* DMA Tab Ptr : Ch#21
|
||||
#define MO_DMA22_PTR2 0x3000C4 // {24}RW* DMA Tab Ptr : Ch#22
|
||||
#define MO_DMA23_PTR2 0x3000C8 // {24}RW* DMA Tab Ptr : Ch#23
|
||||
#define MO_DMA24_PTR2 0x3000CC // {24}RW* DMA Tab Ptr : Ch#24
|
||||
#define MO_DMA25_PTR2 0x3000D0 // {24}RW* DMA Tab Ptr : Ch#25
|
||||
#define MO_DMA26_PTR2 0x3000D4 // {24}RW* DMA Tab Ptr : Ch#26
|
||||
#define MO_DMA27_PTR2 0x3000D8 // {24}RW* DMA Tab Ptr : Ch#27
|
||||
#define MO_DMA28_PTR2 0x3000DC // {24}RW* DMA Tab Ptr : Ch#28
|
||||
#define MO_DMA29_PTR2 0x3000E0 // {24}RW* DMA Tab Ptr : Ch#29
|
||||
#define MO_DMA30_PTR2 0x3000E4 // {24}RW* DMA Tab Ptr : Ch#30
|
||||
#define MO_DMA31_PTR2 0x3000E8 // {24}RW* DMA Tab Ptr : Ch#31
|
||||
#define MO_DMA32_PTR2 0x3000EC // {24}RW* DMA Tab Ptr : Ch#32
|
||||
|
||||
#define MO_DMA21_CNT1 0x300100 // {11}RW* DMA Buffer Size : Ch#21
|
||||
#define MO_DMA22_CNT1 0x300104 // {11}RW* DMA Buffer Size : Ch#22
|
||||
#define MO_DMA23_CNT1 0x300108 // {11}RW* DMA Buffer Size : Ch#23
|
||||
#define MO_DMA24_CNT1 0x30010C // {11}RW* DMA Buffer Size : Ch#24
|
||||
#define MO_DMA25_CNT1 0x300110 // {11}RW* DMA Buffer Size : Ch#25
|
||||
#define MO_DMA26_CNT1 0x300114 // {11}RW* DMA Buffer Size : Ch#26
|
||||
#define MO_DMA27_CNT1 0x300118 // {11}RW* DMA Buffer Size : Ch#27
|
||||
#define MO_DMA28_CNT1 0x30011C // {11}RW* DMA Buffer Size : Ch#28
|
||||
#define MO_DMA29_CNT1 0x300120 // {11}RW* DMA Buffer Size : Ch#29
|
||||
#define MO_DMA30_CNT1 0x300124 // {11}RW* DMA Buffer Size : Ch#30
|
||||
#define MO_DMA31_CNT1 0x300128 // {11}RW* DMA Buffer Size : Ch#31
|
||||
#define MO_DMA32_CNT1 0x30012C // {11}RW* DMA Buffer Size : Ch#32
|
||||
|
||||
#define MO_DMA21_CNT2 0x300140 // {11}RW* DMA Table Size : Ch#21
|
||||
#define MO_DMA22_CNT2 0x300144 // {11}RW* DMA Table Size : Ch#22
|
||||
#define MO_DMA23_CNT2 0x300148 // {11}RW* DMA Table Size : Ch#23
|
||||
#define MO_DMA24_CNT2 0x30014C // {11}RW* DMA Table Size : Ch#24
|
||||
#define MO_DMA25_CNT2 0x300150 // {11}RW* DMA Table Size : Ch#25
|
||||
#define MO_DMA26_CNT2 0x300154 // {11}RW* DMA Table Size : Ch#26
|
||||
#define MO_DMA27_CNT2 0x300158 // {11}RW* DMA Table Size : Ch#27
|
||||
#define MO_DMA28_CNT2 0x30015C // {11}RW* DMA Table Size : Ch#28
|
||||
#define MO_DMA29_CNT2 0x300160 // {11}RW* DMA Table Size : Ch#29
|
||||
#define MO_DMA30_CNT2 0x300164 // {11}RW* DMA Table Size : Ch#30
|
||||
#define MO_DMA31_CNT2 0x300168 // {11}RW* DMA Table Size : Ch#31
|
||||
#define MO_DMA32_CNT2 0x30016C // {11}RW* DMA Table Size : Ch#32
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Video registers */
|
||||
|
||||
#define MO_VIDY_DMA 0x310000 // {64}RWp Video Y
|
||||
#define MO_VIDU_DMA 0x310008 // {64}RWp Video U
|
||||
#define MO_VIDV_DMA 0x310010 // {64}RWp Video V
|
||||
#define MO_VBI_DMA 0x310018 // {64}RWp VBI (Vertical blanking interval)
|
||||
|
||||
#define MO_DEVICE_STATUS 0x310100
|
||||
#define MO_INPUT_FORMAT 0x310104
|
||||
#define MO_AGC_BURST 0x31010c
|
||||
#define MO_CONTR_BRIGHT 0x310110
|
||||
#define MO_UV_SATURATION 0x310114
|
||||
#define MO_HUE 0x310118
|
||||
#define MO_HTOTAL 0x310120
|
||||
#define MO_HDELAY_EVEN 0x310124
|
||||
#define MO_HDELAY_ODD 0x310128
|
||||
#define MO_VDELAY_ODD 0x31012c
|
||||
#define MO_VDELAY_EVEN 0x310130
|
||||
#define MO_HACTIVE_EVEN 0x31013c
|
||||
#define MO_HACTIVE_ODD 0x310140
|
||||
#define MO_VACTIVE_EVEN 0x310144
|
||||
#define MO_VACTIVE_ODD 0x310148
|
||||
#define MO_HSCALE_EVEN 0x31014c
|
||||
#define MO_HSCALE_ODD 0x310150
|
||||
#define MO_VSCALE_EVEN 0x310154
|
||||
#define MO_FILTER_EVEN 0x31015c
|
||||
#define MO_VSCALE_ODD 0x310158
|
||||
#define MO_FILTER_ODD 0x310160
|
||||
#define MO_OUTPUT_FORMAT 0x310164
|
||||
|
||||
#define MO_PLL_REG 0x310168 // PLL register
|
||||
#define MO_PLL_ADJ_CTRL 0x31016c // PLL adjust control register
|
||||
#define MO_SCONV_REG 0x310170 // sample rate conversion register
|
||||
#define MO_SCONV_FIFO 0x310174 // sample rate conversion fifo
|
||||
#define MO_SUB_STEP 0x310178 // subcarrier step size
|
||||
#define MO_SUB_STEP_DR 0x31017c // subcarrier step size for DR line
|
||||
|
||||
#define MO_CAPTURE_CTRL 0x310180 // capture control
|
||||
#define MO_COLOR_CTRL 0x310184
|
||||
#define MO_VBI_PACKET 0x310188 // vbi packet size / delay
|
||||
#define MO_FIELD_COUNT 0x310190 // field counter
|
||||
#define MO_VIP_CONFIG 0x310194
|
||||
#define MO_VBOS_CONTROL 0x3101a8
|
||||
|
||||
#define MO_AGC_BACK_VBI 0x310200
|
||||
#define MO_AGC_SYNC_TIP1 0x310208
|
||||
|
||||
#define MO_VIDY_GPCNT 0x31C020 // {16}RO Video Y general purpose counter
|
||||
#define MO_VIDU_GPCNT 0x31C024 // {16}RO Video U general purpose counter
|
||||
#define MO_VIDV_GPCNT 0x31C028 // {16}RO Video V general purpose counter
|
||||
#define MO_VBI_GPCNT 0x31C02C // {16}RO VBI general purpose counter
|
||||
#define MO_VIDY_GPCNTRL 0x31C030 // {2}WO Video Y general purpose control
|
||||
#define MO_VIDU_GPCNTRL 0x31C034 // {2}WO Video U general purpose control
|
||||
#define MO_VIDV_GPCNTRL 0x31C038 // {2}WO Video V general purpose control
|
||||
#define MO_VBI_GPCNTRL 0x31C03C // {2}WO VBI general purpose counter
|
||||
#define MO_VID_DMACNTRL 0x31C040 // {8}RW Video DMA control
|
||||
#define MO_VID_XFR_STAT 0x31C044 // {1}RO Video transfer status
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* audio registers */
|
||||
|
||||
#define MO_AUDD_DMA 0x320000 // {64}RWp Audio downstream
|
||||
#define MO_AUDU_DMA 0x320008 // {64}RWp Audio upstream
|
||||
#define MO_AUDR_DMA 0x320010 // {64}RWp Audio RDS (downstream)
|
||||
#define MO_AUDD_GPCNT 0x32C020 // {16}RO Audio down general purpose counter
|
||||
#define MO_AUDU_GPCNT 0x32C024 // {16}RO Audio up general purpose counter
|
||||
#define MO_AUDR_GPCNT 0x32C028 // {16}RO Audio RDS general purpose counter
|
||||
#define MO_AUDD_GPCNTRL 0x32C030 // {2}WO Audio down general purpose control
|
||||
#define MO_AUDU_GPCNTRL 0x32C034 // {2}WO Audio up general purpose control
|
||||
#define MO_AUDR_GPCNTRL 0x32C038 // {2}WO Audio RDS general purpose control
|
||||
#define MO_AUD_DMACNTRL 0x32C040 // {6}RW Audio DMA control
|
||||
#define MO_AUD_XFR_STAT 0x32C044 // {1}RO Audio transfer status
|
||||
#define MO_AUDD_LNGTH 0x32C048 // {12}RW Audio down line length
|
||||
#define MO_AUDR_LNGTH 0x32C04C // {12}RW Audio RDS line length
|
||||
|
||||
#define AUD_INIT 0x320100
|
||||
#define AUD_INIT_LD 0x320104
|
||||
#define AUD_SOFT_RESET 0x320108
|
||||
#define AUD_I2SINPUTCNTL 0x320120
|
||||
#define AUD_BAUDRATE 0x320124
|
||||
#define AUD_I2SOUTPUTCNTL 0x320128
|
||||
#define AAGC_HYST 0x320134
|
||||
#define AAGC_GAIN 0x320138
|
||||
#define AAGC_DEF 0x32013c
|
||||
#define AUD_IIR1_0_SEL 0x320150
|
||||
#define AUD_IIR1_0_SHIFT 0x320154
|
||||
#define AUD_IIR1_1_SEL 0x320158
|
||||
#define AUD_IIR1_1_SHIFT 0x32015c
|
||||
#define AUD_IIR1_2_SEL 0x320160
|
||||
#define AUD_IIR1_2_SHIFT 0x320164
|
||||
#define AUD_IIR1_3_SEL 0x320168
|
||||
#define AUD_IIR1_3_SHIFT 0x32016c
|
||||
#define AUD_IIR1_4_SEL 0x320170
|
||||
#define AUD_IIR1_4_SHIFT 0x32017c
|
||||
#define AUD_IIR1_5_SEL 0x320180
|
||||
#define AUD_IIR1_5_SHIFT 0x320184
|
||||
#define AUD_IIR2_0_SEL 0x320190
|
||||
#define AUD_IIR2_0_SHIFT 0x320194
|
||||
#define AUD_IIR2_1_SEL 0x320198
|
||||
#define AUD_IIR2_1_SHIFT 0x32019c
|
||||
#define AUD_IIR2_2_SEL 0x3201a0
|
||||
#define AUD_IIR2_2_SHIFT 0x3201a4
|
||||
#define AUD_IIR2_3_SEL 0x3201a8
|
||||
#define AUD_IIR2_3_SHIFT 0x3201ac
|
||||
#define AUD_IIR3_0_SEL 0x3201c0
|
||||
#define AUD_IIR3_0_SHIFT 0x3201c4
|
||||
#define AUD_IIR3_1_SEL 0x3201c8
|
||||
#define AUD_IIR3_1_SHIFT 0x3201cc
|
||||
#define AUD_IIR3_2_SEL 0x3201d0
|
||||
#define AUD_IIR3_2_SHIFT 0x3201d4
|
||||
#define AUD_IIR4_0_SEL 0x3201e0
|
||||
#define AUD_IIR4_0_SHIFT 0x3201e4
|
||||
#define AUD_IIR4_1_SEL 0x3201e8
|
||||
#define AUD_IIR4_1_SHIFT 0x3201ec
|
||||
#define AUD_IIR4_2_SEL 0x3201f0
|
||||
#define AUD_IIR4_2_SHIFT 0x3201f4
|
||||
#define AUD_IIR4_0_CA0 0x320200
|
||||
#define AUD_IIR4_0_CA1 0x320204
|
||||
#define AUD_IIR4_0_CA2 0x320208
|
||||
#define AUD_IIR4_0_CB0 0x32020c
|
||||
#define AUD_IIR4_0_CB1 0x320210
|
||||
#define AUD_IIR4_1_CA0 0x320214
|
||||
#define AUD_IIR4_1_CA1 0x320218
|
||||
#define AUD_IIR4_1_CA2 0x32021c
|
||||
#define AUD_IIR4_1_CB0 0x320220
|
||||
#define AUD_IIR4_1_CB1 0x320224
|
||||
#define AUD_IIR4_2_CA0 0x320228
|
||||
#define AUD_IIR4_2_CA1 0x32022c
|
||||
#define AUD_IIR4_2_CA2 0x320230
|
||||
#define AUD_IIR4_2_CB0 0x320234
|
||||
#define AUD_IIR4_2_CB1 0x320238
|
||||
#define AUD_HP_MD_IIR4_1 0x320250
|
||||
#define AUD_HP_PROG_IIR4_1 0x320254
|
||||
#define AUD_FM_MODE_ENABLE 0x320258
|
||||
#define AUD_POLY0_DDS_CONSTANT 0x320270
|
||||
#define AUD_DN0_FREQ 0x320274
|
||||
#define AUD_DN1_FREQ 0x320278
|
||||
#define AUD_DN1_FREQ_SHIFT 0x32027c
|
||||
#define AUD_DN1_AFC 0x320280
|
||||
#define AUD_DN1_SRC_SEL 0x320284
|
||||
#define AUD_DN1_SHFT 0x320288
|
||||
#define AUD_DN2_FREQ 0x32028c
|
||||
#define AUD_DN2_FREQ_SHIFT 0x320290
|
||||
#define AUD_DN2_AFC 0x320294
|
||||
#define AUD_DN2_SRC_SEL 0x320298
|
||||
#define AUD_DN2_SHFT 0x32029c
|
||||
#define AUD_CRDC0_SRC_SEL 0x320300
|
||||
#define AUD_CRDC0_SHIFT 0x320304
|
||||
#define AUD_CORDIC_SHIFT_0 0x320308
|
||||
#define AUD_CRDC1_SRC_SEL 0x32030c
|
||||
#define AUD_CRDC1_SHIFT 0x320310
|
||||
#define AUD_CORDIC_SHIFT_1 0x320314
|
||||
#define AUD_DCOC_0_SRC 0x320320
|
||||
#define AUD_DCOC0_SHIFT 0x320324
|
||||
#define AUD_DCOC_0_SHIFT_IN0 0x320328
|
||||
#define AUD_DCOC_0_SHIFT_IN1 0x32032c
|
||||
#define AUD_DCOC_1_SRC 0x320330
|
||||
#define AUD_DCOC1_SHIFT 0x320334
|
||||
#define AUD_DCOC_1_SHIFT_IN0 0x320338
|
||||
#define AUD_DCOC_1_SHIFT_IN1 0x32033c
|
||||
#define AUD_DCOC_2_SRC 0x320340
|
||||
#define AUD_DCOC2_SHIFT 0x320344
|
||||
#define AUD_DCOC_2_SHIFT_IN0 0x320348
|
||||
#define AUD_DCOC_2_SHIFT_IN1 0x32034c
|
||||
#define AUD_DCOC_PASS_IN 0x320350
|
||||
#define AUD_PDET_SRC 0x320370
|
||||
#define AUD_PDET_SHIFT 0x320374
|
||||
#define AUD_PILOT_BQD_1_K0 0x320380
|
||||
#define AUD_PILOT_BQD_1_K1 0x320384
|
||||
#define AUD_PILOT_BQD_1_K2 0x320388
|
||||
#define AUD_PILOT_BQD_1_K3 0x32038c
|
||||
#define AUD_PILOT_BQD_1_K4 0x320390
|
||||
#define AUD_PILOT_BQD_2_K0 0x320394
|
||||
#define AUD_PILOT_BQD_2_K1 0x320398
|
||||
#define AUD_PILOT_BQD_2_K2 0x32039c
|
||||
#define AUD_PILOT_BQD_2_K3 0x3203a0
|
||||
#define AUD_PILOT_BQD_2_K4 0x3203a4
|
||||
#define AUD_THR_FR 0x3203c0
|
||||
#define AUD_X_PROG 0x3203c4
|
||||
#define AUD_Y_PROG 0x3203c8
|
||||
#define AUD_HARMONIC_MULT 0x3203cc
|
||||
#define AUD_C1_UP_THR 0x3203d0
|
||||
#define AUD_C1_LO_THR 0x3203d4
|
||||
#define AUD_C2_UP_THR 0x3203d8
|
||||
#define AUD_C2_LO_THR 0x3203dc
|
||||
#define AUD_PLL_EN 0x320400
|
||||
#define AUD_PLL_SRC 0x320404
|
||||
#define AUD_PLL_SHIFT 0x320408
|
||||
#define AUD_PLL_IF_SEL 0x32040c
|
||||
#define AUD_PLL_IF_SHIFT 0x320410
|
||||
#define AUD_BIQUAD_PLL_K0 0x320414
|
||||
#define AUD_BIQUAD_PLL_K1 0x320418
|
||||
#define AUD_BIQUAD_PLL_K2 0x32041c
|
||||
#define AUD_BIQUAD_PLL_K3 0x320420
|
||||
#define AUD_BIQUAD_PLL_K4 0x320424
|
||||
#define AUD_DEEMPH0_SRC_SEL 0x320440
|
||||
#define AUD_DEEMPH0_SHIFT 0x320444
|
||||
#define AUD_DEEMPH0_G0 0x320448
|
||||
#define AUD_DEEMPH0_A0 0x32044c
|
||||
#define AUD_DEEMPH0_B0 0x320450
|
||||
#define AUD_DEEMPH0_A1 0x320454
|
||||
#define AUD_DEEMPH0_B1 0x320458
|
||||
#define AUD_DEEMPH1_SRC_SEL 0x32045c
|
||||
#define AUD_DEEMPH1_SHIFT 0x320460
|
||||
#define AUD_DEEMPH1_G0 0x320464
|
||||
#define AUD_DEEMPH1_A0 0x320468
|
||||
#define AUD_DEEMPH1_B0 0x32046c
|
||||
#define AUD_DEEMPH1_A1 0x320470
|
||||
#define AUD_DEEMPH1_B1 0x320474
|
||||
#define AUD_OUT0_SEL 0x320490
|
||||
#define AUD_OUT0_SHIFT 0x320494
|
||||
#define AUD_OUT1_SEL 0x320498
|
||||
#define AUD_OUT1_SHIFT 0x32049c
|
||||
#define AUD_RDSI_SEL 0x3204a0
|
||||
#define AUD_RDSI_SHIFT 0x3204a4
|
||||
#define AUD_RDSQ_SEL 0x3204a8
|
||||
#define AUD_RDSQ_SHIFT 0x3204ac
|
||||
#define AUD_DBX_IN_GAIN 0x320500
|
||||
#define AUD_DBX_WBE_GAIN 0x320504
|
||||
#define AUD_DBX_SE_GAIN 0x320508
|
||||
#define AUD_DBX_RMS_WBE 0x32050c
|
||||
#define AUD_DBX_RMS_SE 0x320510
|
||||
#define AUD_DBX_SE_BYPASS 0x320514
|
||||
#define AUD_FAWDETCTL 0x320530
|
||||
#define AUD_FAWDETWINCTL 0x320534
|
||||
#define AUD_DEEMPHGAIN_R 0x320538
|
||||
#define AUD_DEEMPHNUMER1_R 0x32053c
|
||||
#define AUD_DEEMPHNUMER2_R 0x320540
|
||||
#define AUD_DEEMPHDENOM1_R 0x320544
|
||||
#define AUD_DEEMPHDENOM2_R 0x320548
|
||||
#define AUD_ERRLOGPERIOD_R 0x32054c
|
||||
#define AUD_ERRINTRPTTHSHLD1_R 0x320550
|
||||
#define AUD_ERRINTRPTTHSHLD2_R 0x320554
|
||||
#define AUD_ERRINTRPTTHSHLD3_R 0x320558
|
||||
#define AUD_NICAM_STATUS1 0x32055c
|
||||
#define AUD_NICAM_STATUS2 0x320560
|
||||
#define AUD_ERRLOG1 0x320564
|
||||
#define AUD_ERRLOG2 0x320568
|
||||
#define AUD_ERRLOG3 0x32056c
|
||||
#define AUD_DAC_BYPASS_L 0x320580
|
||||
#define AUD_DAC_BYPASS_R 0x320584
|
||||
#define AUD_DAC_BYPASS_CTL 0x320588
|
||||
#define AUD_CTL 0x32058c
|
||||
#define AUD_STATUS 0x320590
|
||||
#define AUD_VOL_CTL 0x320594
|
||||
#define AUD_BAL_CTL 0x320598
|
||||
#define AUD_START_TIMER 0x3205b0
|
||||
#define AUD_MODE_CHG_TIMER 0x3205b4
|
||||
#define AUD_POLYPH80SCALEFAC 0x3205b8
|
||||
#define AUD_DMD_RA_DDS 0x3205bc
|
||||
#define AUD_I2S_RA_DDS 0x3205c0
|
||||
#define AUD_RATE_THRES_DMD 0x3205d0
|
||||
#define AUD_RATE_THRES_I2S 0x3205d4
|
||||
#define AUD_RATE_ADJ1 0x3205d8
|
||||
#define AUD_RATE_ADJ2 0x3205dc
|
||||
#define AUD_RATE_ADJ3 0x3205e0
|
||||
#define AUD_RATE_ADJ4 0x3205e4
|
||||
#define AUD_RATE_ADJ5 0x3205e8
|
||||
#define AUD_APB_IN_RATE_ADJ 0x3205ec
|
||||
#define AUD_I2SCNTL 0x3205ec
|
||||
#define AUD_PHASE_FIX_CTL 0x3205f0
|
||||
#define AUD_PLL_PRESCALE 0x320600
|
||||
#define AUD_PLL_DDS 0x320604
|
||||
#define AUD_PLL_INT 0x320608
|
||||
#define AUD_PLL_FRAC 0x32060c
|
||||
#define AUD_PLL_JTAG 0x320620
|
||||
#define AUD_PLL_SPMP 0x320624
|
||||
#define AUD_AFE_12DB_EN 0x320628
|
||||
|
||||
// Audio QAM Register Addresses
|
||||
#define AUD_PDF_DDS_CNST_BYTE2 0x320d01
|
||||
#define AUD_PDF_DDS_CNST_BYTE1 0x320d02
|
||||
#define AUD_PDF_DDS_CNST_BYTE0 0x320d03
|
||||
#define AUD_PHACC_FREQ_8MSB 0x320d2a
|
||||
#define AUD_PHACC_FREQ_8LSB 0x320d2b
|
||||
#define AUD_QAM_MODE 0x320d04
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* transport stream registers */
|
||||
|
||||
#define MO_TS_DMA 0x330000 // {64}RWp Transport stream downstream
|
||||
#define MO_TS_GPCNT 0x33C020 // {16}RO TS general purpose counter
|
||||
#define MO_TS_GPCNTRL 0x33C030 // {2}WO TS general purpose control
|
||||
#define MO_TS_DMACNTRL 0x33C040 // {6}RW TS DMA control
|
||||
#define MO_TS_XFR_STAT 0x33C044 // {1}RO TS transfer status
|
||||
#define MO_TS_LNGTH 0x33C048 // {12}RW TS line length
|
||||
|
||||
#define TS_HW_SOP_CNTRL 0x33C04C
|
||||
#define TS_GEN_CNTRL 0x33C050
|
||||
#define TS_BD_PKT_STAT 0x33C054
|
||||
#define TS_SOP_STAT 0x33C058
|
||||
#define TS_FIFO_OVFL_STAT 0x33C05C
|
||||
#define TS_VALERR_CNTRL 0x33C060
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* VIP registers */
|
||||
|
||||
#define MO_VIPD_DMA 0x340000 // {64}RWp VIP downstream
|
||||
#define MO_VIPU_DMA 0x340008 // {64}RWp VIP upstream
|
||||
#define MO_VIPD_GPCNT 0x34C020 // {16}RO VIP down general purpose counter
|
||||
#define MO_VIPU_GPCNT 0x34C024 // {16}RO VIP up general purpose counter
|
||||
#define MO_VIPD_GPCNTRL 0x34C030 // {2}WO VIP down general purpose control
|
||||
#define MO_VIPU_GPCNTRL 0x34C034 // {2}WO VIP up general purpose control
|
||||
#define MO_VIP_DMACNTRL 0x34C040 // {6}RW VIP DMA control
|
||||
#define MO_VIP_XFR_STAT 0x34C044 // {1}RO VIP transfer status
|
||||
#define MO_VIP_CFG 0x340048 // VIP configuration
|
||||
#define MO_VIPU_CNTRL 0x34004C // VIP upstream control #1
|
||||
#define MO_VIPD_CNTRL 0x340050 // VIP downstream control #2
|
||||
#define MO_VIPD_LNGTH 0x340054 // VIP downstream line length
|
||||
#define MO_VIP_BRSTLN 0x340058 // VIP burst length
|
||||
#define MO_VIP_INTCNTRL 0x34C05C // VIP Interrupt Control
|
||||
#define MO_VIP_XFTERM 0x340060 // VIP transfer terminate
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* misc registers */
|
||||
|
||||
#define MO_M2M_DMA 0x350000 // {64}RWp Mem2Mem DMA Bfr
|
||||
#define MO_GP0_IO 0x350010 // {32}RW* GPIOoutput enablesdata I/O
|
||||
#define MO_GP1_IO 0x350014 // {32}RW* GPIOoutput enablesdata I/O
|
||||
#define MO_GP2_IO 0x350018 // {32}RW* GPIOoutput enablesdata I/O
|
||||
#define MO_GP3_IO 0x35001C // {32}RW* GPIO Mode/Ctrloutput enables
|
||||
#define MO_GPIO 0x350020 // {32}RW* GPIO I2C Ctrldata I/O
|
||||
#define MO_GPOE 0x350024 // {32}RW GPIO I2C Ctrloutput enables
|
||||
#define MO_GP_ISM 0x350028 // {16}WO GPIO Intr Sens/Pol
|
||||
|
||||
#define MO_PLL_B 0x35C008 // {32}RW* PLL Control for ASB bus clks
|
||||
#define MO_M2M_CNT 0x35C024 // {32}RW Mem2Mem DMA Cnt
|
||||
#define MO_M2M_XSUM 0x35C028 // {32}RO M2M XOR-Checksum
|
||||
#define MO_CRC 0x35C02C // {16}RW CRC16 init/result
|
||||
#define MO_CRC_D 0x35C030 // {32}WO CRC16 new data in
|
||||
#define MO_TM_CNT_LDW 0x35C034 // {32}RO Timer : Counter low dword
|
||||
#define MO_TM_CNT_UW 0x35C038 // {16}RO Timer : Counter high word
|
||||
#define MO_TM_LMT_LDW 0x35C03C // {32}RW Timer : Limit low dword
|
||||
#define MO_TM_LMT_UW 0x35C040 // {32}RW Timer : Limit high word
|
||||
#define MO_PINMUX_IO 0x35C044 // {8}RW Pin Mux Control
|
||||
#define MO_TSTSEL_IO 0x35C048 // {2}RW Pin Mux Control
|
||||
#define MO_AFECFG_IO 0x35C04C // AFE configuration reg
|
||||
#define MO_DDS_IO 0x35C050 // DDS Increment reg
|
||||
#define MO_DDSCFG_IO 0x35C054 // DDS Configuration reg
|
||||
#define MO_SAMPLE_IO 0x35C058 // IRIn sample reg
|
||||
#define MO_SRST_IO 0x35C05C // Output system reset reg
|
||||
|
||||
#define MO_INT1_MSK 0x35C060 // DMA RISC interrupt mask
|
||||
#define MO_INT1_STAT 0x35C064 // DMA RISC interrupt status
|
||||
#define MO_INT1_MSTAT 0x35C068 // DMA RISC interrupt masked status
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* i2c bus registers */
|
||||
|
||||
#define MO_I2C 0x368000 // I2C data/control
|
||||
#define MO_I2C_DIV (0xf<<4)
|
||||
#define MO_I2C_SYNC (1<<3)
|
||||
#define MO_I2C_W3B (1<<2)
|
||||
#define MO_I2C_SCL (1<<1)
|
||||
#define MO_I2C_SDA (1<<0)
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* general purpose host registers */
|
||||
/* FIXME: tyops? s/0x35/0x38/ ?? */
|
||||
|
||||
#define MO_GPHSTD_DMA 0x350000 // {64}RWp Host downstream
|
||||
#define MO_GPHSTU_DMA 0x350008 // {64}RWp Host upstream
|
||||
#define MO_GPHSTU_CNTRL 0x380048 // Host upstream control #1
|
||||
#define MO_GPHSTD_CNTRL 0x38004C // Host downstream control #2
|
||||
#define MO_GPHSTD_LNGTH 0x380050 // Host downstream line length
|
||||
#define MO_GPHST_WSC 0x380054 // Host wait state control
|
||||
#define MO_GPHST_XFR 0x380058 // Host transfer control
|
||||
#define MO_GPHST_WDTH 0x38005C // Host interface width
|
||||
#define MO_GPHST_HDSHK 0x380060 // Host peripheral handshake
|
||||
#define MO_GPHST_MUX16 0x380064 // Host muxed 16-bit transfer parameters
|
||||
#define MO_GPHST_MODE 0x380068 // Host mode select
|
||||
|
||||
#define MO_GPHSTD_GPCNT 0x35C020 // Host down general purpose counter
|
||||
#define MO_GPHSTU_GPCNT 0x35C024 // Host up general purpose counter
|
||||
#define MO_GPHSTD_GPCNTRL 0x38C030 // Host down general purpose control
|
||||
#define MO_GPHSTU_GPCNTRL 0x38C034 // Host up general purpose control
|
||||
#define MO_GPHST_DMACNTRL 0x38C040 // Host DMA control
|
||||
#define MO_GPHST_XFR_STAT 0x38C044 // Host transfer status
|
||||
#define MO_GPHST_SOFT_RST 0x38C06C // Host software reset
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* RISC instructions */
|
||||
|
||||
#define RISC_SYNC 0x80000000
|
||||
#define RISC_SYNC_ODD 0x80000000
|
||||
#define RISC_SYNC_EVEN 0x80000200
|
||||
#define RISC_RESYNC 0x80008000
|
||||
#define RISC_RESYNC_ODD 0x80008000
|
||||
#define RISC_RESYNC_EVEN 0x80008200
|
||||
#define RISC_WRITE 0x10000000
|
||||
#define RISC_WRITEC 0x50000000
|
||||
#define RISC_READ 0x90000000
|
||||
#define RISC_READC 0xA0000000
|
||||
#define RISC_JUMP 0x70000000
|
||||
#define RISC_SKIP 0x20000000
|
||||
#define RISC_WRITERM 0xB0000000
|
||||
#define RISC_WRITECM 0xC0000000
|
||||
#define RISC_WRITECR 0xD0000000
|
||||
#define RISC_IMM 0x00000001
|
||||
|
||||
#define RISC_SOL 0x08000000
|
||||
#define RISC_EOL 0x04000000
|
||||
|
||||
#define RISC_IRQ2 0x02000000
|
||||
#define RISC_IRQ1 0x01000000
|
||||
|
||||
#define RISC_CNT_NONE 0x00000000
|
||||
#define RISC_CNT_INC 0x00010000
|
||||
#define RISC_CNT_RSVR 0x00020000
|
||||
#define RISC_CNT_RESET 0x00030000
|
||||
#define RISC_JMP_SRP 0x01
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* various constants */
|
||||
|
||||
// DMA
|
||||
/* Interrupt mask/status */
|
||||
#define PCI_INT_VIDINT (1 << 0)
|
||||
#define PCI_INT_AUDINT (1 << 1)
|
||||
#define PCI_INT_TSINT (1 << 2)
|
||||
#define PCI_INT_VIPINT (1 << 3)
|
||||
#define PCI_INT_HSTINT (1 << 4)
|
||||
#define PCI_INT_TM1INT (1 << 5)
|
||||
#define PCI_INT_SRCDMAINT (1 << 6)
|
||||
#define PCI_INT_DSTDMAINT (1 << 7)
|
||||
#define PCI_INT_RISC_RD_BERRINT (1 << 10)
|
||||
#define PCI_INT_RISC_WR_BERRINT (1 << 11)
|
||||
#define PCI_INT_BRDG_BERRINT (1 << 12)
|
||||
#define PCI_INT_SRC_DMA_BERRINT (1 << 13)
|
||||
#define PCI_INT_DST_DMA_BERRINT (1 << 14)
|
||||
#define PCI_INT_IPB_DMA_BERRINT (1 << 15)
|
||||
#define PCI_INT_I2CDONE (1 << 16)
|
||||
#define PCI_INT_I2CRACK (1 << 17)
|
||||
#define PCI_INT_IR_SMPINT (1 << 18)
|
||||
#define PCI_INT_GPIO_INT0 (1 << 19)
|
||||
#define PCI_INT_GPIO_INT1 (1 << 20)
|
||||
|
||||
#define SEL_BTSC 0x01
|
||||
#define SEL_EIAJ 0x02
|
||||
#define SEL_A2 0x04
|
||||
#define SEL_SAP 0x08
|
||||
#define SEL_NICAM 0x10
|
||||
#define SEL_FMRADIO 0x20
|
||||
|
||||
// AUD_CTL
|
||||
#define AUD_INT_DN_RISCI1 (1 << 0)
|
||||
#define AUD_INT_UP_RISCI1 (1 << 1)
|
||||
#define AUD_INT_RDS_DN_RISCI1 (1 << 2)
|
||||
#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */
|
||||
#define AUD_INT_UP_RISCI2 (1 << 5)
|
||||
#define AUD_INT_RDS_DN_RISCI2 (1 << 6)
|
||||
#define AUD_INT_DN_SYNC (1 << 12)
|
||||
#define AUD_INT_UP_SYNC (1 << 13)
|
||||
#define AUD_INT_RDS_DN_SYNC (1 << 14)
|
||||
#define AUD_INT_OPC_ERR (1 << 16)
|
||||
#define AUD_INT_BER_IRQ (1 << 20)
|
||||
#define AUD_INT_MCHG_IRQ (1 << 21)
|
||||
|
||||
#define EN_BTSC_FORCE_MONO 0
|
||||
#define EN_BTSC_FORCE_STEREO 1
|
||||
#define EN_BTSC_FORCE_SAP 2
|
||||
#define EN_BTSC_AUTO_STEREO 3
|
||||
#define EN_BTSC_AUTO_SAP 4
|
||||
|
||||
#define EN_A2_FORCE_MONO1 8
|
||||
#define EN_A2_FORCE_MONO2 9
|
||||
#define EN_A2_FORCE_STEREO 10
|
||||
#define EN_A2_AUTO_MONO2 11
|
||||
#define EN_A2_AUTO_STEREO 12
|
||||
|
||||
#define EN_EIAJ_FORCE_MONO1 16
|
||||
#define EN_EIAJ_FORCE_MONO2 17
|
||||
#define EN_EIAJ_FORCE_STEREO 18
|
||||
#define EN_EIAJ_AUTO_MONO2 19
|
||||
#define EN_EIAJ_AUTO_STEREO 20
|
||||
|
||||
#define EN_NICAM_FORCE_MONO1 32
|
||||
#define EN_NICAM_FORCE_MONO2 33
|
||||
#define EN_NICAM_FORCE_STEREO 34
|
||||
#define EN_NICAM_AUTO_MONO2 35
|
||||
#define EN_NICAM_AUTO_STEREO 36
|
||||
|
||||
#define EN_FMRADIO_FORCE_MONO 24
|
||||
#define EN_FMRADIO_FORCE_STEREO 25
|
||||
#define EN_FMRADIO_AUTO_STEREO 26
|
||||
|
||||
#define EN_NICAM_AUTO_FALLBACK 0x00000040
|
||||
#define EN_FMRADIO_EN_RDS 0x00000200
|
||||
#define EN_NICAM_TRY_AGAIN_BIT 0x00000400
|
||||
#define EN_DAC_ENABLE 0x00001000
|
||||
#define EN_I2SOUT_ENABLE 0x00002000
|
||||
#define EN_I2SIN_STR2DAC 0x00004000
|
||||
#define EN_I2SIN_ENABLE 0x00008000
|
||||
|
||||
#define EN_DMTRX_SUMDIFF (0 << 7)
|
||||
#define EN_DMTRX_SUMR (1 << 7)
|
||||
#define EN_DMTRX_LR (2 << 7)
|
||||
#define EN_DMTRX_MONO (3 << 7)
|
||||
#define EN_DMTRX_BYPASS (1 << 11)
|
||||
|
||||
// Video
|
||||
#define VID_CAPTURE_CONTROL 0x310180
|
||||
|
||||
#define CX23880_CAP_CTL_CAPTURE_VBI_ODD (1<<3)
|
||||
#define CX23880_CAP_CTL_CAPTURE_VBI_EVEN (1<<2)
|
||||
#define CX23880_CAP_CTL_CAPTURE_ODD (1<<1)
|
||||
#define CX23880_CAP_CTL_CAPTURE_EVEN (1<<0)
|
||||
|
||||
#define VideoInputMux0 0x0
|
||||
#define VideoInputMux1 0x1
|
||||
#define VideoInputMux2 0x2
|
||||
#define VideoInputMux3 0x3
|
||||
#define VideoInputTuner 0x0
|
||||
#define VideoInputComposite 0x1
|
||||
#define VideoInputSVideo 0x2
|
||||
#define VideoInputOther 0x3
|
||||
|
||||
#define Xtal0 0x1
|
||||
#define Xtal1 0x2
|
||||
#define XtalAuto 0x3
|
||||
|
||||
#define VideoFormatAuto 0x0
|
||||
#define VideoFormatNTSC 0x1
|
||||
#define VideoFormatNTSCJapan 0x2
|
||||
#define VideoFormatNTSC443 0x3
|
||||
#define VideoFormatPAL 0x4
|
||||
#define VideoFormatPALB 0x4
|
||||
#define VideoFormatPALD 0x4
|
||||
#define VideoFormatPALG 0x4
|
||||
#define VideoFormatPALH 0x4
|
||||
#define VideoFormatPALI 0x4
|
||||
#define VideoFormatPALBDGHI 0x4
|
||||
#define VideoFormatPALM 0x5
|
||||
#define VideoFormatPALN 0x6
|
||||
#define VideoFormatPALNC 0x7
|
||||
#define VideoFormatPAL60 0x8
|
||||
#define VideoFormatSECAM 0x9
|
||||
|
||||
#define VideoFormatAuto27MHz 0x10
|
||||
#define VideoFormatNTSC27MHz 0x11
|
||||
#define VideoFormatNTSCJapan27MHz 0x12
|
||||
#define VideoFormatNTSC44327MHz 0x13
|
||||
#define VideoFormatPAL27MHz 0x14
|
||||
#define VideoFormatPALB27MHz 0x14
|
||||
#define VideoFormatPALD27MHz 0x14
|
||||
#define VideoFormatPALG27MHz 0x14
|
||||
#define VideoFormatPALH27MHz 0x14
|
||||
#define VideoFormatPALI27MHz 0x14
|
||||
#define VideoFormatPALBDGHI27MHz 0x14
|
||||
#define VideoFormatPALM27MHz 0x15
|
||||
#define VideoFormatPALN27MHz 0x16
|
||||
#define VideoFormatPALNC27MHz 0x17
|
||||
#define VideoFormatPAL6027MHz 0x18
|
||||
#define VideoFormatSECAM27MHz 0x19
|
||||
|
||||
#define NominalUSECAM 0x87
|
||||
#define NominalVSECAM 0x85
|
||||
#define NominalUNTSC 0xFE
|
||||
#define NominalVNTSC 0xB4
|
||||
|
||||
#define NominalContrast 0xD8
|
||||
|
||||
#define HFilterAutoFormat 0x0
|
||||
#define HFilterCIF 0x1
|
||||
#define HFilterQCIF 0x2
|
||||
#define HFilterICON 0x3
|
||||
|
||||
#define VFilter2TapInterpolate 0
|
||||
#define VFilter3TapInterpolate 1
|
||||
#define VFilter4TapInterpolate 2
|
||||
#define VFilter5TapInterpolate 3
|
||||
#define VFilter2TapNoInterpolate 4
|
||||
#define VFilter3TapNoInterpolate 5
|
||||
#define VFilter4TapNoInterpolate 6
|
||||
#define VFilter5TapNoInterpolate 7
|
||||
|
||||
#define ColorFormatRGB32 0x0000
|
||||
#define ColorFormatRGB24 0x0011
|
||||
#define ColorFormatRGB16 0x0022
|
||||
#define ColorFormatRGB15 0x0033
|
||||
#define ColorFormatYUY2 0x0044
|
||||
#define ColorFormatBTYUV 0x0055
|
||||
#define ColorFormatY8 0x0066
|
||||
#define ColorFormatRGB8 0x0077
|
||||
#define ColorFormatPL422 0x0088
|
||||
#define ColorFormatPL411 0x0099
|
||||
#define ColorFormatYUV12 0x00AA
|
||||
#define ColorFormatYUV9 0x00BB
|
||||
#define ColorFormatRAW 0x00EE
|
||||
#define ColorFormatBSWAP 0x0300
|
||||
#define ColorFormatWSWAP 0x0c00
|
||||
#define ColorFormatEvenMask 0x050f
|
||||
#define ColorFormatOddMask 0x0af0
|
||||
#define ColorFormatGamma 0x1000
|
||||
|
||||
#define Interlaced 0x1
|
||||
#define NonInterlaced 0x0
|
||||
|
||||
#define FieldEven 0x1
|
||||
#define FieldOdd 0x0
|
||||
|
||||
#define TGReadWriteMode 0x0
|
||||
#define TGEnableMode 0x1
|
||||
|
||||
#define DV_CbAlign 0x0
|
||||
#define DV_Y0Align 0x1
|
||||
#define DV_CrAlign 0x2
|
||||
#define DV_Y1Align 0x3
|
||||
|
||||
#define DVF_Analog 0x0
|
||||
#define DVF_CCIR656 0x1
|
||||
#define DVF_ByteStream 0x2
|
||||
#define DVF_ExtVSYNC 0x4
|
||||
#define DVF_ExtField 0x5
|
||||
|
||||
#define CHANNEL_VID_Y 0x1
|
||||
#define CHANNEL_VID_U 0x2
|
||||
#define CHANNEL_VID_V 0x3
|
||||
#define CHANNEL_VID_VBI 0x4
|
||||
#define CHANNEL_AUD_DN 0x5
|
||||
#define CHANNEL_AUD_UP 0x6
|
||||
#define CHANNEL_AUD_RDS_DN 0x7
|
||||
#define CHANNEL_MPEG_DN 0x8
|
||||
#define CHANNEL_VIP_DN 0x9
|
||||
#define CHANNEL_VIP_UP 0xA
|
||||
#define CHANNEL_HOST_DN 0xB
|
||||
#define CHANNEL_HOST_UP 0xC
|
||||
#define CHANNEL_FIRST 0x1
|
||||
#define CHANNEL_LAST 0xC
|
||||
|
||||
#define GP_COUNT_CONTROL_NONE 0x0
|
||||
#define GP_COUNT_CONTROL_INC 0x1
|
||||
#define GP_COUNT_CONTROL_RESERVED 0x2
|
||||
#define GP_COUNT_CONTROL_RESET 0x3
|
||||
|
||||
#define PLL_PRESCALE_BY_2 2
|
||||
#define PLL_PRESCALE_BY_3 3
|
||||
#define PLL_PRESCALE_BY_4 4
|
||||
#define PLL_PRESCALE_BY_5 5
|
||||
|
||||
#define HLNotchFilter4xFsc 0
|
||||
#define HLNotchFilterSquare 1
|
||||
#define HLNotchFilter135NTSC 2
|
||||
#define HLNotchFilter135PAL 3
|
||||
|
||||
#define NTSC_8x_SUB_CARRIER 28.63636E6
|
||||
#define PAL_8x_SUB_CARRIER 35.46895E6
|
||||
|
||||
// Default analog settings
|
||||
#define DEFAULT_HUE_NTSC 0x00
|
||||
#define DEFAULT_BRIGHTNESS_NTSC 0x00
|
||||
#define DEFAULT_CONTRAST_NTSC 0x39
|
||||
#define DEFAULT_SAT_U_NTSC 0x7F
|
||||
#define DEFAULT_SAT_V_NTSC 0x5A
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SOURCE_TUNER = 0,
|
||||
SOURCE_COMPOSITE,
|
||||
SOURCE_SVIDEO,
|
||||
SOURCE_OTHER1,
|
||||
SOURCE_OTHER2,
|
||||
SOURCE_COMPVIASVIDEO,
|
||||
SOURCE_CCIR656
|
||||
} VIDEOSOURCETYPE;
|
||||
|
||||
#endif /* _CX88_REG_H_ */
|
1059
drivers/media/pci/cx88/cx88-tvaudio.c
Normal file
1059
drivers/media/pci/cx88/cx88-tvaudio.c
Normal file
File diff suppressed because it is too large
Load diff
245
drivers/media/pci/cx88/cx88-vbi.c
Normal file
245
drivers/media/pci/cx88/cx88-vbi.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "cx88.h"
|
||||
|
||||
static unsigned int vbibufs = 4;
|
||||
module_param(vbibufs,int,0644);
|
||||
MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
|
||||
|
||||
static unsigned int vbi_debug;
|
||||
module_param(vbi_debug,int,0644);
|
||||
MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
|
||||
|
||||
#define dprintk(level,fmt, arg...) if (vbi_debug >= level) \
|
||||
printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
int cx8800_vbi_fmt (struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct cx8800_fh *fh = priv;
|
||||
struct cx8800_dev *dev = fh->dev;
|
||||
|
||||
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
|
||||
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
f->fmt.vbi.offset = 244;
|
||||
f->fmt.vbi.count[0] = VBI_LINE_COUNT;
|
||||
f->fmt.vbi.count[1] = VBI_LINE_COUNT;
|
||||
|
||||
if (dev->core->tvnorm & V4L2_STD_525_60) {
|
||||
/* ntsc */
|
||||
f->fmt.vbi.sampling_rate = 28636363;
|
||||
f->fmt.vbi.start[0] = 10;
|
||||
f->fmt.vbi.start[1] = 273;
|
||||
|
||||
} else if (dev->core->tvnorm & V4L2_STD_625_50) {
|
||||
/* pal */
|
||||
f->fmt.vbi.sampling_rate = 35468950;
|
||||
f->fmt.vbi.start[0] = 7 -1;
|
||||
f->fmt.vbi.start[1] = 319 -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
|
||||
struct cx88_dmaqueue *q,
|
||||
struct cx88_buffer *buf)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
|
||||
/* setup fifo + format */
|
||||
cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24],
|
||||
buf->vb.width, buf->risc.dma);
|
||||
|
||||
cx_write(MO_VBOS_CONTROL, ( (1 << 18) | // comb filter delay fixup
|
||||
(1 << 15) | // enable vbi capture
|
||||
(1 << 11) ));
|
||||
|
||||
/* reset counter */
|
||||
cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET);
|
||||
q->count = 1;
|
||||
|
||||
/* enable irqs */
|
||||
cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
|
||||
cx_set(MO_VID_INTMSK, 0x0f0088);
|
||||
|
||||
/* enable capture */
|
||||
cx_set(VID_CAPTURE_CONTROL,0x18);
|
||||
|
||||
/* start dma */
|
||||
cx_set(MO_DEV_CNTRL2, (1<<5));
|
||||
cx_set(MO_VID_DMACNTRL, 0x88);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx8800_stop_vbi_dma(struct cx8800_dev *dev)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
|
||||
/* stop dma */
|
||||
cx_clear(MO_VID_DMACNTRL, 0x88);
|
||||
|
||||
/* disable capture */
|
||||
cx_clear(VID_CAPTURE_CONTROL,0x18);
|
||||
|
||||
/* disable irqs */
|
||||
cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
|
||||
cx_clear(MO_VID_INTMSK, 0x0f0088);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
|
||||
struct cx88_dmaqueue *q)
|
||||
{
|
||||
struct cx88_buffer *buf;
|
||||
|
||||
if (list_empty(&q->active))
|
||||
return 0;
|
||||
|
||||
buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
|
||||
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
|
||||
buf, buf->vb.i);
|
||||
cx8800_start_vbi_dma(dev, q, buf);
|
||||
list_for_each_entry(buf, &q->active, vb.queue)
|
||||
buf->count = q->count++;
|
||||
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cx8800_vbi_timeout(unsigned long data)
|
||||
{
|
||||
struct cx8800_dev *dev = (struct cx8800_dev*)data;
|
||||
struct cx88_core *core = dev->core;
|
||||
struct cx88_dmaqueue *q = &dev->vbiq;
|
||||
struct cx88_buffer *buf;
|
||||
unsigned long flags;
|
||||
|
||||
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH24]);
|
||||
|
||||
cx_clear(MO_VID_DMACNTRL, 0x88);
|
||||
cx_clear(VID_CAPTURE_CONTROL, 0x18);
|
||||
|
||||
spin_lock_irqsave(&dev->slock,flags);
|
||||
while (!list_empty(&q->active)) {
|
||||
buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
|
||||
list_del(&buf->vb.queue);
|
||||
buf->vb.state = VIDEOBUF_ERROR;
|
||||
wake_up(&buf->vb.done);
|
||||
printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
|
||||
buf, buf->vb.i, (unsigned long)buf->risc.dma);
|
||||
}
|
||||
cx8800_restart_vbi_queue(dev,q);
|
||||
spin_unlock_irqrestore(&dev->slock,flags);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int
|
||||
vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
|
||||
{
|
||||
*size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
|
||||
if (0 == *count)
|
||||
*count = vbibufs;
|
||||
if (*count < 2)
|
||||
*count = 2;
|
||||
if (*count > 32)
|
||||
*count = 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
|
||||
enum v4l2_field field)
|
||||
{
|
||||
struct cx8800_fh *fh = q->priv_data;
|
||||
struct cx8800_dev *dev = fh->dev;
|
||||
struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
|
||||
unsigned int size;
|
||||
int rc;
|
||||
|
||||
size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < size)
|
||||
return -EINVAL;
|
||||
|
||||
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
|
||||
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
|
||||
buf->vb.width = VBI_LINE_LENGTH;
|
||||
buf->vb.height = VBI_LINE_COUNT;
|
||||
buf->vb.size = size;
|
||||
buf->vb.field = V4L2_FIELD_SEQ_TB;
|
||||
|
||||
if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
|
||||
goto fail;
|
||||
cx88_risc_buffer(dev->pci, &buf->risc,
|
||||
dma->sglist,
|
||||
0, buf->vb.width * buf->vb.height,
|
||||
buf->vb.width, 0,
|
||||
buf->vb.height);
|
||||
}
|
||||
buf->vb.state = VIDEOBUF_PREPARED;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
cx88_free_buffer(q,buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
|
||||
{
|
||||
struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
|
||||
struct cx88_buffer *prev;
|
||||
struct cx8800_fh *fh = vq->priv_data;
|
||||
struct cx8800_dev *dev = fh->dev;
|
||||
struct cx88_dmaqueue *q = &dev->vbiq;
|
||||
|
||||
/* add jump to stopper */
|
||||
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
|
||||
buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
|
||||
|
||||
if (list_empty(&q->active)) {
|
||||
list_add_tail(&buf->vb.queue,&q->active);
|
||||
cx8800_start_vbi_dma(dev, q, buf);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
|
||||
dprintk(2,"[%p/%d] vbi_queue - first active\n",
|
||||
buf, buf->vb.i);
|
||||
|
||||
} else {
|
||||
prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
|
||||
list_add_tail(&buf->vb.queue,&q->active);
|
||||
buf->vb.state = VIDEOBUF_ACTIVE;
|
||||
buf->count = q->count++;
|
||||
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
|
||||
dprintk(2,"[%p/%d] buffer_queue - append to active\n",
|
||||
buf, buf->vb.i);
|
||||
}
|
||||
}
|
||||
|
||||
static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
||||
{
|
||||
struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
|
||||
|
||||
cx88_free_buffer(q,buf);
|
||||
}
|
||||
|
||||
const struct videobuf_queue_ops cx8800_vbi_qops = {
|
||||
.buf_setup = vbi_setup,
|
||||
.buf_prepare = vbi_prepare,
|
||||
.buf_queue = vbi_queue,
|
||||
.buf_release = vbi_release,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
2038
drivers/media/pci/cx88/cx88-video.c
Normal file
2038
drivers/media/pci/cx88/cx88-video.c
Normal file
File diff suppressed because it is too large
Load diff
158
drivers/media/pci/cx88/cx88-vp3054-i2c.c
Normal file
158
drivers/media/pci/cx88/cx88-vp3054-i2c.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
|
||||
cx88-vp3054-i2c.c -- support for the secondary I2C bus of the
|
||||
DNTV Live! DVB-T Pro (VP-3054), wired as:
|
||||
GPIO[0] -> SCL, GPIO[1] -> SDA
|
||||
|
||||
(c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
|
||||
|
||||
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/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "cx88.h"
|
||||
#include "cx88-vp3054-i2c.h"
|
||||
|
||||
MODULE_DESCRIPTION("driver for cx2388x VP3054 design");
|
||||
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static void vp3054_bit_setscl(void *data, int state)
|
||||
{
|
||||
struct cx8802_dev *dev = data;
|
||||
struct cx88_core *core = dev->core;
|
||||
struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
|
||||
|
||||
if (state) {
|
||||
vp3054_i2c->state |= 0x0001; /* SCL high */
|
||||
vp3054_i2c->state &= ~0x0100; /* external pullup */
|
||||
} else {
|
||||
vp3054_i2c->state &= ~0x0001; /* SCL low */
|
||||
vp3054_i2c->state |= 0x0100; /* drive pin */
|
||||
}
|
||||
cx_write(MO_GP0_IO, 0x010000 | vp3054_i2c->state);
|
||||
cx_read(MO_GP0_IO);
|
||||
}
|
||||
|
||||
static void vp3054_bit_setsda(void *data, int state)
|
||||
{
|
||||
struct cx8802_dev *dev = data;
|
||||
struct cx88_core *core = dev->core;
|
||||
struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
|
||||
|
||||
if (state) {
|
||||
vp3054_i2c->state |= 0x0002; /* SDA high */
|
||||
vp3054_i2c->state &= ~0x0200; /* tristate pin */
|
||||
} else {
|
||||
vp3054_i2c->state &= ~0x0002; /* SDA low */
|
||||
vp3054_i2c->state |= 0x0200; /* drive pin */
|
||||
}
|
||||
cx_write(MO_GP0_IO, 0x020000 | vp3054_i2c->state);
|
||||
cx_read(MO_GP0_IO);
|
||||
}
|
||||
|
||||
static int vp3054_bit_getscl(void *data)
|
||||
{
|
||||
struct cx8802_dev *dev = data;
|
||||
struct cx88_core *core = dev->core;
|
||||
u32 state;
|
||||
|
||||
state = cx_read(MO_GP0_IO);
|
||||
return (state & 0x01) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int vp3054_bit_getsda(void *data)
|
||||
{
|
||||
struct cx8802_dev *dev = data;
|
||||
struct cx88_core *core = dev->core;
|
||||
u32 state;
|
||||
|
||||
state = cx_read(MO_GP0_IO);
|
||||
return (state & 0x02) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
|
||||
.setsda = vp3054_bit_setsda,
|
||||
.setscl = vp3054_bit_setscl,
|
||||
.getsda = vp3054_bit_getsda,
|
||||
.getscl = vp3054_bit_getscl,
|
||||
.udelay = 16,
|
||||
.timeout = 200,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
int vp3054_i2c_probe(struct cx8802_dev *dev)
|
||||
{
|
||||
struct cx88_core *core = dev->core;
|
||||
struct vp3054_i2c_state *vp3054_i2c;
|
||||
int rc;
|
||||
|
||||
if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
|
||||
return 0;
|
||||
|
||||
vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
|
||||
if (vp3054_i2c == NULL)
|
||||
return -ENOMEM;
|
||||
dev->vp3054 = vp3054_i2c;
|
||||
|
||||
vp3054_i2c->algo = vp3054_i2c_algo_template;
|
||||
|
||||
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
|
||||
strlcpy(vp3054_i2c->adap.name, core->name,
|
||||
sizeof(vp3054_i2c->adap.name));
|
||||
vp3054_i2c->adap.owner = THIS_MODULE;
|
||||
vp3054_i2c->algo.data = dev;
|
||||
i2c_set_adapdata(&vp3054_i2c->adap, dev);
|
||||
vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
|
||||
|
||||
vp3054_bit_setscl(dev,1);
|
||||
vp3054_bit_setsda(dev,1);
|
||||
|
||||
rc = i2c_bit_add_bus(&vp3054_i2c->adap);
|
||||
if (0 != rc) {
|
||||
printk("%s: vp3054_i2c register FAILED\n", core->name);
|
||||
|
||||
kfree(dev->vp3054);
|
||||
dev->vp3054 = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void vp3054_i2c_remove(struct cx8802_dev *dev)
|
||||
{
|
||||
struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
|
||||
|
||||
if (vp3054_i2c == NULL ||
|
||||
dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
|
||||
return;
|
||||
|
||||
i2c_del_adapter(&vp3054_i2c->adap);
|
||||
kfree(vp3054_i2c);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vp3054_i2c_probe);
|
||||
EXPORT_SYMBOL(vp3054_i2c_remove);
|
41
drivers/media/pci/cx88/cx88-vp3054-i2c.h
Normal file
41
drivers/media/pci/cx88/cx88-vp3054-i2c.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
|
||||
cx88-vp3054-i2c.h -- support for the secondary I2C bus of the
|
||||
DNTV Live! DVB-T Pro (VP-3054), wired as:
|
||||
GPIO[0] -> SCL, GPIO[1] -> SDA
|
||||
|
||||
(c) 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
struct vp3054_i2c_state {
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_algo_bit_data algo;
|
||||
u32 state;
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
#if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
|
||||
int vp3054_i2c_probe(struct cx8802_dev *dev);
|
||||
void vp3054_i2c_remove(struct cx8802_dev *dev);
|
||||
#else
|
||||
static inline int vp3054_i2c_probe(struct cx8802_dev *dev)
|
||||
{ return 0; }
|
||||
static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
|
||||
{ }
|
||||
#endif
|
753
drivers/media/pci/cx88/cx88.h
Normal file
753
drivers/media/pci/cx88/cx88.h
Normal file
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
*
|
||||
* v4l2 device driver for cx2388x based TV cards
|
||||
*
|
||||
* (c) 2003,04 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/pci.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/tuner.h>
|
||||
#include <media/tveeprom.h>
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/cx2341x.h>
|
||||
#include <media/videobuf-dvb.h>
|
||||
#include <media/ir-kbd-i2c.h>
|
||||
#include <media/wm8775.h>
|
||||
|
||||
#include "btcx-risc.h"
|
||||
#include "cx88-reg.h"
|
||||
#include "tuner-xc2028.h"
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define CX88_VERSION "0.0.9"
|
||||
|
||||
#define UNSET (-1U)
|
||||
|
||||
#define CX88_MAXBOARDS 8
|
||||
|
||||
/* Max number of inputs by card */
|
||||
#define MAX_CX88_INPUT 8
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* defines and enums */
|
||||
|
||||
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */
|
||||
#define CX88_NORMS (V4L2_STD_ALL \
|
||||
& ~V4L2_STD_PAL_H \
|
||||
& ~V4L2_STD_NTSC_M_KR \
|
||||
& ~V4L2_STD_SECAM_LC)
|
||||
|
||||
#define FORMAT_FLAGS_PACKED 0x01
|
||||
#define FORMAT_FLAGS_PLANAR 0x02
|
||||
|
||||
#define VBI_LINE_COUNT 17
|
||||
#define VBI_LINE_LENGTH 2048
|
||||
|
||||
#define AUD_RDS_LINES 4
|
||||
|
||||
/* need "shadow" registers for some write-only ones ... */
|
||||
#define SHADOW_AUD_VOL_CTL 1
|
||||
#define SHADOW_AUD_BAL_CTL 2
|
||||
#define SHADOW_MAX 3
|
||||
|
||||
/* FM Radio deemphasis type */
|
||||
enum cx88_deemph_type {
|
||||
FM_NO_DEEMPH = 0,
|
||||
FM_DEEMPH_50,
|
||||
FM_DEEMPH_75
|
||||
};
|
||||
|
||||
enum cx88_board_type {
|
||||
CX88_BOARD_NONE = 0,
|
||||
CX88_MPEG_DVB,
|
||||
CX88_MPEG_BLACKBIRD
|
||||
};
|
||||
|
||||
enum cx8802_board_access {
|
||||
CX8802_DRVCTL_SHARED = 1,
|
||||
CX8802_DRVCTL_EXCLUSIVE = 2,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* tv norms */
|
||||
|
||||
static inline unsigned int norm_maxw(v4l2_std_id norm)
|
||||
{
|
||||
return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned int norm_maxh(v4l2_std_id norm)
|
||||
{
|
||||
return (norm & V4L2_STD_625_50) ? 576 : 480;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* static data */
|
||||
|
||||
struct cx8800_fmt {
|
||||
const char *name;
|
||||
u32 fourcc; /* v4l2 format id */
|
||||
int depth;
|
||||
int flags;
|
||||
u32 cxformat;
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* SRAM memory management data (see cx88-core.c) */
|
||||
|
||||
#define SRAM_CH21 0 /* video */
|
||||
#define SRAM_CH22 1
|
||||
#define SRAM_CH23 2
|
||||
#define SRAM_CH24 3 /* vbi */
|
||||
#define SRAM_CH25 4 /* audio */
|
||||
#define SRAM_CH26 5
|
||||
#define SRAM_CH28 6 /* mpeg */
|
||||
#define SRAM_CH27 7 /* audio rds */
|
||||
/* more */
|
||||
|
||||
struct sram_channel {
|
||||
const char *name;
|
||||
u32 cmds_start;
|
||||
u32 ctrl_start;
|
||||
u32 cdt;
|
||||
u32 fifo_start;
|
||||
u32 fifo_size;
|
||||
u32 ptr1_reg;
|
||||
u32 ptr2_reg;
|
||||
u32 cnt1_reg;
|
||||
u32 cnt2_reg;
|
||||
};
|
||||
extern const struct sram_channel cx88_sram_channels[];
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* card configuration */
|
||||
|
||||
#define CX88_BOARD_NOAUTO UNSET
|
||||
#define CX88_BOARD_UNKNOWN 0
|
||||
#define CX88_BOARD_HAUPPAUGE 1
|
||||
#define CX88_BOARD_GDI 2
|
||||
#define CX88_BOARD_PIXELVIEW 3
|
||||
#define CX88_BOARD_ATI_WONDER_PRO 4
|
||||
#define CX88_BOARD_WINFAST2000XP_EXPERT 5
|
||||
#define CX88_BOARD_AVERTV_STUDIO_303 6
|
||||
#define CX88_BOARD_MSI_TVANYWHERE_MASTER 7
|
||||
#define CX88_BOARD_WINFAST_DV2000 8
|
||||
#define CX88_BOARD_LEADTEK_PVR2000 9
|
||||
#define CX88_BOARD_IODATA_GVVCP3PCI 10
|
||||
#define CX88_BOARD_PROLINK_PLAYTVPVR 11
|
||||
#define CX88_BOARD_ASUS_PVR_416 12
|
||||
#define CX88_BOARD_MSI_TVANYWHERE 13
|
||||
#define CX88_BOARD_KWORLD_DVB_T 14
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
|
||||
#define CX88_BOARD_KWORLD_LTV883 16
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17
|
||||
#define CX88_BOARD_HAUPPAUGE_DVB_T1 18
|
||||
#define CX88_BOARD_CONEXANT_DVB_T1 19
|
||||
#define CX88_BOARD_PROVIDEO_PV259 20
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS 21
|
||||
#define CX88_BOARD_PCHDTV_HD3000 22
|
||||
#define CX88_BOARD_DNTV_LIVE_DVB_T 23
|
||||
#define CX88_BOARD_HAUPPAUGE_ROSLYN 24
|
||||
#define CX88_BOARD_DIGITALLOGIC_MEC 25
|
||||
#define CX88_BOARD_IODATA_GVBCTV7E 26
|
||||
#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28
|
||||
#define CX88_BOARD_ADSTECH_DVB_T_PCI 29
|
||||
#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD 31
|
||||
#define CX88_BOARD_AVERMEDIA_ULTRATV_MC_550 32
|
||||
#define CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD 33
|
||||
#define CX88_BOARD_ATI_HDTVWONDER 34
|
||||
#define CX88_BOARD_WINFAST_DTV1000 35
|
||||
#define CX88_BOARD_AVERTV_303 36
|
||||
#define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1 37
|
||||
#define CX88_BOARD_HAUPPAUGE_NOVASE2_S1 38
|
||||
#define CX88_BOARD_KWORLD_DVBS_100 39
|
||||
#define CX88_BOARD_HAUPPAUGE_HVR1100 40
|
||||
#define CX88_BOARD_HAUPPAUGE_HVR1100LP 41
|
||||
#define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42
|
||||
#define CX88_BOARD_KWORLD_DVB_T_CX22702 43
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
|
||||
#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
|
||||
#define CX88_BOARD_PCHDTV_HD5500 47
|
||||
#define CX88_BOARD_KWORLD_MCE200_DELUXE 48
|
||||
#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49
|
||||
#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
|
||||
#define CX88_BOARD_WINFAST_DTV2000H 51
|
||||
#define CX88_BOARD_GENIATECH_DVBS 52
|
||||
#define CX88_BOARD_HAUPPAUGE_HVR3000 53
|
||||
#define CX88_BOARD_NORWOOD_MICRO 54
|
||||
#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
|
||||
#define CX88_BOARD_HAUPPAUGE_HVR1300 56
|
||||
#define CX88_BOARD_ADSTECH_PTV_390 57
|
||||
#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59
|
||||
#define CX88_BOARD_PINNACLE_HYBRID_PCTV 60
|
||||
#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61
|
||||
#define CX88_BOARD_POWERCOLOR_REAL_ANGEL 62
|
||||
#define CX88_BOARD_GENIATECH_X8000_MT 63
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64
|
||||
#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
|
||||
#define CX88_BOARD_PROLINK_PV_8000GT 66
|
||||
#define CX88_BOARD_KWORLD_ATSC_120 67
|
||||
#define CX88_BOARD_HAUPPAUGE_HVR4000 68
|
||||
#define CX88_BOARD_HAUPPAUGE_HVR4000LITE 69
|
||||
#define CX88_BOARD_TEVII_S460 70
|
||||
#define CX88_BOARD_OMICOM_SS4_PCI 71
|
||||
#define CX88_BOARD_TBS_8920 72
|
||||
#define CX88_BOARD_TEVII_S420 73
|
||||
#define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74
|
||||
#define CX88_BOARD_PROF_7300 75
|
||||
#define CX88_BOARD_SATTRADE_ST4200 76
|
||||
#define CX88_BOARD_TBS_8910 77
|
||||
#define CX88_BOARD_PROF_6200 78
|
||||
#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
|
||||
#define CX88_BOARD_HAUPPAUGE_IRONLY 80
|
||||
#define CX88_BOARD_WINFAST_DTV1800H 81
|
||||
#define CX88_BOARD_WINFAST_DTV2000H_J 82
|
||||
#define CX88_BOARD_PROF_7301 83
|
||||
#define CX88_BOARD_SAMSUNG_SMT_7020 84
|
||||
#define CX88_BOARD_TWINHAN_VP1027_DVBS 85
|
||||
#define CX88_BOARD_TEVII_S464 86
|
||||
#define CX88_BOARD_WINFAST_DTV2000H_PLUS 87
|
||||
#define CX88_BOARD_WINFAST_DTV1800H_XC4000 88
|
||||
#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89
|
||||
#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90
|
||||
|
||||
enum cx88_itype {
|
||||
CX88_VMUX_COMPOSITE1 = 1,
|
||||
CX88_VMUX_COMPOSITE2,
|
||||
CX88_VMUX_COMPOSITE3,
|
||||
CX88_VMUX_COMPOSITE4,
|
||||
CX88_VMUX_SVIDEO,
|
||||
CX88_VMUX_TELEVISION,
|
||||
CX88_VMUX_CABLE,
|
||||
CX88_VMUX_DVB,
|
||||
CX88_VMUX_DEBUG,
|
||||
CX88_RADIO,
|
||||
};
|
||||
|
||||
struct cx88_input {
|
||||
enum cx88_itype type;
|
||||
u32 gpio0, gpio1, gpio2, gpio3;
|
||||
unsigned int vmux:2;
|
||||
unsigned int audioroute:4;
|
||||
};
|
||||
|
||||
enum cx88_audio_chip {
|
||||
CX88_AUDIO_WM8775 = 1,
|
||||
CX88_AUDIO_TVAUDIO,
|
||||
};
|
||||
|
||||
struct cx88_board {
|
||||
const char *name;
|
||||
unsigned int tuner_type;
|
||||
unsigned int radio_type;
|
||||
unsigned char tuner_addr;
|
||||
unsigned char radio_addr;
|
||||
int tda9887_conf;
|
||||
struct cx88_input input[MAX_CX88_INPUT];
|
||||
struct cx88_input radio;
|
||||
enum cx88_board_type mpeg;
|
||||
enum cx88_audio_chip audio_chip;
|
||||
int num_frontends;
|
||||
|
||||
/* Used for I2S devices */
|
||||
int i2sinputcntl;
|
||||
};
|
||||
|
||||
struct cx88_subid {
|
||||
u16 subvendor;
|
||||
u16 subdevice;
|
||||
u32 card;
|
||||
};
|
||||
|
||||
enum cx88_tvaudio {
|
||||
WW_NONE = 1,
|
||||
WW_BTSC,
|
||||
WW_BG,
|
||||
WW_DK,
|
||||
WW_I,
|
||||
WW_L,
|
||||
WW_EIAJ,
|
||||
WW_I2SPT,
|
||||
WW_FM,
|
||||
WW_I2SADC,
|
||||
WW_M
|
||||
};
|
||||
|
||||
#define INPUT(nr) (core->board.input[nr])
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* device / file handle status */
|
||||
|
||||
#define RESOURCE_OVERLAY 1
|
||||
#define RESOURCE_VIDEO 2
|
||||
#define RESOURCE_VBI 4
|
||||
|
||||
#define BUFFER_TIMEOUT msecs_to_jiffies(2000)
|
||||
|
||||
/* buffer for one video frame */
|
||||
struct cx88_buffer {
|
||||
/* common v4l buffer stuff -- must be first */
|
||||
struct videobuf_buffer vb;
|
||||
|
||||
/* cx88 specific */
|
||||
unsigned int bpl;
|
||||
struct btcx_riscmem risc;
|
||||
const struct cx8800_fmt *fmt;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
struct cx88_dmaqueue {
|
||||
struct list_head active;
|
||||
struct list_head queued;
|
||||
struct timer_list timeout;
|
||||
struct btcx_riscmem stopper;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
struct cx88_core {
|
||||
struct list_head devlist;
|
||||
atomic_t refcount;
|
||||
|
||||
/* board name */
|
||||
int nr;
|
||||
char name[32];
|
||||
u32 model;
|
||||
|
||||
/* pci stuff */
|
||||
int pci_bus;
|
||||
int pci_slot;
|
||||
u32 __iomem *lmmio;
|
||||
u8 __iomem *bmmio;
|
||||
u32 shadow[SHADOW_MAX];
|
||||
int pci_irqmask;
|
||||
|
||||
/* i2c i/o */
|
||||
struct i2c_adapter i2c_adap;
|
||||
struct i2c_algo_bit_data i2c_algo;
|
||||
struct i2c_client i2c_client;
|
||||
u32 i2c_state, i2c_rc;
|
||||
|
||||
/* config info -- analog */
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct v4l2_ctrl_handler video_hdl;
|
||||
struct v4l2_ctrl *chroma_agc;
|
||||
struct v4l2_ctrl_handler audio_hdl;
|
||||
struct v4l2_subdev *sd_wm8775;
|
||||
struct i2c_client *i2c_rtc;
|
||||
unsigned int boardnr;
|
||||
struct cx88_board board;
|
||||
|
||||
/* Supported V4L _STD_ tuner formats */
|
||||
unsigned int tuner_formats;
|
||||
|
||||
/* config info -- dvb */
|
||||
#if IS_ENABLED(CONFIG_VIDEO_CX88_DVB)
|
||||
int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
|
||||
#endif
|
||||
void (*gate_ctrl)(struct cx88_core *core, int open);
|
||||
|
||||
/* state info */
|
||||
struct task_struct *kthread;
|
||||
v4l2_std_id tvnorm;
|
||||
enum cx88_tvaudio tvaudio;
|
||||
u32 audiomode_manual;
|
||||
u32 audiomode_current;
|
||||
u32 input;
|
||||
u32 last_analog_input;
|
||||
u32 astat;
|
||||
u32 use_nicam;
|
||||
unsigned long last_change;
|
||||
|
||||
/* IR remote control state */
|
||||
struct cx88_IR *ir;
|
||||
|
||||
/* I2C remote data */
|
||||
struct IR_i2c_init_data init_data;
|
||||
struct wm8775_platform_data wm8775_data;
|
||||
|
||||
struct mutex lock;
|
||||
/* various v4l controls */
|
||||
u32 freq;
|
||||
int users;
|
||||
int mpeg_users;
|
||||
|
||||
/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
|
||||
struct cx8802_dev *dvbdev;
|
||||
enum cx88_board_type active_type_id;
|
||||
int active_ref;
|
||||
int active_fe_id;
|
||||
};
|
||||
|
||||
static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
|
||||
{
|
||||
return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
|
||||
}
|
||||
|
||||
#define call_hw(core, grpid, o, f, args...) \
|
||||
do { \
|
||||
if (!core->i2c_rc) { \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 1); \
|
||||
v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
|
||||
|
||||
#define WM8775_GID (1 << 0)
|
||||
|
||||
#define wm8775_s_ctrl(core, id, val) \
|
||||
do { \
|
||||
struct v4l2_ctrl *ctrl_ = \
|
||||
v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \
|
||||
if (ctrl_ && !core->i2c_rc) { \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 1); \
|
||||
v4l2_ctrl_s_ctrl(ctrl_, val); \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define wm8775_g_ctrl(core, id) \
|
||||
({ \
|
||||
struct v4l2_ctrl *ctrl_ = \
|
||||
v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \
|
||||
s32 val = 0; \
|
||||
if (ctrl_ && !core->i2c_rc) { \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 1); \
|
||||
val = v4l2_ctrl_g_ctrl(ctrl_); \
|
||||
if (core->gate_ctrl) \
|
||||
core->gate_ctrl(core, 0); \
|
||||
} \
|
||||
val; \
|
||||
})
|
||||
|
||||
struct cx8800_dev;
|
||||
struct cx8802_dev;
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* function 0: video stuff */
|
||||
|
||||
struct cx8800_fh {
|
||||
struct v4l2_fh fh;
|
||||
struct cx8800_dev *dev;
|
||||
unsigned int resources;
|
||||
|
||||
/* video capture */
|
||||
struct videobuf_queue vidq;
|
||||
|
||||
/* vbi capture */
|
||||
struct videobuf_queue vbiq;
|
||||
};
|
||||
|
||||
struct cx8800_suspend_state {
|
||||
int disabled;
|
||||
};
|
||||
|
||||
struct cx8800_dev {
|
||||
struct cx88_core *core;
|
||||
spinlock_t slock;
|
||||
|
||||
/* various device info */
|
||||
unsigned int resources;
|
||||
struct video_device *video_dev;
|
||||
struct video_device *vbi_dev;
|
||||
struct video_device *radio_dev;
|
||||
|
||||
/* pci i/o */
|
||||
struct pci_dev *pci;
|
||||
unsigned char pci_rev,pci_lat;
|
||||
|
||||
const struct cx8800_fmt *fmt;
|
||||
unsigned int width, height;
|
||||
|
||||
/* capture queues */
|
||||
struct cx88_dmaqueue vidq;
|
||||
struct cx88_dmaqueue vbiq;
|
||||
|
||||
/* various v4l controls */
|
||||
|
||||
/* other global state info */
|
||||
struct cx8800_suspend_state state;
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* function 1: audio/alsa stuff */
|
||||
/* =============> moved to cx88-alsa.c <====================== */
|
||||
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* function 2: mpeg stuff */
|
||||
|
||||
struct cx8802_fh {
|
||||
struct v4l2_fh fh;
|
||||
struct cx8802_dev *dev;
|
||||
struct videobuf_queue mpegq;
|
||||
};
|
||||
|
||||
struct cx8802_suspend_state {
|
||||
int disabled;
|
||||
};
|
||||
|
||||
struct cx8802_driver {
|
||||
struct cx88_core *core;
|
||||
|
||||
/* List of drivers attached to device */
|
||||
struct list_head drvlist;
|
||||
|
||||
/* Type of driver and access required */
|
||||
enum cx88_board_type type_id;
|
||||
enum cx8802_board_access hw_access;
|
||||
|
||||
/* MPEG 8802 internal only */
|
||||
int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
|
||||
int (*resume)(struct pci_dev *pci_dev);
|
||||
|
||||
/* Callers to the following functions must hold core->lock */
|
||||
|
||||
/* MPEG 8802 -> mini driver - Driver probe and configuration */
|
||||
int (*probe)(struct cx8802_driver *drv);
|
||||
int (*remove)(struct cx8802_driver *drv);
|
||||
|
||||
/* MPEG 8802 -> mini driver - Access for hardware control */
|
||||
int (*advise_acquire)(struct cx8802_driver *drv);
|
||||
int (*advise_release)(struct cx8802_driver *drv);
|
||||
|
||||
/* MPEG 8802 <- mini driver - Access for hardware control */
|
||||
int (*request_acquire)(struct cx8802_driver *drv);
|
||||
int (*request_release)(struct cx8802_driver *drv);
|
||||
};
|
||||
|
||||
struct cx8802_dev {
|
||||
struct cx88_core *core;
|
||||
spinlock_t slock;
|
||||
|
||||
/* pci i/o */
|
||||
struct pci_dev *pci;
|
||||
unsigned char pci_rev,pci_lat;
|
||||
|
||||
/* dma queues */
|
||||
struct cx88_dmaqueue mpegq;
|
||||
u32 ts_packet_size;
|
||||
u32 ts_packet_count;
|
||||
|
||||
/* other global state info */
|
||||
struct cx8802_suspend_state state;
|
||||
|
||||
/* for blackbird only */
|
||||
struct list_head devlist;
|
||||
#if IS_ENABLED(CONFIG_VIDEO_CX88_BLACKBIRD)
|
||||
struct video_device *mpeg_dev;
|
||||
u32 mailbox;
|
||||
int width;
|
||||
int height;
|
||||
unsigned char mpeg_active; /* nonzero if mpeg encoder is active */
|
||||
|
||||
/* mpeg params */
|
||||
struct cx2341x_handler cxhdl;
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_VIDEO_CX88_DVB)
|
||||
/* for dvb only */
|
||||
struct videobuf_dvb_frontends frontends;
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
|
||||
/* For VP3045 secondary I2C bus support */
|
||||
struct vp3054_i2c_state *vp3054;
|
||||
#endif
|
||||
/* for switching modulation types */
|
||||
unsigned char ts_gen_cntrl;
|
||||
|
||||
/* List of attached drivers; must hold core->lock to access */
|
||||
struct list_head drvlist;
|
||||
|
||||
struct work_struct request_module_wk;
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
||||
#define cx_read(reg) readl(core->lmmio + ((reg)>>2))
|
||||
#define cx_write(reg,value) writel((value), core->lmmio + ((reg)>>2))
|
||||
#define cx_writeb(reg,value) writeb((value), core->bmmio + (reg))
|
||||
|
||||
#define cx_andor(reg,mask,value) \
|
||||
writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\
|
||||
((value) & (mask)), core->lmmio+((reg)>>2))
|
||||
#define cx_set(reg,bit) cx_andor((reg),(bit),(bit))
|
||||
#define cx_clear(reg,bit) cx_andor((reg),(bit),0)
|
||||
|
||||
#define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); }
|
||||
|
||||
/* shadow registers */
|
||||
#define cx_sread(sreg) (core->shadow[sreg])
|
||||
#define cx_swrite(sreg,reg,value) \
|
||||
(core->shadow[sreg] = value, \
|
||||
writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
|
||||
#define cx_sandor(sreg,reg,mask,value) \
|
||||
(core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \
|
||||
writel(core->shadow[sreg], core->lmmio + ((reg)>>2)))
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-core.c */
|
||||
|
||||
extern unsigned int cx88_core_debug;
|
||||
|
||||
extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
|
||||
int len, u32 bits, u32 mask);
|
||||
|
||||
extern int cx88_core_irq(struct cx88_core *core, u32 status);
|
||||
extern void cx88_wakeup(struct cx88_core *core,
|
||||
struct cx88_dmaqueue *q, u32 count);
|
||||
extern void cx88_shutdown(struct cx88_core *core);
|
||||
extern int cx88_reset(struct cx88_core *core);
|
||||
|
||||
extern int
|
||||
cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
||||
struct scatterlist *sglist,
|
||||
unsigned int top_offset, unsigned int bottom_offset,
|
||||
unsigned int bpl, unsigned int padding, unsigned int lines);
|
||||
extern int
|
||||
cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
|
||||
struct scatterlist *sglist, unsigned int bpl,
|
||||
unsigned int lines, unsigned int lpi);
|
||||
extern int
|
||||
cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
|
||||
u32 reg, u32 mask, u32 value);
|
||||
extern void
|
||||
cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
|
||||
|
||||
extern void cx88_risc_disasm(struct cx88_core *core,
|
||||
struct btcx_riscmem *risc);
|
||||
extern int cx88_sram_channel_setup(struct cx88_core *core,
|
||||
const struct sram_channel *ch,
|
||||
unsigned int bpl, u32 risc);
|
||||
extern void cx88_sram_channel_dump(struct cx88_core *core,
|
||||
const struct sram_channel *ch);
|
||||
|
||||
extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
|
||||
unsigned int height, enum v4l2_field field);
|
||||
extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
|
||||
|
||||
extern struct video_device *cx88_vdev_init(struct cx88_core *core,
|
||||
struct pci_dev *pci,
|
||||
const struct video_device *template_,
|
||||
const char *type);
|
||||
extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
|
||||
extern void cx88_core_put(struct cx88_core *core,
|
||||
struct pci_dev *pci);
|
||||
|
||||
extern int cx88_start_audio_dma(struct cx88_core *core);
|
||||
extern int cx88_stop_audio_dma(struct cx88_core *core);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-vbi.c */
|
||||
|
||||
/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
|
||||
int cx8800_vbi_fmt (struct file *file, void *priv,
|
||||
struct v4l2_format *f);
|
||||
|
||||
/*
|
||||
int cx8800_start_vbi_dma(struct cx8800_dev *dev,
|
||||
struct cx88_dmaqueue *q,
|
||||
struct cx88_buffer *buf);
|
||||
*/
|
||||
int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
|
||||
int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
|
||||
struct cx88_dmaqueue *q);
|
||||
void cx8800_vbi_timeout(unsigned long data);
|
||||
|
||||
extern const struct videobuf_queue_ops cx8800_vbi_qops;
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-i2c.c */
|
||||
|
||||
extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-cards.c */
|
||||
|
||||
extern int cx88_tuner_callback(void *dev, int component, int command, int arg);
|
||||
extern int cx88_get_resources(const struct cx88_core *core,
|
||||
struct pci_dev *pci);
|
||||
extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
|
||||
extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-tvaudio.c */
|
||||
|
||||
void cx88_set_tvaudio(struct cx88_core *core);
|
||||
void cx88_newstation(struct cx88_core *core);
|
||||
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
|
||||
void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual);
|
||||
int cx88_audio_thread(void *data);
|
||||
|
||||
int cx8802_register_driver(struct cx8802_driver *drv);
|
||||
int cx8802_unregister_driver(struct cx8802_driver *drv);
|
||||
|
||||
/* Caller must hold core->lock */
|
||||
struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-dsp.c */
|
||||
|
||||
s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-input.c */
|
||||
|
||||
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
|
||||
int cx88_ir_fini(struct cx88_core *core);
|
||||
void cx88_ir_irq(struct cx88_core *core);
|
||||
int cx88_ir_start(struct cx88_core *core);
|
||||
void cx88_ir_stop(struct cx88_core *core);
|
||||
extern void cx88_i2c_init_ir(struct cx88_core *core);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-mpeg.c */
|
||||
|
||||
int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
|
||||
struct cx88_buffer *buf, enum v4l2_field field);
|
||||
void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
|
||||
void cx8802_cancel_buffers(struct cx8802_dev *dev);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-video.c*/
|
||||
int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
|
||||
int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f);
|
||||
int cx88_video_mux(struct cx88_core *core, unsigned int input);
|
||||
void cx88_querycap(struct file *file, struct cx88_core *core,
|
||||
struct v4l2_capability *cap);
|
Loading…
Add table
Add a link
Reference in a new issue