All of lore.kernel.org
 help / color / mirror / Atom feed
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

             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.