summaryrefslogtreecommitdiffstats
path: root/drivers/media/pci/tw68
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2014-09-03 03:36:14 -0300
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-09-04 11:30:53 -0300
commite15d1c12c5878b3a80d6573af1721e17264e0286 (patch)
tree88371b64c975b890d6a49b15b2607bdcab8509dd /drivers/media/pci/tw68
parent5740f4e75f713015067e2667a52bd3b35ef91e07 (diff)
[media] tw68: refactor and cleanup the tw68 driver
Refactor and clean up the tw68 driver. It's now using the proper V4L2 core frameworks. Tested with my Techwell tw6805a and tw6816 grabber boards. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/pci/tw68')
-rw-r--r--drivers/media/pci/tw68/Kconfig10
-rw-r--r--drivers/media/pci/tw68/Makefile3
-rw-r--r--drivers/media/pci/tw68/tw68-cards.c172
-rw-r--r--drivers/media/pci/tw68/tw68-core.c801
-rw-r--r--drivers/media/pci/tw68/tw68-i2c.c245
-rw-r--r--drivers/media/pci/tw68/tw68-reg.h10
-rw-r--r--drivers/media/pci/tw68/tw68-risc.c156
-rw-r--r--drivers/media/pci/tw68/tw68-ts.c66
-rw-r--r--drivers/media/pci/tw68/tw68-tvaudio.c80
-rw-r--r--drivers/media/pci/tw68/tw68-vbi.c76
-rw-r--r--drivers/media/pci/tw68/tw68-video.c1906
-rw-r--r--drivers/media/pci/tw68/tw68.h435
12 files changed, 556 insertions, 3404 deletions
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-cards.c b/drivers/media/pci/tw68/tw68-cards.c
deleted file mode 100644
index 62aec4faa0d1..000000000000
--- a/drivers/media/pci/tw68/tw68-cards.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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 <wbrack@mmm.com.hk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h> /* must appear before i2c-algo-bit.h */
-#include <linux/i2c-algo-bit.h>
-
-#include <media/v4l2-common.h>
-#include <media/tveeprom.h>
-
-#include "tw68.h"
-#include "tw68-reg.h"
-
-/* commly used strings */
-#if 0
-static char name_mute[] = "mute";
-static char name_radio[] = "Radio";
-static char name_tv[] = "Television";
-static char name_tv_mono[] = "TV (mono only)";
-static char name_svideo[] = "S-Video";
-static char name_comp[] = "Composite";
-#endif
-static char name_comp1[] = "Composite1";
-static char name_comp2[] = "Composite2";
-static char name_comp3[] = "Composite3";
-static char name_comp4[] = "Composite4";
-
-/* ------------------------------------------------------------------ */
-/* board config info */
-
-/* If radio_type !=UNSET, radio_addr should be specified
- */
-
-struct tw68_board tw68_boards[] = {
- [TW68_BOARD_UNKNOWN] = {
- .name = "GENERIC",
- .tuner_type = TUNER_ABSENT,
- .radio_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .radio_addr = ADDR_UNSET,
-
- .inputs = {
- {
- .name = name_comp1,
- .vmux = 0,
- }, {
- .name = name_comp2,
- .vmux = 1,
- }, {
- .name = name_comp3,
- .vmux = 2,
- }, {
- .name = name_comp4,
- .vmux = 3,
- }, { /* Must have a NULL entry at end of list */
- .name = NULL,
- .vmux = 0,
- }
- },
- },
-};
-
-const unsigned int tw68_bcount = ARRAY_SIZE(tw68_boards);
-
-/*
- * 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.
- */
-struct pci_device_id tw68_pci_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_TECHWELL,
- .device = PCI_DEVICE_ID_6800,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = TW68_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_TECHWELL,
- .device = PCI_DEVICE_ID_6801,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = TW68_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_TECHWELL,
- .device = PCI_DEVICE_ID_6804,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = TW68_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_TECHWELL,
- .device = PCI_DEVICE_ID_6816_1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = TW68_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_TECHWELL,
- .device = PCI_DEVICE_ID_6816_2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = TW68_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_TECHWELL,
- .device = PCI_DEVICE_ID_6816_3,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = TW68_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_TECHWELL,
- .device = PCI_DEVICE_ID_6816_4,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = TW68_BOARD_UNKNOWN,
- }, {
- /* end of list */
- }
-};
-MODULE_DEVICE_TABLE(pci, tw68_pci_tbl);
-
-/* ------------------------------------------------------------ */
-/* stuff done before i2c enabled */
-int tw68_board_init1(struct tw68_dev *dev)
-{
- /* Clear GPIO outputs */
- tw_writel(TW68_GPOE, 0);
- /* Remainder of setup according to board ID */
- switch (dev->board) {
- case TW68_BOARD_UNKNOWN:
- printk(KERN_INFO "%s: Unable to determine board type, "
- "using generic values\n", dev->name);
- break;
- }
- dev->input = dev->hw_input = &card_in(dev,0);
- return 0;
-}
-
-int tw68_tuner_setup(struct tw68_dev *dev)
-{
- return 0;
-}
-
-/* stuff which needs working i2c */
-int tw68_board_init2(struct tw68_dev *dev)
-{
- return 0;
-}
-
-
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
index 2c5d7a5f3f8e..baf93af1d764 100644
--- a/drivers/media/pci/tw68/tw68-core.c
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -9,7 +9,11 @@
* acknowledged. Full credit goes to them - any problems within this code
* are mine.
*
- * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk>
+ * 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
@@ -20,10 +24,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/init.h>
@@ -44,320 +44,44 @@
#include "tw68-reg.h"
MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards");
-MODULE_AUTHOR("William M. Brack <wbrack@mmm.com.hk>");
+MODULE_AUTHOR("William M. Brack");
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
MODULE_LICENSE("GPL");
-static unsigned int core_debug;
-module_param(core_debug, int, 0644);
-MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
-
-static unsigned int gpio_tracking;
-module_param(gpio_tracking, int, 0644);
-MODULE_PARM_DESC(gpio_tracking, "enable debug messages [gpio]");
-
-static unsigned int alsa = 1;
-module_param(alsa, int, 0644);
-MODULE_PARM_DESC(alsa, "enable/disable ALSA DMA sound [dmasound]");
-
static unsigned int latency = UNSET;
module_param(latency, int, 0444);
MODULE_PARM_DESC(latency, "pci latency timer");
-static unsigned int nocomb;
-module_param(nocomb, int, 0644);
-MODULE_PARM_DESC(nocomb, "disable comb filter");
-
static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
-static unsigned int vbi_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
-static unsigned int tuner[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
-static unsigned int card[] = {[0 ... (TW68_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_param_array(tuner, int, NULL, 0444);
-module_param_array(card, int, NULL, 0444);
-
MODULE_PARM_DESC(video_nr, "video device number");
-MODULE_PARM_DESC(vbi_nr, "vbi device number");
-MODULE_PARM_DESC(radio_nr, "radio device number");
-MODULE_PARM_DESC(tuner, "tuner type");
-MODULE_PARM_DESC(card, "card type");
-
-LIST_HEAD(tw68_devlist);
-EXPORT_SYMBOL(tw68_devlist);
-DEFINE_MUTEX(tw68_devlist_lock);
-EXPORT_SYMBOL(tw68_devlist_lock);
-static LIST_HEAD(mops_list);
-static unsigned int tw68_devcount; /* curr tot num of devices present */
-int (*tw68_dmasound_init)(struct tw68_dev *dev);
-EXPORT_SYMBOL(tw68_dmasound_init);
-int (*tw68_dmasound_exit)(struct tw68_dev *dev);
-EXPORT_SYMBOL(tw68_dmasound_exit);
+static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card, "card type");
-#define dprintk(level, fmt, arg...) if (core_debug & (level)) \
- printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+static atomic_t tw68_instance = ATOMIC_INIT(0);
/* ------------------------------------------------------------------ */
-void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
-
- if (core_debug & DBG_FLOW)
- printk(KERN_DEBUG "%s: called\n", __func__);
- BUG_ON(in_interrupt());
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)
- videobuf_waiton(&buf->vb, 0, 0);
-#else
- videobuf_waiton(q, &buf->vb, 0, 0);
-#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35)
- videobuf_dma_unmap(q, dma);
-#else
- videobuf_dma_unmap(q->dev, dma);
-#endif
- videobuf_dma_free(dma);
- /* if no risc area allocated, btcx_riscmem_free just returns */
- btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-/* ------------------------------------------------------------------ */
-/* ------------- placeholders for later development ----------------- */
-
-static int tw68_input_init1(struct tw68_dev *dev)
-{
- return 0;
-}
-
-static void tw68_input_fini(struct tw68_dev *dev)
-{
- return;
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38)
-static void tw68_ir_start(struct tw68_dev *dev, struct card_ir *ir)
-{
- return;
-}
-
-static void tw68_ir_stop(struct tw68_dev *dev)
-{
- return;
-}
-#endif
-
-/* ------------------------------------------------------------------ */
/*
- * Buffer handling routines
- *
- * These routines are "generic", i.e. are intended to be used by more
- * than one module, e.g. the video and the transport stream modules.
- * To accomplish this generality, callbacks are used whenever some
- * module-specific test or action is required.
+ * 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.
*/
-
-/* resends a current buffer in queue after resume */
-int tw68_buffer_requeue(struct tw68_dev *dev,
- struct tw68_dmaqueue *q)
-{
- struct tw68_buf *buf, *prev;
-
- dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__);
- if (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct tw68_buf, vb.queue);
- dprintk(DBG_BUFF, "%s: [%p/%d] restart dma\n", __func__,
- buf, buf->vb.i);
- q->start_dma(dev, q, buf);
- 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 tw68_buf, vb.queue);
- /* if nothing precedes this one */
- if (NULL == prev) {
- list_move_tail(&buf->vb.queue, &q->active);
- q->start_dma(dev, q, buf);
- buf->activate(dev, buf, NULL);
- dprintk(DBG_BUFF, "%s: [%p/%d] first active\n",
- __func__, buf, buf->vb.i);
-
- } else if (q->buf_compat(prev, buf) &&
- (prev->fmt == buf->fmt)) {
- list_move_tail(&buf->vb.queue, &q->active);
- buf->activate(dev, buf, NULL);
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- dprintk(DBG_BUFF, "%s: [%p/%d] move to active\n",
- __func__, buf, buf->vb.i);
- } else {
- dprintk(DBG_BUFF, "%s: no action taken\n", __func__);
- return 0;
- }
- prev = buf;
- }
-}
-
-/* nr of (tw68-)pages for the given buffer size */
-static int tw68_buffer_pages(int size)
-{
- size = PAGE_ALIGN(size);
- size += PAGE_SIZE; /* for non-page-aligned buffers */
- size /= 4096;
- return size;
-}
-
-/* calc max # of buffers from size (must not exceed the 4MB virtual
- * address space per DMA channel) */
-int tw68_buffer_count(unsigned int size, unsigned int count)
-{
- unsigned int maxcount;
-
- maxcount = 1024 / tw68_buffer_pages(size);
- if (count > maxcount)
- count = maxcount;
- return count;
-}
-
-/*
- * tw68_wakeup
- *
- * Called when the driver completes filling a buffer, and tasks waiting
- * for the data need to be awakened.
- */
-void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *fc)
-{
- struct tw68_dev *dev = q->dev;
- struct tw68_buf *buf;
-
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- if (list_empty(&q->active)) {
- dprintk(DBG_BUFF | DBG_TESTING, "%s: active list empty",
- __func__);
- del_timer(&q->timeout);
- return;
- }
- buf = list_entry(q->active.next, struct tw68_buf, vb.queue);
- do_gettimeofday(&buf->vb.ts);
- buf->vb.field_count = (*fc)++;
- dprintk(DBG_BUFF | DBG_TESTING, "%s: [%p/%d] field_count=%d\n",
- __func__, buf, buf->vb.i, *fc);
- buf->vb.state = VIDEOBUF_DONE;
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
-}
-
-/*
- * tw68_buffer_queue
- *
- * Add specified buffer to specified queue
- */
-void tw68_buffer_queue(struct tw68_dev *dev,
- struct tw68_dmaqueue *q,
- struct tw68_buf *buf)
-{
- struct tw68_buf *prev;
-
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- assert_spin_locked(&dev->slock);
- dprintk(DBG_BUFF, "%s: queuing buffer %p\n", __func__, buf);
-
- /* append a 'JUMP to stopper' to the buffer risc program */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_INT_BIT);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
-
- /* if this buffer is not "compatible" (in dimensions and format)
- * with the currently active chain of buffers, we must change
- * settings before filling it; if a previous buffer has already
- * been determined to require changes, this buffer must follow
- * it. To do this, we maintain a "queued" chain. If that
- * chain exists, append this buffer to it */
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(DBG_BUFF, "%s: [%p/%d] appended to queued\n",
- __func__, buf, buf->vb.i);
-
- /* else if the 'active' chain doesn't yet exist we create it now */
- } else if (list_empty(&q->active)) {
- dprintk(DBG_BUFF, "%s: [%p/%d] first active\n",
- __func__, buf, buf->vb.i);
- list_add_tail(&buf->vb.queue, &q->active);
- q->start_dma(dev, q, buf); /* 1st one - start dma */
- /* TODO - why have we removed buf->count and q->count? */
- buf->activate(dev, buf, NULL);
-
- /* else we would like to put this buffer on the tail of the
- * active chain, provided it is "compatible". */
- } else {
- /* "compatibility" depends upon the type of buffer */
- prev = list_entry(q->active.prev, struct tw68_buf, vb.queue);
- if (q->buf_compat(prev, buf)) {
- /* If "compatible", append to active chain */
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- /* the param 'prev' is only for debug printing */
- buf->activate(dev, buf, prev);
- list_add_tail(&buf->vb.queue, &q->active);
- dprintk(DBG_BUFF, "%s: [%p/%d] appended to active\n",
- __func__, buf, buf->vb.i);
- } else {
- /* If "incompatible", append to queued chain */
- list_add_tail(&buf->vb.queue, &q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(DBG_BUFF, "%s: [%p/%d] incompatible - appended "
- "to queued\n", __func__, buf, buf->vb.i);
- }
- }
-}
-
-/*
- * tw68_buffer_timeout
- *
- * This routine is set as the video_q.timeout.function
- *
- * Log the event, try to reset the h/w.
- * Flag the current buffer as failed, try to start again with next buff
- */
-void tw68_buffer_timeout(unsigned long data)
-{
- struct tw68_dmaqueue *q = (struct tw68_dmaqueue *)data;
- struct tw68_dev *dev = q->dev;
- struct tw68_buf *buf;
- unsigned long flags;
-
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- spin_lock_irqsave(&dev->slock, flags);
-
- /* flag all current active buffers as failed */
- while (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct tw68_buf, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- printk(KERN_INFO "%s/0: [%p/%d] timeout - dma=0x%08lx\n",
- dev->name, buf, buf->vb.i,
- (unsigned long)buf->risc.dma);
- }
- tw68_buffer_requeue(dev, q);
- spin_unlock_irqrestore(&dev->slock, flags);
-}
+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,}
+};
/* ------------------------------------------------------------------ */
-/* early init (no i2c, no irq) */
-/* Called from tw68_hw_init1 and tw68_resume */
-static int tw68_hw_enable1(struct tw68_dev *dev)
-{
- return 0;
-}
/*
* The device is given a "soft reset". According to the specifications,
@@ -367,7 +91,6 @@ static int tw68_hw_enable1(struct tw68_dev *dev)
*/
static int tw68_hw_init1(struct tw68_dev *dev)
{
- dprintk(DBG_FLOW, "%s: called\n", __func__);
/* Assure all interrupts are disabled */
tw_writel(TW68_INTMASK, 0); /* 020 */
/* Clear any pending interrupts */
@@ -415,7 +138,7 @@ static int tw68_hw_init1(struct tw68_dev *dev)
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, 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 */
@@ -465,80 +188,9 @@ static int tw68_hw_init1(struct tw68_dev *dev)
/* Initialize any subsystems */
tw68_video_init1(dev);
- tw68_vbi_init1(dev);
- if (card_has_mpeg(dev))
- tw68_ts_init1(dev);
- tw68_input_init1(dev);
-
- /* Do any other h/w early initialisation at this point */
- tw68_hw_enable1(dev);
-
- return 0;
-}
-
-/* late init (with i2c + irq) */
-static int tw68_hw_enable2(struct tw68_dev *dev)
-{
-
- dprintk(DBG_FLOW, "%s: called\n", __func__);
-#ifdef TW68_TESTING
- dev->pci_irqmask |= TW68_I2C_INTS;
-#endif
- tw_setl(TW68_INTMASK, dev->pci_irqmask);
return 0;
}
-static int tw68_hw_init2(struct tw68_dev *dev)
-{
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- tw68_video_init2(dev); /* initialise video function first */
- tw68_tvaudio_init2(dev);/* audio next */
-
- /* all other board-related things, incl. enabling interrupts */
- tw68_hw_enable2(dev);
- return 0;
-}
-
-/* shutdown */
-static int tw68_hwfini(struct tw68_dev *dev)
-{
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- if (card_has_mpeg(dev))
- tw68_ts_fini(dev);
- tw68_input_fini(dev);
- tw68_vbi_fini(dev);
- tw68_tvaudio_fini(dev);
- return 0;
-}
-
-static void __devinit must_configure_manually(void)
-{
- unsigned int i, p;
-
- printk(KERN_WARNING
- "tw68: <rant>\n"
- "tw68: Congratulations! Your TV card vendor saved a few\n"
- "tw68: cents for a eeprom, thus your pci board has no\n"
- "tw68: subsystem ID and I can't identify it automatically\n"
- "tw68: </rant>\n"
- "tw68: I feel better now. Ok, here is the good news:\n"
- "tw68: You can use the card=<nr> insmod option to specify\n"
- "tw68: which board you have. The list:\n");
- for (i = 0; i < tw68_bcount; i++) {
- printk(KERN_WARNING "tw68: card=%d -> %-40.40s",
- i, tw68_boards[i].name);
- for (p = 0; tw68_pci_tbl[p].driver_data; p++) {
- if (tw68_pci_tbl[p].driver_data != i)
- continue;
- printk(" %04x:%04x",
- tw68_pci_tbl[p].subvendor,
- tw68_pci_tbl[p].subdevice);
- }
- printk("\n");
- }
-}
-
-
static irqreturn_t tw68_irq(int irq, void *dev_id)
{
struct tw68_dev *dev = dev_id;
@@ -548,126 +200,39 @@ static irqreturn_t tw68_irq(int irq, void *dev_id)
status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
/* Check if anything to do */
if (0 == status)
- return IRQ_RETVAL(0); /* Nope - return */
+ return IRQ_NONE; /* Nope - return */
for (loop = 0; loop < 10; loop++) {
if (status & dev->board_virqmask) /* video interrupt */
tw68_irq_video_done(dev, status);
-#ifdef TW68_TESTING
- if (status & TW68_I2C_INTS)
- tw68_irq_i2c(dev, status);
-#endif
status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask;
if (0 == status)
- goto out;
+ return IRQ_HANDLED;
}
- dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask"
- " (orig 0x%08x, cur 0x%08x)",
- dev->name, orig, tw_readl(TW68_INTSTAT));
- dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask "
- "0x%08x ****\n", dev->name,
- dev->pci_irqmask, dev->board_virqmask);
+ 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);
-out:
- return IRQ_RETVAL(1);
-}
-
-int tw68_set_dmabits(struct tw68_dev *dev)
-{
- return 0;
-}
-
-static struct video_device *vdev_init(struct tw68_dev *dev,
- struct video_device *template,
- char *type)
-{
- struct video_device *vfd;
-
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- vfd = video_device_alloc();
- if (NULL == vfd)
- return NULL;
- *vfd = *template;
- vfd->minor = -1;
- vfd->parent = &dev->pci->dev;
- vfd->release = video_device_release;
- /* vfd->debug = tw_video_debug; */
- snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
- dev->name, type, tw68_boards[dev->board].name);
- return vfd;
+ return IRQ_HANDLED;
}
-static void tw68_unregister_video(struct tw68_dev *dev)
-{
-
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- if (dev->video_dev) {
- if (-1 != dev->video_dev->minor)
- video_unregister_device(dev->video_dev);
- else
- video_device_release(dev->video_dev);
- dev->video_dev = NULL;
- }
- if (dev->vbi_dev) {
- if (-1 != dev->vbi_dev->minor)
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
- }
- if (dev->radio_dev) {
- if (-1 != dev->radio_dev->minor)
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
- }
-}
-
-static void mpeg_ops_attach(struct tw68_mpeg_ops *ops,
- struct tw68_dev *dev)
-{
- int err;
-
- dprintk(DBG_FLOW, "%s: called\n", __func__);
- if (NULL != dev->mops)
- return;
- if (tw68_boards[dev->board].mpeg != ops->type)
- return;
- err = ops->init(dev);
- if (0 != err)
- return;
- dev->mops = ops;
-}
-
-static void mpeg_ops_detach(struct tw68_mpeg_ops *ops,
- struct tw68_dev *dev)
-{
-
- if (NULL == dev->mops)
- return;
- if (dev->mops != ops)
- return;
- dev->mops->fini(dev);
- dev->mops = NULL;
-}
-
-static int __devinit tw68_initdev(struct pci_dev *pci_dev,
+static int tw68_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
struct tw68_dev *dev;
- struct tw68_mpeg_ops *mops;
+ int vidnr = -1;
int err;
- if (tw68_devcount == TW68_MAXBOARDS)
- return -ENOMEM;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ 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)
- goto fail0;
+ return err;
/* pci init */
dev->pci = pci_dev;
@@ -676,33 +241,10 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev,
goto fail1;
}
- dev->nr = tw68_devcount;
- sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr);
+ dev->name = dev->v4l2_dev.name;
- /* pci quirks */
- if (pci_pci_problems) {
- if (pci_pci_problems & PCIPCI_TRITON)
- printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n",
- dev->name);
- if (pci_pci_problems & PCIPCI_NATOMA)
- printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n",
- dev->name);
- if (pci_pci_problems & PCIPCI_VIAETBF)
- printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n",
- dev->name);
- if (pci_pci_problems & PCIPCI_VSFX)
- printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",
- dev->name);
-#ifdef PCIPCI_ALIMAGIK
- if (pci_pci_problems & PCIPCI_ALIMAGIK) {
- printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK "
- "-- latency fixup\n", dev->name);
- latency = 0x0A;
- }
-#endif
- }
if (UNSET != latency) {
- printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+ pr_info("%s: setting pci latency timer to %d\n",
dev->name, latency);
pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
}
@@ -710,13 +252,12 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev,
/* 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);
- printk(KERN_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,
- (unsigned long long)pci_resource_start(pci_dev, 0));
+ 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))) {
- printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
+ pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
err = -EIO;
goto fail1;
}
@@ -730,7 +271,7 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev,
dev->vdecoder = TW6801;
dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
break;
- case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */
+ case PCI_DEVICE_ID_6804: /* Video decoder for TW6804 */
dev->vdecoder = TW6804;
dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
break;
@@ -739,35 +280,13 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev,
dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX;
break;
}
- /* board config */
- dev->board = pci_id->driver_data;
- if (card[dev->nr] >= 0 &&
- card[dev->nr] < tw68_bcount)
- dev->board = card[dev->nr];
- if (TW68_BOARD_NOAUTO == dev->board) {
- must_configure_manually();
- dev->board = TW68_BOARD_UNKNOWN;
- }
- dev->autodetected = card[dev->nr] != dev->board;
- dev->tuner_type = tw68_boards[dev->board].tuner_type;
- dev->tuner_addr = tw68_boards[dev->board].tuner_addr;
- dev->radio_type = tw68_boards[dev->board].radio_type;
- dev->radio_addr = tw68_boards[dev->board].radio_addr;
- dev->tda9887_conf = tw68_boards[dev->board].tda9887_conf;
- if (UNSET != tuner[dev->nr])
- dev->tuner_type = tuner[dev->nr];
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- dev->name, pci_dev->subsystem_vendor,
- pci_dev->subsystem_device, tw68_boards[dev->board].name,
- dev->board, dev->autodetected ?
- "autodetected" : "insmod option");
/* get mmio */
if (!request_mem_region(pci_resource_start(pci_dev, 0),
pci_resource_len(pci_dev, 0),
dev->name)) {
err = -EBUSY;
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+ pr_err("%s: can't get MMIO memory @ 0x%llx\n",
dev->name,
(unsigned long long)pci_resource_start(pci_dev, 0));
goto fail1;
@@ -777,185 +296,75 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev,
dev->bmmio = (__u8 __iomem *)dev->lmmio;
if (NULL == dev->lmmio) {
err = -EIO;
- printk(KERN_ERR "%s: can't ioremap() MMIO memory\n",
+ pr_err("%s: can't ioremap() MMIO memory\n",
dev->name);
goto fail2;
}
/* initialize hardware #1 */
- /* First, take care of anything unique to a particular card */
- tw68_board_init1(dev);
/* Then do any initialisation wanted before interrupts are on */
tw68_hw_init1(dev);
/* get irq */
- err = request_irq(pci_dev->irq, tw68_irq,
+ err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq,
IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
if (err < 0) {
- printk(KERN_ERR "%s: can't get IRQ %d\n",
+ pr_err("%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
goto fail3;
}
-#ifdef TW68_TESTING
- dev->pci_irqmask |= TW68_SBDONE;
- tw_setl(TW68_INTMASK, dev->pci_irqmask);
- printk(KERN_INFO "Calling tw68_i2c_register\n");
- /* Register the i2c bus */
- tw68_i2c_register(dev);
-#endif
-
/*
* Now do remainder of initialisation, first for
* things unique for this card, then for general board
*/
- tw68_board_init2(dev);
-
- tw68_hw_init2(dev);
-
-#if 0
- /* load i2c helpers */
- if (card_is_empress(dev)) {
- struct v4l2_subdev *sd =
- v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs",
- "saa6752hs", 0x20);
-
- if (sd)
- sd->grp_id = GRP_EMPRESS;
- }
-
- request_submodules(dev);