From: Mijhail Moreyra <mijhail.moreyra@gmail.com>
To: linux-dvb@linuxtv.org
Subject: [linux-dvb] [PATCH] cx23885 analog TV and audio support for HVR-1500
Date: Tue, 26 Aug 2008 15:33:01 -0500 [thread overview]
Message-ID: <48B4687D.8070205@gmail.com> (raw)
Hi,
This patch adds analog TV support for the HVR-1500 which has a cx23885
bridge and a xc3028 tuner but no MPEG encoder. It also adds support for
ALSA audio capture.
There isn't digital TV in my country so I didn't test if it breaks
digital mode.
Hope it will be useful for anyone interested.
Regards.
Mijhail Moreyra
-----------------------------------------------------------------------
diff -uprN old/linux/drivers/media/video/cx23885/cx23885-alsa.c
new/linux/drivers/media/video/cx23885/cx23885-alsa.c
--- old/linux/drivers/media/video/cx23885/cx23885-alsa.c 1969-12-31
19:00:00.000000000 -0500
+++ new/linux/drivers/media/video/cx23885/cx23885-alsa.c 2008-08-26
15:00:38.386185324 -0500
@@ -0,0 +1,533 @@
+/*
+ *
+ * Support for CX23885 analog audio capture
+ *
+ * (c) 2008 Mijhail Moreyra <mijhail.moreyra@gmail.com>
+ * Adapted from cx88-alsa.c
+ *
+ * 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 <asm/delay.h>
+#include "compat.h"
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
+#include <sound/tlv.h>
+#endif
+
+#include "cx23885.h"
+#include "cx23885-reg.h"
+
+#define AUDIO_SRAM_CHANNEL SRAM_CH07
+
+#define dprintk(level, fmt, arg...) if (audio_debug >= level) \
+ printk(KERN_INFO "%s/1: " fmt, chip->dev->name , ## arg)
+
+#define dprintk_core(level, fmt, arg...) if (audio_debug >= level) \
+ printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name , ## arg)
+
+/****************************************************************************
+ Module global static vars
+
****************************************************************************/
+
+static unsigned int disable_analog_audio;
+module_param(disable_analog_audio, int, 0644);
+MODULE_PARM_DESC(disable_analog_audio, "disable analog audio ALSA driver");
+
+static unsigned int audio_debug;
+module_param(audio_debug, int, 0644);
+MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");
+
+/****************************************************************************
+ Board specific funtions
+
****************************************************************************/
+
+/* Constants taken from cx88-reg.h */
+#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 GP_COUNT_CONTROL_RESET 0x3
+
+/*
+ * BOARD Specific: Sets audio DMA
+ */
+
+static int cx23885_start_audio_dma(struct cx23885_audio_dev *chip)
+{
+ struct cx23885_buffer *buf = chip->buf;
+ struct cx23885_dev *dev = chip->dev;
+ struct sram_channel *audio_ch = &dev->sram_channels[AUDIO_SRAM_CHANNEL];
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+ cx_clear(AUD_INT_DMA_CTL, 0x11);
+
+ /* setup fifo + format - out channel */
+ cx23885_sram_channel_setup(chip->dev, audio_ch, buf->bpl, buf->risc.dma);
+
+ /* sets bpl size */
+ cx_write(AUD_INT_A_LNGTH, buf->bpl);
+
+ /* This is required to get good audio (1 seems to be ok) */
+ cx_write(AUD_INT_A_MODE, 1);
+
+ /* reset counter */
+ cx_write(AUD_INT_A_GPCNT_CTL, 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+12)>>1,
+ chip->num_periods, buf->bpl * chip->num_periods);
+
+ /* Enables corresponding bits at AUD_INT_STAT */
+ cx_write(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI1);
+
+ /* Clean any pending interrupt bits already set */
+ cx_write(AUDIO_INT_INT_STAT, ~0);
+
+ /* enable audio irqs */
+ cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT);
+
+ /* start dma */
+ cx_set(DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+ cx_set(AUD_INT_DMA_CTL, 0x11); /* audio downstream FIFO and
+ RISC enable */
+ if (audio_debug)
+ cx23885_sram_channel_dump(chip->dev, audio_ch);
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ */
+static int cx23885_stop_audio_dma(struct cx23885_audio_dev *chip)
+{
+ struct cx23885_dev *dev = chip->dev;
+ dprintk(1, "Stopping audio DMA\n");
+
+ /* stop dma */
+ cx_clear(AUD_INT_DMA_CTL, 0x11);
+
+ /* disable irqs */
+ cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT);
+ cx_clear(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI1);
+
+ if (audio_debug)
+ cx23885_sram_channel_dump(chip->dev,
+ &dev->sram_channels[AUDIO_SRAM_CHANNEL]);
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Handles audio IRQ
+ */
+int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask)
+{
+ struct cx23885_audio_dev *chip = dev->audio_dev;
+
+ if (0 == (status & mask))
+ return 0;
+
+ cx_write(AUDIO_INT_INT_STAT, status);
+
+ /* risc op code error */
+ if (status & AUD_INT_OPC_ERR) {
+ printk(KERN_WARNING "%s/1: Audio risc op code error\n", dev->name);
+ cx_clear(AUD_INT_DMA_CTL, 0x11);
+ cx23885_sram_channel_dump(dev,
+ &dev->sram_channels[AUDIO_SRAM_CHANNEL]);
+ }
+ if (status & AUD_INT_DN_SYNC) {
+ dprintk(1, "Downstream sync error\n");
+ cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);
+ return 1;
+ }
+ /* risc1 downstream */
+ if (status & AUD_INT_DN_RISCI1) {
+ atomic_set(&chip->count, cx_read(AUD_INT_A_GPCNT));
+ snd_pcm_period_elapsed(chip->substream);
+ }
+ /* FIXME: Any other status should deserve a special handling? */
+
+ return 1;
+}
+
+static int dsp_buffer_free(struct cx23885_audio_dev *chip)
+{
+ BUG_ON(!chip->dma_size);
+
+ dprintk(2, "Freeing buffer\n");
+ videobuf_sg_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 struct snd_pcm_hardware snd_cx23885_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_cx23885_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ if (!chip) {
+ printk(KERN_ERR "BUG: cx23885 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_cx23885_digital_hw;
+
+ if (chip->dev->sram_channels[AUDIO_SRAM_CHANNEL].fifo_size !=
DEFAULT_FIFO_SIZE) {
+ unsigned int bpl =
chip->dev->sram_channels[AUDIO_SRAM_CHANNEL].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_cx23885_close(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+ struct videobuf_dmabuf *dma;
+
+ struct cx23885_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 = videobuf_sg_alloc(sizeof(*buf));
+ if (NULL == buf)
+ return -ENOMEM;
+
+ buf->vb.memory = V4L2_MEMORY_MMAP;
+ buf->vb.field = V4L2_FIELD_NONE;
+ buf->vb.width = chip->period_size;
+ buf->bpl = chip->period_size;
+ buf->vb.height = chip->num_periods;
+ buf->vb.size = chip->dma_size;
+
+ dma = videobuf_to_dma(&buf->vb);
+ videobuf_dma_init(dma);
+ ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+ (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+ if (ret < 0)
+ goto error;
+
+ ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+ if (ret < 0)
+ goto error;
+
+ ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+ buf->vb.width, buf->vb.height, 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);
+ buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+
+ chip->buf = buf;
+ chip->dma_risc = dma;
+
+ substream->runtime->dma_area = chip->dma_risc->vmalloc;
+ 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_cx23885_hw_free(struct snd_pcm_substream *substream)
+{
+
+ struct cx23885_audio_dev *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_cx23885_prepare(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+/*
+ * trigger callback
+ */
+static int snd_cx23885_card_trigger(struct snd_pcm_substream
*substream, int cmd)
+{
+ struct cx23885_audio_dev *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 = cx23885_start_audio_dma(chip);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ err = cx23885_stop_audio_dma(chip);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ spin_unlock(&chip->reg_lock);
+
+ return err;
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx23885_pointer(struct snd_pcm_substream
*substream)
+{
+ struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u16 count;
+
+ count = atomic_read(&chip->count);
+
+ return runtime->period_size * (count & (runtime->periods-1));
+}
+
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx23885_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_cx23885_pcm_ops = {
+ .open = snd_cx23885_pcm_open,
+ .close = snd_cx23885_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cx23885_hw_params,
+ .hw_free = snd_cx23885_hw_free,
+ .prepare = snd_cx23885_prepare,
+ .trigger = snd_cx23885_card_trigger,
+ .pointer = snd_cx23885_pointer,
+ .page = snd_cx23885_page,
+};
+
+/*
+ * create a PCM device
+ */
+static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device,
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_cx23885_pcm_ops);
+
+ return 0;
+}
+
+/****************************************************************************
+ Basic Flow for Sound Devices
+
****************************************************************************/
+
+/*
+ * Alsa Constructor - Component probe
+ */
+
+struct cx23885_audio_dev *cx23885_audio_initdev(struct cx23885_dev *dev)
+{
+ struct snd_card *card;
+ struct cx23885_audio_dev *chip;
+ int err;
+
+ if (disable_analog_audio)
+ return NULL;
+
+ if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) {
+ printk(KERN_WARNING "%s(): Missing SRAM channel configuration "
+ "for analog TV Audio\n", __func__);
+ return NULL;
+ }
+
+ card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, sizeof(struct cx23885_audio_dev));
+ if (!card)
+ goto error;
+
+ chip = (struct cx23885_audio_dev *) card->private_data;
+ chip->dev = dev;
+ chip->pci = dev->pci;
+ chip->card = card;
+ spin_lock_init(&chip->reg_lock);
+
+ snd_card_set_dev(card, &dev->pci->dev);
+
+ err = snd_cx23885_pcm(chip, 0, "CX23885 Digital");
+ if (err < 0)
+ goto error;
+
+ strcpy(card->driver, "CX23885");
+ sprintf(card->shortname, "Conexant CX23885");
+ sprintf(card->longname, "%s at %s", card->shortname, dev->name);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+
+ dprintk(0, "registered ALSA audio device\n");
+
+ return chip;
+
+error:
+ snd_card_free(card);
+ printk(KERN_ERR "%s(): Failed to register analog "
+ "audio adapter\n", __func__);
+
+ return NULL;
+}
+
+/*
+ * ALSA destructor
+ */
+void cx23885_audio_finidev(struct cx23885_dev *dev)
+{
+ struct cx23885_audio_dev *chip = dev->audio_dev;
+
+ snd_card_free(chip->card);
+}
+
diff -uprN old/linux/drivers/media/video/cx23885/cx23885-cards.c
new/linux/drivers/media/video/cx23885/cx23885-cards.c
--- old/linux/drivers/media/video/cx23885/cx23885-cards.c 2008-08-09
07:21:15.000000000 -0500
+++ new/linux/drivers/media/video/cx23885/cx23885-cards.c 2008-08-26
14:40:47.316185717 -0500
@@ -131,7 +131,30 @@ struct cx23885_board cx23885_boards[] =
},
[CX23885_BOARD_HAUPPAUGE_HVR1500] = {
.name = "Hauppauge WinTV-HVR1500",
+ .porta = CX23885_ANALOG_VIDEO,
.portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61, /* 0xc2 >> 1 */
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH2 |
+ CX25840_VIN2_CH1,
+ .gpio0 = 0,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .gpio0 = 0,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .gpio0 = 0,
+ }},
},
[CX23885_BOARD_HAUPPAUGE_HVR1200] = {
.name = "Hauppauge WinTV-HVR1200",
@@ -592,6 +615,7 @@ void cx23885_card_setup(struct cx23885_d
case CX23885_BOARD_HAUPPAUGE_HVR1800:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ case CX23885_BOARD_HAUPPAUGE_HVR1500:
request_module("cx25840");
break;
}
diff -uprN old/linux/drivers/media/video/cx23885/cx23885-core.c
new/linux/drivers/media/video/cx23885/cx23885-core.c
--- old/linux/drivers/media/video/cx23885/cx23885-core.c 2008-08-09
07:21:15.000000000 -0500
+++ new/linux/drivers/media/video/cx23885/cx23885-core.c 2008-08-26
15:03:38.149188305 -0500
@@ -151,12 +151,12 @@ static struct sram_channel cx23885_sram_
.cnt2_reg = DMA5_CNT2,
},
[SRAM_CH07] = {
- .name = "ch7",
- .cmds_start = 0x0,
- .ctrl_start = 0x0,
- .cdt = 0x0,
- .fifo_start = 0x0,
- .fifo_size = 0x0,
+ .name = "TV Audio",
+ .cmds_start = 0x10190,
+ .ctrl_start = 0x10480,
+ .cdt = 0x10a00,
+ .fifo_start = 0x7000,
+ .fifo_size = 0x1000,
.ptr1_reg = DMA6_PTR1,
.ptr2_reg = DMA6_PTR2,
.cnt1_reg = DMA6_CNT1,
@@ -940,10 +940,10 @@ static void cx23885_dev_unregister(struc
static __le32* cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
- unsigned int lines)
+ unsigned int lines, unsigned int lpi)
{
struct scatterlist *sg;
- unsigned int line, todo;
+ unsigned int line, todo, sol;
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
@@ -956,16 +956,22 @@ static __le32* cx23885_risc_field(__le32
offset -= sg_dma_len(sg);
sg++;
}
+
+ if (lpi && line>0 && !(line % lpi))
+ sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+ else
+ sol = RISC_SOL;
+
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
*(rp++)=cpu_to_le32(0); /* bits 63-32 */
offset+=bpl;
} else {
/* scanline needs to be split */
todo = bpl;
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ *(rp++)=cpu_to_le32(RISC_WRITE|sol|
(sg_dma_len(sg)-offset));
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
*(rp++)=cpu_to_le32(0); /* bits 63-32 */
@@ -1020,10 +1026,10 @@ int cx23885_risc_buffer(struct pci_dev *
rp = risc->cpu;
if (UNSET != top_offset)
rp = cx23885_risc_field(rp, sglist, top_offset, 0,
- bpl, padding, lines);
+ bpl, padding, lines, 0);
if (UNSET != bottom_offset)
rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
- bpl, padding, lines);
+ bpl, padding, lines, 0);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -1031,11 +1037,12 @@ int cx23885_risc_buffer(struct pci_dev *
return 0;
}
-static int cx23885_risc_databuffer(struct pci_dev *pci,
+int cx23885_risc_databuffer(struct pci_dev *pci,
struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int bpl,
- unsigned int lines)
+ unsigned int lines,
+ unsigned int lpi)
{
u32 instructions;
__le32 *rp;
@@ -1054,7 +1061,7 @@ static int cx23885_risc_databuffer(struc
/* write risc instructions */
rp = risc->cpu;
- rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+ rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -1373,7 +1380,7 @@ int cx23885_buf_prepare(struct videobuf_
goto fail;
cx23885_risc_databuffer(dev->pci, &buf->risc,
videobuf_to_dma(&buf->vb)->sglist,
- buf->vb.width, buf->vb.height);
+ buf->vb.width, buf->vb.height, 0);
}
buf->vb.state = VIDEOBUF_PREPARED;
return 0;
@@ -1593,14 +1600,17 @@ static irqreturn_t cx23885_irq(int irq,
struct cx23885_tsport *ts2 = &dev->ts2;
u32 pci_status, pci_mask;
u32 vida_status, vida_mask;
+ u32 audint_status, audint_mask;
u32 ts1_status, ts1_mask;
u32 ts2_status, ts2_mask;
- int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
+ int vida_count = 0, audint_count = 0, ts1_count = 0, ts2_count = 0,
handled = 0;
pci_status = cx_read(PCI_INT_STAT);
pci_mask = cx_read(PCI_INT_MSK);
vida_status = cx_read(VID_A_INT_STAT);
vida_mask = cx_read(VID_A_INT_MSK);
+ audint_status = cx_read(AUDIO_INT_INT_STAT);
+ audint_mask = cx_read(AUDIO_INT_INT_MSK);
ts1_status = cx_read(VID_B_INT_STAT);
ts1_mask = cx_read(VID_B_INT_MSK);
ts2_status = cx_read(VID_C_INT_STAT);
@@ -1610,12 +1620,15 @@ static irqreturn_t cx23885_irq(int irq,
goto out;
vida_count = cx_read(VID_A_GPCNT);
+ audint_count = cx_read(AUD_INT_A_GPCNT);
ts1_count = cx_read(ts1->reg_gpcnt);
ts2_count = cx_read(ts2->reg_gpcnt);
dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n",
pci_status, pci_mask);
dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n",
vida_status, vida_mask, vida_count);
+ dprintk(7, "audint_status: 0x%08x audint_mask: 0x%08x count: 0x%x\n",
+ audint_status, audint_mask, audint_count);
dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n",
ts1_status, ts1_mask, ts1_count);
dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n",
@@ -1675,6 +1688,9 @@ static irqreturn_t cx23885_irq(int irq,
if (vida_status)
handled += cx23885_video_irq(dev, vida_status);
+ if (audint_status)
+ handled += cx23885_audio_irq(dev, audint_status, audint_mask);
+
if (handled)
cx_write(PCI_INT_STAT, pci_status);
out:
diff -uprN old/linux/drivers/media/video/cx23885/cx23885.h
new/linux/drivers/media/video/cx23885/cx23885.h
--- old/linux/drivers/media/video/cx23885/cx23885.h 2008-08-09
07:21:15.000000000 -0500
+++ new/linux/drivers/media/video/cx23885/cx23885.h 2008-08-26
14:40:47.318185412 -0500
@@ -264,6 +264,27 @@ struct cx23885_tsport {
u32 hw_sop_ctrl_val;
};
+struct cx23885_audio_dev {
+ struct cx23885_dev *dev;
+
+ struct pci_dev *pci;
+
+ 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 cx23885_buffer *buf;
+
+ struct snd_pcm_substream *substream;
+};
+
struct cx23885_dev {
struct list_head devlist;
atomic_t refcount;
@@ -313,6 +334,9 @@ struct cx23885_dev {
unsigned char radio_addr;
unsigned int has_radio;
+ /* Analog audio */
+ struct cx23885_audio_dev *audio_dev;
+
/* V4l */
u32 freq;
struct video_device *video_dev;
@@ -394,6 +418,13 @@ extern int cx23885_risc_buffer(struct pc
unsigned int top_offset, unsigned int bottom_offset,
unsigned int bpl, unsigned int padding, unsigned int lines);
+extern int cx23885_risc_databuffer(struct pci_dev *pci,
+ struct btcx_riscmem *risc,
+ struct scatterlist *sglist,
+ unsigned int bpl,
+ unsigned int lines,
+ unsigned int lpi);
+
void cx23885_cancel_buffers(struct cx23885_tsport *port);
extern int cx23885_restart_queue(struct cx23885_tsport *port,
@@ -438,6 +469,13 @@ extern void cx23885_video_unregister(str
extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status);
/* ----------------------------------------------------------- */
+/* cx23885-alsa.c */
+/* Analog audio */
+extern struct cx23885_audio_dev *cx23885_audio_initdev(struct
cx23885_dev *dev);
+extern void cx23885_audio_finidev(struct cx23885_dev *dev);
+extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32
mask);
+
+/* ----------------------------------------------------------- */
/* cx23885-vbi.c */
extern int cx23885_vbi_fmt(struct file *file, void *priv,
struct v4l2_format *f);
diff -uprN old/linux/drivers/media/video/cx23885/cx23885-video.c
new/linux/drivers/media/video/cx23885/cx23885-video.c
--- old/linux/drivers/media/video/cx23885/cx23885-video.c 2008-08-09
07:21:15.000000000 -0500
+++ new/linux/drivers/media/video/cx23885/cx23885-video.c 2008-08-26
14:40:47.319185469 -0500
@@ -36,6 +36,9 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include "tuner-xc2028.h"
+#include <media/cx25840.h>
+
#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* Include V4L1 specific functions. Should be removed soon */
#include <linux/videodev.h>
@@ -206,7 +209,7 @@ static struct cx23885_ctrl cx23885_ctls[
.id = V4L2_CID_CONTRAST,
.name = "Contrast",
.minimum = 0,
- .maximum = 0xff,
+ .maximum = 0x7f,
.step = 1,
.default_value = 0x3f,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -219,10 +222,10 @@ static struct cx23885_ctrl cx23885_ctls[
.v = {
.id = V4L2_CID_HUE,
.name = "Hue",
- .minimum = 0,
- .maximum = 0xff,
+ .minimum = -127,
+ .maximum = 127,
.step = 1,
- .default_value = 0x7f,
+ .default_value = 0,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 128,
@@ -237,9 +240,9 @@ static struct cx23885_ctrl cx23885_ctls[
.id = V4L2_CID_SATURATION,
.name = "Saturation",
.minimum = 0,
- .maximum = 0xff,
+ .maximum = 0x7f,
.step = 1,
- .default_value = 0x7f,
+ .default_value = 0x3f,
.type = V4L2_CTRL_TYPE_INTEGER,
},
.off = 0,
@@ -977,11 +980,8 @@ EXPORT_SYMBOL(cx23885_get_control);
int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
{
- dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
- " (disabled - no action)\n", __func__);
-#if 0
+ dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, ctl);
-#endif
return 0;
}
EXPORT_SYMBOL(cx23885_set_control);
@@ -1339,14 +1339,13 @@ static int vidioc_g_tuner(struct file *f
if (0 != t->index)
return -EINVAL;
+ memset(t, 0, sizeof(*t));
strcpy(t->name, "Television");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL;
-#if 0
- cx23885_get_stereo(dev, t);
-#endif
- t->signal = 0xffff ; /* LOCKED */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
+
+ dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
return 0;
}
@@ -1362,6 +1361,9 @@ static int vidioc_s_tuner(struct file *f
#if 0
cx23885_set_stereo(dev, t->audmode, 1);
#endif
+ /* Update the A/V core */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
+
return 0;
}
@@ -1757,6 +1759,40 @@ void cx23885_video_unregister(struct cx2
btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
}
+
+ if (dev->audio_dev)
+ cx23885_audio_finidev(dev);
+}
+
+static void config_analog_tuner(struct cx23885_dev *dev)
+{
+ struct tuner_setup tun_setup;
+
+ if (dev->tuner_type == TUNER_ABSENT)
+ return;
+
+ request_module("tuner");
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+ tun_setup.mode_mask = T_ANALOG_TV;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+ tun_setup.tuner_callback = cx23885_tuner_callback; /* Is this ok ??? */
+
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], TUNER_SET_TYPE_ADDR,
&tun_setup);
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct xc2028_ctrl ctl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ };
+ struct v4l2_priv_tun_config xc2028_cfg = {
+ .tuner = TUNER_XC2028,
+ .priv = &ctl,
+ };
+
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], TUNER_SET_CONFIG,
&xc2028_cfg);
+ }
}
int cx23885_video_register(struct cx23885_dev *dev)
@@ -1805,6 +1841,9 @@ int cx23885_video_register(struct cx2388
request_module("wm8775");
#endif
+ /* Configure Analog Tuner */
+ config_analog_tuner(dev);
+
/* register v4l devices */
dev->video_dev = cx23885_vdev_init(dev, dev->pci,
&cx23885_video_template, "video");
@@ -1844,6 +1883,9 @@ int cx23885_video_register(struct cx2388
dev->name, dev->radio_dev->minor & 0x1f);
}
#endif
+ /* Register ALSA audio device */
+ dev->audio_dev = cx23885_audio_initdev(dev);
+
/* initial device configuration */
mutex_lock(&dev->lock);
cx23885_set_tvnorm(dev, dev->tvnorm);
diff -uprN old/linux/drivers/media/video/cx23885/Makefile
new/linux/drivers/media/video/cx23885/Makefile
--- old/linux/drivers/media/video/cx23885/Makefile 2008-08-09
07:21:15.000000000 -0500
+++ new/linux/drivers/media/video/cx23885/Makefile 2008-08-26
14:40:47.319185469 -0500
@@ -1,4 +1,4 @@
-cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o
cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
+cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o
cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o cx23885-alsa.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
diff -uprN old/linux/drivers/media/video/cx25840/cx25840-core.c
new/linux/drivers/media/video/cx25840/cx25840-core.c
--- old/linux/drivers/media/video/cx25840/cx25840-core.c 2008-08-09
07:21:15.000000000 -0500
+++ new/linux/drivers/media/video/cx25840/cx25840-core.c 2008-08-26
14:40:47.320185527 -0500
@@ -285,7 +285,9 @@ static void cx23885_initialize(struct i2
/* Trust the default xtal, no division */
/* This changes for the cx23888 products */
- cx25840_write(client, 0x2, 0x76);
+ if (state->rev != 0x0000) /* FIXME: How to detect the bridge type ??? */
+ /* This causes image distortion on a true cx23885 board */
+ cx25840_write(client, 0x2, 0x76);
/* Bring down the regulator for AUX clk */
cx25840_write(client, 0x1, 0x40);
_______________________________________________
linux-dvb mailing list
linux-dvb@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb
next reply other threads:[~2008-08-26 20:33 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-08-26 20:33 Mijhail Moreyra [this message]
2008-08-26 20:53 ` [linux-dvb] [PATCH] cx23885 analog TV and audio support for HVR-1500 Steven Toth
2008-08-26 21:03 ` Mijhail Moreyra
2008-08-26 22:01 ` Steven Toth
2008-08-26 23:18 ` Mijhail Moreyra
2008-08-27 6:59 ` Steven Toth
2008-08-29 19:52 ` Mijhail Moreyra
2008-08-29 19:55 ` Steven Toth
2008-08-29 20:17 ` Mijhail Moreyra
2008-08-29 20:19 ` Steven Toth
-- strict thread matches above, loose matches on Subject: below --
2008-08-29 21:01 Tim Lucas
2008-08-29 21:56 ` Steven Toth
2008-08-30 0:41 ` Steven Toth
2008-08-30 18:11 ` Mijhail Moreyra
[not found] ` <e32e0e5d0808301411w1ae01563y65ce27d6c43e2beb@mail.gmail.com>
[not found] ` <e32e0e5d0808301456v4b5ca363l5a121b426438bd64@mail.gmail.com>
2008-08-31 22:04 ` Steven Toth
[not found] ` <e32e0e5d0809012006j72eb10e5r80ccf7e3211b8ee7@mail.gmail.com>
2008-09-02 16:08 ` Steven Toth
2008-09-03 2:28 ` Tim Lucas
2008-08-29 22:14 ` Michael Krufky
2008-08-29 23:02 ` Dustin Coates
2008-08-30 0:26 ` Michael Krufky
2008-08-30 0:30 ` Dustin Coates
2008-08-30 0:34 ` Steven Toth
2008-08-30 0:24 ` Mijhail Moreyra
2008-09-04 23:25 Tim Lucas
2008-09-05 13:22 ` Steven Toth
2008-09-05 14:31 Tim Lucas
2008-09-06 21:24 ` Tim Lucas
2008-09-08 23:22 ` Tim Lucas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48B4687D.8070205@gmail.com \
--to=mijhail.moreyra@gmail.com \
--cc=linux-dvb@linuxtv.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.