summaryrefslogtreecommitdiffstats
path: root/drivers/media/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/pci')
-rw-r--r--drivers/media/pci/Kconfig2
-rw-r--r--drivers/media/pci/Makefile3
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c5
-rw-r--r--drivers/media/pci/bt8xx/dst_ca.c4
-rw-r--r--drivers/media/pci/cx18/cx18-alsa-pcm.c2
-rw-r--r--drivers/media/pci/cx18/cx18-firmware.c6
-rw-r--r--drivers/media/pci/cx18/cx18-queue.c2
-rw-r--r--drivers/media/pci/cx23885/Kconfig9
-rw-r--r--drivers/media/pci/cx23885/Makefile1
-rw-r--r--drivers/media/pci/cx23885/altera-ci.c8
-rw-r--r--drivers/media/pci/cx23885/altera-ci.h4
-rw-r--r--drivers/media/pci/cx23885/cimax2.c4
-rw-r--r--drivers/media/pci/cx23885/cimax2.h4
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c503
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c109
-rw-r--r--drivers/media/pci/cx23885/cx23885-av.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-av.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c32
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c362
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c323
-rw-r--r--drivers/media/pci/cx23885/cx23885-f300.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-i2c.c12
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.c10
-rw-r--r--drivers/media/pci/cx23885/cx23885-ioctl.h4
-rw-r--r--drivers/media/pci/cx23885/cx23885-ir.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-ir.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885-reg.h4
-rw-r--r--drivers/media/pci/cx23885/cx23885-vbi.c284
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c1294
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.h5
-rw-r--r--drivers/media/pci/cx23885/cx23885.h136
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c5
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.h5
-rw-r--r--drivers/media/pci/cx23885/netup-eeprom.c4
-rw-r--r--drivers/media/pci/cx23885/netup-eeprom.h4
-rw-r--r--drivers/media/pci/cx23885/netup-init.c4
-rw-r--r--drivers/media/pci/cx23885/netup-init.h4
-rw-r--r--drivers/media/pci/cx25821/cx25821-video-upstream.c5
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c632
-rw-r--r--drivers/media/pci/cx88/cx88-video.c3
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c30
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h12
-rw-r--r--drivers/media/pci/dm1105/dm1105.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-pcm.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-firmware.c4
-rw-r--r--drivers/media/pci/ivtv/ivtv-irq.c12
-rw-r--r--drivers/media/pci/mantis/hopper_vp3028.c2
-rw-r--r--drivers/media/pci/mantis/mantis_common.h2
-rw-r--r--drivers/media/pci/mantis/mantis_vp1033.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp1034.c2
-rw-r--r--drivers/media/pci/mantis/mantis_vp1041.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp2033.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp2040.c4
-rw-r--r--drivers/media/pci/mantis/mantis_vp3030.c4
-rw-r--r--drivers/media/pci/ngene/ngene-cards.c2
-rw-r--r--drivers/media/pci/ngene/ngene-core.c14
-rw-r--r--drivers/media/pci/ngene/ngene-dvb.c7
-rw-r--r--drivers/media/pci/ngene/ngene.h2
-rw-r--r--drivers/media/pci/pt3/Kconfig10
-rw-r--r--drivers/media/pci/pt3/Makefile8
-rw-r--r--drivers/media/pci/pt3/pt3.c876
-rw-r--r--drivers/media/pci/pt3/pt3.h186
-rw-r--r--drivers/media/pci/pt3/pt3_dma.c225
-rw-r--r--drivers/media/pci/pt3/pt3_i2c.c240
-rw-r--r--drivers/media/pci/saa7134/Kconfig8
-rw-r--r--drivers/media/pci/saa7134/Makefile2
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c29
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c10
-rw-r--r--drivers/media/pci/saa7134/saa7134-go7007.c531
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134.h5
-rw-r--r--drivers/media/pci/saa7164/saa7164-api.c3
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c6
-rw-r--r--drivers/media/pci/solo6x10/Kconfig1
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-disp.c4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-eeprom.c8
-rw-r--r--drivers/media/pci/solo6x10/solo6x10.h4
-rw-r--r--drivers/media/pci/sta2x11/Kconfig1
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c2
-rw-r--r--drivers/media/pci/ttpci/Kconfig4
-rw-r--r--drivers/media/pci/ttpci/Makefile2
-rw-r--r--drivers/media/pci/ttpci/av7110.c8
-rw-r--r--drivers/media/pci/tw68/Kconfig10
-rw-r--r--drivers/media/pci/tw68/Makefile3
-rw-r--r--drivers/media/pci/tw68/tw68-core.c434
-rw-r--r--drivers/media/pci/tw68/tw68-reg.h195
-rw-r--r--drivers/media/pci/tw68/tw68-risc.c230
-rw-r--r--drivers/media/pci/tw68/tw68-video.c1051
-rw-r--r--drivers/media/pci/tw68/tw68.h231
-rw-r--r--drivers/media/pci/zoran/zoran_device.c2
93 files changed, 5858 insertions, 2420 deletions
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index 5c16c9c2203e..f8cec8e8cf82 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -20,6 +20,7 @@ source "drivers/media/pci/ivtv/Kconfig"
source "drivers/media/pci/zoran/Kconfig"
source "drivers/media/pci/saa7146/Kconfig"
source "drivers/media/pci/solo6x10/Kconfig"
+source "drivers/media/pci/tw68/Kconfig"
endif
if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
@@ -41,6 +42,7 @@ source "drivers/media/pci/b2c2/Kconfig"
source "drivers/media/pci/pluto2/Kconfig"
source "drivers/media/pci/dm1105/Kconfig"
source "drivers/media/pci/pt1/Kconfig"
+source "drivers/media/pci/pt3/Kconfig"
source "drivers/media/pci/mantis/Kconfig"
source "drivers/media/pci/ngene/Kconfig"
source "drivers/media/pci/ddbridge/Kconfig"
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index e5b53fb569ef..a12926e4b51f 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -7,10 +7,10 @@ obj-y += ttpci/ \
pluto2/ \
dm1105/ \
pt1/ \
+ pt3/ \
mantis/ \
ngene/ \
ddbridge/ \
- b2c2/ \
saa7146/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
@@ -22,6 +22,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
+obj-$(CONFIG_VIDEO_TW68) += tw68/
obj-$(CONFIG_VIDEO_MEYE) += meye/
obj-$(CONFIG_STA2X11_VIP) += sta2x11/
obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 970e542d3a51..4a8176c09fc9 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -1531,7 +1531,6 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
{
struct bttv_buffer *old;
unsigned long flags;
- int retval = 0;
dprintk("switch_overlay: enter [new=%p]\n", new);
if (new)
@@ -1551,7 +1550,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
if (NULL == new)
free_btres_lock(btv,fh,RESOURCE_OVERLAY);
dprintk("switch_overlay: done\n");
- return retval;
+ return 0;
}
/* ----------------------------------------------------------------------- */
@@ -3856,7 +3855,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
BT848_INT_MASK);
- };
+ }
bttv_print_irqbits(stat,astat);
diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c
index 0e788fca992c..c22c4ae06844 100644
--- a/drivers/media/pci/bt8xx/dst_ca.c
+++ b/drivers/media/pci/bt8xx/dst_ca.c
@@ -674,11 +674,9 @@ static int dst_ca_release(struct inode *inode, struct file *file)
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{
- ssize_t bytes_read = 0;
-
dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
- return bytes_read;
+ return 0;
}
static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c
index 180077c49123..ffb6acdc575f 100644
--- a/drivers/media/pci/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c
@@ -80,7 +80,7 @@ void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data,
int period_elapsed = 0;
int length;
- dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc,
+ dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc,
pcm_data, num_bytes);
substream = cxsc->capture_pcm_substream;
diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c
index a1c1cec05f98..c6c83445f8bf 100644
--- a/drivers/media/pci/cx18/cx18-firmware.c
+++ b/drivers/media/pci/cx18/cx18-firmware.c
@@ -130,7 +130,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx)
}
}
if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
- CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size);
size = fw->size;
release_firmware(fw);
cx18_setup_page(cx, SCB_OFFSET);
@@ -164,7 +164,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
while (offset + sizeof(seghdr) < fw->size) {
- const u32 *shptr = src + offset / 4;
+ const __le32 *shptr = (__force __le32 *)src + offset / 4;
seghdr.sync1 = le32_to_cpu(shptr[0]);
seghdr.sync2 = le32_to_cpu(shptr[1]);
@@ -202,7 +202,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx,
offset += seghdr.size;
}
if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
- CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+ CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n",
fn, apu_version, fw->size);
size = fw->size;
release_firmware(fw);
diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c
index 8884537bd62f..2a247d264b87 100644
--- a/drivers/media/pci/cx18/cx18-queue.c
+++ b/drivers/media/pci/cx18/cx18-queue.c
@@ -364,7 +364,7 @@ int cx18_stream_alloc(struct cx18_stream *s)
((char __iomem *)cx->scb->cpu_mdl));
CX18_ERR("Too many buffers, cannot fit in SCB area\n");
- CX18_ERR("Max buffers = %zd\n",
+ CX18_ERR("Max buffers = %zu\n",
bufsz / sizeof(struct cx18_mdl_ent));
return -ENOMEM;
}
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index e12c006e6e2d..f613314b360b 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -3,12 +3,11 @@ config VIDEO_CX23885
depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND
select SND_PCM
select I2C_ALGOBIT
- select VIDEO_BTCX
select VIDEO_TUNER
select VIDEO_TVEEPROM
depends on RC_CORE
- select VIDEOBUF_DVB
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF2_DVB
+ select VIDEOBUF2_DMA_SG
select VIDEO_CX25840
select VIDEO_CX2341X
select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
@@ -32,12 +31,16 @@ config VIDEO_CX23885
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
---help---
This is a video4linux driver for Conexant 23885 based
diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile
index 2a2cafb8cf5b..a2cbdcf15a8c 100644
--- a/drivers/media/pci/cx23885/Makefile
+++ b/drivers/media/pci/cx23885/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.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
diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c
index 2926f7fadccd..2bbbf545b042 100644
--- a/drivers/media/pci/cx23885/altera-ci.c
+++ b/drivers/media/pci/cx23885/altera-ci.c
@@ -16,10 +16,6 @@
* 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.
*/
/*
@@ -52,8 +48,8 @@
* | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0|
* +-------+-------+-------+-------+-------+-------+-------+-------+
*/
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
#include "altera-ci.h"
#include "dvb_ca_en50221.h"
diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h
index 4998c96caebe..5028f0cf83f4 100644
--- a/drivers/media/pci/cx23885/altera-ci.h
+++ b/drivers/media/pci/cx23885/altera-ci.h
@@ -16,10 +16,6 @@
* 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 __ALTERA_CI_H
#define __ALTERA_CI_H
diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c
index 16fa7ea4d4aa..631e4f24aea6 100644
--- a/drivers/media/pci/cx23885/cimax2.c
+++ b/drivers/media/pci/cx23885/cimax2.c
@@ -17,10 +17,6 @@
* 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 "cx23885.h"
diff --git a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h
index 518744a4c8a5..565e958f6f8d 100644
--- a/drivers/media/pci/cx23885/cimax2.h
+++ b/drivers/media/pci/cx23885/cimax2.h
@@ -17,10 +17,6 @@
* 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 CIMAX2_H
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index bf89fc88692e..3948db386fb5 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -18,10 +18,6 @@
* 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>
@@ -865,6 +861,11 @@ static int cx23885_api_cmd(struct cx23885_dev *dev,
return err;
}
+static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ return cx23885_mbox_func(priv, cmd, in, out, data);
+}
+
static int cx23885_find_mailbox(struct cx23885_dev *dev)
{
u32 signature[4] = {
@@ -941,7 +942,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev)
if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
printk(KERN_ERR "ERROR: Firmware size mismatch "
- "(have %zd, expected %d)\n",
+ "(have %zu, expected %d)\n",
firmware->size, CX23885_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
@@ -1033,12 +1034,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev)
cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
dev->ts1.height, dev->ts1.width);
- dev->mpeg_params.width = dev->ts1.width;
- dev->mpeg_params.height = dev->ts1.height;
- dev->mpeg_params.is_50hz =
+ dev->cxhdl.width = dev->ts1.width;
+ dev->cxhdl.height = dev->ts1.height;
+ dev->cxhdl.is_50hz =
(dev->encodernorm.id & V4L2_STD_625_50) != 0;
- cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+ cx2341x_handler_setup(&dev->cxhdl);
cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
@@ -1137,85 +1138,107 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
/* ------------------------------------------------------------------ */
-static int bb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct cx23885_fh *fh = q->priv_data;
-
- fh->dev->ts1.ts_packet_size = mpeglinesize;
- fh->dev->ts1.ts_packet_count = mpeglines;
-
- *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
- *count = mpegbufs;
+ struct cx23885_dev *dev = q->drv_priv;
+ dev->ts1.ts_packet_size = mpeglinesize;
+ dev->ts1.ts_packet_count = mpeglines;
+ *num_planes = 1;
+ sizes[0] = mpeglinesize * mpeglines;
+ *num_buffers = mpegbufs;
return 0;
}
-static int bb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct cx23885_fh *fh = q->priv_data;
- return cx23885_buf_prepare(q, &fh->dev->ts1,
- (struct cx23885_buffer *)vb,
- field);
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf =
+ container_of(vb, struct cx23885_buffer, vb);
+
+ return cx23885_buf_prepare(buf, &dev->ts1);
}
-static void bb_buf_queue(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
{
- struct cx23885_fh *fh = q->priv_data;
- cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf = container_of(vb,
+ struct cx23885_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+ cx23885_free_buffer(dev, buf);
+
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
-static void bb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
{
- cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
-}
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf = container_of(vb,
+ struct cx23885_buffer, vb);
-static struct videobuf_queue_ops cx23885_qops = {
- .buf_setup = bb_buf_setup,
- .buf_prepare = bb_buf_prepare,
- .buf_queue = bb_buf_queue,
- .buf_release = bb_buf_release,
-};
+ cx23885_buf_queue(&dev->ts1, buf);
+}
-/* ------------------------------------------------------------------ */
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct cx23885_dev *dev = q->drv_priv;
+ struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq;
+ unsigned long flags;
+ int ret;
+
+ ret = cx23885_initialize_codec(dev, 1);
+ if (ret == 0) {
+ struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+ struct cx23885_buffer, queue);
+
+ cx23885_start_dma(&dev->ts1, dmaq, buf);
+ return 0;
+ }
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+ struct cx23885_buffer, queue);
-static const u32 *ctrl_classes[] = {
- cx2341x_mpeg_ctrls,
- NULL
-};
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return ret;
+}
-static int cx23885_queryctrl(struct cx23885_dev *dev,
- struct v4l2_queryctrl *qctrl)
+static void cx23885_stop_streaming(struct vb2_queue *q)
{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
+ struct cx23885_dev *dev = q->drv_priv;
- /* MPEG V4L2 controls */
- if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ /* stop mpeg capture */
+ cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+ CX23885_RAW_BITS_NONE);
- return 0;
+ msleep(500);
+ cx23885_417_check_encoder(dev);
+ cx23885_cancel_buffers(&dev->ts1);
}
-static int cx23885_querymenu(struct cx23885_dev *dev,
- struct v4l2_querymenu *qmenu)
-{
- struct v4l2_queryctrl qctrl;
+static struct vb2_ops cx23885_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = cx23885_start_streaming,
+ .stop_streaming = cx23885_stop_streaming,
+};
- qctrl.id = qmenu->id;
- cx23885_queryctrl(dev, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
-}
+/* ------------------------------------------------------------------ */
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
*id = dev->tvnorm;
return 0;
@@ -1223,29 +1246,26 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
unsigned int i;
+ int ret;
for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
if (id & cx23885_tvnorms[i].id)
break;
if (i == ARRAY_SIZE(cx23885_tvnorms))
return -EINVAL;
- dev->encodernorm = cx23885_tvnorms[i];
- /* Have the drier core notify the subdevices */
- mutex_lock(&dev->lock);
- cx23885_set_tvnorm(dev, id);
- mutex_unlock(&dev->lock);
-
- return 0;
+ ret = cx23885_set_tvnorm(dev, id);
+ if (!ret)
+ dev->encodernorm = cx23885_tvnorms[i];
+ return ret;
}
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
dprintk(1, "%s()\n", __func__);
return cx23885_enum_input(dev, i);
}
@@ -1263,8 +1283,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
@@ -1281,8 +1300,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
static int vidioc_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
@@ -1296,8 +1314,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
@@ -1315,27 +1332,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return cx23885_set_frequency(file, priv, f);
}
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
- return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
- return cx23885_set_control(dev, ctl);
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
struct cx23885_tsport *tsport = &dev->ts1;
strlcpy(cap->driver, dev->name, sizeof(cap->driver));
@@ -1368,8 +1368,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
@@ -1378,285 +1377,63 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = 0;
f->fmt.pix.width = dev->ts1.width;
f->fmt.pix.height = dev->ts1.height;
- f->fmt.pix.field = fh->mpegq.field;
- dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
+ dev->ts1.width, dev->ts1.height);
return 0;
}
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage =
dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
f->fmt.pix.colorspace = 0;
- dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+ dev->ts1.width, dev->ts1.height);
return 0;
}
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage =
dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
f->fmt.pix.colorspace = 0;
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
return 0;
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_reqbufs(&fh->mpegq, p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_querybuf(&fh->mpegq, p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_qbuf(&fh->mpegq, p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct cx23885_fh *fh = priv;
-
- return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK);
-}
-
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_streamon(&fh->mpegq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_streamoff(&fh->mpegq);
-}
-
-static int vidioc_g_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
-}
-
-static int vidioc_s_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
-
- if (err == 0) {
- err = cx2341x_update(dev, cx23885_mbox_func,
- &dev->mpeg_params, &p);
- dev->mpeg_params = p;
- }
- return err;
-}
-
-static int vidioc_try_ext_ctrls(struct file *file, void *priv,
- struct v4l2_ext_controls *f)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
-
- p = dev->mpeg_params;
- err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
- return err;
-}
-
static int vidioc_log_status(struct file *file, void *priv)
{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
char name[32 + 2];
snprintf(name, sizeof(name), "%s/2", dev->name);
- printk(KERN_INFO
- "%s/2: ============ START LOG STATUS ============\n",
- dev->name);
call_all(dev, core, log_status);
- cx2341x_log_status(&dev->mpeg_params, name);
- printk(KERN_INFO
- "%s/2: ============= END LOG STATUS =============\n",
- dev->name);
+ v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name);
return 0;
}
-static int vidioc_querymenu(struct file *file, void *priv,
- struct v4l2_querymenu *a)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
-
- return cx23885_querymenu(dev, a);
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *c)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
-
- return cx23885_queryctrl(dev, c);
-}
-
-static int mpeg_open(struct file *file)
-{
- struct cx23885_dev *dev = video_drvdata(file);
- struct cx23885_fh *fh;
-
- dprintk(2, "%s()\n", __func__);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (!fh)
- return -ENOMEM;
-
- file->private_data = fh;
- fh->dev = dev;
-
- videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
- &dev->pci->dev, &dev->ts1.slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx23885_buffer),
- fh, NULL);
- return 0;
-}
-
-static int mpeg_release(struct file *file)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s()\n", __func__);
-
- /* FIXME: Review this crap */
- /* Shut device down on last close */
- if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
- if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
- /* stop mpeg capture */
- cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- CX23885_END_NOW, CX23885_MPEG_CAPTURE,
- CX23885_RAW_BITS_NONE);
-
- msleep(500);
- cx23885_417_check_encoder(dev);
-
- cx23885_cancel_buffers(&fh->dev->ts1);
- }
- }
-
- if (fh->mpegq.streaming)
- videobuf_streamoff(&fh->mpegq);
- if (fh->mpegq.reading)
- videobuf_read_stop(&fh->mpegq);
-
- videobuf_mmap_free(&fh->mpegq);
- file->private_data = NULL;
- kfree(fh);
-
- return 0;
-}
-
-static ssize_t mpeg_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s()\n", __func__);
-
- /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
- /* Start mpeg encoder on first read. */
- if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
- if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
- if (cx23885_initialize_codec(dev, 1) < 0)
- return -EINVAL;
- }
- }
-
- return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int mpeg_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s\n", __func__);
-
- return videobuf_poll_stream(file, &fh->mpegq, wait);
-}
-
-static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- dprintk(2, "%s()\n", __func__);
-
- return videobuf_mmap_mapper(&fh->mpegq, vma);
-}
-
static struct v4l2_file_operations mpeg_fops = {
.owner = THIS_MODULE,
- .open = mpeg_open,
- .release = mpeg_release,
- .read = mpeg_read,
- .poll = mpeg_poll,
- .mmap = mpeg_mmap,
- .ioctl = video_ioctl2,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
};
static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
@@ -1669,25 +1446,19 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
- .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
- .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_log_status = vidioc_log_status,
- .vidioc_querymenu = vidioc_querymenu,
- .vidioc_queryctrl = vidioc_queryctrl,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_chip_info = cx23885_g_chip_info,
.vidioc_g_register = cx23885_g_register,
@@ -1711,6 +1482,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev)
video_unregister_device(dev->v4l_device);
else
video_device_release(dev->v4l_device);
+ v4l2_ctrl_handler_free(&dev->cxhdl.hdl);
dev->v4l_device = NULL;
}
}
@@ -1742,6 +1514,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
/* FIXME: Port1 hardcoded here */
int err = -ENODEV;
struct cx23885_tsport *tsport = &dev->ts1;
+ struct vb2_queue *q;
dprintk(1, "%s()\n", __func__);
@@ -1757,14 +1530,36 @@ int cx23885_417_register(struct cx23885_dev *dev)
tsport->height = 576;
tsport->width = 720;
- cx2341x_fill_defaults(&dev->mpeg_params);
-
- dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+ dev->cxhdl.port = CX2341X_PORT_SERIAL;
+ err = cx2341x_handler_init(&dev->cxhdl, 50);
+ if (err)
+ return err;
+ dev->cxhdl.priv = dev;
+ dev->cxhdl.func = cx23885_api_func;
+ cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576);
+ v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL);
/* Allocate and initialize V4L video device */
dev->v4l_device = cx23885_video_dev_alloc(tsport,
dev->pci, &cx23885_mpeg_template, "mpeg");
+ q = &dev->vb2_mpegq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx23885_buffer);
+ q->ops = &cx23885_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ return err;
video_set_drvdata(dev->v4l_device, dev);
+ dev->v4l_device->lock = &dev->lock;
+ dev->v4l_device->queue = q;
err = video_register_device(dev->v4l_device,
VFL_TYPE_GRABBER, -1);
if (err < 0) {
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index 554798dcedd0..ae7c2e89ad1c 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -15,10 +15,6 @@
* 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>
@@ -84,6 +80,82 @@ MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");
#define AUD_INT_MCHG_IRQ (1 << 21)
#define GP_COUNT_CONTROL_RESET 0x3
+static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages)
+{
+ struct cx23885_audio_buffer *buf = chip->buf;
+ struct page *pg;
+ int i;
+
+ buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == buf->vaddr) {
+ dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+ return -ENOMEM;
+ }
+
+ dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
+ (unsigned long)buf->vaddr,
+ nr_pages << PAGE_SHIFT);
+
+ memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
+ buf->nr_pages = nr_pages;
+
+ buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist));
+ if (NULL == buf->sglist)
+ goto vzalloc_err;
+
+ sg_init_table(buf->sglist, buf->nr_pages);
+ for (i = 0; i < buf->nr_pages; i++) {
+ pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);
+ if (NULL == pg)
+ goto vmalloc_to_page_err;
+ sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);
+ }
+ return 0;
+
+vmalloc_to_page_err:
+ vfree(buf->sglist);
+ buf->sglist = NULL;
+vzalloc_err:
+ vfree(buf->vaddr);
+ buf->vaddr = NULL;
+ return -ENOMEM;
+}
+
+static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev)
+{
+ struct cx23885_audio_buffer *buf = dev->buf;
+
+ buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
+ buf->nr_pages, PCI_DMA_FROMDEVICE);
+
+ if (0 == buf->sglen) {
+ pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev)
+{
+ struct cx23885_audio_buffer *buf = dev->buf;
+
+ if (!buf->sglen)
+ return 0;
+
+ dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);
+ buf->sglen = 0;
+ return 0;
+}
+
+static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf)
+{
+ vfree(buf->sglist);
+ buf->sglist = NULL;
+ vfree(buf->vaddr);
+ buf->vaddr = NULL;
+ return 0;
+}
+
/*
* BOARD Specific: Sets audio DMA
*/
@@ -198,15 +270,18 @@ int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask)
static int dsp_buffer_free(struct cx23885_audio_dev *chip)
{
+ struct cx23885_riscmem *risc;
+
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);
+ cx23885_alsa_dma_unmap(chip);
+ cx23885_alsa_dma_free(chip->buf);
+ risc = &chip->buf->risc;
+ pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma);
kfree(chip->buf);
- chip->dma_risc = NULL;
+ chip->buf = NULL;
chip->dma_size = 0;
return 0;
@@ -289,6 +364,7 @@ static int snd_cx23885_close(struct snd_pcm_substream *substream)
return 0;
}
+
/*
* hw_params callback
*/
@@ -296,8 +372,6 @@ 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_audio_buffer *buf;
int ret;
@@ -318,19 +392,18 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
return -ENOMEM;
buf->bpl = chip->period_size;
+ chip->buf = buf;
- dma = &buf->dma;
- videobuf_dma_init(dma);
- ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+ ret = cx23885_alsa_dma_init(chip,
(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
if (ret < 0)
goto error;
- ret = videobuf_dma_map(&chip->pci->dev, dma);
+ ret = cx23885_alsa_dma_map(chip);
if (ret < 0)
goto error;
- ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+ ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
chip->period_size, chip->num_periods, 1);
if (ret < 0)
goto error;
@@ -340,10 +413,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
- chip->buf = buf;
- chip->dma_risc = dma;
-
- substream->runtime->dma_area = chip->dma_risc->vaddr;
+ substream->runtime->dma_area = chip->buf->vaddr;
substream->runtime->dma_bytes = chip->dma_size;
substream->runtime->dma_addr = 0;
@@ -351,6 +421,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
error:
kfree(buf);
+ chip->buf = NULL;
return ret;
}
diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c
index c443b7ac5adf..877dad89107e 100644
--- a/drivers/media/pci/cx23885/cx23885-av.c
+++ b/drivers/media/pci/cx23885/cx23885-av.c
@@ -14,11 +14,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#include "cx23885.h"
diff --git a/drivers/media/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h
index d2915c3e53a2..97f232f8efb9 100644
--- a/drivers/media/pci/cx23885/cx23885-av.h
+++ b/drivers/media/pci/cx23885/cx23885-av.h
@@ -14,11 +14,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#ifndef _CX23885_AV_H_
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index c2b608007190..88c257d1161b 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -13,10 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
@@ -679,6 +675,11 @@ struct cx23885_board cx23885_boards[] = {
.amux = CX25840_AUDIO7,
} },
},
+ [CX23885_BOARD_DVBSKY_T9580] = {
+ .name = "DVBSky T9580",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -934,6 +935,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x18ac,
.subdevice = 0xdb98,
.card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2,
+ }, {
+ .subvendor = 0x4254,
+ .subdevice = 0x9580,
+ .card = CX23885_BOARD_DVBSKY_T9580,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1528,6 +1533,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_set(GP0_IO, 0x00040004);
mdelay(60);
break;
+ case CX23885_BOARD_DVBSKY_T9580:
+ /* enable GPIO3-18 pins */
+ cx_write(MC417_CTL, 0x00000037);
+ cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1);
+ cx23885_gpio_clear(dev, GPIO_2 | GPIO_11);
+ mdelay(100);
+ cx23885_gpio_set(dev, GPIO_2 | GPIO_11);
+ break;
}
}
@@ -1851,6 +1864,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_DVBSKY_T9580:
+ ts1->gen_ctrl_val = 0x5; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ ts2->gen_ctrl_val = 0x8; /* Serial bus */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1913,6 +1934,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_AVERMEDIA_HC81R:
case CX23885_BOARD_TBS_6980:
case CX23885_BOARD_TBS_6981:
+ case CX23885_BOARD_DVBSKY_T9580:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
"cx25840", 0x88 >> 1, NULL);
@@ -1970,5 +1992,3 @@ void cx23885_card_setup(struct cx23885_dev *dev)
}
}
}
-
-/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index edcd79db1e4e..331eddac7222 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -13,10 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
@@ -420,39 +416,23 @@ static int cx23885_risc_decode(u32 risc)
return incr[risc >> 28] ? incr[risc >> 28] : 1;
}
-void cx23885_wakeup(struct cx23885_tsport *port,
+static void cx23885_wakeup(struct cx23885_tsport *port,
struct cx23885_dmaqueue *q, u32 count)
{
struct cx23885_dev *dev = port->dev;
struct cx23885_buffer *buf;
- int bc;
-
- for (bc = 0;; bc++) {
- if (list_empty(&q->active))
- break;
- buf = list_entry(q->active.next,
- struct cx23885_buffer, vb.queue);
-
- /* count comes from the hw and is is 16bit wide --
- * this trick handles wrap-arounds correctly for
- * up to 32767 buffers in flight... */
- if ((s16) (count - buf->count) < 0)
- break;
- v4l2_get_timestamp(&buf->vb.ts);
- dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
- count, buf->count);
- buf->vb.state = VIDEOBUF_DONE;
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- }
if (list_empty(&q->active))
- del_timer(&q->timeout);
- else
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- if (bc != 1)
- printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n",
- __func__, bc);
+ return;
+ buf = list_entry(q->active.next,
+ struct cx23885_buffer, queue);
+
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ buf->vb.v4l2_buf.sequence = q->count++;
+ dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+ count, q->count);
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -482,8 +462,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
lines = 6;
BUG_ON(lines < 2);
- cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- cx_write(8 + 4, 8);
+ cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET);
+ cx_write(8 + 4, 12);
cx_write(8 + 8, 0);
/* write CDT */
@@ -590,7 +570,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev,
}
static void cx23885_risc_disasm(struct cx23885_tsport *port,
- struct btcx_riscmem *risc)
+ struct cx23885_riscmem *risc)
{
struct cx23885_dev *dev = port->dev;
unsigned int i, j, n;
@@ -699,10 +679,6 @@ static int get_resources(struct cx23885_dev *dev)
return -EBUSY;
}
-static void cx23885_timeout(unsigned long data);
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value);
-
static int cx23885_init_tsport(struct cx23885_dev *dev,
struct cx23885_tsport *port, int portno)
{
@@ -719,11 +695,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
port->nr = portno;
INIT_LIST_HEAD(&port->mpegq.active);
- INIT_LIST_HEAD(&port->mpegq.queued);
- port->mpegq.timeout.function = cx23885_timeout;
- port->mpegq.timeout.data = (unsigned long)port;
- init_timer(&port->mpegq.timeout);
-
mutex_init(&port->frontends.lock);
INIT_LIST_HEAD(&port->frontends.felist);
port->frontends.active_fe_id = 0;
@@ -776,9 +747,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev,
BUG();
}
- cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
- port->reg_dma_ctl, port->dma_ctl_val, 0x00);
-
return 0;
}
@@ -1089,11 +1057,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
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 lpi)
+ unsigned int lines, unsigned int lpi, bool jump)
{
struct scatterlist *sg;
unsigned int line, todo, sol;
+
+ if (jump) {
+ *(rp++) = cpu_to_le32(RISC_JUMP);
+ *(rp++) = cpu_to_le32(0);
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+ }
+
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
@@ -1146,14 +1121,13 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
return rp;
}
-int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
struct scatterlist *sglist, unsigned int top_offset,
unsigned int bottom_offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
{
u32 instructions, fields;
__le32 *rp;
- int rc;
fields = 0;
if (UNSET != top_offset)
@@ -1168,19 +1142,20 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
/* write and jump need and extra dword */
instructions = fields * (1 + ((bpl + padding) * lines)
/ PAGE_SIZE + lines);
- instructions += 2;
- rc = btcx_riscmem_alloc(pci, risc, instructions*12);
- if (rc < 0)
- return rc;
+ instructions += 5;
+ risc->size = instructions * 12;
+ risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+ if (risc->cpu == NULL)
+ return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
if (UNSET != top_offset)
rp = cx23885_risc_field(rp, sglist, top_offset, 0,
- bpl, padding, lines, 0);
+ bpl, padding, lines, 0, true);
if (UNSET != bottom_offset)
rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
- bpl, padding, lines, 0);
+ bpl, padding, lines, 0, UNSET == top_offset);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -1189,14 +1164,13 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
}
int cx23885_risc_databuffer(struct pci_dev *pci,
- struct btcx_riscmem *risc,
+ struct cx23885_riscmem *risc,
struct scatterlist *sglist,
unsigned int bpl,
unsigned int lines, unsigned int lpi)
{
u32 instructions;
__le32 *rp;
- int rc;
/* estimate risc mem: worst case is one write per page border +
one write per scan line + syncs + jump (all 2 dwords). Here
@@ -1204,16 +1178,17 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
than PAGE_SIZE */
/* Jump and write need an extra dword */
instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
- instructions += 1;
+ instructions += 4;
- rc = btcx_riscmem_alloc(pci, risc, instructions*12);
- if (rc < 0)
- return rc;
+ risc->size = instructions * 12;
+ risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+ if (risc->cpu == NULL)
+ return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE,
- bpl, 0, lines, lpi);
+ bpl, 0, lines, lpi, lpi == 0);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -1221,14 +1196,13 @@ int cx23885_risc_databuffer(struct pci_dev *pci,
return 0;
}
-int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
struct scatterlist *sglist, unsigned int top_offset,
unsigned int bottom_offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
{
u32 instructions, fields;
__le32 *rp;
- int rc;
fields = 0;
if (UNSET != top_offset)
@@ -1243,22 +1217,23 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
/* write and jump need and extra dword */
instructions = fields * (1 + ((bpl + padding) * lines)
/ PAGE_SIZE + lines);
- instructions += 2;
- rc = btcx_riscmem_alloc(pci, risc, instructions*12);
- if (rc < 0)
- return rc;
+ instructions += 5;
+ risc->size = instructions * 12;
+ risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma);
+ if (risc->cpu == NULL)
+ return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
/* Sync to line 6, so US CC line 21 will appear in line '12'
* in the userland vbi payload */
if (UNSET != top_offset)
- rp = cx23885_risc_field(rp, sglist, top_offset, 6,
- bpl, padding, lines, 0);
+ rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+ bpl, padding, lines, 0, true);
if (UNSET != bottom_offset)
- rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207,
- bpl, padding, lines, 0);
+ rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+ bpl, padding, lines, 0, UNSET == top_offset);
@@ -1269,38 +1244,12 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
}
-int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value)
+void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf)
{
- __le32 *rp;
- int rc;
-
- rc = btcx_riscmem_alloc(pci, risc, 4*16);
- if (rc < 0)
- return rc;
-
- /* write risc instructions */
- rp = risc->cpu;
- *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2);
- *(rp++) = cpu_to_le32(reg);
- *(rp++) = cpu_to_le32(value);
- *(rp++) = cpu_to_le32(mask);
- *(rp++) = cpu_to_le32(RISC_JUMP);
- *(rp++) = cpu_to_le32(risc->dma);
- *(rp++) = cpu_to_le32(0); /* bits 63-32 */
- return 0;
-}
-
-void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+ struct cx23885_riscmem *risc = &buf->risc;
BUG_ON(in_interrupt());
- videobuf_waiton(q, &buf->vb, 0, 0);
- videobuf_dma_unmap(q->dev, dma);
- videobuf_dma_free(dma);
- btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
}
static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
@@ -1355,7 +1304,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
}
-static int cx23885_start_dma(struct cx23885_tsport *port,
+int cx23885_start_dma(struct cx23885_tsport *port,
struct cx23885_dmaqueue *q,
struct cx23885_buffer *buf)
{
@@ -1363,7 +1312,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
u32 reg;
dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
- buf->vb.width, buf->vb.height, buf->vb.field);
+ dev->width, dev->height, dev->field);
/* Stop the fifo and risc engine for this port */
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
@@ -1379,7 +1328,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
}
/* write TS length to chip */
- cx_write(port->reg_lngth, buf->vb.width);
+ cx_write(port->reg_lngth, port->ts_packet_size);
if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) {
@@ -1408,7 +1357,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
/* NOTE: this is 2 (reserved) for portb, does it matter? */
/* reset counter to zero */
cx_write(port->reg_gpcnt_ctl, 3);
- q->count = 1;
+ q->count = 0;
/* Set VIDB pins to input */
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
@@ -1497,134 +1446,83 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
return 0;
}
-int cx23885_restart_queue(struct cx23885_tsport *port,
- struct cx23885_dmaqueue *q)
-{
- struct cx23885_dev *dev = port->dev;
- struct cx23885_buffer *buf;
-
- dprintk(5, "%s()\n", __func__);
- if (list_empty(&q->active)) {
- struct cx23885_buffer *prev;
- prev = NULL;
-
- dprintk(5, "%s() queue is empty\n", __func__);
-
- for (;;) {
- if (list_empty(&q->queued))
- return 0;
- buf = list_entry(q->queued.next, struct cx23885_buffer,
- vb.queue);
- if (NULL == prev) {
- list_move_tail(&buf->vb.queue, &q->active);
- cx23885_start_dma(port, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(5, "[%p/%d] restart_queue - f/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);
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(5, "[%p/%d] restart_queue - m/active\n",
- buf, buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
- return 0;
- }
-
- buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
- dprintk(2, "restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
- cx23885_start_dma(port, 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 cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
- struct cx23885_buffer *buf, enum v4l2_field field)
+int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
int size = port->ts_packet_size * port->ts_packet_count;
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0);
int rc;
dprintk(1, "%s: %p\n", __func__, buf);
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ if (vb2_plane_size(&buf->vb, 0) < size)
return -EINVAL;
+ vb2_set_plane_payload(&buf->vb, 0, size);
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- buf->vb.width = port->ts_packet_size;
- buf->vb.height = port->ts_packet_count;
- buf->vb.size = size;
- buf->vb.field = field /*V4L2_FIELD_TOP*/;
-
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (0 != rc)
- goto fail;
- cx23885_risc_databuffer(dev->pci, &buf->risc,
- videobuf_to_dma(&buf->vb)->sglist,
- buf->vb.width, buf->vb.height, 0);
- }
- buf->vb.state = VIDEOBUF_PREPARED;
- return 0;
+ rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+ if (!rc)
+ return -EIO;
- fail:
- cx23885_free_buffer(q, buf);
- return rc;
+ cx23885_risc_databuffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ port->ts_packet_size, port->ts_packet_count, 0);
+ return 0;
}
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
{
struct cx23885_buffer *prev;
struct cx23885_dev *dev = port->dev;
struct cx23885_dmaqueue *cx88q = &port->mpegq;
+ unsigned long flags;
- /* 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);
+ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+ spin_lock_irqsave(&dev->slock, flags);
if (list_empty(&cx88q->active)) {
- dprintk(1, "queue is empty - first active\n");
- list_add_tail(&buf->vb.queue, &cx88q->active);
- cx23885_start_dma(port, cx88q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = cx88q->count++;
- mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+ list_add_tail(&buf->queue, &cx88q->active);
dprintk(1, "[%p/%d] %s - first active\n",
- buf, buf->vb.i, __func__);
+ buf, buf->vb.v4l2_buf.index, __func__);
} else {
- dprintk(1, "queue is not empty - append to active\n");
+ buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
- vb.queue);
- list_add_tail(&buf->vb.queue, &cx88q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = cx88q->count++;
+ queue);
+ list_add_tail(&buf->queue, &cx88q->active);
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
dprintk(1, "[%p/%d] %s - append to active\n",
- buf, buf->vb.i, __func__);
+ buf, buf->vb.v4l2_buf.index, __func__);
}
+ spin_unlock_irqrestore(&dev->slock, flags);
}
/* ----------------------------------------------------------- */
-static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
- int restart)
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason)
{
struct cx23885_dev *dev = port->dev;
struct cx23885_dmaqueue *q = &port->mpegq;
@@ -1634,16 +1532,11 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
spin_lock_irqsave(&port->slock, flags);
while (!list_empty(&q->active)) {
buf = list_entry(q->active.next, struct cx23885_buffer,
- vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
+ queue);
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
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");
- cx23885_restart_queue(port, q);
+ buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma);
}
spin_unlock_irqrestore(&port->slock, flags);
}
@@ -1651,27 +1544,10 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
void cx23885_cancel_buffers(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
- struct cx23885_dmaqueue *q = &port->mpegq;
-
- dprintk(1, "%s()\n", __func__);
- del_timer_sync(&q->timeout);
- cx23885_stop_dma(port);
- do_cancel_buffers(port, "cancel", 0);
-}
-
-static void cx23885_timeout(unsigned long data)
-{
- struct cx23885_tsport *port = (struct cx23885_tsport *)data;
- struct cx23885_dev *dev = port->dev;
dprintk(1, "%s()\n", __func__);
-
- if (debug > 5)
- cx23885_sram_channel_dump(dev,
- &dev->sram_channels[port->sram_chno]);
-
cx23885_stop_dma(port);
- do_cancel_buffers(port, "timeout", 1);
+ do_cancel_buffers(port, "cancel");
}
int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
@@ -1721,11 +1597,6 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
spin_lock(&port->slock);
cx23885_wakeup(port, &port->mpegq, count);
spin_unlock(&port->slock);
- } else if (status & VID_B_MSK_RISCI2) {
- dprintk(7, " VID_B_MSK_RISCI2\n");
- spin_lock(&port->slock);
- cx23885_restart_queue(port, &port->mpegq);
- spin_unlock(&port->slock);
}
if (status) {
cx_write(port->reg_ts_int_stat, status);
@@ -1777,14 +1648,6 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
cx23885_wakeup(port, &port->mpegq, count);
spin_unlock(&port->slock);
- } else if (status & VID_BC_MSK_RISCI2) {
-
- dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2);
-
- spin_lock(&port->slock);
- cx23885_restart_queue(port, &port->mpegq);
- spin_unlock(&port->slock);
-
}
if (status) {
cx_write(port->reg_ts_int_stat, status);
@@ -2087,6 +1950,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
struct cx23885_dev *dev;
+ struct v4l2_ctrl_handler *hdl;
int err;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -2097,6 +1961,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
if (err < 0)
goto fail_free;
+ hdl = &dev->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 6);
+ if (hdl->error) {
+ err = hdl->error;
+ goto fail_ctrl;
+ }
+ dev->v4l2_dev.ctrl_handler = hdl;
+
/* Prepare to handle notifications from subdevices */
cx23885_v4l2_dev_notify_init(dev);
@@ -2104,12 +1976,12 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
dev->pci = pci_dev;
if (pci_enable_device(pci_dev)) {
err = -EIO;
- goto fail_unreg;
+ goto fail_ctrl;
}
if (cx23885_dev_setup(dev) < 0) {
err = -EINVAL;
- goto fail_unreg;
+ goto fail_ctrl;
}
/* print pci info */
@@ -2157,7 +2029,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
fail_irq:
cx23885_dev_unregister(dev);
-fail_unreg:
+fail_ctrl:
+ v4l2_ctrl_handler_free(hdl);
v4l2_device_unregister(&dev->v4l2_dev);
fail_free:
kfree(dev);
@@ -2180,6 +2053,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev)
free_irq(pci_dev->irq, dev);
cx23885_dev_unregister(dev);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_device_unregister(v4l2_dev);
kfree(dev);
}
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 968fecc32f9c..13734b8c7917 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -13,10 +13,6 @@
* 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>
@@ -73,6 +69,10 @@
#include "a8293.h"
#include "mb86a20s.h"
#include "si2165.h"
+#include "si2168.h"
+#include "si2157.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
static unsigned int debug;
@@ -91,59 +91,95 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* ------------------------------------------------------------------ */
-static int dvb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct cx23885_tsport *port = q->priv_data;
+ struct cx23885_tsport *port = q->drv_priv;
port->ts_packet_size = 188 * 4;
port->ts_packet_count = 32;
-
- *size = port->ts_packet_size * port->ts_packet_count;
- *count = 32;
+ *num_planes = 1;
+ sizes[0] = port->ts_packet_size * port->ts_packet_count;
+ *num_buffers = 32;
return 0;
}
-static int dvb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
+
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct cx23885_tsport *port = q->priv_data;
- return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field);
+ struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf =
+ container_of(vb, struct cx23885_buffer, vb);
+
+ return cx23885_buf_prepare(buf, port);
}
-static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
{
- struct cx23885_tsport *port = q->priv_data;
- cx23885_buf_queue(port, (struct cx23885_buffer *)vb);
+ struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_buffer *buf = container_of(vb,
+ struct cx23885_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+ cx23885_free_buffer(dev, buf);
+
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
-static void dvb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
{
- cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+ struct cx23885_tsport *port = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf = container_of(vb,
+ struct cx23885_buffer, vb);
+
+ cx23885_buf_queue(port, buf);
}
static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open)
{
- struct videobuf_dvb_frontends *f;
- struct videobuf_dvb_frontend *fe;
+ struct vb2_dvb_frontends *f;
+ struct vb2_dvb_frontend *fe;
f = &port->frontends;
if (f->gate <= 1) /* undefined or fe0 */
- fe = videobuf_dvb_get_frontend(f, 1);
+ fe = vb2_dvb_get_frontend(f, 1);
else
- fe = videobuf_dvb_get_frontend(f, f->gate);
+ fe = vb2_dvb_get_frontend(f, f->gate);
if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
}
-static struct videobuf_queue_ops dvb_qops = {
- .buf_setup = dvb_buf_setup,
- .buf_prepare = dvb_buf_prepare,
- .buf_queue = dvb_buf_queue,
- .buf_release = dvb_buf_release,
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct cx23885_tsport *port = q->drv_priv;
+ struct cx23885_dmaqueue *dmaq = &port->mpegq;
+ struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+ struct cx23885_buffer, queue);
+
+ cx23885_start_dma(port, dmaq, buf);
+ return 0;
+}
+
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+ struct cx23885_tsport *port = q->drv_priv;
+
+ cx23885_cancel_buffers(port);
+}
+
+static struct vb2_ops dvb_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = cx23885_start_streaming,
+ .stop_streaming = cx23885_stop_streaming,
};
static struct s5h1409_config hauppauge_generic_config = {
@@ -551,6 +587,35 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
return 0;
}
+static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx23885_tsport *port = fe->dvb->priv;
+ struct cx23885_dev *dev = port->dev;
+
+ cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ cx23885_gpio_set(dev, GPIO_1);
+ cx23885_gpio_clear(dev, GPIO_0);
+ break;
+ case SEC_VOLTAGE_18:
+ cx23885_gpio_set(dev, GPIO_1);
+ cx23885_gpio_set(dev, GPIO_0);
+ break;
+ case SEC_VOLTAGE_OFF:
+ cx23885_gpio_clear(dev, GPIO_1);
+ cx23885_gpio_clear(dev, GPIO_0);
+ break;
+ }
+
+ /* call the frontend set_voltage function */
+ port->fe_set_voltage(fe, voltage);
+
+ return 0;
+}
+
static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -715,6 +780,19 @@ static const struct si2165_config hauppauge_hvr4400_si2165_config = {
.ref_freq_Hz = 16000000,
};
+static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .clock_out = 0,
+ .ts_mode = M88DS3103_TS_PARALLEL,
+ .ts_clk = 16000,
+ .ts_clk_pol = 1,
+ .lnb_en_pol = 1,
+ .lnb_hv_pol = 0,
+ .agc = 0x99,
+};
+
static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -863,16 +941,23 @@ static int dvb_register(struct cx23885_tsport *port)
struct dib7000p_ops dib7000p_ops;
struct cx23885_dev *dev = port->dev;
struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
- struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+ struct vb2_dvb_frontend *fe0, *fe1 = NULL;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+ struct m88ts2022_config m88ts2022_config;
+ struct i2c_board_info info;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client_demod;
+ struct i2c_client *client_tuner;
int mfe_shared = 0; /* bus not shared by default */
int ret;
/* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+ fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
if (!fe0)
return -EINVAL;
- /* init struct videobuf_dvb */
+ /* init struct vb2_dvb */
fe0->dvb.name = dev->name;
/* multi-frontend gate control is undefined or defaults to fe0 */
@@ -1392,7 +1477,7 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
}
/* MFE frontend 2 */
- fe1 = videobuf_dvb_get_frontend(&port->frontends, 2);
+ fe1 = vb2_dvb_get_frontend(&port->frontends, 2);
if (fe1 == NULL)
goto frontend_detach;
/* DVB-C init */
@@ -1491,7 +1576,7 @@ static int dvb_register(struct cx23885_tsport *port)
&hauppauge_hvr4400_si2165_config,
&i2c_bus->i2c_adap);
if (fe0->dvb.frontend != NULL) {
- fe0->dvb.frontend->ops.i2c_gate_ctrl = 0;
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
if (!dvb_attach(tda18271_attach,
fe0->dvb.frontend,
0x60, &i2c_bus2->i2c_adap,
@@ -1501,6 +1586,97 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
break;
+ case CX23885_BOARD_DVBSKY_T9580:
+ i2c_bus = &dev->i2c_bus[0];
+ i2c_bus2 = &dev->i2c_bus[1];
+ switch (port->nr) {
+ /* port b - satellite */
+ case 1:
+ /* attach frontend */
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+ &dvbsky_t9580_m88ds3103_config,
+ &i2c_bus2->i2c_adap, &adapter);
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ /* attach tuner */
+ m88ts2022_config.fe = fe0->dvb.frontend;
+ m88ts2022_config.clock = 27000000;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &m88ts2022_config;
+ request_module(info.type);
+ client_tuner = i2c_new_device(adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL)
+ goto frontend_detach;
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ goto frontend_detach;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ fe0->dvb.frontend->ops.read_signal_strength =
+ fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+
+ /*
+ * for setting the voltage we need to set GPIOs on
+ * the card.
+ */
+ port->fe_set_voltage =
+ fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage =
+ dvbsky_t9580_set_voltage;
+
+ port->i2c_client_tuner = client_tuner;
+
+ break;
+ /* port c - terrestrial/cable */
+ case 2:
+ /* attach frontend */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &fe0->dvb.frontend;
+ si2168_config.ts_mode = SI2168_TS_SERIAL;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+ request_module(info.type);
+ client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+ if (client_demod == NULL ||
+ client_demod->dev.driver == NULL)
+ goto frontend_detach;
+ if (!try_module_get(client_demod->dev.driver->owner)) {
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ port->i2c_client_demod = client_demod;
+
+ /* attach tuner */
+ si2157_config.fe = fe0->dvb.frontend;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module(info.type);
+ client_tuner = i2c_new_device(adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ port->i2c_client_tuner = client_tuner;
+ break;
+ }
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
@@ -1532,7 +1708,7 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend);
/* register everything */
- ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
+ ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr, mfe_shared);
if (ret)
goto frontend_detach;
@@ -1575,20 +1751,36 @@ static int dvb_register(struct cx23885_tsport *port)
memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
break;
}
+ case CX23885_BOARD_DVBSKY_T9580: {
+ u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+ if (port->nr > 2)
+ break;
+
+ /* Read entire EEPROM */
+ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+ sizeof(eeprom));
+ printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n",
+ port->nr, eeprom + 0xc0 + (port->nr-1) * 8);
+ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
+ (port->nr-1) * 8, 6);
+ break;
+ }
}
return ret;
frontend_detach:
port->gate_ctrl = NULL;
- videobuf_dvb_dealloc_frontends(&port->frontends);
+ vb2_dvb_dealloc_frontends(&port->frontends);
return -EINVAL;
}
int cx23885_dvb_register(struct cx23885_tsport *port)
{
- struct videobuf_dvb_frontend *fe0;
+ struct vb2_dvb_frontend *fe0;
struct cx23885_dev *dev = port->dev;
int err, i;
@@ -1605,13 +1797,15 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
port->num_frontends);
for (i = 1; i <= port->num_frontends; i++) {
- if (videobuf_dvb_alloc_frontend(
+ struct vb2_queue *q;
+
+ if (vb2_dvb_alloc_frontend(
&port->frontends, i) == NULL) {
printk(KERN_ERR "%s() failed to alloc\n", __func__);
return -ENOMEM;
}
- fe0 = videobuf_dvb_get_frontend(&port->frontends, i);
+ fe0 = vb2_dvb_get_frontend(&port->frontends, i);
if (!fe0)
err = -EINVAL;
@@ -1627,10 +1821,21 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
/* dvb stuff */
/* We have to init the queue for each frontend on a port. */
printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name);
- videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
- &dev->pci->dev, &port->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
- sizeof(struct cx23885_buffer), port, NULL);
+ q = &fe0->dvb.dvbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = port;
+ q->buf_struct_size = sizeof(struct cx23885_buffer);
+ q->ops = &dvb_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ return err;
}
err = dvb_register(port);
if (err != 0)
@@ -1642,18 +1847,27 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
int cx23885_dvb_unregister(struct cx23885_tsport *port)
{
- struct videobuf_dvb_frontend *fe0;
-
- /* FIXME: in an error condition where the we have
- * an expected number of frontends (attach problem)
- * then this might not clean up correctly, if 1
- * is invalid.
- * This comment only applies to future boards IF they
- * implement MFE support.
- */
- fe0 = videobuf_dvb_get_frontend(&port->frontends, 1);
+ struct vb2_dvb_frontend *fe0;
+ struct i2c_client *client;
+
+ /* remove I2C client for tuner */
+ client = port->i2c_client_tuner;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ /* remove I2C client for demodulator */
+ client = port->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
+
if (fe0 && fe0->dvb.frontend)
- videobuf_dvb_unregister_bus(&port->frontends);
+ vb2_dvb_unregister_bus(&port->frontends);
switch (port->dev->board) {
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
@@ -1668,4 +1882,3 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
return 0;
}
-
diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c
index 5444cc526008..6f817d8732da 100644
--- a/drivers/media/pci/cx23885/cx23885-f300.c
+++ b/drivers/media/pci/cx23885/cx23885-f300.c
@@ -22,10 +22,6 @@
* 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 "cx23885.h"
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
index 4887314339cb..fd71306af6e2 100644
--- a/drivers/media/pci/cx23885/cx23885-i2c.c
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
@@ -13,10 +13,6 @@
* 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>
@@ -386,11 +382,3 @@ void cx23885_av_clk(struct cx23885_dev *dev, int enable)
i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
}
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 1940c18e186c..9d37fe661691 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -28,11 +28,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#include <linux/slab.h>
diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h
index 87dc44e69977..6199c7e86e83 100644
--- a/drivers/media/pci/cx23885/cx23885-input.h
+++ b/drivers/media/pci/cx23885/cx23885-input.h
@@ -14,11 +14,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#ifndef _CX23885_INPUT_H_
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c
index 271d69d1ca8c..d2cdd40f79f5 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.c
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.c
@@ -15,10 +15,6 @@
* 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 "cx23885.h"
@@ -28,7 +24,7 @@
int cx23885_g_chip_info(struct file *file, void *fh,
struct v4l2_dbg_chip_info *chip)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (chip->match.addr > 1)
return -EINVAL;
@@ -64,7 +60,7 @@ static int cx23417_g_register(struct cx23885_dev *dev,
int cx23885_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (reg->match.addr > 1)
return -EINVAL;
@@ -96,7 +92,7 @@ static int cx23417_s_register(struct cx23885_dev *dev,
int cx23885_s_register(struct file *file, void *fh,
const struct v4l2_dbg_register *reg)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (reg->match.addr > 1)
return -EINVAL;
diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h
index 92d9f0774366..cc5dbb6c1afc 100644
--- a/drivers/media/pci/cx23885/cx23885-ioctl.h
+++ b/drivers/media/pci/cx23885/cx23885-ioctl.h
@@ -15,10 +15,6 @@
* 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 _CX23885_IOCTL_H_
diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c
index bfef19359291..89dc4cc3e1ce 100644
--- a/drivers/media/pci/cx23885/cx23885-ir.c
+++ b/drivers/media/pci/cx23885/cx23885-ir.c
@@ -14,11 +14,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#include <media/v4l2-device.h>
diff --git a/drivers/media/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h
index 0c9d8bda9e28..8e93d1f10ae0 100644
--- a/drivers/media/pci/cx23885/cx23885-ir.h
+++ b/drivers/media/pci/cx23885/cx23885-ir.h
@@ -14,11 +14,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#ifndef _CX23885_IR_H_
diff --git a/drivers/media/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h
index a99936e0cbc2..2d3cbafe2402 100644
--- a/drivers/media/pci/cx23885/cx23885-reg.h
+++ b/drivers/media/pci/cx23885/cx23885-reg.h
@@ -13,10 +13,6 @@
* 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 _CX23885_REG_H_
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
index a1154f035bc1..a7c6ef8f3ea3 100644
--- a/drivers/media/pci/cx23885/cx23885-vbi.c
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
@@ -13,10 +13,6 @@
* 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/kernel.h>
@@ -42,33 +38,32 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]");
/* ------------------------------------------------------------------ */
#define VBI_LINE_LENGTH 1440
-#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */
-#define NTSC_VBI_END_LINE 21
-#define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1)
+#define VBI_NTSC_LINE_COUNT 12
+#define VBI_PAL_LINE_COUNT 18
int cx23885_vbi_fmt(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
+ f->fmt.vbi.sampling_rate = 27000000;
+ f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
+ f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.vbi.offset = 0;
+ f->fmt.vbi.flags = 0;
if (dev->tvnorm & V4L2_STD_525_60) {
/* ntsc */
- f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
- f->fmt.vbi.sampling_rate = 27000000;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = 0;
- f->fmt.vbi.flags = 0;
- f->fmt.vbi.start[0] = 10;
- f->fmt.vbi.count[0] = 17;
- f->fmt.vbi.start[1] = 263 + 10 + 1;
- f->fmt.vbi.count[1] = 17;
+ f->fmt.vbi.start[0] = V4L2_VBI_ITU_525_F1_START + 9;
+ f->fmt.vbi.start[1] = V4L2_VBI_ITU_525_F2_START + 9;
+ f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT;
+ f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT;
} else if (dev->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;
+ f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5;
+ f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5;
+ f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT;
+ f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT;
}
return 0;
@@ -94,15 +89,6 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
handled++;
}
- if (status & VID_BC_MSK_VBI_RISCI2) {
- dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__);
- dprintk(2, "stopper vbi\n");
- spin_lock(&dev->slock);
- cx23885_restart_vbi_queue(dev, &dev->vbiq);
- spin_unlock(&dev->slock);
- handled++;
- }
-
return handled;
}
@@ -114,13 +100,13 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev,
/* setup fifo + format */
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02],
- buf->vb.width, buf->risc.dma);
+ VBI_LINE_LENGTH, buf->risc.dma);
/* reset counter */
cx_write(VID_A_GPCNT_CTL, 3);
cx_write(VID_A_VBI_CTRL, 3);
cx_write(VBI_A_GPCNT_CTL, 3);
- q->count = 1;
+ q->count = 0;
/* enable irq */
cx23885_irq_add_enable(dev, 0x01);
@@ -133,163 +119,153 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev,
return 0;
}
+/* ------------------------------------------------------------------ */
-int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
- struct cx23885_dmaqueue *q)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct cx23885_buffer *buf;
- struct list_head *item;
-
- if (list_empty(&q->active))
- return 0;
-
- buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
- dprintk(2, "restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
- cx23885_start_vbi_dma(dev, q, buf);
- list_for_each(item, &q->active) {
- buf = list_entry(item, struct cx23885_buffer, vb.queue);
- buf->count = q->count++;
- }
- mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+ struct cx23885_dev *dev = q->drv_priv;
+ unsigned lines = VBI_PAL_LINE_COUNT;
+
+ if (dev->tvnorm & V4L2_STD_525_60)
+ lines = VBI_NTSC_LINE_COUNT;
+ *num_planes = 1;
+ sizes[0] = lines * VBI_LINE_LENGTH * 2;
return 0;
}
-void cx23885_vbi_timeout(unsigned long data)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct cx23885_dev *dev = (struct cx23885_dev *)data;
- struct cx23885_dmaqueue *q = &dev->vbiq;
- struct cx23885_buffer *buf;
- unsigned long flags;
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf = container_of(vb,
+ struct cx23885_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+ unsigned lines = VBI_PAL_LINE_COUNT;
+ int ret;
- /* Stop the VBI engine */
- cx_clear(VID_A_DMA_CTL, 0x22);
+ if (dev->tvnorm & V4L2_STD_525_60)
+ lines = VBI_NTSC_LINE_COUNT;
- spin_lock_irqsave(&dev->slock, flags);
- while (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx23885_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->name,
- buf, buf->vb.i, (unsigned long)buf->risc.dma);
- }
- cx23885_restart_vbi_queue(dev, q);
- spin_unlock_irqrestore(&dev->slock, flags);
-}
+ if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2)
+ return -EINVAL;
+ vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2);
-/* ------------------------------------------------------------------ */
-#define VBI_LINE_LENGTH 1440
-#define VBI_LINE_COUNT 17
+ ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+ if (!ret)
+ return -EIO;
-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;
+ cx23885_risc_vbibuffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ 0, VBI_LINE_LENGTH * lines,
+ VBI_LINE_LENGTH, 0,
+ lines);
return 0;
}
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static void buffer_finish(struct vb2_buffer *vb)
{
- struct cx23885_fh *fh = q->priv_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
struct cx23885_buffer *buf = container_of(vb,
struct cx23885_buffer, vb);
- struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->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;
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- buf->vb.width = VBI_LINE_LENGTH;
- buf->vb.height = VBI_LINE_COUNT;
- buf->vb.size = size;
- buf->vb.field = V4L2_FIELD_SEQ_TB;
-
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (0 != rc)
- goto fail;
- cx23885_risc_vbibuffer(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;
+ cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
- fail:
- cx23885_free_buffer(q, buf);
- return rc;
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
-static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
{
- struct cx23885_buffer *buf =
- container_of(vb, struct cx23885_buffer, vb);
- struct cx23885_buffer *prev;
- struct cx23885_fh *fh = vq->priv_data;
- struct cx23885_dev *dev = fh->dev;
- struct cx23885_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);
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb);
+ struct cx23885_buffer *prev;
+ struct cx23885_dmaqueue *q = &dev->vbiq;
+ unsigned long flags;
+
+ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx23885_start_vbi_dma(dev, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30));
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->queue, &q->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
dprintk(2, "[%p/%d] vbi_queue - first active\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
} else {
+ buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
prev = list_entry(q->active.prev, struct cx23885_buffer,
- vb.queue);
- list_add_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
+ queue);
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->queue, &q->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */
dprintk(2, "[%p/%d] buffer_queue - append to active\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
}
}
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct cx23885_buffer *buf =
- container_of(vb, struct cx23885_buffer, vb);
+ struct cx23885_dev *dev = q->drv_priv;
+ struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+ struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+ struct cx23885_buffer, queue);
- cx23885_free_buffer(q, buf);
+ cx23885_start_vbi_dma(dev, dmaq, buf);
+ return 0;
}
-struct videobuf_queue_ops cx23885_vbi_qops = {
- .buf_setup = vbi_setup,
- .buf_prepare = vbi_prepare,
- .buf_queue = vbi_queue,
- .buf_release = vbi_release,
-};
+static void cx23885_stop_streaming(struct vb2_queue *q)
+{
+ struct cx23885_dev *dev = q->drv_priv;
+ struct cx23885_dmaqueue *dmaq = &dev->vbiq;
+ unsigned long flags;
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+ cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+ struct cx23885_buffer, queue);
+
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
+struct vb2_ops cx23885_vbi_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = cx23885_start_streaming,
+ .stop_streaming = cx23885_stop_streaming,
+};
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 91e4cb457296..682a4f95df6b 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -13,10 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
@@ -35,6 +31,7 @@
#include "cx23885-video.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include "cx23885-ioctl.h"
#include "tuner-xc2028.h"
@@ -48,15 +45,12 @@ MODULE_LICENSE("GPL");
static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
-module_param_array(radio_nr, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
-MODULE_PARM_DESC(radio_nr, "radio device numbers");
static unsigned int video_debug;
module_param(video_debug, int, 0644);
@@ -79,77 +73,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
/* static data */
#define FORMAT_FLAGS_PACKED 0x01
-#if 0
-static struct cx23885_fmt formats[] = {
- {
- .name = "8 bpp, gray",
- .fourcc = V4L2_PIX_FMT_GREY,
- .depth = 8,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "15 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_RGB555,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "15 bpp RGB, be",
- .fourcc = V4L2_PIX_FMT_RGB555X,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "16 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_RGB565,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "16 bpp RGB, be",
- .fourcc = V4L2_PIX_FMT_RGB565X,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "24 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_BGR24,
- .depth = 24,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "32 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_BGR32,
- .depth = 32,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "32 bpp RGB, be",
- .fourcc = V4L2_PIX_FMT_RGB32,
- .depth = 32,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "4:2:2, packed, YUYV",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
- .name = "4:2:2, packed, UYVY",
- .fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },
-};
-#else
static struct cx23885_fmt formats[] = {
{
-#if 0
- .name = "4:2:2, packed, UYVY",
- .fourcc = V4L2_PIX_FMT_UYVY,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- }, {
-#endif
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.flags = FORMAT_FLAGS_PACKED,
}
};
-#endif
static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
{
@@ -158,163 +89,27 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
for (i = 0; i < ARRAY_SIZE(formats); i++)
if (formats[i].fourcc == fourcc)
return formats+i;
-
- printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__,
- (fourcc & 0xff),
- ((fourcc >> 8) & 0xff),
- ((fourcc >> 16) & 0xff),
- ((fourcc >> 24) & 0xff)
- );
return NULL;
}
/* ------------------------------------------------------------------- */
-static const struct v4l2_queryctrl no_ctl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-
-static struct cx23885_ctrl cx23885_ctls[] = {
- /* --- video --- */
- {
- .v = {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = LUMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- .v = {
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 0x7f,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = LUMA_CTRL,
- .mask = 0xff00,
- .shift = 8,
- }, {
- .v = {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = -127,
- .maximum = 128,
- .step = 1,
- .default_value = 0x0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 128,
- .reg = CHROMA_CTRL,
- .mask = 0xff0000,
- .shift = 16,
- }, {
- /* strictly, this only describes only U saturation.
- * V saturation is handled specially through code.
- */
- .v = {
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 0x7f,
- .step = 1,
- .default_value = 0x3f,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .off = 0,
- .reg = CHROMA_CTRL,
- .mask = 0x00ff,
- .shift = 0,
- }, {
- /* --- audio --- */
- .v = {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
- .reg = PATH1_CTL1,
- .mask = (0x1f << 24),
- .shift = 24,
- }, {
- .v = {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535 / 100,
- .default_value = 65535,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- .reg = PATH1_VOL_CTL,
- .mask = 0xff,
- .shift = 0,
- }
-};
-static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls);
-
-/* Must be sorted from low to high control ID! */
-static const u32 cx23885_user_ctrls[] = {
- V4L2_CID_USER_CLASS,
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_AUDIO_VOLUME,
- V4L2_CID_AUDIO_MUTE,
- 0
-};
-
-static const u32 *ctrl_classes[] = {
- cx23885_user_ctrls,
- NULL
-};
-
void cx23885_video_wakeup(struct cx23885_dev *dev,
struct cx23885_dmaqueue *q, u32 count)
{
struct cx23885_buffer *buf;
- int bc;
-
- for (bc = 0;; bc++) {
- if (list_empty(&q->active))
- break;
- buf = list_entry(q->active.next,
- struct cx23885_buffer, vb.queue);
-
- /* count comes from the hw and is is 16bit wide --
- * this trick handles wrap-arounds correctly for
- * up to 32767 buffers in flight... */
- if ((s16) (count - buf->count) < 0)
- break;
-
- v4l2_get_timestamp(&buf->vb.ts);
- dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
- count, buf->count);
- buf->vb.state = VIDEOBUF_DONE;
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- }
+
if (list_empty(&q->active))
- del_timer(&q->timeout);
- else
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- if (bc != 1)
- printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
- __func__, bc);
+ return;
+ buf = list_entry(q->active.next,
+ struct cx23885_buffer, queue);
+
+ buf->vb.v4l2_buf.sequence = q->count++;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index,
+ count, q->count);
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
@@ -324,6 +119,12 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
(unsigned int)norm,
v4l2_norm_to_name(norm));
+ if (dev->tvnorm != norm) {
+ if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+ vb2_is_busy(&dev->vb2_mpegq))
+ return -EBUSY;
+ }
+
dev->tvnorm = norm;
call_all(dev, video, s_std, norm);
@@ -345,79 +146,13 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
+ vfd->lock = &dev->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s (%s)",
cx23885_boards[dev->board].name, type);
video_set_drvdata(vfd, dev);
return vfd;
}
-static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl)
-{
- int i;
-
- if (qctrl->id < V4L2_CID_BASE ||
- qctrl->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- for (i = 0; i < CX23885_CTLS; i++)
- if (cx23885_ctls[i].v.id == qctrl->id)
- break;
- if (i == CX23885_CTLS) {
- *qctrl = no_ctl;
- return 0;
- }
- *qctrl = cx23885_ctls[i].v;
- return 0;
-}
-
-/* ------------------------------------------------------------------- */
-/* resource management */
-
-static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
- unsigned int bit)
-{
- dprintk(1, "%s()\n", __func__);
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
-
- /* is it free? */
- mutex_lock(&dev->lock);
- if (dev->resources & bit) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- dev->resources |= bit;
- dprintk(1, "res: get %d\n", bit);
- mutex_unlock(&dev->lock);
- return 1;
-}
-
-static int res_check(struct cx23885_fh *fh, unsigned int bit)
-{
- return fh->resources & bit;
-}
-
-static int res_locked(struct cx23885_dev *dev, unsigned int bit)
-{
- return dev->resources & bit;
-}
-
-static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
- unsigned int bits)
-{
- BUG_ON((fh->resources & bits) != bits);
- dprintk(1, "%s()\n", __func__);
-
- mutex_lock(&dev->lock);
- fh->resources &= ~bits;
- dev->resources &= ~bits;
- dprintk(1, "res: put %d\n", bits);
- mutex_unlock(&dev->lock);
-}
-
int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data)
{
/* 8 bit registers, 8 bit values */
@@ -567,7 +302,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
/* reset counter */
cx_write(VID_A_GPCNT_CTL, 3);
- q->count = 1;
+ q->count = 0;
/* enable irq */
cx23885_irq_add_enable(dev, 0x01);
@@ -580,479 +315,206 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
return 0;
}
-
-static int cx23885_restart_video_queue(struct cx23885_dev *dev,
- struct cx23885_dmaqueue *q)
-{
- struct cx23885_buffer *buf, *prev;
- struct list_head *item;
- dprintk(1, "%s()\n", __func__);
-
- if (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx23885_buffer,
- vb.queue);
- dprintk(2, "restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
- cx23885_start_video_dma(dev, q, buf);
- list_for_each(item, &q->active) {
- buf = list_entry(item, struct cx23885_buffer,
- vb.queue);
- buf->count = q->count++;
- }
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- return 0;
- }
-
- prev = NULL;
- for (;;) {
- if (list_empty(&q->queued))
- return 0;
- buf = list_entry(q->queued.next, struct cx23885_buffer,
- vb.queue);
- if (NULL == prev) {
- list_move_tail(&buf->vb.queue, &q->active);
- cx23885_start_video_dma(dev, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(2, "[%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);
- prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
- dprintk(2, "[%p/%d] restart_queue - move to active\n",
- buf, buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
-}
-
-static int buffer_setup(struct videobuf_queue *q, unsigned int *count,
- unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct cx23885_fh *fh = q->priv_data;
+ struct cx23885_dev *dev = q->drv_priv;
- *size = fh->fmt->depth*fh->width*fh->height >> 3;
- if (0 == *count)
- *count = 32;
- if (*size * *count > vid_limit * 1024 * 1024)
- *count = (vid_limit * 1024 * 1024) / *size;
+ *num_planes = 1;
+ sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
return 0;
}
-static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct cx23885_fh *fh = q->priv_data;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
struct cx23885_buffer *buf =
container_of(vb, struct cx23885_buffer, vb);
- int rc, init_buffer = 0;
u32 line0_offset, line1_offset;
- struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
int field_tff;
+ int ret;
- BUG_ON(NULL == fh->fmt);
- if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) ||
- fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))
- return -EINVAL;
- buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ buf->bpl = (dev->width * dev->fmt->depth) >> 3;
+
+ if (vb2_plane_size(vb, 0) < dev->height * buf->bpl)
return -EINVAL;
+ vb2_set_plane_payload(vb, 0, dev->height * buf->bpl);
- if (buf->fmt != fh->fmt ||
- buf->vb.width != fh->width ||
- buf->vb.height != fh->height ||
- buf->vb.field != field) {
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- init_buffer = 1;
- }
+ ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+ if (!ret)
+ return -EIO;
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- init_buffer = 1;
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (0 != rc)
- goto fail;
- }
+ switch (dev->field) {
+ case V4L2_FIELD_TOP:
+ cx23885_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, 0, UNSET,
+ buf->bpl, 0, dev->height);
+ break;
+ case V4L2_FIELD_BOTTOM:
+ cx23885_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, UNSET, 0,
+ buf->bpl, 0, dev->height);
+ break;
+ case V4L2_FIELD_INTERLACED:
+ if (dev->tvnorm & V4L2_STD_525_60)
+ /* NTSC or */
+ field_tff = 1;
+ else
+ field_tff = 0;
+
+ if (cx23885_boards[dev->board].force_bff)
+ /* PAL / SECAM OR 888 in NTSC MODE */
+ field_tff = 0;
- if (init_buffer) {
- buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
- switch (buf->vb.field) {
- case V4L2_FIELD_TOP:
- cx23885_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, 0, UNSET,
- buf->bpl, 0, buf->vb.height);
- break;
- case V4L2_FIELD_BOTTOM:
- cx23885_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, UNSET, 0,
- buf->bpl, 0, buf->vb.height);
- break;
- case V4L2_FIELD_INTERLACED:
- if (dev->tvnorm & V4L2_STD_NTSC)
- /* NTSC or */
- field_tff = 1;
- else
- field_tff = 0;
-
- if (cx23885_boards[dev->board].force_bff)
- /* PAL / SECAM OR 888 in NTSC MODE */
- field_tff = 0;
-
- if (field_tff) {
- /* cx25840 transmits NTSC bottom field first */
- dprintk(1, "%s() Creating TFF/NTSC risc\n",
+ if (field_tff) {
+ /* cx25840 transmits NTSC bottom field first */
+ dprintk(1, "%s() Creating TFF/NTSC risc\n",
__func__);
- line0_offset = buf->bpl;
- line1_offset = 0;
- } else {
- /* All other formats are top field first */
- dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
+ line0_offset = buf->bpl;
+ line1_offset = 0;
+ } else {
+ /* All other formats are top field first */
+ dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n",
__func__);
- line0_offset = 0;
- line1_offset = buf->bpl;
- }
- cx23885_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, line0_offset,
- line1_offset,
- buf->bpl, buf->bpl,
- buf->vb.height >> 1);
- break;
- case V4L2_FIELD_SEQ_TB:
- cx23885_risc_buffer(dev->pci, &buf->risc,
- dma->sglist,
- 0, buf->bpl * (buf->vb.height >> 1),
- buf->bpl, 0,
- buf->vb.height >> 1);
- break;
- case V4L2_FIELD_SEQ_BT:
- cx23885_risc_buffer(dev->pci, &buf->risc,
- dma->sglist,
- buf->bpl * (buf->vb.height >> 1), 0,
- buf->bpl, 0,
- buf->vb.height >> 1);
- break;
- default:
- BUG();
+ line0_offset = 0;
+ line1_offset = buf->bpl;
}
+ cx23885_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, line0_offset,
+ line1_offset,
+ buf->bpl, buf->bpl,
+ dev->height >> 1);
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ cx23885_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ 0, buf->bpl * (dev->height >> 1),
+ buf->bpl, 0,
+ dev->height >> 1);
+ break;
+ case V4L2_FIELD_SEQ_BT:
+ cx23885_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ buf->bpl * (dev->height >> 1), 0,
+ buf->bpl, 0,
+ dev->height >> 1);
+ break;
+ default:
+ BUG();
}
- dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
- buf, buf->vb.i,
- fh->width, fh->height, fh->fmt->depth, fh->fmt->name,
+ dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
+ buf, buf->vb.v4l2_buf.index,
+ dev->width, dev->height, dev->fmt->depth, dev->fmt->name,
(unsigned long)buf->risc.dma);
-
- buf->vb.state = VIDEOBUF_PREPARED;
return 0;
+}
+
+static void buffer_finish(struct vb2_buffer *vb)
+{
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx23885_buffer *buf = container_of(vb,
+ struct cx23885_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+
+ cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
- fail:
- cx23885_free_buffer(q, buf);
- return rc;
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/*
+ * The risc program for each buffer works as follows: it starts with a simple
+ * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 12 (skipping
+ * the initial JUMP).
+ *
+ * This is the risc program of the first buffer to be queued if the active list
+ * is empty and it just keeps DMAing this buffer without generating any
+ * interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the code for that buffer
+ * will generate an interrupt which signals that the previous buffer has been
+ * DMAed successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void buffer_queue(struct vb2_buffer *vb)
{
+ struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
struct cx23885_buffer *buf = container_of(vb,
struct cx23885_buffer, vb);
struct cx23885_buffer *prev;
- struct cx23885_fh *fh = vq->priv_data;
- struct cx23885_dev *dev = fh->dev;
struct cx23885_dmaqueue *q = &dev->vidq;
+ unsigned long flags;
- /* 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);
+ /* add jump to start */
+ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
- buf, buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue, &q->active);
- cx23885_start_video_dma(dev, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ spin_lock_irqsave(&dev->slock, flags);
+ if (list_empty(&q->active)) {
+ list_add_tail(&buf->queue, &q->active);
dprintk(2, "[%p/%d] buffer_queue - first active\n",
- buf, buf->vb.i);
-
+ buf, buf->vb.v4l2_buf.index);
} else {
+ buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
prev = list_entry(q->active.prev, struct cx23885_buffer,
- vb.queue);
- if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- 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);
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2, "[%p/%d] buffer_queue - append to active\n",
- buf, buf->vb.i);
-
- } else {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2, "[%p/%d] buffer_queue - first queued\n",
- buf, buf->vb.i);
- }
- }
-}
-
-static void buffer_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- struct cx23885_buffer *buf = container_of(vb,
- struct cx23885_buffer, vb);
-
- cx23885_free_buffer(q, buf);
-}
-
-static struct videobuf_queue_ops cx23885_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-static struct videobuf_queue *get_queue(struct cx23885_fh *fh)
-{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return &fh->vidq;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- return &fh->vbiq;
- default:
- BUG();
- return NULL;
- }
-}
-
-static int get_resource(struct cx23885_fh *fh)
-{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return RESOURCE_VIDEO;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- return RESOURCE_VBI;
- default:
- BUG();
- return 0;
+ queue);
+ list_add_tail(&buf->queue, &q->active);
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+ buf, buf->vb.v4l2_buf.index);
}
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-static int video_open(struct file *file)
+static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct video_device *vdev = video_devdata(file);
- struct cx23885_dev *dev = video_drvdata(file);
- struct cx23885_fh *fh;
- enum v4l2_buf_type type = 0;
- int radio = 0;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- }
-
- dprintk(1, "open dev=%s radio=%d type=%s\n",
- video_device_node_name(vdev), radio, v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- file->private_data = fh;
- fh->dev = dev;
- fh->radio = radio;
- fh->type = type;
- fh->width = 320;
- fh->height = 240;
- fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
-
- videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx23885_buffer),
- fh, NULL);
-
- videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct cx23885_buffer),
- fh, NULL);
-
-
- dprintk(1, "post videobuf_queue_init()\n");
+ struct cx23885_dev *dev = q->drv_priv;
+ struct cx23885_dmaqueue *dmaq = &dev->vidq;
+ struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+ struct cx23885_buffer, queue);
+ cx23885_start_video_dma(dev, dmaq, buf);
return 0;
}
-static ssize_t video_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
+static void cx23885_stop_streaming(struct vb2_queue *q)
{
- struct cx23885_fh *fh = file->private_data;
-
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (res_locked(fh->dev, RESOURCE_VIDEO))
- return -EBUSY;
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (!res_get(fh->dev, fh, RESOURCE_VBI))
- return -EBUSY;
- return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
- file->f_flags & O_NONBLOCK);
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_buffer *buf;
- unsigned int rc = POLLERR;
-
- if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
- if (!res_get(fh->dev, fh, RESOURCE_VBI))
- return POLLERR;
- return videobuf_poll_stream(file, &fh->vbiq, wait);
- }
-
- mutex_lock(&fh->vidq.vb_lock);
- if (res_check(fh, RESOURCE_VIDEO)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- goto done;
- buf = list_entry(fh->vidq.stream.next,
- struct cx23885_buffer, vb.stream);
- } else {
- /* read() capture */
- buf = (struct cx23885_buffer *)fh->vidq.read_buf;
- if (NULL == buf)
- goto done;
- }
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE ||
- buf->vb.state == VIDEOBUF_ERROR)
- rc = POLLIN|POLLRDNORM;
- else
- rc = 0;
-done:
- mutex_unlock(&fh->vidq.vb_lock);
- return rc;
-}
-
-static int video_release(struct file *file)
-{
- struct cx23885_fh *fh = file->private_data;
- struct cx23885_dev *dev = fh->dev;
-
- /* turn off overlay */
- if (res_check(fh, RESOURCE_OVERLAY)) {
- /* FIXME */
- res_free(dev, fh, RESOURCE_OVERLAY);
- }
+ struct cx23885_dev *dev = q->drv_priv;
+ struct cx23885_dmaqueue *dmaq = &dev->vidq;
+ unsigned long flags;
- /* stop video capture */
- if (res_check(fh, RESOURCE_VIDEO)) {
- videobuf_queue_cancel(&fh->vidq);
- res_free(dev, fh, RESOURCE_VIDEO);
- }
- if (fh->vidq.read_buf) {
- buffer_release(&fh->vidq, fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
+ cx_clear(VID_A_DMA_CTL, 0x11);
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx23885_buffer *buf = list_entry(dmaq->active.next,
+ struct cx23885_buffer, queue);
- /* stop vbi capture */
- if (res_check(fh, RESOURCE_VBI)) {
- if (fh->vbiq.streaming)
- videobuf_streamoff(&fh->vbiq);
- if (fh->vbiq.reading)
- videobuf_read_stop(&fh->vbiq);
- res_free(dev, fh, RESOURCE_VBI);
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
-
- videobuf_mmap_free(&fh->vidq);
- videobuf_mmap_free(&fh->vbiq);
-
- file->private_data = NULL;
- kfree(fh);
-
- /* We are not putting the tuner to sleep here on exit, because
- * we want to use the mpeg encoder in another session to capture
- * tuner video. Closing this will result in no video to the encoder.
- */
-
- return 0;
-}
-
-static int video_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cx23885_fh *fh = file->private_data;
-
- return videobuf_mmap_mapper(get_queue(fh), vma);
-}
-
-/* ------------------------------------------------------------------ */
-/* VIDEO CTRL IOCTLS */
-
-int cx23885_get_control(struct cx23885_dev *dev,
- struct v4l2_control *ctl)
-{
- dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
- call_all(dev, core, g_ctrl, ctl);
- return 0;
-}
-
-int cx23885_set_control(struct cx23885_dev *dev,
- struct v4l2_control *ctl)
-{
- dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__);
- call_all(dev, core, s_ctrl, ctl);
-
- return 0;
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-static void init_controls(struct cx23885_dev *dev)
-{
- struct v4l2_control ctrl;
- int i;
-
- for (i = 0; i < CX23885_CTLS; i++) {
- ctrl.id = cx23885_ctls[i].v.id;
- ctrl.value = cx23885_ctls[i].v.default_value;
-
- cx23885_set_control(dev, &ctrl);
- }
-}
+static struct vb2_ops cx23885_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = cx23885_start_streaming,
+ .stop_streaming = cx23885_stop_streaming,
+};
/* ------------------------------------------------------------------ */
/* VIDEO IOCTLS */
@@ -1060,16 +522,17 @@ static void init_controls(struct cx23885_dev *dev)
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = video_drvdata(file);
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = dev->field;
+ f->fmt.pix.pixelformat = dev->fmt->fourcc;
f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ (f->fmt.pix.width * dev->fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -1077,7 +540,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
struct cx23885_fmt *fmt;
enum v4l2_field field;
unsigned int maxw, maxh;
@@ -1102,9 +565,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
maxh = maxh / 2;
break;
case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_TB:
+ case V4L2_FIELD_SEQ_BT:
break;
default:
- return -EINVAL;
+ field = V4L2_FIELD_INTERLACED;
+ break;
}
f->fmt.pix.field = field;
@@ -1114,6 +580,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -1121,8 +588,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
struct v4l2_mbus_framefmt mbus_fmt;
int err;
@@ -1131,34 +597,44 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (0 != err)
return err;
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
+
+ if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
+ vb2_is_busy(&dev->vb2_mpegq))
+ return -EBUSY;
+
+ dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ dev->field = f->fmt.pix.field;
dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
- fh->width, fh->height, fh->vidq.field);
+ dev->width, dev->height, dev->field);
v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
call_all(dev, video, s_mbus_fmt, &mbus_fmt);
v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
+ /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */
+ f->fmt.pix.field = dev->field;
return 0;
}
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
strcpy(cap->driver, "cx23885");
strlcpy(cap->card, cx23885_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_VBI_CAPTURE;
+ cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO;
if (dev->tuner_type != TUNER_ABSENT)
- cap->capabilities |= V4L2_CAP_TUNER;
+ cap->device_caps |= V4L2_CAP_TUNER;
+ if (vdev->vfl_type == VFL_TYPE_VBI)
+ cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
+ else
+ cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1175,85 +651,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct cx23885_fh *fh = priv;
- return videobuf_reqbufs(get_queue(fh), p);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx23885_fh *fh = priv;
- return videobuf_querybuf(get_queue(fh), p);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx23885_fh *fh = priv;
- return videobuf_qbuf(get_queue(fh), p);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx23885_fh *fh = priv;
- return videobuf_dqbuf(get_queue(fh), p,
- file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type i)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
- dprintk(1, "%s()\n", __func__);
-
- if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
- if (unlikely(i != fh->type))
- return -EINVAL;
-
- if (unlikely(!res_get(dev, fh, get_resource(fh))))
- return -EBUSY;
-
- /* Don't start VBI streaming unless vida streaming
- * has already started.
- */
- if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) &&
- ((cx_read(VID_A_DMA_CTL) & 0x11) == 0))
- return -EINVAL;
-
- return videobuf_streamon(get_queue(fh));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
- int err, res;
- dprintk(1, "%s()\n", __func__);
-
- if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
- (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
- if (i != fh->type)
- return -EINVAL;
-
- res = get_resource(fh);
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- res_free(dev, fh, res);
- return 0;
-}
-
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
dprintk(1, "%s()\n", __func__);
*id = dev->tvnorm;
@@ -1262,14 +662,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
dprintk(1, "%s()\n", __func__);
- mutex_lock(&dev->lock);
- cx23885_set_tvnorm(dev, tvnorms);
- mutex_unlock(&dev->lock);
-
- return 0;
+ return cx23885_set_tvnorm(dev, tvnorms);
}
int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
@@ -1299,16 +695,16 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name, iname[INPUT(n)->type]);
+ i->std = CX23885_NORMS;
if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
(CX23885_VMUX_CABLE == INPUT(n)->type)) {
i->type = V4L2_INPUT_TYPE_TUNER;
- i->std = CX23885_NORMS;
+ i->audioset = 4;
+ } else {
+ /* Two selectable audio inputs for non-tv inputs */
+ i->audioset = 3;
}
- /* Two selectable audio inputs for non-tv inputs */
- if (INPUT(n)->type != CX23885_VMUX_TELEVISION)
- i->audioset = 0x3;
-
if (dev->input == n) {
/* enum'd input matches our configured input.
* Ask the video decoder to process the call
@@ -1324,14 +720,14 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
dprintk(1, "%s()\n", __func__);
return cx23885_enum_input(dev, i);
}
int cx23885_get_input(struct file *file, void *priv, unsigned int *i)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
*i = dev->input;
dprintk(1, "%s() returns %d\n", __func__, *i);
@@ -1345,7 +741,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
int cx23885_set_input(struct file *file, void *priv, unsigned int i)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
dprintk(1, "%s(%d)\n", __func__, i);
@@ -1357,13 +753,11 @@ int cx23885_set_input(struct file *file, void *priv, unsigned int i)
if (INPUT(i)->type == 0)
return -EINVAL;
- mutex_lock(&dev->lock);
cx23885_video_mux(dev, i);
/* By default establish the default audio input for the card also */
/* Caller is free to use VIDIOC_S_AUDIO to override afterwards */
cx23885_audio_mux(dev, i);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1374,39 +768,32 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
static int vidioc_log_status(struct file *file, void *priv)
{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
- printk(KERN_INFO
- "%s/0: ============ START LOG STATUS ============\n",
- dev->name);
call_all(dev, core, log_status);
- printk(KERN_INFO
- "%s/0: ============= END LOG STATUS =============\n",
- dev->name);
return 0;
}
static int cx23885_query_audinput(struct file *file, void *priv,
struct v4l2_audio *i)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
static const char *iname[] = {
[0] = "Baseband L/R 1",
[1] = "Baseband L/R 2",
+ [2] = "TV",
};
unsigned int n;
dprintk(1, "%s()\n", __func__);
n = i->index;
- if (n >= 2)
+ if (n >= 3)
return -EINVAL;
memset(i, 0, sizeof(*i));
i->index = n;
strcpy(i->name, iname[n]);
- i->capability = V4L2_AUDCAP_STEREO;
- i->mode = V4L2_AUDMODE_AVL;
+ i->capability = V4L2_AUDCAP_STEREO;
return 0;
}
@@ -1420,9 +807,13 @@ static int vidioc_enum_audinput(struct file *file, void *priv,
static int vidioc_g_audinput(struct file *file, void *priv,
struct v4l2_audio *i)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
- i->index = dev->audinput;
+ if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+ (CX23885_VMUX_CABLE == INPUT(dev->input)->type))
+ i->index = 2;
+ else
+ i->index = dev->audinput;
dprintk(1, "%s(input=%d)\n", __func__, i->index);
return cx23885_query_audinput(file, priv, i);
@@ -1431,8 +822,13 @@ static int vidioc_g_audinput(struct file *file, void *priv,
static int vidioc_s_audinput(struct file *file, void *priv,
const struct v4l2_audio *i)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- if (i->index >= 2)
+ struct cx23885_dev *dev = video_drvdata(file);
+
+ if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) ||
+ (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) {
+ return i->index != 2 ? -EINVAL : 0;
+ }
+ if (i->index > 1)
return -EINVAL;
dprintk(1, "%s(%d)\n", __func__, i->index);
@@ -1445,35 +841,10 @@ static int vidioc_s_audinput(struct file *file, void *priv,
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (unlikely(qctrl->id == 0))
- return -EINVAL;
- return cx23885_ctrl_query(qctrl);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
- return cx23885_get_control(dev, ctl);
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctl)
-{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
-
- return cx23885_set_control(dev, ctl);
-}
-
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
@@ -1489,7 +860,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
static int vidioc_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
@@ -1504,14 +875,12 @@ static int vidioc_s_tuner(struct file *file, void *priv,
static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
- /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
- f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->type = V4L2_TUNER_ANALOG_TV;
f->frequency = dev->freq;
call_all(dev, tuner, g_frequency, f);
@@ -1521,20 +890,23 @@ static int vidioc_g_frequency(struct file *file, void *priv,
static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f)
{
- struct v4l2_control ctrl;
+ struct v4l2_ctrl *mute;
+ int old_mute_val = 1;
if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
if (unlikely(f->tuner != 0))
return -EINVAL;
- mutex_lock(&dev->lock);
dev->freq = f->frequency;
/* I need to mute audio here */
- ctrl.id = V4L2_CID_AUDIO_MUTE;
- ctrl.value = 1;
- cx23885_set_control(dev, &ctrl);
+ mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+ if (mute) {
+ old_mute_val = v4l2_ctrl_g_ctrl(mute);
+ if (!old_mute_val)
+ v4l2_ctrl_s_ctrl(mute, 1);
+ }
call_all(dev, tuner, s_frequency, f);
@@ -1542,10 +914,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency
msleep(100);
/* I need to unmute audio here */
- ctrl.value = 0;
- cx23885_set_control(dev, &ctrl);
-
- mutex_unlock(&dev->lock);
+ if (old_mute_val == 0)
+ v4l2_ctrl_s_ctrl(mute, old_mute_val);
return 0;
}
@@ -1553,8 +923,9 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency
static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
const struct v4l2_frequency *f)
{
- struct v4l2_control ctrl;
- struct videobuf_dvb_frontend *vfe;
+ struct v4l2_ctrl *mute;
+ int old_mute_val = 1;
+ struct vb2_dvb_frontend *vfe;
struct dvb_frontend *fe;
struct analog_parameters params = {
@@ -1564,21 +935,22 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
.frequency = f->frequency
};
- mutex_lock(&dev->lock);
dev->freq = f->frequency;
/* I need to mute audio here */
- ctrl.id = V4L2_CID_AUDIO_MUTE;
- ctrl.value = 1;
- cx23885_set_control(dev, &ctrl);
+ mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE);
+ if (mute) {
+ old_mute_val = v4l2_ctrl_g_ctrl(mute);
+ if (!old_mute_val)
+ v4l2_ctrl_s_ctrl(mute, 1);
+ }
/* If HVR1850 */
dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__,
params.frequency, f->tuner, params.std);
- vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1);
+ vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1);
if (!vfe) {
- mutex_unlock(&dev->lock);
return -EINVAL;
}
@@ -1600,10 +972,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
msleep(100);
/* I need to unmute audio here */
- ctrl.value = 0;
- cx23885_set_control(dev, &ctrl);
-
- mutex_unlock(&dev->lock);
+ if (old_mute_val == 0)
+ v4l2_ctrl_s_ctrl(mute, old_mute_val);
return 0;
}
@@ -1611,8 +981,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
int cx23885_set_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
- struct cx23885_fh *fh = priv;
- struct cx23885_dev *dev = fh->dev;
+ struct cx23885_dev *dev = video_drvdata(file);
int ret;
switch (dev->board) {
@@ -1636,28 +1005,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
/* ----------------------------------------------------------- */
-static void cx23885_vid_timeout(unsigned long data)
-{
- struct cx23885_dev *dev = (struct cx23885_dev *)data;
- struct cx23885_dmaqueue *q = &dev->vidq;
- struct cx23885_buffer *buf;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->slock, flags);
- while (!list_empty(&q->active)) {
- buf = list_entry(q->active.next,
- struct cx23885_buffer, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n",
- dev->name, buf, buf->vb.i,
- (unsigned long)buf->risc.dma);
- }
- cx23885_restart_video_queue(dev, q);
- spin_unlock_irqrestore(&dev->slock, flags);
-}
-
int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
{
u32 mask, count;
@@ -1702,13 +1049,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
spin_unlock(&dev->slock);
handled++;
}
- if (status & VID_BC_MSK_RISCI2) {
- dprintk(2, "stopper video\n");
- spin_lock(&dev->slock);
- cx23885_restart_video_queue(dev, &dev->vidq);
- spin_unlock(&dev->slock);
- handled++;
- }
/* Allow the VBI framework to process it's payload */
handled += cx23885_vbi_irq(dev, status);
@@ -1721,12 +1061,12 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
static const struct v4l2_file_operations video_fops = {
.owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = video_mmap,
- .ioctl = video_ioctl2,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1738,21 +1078,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt,
.vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt,
.vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
.vidioc_log_status = vidioc_log_status,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1765,6 +1103,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_enumaudio = vidioc_enum_audinput,
.vidioc_g_audio = vidioc_g_audinput,
.vidioc_s_audio = vidioc_s_audinput,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device cx23885_vbi_template;
@@ -1775,14 +1115,6 @@ static struct video_device cx23885_video_template = {
.tvnorms = CX23885_NORMS,
};
-static const struct v4l2_file_operations radio_fops = {
- .owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .ioctl = video_ioctl2,
-};
-
-
void cx23885_video_unregister(struct cx23885_dev *dev)
{
dprintk(1, "%s()\n", __func__);
@@ -1794,7 +1126,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
else
video_device_release(dev->vbi_dev);
dev->vbi_dev = NULL;
- btcx_riscmem_free(dev->pci, &dev->vbiq.stopper);
}
if (dev->video_dev) {
if (video_is_registered(dev->video_dev))
@@ -1802,8 +1133,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
else
video_device_release(dev->video_dev);
dev->video_dev = NULL;
-
- btcx_riscmem_free(dev->pci, &dev->vidq.stopper);
}
if (dev->audio_dev)
@@ -1812,6 +1141,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev)
int cx23885_video_register(struct cx23885_dev *dev)
{
+ struct vb2_queue *q;
int err;
dprintk(1, "%s()\n", __func__);
@@ -1822,24 +1152,16 @@ int cx23885_video_register(struct cx23885_dev *dev)
strcpy(cx23885_vbi_template.name, "cx23885-vbi");
dev->tvnorm = V4L2_STD_NTSC_M;
+ dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV);
+ dev->field = V4L2_FIELD_INTERLACED;
+ dev->width = 720;
+ dev->height = norm_maxh(dev->tvnorm);
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
- dev->vidq.timeout.function = cx23885_vid_timeout;
- dev->vidq.timeout.data = (unsigned long)dev;
- init_timer(&dev->vidq.timeout);
- cx23885_risc_stopper(dev->pci, &dev->vidq.stopper,
- VID_A_DMA_CTL, 0x11, 0x00);
/* init vbi dma queues */
INIT_LIST_HEAD(&dev->vbiq.active);
- INIT_LIST_HEAD(&dev->vbiq.queued);
- dev->vbiq.timeout.function = cx23885_vbi_timeout;
- dev->vbiq.timeout.data = (unsigned long)dev;
- init_timer(&dev->vbiq.timeout);
- cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper,
- VID_A_DMA_CTL, 0x22, 0x00);
cx23885_irq_add_enable(dev, 0x01);
@@ -1893,9 +1215,49 @@ int cx23885_video_register(struct cx23885_dev *dev)
}
}
+ /* initial device configuration */
+ mutex_lock(&dev->lock);
+ cx23885_set_tvnorm(dev, dev->tvnorm);
+ cx23885_video_mux(dev, 0);
+ cx23885_audio_mux(dev, 0);
+ mutex_unlock(&dev->lock);
+
+ q = &dev->vb2_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx23885_buffer);
+ q->ops = &cx23885_video_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ goto fail_unreg;
+
+ q = &dev->vb2_vbiq;
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx23885_buffer);
+ q->ops = &cx23885_vbi_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ goto fail_unreg;
+
/* register Video device */
dev->video_dev = cx23885_vdev_init(dev, dev->pci,
&cx23885_video_template, "video");
+ dev->video_dev->queue = &dev->vb2_vidq;
err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
video_nr[dev->nr]);
if (err < 0) {
@@ -1909,6 +1271,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
/* register VBI device */
dev->vbi_dev = cx23885_vdev_init(dev, dev->pci,
&cx23885_vbi_template, "vbi");
+ dev->vbi_dev->queue = &dev->vb2_vbiq;
err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->nr]);
if (err < 0) {
@@ -1922,18 +1285,9 @@ int cx23885_video_register(struct cx23885_dev *dev)
/* Register ALSA audio device */
dev->audio_dev = cx23885_audio_register(dev);
- /* initial device configuration */
- mutex_lock(&dev->lock);
- cx23885_set_tvnorm(dev, dev->tvnorm);
- init_controls(dev);
- cx23885_video_mux(dev, 0);
- cx23885_audio_mux(dev, 0);
- mutex_unlock(&dev->lock);
-
return 0;
fail_unreg:
cx23885_video_unregister(dev);
return err;
}
-
diff --git a/drivers/media/pci/cx23885/cx23885-video.h b/drivers/media/pci/cx23885/cx23885-video.h
index c961a2b0de0f..291e8f3189f0 100644
--- a/drivers/media/pci/cx23885/cx23885-video.h
+++ b/drivers/media/pci/cx23885/cx23885-video.h
@@ -12,11 +12,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#ifndef _CX23885_VIDEO_H_
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 0e086c03da67..6c35e6115969 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -13,10 +13,6 @@
* 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>
@@ -25,19 +21,20 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
-#include <media/videobuf-dma-sg.h>
-#include <media/videobuf-dvb.h>
+#include <media/videobuf2-dma-sg.h>
+#include <media/videobuf2-dvb.h>
#include <media/rc-core.h>
-#include "btcx-risc.h"
#include "cx23885-reg.h"
#include "media/cx2341x.h"
#include <linux/mutex.h>
-#define CX23885_VERSION "0.0.3"
+#define CX23885_VERSION "0.0.4"
#define UNSET (-1U)
@@ -46,9 +43,6 @@
/* Max number of inputs by card */
#define MAX_CX23885_INPUT 8
#define INPUT(nr) (&cx23885_boards[dev->board].input[nr])
-#define RESOURCE_OVERLAY 1
-#define RESOURCE_VIDEO 2
-#define RESOURCE_VBI 4
#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */
@@ -98,6 +92,7 @@
#define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42
#define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE 43
#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44
+#define CX23885_BOARD_DVBSKY_T9580 45
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -131,14 +126,6 @@ struct cx23885_fmt {
u32 cxformat;
};
-struct cx23885_ctrl {
- struct v4l2_queryctrl v;
- u32 off;
- u32 reg;
- u32 mask;
- u32 shift;
-};
-
struct cx23885_tvnorm {
char *name;
v4l2_std_id id;
@@ -146,30 +133,6 @@ struct cx23885_tvnorm {
u32 cxoformat;
};
-struct cx23885_fh {
- struct cx23885_dev *dev;
- enum v4l2_buf_type type;
- int radio;
- u32 resources;
-
- /* video overlay */
- struct v4l2_window win;
- struct v4l2_clip *clips;
- unsigned int nclips;
-
- /* video capture */
- struct cx23885_fmt *fmt;
- unsigned int width, height;
-
- /* vbi capture */
- struct videobuf_queue vidq;
- struct videobuf_queue vbiq;
-
- /* MPEG Encoder specifics ONLY */
- struct videobuf_queue mpegq;
- atomic_t v4l_reading;
-};
-
enum cx23885_itype {
CX23885_VMUX_COMPOSITE1 = 1,
CX23885_VMUX_COMPOSITE2,
@@ -189,14 +152,22 @@ enum cx23885_src_sel_type {
CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
};
+struct cx23885_riscmem {
+ unsigned int size;
+ __le32 *cpu;
+ __le32 *jmp;
+ dma_addr_t dma;
+};
+
/* buffer for one video frame */
struct cx23885_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
+ struct vb2_buffer vb;
+ struct list_head queue;
/* cx23885 specific */
unsigned int bpl;
- struct btcx_riscmem risc;
+ struct cx23885_riscmem risc;
struct cx23885_fmt *fmt;
u32 count;
};
@@ -268,9 +239,6 @@ struct cx23885_i2c {
struct cx23885_dmaqueue {
struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
- struct btcx_riscmem stopper;
u32 count;
};
@@ -280,7 +248,7 @@ struct cx23885_tsport {
int nr;
int sram_chno;
- struct videobuf_dvb_frontends frontends;
+ struct vb2_dvb_frontends frontends;
/* dma queues */
struct cx23885_dmaqueue mpegq;
@@ -326,7 +294,12 @@ struct cx23885_tsport {
/* Workaround for a temp dvb_frontend that the tuner can attached to */
struct dvb_frontend analog_fe;
+ struct i2c_client *i2c_client_demod;
+ struct i2c_client *i2c_client_tuner;
+
int (*set_frontend)(struct dvb_frontend *fe);
+ int (*fe_set_voltage)(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage);
};
struct cx23885_kernel_ir {
@@ -339,8 +312,11 @@ struct cx23885_kernel_ir {
struct cx23885_audio_buffer {
unsigned int bpl;
- struct btcx_riscmem risc;
- struct videobuf_dmabuf dma;
+ struct cx23885_riscmem risc;
+ void *vaddr;
+ struct scatterlist *sglist;
+ int sglen;
+ int nr_pages;
};
struct cx23885_audio_dev {
@@ -358,8 +334,6 @@ struct cx23885_audio_dev {
unsigned int period_size;
unsigned int num_periods;
- struct videobuf_dmabuf *dma_risc;
-
struct cx23885_audio_buffer *buf;
struct snd_pcm_substream *substream;
@@ -368,6 +342,7 @@ struct cx23885_audio_dev {
struct cx23885_dev {
atomic_t refcount;
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
/* pci stuff */
struct pci_dev *pci;
@@ -407,7 +382,6 @@ struct cx23885_dev {
} bridge;
/* Analog video */
- u32 resources;
unsigned int input;
unsigned int audinput; /* Selectable audio input */
u32 tvaudio;
@@ -417,7 +391,6 @@ struct cx23885_dev {
unsigned int tuner_bus;
unsigned int radio_type;
unsigned char radio_addr;
- unsigned int has_radio;
struct v4l2_subdev *sd_cx25840;
struct work_struct cx25840_work;
@@ -435,17 +408,24 @@ struct cx23885_dev {
u32 freq;
struct video_device *video_dev;
struct video_device *vbi_dev;
- struct video_device *radio_dev;
+
+ /* video capture */
+ struct cx23885_fmt *fmt;
+ unsigned int width, height;
+ unsigned field;
struct cx23885_dmaqueue vidq;
+ struct vb2_queue vb2_vidq;
struct cx23885_dmaqueue vbiq;
+ struct vb2_queue vb2_vbiq;
+
spinlock_t slock;
/* MPEG Encoder ONLY settings */
u32 cx23417_mailbox;
- struct cx2341x_mpeg_params mpeg_params;
+ struct cx2341x_handler cxhdl;
struct video_device *v4l_device;
- atomic_t v4l_reader_count;
+ struct vb2_queue vb2_mpegq;
struct cx23885_tvnorm encodernorm;
/* Analog raw audio */
@@ -521,26 +501,21 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
extern void cx23885_sram_channel_dump(struct cx23885_dev *dev,
struct sram_channel *ch);
-extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value);
-
-extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+extern int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc,
struct scatterlist *sglist,
unsigned int top_offset, unsigned int bottom_offset,
unsigned int bpl, unsigned int padding, unsigned int lines);
extern int cx23885_risc_vbibuffer(struct pci_dev *pci,
- struct btcx_riscmem *risc, struct scatterlist *sglist,
+ struct cx23885_riscmem *risc, struct scatterlist *sglist,
unsigned int top_offset, unsigned int bottom_offset,
unsigned int bpl, unsigned int padding, unsigned int lines);
+int cx23885_start_dma(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q,
+ struct cx23885_buffer *buf);
void cx23885_cancel_buffers(struct cx23885_tsport *port);
-extern int cx23885_restart_queue(struct cx23885_tsport *port,
- struct cx23885_dmaqueue *q);
-
-extern void cx23885_wakeup(struct cx23885_tsport *port,
- struct cx23885_dmaqueue *q, u32 count);
extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
@@ -574,13 +549,11 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
extern int cx23885_dvb_register(struct cx23885_tsport *port);
extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
-extern int cx23885_buf_prepare(struct videobuf_queue *q,
- struct cx23885_tsport *port,
- struct cx23885_buffer *buf,
- enum v4l2_field field);
+extern int cx23885_buf_prepare(struct cx23885_buffer *buf,
+ struct cx23885_tsport *port);
extern void cx23885_buf_queue(struct cx23885_tsport *port,
struct cx23885_buffer *buf);
-extern void cx23885_free_buffer(struct videobuf_queue *q,
+extern void cx23885_free_buffer(struct cx23885_dev *dev,
struct cx23885_buffer *buf);
/* ----------------------------------------------------------- */
@@ -595,8 +568,6 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i);
int cx23885_set_input(struct file *file, void *priv, unsigned int i);
int cx23885_get_input(struct file *file, void *priv, unsigned int *i);
int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f);
-int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
-int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl);
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
/* ----------------------------------------------------------- */
@@ -604,9 +575,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm);
extern int cx23885_vbi_fmt(struct file *file, void *priv,
struct v4l2_format *f);
extern void cx23885_vbi_timeout(unsigned long data);
-extern struct videobuf_queue_ops cx23885_vbi_qops;
-extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev,
- struct cx23885_dmaqueue *q);
+extern struct vb2_ops cx23885_vbi_qops;
extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status);
/* cx23885-i2c.c */
@@ -638,7 +607,7 @@ extern struct cx23885_audio_dev *cx23885_audio_register(
extern void cx23885_audio_unregister(struct cx23885_dev *dev);
extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask);
extern int cx23885_risc_databuffer(struct pci_dev *pci,
- struct btcx_riscmem *risc,
+ struct cx23885_riscmem *risc,
struct scatterlist *sglist,
unsigned int bpl,
unsigned int lines,
@@ -649,15 +618,10 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci,
static inline unsigned int norm_maxw(v4l2_std_id norm)
{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+ return (norm & V4L2_STD_525_60) ? 720 : 768;
}
static inline unsigned int norm_maxh(v4l2_std_id norm)
{
- return (norm & V4L2_STD_625_50) ? 576 : 480;
-}
-
-static inline unsigned int norm_swidth(v4l2_std_id norm)
-{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+ return (norm & V4L2_STD_525_60) ? 480 : 576;
}
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index c2ff5fc01157..c1aa888af705 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -14,11 +14,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#include <linux/kfifo.h>
diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h
index d2de41caaf1d..ff74a93575d6 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.h
+++ b/drivers/media/pci/cx23885/cx23888-ir.h
@@ -14,11 +14,6 @@
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
*/
#ifndef _CX23888_IR_H_
diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c
index 98a48f500684..b6542ee4385b 100644
--- a/drivers/media/pci/cx23885/netup-eeprom.c
+++ b/drivers/media/pci/cx23885/netup-eeprom.c
@@ -17,10 +17,6 @@
* 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.
*/
#
diff --git a/drivers/media/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h
index 13926e18feba..90cac5b655d5 100644
--- a/drivers/media/pci/cx23885/netup-eeprom.h
+++ b/drivers/media/pci/cx23885/netup-eeprom.h
@@ -16,10 +16,6 @@
* 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 NETUP_EEPROM_H
diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c
index 0044fef7ca24..76d9487aafc8 100644
--- a/drivers/media/pci/cx23885/netup-init.c
+++ b/drivers/media/pci/cx23885/netup-init.c
@@ -17,10 +17,6 @@
* 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 "cx23885.h"
diff --git a/drivers/media/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h
index d26ae4b1590e..daaa212adfba 100644
--- a/drivers/media/pci/cx23885/netup-init.h
+++ b/drivers/media/pci/cx23885/netup-init.h
@@ -17,9 +17,5 @@
* 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.
*/
extern void netup_initialize(struct cx23885_dev *dev);
diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c
index 1f43be0b04c8..a664997e1958 100644
--- a/drivers/media/pci/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c
@@ -330,8 +330,9 @@ int cx25821_write_frame(struct cx25821_channel *chan,
if (frame_size - curpos < count)
count = frame_size - curpos;
- memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos,
- data, count);
+ if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos,
+ data, count))
+ return -EFAULT;
curpos += count;
if (curpos == frame_size) {
out->_frame_count++;
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index e18a7ace08b1..851754bf1291 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -78,19 +78,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE2,
.vmux = 1,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE3,
.vmux = 2,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE4,
.vmux = 3,
- }},
+ } },
},
[CX88_BOARD_HAUPPAUGE] = {
.name = "Hauppauge WinTV 34xxx models",
@@ -99,23 +99,23 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xff00, // internal decoder
- },{
+ }, {
.type = CX88_VMUX_DEBUG,
.vmux = 0,
.gpio0 = 0xff01, // mono from tuner chip
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xff02,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xff02,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xff01,
@@ -127,13 +127,13 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- }},
+ } },
},
[CX88_BOARD_PIXELVIEW] = {
.name = "PixelView",
@@ -141,17 +141,17 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xff00, // internal decoder
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xff10,
@@ -164,19 +164,19 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x03ff,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x03fe,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x03fe,
- }},
+ } },
},
[CX88_BOARD_WINFAST2000XP_EXPERT] = {
.name = "Leadtek Winfast 2000XP Expert",
@@ -185,28 +185,28 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00F5e700,
.gpio1 = 0x00003004,
.gpio2 = 0x00F5e700,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00F5c700,
.gpio1 = 0x00003004,
.gpio2 = 0x00F5c700,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00F5c700,
.gpio1 = 0x00003004,
.gpio2 = 0x00F5c700,
.gpio3 = 0x02000000,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x00F5d700,
@@ -222,19 +222,19 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio1 = 0xe09f,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio1 = 0xe05f,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio1 = 0xe05f,
- }},
+ } },
.radio = {
.gpio1 = 0xe0df,
.type = CX88_RADIO,
@@ -249,25 +249,25 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000040bf,
.gpio1 = 0x000080c0,
.gpio2 = 0x0000ff40,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.vmux = 3,
@@ -283,14 +283,14 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0035e700,
.gpio1 = 0x00003004,
.gpio2 = 0x0035e700,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
@@ -298,14 +298,14 @@ static const struct cx88_board cx88_boards[] = {
.gpio1 = 0x00003004,
.gpio2 = 0x0035c700,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0035c700,
.gpio1 = 0x0035c700,
.gpio2 = 0x02000000,
.gpio3 = 0x02000000,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x0035d700,
@@ -322,22 +322,22 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000bde2,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0000bde6,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000bde6,
.audioroute = 1,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x0000bd62,
@@ -351,16 +351,16 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE2,
.vmux = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- }},
+ } },
},
[CX88_BOARD_PROLINK_PLAYTVPVR] = {
.name = "Prolink PlayTV PVR",
@@ -369,19 +369,19 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xbff0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xbff3,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xbff3,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xbff0,
@@ -394,16 +394,16 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000fde6,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
.audioroute = 1,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x0000fde2,
@@ -417,22 +417,22 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc08,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc68,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00000fbf,
.gpio2 = 0x0000fc68,
- }},
+ } },
},
[CX88_BOARD_KWORLD_DVB_T] = {
.name = "KWorld/VStream XPert DVB-T",
@@ -440,17 +440,17 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
@@ -459,15 +459,15 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_LTV883] = {
@@ -476,23 +476,23 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x07f8,
- },{
+ }, {
.type = CX88_VMUX_DEBUG,
.vmux = 0,
.gpio0 = 0x07f9, // mono from tuner chip
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000007fa,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000007fa,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x000007f8,
@@ -521,23 +521,23 @@ static const struct cx88_board cx88_boards[] = {
0 - normal RF
1 - high RF
*/
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0f0d,
- },{
+ }, {
.type = CX88_VMUX_CABLE,
.vmux = 0,
.gpio0 = 0x0f05,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0f00,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0f00,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
@@ -546,10 +546,10 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_CONEXANT_DVB_T1] = {
@@ -558,10 +558,10 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PROVIDEO_PV259] = {
@@ -570,11 +570,11 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.audioroute = 1,
- }},
+ } },
.mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
@@ -583,15 +583,15 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DNTV_LIVE_DVB_T] = {
@@ -600,17 +600,17 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00000700,
.gpio2 = 0x00000101,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00000700,
.gpio2 = 0x00000101,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PCHDTV_HD3000] = {
@@ -632,19 +632,19 @@ static const struct cx88_board cx88_boards[] = {
*
* GPIO[16] = Remote control input
*/
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00008484,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00008400,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00008400,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x00008404,
@@ -659,25 +659,25 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xed1a,
.gpio2 = 0x00ff,
- },{
+ }, {
.type = CX88_VMUX_DEBUG,
.vmux = 0,
.gpio0 = 0xff01,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xff02,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xed92,
.gpio2 = 0x00ff,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xed96,
@@ -692,22 +692,22 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00009d80,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00009d76,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00009d76,
.audioroute = 1,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x00009d00,
@@ -722,19 +722,19 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 1,
.gpio1 = 0x0000e03f,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 2,
.gpio1 = 0x0000e07f,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 3,
.gpio1 = 0x0000e07f,
- }}
+ } }
},
[CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
.name = "PixelView PlayTV Ultra Pro (Stereo)",
@@ -745,19 +745,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
/* Some variants use a tda9874 and so need the tvaudio module. */
.audio_chip = CX88_AUDIO_TVAUDIO,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xbf61, /* internal decoder */
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xbf63,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xbf63,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xbf60,
@@ -770,19 +770,19 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x97ed,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x97e9,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x97e9,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_ADSTECH_DVB_T_PCI] = {
@@ -791,32 +791,32 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
.name = "TerraTec Cinergy 1400 DVB-T",
.tuner_type = TUNER_ABSENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 2,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
@@ -826,19 +826,19 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x87fd,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x87f9,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x87f9,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
@@ -848,22 +848,22 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 0,
.gpio0 = 0x0000cd73,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 1,
.gpio0 = 0x0000cd73,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_TELEVISION,
.vmux = 3,
.gpio0 = 0x0000cdb3,
.audioroute = 1,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.vmux = 2,
@@ -876,21 +876,21 @@ static const struct cx88_board cx88_boards[] = {
/* Alexander Wold <awold@bigfoot.com> */
.name = "Kworld V-Stream Xpert DVD",
.tuner_type = UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x03000000,
.gpio1 = 0x01000000,
.gpio2 = 0x02000000,
.gpio3 = 0x00100000,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x03000000,
.gpio1 = 0x01000000,
.gpio2 = 0x02000000,
.gpio3 = 0x00100000,
- }},
+ } },
},
[CX88_BOARD_ATI_HDTVWONDER] = {
.name = "ATI HDTV Wonder",
@@ -898,28 +898,28 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00000ff7,
.gpio1 = 0x000000ff,
.gpio2 = 0x00000001,
.gpio3 = 0x00000000,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00000ffe,
.gpio1 = 0x000000ff,
.gpio2 = 0x00000001,
.gpio3 = 0x00000000,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00000ffe,
.gpio1 = 0x000000ff,
.gpio2 = 0x00000001,
.gpio3 = 0x00000000,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_WINFAST_DTV1000] = {
@@ -928,16 +928,16 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_AVERTV_303] = {
@@ -947,28 +947,28 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00ff,
.gpio1 = 0xe09f,
.gpio2 = 0x0010,
.gpio3 = 0x0000,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00ff,
.gpio1 = 0xe05f,
.gpio2 = 0x0010,
.gpio3 = 0x0000,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00ff,
.gpio1 = 0xe05f,
.gpio2 = 0x0010,
.gpio3 = 0x0000,
- }},
+ } },
},
[CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
.name = "Hauppauge Nova-S-Plus DVB-S",
@@ -978,22 +978,22 @@ static const struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.audio_chip = CX88_AUDIO_WM8775,
.i2sinputcntl = 2,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
/* 2: Line-In */
.audioroute = 2,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
/* 2: Line-In */
.audioroute = 2,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
/* 2: Line-In */
.audioroute = 2,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
@@ -1002,10 +1002,10 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_DVBS_100] = {
@@ -1015,22 +1015,22 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_chip = CX88_AUDIO_WM8775,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
/* 2: Line-In */
.audioroute = 2,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
/* 2: Line-In */
.audioroute = 2,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
/* 2: Line-In */
.audioroute = 2,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_HVR1100] = {
@@ -1040,16 +1040,16 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- }},
+ } },
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB,
},
@@ -1060,13 +1060,13 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- }},
+ } },
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB,
},
@@ -1078,19 +1078,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
TDA9887_PORT2_ACTIVE,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xf80808,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xf80808,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xf80808,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xf80808,
@@ -1106,17 +1106,17 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0700,
.gpio2 = 0x0101,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
@@ -1125,15 +1125,15 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000067df,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000067df,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
@@ -1142,22 +1142,22 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x3de2,
.gpio2 = 0x00ff,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x3de6,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x3de6,
.audioroute = 1,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x3de6,
@@ -1171,19 +1171,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000a75f,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x0000a75b,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x0000a75b,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PCHDTV_HD5500] = {
@@ -1193,19 +1193,19 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x87fd,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x87f9,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x87f9,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_MCE200_DELUXE] = {
@@ -1217,11 +1217,11 @@ static const struct cx88_board cx88_boards[] = {
.tda9887_conf = TDA9887_PRESENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0000BDE6
- }},
+ } },
.mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
@@ -1233,11 +1233,11 @@ static const struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
TDA9887_PORT2_ACTIVE,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x5da6,
- }},
+ } },
.mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
@@ -1246,19 +1246,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0788,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x078b,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x078b,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x074a,
@@ -1271,7 +1271,7 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00017304,
@@ -1299,7 +1299,7 @@ static const struct cx88_board cx88_boards[] = {
.gpio1 = 0x0000b207,
.gpio2 = 0x0001d701,
.gpio3 = 0x02000000,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x00015702,
@@ -1316,35 +1316,35 @@ static const struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00017300,
.gpio1 = 0x00008207,
.gpio2 = 0x00000000,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00018300,
.gpio1 = 0x0000f207,
.gpio2 = 0x00017304,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00018301,
.gpio1 = 0x0000f207,
.gpio2 = 0x00017304,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00018301,
.gpio1 = 0x0000f207,
.gpio2 = 0x00017304,
.gpio3 = 0x02000000,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x00015702,
@@ -1360,13 +1360,13 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_HVR3000] = {
@@ -1377,25 +1377,25 @@ static const struct cx88_board cx88_boards[] = {
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.audio_chip = CX88_AUDIO_WM8775,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x84bf,
/* 1: TV Audio / FM Mono */
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x84bf,
/* 2: Line-In */
.audioroute = 2,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x84bf,
/* 2: Line-In */
.audioroute = 2,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x84bf,
@@ -1411,19 +1411,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0709,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x070b,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x070b,
- }},
+ } },
},
[CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
.name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
@@ -1431,28 +1431,28 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x003fffff,
.gpio1 = 0x00e00000,
.gpio2 = 0x003fffff,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x003fffff,
.gpio1 = 0x00e00000,
.gpio2 = 0x003fffff,
.gpio3 = 0x02000000,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x003fffff,
.gpio1 = 0x00e00000,
.gpio2 = 0x003fffff,
.gpio3 = 0x02000000,
- }},
+ } },
},
[CX88_BOARD_HAUPPAUGE_HVR1300] = {
.name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
@@ -1465,25 +1465,25 @@ static const struct cx88_board cx88_boards[] = {
/*
* gpio0 as reported by Mike Crash <mike AT mikecrash.com>
*/
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xef88,
/* 1: TV Audio / FM Mono */
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0xef88,
/* 2: Line-In */
.audioroute = 2,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0xef88,
/* 2: Line-In */
.audioroute = 2,
- }},
+ } },
.mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
.radio = {
.type = CX88_RADIO,
@@ -1510,19 +1510,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DEBUG,
.vmux = 3,
.gpio0 = 0x04ff,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x07fa,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x07fa,
- }},
+ } },
},
[CX88_BOARD_PINNACLE_PCTV_HD_800i] = {
.name = "Pinnacle PCTV HD 800i",
@@ -1530,24 +1530,24 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x04fb,
.gpio1 = 0x10ff,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x04fb,
.gpio1 = 0x10ef,
.audioroute = 1,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x04fb,
.gpio1 = 0x10ef,
.audioroute = 1,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
@@ -1557,7 +1557,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x000027df, /* Unconfirmed */
@@ -1815,19 +1815,19 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x10df,
- },{
+ }, {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x16d9,
- },{
+ }, {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x16d9,
- }},
+ } },
.mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PROLINK_PV_8000GT] = {
@@ -1967,7 +1967,7 @@ static const struct cx88_board cx88_boards[] = {
* 3: Line-In Expansion
* 4: FM Stereo
*/
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0xc4bf,
@@ -2001,7 +2001,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2013,7 +2013,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2025,7 +2025,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2037,7 +2037,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2049,7 +2049,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2061,7 +2061,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2073,7 +2073,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
.gpio0 = 0x8080,
@@ -2086,7 +2086,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2098,7 +2098,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2110,7 +2110,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2170,7 +2170,7 @@ static const struct cx88_board cx88_boards[] = {
* 13: audio source (0=tuner audio,1=line in)
* 14: FM (0=on,1=off ???)
*/
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0400, /* pin 2 = 0 */
@@ -2211,7 +2211,7 @@ static const struct cx88_board cx88_boards[] = {
* 13: audio source (0=tuner audio,1=line in)
* 14: FM (0=on,1=off ???)
*/
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0400, /* pin 2 = 0 */
@@ -2229,7 +2229,7 @@ static const struct cx88_board cx88_boards[] = {
.gpio0 = 0x0400, /* pin 2 = 0 */
.gpio1 = 0x6060, /* pin 13 = 1, pin 14 = 1 */
.gpio2 = 0x0000,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x0400, /* pin 2 = 0 */
@@ -2252,7 +2252,7 @@ static const struct cx88_board cx88_boards[] = {
* 14: 0: FM radio
* 16: 0: RF input is cable
*/
- .input = {{
+ .input = { {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x0403,
@@ -2280,7 +2280,7 @@ static const struct cx88_board cx88_boards[] = {
.gpio1 = 0xF0F7,
.gpio2 = 0x0101,
.gpio3 = 0x0000,
- }},
+ } },
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x0403,
@@ -2308,7 +2308,7 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .input = {{
+ .input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
} },
@@ -2324,19 +2324,19 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x3400,
.card = CX88_BOARD_HAUPPAUGE,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x3401,
.card = CX88_BOARD_HAUPPAUGE,
- },{
+ }, {
.subvendor = 0x14c7,
.subdevice = 0x0106,
.card = CX88_BOARD_GDI,
- },{
+ }, {
.subvendor = 0x14c7,
.subdevice = 0x0107, /* with mpeg encoder */
.card = CX88_BOARD_GDI,
- },{
+ }, {
.subvendor = PCI_VENDOR_ID_ATI,
.subdevice = 0x00f8,
.card = CX88_BOARD_ATI_WONDER_PRO,
@@ -2348,176 +2348,176 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0x107d,
.subdevice = 0x6611,
.card = CX88_BOARD_WINFAST2000XP_EXPERT,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x6613, /* NTSC */
.card = CX88_BOARD_WINFAST2000XP_EXPERT,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x6620,
.card = CX88_BOARD_WINFAST_DV2000,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x663b,
.card = CX88_BOARD_LEADTEK_PVR2000,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x663c,
.card = CX88_BOARD_LEADTEK_PVR2000,
- },{
+ }, {
.subvendor = 0x1461,
.subdevice = 0x000b,
.card = CX88_BOARD_AVERTV_STUDIO_303,
- },{
+ }, {
.subvendor = 0x1462,
.subdevice = 0x8606,
.card = CX88_BOARD_MSI_TVANYWHERE_MASTER,
- },{
+ }, {
.subvendor = 0x10fc,
.subdevice = 0xd003,
.card = CX88_BOARD_IODATA_GVVCP3PCI,
- },{
+ }, {
.subvendor = 0x1043,
.subdevice = 0x4823, /* with mpeg encoder */
.card = CX88_BOARD_ASUS_PVR_416,
- },{
+ }, {
.subvendor = 0x17de,
.subdevice = 0x08a6,
.card = CX88_BOARD_KWORLD_DVB_T,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xd810,
.card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xd820,
.card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb00,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9002,
.card = CX88_BOARD_HAUPPAUGE_DVB_T1,
- },{
+ }, {
.subvendor = 0x14f1,
.subdevice = 0x0187,
.card = CX88_BOARD_CONEXANT_DVB_T1,
- },{
+ }, {
.subvendor = 0x1540,
.subdevice = 0x2580,
.card = CX88_BOARD_PROVIDEO_PV259,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb10,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
- },{
+ }, {
.subvendor = 0x1554,
.subdevice = 0x4811,
.card = CX88_BOARD_PIXELVIEW,
- },{
+ }, {
.subvendor = 0x7063,
.subdevice = 0x3000, /* HD-3000 card */
.card = CX88_BOARD_PCHDTV_HD3000,
- },{
+ }, {
.subvendor = 0x17de,
.subdevice = 0xa8a6,
.card = CX88_BOARD_DNTV_LIVE_DVB_T,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x2801,
.card = CX88_BOARD_HAUPPAUGE_ROSLYN,
- },{
+ }, {
.subvendor = 0x14f1,
.subdevice = 0x0342,
.card = CX88_BOARD_DIGITALLOGIC_MEC,
- },{
+ }, {
.subvendor = 0x10fc,
.subdevice = 0xd035,
.card = CX88_BOARD_IODATA_GVBCTV7E,
- },{
+ }, {
.subvendor = 0x1421,
.subdevice = 0x0334,
.card = CX88_BOARD_ADSTECH_DVB_T_PCI,
- },{
+ }, {
.subvendor = 0x153b,
.subdevice = 0x1166,
.card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xd500,
.card = CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD,
- },{
+ }, {
.subvendor = 0x1461,
.subdevice = 0x8011,
.card = CX88_BOARD_AVERMEDIA_ULTRATV_MC_550,
- },{
+ }, {
.subvendor = PCI_VENDOR_ID_ATI,
.subdevice = 0xa101,
.card = CX88_BOARD_ATI_HDTVWONDER,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x665f,
.card = CX88_BOARD_WINFAST_DTV1000,
- },{
+ }, {
.subvendor = 0x1461,
.subdevice = 0x000a,
.card = CX88_BOARD_AVERTV_303,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9200,
.card = CX88_BOARD_HAUPPAUGE_NOVASE2_S1,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9201,
.card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9202,
.card = CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1,
- },{
+ }, {
.subvendor = 0x17de,
.subdevice = 0x08b2,
.card = CX88_BOARD_KWORLD_DVBS_100,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9400,
.card = CX88_BOARD_HAUPPAUGE_HVR1100,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9402,
.card = CX88_BOARD_HAUPPAUGE_HVR1100,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9800,
.card = CX88_BOARD_HAUPPAUGE_HVR1100LP,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9802,
.card = CX88_BOARD_HAUPPAUGE_HVR1100LP,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9001,
.card = CX88_BOARD_HAUPPAUGE_DVB_T1,
- },{
+ }, {
.subvendor = 0x1822,
.subdevice = 0x0025,
.card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
- },{
+ }, {
.subvendor = 0x17de,
.subdevice = 0x08a1,
.card = CX88_BOARD_KWORLD_DVB_T_CX22702,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb50,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb54,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL,
/* Re-branded DViCO: DigitalNow DVB-T Dual */
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb11,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
@@ -2530,55 +2530,55 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0x17de,
.subdevice = 0x0840,
.card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
- },{
+ }, {
.subvendor = 0x1421,
.subdevice = 0x0305,
.card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb40,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xdb44,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
- },{
+ }, {
.subvendor = 0x7063,
.subdevice = 0x5500,
.card = CX88_BOARD_PCHDTV_HD5500,
- },{
+ }, {
.subvendor = 0x17de,
.subdevice = 0x0841,
.card = CX88_BOARD_KWORLD_MCE200_DELUXE,
- },{
+ }, {
.subvendor = 0x1822,
.subdevice = 0x0019,
.card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
- },{
+ }, {
.subvendor = 0x1554,
.subdevice = 0x4813,
.card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
- },{
+ }, {
.subvendor = 0x14f1,
.subdevice = 0x0842,
.card = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x665e,
.card = CX88_BOARD_WINFAST_DTV2000H,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x6f2b,
.card = CX88_BOARD_WINFAST_DTV2000H_J,
- },{
+ }, {
.subvendor = 0x18ac,
.subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
.card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
- },{
+ }, {
.subvendor = 0x14f1,
.subdevice = 0x0084,
.card = CX88_BOARD_GENIATECH_DVBS,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x1404,
.card = CX88_BOARD_HAUPPAUGE_HVR3000,
@@ -2590,60 +2590,60 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0x18ac,
.subdevice = 0xdccd,
.card = CX88_BOARD_SAMSUNG_SMT_7020,
- },{
+ }, {
.subvendor = 0x1461,
.subdevice = 0xc111, /* AverMedia M150-D */
/* This board is known to work with the ASUS PVR416 config */
.card = CX88_BOARD_ASUS_PVR_416,
- },{
+ }, {
.subvendor = 0xc180,
.subdevice = 0xc980,
.card = CX88_BOARD_TE_DTV_250_OEM_SWANN,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9600,
.card = CX88_BOARD_HAUPPAUGE_HVR1300,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9601,
.card = CX88_BOARD_HAUPPAUGE_HVR1300,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9602,
.card = CX88_BOARD_HAUPPAUGE_HVR1300,
- },{
+ }, {
.subvendor = 0x107d,
.subdevice = 0x6632,
.card = CX88_BOARD_LEADTEK_PVR2000,
- },{
+ }, {
.subvendor = 0x12ab,
.subdevice = 0x2300, /* Club3D Zap TV2100 */
.card = CX88_BOARD_KWORLD_DVB_T_CX22702,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x9000,
.card = CX88_BOARD_HAUPPAUGE_DVB_T1,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x1400,
.card = CX88_BOARD_HAUPPAUGE_HVR3000,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x1401,
.card = CX88_BOARD_HAUPPAUGE_HVR3000,
- },{
+ }, {
.subvendor = 0x0070,
.subdevice = 0x1402,
.card = CX88_BOARD_HAUPPAUGE_HVR3000,
- },{
+ }, {
.subvendor = 0x1421,
.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
.card = CX88_BOARD_KWORLD_DVBS_100,
- },{
+ }, {
.subvendor = 0x1421,
.subdevice = 0x0390,
.card = CX88_BOARD_ADSTECH_PTV_390,
- },{
+ }, {
.subvendor = 0x11bd,
.subdevice = 0x0051,
.card = CX88_BOARD_PINNACLE_PCTV_HD_800i,
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index ed8cb9037b6f..ce27e6d4f16e 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -696,7 +696,6 @@ static struct videobuf_queue *get_queue(struct file *file)
return &fh->vbiq;
default:
BUG();
- return NULL;
}
}
@@ -711,7 +710,6 @@ static int get_resource(struct file *file)
return RESOURCE_VBI;
default:
BUG();
- return 0;
}
}
@@ -812,7 +810,6 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
file->f_flags & O_NONBLOCK);
default:
BUG();
- return 0;
}
}
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index da8f848be3b8..c82e855a0814 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -149,7 +149,7 @@ static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-struct i2c_algorithm ddb_i2c_algo = {
+static struct i2c_algorithm ddb_i2c_algo = {
.master_xfer = ddb_i2c_master_xfer,
.functionality = ddb_i2c_functionality,
};
@@ -266,7 +266,7 @@ static void io_free(struct pci_dev *pdev, u8 **vbuf,
for (i = 0; i < num; i++) {
if (vbuf[i]) {
pci_free_consistent(pdev, size, vbuf[i], pbuf[i]);
- vbuf[i] = 0;
+ vbuf[i] = NULL;
}
}
}
@@ -440,7 +440,7 @@ static u32 ddb_output_free(struct ddb_output *output)
}
static ssize_t ddb_output_write(struct ddb_output *output,
- const u8 *buf, size_t count)
+ const __user u8 *buf, size_t count)
{
struct ddb *dev = output->port->dev;
u32 idx, off, stat = output->stat;
@@ -506,7 +506,7 @@ static u32 ddb_input_avail(struct ddb_input *input)
return 0;
}
-static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count)
+static ssize_t ddb_input_read(struct ddb_input *input, __user u8 *buf, size_t count)
{
struct ddb *dev = input->port->dev;
u32 left = count;
@@ -849,7 +849,7 @@ static int dvb_input_attach(struct ddb_input *input)
return ret;
input->attached = 4;
- input->fe = 0;
+ input->fe = NULL;
switch (port->type) {
case DDB_TUNER_DVBS_ST:
if (demod_attach_stv0900(input, 0) < 0)
@@ -895,7 +895,7 @@ static int dvb_input_attach(struct ddb_input *input)
/****************************************************************************/
/****************************************************************************/
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const __user char *buf,
size_t count, loff_t *ppos)
{
struct dvb_device *dvbdev = file->private_data;
@@ -920,7 +920,7 @@ static ssize_t ts_write(struct file *file, const char *buf,
return (left == count) ? -EAGAIN : (count - left);
}
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, __user char *buf,
size_t count, loff_t *ppos)
{
struct dvb_device *dvbdev = file->private_data;
@@ -975,11 +975,9 @@ static const struct file_operations ci_fops = {
.open = dvb_generic_open,
.release = dvb_generic_release,
.poll = ts_poll,
- .mmap = 0,
};
static struct dvb_device dvbdev_ci = {
- .priv = 0,
.readers = -1,
.writers = -1,
.users = -1,
@@ -1038,7 +1036,7 @@ static void output_tasklet(unsigned long data)
}
-struct cxd2099_cfg cxd_cfg = {
+static struct cxd2099_cfg cxd_cfg = {
.bitrate = 62000,
.adr = 0x40,
.polarity = 1,
@@ -1127,7 +1125,7 @@ static void ddb_ports_detach(struct ddb *dev)
ddb_output_stop(port->output);
dvb_ca_en50221_release(port->en);
kfree(port->en);
- port->en = 0;
+ port->en = NULL;
dvb_unregister_adapter(&port->output->adap);
}
break;
@@ -1413,9 +1411,9 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
#define DDB_MAGIC 'd'
struct ddb_flashio {
- __u8 *write_buf;
+ __user __u8 *write_buf;
__u32 write_len;
- __u8 *read_buf;
+ __user __u8 *read_buf;
__u32 read_len;
};
@@ -1439,7 +1437,7 @@ static int ddb_open(struct inode *inode, struct file *file)
static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ddb *dev = file->private_data;
- void *parg = (void *)arg;
+ __user void *parg = (__user void *)arg;
int res;
switch (cmd) {
@@ -1558,7 +1556,7 @@ static void ddb_remove(struct pci_dev *pdev)
ddb_device_destroy(dev);
ddb_unmap(dev);
- pci_set_drvdata(pdev, 0);
+ pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
@@ -1637,7 +1635,7 @@ fail1:
fail:
printk(KERN_ERR "fail\n");
ddb_unmap(dev);
- pci_set_drvdata(pdev, 0);
+ pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
return -1;
}
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 8b1b41d2a52d..be87fbd90456 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -156,7 +156,7 @@ struct ddb_port {
struct ddb {
struct pci_dev *pdev;
- unsigned char *regs;
+ unsigned char __iomem *regs;
struct ddb_port port[DDB_MAX_PORT];
struct ddb_i2c i2c[DDB_MAX_I2C];
struct ddb_input input[DDB_MAX_INPUT];
@@ -173,12 +173,10 @@ struct ddb {
/****************************************************************************/
#define ddbwritel(_val, _adr) writel((_val), \
- (char *) (dev->regs+(_adr)))
-#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr)))
-#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \
- (dev->regs+(_adr)), (_src), (_count))
-#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \
- (dev->regs+(_adr)), (_count))
+ dev->regs+(_adr))
+#define ddbreadl(_adr) readl(dev->regs+(_adr))
+#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count))
+#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count))
/****************************************************************************/
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index e8826c535ccd..ed11716731e9 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -614,7 +614,7 @@ static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
static void dm1105_set_dma_addr(struct dm1105_dev *dev)
{
- dm_writel(DM1105_STADR, cpu_to_le32(dev->dma_addr));
+ dm_writel(DM1105_STADR, (__force u32)cpu_to_le32(dev->dma_addr));
}
static int dm1105_dma_map(struct dm1105_dev *dev)
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
index 7a9b98bc208b..7bf9cbca4fa6 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
@@ -81,7 +81,7 @@ static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc,
int period_elapsed = 0;
int length;
- dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc,
+ dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zu\n", itvsc,
pcm_data, num_bytes);
substream = itvsc->capture_pcm_substream;
diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c
index ed73edd2bcd3..4b0e758a7bce 100644
--- a/drivers/media/pci/ivtv/ivtv-firmware.c
+++ b/drivers/media/pci/ivtv/ivtv-firmware.c
@@ -65,7 +65,7 @@ retry:
the wrong file was sometimes loaded. So we check filesizes to
see if at least the right-sized file was loaded. If not, then we
retry. */
- IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+ IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zu)\n", fn, size, fw->size);
release_firmware(fw);
retries--;
goto retry;
@@ -76,7 +76,7 @@ retry:
dst++;
src++;
}
- IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ IVTV_INFO("Loaded %s firmware (%zu bytes)\n", fn, fw->size);
release_firmware(fw);
return size;
}
diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c
index 19a7c9b990a3..ab6d5d25aa6f 100644
--- a/drivers/media/pci/ivtv/ivtv-irq.c
+++ b/drivers/media/pci/ivtv/ivtv-irq.c
@@ -192,11 +192,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
- write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
+ write_dec_sync(DMA_MAGIC_COOKIE, offset - IVTV_DECODER_OFFSET);
}
else {
s->pending_backup = read_enc(offset);
- write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
+ write_enc_sync(DMA_MAGIC_COOKIE, offset);
}
s->pending_offset = offset;
}
@@ -275,13 +275,11 @@ static void dma_post(struct ivtv_stream *s)
if (x == 0 && ivtv_use_dma(s)) {
offset = s->dma_last_offset;
- if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
+ if (le32_to_cpu(u32buf[offset / 4]) != DMA_MAGIC_COOKIE)
{
- for (offset = 0; offset < 64; offset++) {
- if (u32buf[offset] == DMA_MAGIC_COOKIE) {
+ for (offset = 0; offset < 64; offset++)
+ if (le32_to_cpu(u32buf[offset]) == DMA_MAGIC_COOKIE)
break;
- }
- }
offset *= 4;
if (offset == 256) {
IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name);
diff --git a/drivers/media/pci/mantis/hopper_vp3028.c b/drivers/media/pci/mantis/hopper_vp3028.c
index 68a29f8bdf73..1032db6bb789 100644
--- a/drivers/media/pci/mantis/hopper_vp3028.c
+++ b/drivers/media/pci/mantis/hopper_vp3028.c
@@ -34,7 +34,7 @@
#include "mantis_dvb.h"
#include "hopper_vp3028.h"
-struct zl10353_config hopper_vp3028_config = {
+static struct zl10353_config hopper_vp3028_config = {
.demod_address = 0x0f,
};
diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h
index f2410cf0a6bf..8ff448bb792d 100644
--- a/drivers/media/pci/mantis/mantis_common.h
+++ b/drivers/media/pci/mantis/mantis_common.h
@@ -127,7 +127,7 @@ struct mantis_pci {
u32 last_block;
u8 *buf_cpu;
dma_addr_t buf_dma;
- u32 *risc_cpu;
+ __le32 *risc_cpu;
dma_addr_t risc_dma;
struct tasklet_struct tasklet;
diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c
index 115003e8d19d..12a6adb2bd7e 100644
--- a/drivers/media/pci/mantis/mantis_vp1033.c
+++ b/drivers/media/pci/mantis/mantis_vp1033.c
@@ -35,7 +35,7 @@
#include "mantis_vp1033.h"
#include "mantis_reg.h"
-u8 lgtdqcs001f_inittab[] = {
+static u8 lgtdqcs001f_inittab[] = {
0x01, 0x15,
0x02, 0x30,
0x03, 0x00,
@@ -150,7 +150,7 @@ static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
return 0;
}
-struct stv0299_config lgtdqcs001f_config = {
+static struct stv0299_config lgtdqcs001f_config = {
.demod_address = 0x68,
.inittab = lgtdqcs001f_inittab,
.mclk = 88000000UL,
diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c
index 430ae84ce528..7c1bd167225c 100644
--- a/drivers/media/pci/mantis/mantis_vp1034.c
+++ b/drivers/media/pci/mantis/mantis_vp1034.c
@@ -36,7 +36,7 @@
#include "mantis_vp1034.h"
#include "mantis_reg.h"
-struct mb86a16_config vp1034_mb86a16_config = {
+static struct mb86a16_config vp1034_mb86a16_config = {
.demod_address = 0x08,
.set_voltage = vp1034_set_voltage,
};
diff --git a/drivers/media/pci/mantis/mantis_vp1041.c b/drivers/media/pci/mantis/mantis_vp1041.c
index 07a20748b707..7082fcbc94a1 100644
--- a/drivers/media/pci/mantis/mantis_vp1041.c
+++ b/drivers/media/pci/mantis/mantis_vp1041.c
@@ -263,7 +263,7 @@ static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = {
{ 0xffff , 0xff },
};
-struct stb0899_config vp1041_stb0899_config = {
+static struct stb0899_config vp1041_stb0899_config = {
.init_dev = vp1041_stb0899_s1_init_1,
.init_s2_demod = stb0899_s2_init_2,
.init_s1_demod = vp1041_stb0899_s1_init_3,
@@ -300,7 +300,7 @@ struct stb0899_config vp1041_stb0899_config = {
.tuner_set_rfsiggain = NULL,
};
-struct stb6100_config vp1041_stb6100_config = {
+static struct stb6100_config vp1041_stb6100_config = {
.tuner_address = 0x60,
.refclock = 27000000,
};
diff --git a/drivers/media/pci/mantis/mantis_vp2033.c b/drivers/media/pci/mantis/mantis_vp2033.c
index 1ca6837fbe46..8d48b5abe04a 100644
--- a/drivers/media/pci/mantis/mantis_vp2033.c
+++ b/drivers/media/pci/mantis/mantis_vp2033.c
@@ -37,12 +37,12 @@
#define MANTIS_MODEL_NAME "VP-2033"
#define MANTIS_DEV_TYPE "DVB-C"
-struct tda1002x_config vp2033_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2033_tda1002x_cu1216_config = {
.demod_address = 0x18 >> 1,
.invert = 1,
};
-struct tda10023_config vp2033_tda10023_cu1216_config = {
+static struct tda10023_config vp2033_tda10023_cu1216_config = {
.demod_address = 0x18 >> 1,
.invert = 1,
};
diff --git a/drivers/media/pci/mantis/mantis_vp2040.c b/drivers/media/pci/mantis/mantis_vp2040.c
index d480741afd78..8dd17d7c0881 100644
--- a/drivers/media/pci/mantis/mantis_vp2040.c
+++ b/drivers/media/pci/mantis/mantis_vp2040.c
@@ -37,12 +37,12 @@
#define MANTIS_MODEL_NAME "VP-2040"
#define MANTIS_DEV_TYPE "DVB-C"
-struct tda1002x_config vp2040_tda1002x_cu1216_config = {
+static struct tda1002x_config vp2040_tda1002x_cu1216_config = {
.demod_address = 0x18 >> 1,
.invert = 1,
};
-struct tda10023_config vp2040_tda10023_cu1216_config = {
+static struct tda10023_config vp2040_tda10023_cu1216_config = {
.demod_address = 0x18 >> 1,
.invert = 1,
};
diff --git a/drivers/media/pci/mantis/mantis_vp3030.c b/drivers/media/pci/mantis/mantis_vp3030.c
index c09308cd3ac6..5c1dd925bdd5 100644
--- a/drivers/media/pci/mantis/mantis_vp3030.c
+++ b/drivers/media/pci/mantis/mantis_vp3030.c
@@ -35,11 +35,11 @@
#include "mantis_dvb.h"
#include "mantis_vp3030.h"
-struct zl10353_config mantis_vp3030_config = {
+static struct zl10353_config mantis_vp3030_config = {
.demod_address = 0x0f,
};
-struct tda665x_config env57h12d5_config = {
+static struct tda665x_config env57h12d5_config = {
.name = "ENV57H12D5 (ET-50DT)",
.addr = 0x60,
.frequency_min = 47000000,
diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c
index 9e82d2105d53..039bed3cc919 100644
--- a/drivers/media/pci/ngene/ngene-cards.c
+++ b/drivers/media/pci/ngene/ngene-cards.c
@@ -696,7 +696,7 @@ static struct ngene_info ngene_info_m780 = {
.demod_attach = { NULL, demod_attach_lg330x },
/* Ensure these are NULL else the frame will call them (as funcs) */
- .tuner_attach = { 0, 0, 0, 0 },
+ .tuner_attach = { NULL, NULL, NULL, NULL },
.fe_config = { NULL, &aver_m780 },
.avf = { 0 },
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 4930b55fd5f4..e29bc3af4baf 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -57,15 +57,13 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define dprintk if (debug) printk
-#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
-#define ngwritel(dat, adr) writel((dat), (char *)(dev->iomem + (adr)))
-#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
+#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr))
+#define ngwritel(dat, adr) writel((dat), dev->iomem + (adr))
+#define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr))
#define ngreadl(adr) readl(dev->iomem + (adr))
#define ngreadb(adr) readb(dev->iomem + (adr))
-#define ngcpyto(adr, src, count) memcpy_toio((char *) \
- (dev->iomem + (adr)), (src), (count))
-#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), (char *) \
- (dev->iomem + (adr)), (count))
+#define ngcpyto(adr, src, count) memcpy_toio(dev->iomem + (adr), (src), (count))
+#define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), dev->iomem + (adr), (count))
/****************************************************************************/
/* nGene interrupt handler **************************************************/
@@ -1592,7 +1590,7 @@ static void cxd_detach(struct ngene *dev)
dvb_ca_en50221_release(ci->en);
kfree(ci->en);
- ci->en = 0;
+ ci->en = NULL;
}
/***********************************/
diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c
index fcb16a615aab..59bb2858c8d0 100644
--- a/drivers/media/pci/ngene/ngene-dvb.c
+++ b/drivers/media/pci/ngene/ngene-dvb.c
@@ -47,7 +47,7 @@
/* COMMAND API interface ****************************************************/
/****************************************************************************/
-static ssize_t ts_write(struct file *file, const char *buf,
+static ssize_t ts_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct dvb_device *dvbdev = file->private_data;
@@ -59,12 +59,12 @@ static ssize_t ts_write(struct file *file, const char *buf,
(&dev->tsout_rbuf) >= count) < 0)
return 0;
- dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count);
+ dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
return count;
}
-static ssize_t ts_read(struct file *file, char *buf,
+static ssize_t ts_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct dvb_device *dvbdev = file->private_data;
@@ -97,7 +97,6 @@ static const struct file_operations ci_fops = {
};
struct dvb_device ngene_dvbdev_ci = {
- .priv = 0,
.readers = -1,
.writers = -1,
.users = -1,
diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
index 22c39ff6bfa0..51e2fbd18b1b 100644
--- a/drivers/media/pci/ngene/ngene.h
+++ b/drivers/media/pci/ngene/ngene.h
@@ -737,7 +737,7 @@ typedef void (tx_cb_t)(struct ngene *, u32);
struct ngene {
int nr;
struct pci_dev *pci_dev;
- unsigned char *iomem;
+ unsigned char __iomem *iomem;
/*struct i2c_adapter i2c_adapter;*/
diff --git a/drivers/media/pci/pt3/Kconfig b/drivers/media/pci/pt3/Kconfig
new file mode 100644
index 000000000000..16c208ae0079
--- /dev/null
+++ b/drivers/media/pci/pt3/Kconfig
@@ -0,0 +1,10 @@
+config DVB_PT3
+ tristate "Earthsoft PT3 cards"
+ depends on DVB_CORE && PCI && I2C
+ select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL301RF if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for Earthsoft PT3 PCIe cards.
+
+ Say Y or M if you own such a device and want to use it.
diff --git a/drivers/media/pci/pt3/Makefile b/drivers/media/pci/pt3/Makefile
new file mode 100644
index 000000000000..396f146b1c18
--- /dev/null
+++ b/drivers/media/pci/pt3/Makefile
@@ -0,0 +1,8 @@
+
+earth-pt3-objs += pt3.o pt3_i2c.o pt3_dma.o
+
+obj-$(CONFIG_DVB_PT3) += earth-pt3.o
+
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
new file mode 100644
index 000000000000..1fdeac11501a
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3.c
@@ -0,0 +1,876 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * 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 version 2.
+ *
+ *
+ * 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.
+ */
+
+#include <linux/freezer.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
+#include "pt3.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static bool one_adapter;
+module_param(one_adapter, bool, 0444);
+MODULE_PARM_DESC(one_adapter, "Place FE's together under one adapter.");
+
+static int num_bufs = 4;
+module_param(num_bufs, int, 0444);
+MODULE_PARM_DESC(num_bufs, "Number of DMA buffer (188KiB) per FE.");
+
+
+static const struct i2c_algorithm pt3_i2c_algo = {
+ .master_xfer = &pt3_i2c_master_xfer,
+ .functionality = &pt3_i2c_functionality,
+};
+
+static const struct pt3_adap_config adap_conf[PT3_NUM_FE] = {
+ {
+ .demod_info = {
+ I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x11),
+ },
+ .tuner_info = {
+ I2C_BOARD_INFO("qm1d1c0042", 0x63),
+ },
+ .tuner_cfg.qm1d1c0042 = {
+ .lpf = 1,
+ },
+ .init_freq = 1049480 - 300,
+ },
+ {
+ .demod_info = {
+ I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x10),
+ },
+ .tuner_info = {
+ I2C_BOARD_INFO("mxl301rf", 0x62),
+ },
+ .init_freq = 515142857,
+ },
+ {
+ .demod_info = {
+ I2C_BOARD_INFO(TC90522_I2C_DEV_SAT, 0x13),
+ },
+ .tuner_info = {
+ I2C_BOARD_INFO("qm1d1c0042", 0x60),
+ },
+ .tuner_cfg.qm1d1c0042 = {
+ .lpf = 1,
+ },
+ .init_freq = 1049480 + 300,
+ },
+ {
+ .demod_info = {
+ I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x12),
+ },
+ .tuner_info = {
+ I2C_BOARD_INFO("mxl301rf", 0x61),
+ },
+ .init_freq = 521142857,
+ },
+};
+
+
+struct reg_val {
+ u8 reg;
+ u8 val;
+};
+
+static int
+pt3_demod_write(struct pt3_adapter *adap, const struct reg_val *data, int num)
+{
+ struct i2c_msg msg;
+ int i, ret;
+
+ ret = 0;
+ msg.addr = adap->i2c_demod->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ for (i = 0; i < num; i++) {
+ msg.buf = (u8 *)&data[i];
+ ret = i2c_transfer(adap->i2c_demod->adapter, &msg, 1);
+ if (ret == 0)
+ ret = -EREMOTE;
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static inline void pt3_lnb_ctrl(struct pt3_board *pt3, bool on)
+{
+ iowrite32((on ? 0x0f : 0x0c), pt3->regs[0] + REG_SYSTEM_W);
+}
+
+static inline struct pt3_adapter *pt3_find_adapter(struct dvb_frontend *fe)
+{
+ struct pt3_board *pt3;
+ int i;
+
+ if (one_adapter) {
+ pt3 = fe->dvb->priv;
+ for (i = 0; i < PT3_NUM_FE; i++)
+ if (pt3->adaps[i]->fe == fe)
+ return pt3->adaps[i];
+ }
+ return container_of(fe->dvb, struct pt3_adapter, dvb_adap);
+}
+
+/*
+ * all 4 tuners in PT3 are packaged in a can module (Sharp VA4M6JC2103).
+ * it seems that they share the power lines and Amp power line and
+ * adaps[3] controls those powers.
+ */
+static int
+pt3_set_tuner_power(struct pt3_board *pt3, bool tuner_on, bool amp_on)
+{
+ struct reg_val rv = { 0x1e, 0x99 };
+
+ if (tuner_on)
+ rv.val |= 0x40;
+ if (amp_on)
+ rv.val |= 0x04;
+ return pt3_demod_write(pt3->adaps[PT3_NUM_FE - 1], &rv, 1);
+}
+
+static int pt3_set_lna(struct dvb_frontend *fe)
+{
+ struct pt3_adapter *adap;
+ struct pt3_board *pt3;
+ u32 val;
+ int ret;
+
+ /* LNA is shared btw. 2 TERR-tuners */
+
+ adap = pt3_find_adapter(fe);
+ val = fe->dtv_property_cache.lna;
+ if (val == LNA_AUTO || val == adap->cur_lna)
+ return 0;
+
+ pt3 = adap->dvb_adap.priv;
+ if (mutex_lock_interruptible(&pt3->lock))
+ return -ERESTARTSYS;
+ if (val)
+ pt3->lna_on_cnt++;
+ else
+ pt3->lna_on_cnt--;
+
+ if (val && pt3->lna_on_cnt <= 1) {
+ pt3->lna_on_cnt = 1;
+ ret = pt3_set_tuner_power(pt3, true, true);
+ } else if (!val && pt3->lna_on_cnt <= 0) {
+ pt3->lna_on_cnt = 0;
+ ret = pt3_set_tuner_power(pt3, true, false);
+ } else
+ ret = 0;
+ mutex_unlock(&pt3->lock);
+ adap->cur_lna = (val != 0);
+ return ret;
+}
+
+static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
+{
+ struct pt3_adapter *adap;
+ struct pt3_board *pt3;
+ bool on;
+
+ /* LNB power is shared btw. 2 SAT-tuners */
+
+ adap = pt3_find_adapter(fe);
+ on = (volt != SEC_VOLTAGE_OFF);
+ if (on == adap->cur_lnb)
+ return 0;
+ adap->cur_lnb = on;
+ pt3 = adap->dvb_adap.priv;
+ if (mutex_lock_interruptible(&pt3->lock))
+ return -ERESTARTSYS;
+ if (on)
+ pt3->lnb_on_cnt++;
+ else
+ pt3->lnb_on_cnt--;
+
+ if (on && pt3->lnb_on_cnt <= 1) {
+ pt3->lnb_on_cnt = 1;
+ pt3_lnb_ctrl(pt3, true);
+ } else if (!on && pt3->lnb_on_cnt <= 0) {
+ pt3->lnb_on_cnt = 0;
+ pt3_lnb_ctrl(pt3, false);
+ }
+ mutex_unlock(&pt3->lock);
+ return 0;
+}
+
+/* register values used in pt3_fe_init() */
+
+static const struct reg_val init0_sat[] = {
+ { 0x03, 0x01 },
+ { 0x1e, 0x10 },
+};
+static const struct reg_val init0_ter[] = {
+ { 0x01, 0x40 },
+ { 0x1c, 0x10 },
+};
+static const struct reg_val cfg_sat[] = {
+ { 0x1c, 0x15 },
+ { 0x1f, 0x04 },
+};
+static const struct reg_val cfg_ter[] = {
+ { 0x1d, 0x01 },
+};
+
+/*
+ * pt3_fe_init: initialize demod sub modules and ISDB-T tuners all at once.
+ *
+ * As for demod IC (TC90522) and ISDB-T tuners (MxL301RF),
+ * the i2c sequences for init'ing them are not public and hidden in a ROM,
+ * and include the board specific configurations as well.
+ * They are stored in a lump and cannot be taken out / accessed separately,
+ * thus cannot be moved to the FE/tuner driver.
+ */
+static int pt3_fe_init(struct pt3_board *pt3)
+{
+ int i, ret;
+ struct dvb_frontend *fe;
+
+ pt3_i2c_reset(pt3);
+ ret = pt3_init_all_demods(pt3);
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev, "Failed to init demod chips.");
+ return ret;
+ }
+
+ /* additional config? */
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ fe = pt3->adaps[i]->fe;
+
+ if (fe->ops.delsys[0] == SYS_ISDBS)
+ ret = pt3_demod_write(pt3->adaps[i],
+ init0_sat, ARRAY_SIZE(init0_sat));
+ else
+ ret = pt3_demod_write(pt3->adaps[i],
+ init0_ter, ARRAY_SIZE(init0_ter));
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev,
+ "demod[%d] faild in init sequence0.", i);
+ return ret;
+ }
+ ret = fe->ops.init(fe);
+ if (ret < 0)
+ return ret;
+ }
+
+ usleep_range(2000, 4000);
+ ret = pt3_set_tuner_power(pt3, true, false);
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+ return ret;
+ }
+
+ /* output pin configuration */
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ fe = pt3->adaps[i]->fe;
+ if (fe->ops.delsys[0] == SYS_ISDBS)
+ ret = pt3_demod_write(pt3->adaps[i],
+ cfg_sat, ARRAY_SIZE(cfg_sat));
+ else
+ ret = pt3_demod_write(pt3->adaps[i],
+ cfg_ter, ARRAY_SIZE(cfg_ter));
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev,
+ "demod[%d] faild in init sequence1.", i);
+ return ret;
+ }
+ }
+ usleep_range(4000, 6000);
+
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ fe = pt3->adaps[i]->fe;
+ if (fe->ops.delsys[0] != SYS_ISDBS)
+ continue;
+ /* init and wake-up ISDB-S tuners */
+ ret = fe->ops.tuner_ops.init(fe);
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev,
+ "Failed to init SAT-tuner[%d].", i);
+ return ret;
+ }
+ }
+ ret = pt3_init_all_mxl301rf(pt3);
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners.");
+ return ret;
+ }
+
+ ret = pt3_set_tuner_power(pt3, true, true);
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+ return ret;
+ }
+
+ /* Wake up all tuners and make an initial tuning,
+ * in order to avoid interference among the tuners in the module,
+ * according to the doc from the manufacturer.
+ */
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ fe = pt3->adaps[i]->fe;
+ ret = 0;
+ if (fe->ops.delsys[0] == SYS_ISDBT)
+ ret = fe->ops.tuner_ops.init(fe);
+ /* set only when called from pt3_probe(), not resume() */
+ if (ret == 0 && fe->dtv_property_cache.frequency == 0) {
+ fe->dtv_property_cache.frequency =
+ adap_conf[i].init_freq;
+ ret = fe->ops.tuner_ops.set_params(fe);
+ }
+ if (ret < 0) {
+ dev_warn(&pt3->pdev->dev,
+ "Failed in initial tuning of tuner[%d].", i);
+ return ret;
+ }
+ }
+
+ /* and sleep again, waiting to be opened by users. */
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ fe = pt3->adaps[i]->fe;
+ if (fe->ops.tuner_ops.sleep)
+ ret = fe->ops.tuner_ops.sleep(fe);
+ if (ret < 0)
+ break;
+ if (fe->ops.sleep)
+ ret = fe->ops.sleep(fe);
+ if (ret < 0)
+ break;
+ if (fe->ops.delsys[0] == SYS_ISDBS)
+ fe->ops.set_voltage = &pt3_set_voltage;
+ else
+ fe->ops.set_lna = &pt3_set_lna;
+ }
+ if (i < PT3_NUM_FE) {
+ dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby.", i);
+ return ret;
+ }
+ return 0;
+}
+
+
+static int pt3_attach_fe(struct pt3_board *pt3, int i)
+{
+ struct i2c_board_info info;
+ struct tc90522_config cfg;
+ struct i2c_client *cl;
+ struct dvb_adapter *dvb_adap;
+ int ret;
+
+ info = adap_conf[i].demod_info;
+ cfg = adap_conf[i].demod_cfg;
+ cfg.tuner_i2c = NULL;
+ info.platform_data = &cfg;
+
+ ret = -ENODEV;
+ request_module("tc90522");
+ cl = i2c_new_device(&pt3->i2c_adap, &info);
+ if (!cl || !cl->dev.driver)
+ return -ENODEV;
+ pt3->adaps[i]->i2c_demod = cl;
+ if (!try_module_get(cl->dev.driver->owner))
+ goto err_demod_i2c_unregister_device;
+
+ if (!strncmp(cl->name, TC90522_I2C_DEV_SAT, sizeof(cl->name))) {
+ struct qm1d1c0042_config tcfg;
+
+ tcfg = adap_conf[i].tuner_cfg.qm1d1c0042;
+ tcfg.fe = cfg.fe;
+ info = adap_conf[i].tuner_info;
+ info.platform_data = &tcfg;
+ request_module("qm1d1c0042");
+ cl = i2c_new_device(cfg.tuner_i2c, &info);
+ } else {
+ struct mxl301rf_config tcfg;
+
+ tcfg = adap_conf[i].tuner_cfg.mxl301rf;
+ tcfg.fe = cfg.fe;
+ info = adap_conf[i].tuner_info;
+ info.platform_data = &tcfg;
+ request_module("mxl301rf");
+ cl = i2c_new_device(cfg.tuner_i2c, &info);
+ }
+ if (!cl || !cl->dev.driver)
+ goto err_demod_module_put;
+ pt3->adaps[i]->i2c_tuner = cl;
+ if (!try_module_get(cl->dev.driver->owner))
+ goto err_tuner_i2c_unregister_device;
+
+ dvb_adap = &pt3->adaps[one_adapter ? 0 : i]->dvb_adap;
+ ret = dvb_register_frontend(dvb_adap, cfg.fe);
+ if (ret < 0)
+ goto err_tuner_module_put;
+ pt3->adaps[i]->fe = cfg.fe;
+ return 0;
+
+err_tuner_module_put:
+ module_put(pt3->adaps[i]->i2c_tuner->dev.driver->owner);
+err_tuner_i2c_unregister_device:
+ i2c_unregister_device(pt3->adaps[i]->i2c_tuner);
+err_demod_module_put:
+ module_put(pt3->adaps[i]->i2c_demod->dev.driver->owner);
+err_demod_i2c_unregister_device:
+ i2c_unregister_device(pt3->adaps[i]->i2c_demod);
+
+ return ret;
+}
+
+
+static int pt3_fetch_thread(void *data)
+{
+ struct pt3_adapter *adap = data;
+ ktime_t delay;
+ bool was_frozen;
+
+#define PT3_INITIAL_BUF_DROPS 4
+#define PT3_FETCH_DELAY 10
+#define PT3_FETCH_DELAY_DELTA 2
+
+ pt3_init_dmabuf(adap);
+ adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+ dev_dbg(adap->dvb_adap.device,
+ "PT3: [%s] started.\n", adap->thread->comm);
+ set_freezable();
+ while (!kthread_freezable_should_stop(&was_frozen)) {
+ if (was_frozen)
+ adap->num_discard = PT3_INITIAL_BUF_DROPS;
+
+ pt3_proc_dma(adap);
+
+ delay = ktime_set(0, PT3_FETCH_DELAY * NSEC_PER_MSEC);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ freezable_schedule_hrtimeout_range(&delay,
+ PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC,
+ HRTIMER_MODE_REL);
+ }
+ dev_dbg(adap->dvb_adap.device,
+ "PT3: [%s] exited.\n", adap->thread->comm);
+ adap->thread = NULL;
+ return 0;
+}
+
+static int pt3_start_streaming(struct pt3_adapter *adap)
+{
+ struct task_struct *thread;
+
+ /* start fetching thread */
+ thread = kthread_run(pt3_fetch_thread, adap, "pt3-ad%i-dmx%i",
+ adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+ if (IS_ERR(thread)) {
+ int ret = PTR_ERR(thread);
+
+ dev_warn(adap->dvb_adap.device,
+ "PT3 (adap:%d, dmx:%d): failed to start kthread.\n",
+ adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+ return ret;
+ }
+ adap->thread = thread;
+
+ return pt3_start_dma(adap);
+}
+
+static int pt3_stop_streaming(struct pt3_adapter *adap)
+{
+ int ret;
+
+ ret = pt3_stop_dma(adap);
+ if (ret)
+ dev_warn(adap->dvb_adap.device,
+ "PT3: failed to stop streaming of adap:%d/FE:%d\n",
+ adap->dvb_adap.num, adap->fe->id);
+
+ /* kill the fetching thread */
+ ret = kthread_stop(adap->thread);
+ return ret;
+}
+
+static int pt3_start_feed(struct dvb_demux_feed *feed)
+{
+ struct pt3_adapter *adap;
+
+ if (signal_pending(current))
+ return -EINTR;
+
+ adap = container_of(feed->demux, struct pt3_adapter, demux);
+ adap->num_feeds++;
+ if (adap->thread)
+ return 0;
+ if (adap->num_feeds != 1) {
+ dev_warn(adap->dvb_adap.device,
+ "%s: unmatched start/stop_feed in adap:%i/dmx:%i.\n",
+ __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+ adap->num_feeds = 1;
+ }
+
+ return pt3_start_streaming(adap);
+
+}
+
+static int pt3_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct pt3_adapter *adap;
+
+ adap = container_of(feed->demux, struct pt3_adapter, demux);
+
+ adap->num_feeds--;
+ if (adap->num_feeds > 0 || !adap->thread)
+ return 0;
+ adap->num_feeds = 0;
+
+ return pt3_stop_streaming(adap);
+}
+
+
+static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
+{
+ int ret;
+ struct pt3_adapter *adap;
+ struct dvb_adapter *da;
+
+ adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+ if (!adap) {
+ dev_err(&pt3->pdev->dev, "failed to alloc mem for adapter.\n");
+ return -ENOMEM;
+ }
+ pt3->adaps[index] = adap;
+ adap->adap_idx = index;
+
+ if (index == 0 || !one_adapter) {
+ ret = dvb_register_adapter(&adap->dvb_adap, "PT3 DVB",
+ THIS_MODULE, &pt3->pdev->dev, adapter_nr);
+ if (ret < 0) {
+ dev_err(&pt3->pdev->dev,
+ "failed to register adapter dev.\n");
+ goto err_mem;
+ }
+ da = &adap->dvb_adap;
+ } else
+ da = &pt3->adaps[0]->dvb_adap;
+
+ adap->dvb_adap.priv = pt3;
+ adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ adap->demux.priv = adap;
+ adap->demux.feednum = 256;
+ adap->demux.filternum = 256;
+ adap->demux.start_feed = pt3_start_feed;
+ adap->demux.stop_feed = pt3_stop_feed;
+ ret = dvb_dmx_init(&adap->demux);
+ if (ret < 0) {
+ dev_err(&pt3->pdev->dev, "failed to init dmx dev.\n");
+ goto err_adap;
+ }
+
+ adap->dmxdev.filternum = 256;
+ adap->dmxdev.demux = &adap->demux.dmx;
+ ret = dvb_dmxdev_init(&adap->dmxdev, da);
+ if (ret < 0) {
+ dev_err(&pt3->pdev->dev, "failed to init dmxdev.\n");
+ goto err_demux;
+ }
+
+ ret = pt3_alloc_dmabuf(adap);
+ if (ret) {
+ dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers.\n");
+ goto err_dmabuf;
+ }
+
+ return 0;
+
+err_dmabuf:
+ pt3_free_dmabuf(adap);
+ dvb_dmxdev_release(&adap->dmxdev);
+err_demux:
+ dvb_dmx_release(&adap->demux);
+err_adap:
+ if (index == 0 || !one_adapter)
+ dvb_unregister_adapter(da);
+err_mem:
+ kfree(adap);
+ pt3->adaps[index] = NULL;
+ return ret;
+}
+
+static void pt3_cleanup_adapter(struct pt3_board *pt3, int index)
+{
+ struct pt3_adapter *adap;
+ struct dmx_demux *dmx;
+
+ adap = pt3->adaps[index];
+ if (adap == NULL)
+ return;
+
+ /* stop demux kthread */
+ if (adap->thread)
+ pt3_stop_streaming(adap);
+
+ dmx = &adap->demux.dmx;
+ dmx->close(dmx);
+ if (adap->fe) {
+ adap->fe->callback = NULL;
+ if (adap->fe->frontend_priv)
+ dvb_unregister_frontend(adap->fe);
+ if (adap->i2c_tuner) {
+ module_put(adap->i2c_tuner->dev.driver->owner);
+ i2c_unregister_device(adap->i2c_tuner);
+ }
+ if (adap->i2c_demod) {
+ module_put(adap->i2c_demod->dev.driver->owner);
+ i2c_unregister_device(adap->i2c_demod);
+ }
+ }
+ pt3_free_dmabuf(adap);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ if (index == 0 || !one_adapter)
+ dvb_unregister_adapter(&adap->dvb_adap);
+ kfree(adap);
+ pt3->adaps[index] = NULL;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int pt3_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct pt3_board *pt3 = pci_get_drvdata(pdev);
+ int i;
+ struct pt3_adapter *adap;
+
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ adap = pt3->adaps[i];
+ if (adap->num_feeds > 0)
+ pt3_stop_dma(adap);
+ dvb_frontend_suspend(adap->fe);
+ pt3_free_dmabuf(adap);
+ }
+
+ pt3_lnb_ctrl(pt3, false);
+ pt3_set_tuner_power(pt3, false, false);
+ return 0;
+}
+
+static int pt3_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct pt3_board *pt3 = pci_get_drvdata(pdev);
+ int i, ret;
+ struct pt3_adapter *adap;
+
+ ret = pt3_fe_init(pt3);
+ if (ret)
+ return ret;
+
+ if (pt3->lna_on_cnt > 0)
+ pt3_set_tuner_power(pt3, true, true);
+ if (pt3->lnb_on_cnt > 0)
+ pt3_lnb_ctrl(pt3, true);
+
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ adap = pt3->adaps[i];
+ dvb_frontend_resume(adap->fe);
+ ret = pt3_alloc_dmabuf(adap);
+ if (ret) {
+ dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs.\n");
+ continue;
+ }
+ if (adap->num_feeds > 0)
+ pt3_start_dma(adap);
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_PM_SLEEP */
+
+
+static void pt3_remove(struct pci_dev *pdev)
+{
+ struct pt3_board *pt3;
+ int i;
+
+ pt3 = pci_get_drvdata(pdev);
+ for (i = PT3_NUM_FE - 1; i >= 0; i--)
+ pt3_cleanup_adapter(pt3, i);
+ i2c_del_adapter(&pt3->i2c_adap);
+ kfree(pt3->i2c_buf);
+ pci_iounmap(pt3->pdev, pt3->regs[0]);
+ pci_iounmap(pt3->pdev, pt3->regs[1]);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ kfree(pt3);
+}
+
+static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ u8 rev;
+ u32 ver;
+ int i, ret;
+ struct pt3_board *pt3;
+ struct i2c_adapter *i2c;
+
+ if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1)
+ return -ENODEV;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ return -ENODEV;
+ pci_set_master(pdev);
+
+ ret = pci_request_regions(pdev, DRV_NAME);
+ if (ret < 0)
+ goto err_disable_device;
+
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret == 0)
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+ else {
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret == 0)
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ else {
+ dev_err(&pdev->dev, "Failed to set DMA mask.\n");
+ goto err_release_regions;
+ }
+ dev_info(&pdev->dev, "Use 32bit DMA.\n");
+ }
+
+ pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL);
+ if (!pt3) {
+ dev_err(&pdev->dev, "Failed to alloc mem for this dev.\n");
+ ret = -ENOMEM;
+ goto err_release_regions;
+ }
+ pci_set_drvdata(pdev, pt3);
+ pt3->pdev = pdev;
+ mutex_init(&pt3->lock);
+ pt3->regs[0] = pci_ioremap_bar(pdev, 0);
+ pt3->regs[1] = pci_ioremap_bar(pdev, 2);
+ if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) {
+ dev_err(&pdev->dev, "Failed to ioremap.\n");
+ ret = -ENOMEM;
+ goto err_kfree;
+ }
+
+ ver = ioread32(pt3->regs[0] + REG_VERSION);
+ if ((ver >> 16) != 0x0301) {
+ dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported",
+ ver >> 24, (ver & 0x00ff0000) >> 16);
+ ret = -ENODEV;
+ goto err_iounmap;
+ }
+
+ pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS);
+
+ pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL);
+ if (pt3->i2c_buf == NULL) {
+ dev_err(&pdev->dev, "Failed to alloc mem for i2c.\n");
+ ret = -ENOMEM;
+ goto err_iounmap;
+ }
+ i2c = &pt3->i2c_adap;
+ i2c->owner = THIS_MODULE;
+ i2c->algo = &pt3_i2c_algo;
+ i2c->algo_data = NULL;
+ i2c->dev.parent = &pdev->dev;
+ strlcpy(i2c->name, DRV_NAME, sizeof(i2c->name));
+ i2c_set_adapdata(i2c, pt3);
+ ret = i2c_add_adapter(i2c);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to add i2c adapter.\n");
+ goto err_i2cbuf;
+ }
+
+ for (i = 0; i < PT3_NUM_FE; i++) {
+ ret = pt3_alloc_adapter(pt3, i);
+ if (ret < 0)
+ break;
+
+ ret = pt3_attach_fe(pt3, i);
+ if (ret < 0)
+ break;
+ }
+ if (i < PT3_NUM_FE) {
+ dev_err(&pdev->dev, "Failed to create FE%d.\n", i);
+ goto err_cleanup_adapters;
+ }
+
+ ret = pt3_fe_init(pt3);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to init frontends.\n");
+ i = PT3_NUM_FE - 1;
+ goto err_cleanup_adapters;
+ }
+
+ dev_info(&pdev->dev,
+ "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x).\n",
+ ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff);
+ return 0;
+
+err_cleanup_adapters:
+ while (i >= 0)
+ pt3_cleanup_adapter(pt3, i--);
+ i2c_del_adapter(i2c);
+err_i2cbuf:
+ kfree(pt3->i2c_buf);
+err_iounmap:
+ if (pt3->regs[0])
+ pci_iounmap(pdev, pt3->regs[0]);
+ if (pt3->regs[1])
+ pci_iounmap(pdev, pt3->regs[1]);
+err_kfree:
+ kfree(pt3);
+err_release_regions:
+ pci_release_regions(pdev);
+err_disable_device:
+ pci_disable_device(pdev);
+ return ret;
+
+}
+
+static const struct pci_device_id pt3_id_table[] = {
+ { PCI_DEVICE_SUB(0x1172, 0x4c15, 0xee8d, 0x0368) },
+ { },
+};
+MODULE_DEVICE_TABLE(pci, pt3_id_table);
+
+static SIMPLE_DEV_PM_OPS(pt3_pm_ops, pt3_suspend, pt3_resume);
+
+static struct pci_driver pt3_driver = {
+ .name = DRV_NAME,
+ .probe = pt3_probe,
+ .remove = pt3_remove,
+ .id_table = pt3_id_table,
+
+ .driver.pm = &pt3_pm_ops,
+};
+
+module_pci_driver(pt3_driver);
+
+MODULE_DESCRIPTION("Earthsoft PT3 Driver");
+MODULE_AUTHOR("Akihiro TSUKADA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h
new file mode 100644
index 000000000000..1b3f2ad25db3
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3.h
@@ -0,0 +1,186 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * 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 version 2.
+ *
+ *
+ * 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.
+ */
+
+#ifndef PT3_H
+#define PT3_H
+
+#include <linux/atomic.h>
+#include <linux/types.h>
+
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dmxdev.h"
+
+#include "tc90522.h"
+#include "mxl301rf.h"
+#include "qm1d1c0042.h"
+
+#define DRV_NAME KBUILD_MODNAME
+
+#define PT3_NUM_FE 4
+
+/*
+ * register index of the FPGA chip
+ */
+#define REG_VERSION 0x00
+#define REG_BUS 0x04
+#define REG_SYSTEM_W 0x08
+#define REG_SYSTEM_R 0x0c
+#define REG_I2C_W 0x10
+#define REG_I2C_R 0x14
+#define REG_RAM_W 0x18
+#define REG_RAM_R 0x1c
+#define REG_DMA_BASE 0x40 /* regs for FE[i] = REG_DMA_BASE + 0x18 * i */
+#define OFST_DMA_DESC_L 0x00
+#define OFST_DMA_DESC_H 0x04
+#define OFST_DMA_CTL 0x08
+#define OFST_TS_CTL 0x0c
+#define OFST_STATUS 0x10
+#define OFST_TS_ERR 0x14
+
+/*
+ * internal buffer for I2C
+ */
+#define PT3_I2C_MAX 4091
+struct pt3_i2cbuf {
+ u8 data[PT3_I2C_MAX];
+ u8 tmp;
+ u32 num_cmds;
+};
+
+/*
+ * DMA things
+ */
+#define TS_PACKET_SZ 188
+/* DMA transfers must not cross 4GiB, so use one page / transfer */
+#define DATA_XFER_SZ 4096
+#define DATA_BUF_XFERS 47
+/* (num_bufs * DATA_BUF_SZ) % TS_PACKET_SZ must be 0 */
+#define DATA_BUF_SZ (DATA_BUF_XFERS * DATA_XFER_SZ)
+#define MAX_DATA_BUFS 16
+#define MIN_DATA_BUFS 2
+
+#define DESCS_IN_PAGE (PAGE_SIZE / sizeof(struct xfer_desc))
+#define MAX_NUM_XFERS (MAX_DATA_BUFS * DATA_BUF_XFERS)
+#define MAX_DESC_BUFS DIV_ROUND_UP(MAX_NUM_XFERS, DESCS_IN_PAGE)
+
+/* DMA transfer description.
+ * device is passed a pointer to this struct, dma-reads it,
+ * and gets the DMA buffer ring for storing TS data.
+ */
+struct xfer_desc {
+ u32 addr_l; /* bus address of target data buffer */
+ u32 addr_h;
+ u32 size;
+ u32 next_l; /* bus adddress of the next xfer_desc */
+ u32 next_h;
+};
+
+/* A DMA mapping of a page containing xfer_desc's */
+struct xfer_desc_buffer {
+ dma_addr_t b_addr;
+ struct xfer_desc *descs; /* PAGE_SIZE (xfer_desc[DESCS_IN_PAGE]) */
+};
+
+/* A DMA mapping of a data buffer */
+struct dma_data_buffer {
+ dma_addr_t b_addr;
+ u8 *data; /* size: u8[PAGE_SIZE] */
+};
+
+/*
+ * device things
+ */
+struct pt3_adap_config {
+ struct i2c_board_info demod_info;
+ struct tc90522_config demod_cfg;
+
+ struct i2c_board_info tuner_info;
+ union tuner_config {
+ struct qm1d1c0042_config qm1d1c0042;
+ struct mxl301rf_config mxl301rf;
+ } tuner_cfg;
+ u32 init_freq;
+};
+
+struct pt3_adapter {
+ struct dvb_adapter dvb_adap; /* dvb_adap.priv => struct pt3_board */
+ int adap_idx;
+
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dvb_frontend *fe;
+ struct i2c_client *i2c_demod;
+ struct i2c_client *i2c_tuner;
+
+ /* data fetch thread */
+ struct task_struct *thread;
+ int num_feeds;
+
+ bool cur_lna;
+ bool cur_lnb; /* current LNB power status (on/off) */
+
+ /* items below are for DMA */
+ struct dma_data_buffer buffer[MAX_DATA_BUFS];
+ int buf_idx;
+ int buf_ofs;
+ int num_bufs; /* == pt3_board->num_bufs */
+ int num_discard; /* how many access units to discard initially */
+
+ struct xfer_desc_buffer desc_buf[MAX_DESC_BUFS];
+ int num_desc_bufs; /* == num_bufs * DATA_BUF_XFERS / DESCS_IN_PAGE */
+};
+
+
+struct pt3_board {
+ struct pci_dev *pdev;
+ void __iomem *regs[2];
+ /* regs[0]: registers, regs[1]: internal memory, used for I2C */
+
+ struct mutex lock;
+
+ /* LNB power shared among sat-FEs */
+ int lnb_on_cnt; /* LNB power on count */
+
+ /* LNA shared among terr-FEs */
+ int lna_on_cnt; /* booster enabled count */
+
+ int num_bufs; /* number of DMA buffers allocated/mapped per FE */
+
+ struct i2c_adapter i2c_adap;
+ struct pt3_i2cbuf *i2c_buf;
+
+ struct pt3_adapter *adaps[PT3_NUM_FE];
+};
+
+
+/*
+ * prototypes
+ */
+extern int pt3_alloc_dmabuf(struct pt3_adapter *adap);
+extern void pt3_init_dmabuf(struct pt3_adapter *adap);
+extern void pt3_free_dmabuf(struct pt3_adapter *adap);
+extern int pt3_start_dma(struct pt3_adapter *adap);
+extern int pt3_stop_dma(struct pt3_adapter *adap);
+extern int pt3_proc_dma(struct pt3_adapter *adap);
+
+extern int pt3_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num);
+extern u32 pt3_i2c_functionality(struct i2c_adapter *adap);
+extern void pt3_i2c_reset(struct pt3_board *pt3);
+extern int pt3_init_all_demods(struct pt3_board *pt3);
+extern int pt3_init_all_mxl301rf(struct pt3_board *pt3);
+#endif /* PT3_H */
diff --git a/drivers/media/pci/pt3/pt3_dma.c b/drivers/media/pci/pt3/pt3_dma.c
new file mode 100644
index 000000000000..f0ce90437fac
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3_dma.c
@@ -0,0 +1,225 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * 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 version 2.
+ *
+ *
+ * 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.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128)
+#define PT3_BUF_CANARY (0x74)
+
+static u32 get_dma_base(int idx)
+{
+ int i;
+
+ i = (idx == 1 || idx == 2) ? 3 - idx : idx;
+ return REG_DMA_BASE + 0x18 * i;
+}
+
+int pt3_stop_dma(struct pt3_adapter *adap)
+{
+ struct pt3_board *pt3 = adap->dvb_adap.priv;
+ u32 base;
+ u32 stat;
+ int retry;
+
+ base = get_dma_base(adap->adap_idx);
+ stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+ if (!(stat & 0x01))
+ return 0;
+
+ iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+ for (retry = 0; retry < 5; retry++) {
+ stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
+ if (!(stat & 0x01))
+ return 0;
+ msleep(50);
+ }
+ return -EIO;
+}
+
+int pt3_start_dma(struct pt3_adapter *adap)
+{
+ struct pt3_board *pt3 = adap->dvb_adap.priv;
+ u32 base = get_dma_base(adap->adap_idx);
+
+ iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
+ iowrite32(lower_32_bits(adap->desc_buf[0].b_addr),
+ pt3->regs[0] + base + OFST_DMA_DESC_L);
+ iowrite32(upper_32_bits(adap->desc_buf[0].b_addr),
+ pt3->regs[0] + base + OFST_DMA_DESC_H);
+ iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL);
+ return 0;
+}
+
+
+static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs)
+{
+ *ofs += PT3_ACCESS_UNIT;
+ if (*ofs >= DATA_BUF_SZ) {
+ *ofs -= DATA_BUF_SZ;
+ (*idx)++;
+ if (*idx == adap->num_bufs)
+ *idx = 0;
+ }
+ return &adap->buffer[*idx].data[*ofs];
+}
+
+int pt3_proc_dma(struct pt3_adapter *adap)
+{
+ int idx, ofs;
+
+ idx = adap->buf_idx;
+ ofs = adap->buf_ofs;
+
+ if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY)
+ return 0;
+
+ while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) {
+ u8 *p;
+
+ p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs];
+ if (adap->num_discard > 0)
+ adap->num_discard--;
+ else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) {
+ dvb_dmx_swfilter_packets(&adap->demux, p,
+ (DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ);
+ dvb_dmx_swfilter_packets(&adap->demux,
+ adap->buffer[idx].data, ofs / TS_PACKET_SZ);
+ } else
+ dvb_dmx_swfilter_packets(&adap->demux, p,
+ PT3_ACCESS_UNIT / TS_PACKET_SZ);
+
+ *p = PT3_BUF_CANARY;
+ adap->buf_idx = idx;
+ adap->buf_ofs = ofs;
+ }
+ return 0;
+}
+
+void pt3_init_dmabuf(struct pt3_adapter *adap)
+{
+ int idx, ofs;
+ u8 *p;
+
+ idx = 0;
+ ofs = 0;
+ p = adap->buffer[0].data;
+ /* mark the whole buffers as "not written yet" */
+ while (idx < adap->num_bufs) {
+ p[ofs] = PT3_BUF_CANARY;
+ ofs += PT3_ACCESS_UNIT;
+ if (ofs >= DATA_BUF_SZ) {
+ ofs -= DATA_BUF_SZ;
+ idx++;
+ p = adap->buffer[idx].data;
+ }
+ }
+ adap->buf_idx = 0;
+ adap->buf_ofs = 0;
+}
+
+void pt3_free_dmabuf(struct pt3_adapter *adap)
+{
+ struct pt3_board *pt3;
+ int i;
+
+ pt3 = adap->dvb_adap.priv;
+ for (i = 0; i < adap->num_bufs; i++)
+ dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+ adap->buffer[i].data, adap->buffer[i].b_addr);
+ adap->num_bufs = 0;
+
+ for (i = 0; i < adap->num_desc_bufs; i++)
+ dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE,
+ adap->desc_buf[i].descs, adap->desc_buf[i].b_addr);
+ adap->num_desc_bufs = 0;
+}
+
+
+int pt3_alloc_dmabuf(struct pt3_adapter *adap)
+{
+ struct pt3_board *pt3;
+ void *p;
+ int i, j;
+ int idx, ofs;
+ int num_desc_bufs;
+ dma_addr_t data_addr, desc_addr;
+ struct xfer_desc *d;
+
+ pt3 = adap->dvb_adap.priv;
+ adap->num_bufs = 0;
+ adap->num_desc_bufs = 0;
+ for (i = 0; i < pt3->num_bufs; i++) {
+ p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
+ &adap->buffer[i].b_addr, GFP_KERNEL);
+ if (p == NULL)
+ goto failed;
+ adap->buffer[i].data = p;
+ adap->num_bufs++;
+ }
+ pt3_init_dmabuf(adap);
+
+ /* build circular-linked pointers (xfer_desc) to the data buffers*/
+ idx = 0;
+ ofs = 0;
+ num_desc_bufs =
+ DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE);
+ for (i = 0; i < num_desc_bufs; i++) {
+ p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE,
+ &desc_addr, GFP_KERNEL);
+ if (p == NULL)
+ goto failed;
+ adap->num_desc_bufs++;
+ adap->desc_buf[i].descs = p;
+ adap->desc_buf[i].b_addr = desc_addr;
+
+ if (i > 0) {
+ d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1];
+ d->next_l = lower_32_bits(desc_addr);
+ d->next_h = upper_32_bits(desc_addr);
+ }
+ for (j = 0; j < DESCS_IN_PAGE; j++) {
+ data_addr = adap->buffer[idx].b_addr + ofs;
+ d = &adap->desc_buf[i].descs[j];
+ d->addr_l = lower_32_bits(data_addr);
+ d->addr_h = upper_32_bits(data_addr);
+ d->size = DATA_XFER_SZ;
+
+ desc_addr += sizeof(struct xfer_desc);
+ d->next_l = lower_32_bits(desc_addr);
+ d->next_h = upper_32_bits(desc_addr);
+
+ ofs += DATA_XFER_SZ;
+ if (ofs >= DATA_BUF_SZ) {
+ ofs -= DATA_BUF_SZ;
+ idx++;
+ if (idx >= adap->num_bufs) {
+ desc_addr = adap->desc_buf[0].b_addr;
+ d->next_l = lower_32_bits(desc_addr);
+ d->next_h = upper_32_bits(desc_addr);
+ return 0;
+ }
+ }
+ }
+ }
+ return 0;
+
+failed:
+ pt3_free_dmabuf(adap);
+ return -ENOMEM;
+}
diff --git a/drivers/media/pci/pt3/pt3_i2c.c b/drivers/media/pci/pt3/pt3_i2c.c
new file mode 100644
index 000000000000..ec6a8a2e4744
--- /dev/null
+++ b/drivers/media/pci/pt3/pt3_i2c.c
@@ -0,0 +1,240 @@
+/*
+ * Earthsoft PT3 driver
+ *
+ * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
+ *
+ * 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 version 2.
+ *
+ *
+ * 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.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+
+#include "pt3.h"
+
+#define PT3_I2C_BASE 2048
+#define PT3_CMD_ADDR_NORMAL 0
+#define PT3_CMD_ADDR_INIT_DEMOD 4096
+#define PT3_CMD_ADDR_INIT_TUNER (4096 + 2042)
+
+/* masks for I2C status register */
+#define STAT_SEQ_RUNNING 0x1
+#define STAT_SEQ_ERROR 0x6
+#define STAT_NO_SEQ 0x8
+
+#define PT3_I2C_RUN (1 << 16)
+#define PT3_I2C_RESET (1 << 17)
+
+enum ctl_cmd {
+ I_END,
+ I_ADDRESS,
+ I_CLOCK_L,
+ I_CLOCK_H,
+ I_DATA_L,
+ I_DATA_H,
+ I_RESET,
+ I_SLEEP,
+ I_DATA_L_NOP = 0x08,
+ I_DATA_H_NOP = 0x0c,
+ I_DATA_H_READ = 0x0d,
+ I_DATA_H_ACK0 = 0x0e,
+ I_DATA_H_ACK1 = 0x0f,
+};
+
+
+static void cmdbuf_add(struct pt3_i2cbuf *cbuf, enum ctl_cmd cmd)
+{
+ int buf_idx;
+
+ if ((cbuf->num_cmds % 2) == 0)
+ cbuf->tmp = cmd;
+ else {
+ cbuf->tmp |= cmd << 4;
+ buf_idx = cbuf->num_cmds / 2;
+ if (buf_idx < ARRAY_SIZE(cbuf->data))
+ cbuf->data[buf_idx] = cbuf->tmp;
+ }
+ cbuf->num_cmds++;
+}
+
+static void put_end(struct pt3_i2cbuf *cbuf)
+{
+ cmdbuf_add(cbuf, I_END);
+ if (cbuf->num_cmds % 2)
+ cmdbuf_add(cbuf, I_END);
+}
+
+static void put_start(struct pt3_i2cbuf *cbuf)
+{
+ cmdbuf_add(cbuf, I_DATA_H);
+ cmdbuf_add(cbuf, I_CLOCK_H);
+ cmdbuf_add(cbuf, I_DATA_L);
+ cmdbuf_add(cbuf, I_CLOCK_L);
+}
+
+static void put_byte_write(struct pt3_i2cbuf *cbuf, u8 val)
+{
+ u8 mask;
+
+ mask = 0x80;
+ for (mask = 0x80; mask > 0; mask >>= 1)
+ cmdbuf_add(cbuf, (val & mask) ? I_DATA_H_NOP : I_DATA_L_NOP);
+ cmdbuf_add(cbuf, I_DATA_H_ACK0);
+}
+
+static void put_byte_read(struct pt3_i2cbuf *cbuf, u32 size)
+{
+ int i, j;
+
+ for (i = 0; i < size; i++) {
+ for (j = 0; j < 8; j++)
+ cmdbuf_add(cbuf, I_DATA_H_READ);
+ cmdbuf_add(cbuf, (i == size - 1) ? I_DATA_H_NOP : I_DATA_L_NOP);
+ }
+}
+
+static void put_stop(struct pt3_i2cbuf *cbuf)
+{
+ cmdbuf_add(cbuf, I_DATA_L);
+ cmdbuf_add(cbuf, I_CLOCK_H);
+ cmdbuf_add(cbuf, I_DATA_H);
+}
+
+
+/* translates msgs to internal commands for bit-banging */
+static void translate(struct pt3_i2cbuf *cbuf, struct i2c_msg *msgs, int num)
+{
+ int i, j;
+ bool rd;
+
+ cbuf->num_cmds = 0;
+ for (i = 0; i < num; i++) {
+ rd = !!(msgs[i].flags & I2C_M_RD);
+ put_start(cbuf);
+ put_byte_write(cbuf, msgs[i].addr << 1 | rd);
+ if (rd)
+ put_byte_read(cbuf, msgs[i].len);
+ else
+ for (j = 0; j < msgs[i].len; j++)
+ put_byte_write(cbuf, msgs[i].buf[j]);
+ }
+ if (num > 0) {
+ put_stop(cbuf);
+ put_end(cbuf);
+ }
+}
+
+static int wait_i2c_result(struct pt3_board *pt3, u32 *result, int max_wait)
+{
+ int i;
+ u32 v;
+
+ for (i = 0; i < max_wait; i++) {
+ v = ioread32(pt3->regs[0] + REG_I2C_R);
+ if (!(v & STAT_SEQ_RUNNING))
+ break;
+ usleep_range(500, 750);
+ }
+ if (i >= max_wait)
+ return -EIO;
+ if (result)
+ *result = v;
+ return 0;
+}
+
+/* send [pre-]translated i2c msgs stored at addr */
+static int send_i2c_cmd(struct pt3_board *pt3, u32 addr)
+{
+ u32 ret;
+
+ /* make sure that previous transactions had finished */
+ if (wait_i2c_result(pt3, NULL, 50)) {
+ dev_warn(&pt3->pdev->dev, "(%s) prev. transaction stalled\n",
+ __func__);
+ return -EIO;
+ }
+
+ iowrite32(PT3_I2C_RUN | addr, pt3->regs[0] + REG_I2C_W);
+ usleep_range(200, 300);
+ /* wait for the current transaction to finish */
+ if (wait_i2c_result(pt3, &ret, 500) || (ret & STAT_SEQ_ERROR)) {
+ dev_warn(&pt3->pdev->dev, "(%s) failed.\n", __func__);
+ return -EIO;
+ }
+ return 0;
+}
+
+
+/* init commands for each demod are combined into one transaction
+ * and hidden in ROM with the address PT3_CMD_ADDR_INIT_DEMOD.
+ */
+int pt3_init_all_demods(struct pt3_board *pt3)
+{
+ ioread32(pt3->regs[0] + REG_I2C_R);
+ return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_DEMOD);
+}
+
+/* init commands for two ISDB-T tuners are hidden in ROM. */
+int pt3_init_all_mxl301rf(struct pt3_board *pt3)
+{
+ usleep_range(1000, 2000);
+ return send_i2c_cmd(pt3, PT3_CMD_ADDR_INIT_TUNER);
+}
+
+void pt3_i2c_reset(struct pt3_board *pt3)
+{
+ iowrite32(PT3_I2C_RESET, pt3->regs[0] + REG_I2C_W);
+}
+
+/*
+ * I2C algorithm
+ */
+int
+pt3_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct pt3_board *pt3;
+ struct pt3_i2cbuf *cbuf;
+ int i;
+ void __iomem *p;
+
+ pt3 = i2c_get_adapdata(adap);
+ cbuf = pt3->i2c_buf;
+
+ for (i = 0; i < num; i++)
+ if (msgs[i].flags & I2C_M_RECV_LEN) {
+ dev_warn(&pt3->pdev->dev,
+ "(%s) I2C_M_RECV_LEN not supported.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ translate(cbuf, msgs, num);
+ memcpy_toio(pt3->regs[1] + PT3_I2C_BASE + PT3_CMD_ADDR_NORMAL / 2,
+ cbuf->data, cbuf->num_cmds);
+
+ if (send_i2c_cmd(pt3, PT3_CMD_ADDR_NORMAL) < 0)
+ return -EIO;
+
+ p = pt3->regs[1] + PT3_I2C_BASE;
+ for (i = 0; i < num; i++)
+ if ((msgs[i].flags & I2C_M_RD) && msgs[i].len > 0) {
+ memcpy_fromio(msgs[i].buf, p, msgs[i].len);
+ p += msgs[i].len;
+ }
+
+ return num;
+}
+
+u32 pt3_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C;
+}
diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig
index 18ae75546302..b44e0d70907e 100644
--- a/drivers/media/pci/saa7134/Kconfig
+++ b/drivers/media/pci/saa7134/Kconfig
@@ -63,3 +63,11 @@ config VIDEO_SAA7134_DVB
To compile this driver as a module, choose M here: the
module will be called saa7134-dvb.
+
+config VIDEO_SAA7134_GO7007
+ tristate "go7007 support for saa7134 based TV cards"
+ depends on VIDEO_SAA7134
+ depends on VIDEO_GO7007
+ ---help---
+ Enables saa7134 driver support for boards with go7007
+ MPEG encoder (WIS Voyager or compatible).
diff --git a/drivers/media/pci/saa7134/Makefile b/drivers/media/pci/saa7134/Makefile
index 58de9b085689..09c43da67588 100644
--- a/drivers/media/pci/saa7134/Makefile
+++ b/drivers/media/pci/saa7134/Makefile
@@ -5,6 +5,7 @@ saa7134-y += saa7134-video.o
saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o
+obj-$(CONFIG_VIDEO_SAA7134_GO7007) += saa7134-go7007.o
obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
@@ -14,3 +15,4 @@ ccflags-y += -I$(srctree)/drivers/media/i2c
ccflags-y += -I$(srctree)/drivers/media/tuners
ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+ccflags-y += -I$(srctree)/drivers/media/usb/go7007
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index 6e4bdb90aa92..3ca078057755 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -5827,6 +5827,29 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x0000800,
},
},
+ [SAA7134_BOARD_WIS_VOYAGER] = {
+ .name = "WIS Voyager or compatible",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_GO7007,
+ .inputs = { {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ } },
+ },
};
@@ -7080,6 +7103,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */
.driver_data = SAA7134_BOARD_AVERMEDIA_A706,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1905, /* WIS */
+ .subdevice = 0x7007,
+ .driver_data = SAA7134_BOARD_WIS_VOYAGER,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 9ff03a69ced4..236ed725f933 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -160,6 +160,8 @@ static void request_module_async(struct work_struct *work){
request_module("saa7134-empress");
if (card_is_dvb(dev))
request_module("saa7134-dvb");
+ if (card_is_go7007(dev))
+ request_module("saa7134-go7007");
if (alsa) {
if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130)
request_module("saa7134-alsa");
@@ -563,8 +565,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
saa7134_irq_vbi_done(dev,status);
if ((report & SAA7134_IRQ_REPORT_DONE_RA2) &&
- card_has_mpeg(dev))
- saa7134_irq_ts_done(dev,status);
+ card_has_mpeg(dev)) {
+ if (dev->mops->irq_ts_done != NULL)
+ dev->mops->irq_ts_done(dev, status);
+ else
+ saa7134_irq_ts_done(dev, status);
+ }
if (report & SAA7134_IRQ_REPORT_GPIO16) {
switch (dev->has_remote) {
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
new file mode 100644
index 000000000000..54e650b4dff1
--- /dev/null
+++ b/drivers/media/pci/saa7134/saa7134-go7007.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "saa7134.h"
+#include "saa7134-reg.h"
+#include "go7007-priv.h"
+
+/*#define GO7007_HPI_DEBUG*/
+
+enum hpi_address {
+ HPI_ADDR_VIDEO_BUFFER = 0xe4,
+ HPI_ADDR_INIT_BUFFER = 0xea,
+ HPI_ADDR_INTR_RET_VALUE = 0xee,
+ HPI_ADDR_INTR_RET_DATA = 0xec,
+ HPI_ADDR_INTR_STATUS = 0xf4,
+ HPI_ADDR_INTR_WR_PARAM = 0xf6,
+ HPI_ADDR_INTR_WR_INDEX = 0xf8,
+};
+
+enum gpio_command {
+ GPIO_COMMAND_RESET = 0x00, /* 000b */
+ GPIO_COMMAND_REQ1 = 0x04, /* 001b */
+ GPIO_COMMAND_WRITE = 0x20, /* 010b */
+ GPIO_COMMAND_REQ2 = 0x24, /* 011b */
+ GPIO_COMMAND_READ = 0x80, /* 100b */
+ GPIO_COMMAND_VIDEO = 0x84, /* 101b */
+ GPIO_COMMAND_IDLE = 0xA0, /* 110b */
+ GPIO_COMMAND_ADDR = 0xA4, /* 111b */
+};
+
+struct saa7134_go7007 {
+ struct v4l2_subdev sd;
+ struct saa7134_dev *dev;
+ u8 *top;
+ u8 *bottom;
+ dma_addr_t top_dma;
+ dma_addr_t bottom_dma;
+};
+
+static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct saa7134_go7007, sd);
+}
+
+static const struct go7007_board_info board_voyager = {
+ .flags = 0,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_VALID_ENABLE |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .num_inputs = 1,
+ .inputs = {
+ {
+ .name = "SAA7134",
+ },
+ },
+};
+
+/********************* Driver for GPIO HPI interface *********************/
+
+static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
+{
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ /* Write HPI address */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Write low byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Write high byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ return 0;
+}
+
+static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
+{
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ /* Write HPI address */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+ /* Read low byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ *data = saa_readb(SAA7134_GPIO_GPSTATUS0);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Read high byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ return 0;
+}
+
+static int saa7134_go7007_interface_reset(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ u16 intr_val, intr_data;
+ int count = 20;
+
+ saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
+ saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
+ msleep(1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+ msleep(10);
+
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ saa_readb(SAA7134_GPIO_GPSTATUS2);
+ /*pr_debug("status is %s\n", saa_readb(SAA7134_GPIO_GPSTATUS2) & 0x40 ? "OK" : "not OK"); */
+
+ /* enter command mode...(?) */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+
+ do {
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_readb(SAA7134_GPIO_GPSTATUS2);
+ /*pr_info("gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
+ } while (--count > 0);
+
+ /* Wait for an interrupt to indicate successful hardware reset */
+ if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+ (intr_val & ~0x1) != 0x55aa) {
+ pr_err("saa7134-go7007: unable to reset the GO7007\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ int i;
+ u16 status_reg;
+
+#ifdef GO7007_HPI_DEBUG
+ pr_debug("saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+ for (i = 0; i < 100; ++i) {
+ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+ if (!(status_reg & 0x0010))
+ break;
+ msleep(10);
+ }
+ if (i == 100) {
+ pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+ status_reg);
+ return -1;
+ }
+ gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
+ gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
+
+ return 0;
+}
+
+static int saa7134_go7007_read_interrupt(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+
+ /* XXX we need to wait if there is no interrupt available */
+ go->interrupt_available = 1;
+ gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
+ gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
+#ifdef GO7007_HPI_DEBUG
+ pr_debug("saa7134-go7007: ReadInterrupt: %04x %04x\n",
+ go->interrupt_value, go->interrupt_data);
+#endif
+ return 0;
+}
+
+static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
+ unsigned long status)
+{
+ struct go7007 *go = video_get_drvdata(dev->empress_dev);
+ struct saa7134_go7007 *saa = go->hpi_context;
+
+ if (!vb2_is_streaming(&go->vidq))
+ return;
+ if (0 != (status & 0x000f0000))
+ pr_debug("saa7134-go7007: irq: lost %ld\n",
+ (status >> 16) & 0x0f);
+ if (status & 0x100000) {
+ dma_sync_single_for_cpu(&dev->pci->dev,
+ saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
+ saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+ } else {
+ dma_sync_single_for_cpu(&dev->pci->dev,
+ saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
+ saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+ }
+}
+
+static int saa7134_go7007_stream_start(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+
+ saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&dev->pci->dev, saa->top_dma))
+ return -ENOMEM;
+ saa->bottom_dma = dma_map_page(&dev->pci->dev,
+ virt_to_page(saa->bottom),
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) {
+ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ return -ENOMEM;
+ }
+
+ saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
+ saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
+
+ /* Set HPI interface for video */
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+ /* Enable TS interface */
+ saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
+
+ /* Reset TS interface */
+ saa_setb(SAA7134_TS_SERIAL1, 0x01);
+ saa_clearb(SAA7134_TS_SERIAL1, 0x01);
+
+ /* Set up transfer block size */
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
+ saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1);
+ saa_writeb(SAA7134_TS_DMA1, 0);
+ saa_writeb(SAA7134_TS_DMA2, 0);
+
+ /* Enable video streaming mode */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
+
+ saa_writel(SAA7134_RS_BA1(5), saa->top_dma);
+ saa_writel(SAA7134_RS_BA2(5), saa->bottom_dma);
+ saa_writel(SAA7134_RS_PITCH(5), 128);
+ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
+
+ /* Enable TS FIFO */
+ saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+ /* Enable DMA IRQ */
+ saa_setl(SAA7134_IRQ1,
+ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+ return 0;
+}
+
+static int saa7134_go7007_stream_stop(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev;
+
+ if (!saa)
+ return -EINVAL;
+ dev = saa->dev;
+ if (!dev)
+ return -EINVAL;
+
+ /* Shut down TS FIFO */
+ saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+ /* Disable DMA IRQ */
+ saa_clearl(SAA7134_IRQ1,
+ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+ /* Disable TS interface */
+ saa_clearb(SAA7134_TS_PARALLEL, 0x80);
+
+ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+
+ return 0;
+}
+
+static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ u16 status_reg;
+ int i;
+
+#ifdef GO7007_HPI_DEBUG
+ pr_debug("saa7134-go7007: DownloadBuffer sending %d bytes\n", len);
+#endif
+
+ while (len > 0) {
+ i = len > 64 ? 64 : len;
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+ while (i-- > 0) {
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+ ++data;
+ --len;
+ }
+ for (i = 0; i < 100; ++i) {
+ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+ if (!(status_reg & 0x0002))
+ break;
+ }
+ if (i == 100) {
+ pr_err("saa7134-go7007: device is hung, status reg = 0x%04x\n",
+ status_reg);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+ .interface_reset = saa7134_go7007_interface_reset,
+ .write_interrupt = saa7134_go7007_write_interrupt,
+ .read_interrupt = saa7134_go7007_read_interrupt,
+ .stream_start = saa7134_go7007_stream_start,
+ .stream_stop = saa7134_go7007_stream_stop,
+ .send_firmware = saa7134_go7007_send_firmware,
+};
+MODULE_FIRMWARE("go7007/go7007tv.bin");
+
+/* --------------------------------------------------------------------------*/
+
+static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+#if 0
+ struct saa7134_go7007 *saa = to_state(sd);
+ struct saa7134_dev *dev = saa->dev;
+
+ return saa7134_s_std_internal(dev, NULL, norm);
+#else
+ return 0;
+#endif
+}
+
+static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = {
+ .s_std = saa7134_go7007_s_std,
+};
+
+static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = {
+ .video = &saa7134_go7007_video_ops,
+};
+
+/* --------------------------------------------------------------------------*/
+
+
+/********************* Add/remove functions *********************/
+
+static int saa7134_go7007_init(struct saa7134_dev *dev)
+{
+ struct go7007 *go;
+ struct saa7134_go7007 *saa;
+ struct v4l2_subdev *sd;
+
+ pr_debug("saa7134-go7007: probing new SAA713X board\n");
+
+ go = go7007_alloc(&board_voyager, &dev->pci->dev);
+ if (go == NULL)
+ return -ENOMEM;
+
+ saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
+ if (saa == NULL) {
+ kfree(go);
+ return -ENOMEM;
+ }
+
+ go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+ snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci));
+ strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+ go->hpi_ops = &saa7134_go7007_hpi_ops;
+ go->hpi_context = saa;
+ saa->dev = dev;
+
+ /* Init the subdevice interface */
+ sd = &saa->sd;
+ v4l2_subdev_init(sd, &saa7134_go7007_sd_ops);
+ v4l2_set_subdevdata(sd, saa);
+ strncpy(sd->name, "saa7134-go7007", sizeof(sd->name));
+
+ /* Allocate a couple pages for receiving the compressed stream */
+ saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
+ if (!saa->top)
+ goto allocfail;
+ saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
+ if (!saa->bottom)
+ goto allocfail;
+
+ /* Boot the GO7007 */
+ if (go7007_boot_encoder(go, go->board_info->flags &
+ GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+ goto allocfail;
+
+ /* Do any final GO7007 initialization, then register the
+ * V4L2 and ALSA interfaces */
+ if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0)
+ goto allocfail;
+
+ /* Register the subdevice interface with the go7007 device */
+ if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0)
+ pr_info("saa7134-go7007: register subdev failed\n");
+
+ dev->empress_dev = &go->vdev;
+
+ go->status = STATUS_ONLINE;
+ return 0;
+
+allocfail:
+ if (saa->top)
+ free_page((unsigned long)saa->top);
+ if (saa->bottom)
+ free_page((unsigned long)saa->bottom);
+ kfree(saa);
+ kfree(go);
+ return -ENOMEM;
+}
+
+static int saa7134_go7007_fini(struct saa7134_dev *dev)
+{
+ struct go7007 *go;
+ struct saa7134_go7007 *saa;
+
+ if (NULL == dev->empress_dev)
+ return 0;
+
+ go = video_get_drvdata(dev->empress_dev);
+ if (go->audio_enabled)
+ go7007_snd_remove(go);
+
+ saa = go->hpi_context;
+ go->status = STATUS_SHUTDOWN;
+ free_page((unsigned long)saa->top);
+ free_page((unsigned long)saa->bottom);
+ v4l2_device_unregister_subdev(&saa->sd);
+ kfree(saa);
+ video_unregister_device(&go->vdev);
+
+ v4l2_device_put(&go->v4l2_dev);
+ dev->empress_dev = NULL;
+
+ return 0;
+}
+
+static struct saa7134_mpeg_ops saa7134_go7007_ops = {
+ .type = SAA7134_MPEG_GO7007,
+ .init = saa7134_go7007_init,
+ .fini = saa7134_go7007_fini,
+ .irq_ts_done = saa7134_go7007_irq_ts_done,
+};
+
+static int __init saa7134_go7007_mod_init(void)
+{
+ return saa7134_ts_register(&saa7134_go7007_ops);
+}
+
+static void __exit saa7134_go7007_mod_cleanup(void)
+{
+ saa7134_ts_unregister(&saa7134_go7007_ops);
+}
+
+module_init(saa7134_go7007_mod_init);
+module_exit(saa7134_go7007_mod_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index c06dbe17a87f..4f0b1012e4f3 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
/* ------------------------------------------------------------------ */
-#define VBI_LINE_COUNT 16
+#define VBI_LINE_COUNT 17
#define VBI_LINE_LENGTH 2048
#define VBI_SCALE 0x200
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 0cfa2ca6a32a..fc4a427cb51f 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -201,7 +201,7 @@ static struct saa7134_format formats[] = {
.video_v_start = 24, \
.video_v_stop = 311, \
.vbi_v_start_0 = 7, \
- .vbi_v_stop_0 = 22, \
+ .vbi_v_stop_0 = 23, \
.vbi_v_start_1 = 319, \
.src_timing = 4
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index e47edd4b57ce..1a82dd07205b 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -338,6 +338,7 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_ASUSTeK_PS3_100 190
#define SAA7134_BOARD_HAWELL_HW_9004V1 191
#define SAA7134_BOARD_AVERMEDIA_A706 192
+#define SAA7134_BOARD_WIS_VOYAGER 193
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -368,6 +369,7 @@ enum saa7134_mpeg_type {
SAA7134_MPEG_UNUSED,
SAA7134_MPEG_EMPRESS,
SAA7134_MPEG_DVB,
+ SAA7134_MPEG_GO7007,
};
enum saa7134_mpeg_ts_type {
@@ -407,6 +409,7 @@ struct saa7134_board {
#define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name)
#define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg)
#define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg)
+#define card_is_go7007(dev) (SAA7134_MPEG_GO7007 == saa7134_boards[dev->board].mpeg)
#define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg)
#define card(dev) (saa7134_boards[dev->board])
#define card_in(dev,n) (saa7134_boards[dev->board].inputs[n])
@@ -522,6 +525,8 @@ struct saa7134_mpeg_ops {
int (*init)(struct saa7134_dev *dev);
int (*fini)(struct saa7134_dev *dev);
void (*signal_change)(struct saa7134_dev *dev);
+ void (*irq_ts_done)(struct saa7134_dev *dev,
+ unsigned long status);
};
/* global device status */
diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c
index e042963d377d..4f3b1dd18ba4 100644
--- a/drivers/media/pci/saa7164/saa7164-api.c
+++ b/drivers/media/pci/saa7164/saa7164-api.c
@@ -680,7 +680,6 @@ static int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
{
struct saa7164_dev *dev = port->dev;
- int ret = 0;
u8 agc_disable;
dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
@@ -733,7 +732,7 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
msleep(100);
- return ret;
+ return 0;
}
/* Ensure the dif is in the correct state for the operating mode
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index 1bf06970ca3e..cc1be8a7a451 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -52,7 +52,7 @@ unsigned int saa_debug;
module_param_named(debug, saa_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
-unsigned int fw_debug;
+static unsigned int fw_debug;
module_param(fw_debug, int, 0644);
MODULE_PARM_DESC(fw_debug, "Firmware debug level def:2");
@@ -72,7 +72,7 @@ static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
-unsigned int print_histogram = 64;
+static unsigned int print_histogram = 64;
module_param(print_histogram, int, 0644);
MODULE_PARM_DESC(print_histogram, "print histogram values once");
@@ -80,7 +80,7 @@ unsigned int crc_checking = 1;
module_param(crc_checking, int, 0644);
MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
-unsigned int guard_checking = 1;
+static unsigned int guard_checking = 1;
module_param(guard_checking, int, 0644);
MODULE_PARM_DESC(guard_checking,
"enable dma sanity checking for buffer overruns");
diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig
index d9e06a6bf1eb..0fb91dc7ca73 100644
--- a/drivers/media/pci/solo6x10/Kconfig
+++ b/drivers/media/pci/solo6x10/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_SOLO6X10
tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
depends on PCI && VIDEO_DEV && SND && I2C
+ depends on HAS_DMA
select BITREVERSE
select FONT_SUPPORT
select FONT_8x16
diff --git a/drivers/media/pci/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c
index 5ea9cac03968..11c98f0625e4 100644
--- a/drivers/media/pci/solo6x10/solo6x10-disp.c
+++ b/drivers/media/pci/solo6x10/solo6x10-disp.c
@@ -172,7 +172,7 @@ static void solo_vout_config(struct solo_dev *solo_dev)
static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off,
u16 val, int reg_size)
{
- u16 *buf;
+ __le16 *buf;
const int n = 64, size = n * sizeof(*buf);
int i, ret = 0;
@@ -211,7 +211,7 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
{
const unsigned size = sizeof(u16) * 64;
u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
- u16 *buf;
+ __le16 *buf;
int x, y;
int ret = 0;
diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
index af40b3aba410..da25ce4a6952 100644
--- a/drivers/media/pci/solo6x10/solo6x10-eeprom.c
+++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
@@ -100,7 +100,7 @@ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
return retval;
}
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
{
int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
unsigned short retval = 0;
@@ -117,11 +117,11 @@ unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
solo_eeprom_reg_write(solo_dev, ~EE_CS);
- return retval;
+ return (__force __be16)retval;
}
int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
- unsigned short data)
+ __be16 data)
{
int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
unsigned int retval;
@@ -130,7 +130,7 @@ int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
solo_eeprom_cmd(solo_dev, write_cmd);
for (i = 15; i >= 0; i--) {
- unsigned int dataval = (data >> i) & 1;
+ unsigned int dataval = ((__force unsigned)data >> i) & 1;
solo_eeprom_reg_write(solo_dev, EE_ENB);
solo_eeprom_reg_write(solo_dev,
diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h
index c6154b00fcbd..72017b7f0a75 100644
--- a/drivers/media/pci/solo6x10/solo6x10.h
+++ b/drivers/media/pci/solo6x10/solo6x10.h
@@ -394,9 +394,9 @@ int solo_osd_print(struct solo_enc_dev *solo_enc);
/* EEPROM commands */
unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en);
-unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc);
+__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc);
int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
- unsigned short data);
+ __be16 data);
/* JPEG Qp functions */
void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch,
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index 03130157db83..f6f30abc088b 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -1,6 +1,7 @@
config STA2X11_VIP
tristate "STA2X11 VIP Video For Linux"
depends on STA2X11
+ depends on HAS_DMA
select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
select VIDEOBUF2_DMA_CONTIG
depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 365bd21301ba..22450f583da1 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -152,7 +152,7 @@ struct sta2x11_vip {
int tcount, bcount;
int overflow;
- void *iomem; /* I/O Memory */
+ void __iomem *iomem; /* I/O Memory */
struct vip_config *config;
};
diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig
index 0dcb8cd77676..7b83151ed6c4 100644
--- a/drivers/media/pci/ttpci/Kconfig
+++ b/drivers/media/pci/ttpci/Kconfig
@@ -1,8 +1,12 @@
+config DVB_AV7110_IR
+ bool
+
config DVB_AV7110
tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C
select TTPCI_EEPROM
select VIDEO_SAA7146_VV
+ select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110
depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV
select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT
select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile
index 98905963ff08..49f71b1eaf14 100644
--- a/drivers/media/pci/ttpci/Makefile
+++ b/drivers/media/pci/ttpci/Makefile
@@ -5,7 +5,7 @@
dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o
-ifdef CONFIG_INPUT_EVDEV
+ifdef CONFIG_DVB_AV7110_IR
dvb-ttpci-objs += av7110_ir.o
endif
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index f38329d29daa..c1f0617a6973 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -235,7 +235,7 @@ static void recover_arm(struct av7110 *av7110)
restart_feeds(av7110);
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
av7110_check_ir_config(av7110, true);
#endif
}
@@ -268,7 +268,7 @@ static int arm_thread(void *data)
if (!av7110->arm_ready)
continue;
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
av7110_check_ir_config(av7110, false);
#endif
@@ -2725,7 +2725,7 @@ static int av7110_attach(struct saa7146_dev* dev,
mutex_init(&av7110->ioctl_mutex);
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
av7110_ir_init(av7110);
#endif
printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
@@ -2768,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa)
struct av7110 *av7110 = saa->ext_priv;
dprintk(4, "%p\n", av7110);
-#if IS_ENABLED(CONFIG_INPUT_EVDEV)
+#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
av7110_ir_exit(av7110);
#endif
if (budgetpatch || av7110->full_ts) {
diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig
new file mode 100644
index 000000000000..5425ba1e320d
--- /dev/null
+++ b/drivers/media/pci/tw68/Kconfig
@@ -0,0 +1,10 @@
+config VIDEO_TW68
+ tristate "Techwell tw68x Video For Linux"
+ depends on VIDEO_DEV && PCI && VIDEO_V4L2
+ select I2C_ALGOBIT
+ select VIDEOBUF2_DMA_SG
+ ---help---
+ Support for Techwell tw68xx based frame grabber boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tw68.
diff --git a/drivers/media/pci/tw68/Makefile b/drivers/media/pci/tw68/Makefile
new file mode 100644
index 000000000000..3d02f28b14fb
--- /dev/null
+++ b/drivers/media/pci/tw68/Makefile
@@ -0,0 +1,3 @@
+tw68-objs := tw68-core.o tw68-video.o tw68-risc.o
+
+obj-$(CONFIG_VIDEO_TW68) += tw68.o
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
new file mode 100644
index 000000000000..a6fb48cf7aae
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -0,0 +1,434 @@
+/*
+ * tw68-core.c
+ * Core functions for the Techwell 68xx driver
+ *
+ * Much of this code is derived from the cx88 and sa7134 drivers, which
+ * were in turn derived from the bt87x driver. The original work was by
+ * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ * Hans Verkuil, Andy Walls and many others. Their work is gratefully
+ * acknowledged. Full credit goes to them - any problems within this code
+ * are mine.
+ *
+ * Copyright (C) 2009 William M. Brack
+ *
+ * Refactored and updated to the latest v4l core frameworks:
+ *
+ * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/sound.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+
+#include <media/v4l2-dev.h>
+#include "tw68.h"
+#include "tw68-reg.h"
+
+MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards");
+MODULE_AUTHOR("William M. Brack");
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_LICENSE("GPL");
+
+static unsigned int latency = UNSET;
+module_param(latency, int, 0444);
+MODULE_PARM_DESC(latency, "pci latency timer");
+
+static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number");
+
+static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
+
+static atomic_t tw68_instance = ATOMIC_INIT(0);
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps
+ * the PCI ID database up to date. Note that the entries must be
+ * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs.
+ */
+static const struct pci_device_id tw68_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)},
+ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)},
+ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)},
+ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)},
+ {0,}
+};
+
+/* ------------------------------------------------------------------ */
+
+
+/*
+ * The device is given a "soft reset". According to the specifications,
+ * after this "all register content remain unchanged", so we also write
+ * to all specified registers manually as well (mostly to manufacturer's
+ * specified reset values)
+ */
+static int tw68_hw_init1(struct tw68_dev *dev)
+{
+ /* Assure all interrupts are disabled */
+ tw_writel(TW68_INTMASK, 0); /* 020 */
+ /* Clear any pending interrupts */
+ tw_writel(TW68_INTSTAT, 0xffffffff); /* 01C */
+ /* Stop risc processor, set default buffer level */
+ tw_writel(TW68_DMAC, 0x1600);
+
+ tw_writeb(TW68_ACNTL, 0x80); /* 218 soft reset */
+ msleep(100);
+
+ tw_writeb(TW68_INFORM, 0x40); /* 208 mux0, 27mhz xtal */
+ tw_writeb(TW68_OPFORM, 0x04); /* 20C analog line-lock */
+ tw_writeb(TW68_HSYNC, 0); /* 210 color-killer high sens */
+ tw_writeb(TW68_ACNTL, 0x42); /* 218 int vref #2, chroma adc off */
+
+ tw_writeb(TW68_CROP_HI, 0x02); /* 21C Hactive m.s. bits */
+ tw_writeb(TW68_VDELAY_LO, 0x12);/* 220 Mfg specified reset value */
+ tw_writeb(TW68_VACTIVE_LO, 0xf0);
+ tw_writeb(TW68_HDELAY_LO, 0x0f);
+ tw_writeb(TW68_HACTIVE_LO, 0xd0);
+
+ tw_writeb(TW68_CNTRL1, 0xcd); /* 230 Wide Chroma BPF B/W
+ * Secam reduction, Adap comb for
+ * NTSC, Op Mode 1 */
+
+ tw_writeb(TW68_VSCALE_LO, 0); /* 234 */
+ tw_writeb(TW68_SCALE_HI, 0x11); /* 238 */
+ tw_writeb(TW68_HSCALE_LO, 0); /* 23c */
+ tw_writeb(TW68_BRIGHT, 0); /* 240 */
+ tw_writeb(TW68_CONTRAST, 0x5c); /* 244 */
+ tw_writeb(TW68_SHARPNESS, 0x51);/* 248 */
+ tw_writeb(TW68_SAT_U, 0x80); /* 24C */
+ tw_writeb(TW68_SAT_V, 0x80); /* 250 */
+ tw_writeb(TW68_HUE, 0x00); /* 254 */
+
+ /* TODO - Check that none of these are set by control defaults */
+ tw_writeb(TW68_SHARP2, 0x53); /* 258 Mfg specified reset val */
+ tw_writeb(TW68_VSHARP, 0x80); /* 25C Sharpness Coring val 8 */
+ tw_writeb(TW68_CORING, 0x44); /* 260 CTI and Vert Peak coring */
+ tw_writeb(TW68_CNTRL2, 0x00); /* 268 No power saving enabled */
+ tw_writeb(TW68_SDT, 0x07); /* 270 Enable shadow reg, auto-det */
+ tw_writeb(TW68_SDTR, 0x7f); /* 274 All stds recog, don't start */
+ tw_writeb(TW68_CLMPG, 0x50); /* 280 Clamp end at 40 sys clocks */
+ tw_writeb(TW68_IAGC, 0x22); /* 284 Mfg specified reset val */
+ tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */
+ tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */
+ tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */
+/* tw_writeb(TW68_SYNCT, 0x38);*/ /* 294 Sync amplitude */
+ tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */
+ tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */
+ tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */
+ /* Bit DETV of VCNTL1 helps sync multi cams/chip board */
+ tw_writeb(TW68_VCNTL1, 0x04); /* 2A0 */
+ tw_writeb(TW68_VCNTL2, 0); /* 2A4 */
+ tw_writeb(TW68_CKILL, 0x68); /* 2A8 Mfg specified reset val */
+ tw_writeb(TW68_COMB, 0x44); /* 2AC Mfg specified reset val */
+ tw_writeb(TW68_LDLY, 0x30); /* 2B0 Max positive luma delay */
+ tw_writeb(TW68_MISC1, 0x14); /* 2B4 Mfg specified reset val */
+ tw_writeb(TW68_LOOP, 0xa5); /* 2B8 Mfg specified reset val */
+ tw_writeb(TW68_MISC2, 0xe0); /* 2BC Enable colour killer */
+ tw_writeb(TW68_MVSN, 0); /* 2C0 */
+ tw_writeb(TW68_CLMD, 0x05); /* 2CC slice level auto, clamp med. */
+ tw_writeb(TW68_IDCNTL, 0); /* 2D0 Writing zero to this register
+ * selects NTSC ID detection,
+ * but doesn't change the
+ * sensitivity (which has a reset
+ * value of 1E). Since we are
+ * not doing auto-detection, it
+ * has no real effect */
+ tw_writeb(TW68_CLCNTL1, 0); /* 2D4 */
+ tw_writel(TW68_VBIC, 0x03); /* 010 */
+ tw_writel(TW68_CAP_CTL, 0x03); /* 040 Enable both even & odd flds */
+ tw_writel(TW68_DMAC, 0x2000); /* patch set had 0x2080 */
+ tw_writel(TW68_TESTREG, 0); /* 02C */
+
+ /*
+ * Some common boards, especially inexpensive single-chip models,
+ * use the GPIO bits 0-3 to control an on-board video-output mux.
+ * For these boards, we need to set up the GPIO register into
+ * "normal" mode, set bits 0-3 as output, and then set those bits
+ * zero.
+ *
+ * Eventually, it would be nice if we could identify these boards
+ * uniquely, and only do this initialisation if the board has been
+ * identify. For the moment, however, it shouldn't hurt anything
+ * to do these steps.
+ */
+ tw_writel(TW68_GPIOC, 0); /* Set the GPIO to "normal", no ints */
+ tw_writel(TW68_GPOE, 0x0f); /* Set bits 0-3 to "output" */
+ tw_writel(TW68_GPDATA, 0); /* Set all bits to low state */
+
+ /* Initialize the device control structures */
+ mutex_init(&dev->lock);
+ spin_lock_init(&dev->slock);
+
+ /* Initialize any subsystems */
+ tw68_video_init1(dev);
+ return 0;
+}
+
+static irqreturn_t tw68_irq(int irq, void *dev_id)
+{
+ struct tw68_dev *dev = dev_id;
+ u32 status, orig;
+ int loop;
+
+ status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+ /* Check if anything to do */
+ if (0 == status)
+ return IRQ_NONE; /* Nope - return */
+ for (loop = 0; loop < 10; loop++) {
+ if (status & dev->board_virqmask) /* video interrupt */
+ tw68_irq_video_done(dev, status);
+ status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
+ if (0 == status)
+ return IRQ_HANDLED;
+ }
+ dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)",
+ dev->name, orig, tw_readl(TW68_INTSTAT));
+ dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n",
+ dev->name, dev->pci_irqmask, dev->board_virqmask);
+ tw_clearl(TW68_INTMASK, dev->pci_irqmask);
+ return IRQ_HANDLED;
+}
+
+static int tw68_initdev(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct tw68_dev *dev;
+ int vidnr = -1;
+ int err;
+
+ dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL);
+ if (NULL == dev)
+ return -ENOMEM;
+
+ dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68",
+ &tw68_instance);
+
+ err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
+ if (err)
+ return err;
+
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+ goto fail1;
+ }
+
+ dev->name = dev->v4l2_dev.name;
+
+ if (UNSET != latency) {
+ pr_info("%s: setting pci latency timer to %d\n",
+ dev->name, latency);
+ pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
+ }
+
+ /* print pci info */
+ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",
+ dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+ dev->pci_lat, (u64)pci_resource_start(pci_dev, 0));
+ pci_set_master(pci_dev);
+ if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) {
+ pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
+ err = -EIO;
+ goto fail1;
+ }
+
+ switch (pci_id->device) {
+ case PCI_DEVICE_ID_6800: /* TW6800 */
+ dev->vdecoder = TW6800;
+ dev->board_virqmask = TW68_VID_INTS;
+ break;
+ case PCI_DEVICE_ID_6801: /* Video decoder for TW6802 */
+ dev->vdecoder = TW6801;
+ dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+ break;
+ case PCI_DEVICE_ID_6804: /* Video decoder for TW6804 */
+ dev->vdecoder = TW6804;
+ dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+ break;
+ default:
+ dev->vdecoder = TWXXXX; /* To be announced */
+ dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
+ break;
+ }
+
+ /* get mmio */
+ if (!request_mem_region(pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0),
+ dev->name)) {
+ err = -EBUSY;
+ pr_err("%s: can't get MMIO memory @ 0x%llx\n",
+ dev->name,
+ (unsigned long long)pci_resource_start(pci_dev, 0));
+ goto fail1;
+ }
+ dev->lmmio = ioremap(pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+ dev->bmmio = (__u8 __iomem *)dev->lmmio;
+ if (NULL == dev->lmmio) {
+ err = -EIO;
+ pr_err("%s: can't ioremap() MMIO memory\n",
+ dev->name);
+ goto fail2;
+ }
+ /* initialize hardware #1 */
+ /* Then do any initialisation wanted before interrupts are on */
+ tw68_hw_init1(dev);
+
+ /* get irq */
+ err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq,
+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+ if (err < 0) {
+ pr_err("%s: can't get IRQ %d\n",
+ dev->name, pci_dev->irq);
+ goto fail3;
+ }
+
+ /*
+ * Now do remainder of initialisation, first for
+ * things unique for this card, then for general board
+ */
+ if (dev->instance < TW68_MAXBOARDS)
+ vidnr = video_nr[dev->instance];
+ /* initialise video function first */
+ err = tw68_video_init2(dev, vidnr);
+ if (err < 0) {
+ pr_err("%s: can't register video device\n",
+ dev->name);
+ goto fail4;
+ }
+ tw_setl(TW68_INTMASK, dev->pci_irqmask);
+
+ pr_info("%s: registered device %s\n",
+ dev->name, video_device_node_name(&dev->vdev));
+
+ return 0;
+
+fail4:
+ video_unregister_device(&dev->vdev);
+fail3:
+ iounmap(dev->lmmio);
+fail2:
+ release_mem_region(pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+fail1:
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return err;
+}
+
+static void tw68_finidev(struct pci_dev *pci_dev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct tw68_dev *dev =
+ container_of(v4l2_dev, struct tw68_dev, v4l2_dev);
+
+ /* shutdown subsystems */
+ tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+ tw_writel(TW68_INTMASK, 0);
+
+ /* unregister */
+ video_unregister_device(&dev->vdev);
+ v4l2_ctrl_handler_free(&dev->hdl);
+
+ /* release resources */
+ iounmap(dev->lmmio);
+ release_mem_region(pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+}
+
+#ifdef CONFIG_PM
+
+static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct tw68_dev *dev = container_of(v4l2_dev,
+ struct tw68_dev, v4l2_dev);
+
+ tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+ dev->pci_irqmask &= ~TW68_VID_INTS;
+ tw_writel(TW68_INTMASK, 0);
+
+ synchronize_irq(pci_dev->irq);
+
+ pci_save_state(pci_dev);
+ pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+ vb2_discard_done(&dev->vidq);
+
+ return 0;
+}
+
+static int tw68_resume(struct pci_dev *pci_dev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct tw68_dev *dev = container_of(v4l2_dev,
+ struct tw68_dev, v4l2_dev);
+ struct tw68_buf *buf;
+ unsigned long flags;
+
+ pci_set_power_state(pci_dev, PCI_D0);
+ pci_restore_state(pci_dev);
+
+ /* Do things that are done in tw68_initdev ,
+ except of initializing memory structures.*/
+
+ msleep(100);
+
+ tw68_set_tvnorm_hw(dev);
+
+ /*resume unfinished buffer(s)*/
+ spin_lock_irqsave(&dev->slock, flags);
+ buf = container_of(dev->active.next, struct tw68_buf, list);
+
+ tw68_video_start_dma(dev, buf);
+
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+
+static struct pci_driver tw68_pci_driver = {
+ .name = "tw68",
+ .id_table = tw68_pci_tbl,
+ .probe = tw68_initdev,
+ .remove = tw68_finidev,
+#ifdef CONFIG_PM
+ .suspend = tw68_suspend,
+ .resume = tw68_resume
+#endif
+};
+
+module_pci_driver(tw68_pci_driver);
diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h
new file mode 100644
index 000000000000..f60b3a896fa7
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-reg.h
@@ -0,0 +1,195 @@
+/*
+ * tw68-reg.h - TW68xx register offsets
+ *
+ * Much of this code is derived from the cx88 and sa7134 drivers, which
+ * were in turn derived from the bt87x driver. The original work was by
+ * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ * Hans Verkuil, Andy Walls and many others. Their work is gratefully
+ * acknowledged. Full credit goes to them - any problems within this code
+ * are mine.
+ *
+ * Copyright (C) William M. Brack
+ *
+ * Refactored and updated to the latest v4l core frameworks:
+ *
+ * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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.
+*/
+
+#ifndef _TW68_REG_H_
+#define _TW68_REG_H_
+
+/* ---------------------------------------------------------------------- */
+#define TW68_DMAC 0x000
+#define TW68_DMAP_SA 0x004
+#define TW68_DMAP_EXE 0x008
+#define TW68_DMAP_PP 0x00c
+#define TW68_VBIC 0x010
+#define TW68_SBUSC 0x014
+#define TW68_SBUSSD 0x018
+#define TW68_INTSTAT 0x01C
+#define TW68_INTMASK 0x020
+#define TW68_GPIOC 0x024
+#define TW68_GPOE 0x028
+#define TW68_TESTREG 0x02C
+#define TW68_SBUSRD 0x030
+#define TW68_SBUS_TRIG 0x034
+#define TW68_CAP_CTL 0x040
+#define TW68_SUBSYS 0x054
+#define TW68_I2C_RST 0x064
+#define TW68_VBIINST 0x06C
+/* define bits in FIFO and DMAP Control reg */
+#define TW68_DMAP_EN (1 << 0)
+#define TW68_FIFO_EN (1 << 1)
+/* define the Interrupt Status Register bits */
+#define TW68_SBDONE (1 << 0)
+#define TW68_DMAPI (1 << 1)
+#define TW68_GPINT (1 << 2)
+#define TW68_FFOF (1 << 3)
+#define TW68_FDMIS (1 << 4)
+#define TW68_DMAPERR (1 << 5)
+#define TW68_PABORT (1 << 6)
+#define TW68_SBDONE2 (1 << 12)
+#define TW68_SBERR2 (1 << 13)
+#define TW68_PPERR (1 << 14)
+#define TW68_FFERR (1 << 15)
+#define TW68_DET50 (1 << 16)
+#define TW68_FLOCK (1 << 17)
+#define TW68_CCVALID (1 << 18)
+#define TW68_VLOCK (1 << 19)
+#define TW68_FIELD (1 << 20)
+#define TW68_SLOCK (1 << 21)
+#define TW68_HLOCK (1 << 22)
+#define TW68_VDLOSS (1 << 23)
+#define TW68_SBERR (1 << 24)
+/* define the i2c control register bits */
+#define TW68_SBMODE (0)
+#define TW68_WREN (1)
+#define TW68_SSCLK (6)
+#define TW68_SSDAT (7)
+#define TW68_SBCLK (8)
+#define TW68_WDLEN (16)
+#define TW68_RDLEN (20)
+#define TW68_SBRW (24)
+#define TW68_SBDEV (25)
+
+#define TW68_SBMODE_B (1 << TW68_SBMODE)
+#define TW68_WREN_B (1 << TW68_WREN)
+#define TW68_SSCLK_B (1 << TW68_SSCLK)
+#define TW68_SSDAT_B (1 << TW68_SSDAT)
+#define TW68_SBRW_B (1 << TW68_SBRW)
+
+#define TW68_GPDATA 0x100
+#define TW68_STATUS1 0x204
+#define TW68_INFORM 0x208
+#define TW68_OPFORM 0x20C
+#define TW68_HSYNC 0x210
+#define TW68_ACNTL 0x218
+#define TW68_CROP_HI 0x21C
+#define TW68_VDELAY_LO 0x220
+#define TW68_VACTIVE_LO 0x224
+#define TW68_HDELAY_LO 0x228
+#define TW68_HACTIVE_LO 0x22C
+#define TW68_CNTRL1 0x230
+#define TW68_VSCALE_LO 0x234
+#define TW68_SCALE_HI 0x238
+#define TW68_HSCALE_LO 0x23C
+#define TW68_BRIGHT 0x240
+#define TW68_CONTRAST 0x244
+#define TW68_SHARPNESS 0x248
+#define TW68_SAT_U 0x24C
+#define TW68_SAT_V 0x250
+#define TW68_HUE 0x254
+#define TW68_SHARP2 0x258
+#define TW68_VSHARP 0x25C
+#define TW68_CORING 0x260
+#define TW68_VBICNTL 0x264
+#define TW68_CNTRL2 0x268
+#define TW68_CC_DATA 0x26C
+#define TW68_SDT 0x270
+#define TW68_SDTR 0x274
+#define TW68_RESERV2 0x278
+#define TW68_RESERV3 0x27C
+#define TW68_CLMPG 0x280
+#define TW68_IAGC 0x284
+#define TW68_AGCGAIN 0x288
+#define TW68_PEAKWT 0x28C
+#define TW68_CLMPL 0x290
+#define TW68_SYNCT 0x294
+#define TW68_MISSCNT 0x298
+#define TW68_PCLAMP 0x29C
+#define TW68_VCNTL1 0x2A0
+#define TW68_VCNTL2 0x2A4
+#define TW68_CKILL 0x2A8
+#define TW68_COMB 0x2AC
+#define TW68_LDLY 0x2B0
+#define TW68_MISC1 0x2B4
+#define TW68_LOOP 0x2B8
+#define TW68_MISC2 0x2BC
+#define TW68_MVSN 0x2C0
+#define TW68_STATUS2 0x2C4
+#define TW68_HFREF 0x2C8
+#define TW68_CLMD 0x2CC
+#define TW68_IDCNTL 0x2D0
+#define TW68_CLCNTL1 0x2D4
+
+/* Audio */
+#define TW68_ACKI1 0x300
+#define TW68_ACKI2 0x304
+#define TW68_ACKI3 0x308
+#define TW68_ACKN1 0x30C
+#define TW68_ACKN2 0x310
+#define TW68_ACKN3 0x314
+#define TW68_SDIV 0x318
+#define TW68_LRDIV 0x31C
+#define TW68_ACCNTL 0x320
+
+#define TW68_VSCTL 0x3B8
+#define TW68_CHROMAGVAL 0x3BC
+
+#define TW68_F2CROP_HI 0x3DC
+#define TW68_F2VDELAY_LO 0x3E0
+#define TW68_F2VACTIVE_LO 0x3E4
+#define TW68_F2HDELAY_LO 0x3E8
+#define TW68_F2HACTIVE_LO 0x3EC
+#define TW68_F2CNT 0x3F0
+#define TW68_F2VSCALE_LO 0x3F4
+#define TW68_F2SCALE_HI 0x3F8
+#define TW68_F2HSCALE_LO 0x3FC
+
+#define RISC_INT_BIT 0x08000000
+#define RISC_SYNCO 0xC0000000
+#define RISC_SYNCE 0xD0000000
+#define RISC_JUMP 0xB0000000
+#define RISC_LINESTART 0x90000000
+#define RISC_INLINE 0xA0000000
+
+#define VideoFormatNTSC 0
+#define VideoFormatNTSCJapan 0
+#define VideoFormatPALBDGHI 1
+#define VideoFormatSECAM 2
+#define VideoFormatNTSC443 3
+#define VideoFormatPALM 4
+#define VideoFormatPALN 5
+#define VideoFormatPALNC 5
+#define VideoFormatPAL60 6
+#define VideoFormatAuto 7
+
+#define ColorFormatRGB32 0x00
+#define ColorFormatRGB24 0x10
+#define ColorFormatRGB16 0x20
+#define ColorFormatRGB15 0x30
+#define ColorFormatYUY2 0x40
+#define ColorFormatBSWAP 0x04
+#define ColorFormatWSWAP 0x08
+#define ColorFormatGamma 0x80
+#endif
diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c
new file mode 100644
index 000000000000..7439db212a69
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-risc.c
@@ -0,0 +1,230 @@
+/*
+ * tw68_risc.c
+ * Part of the device driver for Techwell 68xx based cards
+ *
+ * Much of this code is derived from the cx88 and sa7134 drivers, which
+ * were in turn derived from the bt87x driver. The original work was by
+ * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ * Hans Verkuil, Andy Walls and many others. Their work is gratefully
+ * acknowledged. Full credit goes to them - any problems within this code
+ * are mine.
+ *
+ * Copyright (C) 2009 William M. Brack
+ *
+ * Refactored and updated to the latest v4l core frameworks:
+ *
+ * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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.
+ */
+
+#include "tw68.h"
+
+/**
+ * @rp pointer to current risc program position
+ * @sglist pointer to "scatter-gather list" of buffer pointers
+ * @offset offset to target memory buffer
+ * @sync_line 0 -> no sync, 1 -> odd sync, 2 -> even sync
+ * @bpl number of bytes per scan line
+ * @padding number of bytes of padding to add
+ * @lines number of lines in field
+ * @jump insert a jump at the start
+ */
+static __le32 *tw68_risc_field(__le32 *rp, struct scatterlist *sglist,
+ unsigned int offset, u32 sync_line,
+ unsigned int bpl, unsigned int padding,
+ unsigned int lines, bool jump)
+{
+ struct scatterlist *sg;
+ unsigned int line, todo, done;
+
+ if (jump) {
+ *(rp++) = cpu_to_le32(RISC_JUMP);
+ *(rp++) = 0;
+ }
+
+ /* sync instruction */
+ if (sync_line == 1)
+ *(rp++) = cpu_to_le32(RISC_SYNCO);
+ else
+ *(rp++) = cpu_to_le32(RISC_SYNCE);
+ *(rp++) = 0;
+
+ /* scan lines */
+ sg = sglist;
+ for (line = 0; line < lines; line++) {
+ /* calculate next starting position */
+ while (offset && offset >= sg_dma_len(sg)) {
+ offset -= sg_dma_len(sg);
+ sg = sg_next(sg);
+ }
+ if (bpl <= sg_dma_len(sg) - offset) {
+ /* fits into current chunk */
+ *(rp++) = cpu_to_le32(RISC_LINESTART |
+ /* (offset<<12) |*/ bpl);
+ *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+ offset += bpl;
+ } else {
+ /*
+ * scanline needs to be split. Put the start in
+ * whatever memory remains using RISC_LINESTART,
+ * then the remainder into following addresses
+ * given by the scatter-gather list.
+ */
+ todo = bpl; /* one full line to be done */
+ /* first fragment */
+ done = (sg_dma_len(sg) - offset);
+ *(rp++) = cpu_to_le32(RISC_LINESTART |
+ (7 << 24) |
+ done);
+ *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset);
+ todo -= done;
+ sg = sg_next(sg);
+ /* succeeding fragments have no offset */
+ while (todo > sg_dma_len(sg)) {
+ *(rp++) = cpu_to_le32(RISC_INLINE |
+ (done << 12) |
+ sg_dma_len(sg));
+ *(rp++) = cpu_to_le32(sg_dma_address(sg));
+ todo -= sg_dma_len(sg);
+ sg = sg_next(sg);
+ done += sg_dma_len(sg);
+ }
+ if (todo) {
+ /* final chunk - offset 0, count 'todo' */
+ *(rp++) = cpu_to_le32(RISC_INLINE |
+ (done << 12) |
+ todo);
+ *(rp++) = cpu_to_le32(sg_dma_address(sg));
+ }
+ offset = todo;
+ }
+ offset += padding;
+ }
+
+ return rp;
+}
+
+/**
+ * tw68_risc_buffer
+ *
+ * This routine is called by tw68-video. It allocates
+ * memory for the dma controller "program" and then fills in that
+ * memory with the appropriate "instructions".
+ *
+ * @pci_dev structure with info about the pci
+ * slot which our device is in.
+ * @risc structure with info about the memory
+ * used for our controller program.
+ * @sglist scatter-gather list entry
+ * @top_offset offset within the risc program area for the
+ * first odd frame line
+ * @bottom_offset offset within the risc program area for the
+ * first even frame line
+ * @bpl number of data bytes per scan line
+ * @padding number of extra bytes to add at end of line
+ * @lines number of scan lines
+ */
+int tw68_risc_buffer(struct pci_dev *pci,
+ struct tw68_buf *buf,
+ struct scatterlist *sglist,
+ unsigned int top_offset,
+ unsigned int bottom_offset,
+ unsigned int bpl,
+ unsigned int padding,
+ unsigned int lines)
+{
+ u32 instructions, fields;
+ __le32 *rp;
+
+ fields = 0;
+ if (UNSET != top_offset)
+ fields++;
+ if (UNSET != bottom_offset)
+ fields++;
+ /*
+ * estimate risc mem: worst case is one write per page border +
+ * one write per scan line + syncs + 2 jumps (all 2 dwords).
+ * Padding can cause next bpl to start close to a page border.
+ * First DMA region may be smaller than PAGE_SIZE
+ */
+ instructions = fields * (1 + (((bpl + padding) * lines) /
+ PAGE_SIZE) + lines) + 4;
+ buf->size = instructions * 8;
+ buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma);
+ if (buf->cpu == NULL)
+ return -ENOMEM;
+
+ /* write risc instructions */
+ rp = buf->cpu;
+ if (UNSET != top_offset) /* generates SYNCO */
+ rp = tw68_risc_field(rp, sglist, top_offset, 1,
+ bpl, padding, lines, true);
+ if (UNSET != bottom_offset) /* generates SYNCE */
+ rp = tw68_risc_field(rp, sglist, bottom_offset, 2,
+ bpl, padding, lines, top_offset == UNSET);
+
+ /* save pointer to jmp instruction address */
+ buf->jmp = rp;
+ buf->cpu[1] = cpu_to_le32(buf->dma + 8);
+ /* assure risc buffer hasn't overflowed */
+ BUG_ON((buf->jmp - buf->cpu + 2) * sizeof(buf->cpu[0]) > buf->size);
+ return 0;
+}
+
+#if 0
+/* ------------------------------------------------------------------ */
+/* debug helper code */
+
+static void tw68_risc_decode(u32 risc, u32 addr)
+{
+#define RISC_OP(reg) (((reg) >> 28) & 7)
+ static struct instr_details {
+ char *name;
+ u8 has_data_type;
+ u8 has_byte_info;
+ u8 has_addr;
+ } instr[8] = {
+ [RISC_OP(RISC_SYNCO)] = {"syncOdd", 0, 0, 0},
+ [RISC_OP(RISC_SYNCE)] = {"syncEven", 0, 0, 0},
+ [RISC_OP(RISC_JUMP)] = {"jump", 0, 0, 1},
+ [RISC_OP(RISC_LINESTART)] = {"lineStart", 1, 1, 1},
+ [RISC_OP(RISC_INLINE)] = {"inline", 1, 1, 1},
+ };
+ u32 p;
+
+ p = RISC_OP(risc);
+ if (!(risc & 0x80000000) || !instr[p].name) {
+ pr_debug("0x%08x [ INVALID ]\n", risc);
+ return;
+ }
+ pr_debug("0x%08x %-9s IRQ=%d",
+ risc, instr[p].name, (risc >> 27) & 1);
+ if (instr[p].has_data_type)
+ pr_debug(" Type=%d", (risc >> 24) & 7);
+ if (instr[p].has_byte_info)
+ pr_debug(" Start=0x%03x Count=%03u",
+ (risc >> 12) & 0xfff, risc & 0xfff);
+ if (instr[p].has_addr)
+ pr_debug(" StartAddr=0x%08x", addr);
+ pr_debug("\n");
+}
+
+void tw68_risc_program_dump(struct tw68_core *core, struct tw68_buf *buf)
+{
+ const __le32 *addr;
+
+ pr_debug("%s: risc_program_dump: risc=%p, buf->cpu=0x%p, buf->jmp=0x%p\n",
+ core->name, buf, buf->cpu, buf->jmp);
+ for (addr = buf->cpu; addr <= buf->jmp; addr += 2)
+ tw68_risc_decode(*addr, *(addr+1));
+}
+#endif
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
new file mode 100644
index 000000000000..5c94ac7c88d9
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -0,0 +1,1051 @@
+/*
+ * tw68 functions to handle video data
+ *
+ * Much of this code is derived from the cx88 and sa7134 drivers, which
+ * were in turn derived from the bt87x driver. The original work was by
+ * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ * Hans Verkuil, Andy Walls and many others. Their work is gratefully
+ * acknowledged. Full credit goes to them - any problems within this code
+ * are mine.
+ *
+ * Copyright (C) 2009 William M. Brack
+ *
+ * Refactored and updated to the latest v4l core frameworks:
+ *
+ * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68.h"
+#include "tw68-reg.h"
+
+/* ------------------------------------------------------------------ */
+/* data structs for video */
+/*
+ * FIXME -
+ * Note that the saa7134 has formats, e.g. YUV420, which are classified
+ * as "planar". These affect overlay mode, and are flagged with a field
+ * ".planar" in the format. Do we need to implement this in this driver?
+ */
+static const struct tw68_format formats[] = {
+ {
+ .name = "15 bpp RGB, le",
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .depth = 16,
+ .twformat = ColorFormatRGB15,
+ }, {
+ .name = "15 bpp RGB, be",
+ .fourcc = V4L2_PIX_FMT_RGB555X,
+ .depth = 16,
+ .twformat = ColorFormatRGB15 | ColorFormatBSWAP,
+ }, {
+ .name = "16 bpp RGB, le",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ .twformat = ColorFormatRGB16,
+ }, {
+ .name = "16 bpp RGB, be",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = 16,
+ .twformat = ColorFormatRGB16 | ColorFormatBSWAP,
+ }, {
+ .name = "24 bpp RGB, le",
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .depth = 24,
+ .twformat = ColorFormatRGB24,
+ }, {
+ .name = "24 bpp RGB, be",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .depth = 24,
+ .twformat = ColorFormatRGB24 | ColorFormatBSWAP,
+ }, {
+ .name = "32 bpp RGB, le",
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .depth = 32,
+ .twformat = ColorFormatRGB32,
+ }, {
+ .name = "32 bpp RGB, be",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ .twformat = ColorFormatRGB32 | ColorFormatBSWAP |
+ ColorFormatWSWAP,
+ }, {
+ .name = "4:2:2 packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .twformat = ColorFormatYUY2,
+ }, {
+ .name = "4:2:2 packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ .twformat = ColorFormatYUY2 | ColorFormatBSWAP,
+ }
+};
+#define FORMATS ARRAY_SIZE(formats)
+
+#define NORM_625_50 \
+ .h_delay = 3, \
+ .h_delay0 = 133, \
+ .h_start = 0, \
+ .h_stop = 719, \
+ .v_delay = 24, \
+ .vbi_v_start_0 = 7, \
+ .vbi_v_stop_0 = 22, \
+ .video_v_start = 24, \
+ .video_v_stop = 311, \
+ .vbi_v_start_1 = 319
+
+#define NORM_525_60 \
+ .h_delay = 8, \
+ .h_delay0 = 138, \
+ .h_start = 0, \
+ .h_stop = 719, \
+ .v_delay = 22, \
+ .vbi_v_start_0 = 10, \
+ .vbi_v_stop_0 = 21, \
+ .video_v_start = 22, \
+ .video_v_stop = 262, \
+ .vbi_v_start_1 = 273
+
+/*
+ * The following table is searched by tw68_s_std, first for a specific
+ * match, then for an entry which contains the desired id. The table
+ * entries should therefore be ordered in ascending order of specificity.
+ */
+static const struct tw68_tvnorm tvnorms[] = {
+ {
+ .name = "PAL", /* autodetect */
+ .id = V4L2_STD_PAL,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x81,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+ .format = VideoFormatPALBDGHI,
+ }, {
+ .name = "NTSC",
+ .id = V4L2_STD_NTSC,
+ NORM_525_60,
+
+ .sync_control = 0x59,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x89,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x0e,
+ .vgate_misc = 0x18,
+ .format = VideoFormatNTSC,
+ }, {
+ .name = "SECAM",
+ .id = V4L2_STD_SECAM,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+ .format = VideoFormatSECAM,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ NORM_525_60,
+
+ .sync_control = 0x59,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0xb9,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x0e,
+ .vgate_misc = 0x18,
+ .format = VideoFormatPALM,
+ }, {
+ .name = "PAL-Nc",
+ .id = V4L2_STD_PAL_Nc,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0xa1,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+ .format = VideoFormatPALNC,
+ }, {
+ .name = "PAL-60",
+ .id = V4L2_STD_PAL_60,
+ .h_delay = 186,
+ .h_start = 0,
+ .h_stop = 719,
+ .v_delay = 26,
+ .video_v_start = 23,
+ .video_v_stop = 262,
+ .vbi_v_start_0 = 10,
+ .vbi_v_stop_0 = 21,
+ .vbi_v_start_1 = 273,
+
+ .sync_control = 0x18,
+ .luma_control = 0x40,
+ .chroma_ctrl1 = 0x81,
+ .chroma_gain = 0x2a,
+ .chroma_ctrl2 = 0x06,
+ .vgate_misc = 0x1c,
+ .format = VideoFormatPAL60,
+ }
+};
+#define TVNORMS ARRAY_SIZE(tvnorms)
+
+static const struct tw68_format *format_by_fourcc(unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < FORMATS; i++)
+ if (formats[i].fourcc == fourcc)
+ return formats+i;
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------ */
+/*
+ * Note that the cropping rectangles are described in terms of a single
+ * frame, i.e. line positions are only 1/2 the interlaced equivalent
+ */
+static void set_tvnorm(struct tw68_dev *dev, const struct tw68_tvnorm *norm)
+{
+ if (norm != dev->tvnorm) {
+ dev->width = 720;
+ dev->height = (norm->id & V4L2_STD_525_60) ? 480 : 576;
+ dev->tvnorm = norm;
+ tw68_set_tvnorm_hw(dev);
+ }
+}
+
+/*
+ * tw68_set_scale
+ *
+ * Scaling and Cropping for video decoding
+ *
+ * We are working with 3 values for horizontal and vertical - scale,
+ * delay and active.
+ *
+ * HACTIVE represent the actual number of pixels in the "usable" image,
+ * before scaling. HDELAY represents the number of pixels skipped
+ * between the start of the horizontal sync and the start of the image.
+ * HSCALE is calculated using the formula
+ * HSCALE = (HACTIVE / (#pixels desired)) * 256
+ *
+ * The vertical registers are similar, except based upon the total number
+ * of lines in the image, and the first line of the image (i.e. ignoring
+ * vertical sync and VBI).
+ *
+ * Note that the number of bytes reaching the FIFO (and hence needing
+ * to be processed by the DMAP program) is completely dependent upon
+ * these values, especially HSCALE.
+ *
+ * Parameters:
+ * @dev pointer to the device structure, needed for
+ * getting current norm (as well as debug print)
+ * @width actual image width (from user buffer)
+ * @height actual image height
+ * @field indicates Top, Bottom or Interlaced
+ */
+static int tw68_set_scale(struct tw68_dev *dev, unsigned int width,
+ unsigned int height, enum v4l2_field field)
+{
+ const struct tw68_tvnorm *norm = dev->tvnorm;
+ /* set individually for debugging clarity */
+ int hactive, hdelay, hscale;
+ int vactive, vdelay, vscale;
+ int comb;
+
+ if (V4L2_FIELD_HAS_BOTH(field)) /* if field is interlaced */
+ height /= 2; /* we must set for 1-frame */
+
+ pr_debug("%s: width=%d, height=%d, both=%d\n"
+ " tvnorm h_delay=%d, h_start=%d, h_stop=%d, "
+ "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__,
+ width, height, V4L2_FIELD_HAS_BOTH(field),
+ norm->h_delay, norm->h_start, norm->h_stop,
+ norm->v_delay, norm->video_v_start,
+ norm->video_v_stop);
+
+ switch (dev->vdecoder) {
+ case TW6800:
+ hdelay = norm->h_delay0;
+ break;
+ default:
+ hdelay = norm->h_delay;
+ break;
+ }
+
+ hdelay += norm->h_start;
+ hactive = norm->h_stop - norm->h_start + 1;
+
+ hscale = (hactive * 256) / (width);
+
+ vdelay = norm->v_delay;
+ vactive = ((norm->id & V4L2_STD_525_60) ? 524 : 624) / 2 - norm->video_v_start;
+ vscale = (vactive * 256) / height;
+
+ pr_debug("%s: %dx%d [%s%s,%s]\n", __func__,
+ width, height,
+ V4L2_FIELD_HAS_TOP(field) ? "T" : "",
+ V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
+ v4l2_norm_to_name(dev->tvnorm->id));
+ pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; "
+ "vactive=%d, vdelay=%d, vscale=%d\n", __func__,
+ hactive, hdelay, hscale, vactive, vdelay, vscale);
+
+ comb = ((vdelay & 0x300) >> 2) |
+ ((vactive & 0x300) >> 4) |
+ ((hdelay & 0x300) >> 6) |
+ ((hactive & 0x300) >> 8);
+ pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, "
+ "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n",
+ __func__, comb, vdelay, vactive, hdelay, hactive);
+ tw_writeb(TW68_CROP_HI, comb);
+ tw_writeb(TW68_VDELAY_LO, vdelay & 0xff);
+ tw_writeb(TW68_VACTIVE_LO, vactive & 0xff);
+ tw_writeb(TW68_HDELAY_LO, hdelay & 0xff);
+ tw_writeb(TW68_HACTIVE_LO, hactive & 0xff);
+
+ comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8);
+ pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, "
+ "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale);
+ tw_writeb(TW68_SCALE_HI, comb);
+ tw_writeb(TW68_VSCALE_LO, vscale);
+ tw_writeb(TW68_HSCALE_LO, hscale);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf)
+{
+ /* Set cropping and scaling */
+ tw68_set_scale(dev, dev->width, dev->height, dev->field);
+ /*
+ * Set start address for RISC program. Note that if the DMAP
+ * processor is currently running, it must be stopped before
+ * a new address can be set.
+ */
+ tw_clearl(TW68_DMAC, TW68_DMAP_EN);
+ tw_writel(TW68_DMAP_SA, buf->dma);
+ /* Clear any pending interrupts */
+ tw_writel(TW68_INTSTAT, dev->board_virqmask);
+ /* Enable the risc engine and the fifo */
+ tw_andorl(TW68_DMAC, 0xff, dev->fmt->twformat |
+ ColorFormatGamma | TW68_DMAP_EN | TW68_FIFO_EN);
+ dev->pci_irqmask |= dev->board_virqmask;
+ tw_setl(TW68_INTMASK, dev->pci_irqmask);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* calc max # of buffers from size (must not exceed the 4MB virtual
+ * address space per DMA channel) */
+static int tw68_buffer_count(unsigned int size, unsigned int count)
+{
+ unsigned int maxcount;
+
+ maxcount = (4 * 1024 * 1024) / roundup(size, PAGE_SIZE);
+ if (count > maxcount)
+ count = maxcount;
+ return count;
+}
+
+/* ------------------------------------------------------------- */
+/* vb2 queue operations */
+
+static int tw68_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct tw68_dev *dev = vb2_get_drv_priv(q);
+ unsigned tot_bufs = q->num_buffers + *num_buffers;
+
+ sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+ /*
+ * We allow create_bufs, but only if the sizeimage is the same as the
+ * current sizeimage. The tw68_buffer_count calculation becomes quite
+ * difficult otherwise.
+ */
+ if (fmt && fmt->fmt.pix.sizeimage < sizes[0])
+ return -EINVAL;
+ *num_planes = 1;
+ if (tot_bufs < 2)
+ tot_bufs = 2;
+ tot_bufs = tw68_buffer_count(sizes[0], tot_bufs);
+ *num_buffers = tot_bufs - q->num_buffers;
+
+ return 0;
+}
+
+/*
+ * The risc program for each buffers works as follows: it starts with a simple
+ * 'JUMP to addr + 8', which is effectively a NOP. Then the program to DMA the
+ * buffer follows and at the end we have a JUMP back to the start + 8 (skipping
+ * the initial JUMP).
+ *
+ * This is the program of the first buffer to be queued if the active list is
+ * empty and it just keeps DMAing this buffer without generating any interrupts.
+ *
+ * If a new buffer is added then the initial JUMP in the program generates an
+ * interrupt as well which signals that the previous buffer has been DMAed
+ * successfully and that it can be returned to userspace.
+ *
+ * It also sets the final jump of the previous buffer to the start of the new
+ * buffer, thus chaining the new buffer into the DMA chain. This is a single
+ * atomic u32 write, so there is no race condition.
+ *
+ * The end-result of all this that you only get an interrupt when a buffer
+ * is ready, so the control flow is very easy.
+ */
+static void tw68_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct tw68_dev *dev = vb2_get_drv_priv(vq);
+ struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+ struct tw68_buf *prev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ /* append a 'JUMP to start of buffer' to the buffer risc program */
+ buf->jmp[0] = cpu_to_le32(RISC_JUMP);
+ buf->jmp[1] = cpu_to_le32(buf->dma + 8);
+
+ if (!list_empty(&dev->active)) {
+ prev = list_entry(dev->active.prev, struct tw68_buf, list);
+ buf->cpu[0] |= cpu_to_le32(RISC_INT_BIT);
+ prev->jmp[1] = cpu_to_le32(buf->dma);
+ }
+ list_add_tail(&buf->list, &dev->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+/*
+ * buffer_prepare
+ *
+ * Set the ancilliary information into the buffer structure. This
+ * includes generating the necessary risc program if it hasn't already
+ * been done for the current buffer format.
+ * The structure fh contains the details of the format requested by the
+ * user - type, width, height and #fields. This is compared with the
+ * last format set for the current buffer. If they differ, the risc
+ * code (which controls the filling of the buffer) is (re-)generated.
+ */
+static int tw68_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct tw68_dev *dev = vb2_get_drv_priv(vq);
+ struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+ unsigned size, bpl;
+ int rc;
+
+ size = (dev->width * dev->height * dev->fmt->depth) >> 3;
+ if (vb2_plane_size(vb, 0) < size)
+ return -EINVAL;
+ vb2_set_plane_payload(vb, 0, size);
+
+ rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+ if (!rc)
+ return -EIO;
+
+ bpl = (dev->width * dev->fmt->depth) >> 3;
+ switch (dev->field) {
+ case V4L2_FIELD_TOP:
+ tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ 0, UNSET, bpl, 0, dev->height);
+ break;
+ case V4L2_FIELD_BOTTOM:
+ tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ UNSET, 0, bpl, 0, dev->height);
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ 0, bpl * (dev->height >> 1),
+ bpl, 0, dev->height >> 1);
+ break;
+ case V4L2_FIELD_SEQ_BT:
+ tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ bpl * (dev->height >> 1), 0,
+ bpl, 0, dev->height >> 1);
+ break;
+ case V4L2_FIELD_INTERLACED:
+ default:
+ tw68_risc_buffer(dev->pci, buf, dma->sgl,
+ 0, bpl, bpl, bpl, dev->height >> 1);
+ break;
+ }
+ return 0;
+}
+
+static void tw68_buf_finish(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct tw68_dev *dev = vb2_get_drv_priv(vq);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
+ struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
+
+ dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+
+ pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma);
+}
+
+static int tw68_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct tw68_dev *dev = vb2_get_drv_priv(q);
+ struct tw68_buf *buf =
+ container_of(dev->active.next, struct tw68_buf, list);
+
+ dev->seqnr = 0;
+ tw68_video_start_dma(dev, buf);
+ return 0;
+}
+
+static void tw68_stop_streaming(struct vb2_queue *q)
+{
+ struct tw68_dev *dev = vb2_get_drv_priv(q);
+
+ /* Stop risc & fifo */
+ tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN);
+ while (!list_empty(&dev->active)) {
+ struct tw68_buf *buf =
+ container_of(dev->active.next, struct tw68_buf, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+}
+
+static struct vb2_ops tw68_video_qops = {
+ .queue_setup = tw68_queue_setup,
+ .buf_queue = tw68_buf_queue,
+ .buf_prepare = tw68_buf_prepare,
+ .buf_finish = tw68_buf_finish,
+ .start_streaming = tw68_start_streaming,
+ .stop_streaming = tw68_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int tw68_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct tw68_dev *dev =
+ container_of(ctrl->handler, struct tw68_dev, hdl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ tw_writeb(TW68_BRIGHT, ctrl->val);
+ break;
+ case V4L2_CID_HUE:
+ tw_writeb(TW68_HUE, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ tw_writeb(TW68_CONTRAST, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ tw_writeb(TW68_SAT_U, ctrl->val);
+ tw_writeb(TW68_SAT_V, ctrl->val);
+ break;
+ case V4L2_CID_COLOR_KILLER:
+ if (ctrl->val)
+ tw_andorb(TW68_MISC2, 0xe0, 0xe0);
+ else
+ tw_andorb(TW68_MISC2, 0xe0, 0x00);
+ break;
+ case V4L2_CID_CHROMA_AGC:
+ if (ctrl->val)
+ tw_andorb(TW68_LOOP, 0x30, 0x20);
+ else
+ tw_andorb(TW68_LOOP, 0x30, 0x00);
+ break;
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+/*
+ * Note that this routine returns what is stored in the fh structure, and
+ * does not interrogate any of the device registers.
+ */
+static int tw68_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = dev->field;
+ f->fmt.pix.pixelformat = dev->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * (dev->fmt->depth)) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+ return 0;
+}
+
+static int tw68_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+ const struct tw68_format *fmt;
+ enum v4l2_field field;
+ unsigned int maxh;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
+
+ field = f->fmt.pix.field;
+ maxh = (dev->tvnorm->id & V4L2_STD_525_60) ? 480 : 576;
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ break;
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_BT:
+ case V4L2_FIELD_SEQ_TB:
+ maxh = maxh * 2;
+ break;
+ default:
+ field = (f->fmt.pix.height > maxh / 2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ break;
+ }
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.width > 720)
+ f->fmt.pix.width = 720;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ f->fmt.pix.width &= ~0x03;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * (fmt->depth)) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ return 0;
+}
+
+/*
+ * Note that tw68_s_fmt_vid_cap sets the information into the fh structure,
+ * and it will be used for all future new buffers. However, there could be
+ * some number of buffers on the "active" chain which will be filled before
+ * the change takes place.
+ */
+static int tw68_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+ int err;
+
+ err = tw68_try_fmt_vid_cap(file, priv, f);
+ if (0 != err)
+ return err;
+
+ dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ dev->field = f->fmt.pix.field;
+ return 0;
+}
+
+static int tw68_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+ unsigned int n;
+
+ n = i->index;
+ if (n >= TW68_INPUT_MAX)
+ return -EINVAL;
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ snprintf(i->name, sizeof(i->name), "Composite %d", n);
+
+ /* If the query is for the current input, get live data */
+ if (n == dev->input) {
+ int v1 = tw_readb(TW68_STATUS1);
+ int v2 = tw_readb(TW68_MVSN);
+
+ if (0 != (v1 & (1 << 7)))
+ i->status |= V4L2_IN_ST_NO_SYNC;
+ if (0 != (v1 & (1 << 6)))
+ i->status |= V4L2_IN_ST_NO_H_LOCK;
+ if (0 != (v1 & (1 << 2)))
+ i->status |= V4L2_IN_ST_NO_SIGNAL;
+ if (0 != (v1 & 1 << 1))
+ i->status |= V4L2_IN_ST_NO_COLOR;
+ if (0 != (v2 & (1 << 2)))
+ i->status |= V4L2_IN_ST_MACROVISION;
+ }
+ i->std = video_devdata(file)->tvnorms;
+ return 0;
+}
+
+static int tw68_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ *i = dev->input;
+ return 0;
+}
+
+static int tw68_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ if (i >= TW68_INPUT_MAX)
+ return -EINVAL;
+ dev->input = i;
+ tw_andorb(TW68_INFORM, 0x03 << 2, dev->input << 2);
+ return 0;
+}
+
+static int tw68_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ strcpy(cap->driver, "tw68");
+ strlcpy(cap->card, "Techwell Capture Card",
+ sizeof(cap->card));
+ sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+ cap->device_caps =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
+}
+
+static int tw68_s_std(struct file *file, void *priv, v4l2_std_id id)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+ unsigned int i;
+
+ if (vb2_is_busy(&dev->vidq))
+ return -EBUSY;
+
+ /* Look for match on complete norm id (may have mult bits) */
+ for (i = 0; i < TVNORMS; i++) {
+ if (id == tvnorms[i].id)
+ break;
+ }
+
+ /* If no exact match, look for norm which contains this one */
+ if (i == TVNORMS) {
+ for (i = 0; i < TVNORMS; i++)
+ if (id & tvnorms[i].id)
+ break;
+ }
+ /* If still not matched, give up */
+ if (i == TVNORMS)
+ return -EINVAL;
+
+ set_tvnorm(dev, &tvnorms[i]); /* do the actual setting */
+ return 0;
+}
+
+static int tw68_g_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ *id = dev->tvnorm->id;
+ return 0;
+}
+
+static int tw68_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index >= FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[f->index].name,
+ sizeof(f->description));
+
+ f->pixelformat = formats[f->index].fourcc;
+
+ return 0;
+}
+
+/*
+ * Used strictly for internal development and debugging, this routine
+ * prints out the current register contents for the tw68xx device.
+ */
+static void tw68_dump_regs(struct tw68_dev *dev)
+{
+ unsigned char line[80];
+ int i, j, k;
+ unsigned char *cptr;
+
+ pr_info("Full dump of TW68 registers:\n");
+ /* First we do the PCI regs, 8 4-byte regs per line */
+ for (i = 0; i < 0x100; i += 32) {
+ cptr = line;
+ cptr += sprintf(cptr, "%03x ", i);
+ /* j steps through the next 4 words */
+ for (j = i; j < i + 16; j += 4)
+ cptr += sprintf(cptr, "%08x ", tw_readl(j));
+ *cptr++ = ' ';
+ for (; j < i + 32; j += 4)
+ cptr += sprintf(cptr, "%08x ", tw_readl(j));
+ *cptr++ = '\n';
+ *cptr = 0;
+ pr_info("%s", line);
+ }
+ /* Next the control regs, which are single-byte, address mod 4 */
+ while (i < 0x400) {
+ cptr = line;
+ cptr += sprintf(cptr, "%03x ", i);
+ /* Print out 4 groups of 4 bytes */
+ for (j = 0; j < 4; j++) {
+ for (k = 0; k < 4; k++) {
+ cptr += sprintf(cptr, "%02x ",
+ tw_readb(i));
+ i += 4;
+ }
+ *cptr++ = ' ';
+ }
+ *cptr++ = '\n';
+ *cptr = 0;
+ pr_info("%s", line);
+ }
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ tw68_dump_regs(dev);
+ return v4l2_ctrl_log_status(file, priv);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ if (reg->size == 1)
+ reg->val = tw_readb(reg->reg);
+ else
+ reg->val = tw_readl(reg->reg);
+ return 0;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+ const struct v4l2_dbg_register *reg)
+{
+ struct tw68_dev *dev = video_drvdata(file);
+
+ if (reg->size == 1)
+ tw_writeb(reg->reg, reg->val);
+ else
+ tw_writel(reg->reg & 0xffff, reg->val);
+ return 0;
+}
+#endif
+
+static const struct v4l2_ctrl_ops tw68_ctrl_ops = {
+ .s_ctrl = tw68_s_ctrl,
+};
+
+static const struct v4l2_file_operations video_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops video_ioctl_ops = {
+ .vidioc_querycap = tw68_querycap,
+ .vidioc_enum_fmt_vid_cap = tw68_enum_fmt_vid_cap,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_s_std = tw68_s_std,
+ .vidioc_g_std = tw68_g_std,
+ .vidioc_enum_input = tw68_enum_input,
+ .vidioc_g_input = tw68_g_input,
+ .vidioc_s_input = tw68_s_input,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_g_fmt_vid_cap = tw68_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = tw68_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = tw68_s_fmt_vid_cap,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+static struct video_device tw68_video_template = {
+ .name = "tw68_video",
+ .fops = &video_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .release = video_device_release_empty,
+ .tvnorms = TW68_NORMS,
+};
+
+/* ------------------------------------------------------------------ */
+/* exported stuff */
+void tw68_set_tvnorm_hw(struct tw68_dev *dev)
+{
+ tw_andorb(TW68_SDT, 0x07, dev->tvnorm->format);
+}
+
+int tw68_video_init1(struct tw68_dev *dev)
+{
+ struct v4l2_ctrl_handler *hdl = &dev->hdl;
+
+ v4l2_ctrl_handler_init(hdl, 6);
+ v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, -128, 127, 1, 20);
+ v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 100);
+ v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 128);
+ /* NTSC only */
+ v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+ V4L2_CID_COLOR_KILLER, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &tw68_ctrl_ops,
+ V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
+ if (hdl->error) {
+ v4l2_ctrl_handler_free(hdl);
+ return hdl->error;
+ }
+ dev->v4l2_dev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
+ return 0;
+}
+
+int tw68_video_init2(struct tw68_dev *dev, int video_nr)
+{
+ int ret;
+
+ set_tvnorm(dev, &tvnorms[0]);
+
+ dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+ dev->width = 720;
+ dev->height = 576;
+ dev->field = V4L2_FIELD_INTERLACED;
+
+ INIT_LIST_HEAD(&dev->active);
+ dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dev->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
+ dev->vidq.ops = &tw68_video_qops;
+ dev->vidq.mem_ops = &vb2_dma_sg_memops;
+ dev->vidq.drv_priv = dev;
+ dev->vidq.gfp_flags = __GFP_DMA32;
+ dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
+ dev->vidq.lock = &dev->lock;
+ dev->vidq.min_buffers_needed = 2;
+ ret = vb2_queue_init(&dev->vidq);
+ if (ret)
+ return ret;
+ dev->vdev = tw68_video_template;
+ dev->vdev.v4l2_dev = &dev->v4l2_dev;
+ dev->vdev.lock = &dev->lock;
+ dev->vdev.queue = &dev->vidq;
+ video_set_drvdata(&dev->vdev, dev);
+ return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+}
+
+/*
+ * tw68_irq_video_done
+ */
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
+{
+ __u32 reg;
+
+ /* reset interrupts handled by this routine */
+ tw_writel(TW68_INTSTAT, status);
+ /*
+ * Check most likely first
+ *
+ * DMAPI shows we have reached the end of the risc code
+ * for the current buffer.
+ */
+ if (status & TW68_DMAPI) {
+ struct tw68_buf *buf;
+
+ spin_lock(&dev->slock);
+ buf = list_entry(dev->active.next, struct tw68_buf, list);
+ list_del(&buf->list);
+ spin_unlock(&dev->slock);
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ buf->vb.v4l2_buf.field = dev->field;
+ buf->vb.v4l2_buf.sequence = dev->seqnr++;
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+ status &= ~(TW68_DMAPI);
+ if (0 == status)
+ return;
+ }
+ if (status & (TW68_VLOCK | TW68_HLOCK))
+ dev_dbg(&dev->pci->dev, "Lost sync\n");
+ if (status & TW68_PABORT)
+ dev_err(&dev->pci->dev, "PABORT interrupt\n");
+ if (status & TW68_DMAPERR)
+ dev_err(&dev->pci->dev, "DMAPERR interrupt\n");
+ /*
+ * On TW6800, FDMIS is apparently generated if video input is switched
+ * during operation. Therefore, it is not enabled for that chip.
+ */
+ if (status & TW68_FDMIS)
+ dev_dbg(&dev->pci->dev, "FDMIS interrupt\n");
+ if (status & TW68_FFOF) {
+ /* probably a logic error */
+ reg = tw_readl(TW68_DMAC) & TW68_FIFO_EN;
+ tw_clearl(TW68_DMAC, TW68_FIFO_EN);
+ dev_dbg(&dev->pci->dev, "FFOF interrupt\n");
+ tw_setl(TW68_DMAC, reg);
+ }
+ if (status & TW68_FFERR)
+ dev_dbg(&dev->pci->dev, "FFERR interrupt\n");
+}
diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h
new file mode 100644
index 000000000000..2c8abe26b13b
--- /dev/null
+++ b/drivers/media/pci/tw68/tw68.h
@@ -0,0 +1,231 @@
+/*
+ * tw68 driver common header file
+ *
+ * Much of this code is derived from the cx88 and sa7134 drivers, which
+ * were in turn derived from the bt87x driver. The original work was by
+ * Gerd Knorr; more recently the code was enhanced by Mauro Carvalho Chehab,
+ * Hans Verkuil, Andy Walls and many others. Their work is gratefully
+ * acknowledged. Full credit goes to them - any problems within this code
+ * are mine.
+ *
+ * Copyright (C) 2009 William M. Brack
+ *
+ * Refactored and updated to the latest v4l core frameworks:
+ *
+ * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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.
+ */
+
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/videodev2.h>
+#include <linux/notifier.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-dma-sg.h>
+
+#include "tw68-reg.h"
+
+#define UNSET (-1U)
+
+/* system vendor and device ID's */
+#define PCI_VENDOR_ID_TECHWELL 0x1797
+#define PCI_DEVICE_ID_6800 0x6800
+#define PCI_DEVICE_ID_6801 0x6801
+#define PCI_DEVICE_ID_AUDIO2 0x6802
+#define PCI_DEVICE_ID_TS3 0x6803
+#define PCI_DEVICE_ID_6804 0x6804
+#define PCI_DEVICE_ID_AUDIO5 0x6805
+#define PCI_DEVICE_ID_TS6 0x6806
+
+/* tw6816 based cards */
+#define PCI_DEVICE_ID_6816_1 0x6810
+#define PCI_DEVICE_ID_6816_2 0x6811
+#define PCI_DEVICE_ID_6816_3 0x6812
+#define PCI_DEVICE_ID_6816_4 0x6813
+
+#define TW68_NORMS ( \
+ V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM | \
+ V4L2_STD_PAL_M | V4L2_STD_PAL_Nc | V4L2_STD_PAL_60)
+
+#define TW68_VID_INTS (TW68_FFERR | TW68_PABORT | TW68_DMAPERR | \
+ TW68_FFOF | TW68_DMAPI)
+/* TW6800 chips have trouble with these, so we don't set them for that chip */
+#define TW68_VID_INTSX (TW68_FDMIS | TW68_HLOCK | TW68_VLOCK)
+
+#define TW68_I2C_INTS (TW68_SBERR | TW68_SBDONE | TW68_SBERR2 | \
+ TW68_SBDONE2)
+
+enum tw68_decoder_type {
+ TW6800,
+ TW6801,
+ TW6804,
+ TWXXXX,
+};
+
+/* ----------------------------------------------------------- */
+/* static data */
+
+struct tw68_tvnorm {
+ char *name;
+ v4l2_std_id id;
+
+ /* video decoder */
+ u32 sync_control;
+ u32 luma_control;
+ u32 chroma_ctrl1;
+ u32 chroma_gain;
+ u32 chroma_ctrl2;
+ u32 vgate_misc;
+
+ /* video scaler */
+ u32 h_delay;
+ u32 h_delay0; /* for TW6800 */
+ u32 h_start;
+ u32 h_stop;
+ u32 v_delay;
+ u32 video_v_start;
+ u32 video_v_stop;
+ u32 vbi_v_start_0;
+ u32 vbi_v_stop_0;
+ u32 vbi_v_start_1;
+
+ /* Techwell specific */
+ u32 format;
+};
+
+struct tw68_format {
+ char *name;
+ u32 fourcc;
+ u32 depth;
+ u32 twformat;
+};
+
+/* ----------------------------------------------------------- */
+/* card configuration */
+
+#define TW68_BOARD_NOAUTO UNSET
+#define TW68_BOARD_UNKNOWN 0
+#define TW68_BOARD_GENERIC_6802 1
+
+#define TW68_MAXBOARDS 16
+#define TW68_INPUT_MAX 4
+
+/* ----------------------------------------------------------- */
+/* device / file handle status */
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+
+struct tw68_dev; /* forward delclaration */
+
+/* buffer for one video/vbi/ts frame */
+struct tw68_buf {
+ struct vb2_buffer vb;
+ struct list_head list;
+
+ unsigned int size;
+ __le32 *cpu;
+ __le32 *jmp;
+ dma_addr_t dma;
+};
+
+struct tw68_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+ int depth;
+ int flags;
+ u32 twformat;
+};
+
+/* global device status */
+struct tw68_dev {
+ struct mutex lock;
+ spinlock_t slock;
+ u16 instance;
+ struct v4l2_device v4l2_dev;
+
+ /* various device info */
+ enum tw68_decoder_type vdecoder;
+ struct video_device vdev;
+ struct v4l2_ctrl_handler hdl;
+
+ /* pci i/o */
+ char *name;
+ struct pci_dev *pci;
+ unsigned char pci_rev, pci_lat;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
+ u32 pci_irqmask;
+ /* The irq mask to be used will depend upon the chip type */
+ u32 board_virqmask;
+
+ /* video capture */
+ const struct tw68_format *fmt;
+ unsigned width, height;
+ unsigned seqnr;
+ unsigned field;
+ struct vb2_queue vidq;
+ struct list_head active;
+
+ /* various v4l controls */
+ const struct tw68_tvnorm *tvnorm; /* video */
+
+ int input;
+};
+
+/* ----------------------------------------------------------- */
+
+#define tw_readl(reg) readl(dev->lmmio + ((reg) >> 2))
+#define tw_readb(reg) readb(dev->bmmio + (reg))
+#define tw_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
+#define tw_writeb(reg, value) writeb((value), dev->bmmio + (reg))
+
+#define tw_andorl(reg, mask, value) \
+ writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+ ((value) & (mask)), dev->lmmio+((reg)>>2))
+#define tw_andorb(reg, mask, value) \
+ writeb((readb(dev->bmmio + (reg)) & ~(mask)) |\
+ ((value) & (mask)), dev->bmmio+(reg))
+#define tw_setl(reg, bit) tw_andorl((reg), (bit), (bit))
+#define tw_setb(reg, bit) tw_andorb((reg), (bit), (bit))
+#define tw_clearl(reg, bit) \
+ writel((readl(dev->lmmio + ((reg) >> 2)) & ~(bit)), \
+ dev->lmmio + ((reg) >> 2))
+#define tw_clearb(reg, bit) \
+ writeb((readb(dev->bmmio+(reg)) & ~(bit)), \
+ dev->bmmio + (reg))
+
+#define tw_wait(us) { udelay(us); }
+
+/* ----------------------------------------------------------- */
+/* tw68-video.c */
+
+void tw68_set_tvnorm_hw(struct tw68_dev *dev);
+
+int tw68_video_init1(struct tw68_dev *dev);
+int tw68_video_init2(struct tw68_dev *dev, int video_nr);
+void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status);
+int tw68_video_start_dma(struct tw68_dev *dev, struct tw68_buf *buf);
+
+/* ----------------------------------------------------------- */
+/* tw68-risc.c */
+
+int tw68_risc_buffer(struct pci_dev *pci, struct tw68_buf *buf,
+ struct scatterlist *sglist, unsigned int top_offset,
+ unsigned int bottom_offset, unsigned int bpl,
+ unsigned int padding, unsigned int lines);
diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c
index bf34b93f23ee..b6801e035ea4 100644
--- a/drivers/media/pci/zoran/zoran_device.c
+++ b/drivers/media/pci/zoran/zoran_device.c
@@ -682,7 +682,7 @@ set_videobus_dir (struct zoran *zr,
switch (zr->card.type) {
case LML33:
case LML33R10:
- if (lml33dpath == 0)
+ if (!lml33dpath)
GPIO(zr, 5, val);
else
GPIO(zr, 5, 1);