diff options
Diffstat (limited to 'drivers/media/pci')
46 files changed, 7231 insertions, 9010 deletions
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 1224d908713a..dff0b450f387 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -13,12 +13,12 @@ if MEDIA_PCI_SUPPORT if MEDIA_CAMERA_SUPPORT comment "Media capture support" -source "drivers/media/pci/meye/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" source "drivers/media/pci/sta2x11/Kconfig" source "drivers/media/pci/tw5864/Kconfig" source "drivers/media/pci/tw68/Kconfig" source "drivers/media/pci/tw686x/Kconfig" +source "drivers/media/pci/zoran/Kconfig" endif @@ -27,7 +27,6 @@ if MEDIA_ANALOG_TV_SUPPORT source "drivers/media/pci/dt3155/Kconfig" source "drivers/media/pci/ivtv/Kconfig" -source "drivers/media/pci/saa7146/Kconfig" endif @@ -58,7 +57,6 @@ source "drivers/media/pci/pluto2/Kconfig" source "drivers/media/pci/pt1/Kconfig" source "drivers/media/pci/pt3/Kconfig" source "drivers/media/pci/smipcie/Kconfig" -source "drivers/media/pci/ttpci/Kconfig" endif diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 551169a3e434..8f887a8a7f17 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -5,8 +5,7 @@ # Please keep it alphabetically sorted by directory # (e. g. LC_ALL=C sort Makefile) -obj-y += ttpci/ \ - b2c2/ \ +obj-y += b2c2/ \ pluto2/ \ dm1105/ \ pt1/ \ @@ -14,7 +13,6 @@ obj-y += ttpci/ \ mantis/ \ ngene/ \ ddbridge/ \ - saa7146/ \ smipcie/ \ netup_unidvb/ \ intel/ @@ -32,10 +30,10 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_DT3155) += dt3155/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ -obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ obj-$(CONFIG_VIDEO_TW5864) += tw5864/ obj-$(CONFIG_VIDEO_TW686X) += tw686x/ obj-$(CONFIG_VIDEO_TW68) += tw68/ +obj-$(CONFIG_VIDEO_ZORAN) += zoran/ diff --git a/drivers/media/pci/cx18/cx18-av-audio.c b/drivers/media/pci/cx18/cx18-av-audio.c index 833baa934448..78e05df9a7ba 100644 --- a/drivers/media/pci/cx18/cx18-av-audio.c +++ b/drivers/media/pci/cx18/cx18-av-audio.c @@ -50,7 +50,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) * * Many thanks to Jeff Campbell and Mike Bradley for their extensive * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. + * audio/video sync problems with SVideo and CVBS captures. */ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index fdac310d7477..1b038b2802bf 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -248,7 +248,7 @@ void cx18_init_power(struct cx18 *cx, int lowpwr) * * Many thanks to Jeff Campbell and Mike Bradley for their extensive * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. + * audio/video sync problems with SVideo and CVBS captures. */ /* the fast clock is at 200/245 MHz */ diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index a07b18f2034e..9232a966bcab 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2086,6 +2086,9 @@ static struct { /* 0x1419 is the PCI ID for the IOMMU found on 15h (Models 10h-1fh) family */ { PCI_VENDOR_ID_AMD, 0x1419 }, + /* 0x1631 is the PCI ID for the IOMMU found on Renoir/Cezanne + */ + { PCI_VENDOR_ID_AMD, 0x1631 }, /* 0x5a23 is the PCI ID for the IOMMU found on RD890S/RD990 */ { PCI_VENDOR_ID_ATI, 0x5a23 }, diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index ddfd2eb37484..222d04421468 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -235,7 +235,7 @@ static u32 clock_divider_to_resolution(u16 divider) { /* * Resolution is the duration of 1 tick of the readable portion of - * of the pulse width counter as read from the FIFO. The two lsb's are + * the pulse width counter as read from the FIFO. The two lsb's are * not readable, hence the << 2. This function returns ns. */ return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index f1e1fc1cb4bd..e378f3b215c7 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -24,7 +24,7 @@ /* * We calculate the baseband frequencies of the carrier and the pilot tones - * based on the the sampling rate of the audio rds fifo. + * based on the sampling rate of the audio rds fifo. */ #define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index a075788c64d4..469aeaa725ad 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -144,11 +144,10 @@ static int buffer_prepare(struct vb2_buffer *vb) return -EINVAL; vb2_set_plane_payload(vb, 0, size); - cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl, - 0, VBI_LINE_LENGTH * lines, - VBI_LINE_LENGTH, 0, - lines); - return 0; + return cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl, + 0, VBI_LINE_LENGTH * lines, + VBI_LINE_LENGTH, 0, + lines); } static void buffer_finish(struct vb2_buffer *vb) diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index d3729be89252..b509c2a03852 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -431,6 +431,7 @@ static int queue_setup(struct vb2_queue *q, static int buffer_prepare(struct vb2_buffer *vb) { + int ret; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct cx8800_dev *dev = vb->vb2_queue->drv_priv; struct cx88_core *core = dev->core; @@ -445,35 +446,35 @@ static int buffer_prepare(struct vb2_buffer *vb) switch (core->field) { case V4L2_FIELD_TOP: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, 0, UNSET, - buf->bpl, 0, core->height); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, core->height); break; case V4L2_FIELD_BOTTOM: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, UNSET, 0, - buf->bpl, 0, core->height); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, core->height); break; case V4L2_FIELD_SEQ_TB: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, - 0, buf->bpl * (core->height >> 1), - buf->bpl, 0, - core->height >> 1); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (core->height >> 1), + buf->bpl, 0, + core->height >> 1); break; case V4L2_FIELD_SEQ_BT: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, - buf->bpl * (core->height >> 1), 0, - buf->bpl, 0, - core->height >> 1); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (core->height >> 1), 0, + buf->bpl, 0, + core->height >> 1); break; case V4L2_FIELD_INTERLACED: default: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, 0, buf->bpl, - buf->bpl, buf->bpl, - core->height >> 1); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, buf->bpl, + buf->bpl, buf->bpl, + core->height >> 1); break; } dprintk(2, @@ -481,7 +482,7 @@ static int buffer_prepare(struct vb2_buffer *vb) buf, buf->vb.vb2_buf.index, __func__, core->width, core->height, dev->fmt->depth, dev->fmt->fourcc, (unsigned long)buf->risc.dma); - return 0; + return ret; } static void buffer_finish(struct vb2_buffer *vb) diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index e79e8a5a744a..4ba10c34a16a 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -538,7 +538,7 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); /* Okay, we've wasted time working out the correct value, - but if we use it, it fouls the the window alignment. + but if we use it, it fouls the window alignment. Fudge it to what we want... */ reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig deleted file mode 100644 index 3e69b66f1a5b..000000000000 --- a/drivers/media/pci/meye/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_MEYE - tristate "Sony Vaio Picturebook Motion Eye Video For Linux" - depends on PCI && VIDEO_DEV - depends on SONY_LAPTOP - depends on X86 || COMPILE_TEST - help - This is the video4linux driver for the Motion Eye camera found - in the Vaio Picturebook laptops. Please read the material in - <file:Documentation/admin-guide/media/meye.rst> for more information. - - If you say Y or M here, you need to say Y or M to "Sony Laptop - Extras" in the misc device section. - - To compile this driver as a module, choose M here: the - module will be called meye. diff --git a/drivers/media/pci/meye/Makefile b/drivers/media/pci/meye/Makefile deleted file mode 100644 index 36f1f86f0d58..000000000000 --- a/drivers/media/pci/meye/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_MEYE) += meye.o diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c deleted file mode 100644 index 5d87efd9b95c..000000000000 --- a/drivers/media/pci/meye/meye.c +++ /dev/null @@ -1,1814 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net> - * - * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com> - * - * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - */ -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/gfp.h> -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-fh.h> -#include <media/v4l2-event.h> -#include <linux/uaccess.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/vmalloc.h> -#include <linux/dma-mapping.h> - -#include "meye.h" -#include <linux/meye.h> - -MODULE_AUTHOR("Stelian Pop <stelian@popies.net>"); -MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MEYE_DRIVER_VERSION); - -/* number of grab buffers */ -static unsigned int gbuffers = 2; -module_param(gbuffers, int, 0444); -MODULE_PARM_DESC(gbuffers, "number of capture buffers, default is 2 (32 max)"); - -/* size of a grab buffer */ -static unsigned int gbufsize = MEYE_MAX_BUFSIZE; -module_param(gbufsize, int, 0444); -MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400 (will be rounded up to a page multiple)"); - -/* /dev/videoX registration number */ -static int video_nr = -1; -module_param(video_nr, int, 0444); -MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)"); - -/* driver structure - only one possible */ -static struct meye meye; - -/****************************************************************************/ -/* Memory allocation routines (stolen from bttv-driver.c) */ -/****************************************************************************/ -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (mem) { - memset(mem, 0, size); - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - return mem; -} - -static void rvfree(void * mem, unsigned long size) -{ - unsigned long adr; - - if (mem) { - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); - } -} - -/* - * return a page table pointing to N pages of locked memory - * - * NOTE: The meye device expects DMA addresses on 32 bits, we build - * a table of 1024 entries = 4 bytes * 1024 = 4096 bytes. - */ -static int ptable_alloc(void) -{ - u32 *pt; - int i; - - memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - - /* give only 32 bit DMA addresses */ - if (dma_set_mask(&meye.mchip_dev->dev, DMA_BIT_MASK(32))) - return -1; - - meye.mchip_ptable_toc = dma_alloc_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - &meye.mchip_dmahandle, - GFP_KERNEL); - if (!meye.mchip_ptable_toc) { - meye.mchip_dmahandle = 0; - return -1; - } - - pt = meye.mchip_ptable_toc; - for (i = 0; i < MCHIP_NB_PAGES; i++) { - dma_addr_t dma; - meye.mchip_ptable[i] = dma_alloc_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - &dma, - GFP_KERNEL); - if (!meye.mchip_ptable[i]) { - int j; - pt = meye.mchip_ptable_toc; - for (j = 0; j < i; ++j) { - dma = (dma_addr_t) *pt; - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable[j], dma); - pt++; - } - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable_toc, - meye.mchip_dmahandle); - meye.mchip_ptable_toc = NULL; - meye.mchip_dmahandle = 0; - return -1; - } - *pt = (u32) dma; - pt++; - } - return 0; -} - -static void ptable_free(void) -{ - u32 *pt; - int i; - - pt = meye.mchip_ptable_toc; - for (i = 0; i < MCHIP_NB_PAGES; i++) { - dma_addr_t dma = (dma_addr_t) *pt; - if (meye.mchip_ptable[i]) - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable[i], dma); - pt++; - } - - if (meye.mchip_ptable_toc) - dma_free_coherent(&meye.mchip_dev->dev, - PAGE_SIZE, - meye.mchip_ptable_toc, - meye.mchip_dmahandle); - - memset(meye.mchip_ptable, 0, sizeof(meye.mchip_ptable)); - meye.mchip_ptable_toc = NULL; - meye.mchip_dmahandle = 0; -} - -/* copy data from ptable into buf */ -static void ptable_copy(u8 *buf, int start, int size, int pt_pages) -{ - int i; - - for (i = 0; i < (size / PAGE_SIZE) * PAGE_SIZE; i += PAGE_SIZE) { - memcpy(buf + i, meye.mchip_ptable[start++], PAGE_SIZE); - if (start >= pt_pages) - start = 0; - } - memcpy(buf + i, meye.mchip_ptable[start], size % PAGE_SIZE); -} - -/****************************************************************************/ -/* JPEG tables at different qualities to load into the VRJ chip */ -/****************************************************************************/ - -/* return a set of quantisation tables based on a quality from 1 to 10 */ -static u16 *jpeg_quantisation_tables(int *length, int quality) -{ - static u16 jpeg_tables[][70] = { { - 0xdbff, 0x4300, 0xff00, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - 0xdbff, 0x4300, 0xff01, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - }, - { - 0xdbff, 0x4300, 0x5000, 0x3c37, 0x3c46, 0x5032, 0x4146, 0x5a46, - 0x5055, 0x785f, 0x82c8, 0x6e78, 0x786e, 0xaff5, 0x91b9, 0xffc8, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - 0xdbff, 0x4300, 0x5501, 0x5a5a, 0x6978, 0xeb78, 0x8282, 0xffeb, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, - }, - { - 0xdbff, 0x4300, 0x2800, 0x1e1c, 0x1e23, 0x2819, 0x2123, 0x2d23, - 0x282b, 0x3c30, 0x4164, 0x373c, 0x3c37, 0x587b, 0x495d, 0x9164, - 0x9980, 0x8f96, 0x8c80, 0xa08a, 0xe6b4, 0xa0c3, 0xdaaa, 0x8aad, - 0xc88c, 0xcbff, 0xeeda, 0xfff5, 0xffff, 0xc19b, 0xffff, 0xfaff, - 0xe6ff, 0xfffd, 0xfff8, - 0xdbff, 0x4300, 0x2b01, 0x2d2d, 0x353c, 0x763c, 0x4141, 0xf876, - 0x8ca5, 0xf8a5, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, 0xf8f8, - 0xf8f8, 0xf8f8, 0xfff8, - }, - { - 0xdbff, 0x4300, 0x1b00, 0x1412, 0x1417, 0x1b11, 0x1617, 0x1e17, - 0x1b1c, 0x2820, 0x2b42, 0x2528, 0x2825, 0x3a51, 0x303d, 0x6042, - 0x6555, 0x5f64, 0x5d55, 0x6a5b, 0x9978, 0x6a81, 0x9071, 0x5b73, - 0x855d, 0x86b5, 0x9e90, 0xaba3, 0xabad, 0x8067, 0xc9bc, 0xa6ba, - 0x99c7, 0xaba8, 0xffa4, - 0xdbff, 0x4300, 0x1c01, 0x1e1e, 0x2328, 0x4e28, 0x2b2b, 0xa44e, - 0x5d6e, 0xa46e, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, - 0xa4a4, 0xa4a4, 0xffa4, - }, - { - 0xdbff, 0x4300, 0x1400, 0x0f0e, 0x0f12, 0x140d, 0x1012, 0x1712, - 0x1415, 0x1e18, 0x2132, 0x1c1e, 0x1e1c, 0x2c3d, 0x242e, 0x4932, - 0x4c40, 0x474b, 0x4640, 0x5045, 0x735a, 0x5062, 0x6d55, 0x4556, - 0x6446, 0x6588, 0x776d, 0x817b, 0x8182, 0x604e, 0x978d, 0x7d8c, - 0x7396, 0x817e, 0xff7c, - 0xdbff, 0x4300, 0x1501, 0x1717, 0x1a1e, 0x3b1e, 0x2121, 0x7c3b, - 0x4653, 0x7c53, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, 0x7c7c, - 0x7c7c, 0x7c7c, 0xff7c, - }, - { - 0xdbff, 0x4300, 0x1000, 0x0c0b, 0x0c0e, 0x100a, 0x0d0e, 0x120e, - 0x1011, 0x1813, 0x1a28, 0x1618, 0x1816, 0x2331, 0x1d25, 0x3a28, - 0x3d33, 0x393c, 0x3833, 0x4037, 0x5c48, 0x404e, 0x5744, 0x3745, - 0x5038, 0x516d, 0x5f57, 0x6762, 0x6768, 0x4d3e, 0x7971, 0x6470, - 0x5c78, 0x6765, 0xff63, - 0xdbff, 0x4300, 0x1101, 0x1212, 0x1518, 0x2f18, 0x1a1a, 0x632f, - 0x3842, 0x6342, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, 0x6363, - 0x6363, 0x6363, 0xff63, - }, - { - 0xdbff, 0x4300, 0x0d00, 0x0a09, 0x0a0b, 0x0d08, 0x0a0b, 0x0e0b, - 0x0d0e, 0x130f, 0x1520, 0x1213, 0x1312, 0x1c27, 0x171e, 0x2e20, - 0x3129, 0x2e30, 0x2d29, 0x332c, 0x4a3a, 0x333e, 0x4636, 0x2c37, - 0x402d, 0x4157, 0x4c46, 0x524e, 0x5253, 0x3e32, 0x615a, 0x505a, - 0x4a60, 0x5251, 0xff4f, - 0xdbff, 0x4300, 0x0e01, 0x0e0e, 0x1113, 0x2613, 0x1515, 0x4f26, - 0x2d35, 0x4f35, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, 0x4f4f, - 0x4f4f, 0x4f4f, 0xff4f, - }, - { - 0xdbff, 0x4300, 0x0a00, 0x0707, 0x0708, 0x0a06, 0x0808, 0x0b08, - 0x0a0a, 0x0e0b, 0x1018, 0x0d0e, 0x0e0d, 0x151d, 0x1116, 0x2318, - 0x251f, 0x2224, 0x221f, 0x2621, 0x372b, 0x262f, 0x3429, 0x2129, - 0x3022, 0x3141, 0x3934, 0x3e3b, 0x3e3e, 0x2e25, 0x4944, 0x3c43, - 0x3748, 0x3e3d, 0xff3b, - 0xdbff, 0x4300, 0x0a01, 0x0b0b, 0x0d0e, 0x1c0e, 0x1010, 0x3b1c, - 0x2228, 0x3b28, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, 0x3b3b, - 0x3b3b, 0x3b3b, 0xff3b, - }, - { - 0xdbff, 0x4300, 0x0600, 0x0504, 0x0506, 0x0604, 0x0506, 0x0706, - 0x0607, 0x0a08, 0x0a10, 0x090a, 0x0a09, 0x0e14, 0x0c0f, 0x1710, - 0x1814, 0x1718, 0x1614, 0x1a16, 0x251d, 0x1a1f, 0x231b, 0x161c, - 0x2016, 0x202c, 0x2623, 0x2927, 0x292a, 0x1f19, 0x302d, 0x282d, - 0x2530, 0x2928, 0xff28, - 0xdbff, 0x4300, 0x0701, 0x0707, 0x080a, 0x130a, 0x0a0a, 0x2813, - 0x161a, 0x281a, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, 0x2828, - 0x2828, 0x2828, 0xff28, - }, - { - 0xdbff, 0x4300, 0x0300, 0x0202, 0x0203, 0x0302, 0x0303, 0x0403, - 0x0303, 0x0504, 0x0508, 0x0405, 0x0504, 0x070a, 0x0607, 0x0c08, - 0x0c0a, 0x0b0c, 0x0b0a, 0x0d0b, 0x120e, 0x0d10, 0x110e, 0x0b0e, - 0x100b, 0x1016, 0x1311, 0x1514, 0x1515, 0x0f0c, 0x1817, 0x1416, - 0x1218, 0x1514, 0xff14, - 0xdbff, 0x4300, 0x0301, 0x0404, 0x0405, 0x0905, 0x0505, 0x1409, - 0x0b0d, 0x140d, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, 0x1414, - 0x1414, 0x1414, 0xff14, - }, - { - 0xdbff, 0x4300, 0x0100, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0xff01, - 0xdbff, 0x4300, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0101, 0x0101, 0xff01, - } }; - - if (quality < 0 || quality > 10) { - printk(KERN_WARNING - "meye: invalid quality level %d - using 8\n", quality); - quality = 8; - } - - *length = ARRAY_SIZE(jpeg_tables[quality]); - return jpeg_tables[quality]; -} - -/* return a generic set of huffman tables */ -static u16 *jpeg_huffman_tables(int *length) -{ - static u16 tables[] = { - 0xC4FF, 0xB500, 0x0010, 0x0102, 0x0303, 0x0402, 0x0503, 0x0405, - 0x0004, 0x0100, 0x017D, 0x0302, 0x0400, 0x0511, 0x2112, 0x4131, - 0x1306, 0x6151, 0x2207, 0x1471, 0x8132, 0xA191, 0x2308, 0xB142, - 0x15C1, 0xD152, 0x24F0, 0x6233, 0x8272, 0x0A09, 0x1716, 0x1918, - 0x251A, 0x2726, 0x2928, 0x342A, 0x3635, 0x3837, 0x3A39, 0x4443, - 0x4645, 0x4847, 0x4A49, 0x5453, 0x5655, 0x5857, 0x5A59, 0x6463, - 0x6665, 0x6867, 0x6A69, 0x7473, 0x7675, 0x7877, 0x7A79, 0x8483, - 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, 0xA29A, - 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, 0xB9B8, - 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, 0xD7D6, - 0xD9D8, 0xE1DA, 0xE3E2, 0xE5E4, 0xE7E6, 0xE9E8, 0xF1EA, 0xF3F2, - 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, - 0xC4FF, 0xB500, 0x0011, 0x0102, 0x0402, 0x0304, 0x0704, 0x0405, - 0x0004, 0x0201, 0x0077, 0x0201, 0x1103, 0x0504, 0x3121, 0x1206, - 0x5141, 0x6107, 0x1371, 0x3222, 0x0881, 0x4214, 0xA191, 0xC1B1, - 0x2309, 0x5233, 0x15F0, 0x7262, 0x0AD1, 0x2416, 0xE134, 0xF125, - 0x1817, 0x1A19, 0x2726, 0x2928, 0x352A, 0x3736, 0x3938, 0x433A, - 0x4544, 0x4746, 0x4948, 0x534A, 0x5554, 0x5756, 0x5958, 0x635A, - 0x6564, 0x6766, 0x6968, 0x736A, 0x7574, 0x7776, 0x7978, 0x827A, - 0x8483, 0x8685, 0x8887, 0x8A89, 0x9392, 0x9594, 0x9796, 0x9998, - 0xA29A, 0xA4A3, 0xA6A5, 0xA8A7, 0xAAA9, 0xB3B2, 0xB5B4, 0xB7B6, - 0xB9B8, 0xC2BA, 0xC4C3, 0xC6C5, 0xC8C7, 0xCAC9, 0xD3D2, 0xD5D4, - 0xD7D6, 0xD9D8, 0xE2DA, 0xE4E3, 0xE6E5, 0xE8E7, 0xEAE9, 0xF3F2, - 0xF5F4, 0xF7F6, 0xF9F8, 0xFFFA, - 0xC4FF, 0x1F00, 0x0000, 0x0501, 0x0101, 0x0101, 0x0101, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, - 0xFF0B, - 0xC4FF, 0x1F00, 0x0001, 0x0103, 0x0101, 0x0101, 0x0101, 0x0101, - 0x0000, 0x0000, 0x0000, 0x0201, 0x0403, 0x0605, 0x0807, 0x0A09, - 0xFF0B - }; - - *length = ARRAY_SIZE(tables); - return tables; -} - -/****************************************************************************/ -/* MCHIP low-level functions */ -/****************************************************************************/ - -/* returns the horizontal capture size */ -static inline int mchip_hsize(void) -{ - return meye.params.subsample ? 320 : 640; -} - -/* returns the vertical capture size */ -static inline int mchip_vsize(void) -{ - return meye.params.subsample ? 240 : 480; -} - -/* waits for a register to be available */ -static void mchip_sync(int reg) -{ - u32 status; - int i; - - if (reg == MCHIP_MM_FIFO_DATA) { - for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { - status = readl(meye.mchip_mmregs + - MCHIP_MM_FIFO_STATUS); - if (!(status & MCHIP_MM_FIFO_WAIT)) { - printk(KERN_WARNING "meye: fifo not ready\n"); - return; - } - if (status & MCHIP_MM_FIFO_READY) - return; - udelay(1); - } - } else if (reg > 0x80) { - u32 mask = (reg < 0x100) ? MCHIP_HIC_STATUS_MCC_RDY - : MCHIP_HIC_STATUS_VRJ_RDY; - for (i = 0; i < MCHIP_REG_TIMEOUT; i++) { - status = readl(meye.mchip_mmregs + MCHIP_HIC_STATUS); - if (status & mask) - return; - udelay(1); - } - } else - return; - printk(KERN_WARNING - "meye: mchip_sync() timeout on reg 0x%x status=0x%x\n", - reg, status); -} - -/* sets a value into the register */ -static inline void mchip_set(int reg, u32 v) -{ - mchip_sync(reg); - writel(v, meye.mchip_mmregs + reg); -} - -/* get the register value */ -static inline u32 mchip_read(int reg) -{ - mchip_sync(reg); - return readl(meye.mchip_mmregs + reg); -} - -/* wait for a register to become a particular value */ -static inline int mchip_delay(u32 reg, u32 v) -{ - int n = 10; - while (--n && mchip_read(reg) != v) - udelay(1); - return n; -} - -/* setup subsampling */ -static void mchip_subsample(void) -{ - mchip_set(MCHIP_MCC_R_SAMPLING, meye.params.subsample); - mchip_set(MCHIP_MCC_R_XRANGE, mchip_hsize()); - mchip_set(MCHIP_MCC_R_YRANGE, mchip_vsize()); - mchip_set(MCHIP_MCC_B_XRANGE, mchip_hsize()); - mchip_set(MCHIP_MCC_B_YRANGE, mchip_vsize()); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); -} - -/* set the framerate into the mchip */ -static void mchip_set_framerate(void) -{ - mchip_set(MCHIP_HIC_S_RATE, meye.params.framerate); -} - -/* load some huffman and quantisation tables into the VRJ chip ready - for JPEG compression */ -static void mchip_load_tables(void) -{ - int i; - int length; - u16 *tables; - - tables = jpeg_huffman_tables(&length); - for (i = 0; i < length; i++) - writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); - - tables = jpeg_quantisation_tables(&length, meye.params.quality); - for (i = 0; i < length; i++) - writel(tables[i], meye.mchip_mmregs + MCHIP_VRJ_TABLE_DATA); -} - -/* setup the VRJ parameters in the chip */ -static void mchip_vrj_setup(u8 mode) -{ - mchip_set(MCHIP_VRJ_BUS_MODE, 5); - mchip_set(MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL, 0x1f); - mchip_set(MCHIP_VRJ_PDAT_USE, 1); - mchip_set(MCHIP_VRJ_IRQ_FLAG, 0xa0); - mchip_set(MCHIP_VRJ_MODE_SPECIFY, mode); - mchip_set(MCHIP_VRJ_NUM_LINES, mchip_vsize()); - mchip_set(MCHIP_VRJ_NUM_PIXELS, mchip_hsize()); - mchip_set(MCHIP_VRJ_NUM_COMPONENTS, 0x1b); - mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_LO, 0xFFFF); - mchip_set(MCHIP_VRJ_LIMIT_COMPRESSED_HI, 0xFFFF); - mchip_set(MCHIP_VRJ_COMP_DATA_FORMAT, 0xC); - mchip_set(MCHIP_VRJ_RESTART_INTERVAL, 0); - mchip_set(MCHIP_VRJ_SOF1, 0x601); - mchip_set(MCHIP_VRJ_SOF2, 0x1502); - mchip_set(MCHIP_VRJ_SOF3, 0x1503); - mchip_set(MCHIP_VRJ_SOF4, 0x1596); - mchip_set(MCHIP_VRJ_SOS, 0x0ed0); - - mchip_load_tables(); -} - -/* sets the DMA parameters into the chip */ -static void mchip_dma_setup(dma_addr_t dma_addr) -{ - int i; - - mchip_set(MCHIP_MM_PT_ADDR, (u32)dma_addr); - for (i = 0; i < 4; i++) - mchip_set(MCHIP_MM_FIR(i), 0); - meye.mchip_fnum = 0; -} - -/* setup for DMA transfers - also zeros the framebuffer */ -static int mchip_dma_alloc(void) -{ - if (!meye.mchip_dmahandle) - if (ptable_alloc()) - return -1; - return 0; -} - -/* frees the DMA buffer */ -static void mchip_dma_free(void) -{ - if (meye.mchip_dmahandle) { - mchip_dma_setup(0); - ptable_free(); - } -} - -/* stop any existing HIC action and wait for any dma to complete then - reset the dma engine */ -static void mchip_hic_stop(void) -{ - int i, j; - - meye.mchip_mode = MCHIP_HIC_MODE_NOOP; - if (!(mchip_read(MCHIP_HIC_STATUS) & MCHIP_HIC_STATUS_BUSY)) - return; - for (i = 0; i < 20; ++i) { - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_STOP); - mchip_delay(MCHIP_HIC_CMD, 0); - for (j = 0; j < 100; ++j) { - if (mchip_delay(MCHIP_HIC_STATUS, - MCHIP_HIC_STATUS_IDLE)) - return; - msleep(1); - } - printk(KERN_ERR "meye: need to reset HIC!\n"); - - mchip_set(MCHIP_HIC_CTL, MCHIP_HIC_CTL_SOFT_RESET); - msleep(250); - } - printk(KERN_ERR "meye: resetting HIC hanged!\n"); -} - -/****************************************************************************/ -/* MCHIP frame processing functions */ -/****************************************************************************/ - -/* get the next ready frame from the dma engine */ -static u32 mchip_get_frame(void) -{ - return mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); -} - -/* frees the current frame from the dma engine */ -static void mchip_free_frame(void) -{ - mchip_set(MCHIP_MM_FIR(meye.mchip_fnum), 0); - meye.mchip_fnum++; - meye.mchip_fnum %= 4; -} - -/* read one frame from the framebuffer assuming it was captured using - a uncompressed transfer */ -static void mchip_cont_read_frame(u32 v, u8 *buf, int size) -{ - int pt_id; - - pt_id = (v >> 17) & 0x3FF; - - ptable_copy(buf, pt_id, size, MCHIP_NB_PAGES); -} - -/* read a compressed frame from the framebuffer */ -static int mchip_comp_read_frame(u32 v, u8 *buf, int size) -{ - int pt_start, pt_end, trailer; - int fsize; - int i; - - pt_start = (v >> 19) & 0xFF; - pt_end = (v >> 11) & 0xFF; - trailer = (v >> 1) & 0x3FF; - - if (pt_end < pt_start) - fsize = (MCHIP_NB_PAGES_MJPEG - pt_start) * PAGE_SIZE + - pt_end * PAGE_SIZE + trailer * 4; - else - fsize = (pt_end - pt_start) * PAGE_SIZE + trailer * 4; - - if (fsize > size) { - printk(KERN_WARNING "meye: oversized compressed frame %d\n", - fsize); - return -1; - } - - ptable_copy(buf, pt_start, fsize, MCHIP_NB_PAGES_MJPEG); - -#ifdef MEYE_JPEG_CORRECTION - - /* Some mchip generated jpeg frames are incorrect. In most - * (all ?) of those cases, the final EOI (0xff 0xd9) marker - * is not present at the end of the frame. - * - * Since adding the final marker is not enough to restore - * the jpeg integrity, we drop the frame. - */ - - for (i = fsize - 1; i > 0 && buf[i] == 0xff; i--) ; - - if (i < 2 || buf[i - 1] != 0xff || buf[i] != 0xd9) - return -1; - -#endif - - return fsize; -} - -/* take a picture into SDRAM */ -static void mchip_take_picture(void) -{ - int i; - - mchip_hic_stop(); - mchip_subsample(); - mchip_dma_setup(meye.mchip_dmahandle); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_CAP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } -} - -/* dma a previously taken picture into a buffer */ -static void mchip_get_picture(u8 *buf, int bufsize) -{ - u32 v; - int i; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_OUT); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } - for (i = 0; i < 4; ++i) { - v = mchip_get_frame(); - if (v & MCHIP_MM_FIR_RDY) { - mchip_cont_read_frame(v, buf, bufsize); - break; - } - mchip_free_frame(); - } -} - -/* start continuous dma capture */ -static void mchip_continuous_start(void) -{ - mchip_hic_stop(); - mchip_subsample(); - mchip_set_framerate(); - mchip_dma_setup(meye.mchip_dmahandle); - - meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_OUT); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); -} - -/* compress one frame into a buffer */ -static int mchip_compress_frame(u8 *buf, int bufsize) -{ - u32 v; - int len = -1, i; - - mchip_vrj_setup(0x3f); - udelay(50); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_COMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - for (i = 0; i < 100; ++i) { - if (mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE)) - break; - msleep(1); - } - - for (i = 0; i < 4; ++i) { - v = mchip_get_frame(); - if (v & MCHIP_MM_FIR_RDY) { - len = mchip_comp_read_frame(v, buf, bufsize); - break; - } - mchip_free_frame(); - } - return len; -} - -#if 0 -/* uncompress one image into a buffer */ -static int mchip_uncompress_frame(u8 *img, int imgsize, u8 *buf, int bufsize) -{ - mchip_vrj_setup(0x3f); - udelay(50); - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_STILL_DECOMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); - - return mchip_comp_read_frame(buf, bufsize); -} -#endif - -/* start continuous compressed capture */ -static void mchip_cont_compression_start(void) -{ - mchip_hic_stop(); - mchip_vrj_setup(0x3f); - mchip_subsample(); - mchip_set_framerate(); - mchip_dma_setup(meye.mchip_dmahandle); - - meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; - - mchip_set(MCHIP_HIC_MODE, MCHIP_HIC_MODE_CONT_COMP); - mchip_set(MCHIP_HIC_CMD, MCHIP_HIC_CMD_START); - - mchip_delay(MCHIP_HIC_CMD, 0); -} - -/****************************************************************************/ -/* Interrupt handling */ -/****************************************************************************/ - -static irqreturn_t meye_irq(int irq, void *dev_id) -{ - u32 v; - int reqnr; - static int sequence; - - v = mchip_read(MCHIP_MM_INTA); - - if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT && - meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) - return IRQ_NONE; - -again: - v = mchip_get_frame(); - if (!(v & MCHIP_MM_FIR_RDY)) - return IRQ_HANDLED; - - if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { - if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, - sizeof(int), &meye.grabq_lock) != sizeof(int)) { - mchip_free_frame(); - return IRQ_HANDLED; - } - mchip_cont_read_frame(v, meye.grab_fbuffer + gbufsize * reqnr, - mchip_hsize() * mchip_vsize() * 2); - meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2; - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - meye.grab_buffer[reqnr].ts = ktime_get_ns(); - meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock); - wake_up_interruptible(&meye.proc_list); - } else { - int size; - size = mchip_comp_read_frame(v, meye.grab_temp, gbufsize); - if (size == -1) { - mchip_free_frame(); - goto again; - } - if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, - sizeof(int), &meye.grabq_lock) != sizeof(int)) { - mchip_free_frame(); - goto again; - } - memcpy(meye.grab_fbuffer + gbufsize * reqnr, meye.grab_temp, - size); - meye.grab_buffer[reqnr].size = size; - meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - meye.grab_buffer[reqnr].ts = ktime_get_ns(); - meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock); - wake_up_interruptible(&meye.proc_list); - } - mchip_free_frame(); - goto again; -} - -/****************************************************************************/ -/* video4linux integration */ -/****************************************************************************/ - -static int meye_open(struct file *file) -{ - int i; - - if (test_and_set_bit(0, &meye.in_use)) - return -EBUSY; - - mchip_hic_stop(); - - if (mchip_dma_alloc()) { - printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); - clear_bit(0, &meye.in_use); - return -ENOBUFS; - } - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - kfifo_reset(&meye.grabq); - kfifo_reset(&meye.doneq); - return v4l2_fh_open(file); -} - -static int meye_release(struct file *file) -{ - mchip_hic_stop(); - mchip_dma_free(); - clear_bit(0, &meye.in_use); - return v4l2_fh_release(file); -} - -static int meyeioc_g_params(struct meye_params *p) -{ - *p = meye.params; - return 0; -} - -static int meyeioc_s_params(struct meye_params *jp) -{ - if (jp->subsample > 1) - return -EINVAL; - - if (jp->quality > 10) - return -EINVAL; - - if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63) - return -EINVAL; - - if (jp->framerate > 31) - return -EINVAL; - - mutex_lock(&meye.lock); - - if (meye.params.subsample != jp->subsample || - meye.params.quality != jp->quality) - mchip_hic_stop(); /* need restart */ - - meye.params = *jp; - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, - meye.params.sharpness); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, - meye.params.agc); - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, - meye.params.picture); - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_qbuf_capt(int *nb) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (*nb >= gbuffers) - return -EINVAL; - - if (*nb < 0) { - /* stop capture */ - mchip_hic_stop(); - return 0; - } - - if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - - if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) - mchip_cont_compression_start(); - - meye.grab_buffer[*nb].state = MEYE_BUF_USING; - kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), - &meye.grabq_lock); - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_sync(struct file *file, void *fh, int *i) -{ - int unused; - - if (*i < 0 || *i >= gbuffers) - return -EINVAL; - - mutex_lock(&meye.lock); - switch (meye.grab_buffer[*i].state) { - - case MEYE_BUF_UNUSED: - mutex_unlock(&meye.lock); - return -EINVAL; - case MEYE_BUF_USING: - if (file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - if (wait_event_interruptible(meye.proc_list, - (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { - mutex_unlock(&meye.lock); - return -EINTR; - } - fallthrough; - case MEYE_BUF_DONE: - meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; - if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, - sizeof(int), &meye.doneq_lock) != sizeof(int)) - break; - } - *i = meye.grab_buffer[*i].size; - mutex_unlock(&meye.lock); - return 0; -} - -static int meyeioc_stillcapt(void) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - meye.grab_buffer[0].state = MEYE_BUF_USING; - mchip_take_picture(); - - mchip_get_picture(meye.grab_fbuffer, - mchip_hsize() * mchip_vsize() * 2); - - meye.grab_buffer[0].state = MEYE_BUF_DONE; - mutex_unlock(&meye.lock); - - return 0; -} - -static int meyeioc_stilljcapt(int *len) -{ - if (!meye.grab_fbuffer) - return -EINVAL; - - if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) - return -EBUSY; - - mutex_lock(&meye.lock); - meye.grab_buffer[0].state = MEYE_BUF_USING; - *len = -1; - - while (*len == -1) { - mchip_take_picture(); - *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); - } - - meye.grab_buffer[0].state = MEYE_BUF_DONE; - mutex_unlock(&meye.lock); - return 0; -} - -static int vidioc_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - strscpy(cap->driver, "meye", sizeof(cap->driver)); - strscpy(cap->card, "meye", sizeof(cap->card)); - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strscpy(i->name, "Camera", sizeof(i->name)); - i->type = V4L2_INPUT_TYPE_CAMERA; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) -{ - if (i != 0) - return -EINVAL; - - return 0; -} - -static int meye_s_ctrl(struct v4l2_ctrl *ctrl) -{ - mutex_lock(&meye.lock); - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, ctrl->val); - meye.brightness = ctrl->val << 10; - break; - case V4L2_CID_HUE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAHUE, ctrl->val); - meye.hue = ctrl->val << 10; - break; - case V4L2_CID_CONTRAST: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACONTRAST, ctrl->val); - meye.contrast = ctrl->val << 10; - break; - case V4L2_CID_SATURATION: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERACOLOR, ctrl->val); - meye.colour = ctrl->val << 10; - break; - case V4L2_CID_MEYE_AGC: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAAGC, ctrl->val); - meye.params.agc = ctrl->val; - break; - case V4L2_CID_SHARPNESS: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERASHARPNESS, ctrl->val); - meye.params.sharpness = ctrl->val; - break; - case V4L2_CID_MEYE_PICTURE: - sony_pic_camera_command( - SONY_PIC_COMMAND_SETCAMERAPICTURE, ctrl->val); - meye.params.picture = ctrl->val; - break; - case V4L2_CID_JPEG_COMPRESSION_QUALITY: - meye.params.quality = ctrl->val; - break; - case V4L2_CID_MEYE_FRAMERATE: - meye.params.framerate = ctrl->val; - break; - default: - mutex_unlock(&meye.lock); - return -EINVAL; - } - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *f) -{ - if (f->index > 1) - return -EINVAL; - - if (f->index == 0) { - /* standard YUV 422 capture */ - f->flags = 0; - f->pixelformat = V4L2_PIX_FMT_YUYV; - } else { - /* compressed MJPEG capture */ - f->pixelformat = V4L2_PIX_FMT_MJPEG; - } - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - - if (f->fmt.pix.width <= 320) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - } else { - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - } - - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - - return 0; -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - switch (meye.mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - default: - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - break; - case MCHIP_HIC_MODE_CONT_COMP: - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; - break; - } - - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.width = mchip_hsize(); - f->fmt.pix.height = mchip_vsize(); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV && - f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (f->fmt.pix.field != V4L2_FIELD_ANY && - f->fmt.pix.field != V4L2_FIELD_NONE) - return -EINVAL; - - f->fmt.pix.field = V4L2_FIELD_NONE; - mutex_lock(&meye.lock); - - if (f->fmt.pix.width <= 320) { - f->fmt.pix.width = 320; - f->fmt.pix.height = 240; - meye.params.subsample = 1; - } else { - f->fmt.pix.width = 640; - f->fmt.pix.height = 480; - meye.params.subsample = 0; - } - - switch (f->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_YUYV: - meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT; - break; - case V4L2_PIX_FMT_MJPEG: - meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; - break; - } - - mutex_unlock(&meye.lock); - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.height * - f->fmt.pix.bytesperline; - f->fmt.pix.colorspace = 0; - - return 0; -} - -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) -{ - int i; - - if (req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (meye.grab_fbuffer && req->count == gbuffers) { - /* already allocated, no modifications */ - return 0; - } - - mutex_lock(&meye.lock); - if (meye.grab_fbuffer) { - for (i = 0; i < gbuffers; i++) - if (meye.vma_use_count[i]) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - rvfree(meye.grab_fbuffer, gbuffers * gbufsize); - meye.grab_fbuffer = NULL; - } - - gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS)); - req->count = gbuffers; - meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize); - - if (!meye.grab_fbuffer) { - printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); - mutex_unlock(&meye.lock); - return -ENOMEM; - } - - for (i = 0; i < gbuffers; i++) - meye.vma_use_count[i] = 0; - - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - unsigned int index = buf->index; - - if (index >= gbuffers) - return -EINVAL; - - buf->bytesused = meye.grab_buffer[index].size; - buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - - if (meye.grab_buffer[index].state == MEYE_BUF_USING) - buf->flags |= V4L2_BUF_FLAG_QUEUED; - - if (meye.grab_buffer[index].state == MEYE_BUF_DONE) - buf->flags |= V4L2_BUF_FLAG_DONE; - - buf->field = V4L2_FIELD_NONE; - v4l2_buffer_set_timestamp(buf, meye.grab_buffer[index].ts); - buf->sequence = meye.grab_buffer[index].sequence; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = index * gbufsize; - buf->length = gbufsize; - - return 0; -} - -static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (buf->index >= gbuffers) - return -EINVAL; - - if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) - return -EINVAL; - - mutex_lock(&meye.lock); - buf->flags |= V4L2_BUF_FLAG_QUEUED; - buf->flags &= ~V4L2_BUF_FLAG_DONE; - meye.grab_buffer[buf->index].state = MEYE_BUF_USING; - kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, - sizeof(int), &meye.grabq_lock); - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) -{ - int reqnr; - - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - mutex_lock(&meye.lock); - - if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - - if (wait_event_interruptible(meye.proc_list, - kfifo_len(&meye.doneq) != 0) < 0) { - mutex_unlock(&meye.lock); - return -EINTR; - } - - if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, - sizeof(int), &meye.doneq_lock)) { - mutex_unlock(&meye.lock); - return -EBUSY; - } - - if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - - buf->index = reqnr; - buf->bytesused = meye.grab_buffer[reqnr].size; - buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - buf->field = V4L2_FIELD_NONE; - v4l2_buffer_set_timestamp(buf, meye.grab_buffer[reqnr].ts); - buf->sequence = meye.grab_buffer[reqnr].sequence; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = reqnr * gbufsize; - buf->length = gbufsize; - meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED; - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -{ - mutex_lock(&meye.lock); - - switch (meye.mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - mchip_continuous_start(); - break; - case MCHIP_HIC_MODE_CONT_COMP: - mchip_cont_compression_start(); - break; - default: - mutex_unlock(&meye.lock); - return -EINVAL; - } - - mutex_unlock(&meye.lock); - - return 0; -} - -static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) -{ - mutex_lock(&meye.lock); - mchip_hic_stop(); - kfifo_reset(&meye.grabq); - kfifo_reset(&meye.doneq); - - for (i = 0; i < MEYE_MAX_BUFNBRS; i++) - meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - - mutex_unlock(&meye.lock); - return 0; -} - -static long vidioc_default(struct file *file, void *fh, bool valid_prio, - unsigned int cmd, void *arg) -{ - switch (cmd) { - case MEYEIOC_G_PARAMS: - return meyeioc_g_params((struct meye_params *) arg); - - case MEYEIOC_S_PARAMS: - return meyeioc_s_params((struct meye_params *) arg); - - case MEYEIOC_QBUF_CAPT: - return meyeioc_qbuf_capt((int *) arg); - - case MEYEIOC_SYNC: - return meyeioc_sync(file, fh, (int *) arg); - - case MEYEIOC_STILLCAPT: - return meyeioc_stillcapt(); - - case MEYEIOC_STILLJCAPT: - return meyeioc_stilljcapt((int *) arg); - - default: - return -ENOTTY; - } - -} - -static __poll_t meye_poll(struct file *file, poll_table *wait) -{ - __poll_t res = v4l2_ctrl_poll(file, wait); - - mutex_lock(&meye.lock); - poll_wait(file, &meye.proc_list, wait); - if (kfifo_len(&meye.doneq)) - res |= EPOLLIN | EPOLLRDNORM; - mutex_unlock(&meye.lock); - return res; -} - -static void meye_vm_open(struct vm_area_struct *vma) -{ - long idx = (long)vma->vm_private_data; - meye.vma_use_count[idx]++; -} - -static void meye_vm_close(struct vm_area_struct *vma) -{ - long idx = (long)vma->vm_private_data; - meye.vma_use_count[idx]--; -} - -static const struct vm_operations_struct meye_vm_ops = { - .open = meye_vm_open, - .close = meye_vm_close, -}; - -static int meye_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long page, pos; - - mutex_lock(&meye.lock); - if (size > gbuffers * gbufsize || offset > gbuffers * gbufsize - size) { - mutex_unlock(&meye.lock); - return -EINVAL; - } - if (!meye.grab_fbuffer) { - int i; - - /* lazy allocation */ - meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize); - if (!meye.grab_fbuffer) { - printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); - mutex_unlock(&meye.lock); - return -ENOMEM; - } - for (i = 0; i < gbuffers; i++) - meye.vma_use_count[i] = 0; - } - pos = (unsigned long)meye.grab_fbuffer + offset; - - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - vma->vm_ops = &meye_vm_ops; - vma->vm_flags &= ~VM_IO; /* not I/O memory */ - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_private_data = (void *) (offset / gbufsize); - meye_vm_open(vma); - - mutex_unlock(&meye.lock); - return 0; -} - -static const struct v4l2_file_operations meye_fops = { - .owner = THIS_MODULE, - .open = meye_open, - .release = meye_release, - .mmap = meye_mmap, - .unlocked_ioctl = video_ioctl2, - .poll = meye_poll, -}; - -static const struct v4l2_ioctl_ops meye_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_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_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - .vidioc_default = vidioc_default, -}; - -static const struct video_device meye_template = { - .name = "meye", - .fops = &meye_fops, - .ioctl_ops = &meye_ioctl_ops, - .release = video_device_release_empty, - .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, -}; - -static const struct v4l2_ctrl_ops meye_ctrl_ops = { - .s_ctrl = meye_s_ctrl, -}; - -static int __maybe_unused meye_suspend(struct device *dev) -{ - meye.pm_mchip_mode = meye.mchip_mode; - mchip_hic_stop(); - mchip_set(MCHIP_MM_INTA, 0x0); - return 0; -} - -static int __maybe_unused meye_resume(struct device *dev) -{ - pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); - - mchip_delay(MCHIP_HIC_CMD, 0); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); - msleep(1); - mchip_set(MCHIP_VRJ_SOFT_RESET, 1); - msleep(1); - mchip_set(MCHIP_MM_PCI_MODE, 5); - msleep(1); - mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - - switch (meye.pm_mchip_mode) { - case MCHIP_HIC_MODE_CONT_OUT: - mchip_continuous_start(); - break; - case MCHIP_HIC_MODE_CONT_COMP: - mchip_cont_compression_start(); - break; - } - return 0; -} - -static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) -{ - static const struct v4l2_ctrl_config ctrl_agc = { - .id = V4L2_CID_MEYE_AGC, - .type = V4L2_CTRL_TYPE_INTEGER, - .ops = &meye_ctrl_ops, - .name = "AGC", - .max = 63, - .step = 1, - .def = 48, - .flags = V4L2_CTRL_FLAG_SLIDER, - }; - static const struct v4l2_ctrl_config ctrl_picture = { - .id = V4L2_CID_MEYE_PICTURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .ops = &meye_ctrl_ops, - .name = "Picture", - .max = 63, - .step = 1, - }; - static const struct v4l2_ctrl_config ctrl_framerate = { - .id = V4L2_CID_MEYE_FRAMERATE, - .type = V4L2_CTRL_TYPE_INTEGER, - .ops = &meye_ctrl_ops, - .name = "Framerate", - .max = 31, - .step = 1, - }; - struct v4l2_device *v4l2_dev = &meye.v4l2_dev; - int ret = -EBUSY; - unsigned long mchip_adr; - - if (meye.mchip_dev != NULL) { - printk(KERN_ERR "meye: only one device allowed!\n"); - return ret; - } - - ret = v4l2_device_register(&pcidev->dev, v4l2_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return ret; - } - ret = -ENOMEM; - meye.mchip_dev = pcidev; - - meye.grab_temp = vmalloc(array_size(PAGE_SIZE, MCHIP_NB_PAGES_MJPEG)); - if (!meye.grab_temp) - goto outvmalloc; - - spin_lock_init(&meye.grabq_lock); - if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) - goto outkfifoalloc1; - - spin_lock_init(&meye.doneq_lock); - if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) - goto outkfifoalloc2; - - meye.vdev = meye_template; - meye.vdev.v4l2_dev = &meye.v4l2_dev; - - ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1); - if (ret) { - v4l2_err(v4l2_dev, "meye: unable to power on the camera\n"); - v4l2_err(v4l2_dev, "meye: did you enable the camera in sonypi using the module options ?\n"); - goto outsonypienable; - } - - ret = pci_enable_device(meye.mchip_dev); - if (ret) { - v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n"); - goto outenabledev; - } - - ret = -EIO; - mchip_adr = pci_resource_start(meye.mchip_dev,0); - if (!mchip_adr) { - v4l2_err(v4l2_dev, "meye: mchip has no device base address\n"); - goto outregions; - } - if (!request_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0), - "meye")) { - v4l2_err(v4l2_dev, "meye: request_mem_region failed\n"); - goto outregions; - } - meye.mchip_mmregs = ioremap(mchip_adr, MCHIP_MM_REGS); - if (!meye.mchip_mmregs) { - v4l2_err(v4l2_dev, "meye: ioremap failed\n"); - goto outremap; - } - - meye.mchip_irq = pcidev->irq; - if (request_irq(meye.mchip_irq, meye_irq, - IRQF_SHARED, "meye", meye_irq)) { - v4l2_err(v4l2_dev, "request_irq failed\n"); - goto outreqirq; - } - - pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8); - pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64); - - pci_set_master(meye.mchip_dev); - - /* Ask the camera to perform a soft reset. */ - pci_write_config_word(meye.mchip_dev, MCHIP_PCI_SOFTRESET_SET, 1); - - mchip_delay(MCHIP_HIC_CMD, 0); - mchip_delay(MCHIP_HIC_STATUS, MCHIP_HIC_STATUS_IDLE); - - msleep(1); - mchip_set(MCHIP_VRJ_SOFT_RESET, 1); - - msleep(1); - mchip_set(MCHIP_MM_PCI_MODE, 5); - - msleep(1); - mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - - mutex_init(&meye.lock); - init_waitqueue_head(&meye.proc_list); - - v4l2_ctrl_handler_init(&meye.hdl, 3); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 63, 1, 32); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_HUE, 0, 63, 1, 32); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_CONTRAST, 0, 63, 1, 32); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_SATURATION, 0, 63, 1, 32); - v4l2_ctrl_new_custom(&meye.hdl, &ctrl_agc, NULL); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_SHARPNESS, 0, 63, 1, 32); - v4l2_ctrl_new_custom(&meye.hdl, &ctrl_picture, NULL); - v4l2_ctrl_new_std(&meye.hdl, &meye_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, 10, 1, 8); - v4l2_ctrl_new_custom(&meye.hdl, &ctrl_framerate, NULL); - if (meye.hdl.error) { - v4l2_err(v4l2_dev, "couldn't register controls\n"); - goto outvideoreg; - } - - v4l2_ctrl_handler_setup(&meye.hdl); - meye.vdev.ctrl_handler = &meye.hdl; - - if (video_register_device(&meye.vdev, VFL_TYPE_VIDEO, - video_nr) < 0) { - v4l2_err(v4l2_dev, "video_register_device failed\n"); - goto outvideoreg; - } - - v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n", - MEYE_DRIVER_VERSION); - v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n", - meye.mchip_dev->revision, mchip_adr, meye.mchip_irq); - - return 0; - -outvideoreg: - v4l2_ctrl_handler_free(&meye.hdl); - free_irq(meye.mchip_irq, meye_irq); -outreqirq: - iounmap(meye.mchip_mmregs); -outremap: - release_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0)); -outregions: - pci_disable_device(meye.mchip_dev); -outenabledev: - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); -outsonypienable: - kfifo_free(&meye.doneq); -outkfifoalloc2: - kfifo_free(&meye.grabq); -outkfifoalloc1: - vfree(meye.grab_temp); -outvmalloc: - return ret; -} - -static void meye_remove(struct pci_dev *pcidev) -{ - video_unregister_device(&meye.vdev); - - mchip_hic_stop(); - - mchip_dma_free(); - - /* disable interrupts */ - mchip_set(MCHIP_MM_INTA, 0x0); - - free_irq(meye.mchip_irq, meye_irq); - - iounmap(meye.mchip_mmregs); - - release_mem_region(pci_resource_start(meye.mchip_dev, 0), - pci_resource_len(meye.mchip_dev, 0)); - - pci_disable_device(meye.mchip_dev); - - sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - - kfifo_free(&meye.doneq); - kfifo_free(&meye.grabq); - - vfree(meye.grab_temp); - - if (meye.grab_fbuffer) { - rvfree(meye.grab_fbuffer, gbuffers*gbufsize); - meye.grab_fbuffer = NULL; - } - - printk(KERN_INFO "meye: removed\n"); -} - -static const struct pci_device_id meye_pci_tbl[] = { - { PCI_VDEVICE(KAWASAKI, PCI_DEVICE_ID_MCHIP_KL5A72002), 0 }, - { } -}; - -MODULE_DEVICE_TABLE(pci, meye_pci_tbl); - -static SIMPLE_DEV_PM_OPS(meye_pm_ops, meye_suspend, meye_resume); - -static struct pci_driver meye_driver = { - .name = "meye", - .id_table = meye_pci_tbl, - .probe = meye_probe, - .remove = meye_remove, - .driver.pm = &meye_pm_ops, -}; - -static int __init meye_init(void) -{ - gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS)); - if (gbufsize > MEYE_MAX_BUFSIZE) - gbufsize = MEYE_MAX_BUFSIZE; - gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) for capture\n", - gbuffers, - gbufsize / 1024, gbuffers * gbufsize / 1024); - return pci_register_driver(&meye_driver); -} - -static void __exit meye_exit(void) -{ - pci_unregister_driver(&meye_driver); -} - -module_init(meye_init); -module_exit(meye_exit); diff --git a/drivers/media/pci/meye/meye.h b/drivers/media/pci/meye/meye.h deleted file mode 100644 index 5fa6552cf93d..000000000000 --- a/drivers/media/pci/meye/meye.h +++ /dev/null @@ -1,311 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Motion Eye video4linux driver for Sony Vaio PictureBook - * - * Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net> - * - * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com> - * - * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> - * - * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. - * - * Some parts borrowed from various video4linux drivers, especially - * bttv-driver.c and zoran.c, see original files for credits. - */ - -#ifndef _MEYE_PRIV_H_ -#define _MEYE_PRIV_H_ - -#define MEYE_DRIVER_MAJORVERSION 1 -#define MEYE_DRIVER_MINORVERSION 14 - -#define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \ - __stringify(MEYE_DRIVER_MINORVERSION) - -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/kfifo.h> -#include <media/v4l2-ctrls.h> - -/****************************************************************************/ -/* Motion JPEG chip registers */ -/****************************************************************************/ - -/* Motion JPEG chip PCI configuration registers */ -#define MCHIP_PCI_POWER_CSR 0x54 -#define MCHIP_PCI_MCORE_STATUS 0x60 /* see HIC_STATUS */ -#define MCHIP_PCI_HOSTUSEREQ_SET 0x64 -#define MCHIP_PCI_HOSTUSEREQ_CLR 0x68 -#define MCHIP_PCI_LOWPOWER_SET 0x6c -#define MCHIP_PCI_LOWPOWER_CLR 0x70 -#define MCHIP_PCI_SOFTRESET_SET 0x74 - -/* Motion JPEG chip memory mapped registers */ -#define MCHIP_MM_REGS 0x200 /* 512 bytes */ -#define MCHIP_REG_TIMEOUT 1000 /* reg access, ~us */ -#define MCHIP_MCC_VRJ_TIMEOUT 1000 /* MCC & VRJ access */ - -#define MCHIP_MM_PCI_MODE 0x00 /* PCI access mode */ -#define MCHIP_MM_PCI_MODE_RETRY 0x00000001 /* retry mode */ -#define MCHIP_MM_PCI_MODE_MASTER 0x00000002 /* master access */ -#define MCHIP_MM_PCI_MODE_READ_LINE 0x00000004 /* read line */ - -#define MCHIP_MM_INTA 0x04 /* Int status/mask */ -#define MCHIP_MM_INTA_MCC 0x00000001 /* MCC interrupt */ -#define MCHIP_MM_INTA_VRJ 0x00000002 /* VRJ interrupt */ -#define MCHIP_MM_INTA_HIC_1 0x00000004 /* one frame done */ -#define MCHIP_MM_INTA_HIC_1_MASK 0x00000400 /* 1: enable */ -#define MCHIP_MM_INTA_HIC_END 0x00000008 /* all frames done */ -#define MCHIP_MM_INTA_HIC_END_MASK 0x00000800 -#define MCHIP_MM_INTA_JPEG 0x00000010 /* decompress. error */ -#define MCHIP_MM_INTA_JPEG_MASK 0x00001000 -#define MCHIP_MM_INTA_CAPTURE 0x00000020 /* capture end */ -#define MCHIP_MM_INTA_PCI_ERR 0x00000040 /* PCI error */ -#define MCHIP_MM_INTA_PCI_ERR_MASK 0x00004000 - -#define MCHIP_MM_PT_ADDR 0x08 /* page table address*/ - /* n*4kB */ -#define MCHIP_NB_PAGES 1024 /* pages for display */ -#define MCHIP_NB_PAGES_MJPEG 256 /* pages for mjpeg */ - -#define MCHIP_MM_FIR(n) (0x0c+(n)*4) /* Frame info 0-3 */ -#define MCHIP_MM_FIR_RDY 0x00000001 /* frame ready */ -#define MCHIP_MM_FIR_FAILFR_MASK 0xf8000000 /* # of failed frames */ -#define MCHIP_MM_FIR_FAILFR_SHIFT 27 - - /* continuous comp/decomp mode */ -#define MCHIP_MM_FIR_C_ENDL_MASK 0x000007fe /* end DW [10] */ -#define MCHIP_MM_FIR_C_ENDL_SHIFT 1 -#define MCHIP_MM_FIR_C_ENDP_MASK 0x0007f800 /* end page [8] */ -#define MCHIP_MM_FIR_C_ENDP_SHIFT 11 -#define MCHIP_MM_FIR_C_STARTP_MASK 0x07f80000 /* start page [8] */ -#define MCHIP_MM_FIR_C_STARTP_SHIFT 19 - - /* continuous picture output mode */ -#define MCHIP_MM_FIR_O_STARTP_MASK 0x7ffe0000 /* start page [10] */ -#define MCHIP_MM_FIR_O_STARTP_SHIFT 17 - -#define MCHIP_MM_FIFO_DATA 0x1c /* PCI TGT FIFO data */ -#define MCHIP_MM_FIFO_STATUS 0x20 /* PCI TGT FIFO stat */ -#define MCHIP_MM_FIFO_MASK 0x00000003 -#define MCHIP_MM_FIFO_WAIT_OR_READY 0x00000002 /* Bits common to WAIT & READY*/ -#define MCHIP_MM_FIFO_IDLE 0x0 /* HIC idle */ -#define MCHIP_MM_FIFO_IDLE1 0x1 /* idem ??? */ -#define MCHIP_MM_FIFO_WAIT 0x2 /* wait request */ -#define MCHIP_MM_FIFO_READY 0x3 /* data ready */ - -#define MCHIP_HIC_HOST_USEREQ 0x40 /* host uses MCORE */ - -#define MCHIP_HIC_TP_BUSY 0x44 /* taking picture */ - -#define MCHIP_HIC_PIC_SAVED 0x48 /* pic in SDRAM */ - -#define MCHIP_HIC_LOWPOWER 0x4c /* clock stopped */ - -#define MCHIP_HIC_CTL 0x50 /* HIC control */ -#define MCHIP_HIC_CTL_SOFT_RESET 0x00000001 /* MCORE reset */ -#define MCHIP_HIC_CTL_MCORE_RDY 0x00000002 /* MCORE ready */ - -#define MCHIP_HIC_CMD 0x54 /* HIC command */ -#define MCHIP_HIC_CMD_BITS 0x00000003 /* cmd width=[1:0]*/ -#define MCHIP_HIC_CMD_NOOP 0x0 -#define MCHIP_HIC_CMD_START 0x1 -#define MCHIP_HIC_CMD_STOP 0x2 - -#define MCHIP_HIC_MODE 0x58 -#define MCHIP_HIC_MODE_NOOP 0x0 -#define MCHIP_HIC_MODE_STILL_CAP 0x1 /* still pic capt */ -#define MCHIP_HIC_MODE_DISPLAY 0x2 /* display */ -#define MCHIP_HIC_MODE_STILL_COMP 0x3 /* still pic comp. */ -#define MCHIP_HIC_MODE_STILL_DECOMP 0x4 /* still pic decomp. */ -#define MCHIP_HIC_MODE_CONT_COMP 0x5 /* cont capt+comp */ -#define MCHIP_HIC_MODE_CONT_DECOMP 0x6 /* cont decomp+disp */ -#define MCHIP_HIC_MODE_STILL_OUT 0x7 /* still pic output */ -#define MCHIP_HIC_MODE_CONT_OUT 0x8 /* cont output */ - -#define MCHIP_HIC_STATUS 0x5c -#define MCHIP_HIC_STATUS_MCC_RDY 0x00000001 /* MCC reg acc ok */ -#define MCHIP_HIC_STATUS_VRJ_RDY 0x00000002 /* VRJ reg acc ok */ -#define MCHIP_HIC_STATUS_IDLE 0x00000003 -#define MCHIP_HIC_STATUS_CAPDIS 0x00000004 /* cap/disp in prog */ -#define MCHIP_HIC_STATUS_COMPDEC 0x00000008 /* (de)comp in prog */ -#define MCHIP_HIC_STATUS_BUSY 0x00000010 /* HIC busy */ - -#define MCHIP_HIC_S_RATE 0x60 /* MJPEG # frames */ - -#define MCHIP_HIC_PCI_VFMT 0x64 /* video format */ -#define MCHIP_HIC_PCI_VFMT_YVYU 0x00000001 /* 0: V Y' U Y */ - /* 1: Y' V Y U */ - -#define MCHIP_MCC_CMD 0x80 /* MCC commands */ -#define MCHIP_MCC_CMD_INITIAL 0x0 /* idle ? */ -#define MCHIP_MCC_CMD_IIC_START_SET 0x1 -#define MCHIP_MCC_CMD_IIC_END_SET 0x2 -#define MCHIP_MCC_CMD_FM_WRITE 0x3 /* frame memory */ -#define MCHIP_MCC_CMD_FM_READ 0x4 -#define MCHIP_MCC_CMD_FM_STOP 0x5 -#define MCHIP_MCC_CMD_CAPTURE 0x6 -#define MCHIP_MCC_CMD_DISPLAY 0x7 -#define MCHIP_MCC_CMD_END_DISP 0x8 -#define MCHIP_MCC_CMD_STILL_COMP 0x9 -#define MCHIP_MCC_CMD_STILL_DECOMP 0xa -#define MCHIP_MCC_CMD_STILL_OUTPUT 0xb -#define MCHIP_MCC_CMD_CONT_OUTPUT 0xc -#define MCHIP_MCC_CMD_CONT_COMP 0xd -#define MCHIP_MCC_CMD_CONT_DECOMP 0xe -#define MCHIP_MCC_CMD_RESET 0xf /* MCC reset */ - -#define MCHIP_MCC_IIC_WR 0x84 - -#define MCHIP_MCC_MCC_WR 0x88 - -#define MCHIP_MCC_MCC_RD 0x8c - -#define MCHIP_MCC_STATUS 0x90 -#define MCHIP_MCC_STATUS_CAPT 0x00000001 /* capturing */ -#define MCHIP_MCC_STATUS_DISP 0x00000002 /* displaying */ -#define MCHIP_MCC_STATUS_COMP 0x00000004 /* compressing */ -#define MCHIP_MCC_STATUS_DECOMP 0x00000008 /* decompressing */ -#define MCHIP_MCC_STATUS_MCC_WR 0x00000010 /* register ready */ -#define MCHIP_MCC_STATUS_MCC_RD 0x00000020 /* register ready */ -#define MCHIP_MCC_STATUS_IIC_WR 0x00000040 /* register ready */ -#define MCHIP_MCC_STATUS_OUTPUT 0x00000080 /* output in prog */ - -#define MCHIP_MCC_SIG_POLARITY 0x94 -#define MCHIP_MCC_SIG_POL_VS_H 0x00000001 /* VS active-high */ -#define MCHIP_MCC_SIG_POL_HS_H 0x00000002 /* HS active-high */ -#define MCHIP_MCC_SIG_POL_DOE_H 0x00000004 /* DOE active-high */ - -#define MCHIP_MCC_IRQ 0x98 -#define MCHIP_MCC_IRQ_CAPDIS_STRT 0x00000001 /* cap/disp started */ -#define MCHIP_MCC_IRQ_CAPDIS_STRT_MASK 0x00000010 -#define MCHIP_MCC_IRQ_CAPDIS_END 0x00000002 /* cap/disp ended */ -#define MCHIP_MCC_IRQ_CAPDIS_END_MASK 0x00000020 -#define MCHIP_MCC_IRQ_COMPDEC_STRT 0x00000004 /* (de)comp started */ -#define MCHIP_MCC_IRQ_COMPDEC_STRT_MASK 0x00000040 -#define MCHIP_MCC_IRQ_COMPDEC_END 0x00000008 /* (de)comp ended */ -#define MCHIP_MCC_IRQ_COMPDEC_END_MASK 0x00000080 - -#define MCHIP_MCC_HSTART 0x9c /* video in */ -#define MCHIP_MCC_VSTART 0xa0 -#define MCHIP_MCC_HCOUNT 0xa4 -#define MCHIP_MCC_VCOUNT 0xa8 -#define MCHIP_MCC_R_XBASE 0xac /* capt/disp */ -#define MCHIP_MCC_R_YBASE 0xb0 -#define MCHIP_MCC_R_XRANGE 0xb4 -#define MCHIP_MCC_R_YRANGE 0xb8 -#define MCHIP_MCC_B_XBASE 0xbc /* comp/decomp */ -#define MCHIP_MCC_B_YBASE 0xc0 -#define MCHIP_MCC_B_XRANGE 0xc4 -#define MCHIP_MCC_B_YRANGE 0xc8 - -#define MCHIP_MCC_R_SAMPLING 0xcc /* 1: 1:4 */ - -#define MCHIP_VRJ_CMD 0x100 /* VRJ commands */ - -/* VRJ registers (see table 12.2.4) */ -#define MCHIP_VRJ_COMPRESSED_DATA 0x1b0 -#define MCHIP_VRJ_PIXEL_DATA 0x1b8 - -#define MCHIP_VRJ_BUS_MODE 0x100 -#define MCHIP_VRJ_SIGNAL_ACTIVE_LEVEL 0x108 -#define MCHIP_VRJ_PDAT_USE 0x110 -#define MCHIP_VRJ_MODE_SPECIFY 0x118 -#define MCHIP_VRJ_LIMIT_COMPRESSED_LO 0x120 -#define MCHIP_VRJ_LIMIT_COMPRESSED_HI 0x124 -#define MCHIP_VRJ_COMP_DATA_FORMAT 0x128 -#define MCHIP_VRJ_TABLE_DATA 0x140 -#define MCHIP_VRJ_RESTART_INTERVAL 0x148 -#define MCHIP_VRJ_NUM_LINES 0x150 -#define MCHIP_VRJ_NUM_PIXELS 0x158 -#define MCHIP_VRJ_NUM_COMPONENTS 0x160 -#define MCHIP_VRJ_SOF1 0x168 -#define MCHIP_VRJ_SOF2 0x170 -#define MCHIP_VRJ_SOF3 0x178 -#define MCHIP_VRJ_SOF4 0x180 -#define MCHIP_VRJ_SOS 0x188 -#define MCHIP_VRJ_SOFT_RESET 0x190 - -#define MCHIP_VRJ_STATUS 0x1c0 -#define MCHIP_VRJ_STATUS_BUSY 0x00001 -#define MCHIP_VRJ_STATUS_COMP_ACCESS 0x00002 -#define MCHIP_VRJ_STATUS_PIXEL_ACCESS 0x00004 -#define MCHIP_VRJ_STATUS_ERROR 0x00008 - -#define MCHIP_VRJ_IRQ_FLAG 0x1c8 -#define MCHIP_VRJ_ERROR_REPORT 0x1d8 - -#define MCHIP_VRJ_START_COMMAND 0x1a0 - -/****************************************************************************/ -/* Driver definitions. */ -/****************************************************************************/ - -/* Sony Programmable I/O Controller for accessing the camera commands */ -#include <linux/sony-laptop.h> - -/* private API definitions */ -#include <linux/meye.h> -#include <linux/mutex.h> - - -/* Enable jpg software correction */ -#define MEYE_JPEG_CORRECTION 1 - -/* Maximum size of a buffer */ -#define MEYE_MAX_BUFSIZE 614400 /* 640 * 480 * 2 */ - -/* Maximum number of buffers */ -#define MEYE_MAX_BUFNBRS 32 - -/* State of a buffer */ -#define MEYE_BUF_UNUSED 0 /* not used */ -#define MEYE_BUF_USING 1 /* currently grabbing / playing */ -#define MEYE_BUF_DONE 2 /* done */ - -/* grab buffer */ -struct meye_grab_buffer { - int state; /* state of buffer */ - unsigned long size; /* size of jpg frame */ - u64 ts; /* timestamp */ - unsigned long sequence; /* sequence number */ -}; - -/* size of kfifos containing buffer indices */ -#define MEYE_QUEUE_SIZE MEYE_MAX_BUFNBRS - -/* Motion Eye device structure */ -struct meye { - struct v4l2_device v4l2_dev; /* Main v4l2_device struct */ - struct v4l2_ctrl_handler hdl; - struct pci_dev *mchip_dev; /* pci device */ - u8 mchip_irq; /* irq */ - u8 mchip_mode; /* actual mchip mode: HIC_MODE... */ - u8 mchip_fnum; /* current mchip frame number */ - unsigned char __iomem *mchip_mmregs;/* mchip: memory mapped registers */ - u8 *mchip_ptable[MCHIP_NB_PAGES];/* mchip: ptable */ - void *mchip_ptable_toc; /* mchip: ptable toc */ - dma_addr_t mchip_dmahandle; /* mchip: dma handle to ptable toc */ - unsigned char *grab_fbuffer; /* capture framebuffer */ - unsigned char *grab_temp; /* temporary buffer */ - /* list of buffers */ - struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; - int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ - struct mutex lock; /* mutex for open/mmap... */ - struct kfifo grabq; /* queue for buffers to be grabbed */ - spinlock_t grabq_lock; /* lock protecting the queue */ - struct kfifo doneq; /* queue for grabbed buffers */ - spinlock_t doneq_lock; /* lock protecting the queue */ - wait_queue_head_t proc_list; /* wait queue */ - struct video_device vdev; /* video device parameters */ - u16 brightness; - u16 hue; - u16 contrast; - u16 colour; - struct meye_params params; /* additional parameters */ - unsigned long in_use; /* set to 1 if the device is in use */ - u8 pm_mchip_mode; /* old mchip mode */ -}; - -#endif diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 3d296f1998a1..d1d7da84cd9d 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -596,43 +596,6 @@ struct mychip { int capture_source[MIXER_ADDR_LAST + 1][2]; }; -#ifdef NGENE_V4L -struct ngene_overlay { - int tvnorm; - struct v4l2_rect w; - enum v4l2_field field; - struct v4l2_clip *clips; - int nclips; - int setup_ok; -}; - -struct ngene_tvnorm { - int v4l2_id; - char *name; - u16 swidth, sheight; /* scaled standard width, height */ - int tuner_norm; - int soundstd; -}; - -struct ngene_vopen { - struct ngene_channel *ch; - enum v4l2_priority prio; - int width; - int height; - int depth; - struct videobuf_queue vbuf_q; - struct videobuf_queue vbi; - int fourcc; - int picxcount; - int resources; - enum v4l2_buf_type type; - const struct ngene_format *fmt; - - const struct ngene_format *ovfmt; - struct ngene_overlay ov; -}; -#endif - struct ngene_channel { struct device device; struct i2c_adapter i2c_adapter; @@ -709,18 +672,6 @@ struct ngene_channel { int tvnorm_num; int tvnorm; -#ifdef NGENE_V4L - int videousers; - struct v4l2_prio_state prio; - struct ngene_vopen init; - int resources; - struct v4l2_framebuffer fbuf; - struct ngene_buffer *screen; /* overlay */ - struct list_head capture; /* video capture queue */ - spinlock_t s_lock; - struct semaphore reslock; -#endif - int running; int tsin_offset; @@ -863,35 +814,6 @@ struct ngene_info { int (*switch_ctrl)(struct ngene_channel *, int, int); }; -#ifdef NGENE_V4L -struct ngene_format { - char *name; - int fourcc; /* video4linux 2 */ - int btformat; /* BT848_COLOR_FMT_* */ - int format; - int btswap; /* BT848_COLOR_CTL_* */ - int depth; /* bit/pixel */ - int flags; - int hshift, vshift; /* for planar modes */ - int palette; -}; - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 - -struct ngene_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* ngene specific */ - const struct ngene_format *fmt; - int tvnorm; - int btformat; - int btswap; -}; -#endif - /* Provided by ngene-core.c */ int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig deleted file mode 100644 index 3bbb68a0ed7b..000000000000 --- a/drivers/media/pci/saa7146/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber" - depends on PCI && VIDEO_DEV && I2C - select VIDEO_SAA7146_VV - help - This is a video4linux driver for the Hexium Gemini frame - grabber card by Hexium. Please note that the Gemini Dual - card is *not* fully supported. - - To compile this driver as a module, choose M here: the - module will be called hexium_gemini. - -config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber" - depends on PCI && VIDEO_DEV && I2C - select VIDEO_SAA7146_VV - help - This is a video4linux driver for the Hexium HV-PCI6 and - Orion frame grabber cards by Hexium. - - To compile this driver as a module, choose M here: the - module will be called hexium_orion. - -config VIDEO_MXB - tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" - depends on PCI && VIDEO_DEV && I2C - select VIDEO_SAA7146_VV - select VIDEO_TUNER - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TDA9840 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TEA6415C if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TEA6420 if MEDIA_SUBDRV_AUTOSELECT - help - This is a video4linux driver for the 'Multimedia eXtension Board' - TV card by Siemens-Nixdorf. - - To compile this driver as a module, choose M here: the - module will be called mxb. diff --git a/drivers/media/pci/saa7146/Makefile b/drivers/media/pci/saa7146/Makefile deleted file mode 100644 index 37c9336f83d5..000000000000 --- a/drivers/media/pci/saa7146/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_MXB) += mxb.o -obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o -obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o - -ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c deleted file mode 100644 index 3947701cd6c7..000000000000 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ /dev/null @@ -1,425 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards - - Visit http://www.mihu.de/linux/saa7146/ and follow the link - to "hexium" for further details about this card. - - Copyright (C) 2003 Michael Hunold <michael@mihu.de> - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DEBUG_VARIABLE debug - -#include <media/drv-intf/saa7146_vv.h> -#include <linux/module.h> -#include <linux/kernel.h> - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "debug verbosity"); - -/* global variables */ -static int hexium_num; - -#define HEXIUM_GEMINI 4 -#define HEXIUM_GEMINI_DUAL 5 - -#define HEXIUM_INPUTS 9 -static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { - { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, -}; - -#define HEXIUM_AUDIOS 0 - -struct hexium_data -{ - s8 adr; - u8 byte; -}; - -#define HEXIUM_GEMINI_V_1_0 1 -#define HEXIUM_GEMINI_DUAL_V_1_0 2 - -struct hexium -{ - int type; - - struct video_device video_dev; - struct i2c_adapter i2c_adapter; - - int cur_input; /* current input */ - v4l2_std_id cur_std; /* current standard */ -}; - -/* Samsung KS0127B decoder default registers */ -static u8 hexium_ks0127b[0x100]={ -/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10, -/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06, -/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00, -/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22, -/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00, -/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80, -/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00, -/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, -/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -static struct hexium_data hexium_pal[] = { - { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_ntsc[] = { - { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_secam[] = { - { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF } -}; - -static struct hexium_data hexium_input_select[] = { - { 0x02, 0x60 }, - { 0x02, 0x64 }, - { 0x02, 0x61 }, - { 0x02, 0x65 }, - { 0x02, 0x62 }, - { 0x02, 0x66 }, - { 0x02, 0x68 }, - { 0x02, 0x69 }, - { 0x02, 0x6A }, -}; - -/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which - are currently *not* supported*/ -static struct saa7146_standard hexium_standards[] = { - { - .name = "PAL", .id = V4L2_STD_PAL, - .v_offset = 28, .v_field = 288, - .h_offset = 1, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 28, .v_field = 240, - .h_offset = 1, .h_pixels = 640, - .v_max_out = 480, .h_max_out = 640, - }, { - .name = "SECAM", .id = V4L2_STD_SECAM, - .v_offset = 28, .v_field = 288, - .h_offset = 1, .h_pixels = 720, - .v_max_out = 576, .h_max_out = 768, - } -}; - -/* bring hardware to a sane state. this has to be done, just in case someone - wants to capture from this device before it has been properly initialized. - the capture engine would badly fail, because no valid signal arrives on the - saa7146, thus leading to timeouts and stuff. */ -static int hexium_init_done(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - union i2c_smbus_data data; - int i = 0; - - DEB_D("hexium_init_done called\n"); - - /* initialize the helper ics to useful values */ - for (i = 0; i < sizeof(hexium_ks0127b); i++) { - data.byte = hexium_ks0127b[i]; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { - pr_err("hexium_init_done() failed for address 0x%02x\n", - i); - } - } - - return 0; -} - -static int hexium_set_input(struct hexium *hexium, int input) -{ - union i2c_smbus_data data; - - DEB_D("\n"); - - data.byte = hexium_input_select[input].byte; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) { - return -1; - } - - return 0; -} - -static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) -{ - union i2c_smbus_data data; - int i = 0; - - DEB_D("\n"); - - while (vdec[i].adr != -1) { - data.byte = vdec[i].byte; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) { - pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", - i); - return -1; - } - i++; - } - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index); - - if (i->index >= HEXIUM_INPUTS) - return -EINVAL; - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - *input = hexium->cur_input; - - DEB_D("VIDIOC_G_INPUT: %d\n", *input); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - DEB_EE("VIDIOC_S_INPUT %d\n", input); - - if (input >= HEXIUM_INPUTS) - return -EINVAL; - - hexium->cur_input = input; - hexium_set_input(hexium, input); - return 0; -} - -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct hexium *hexium; - int ret; - - DEB_EE("\n"); - - hexium = kzalloc(sizeof(*hexium), GFP_KERNEL); - if (!hexium) - return -ENOMEM; - - dev->ext_priv = hexium; - - /* enable i2c-port pins */ - saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - - strscpy(hexium->i2c_adapter.name, "hexium gemini", - sizeof(hexium->i2c_adapter.name)); - saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); - if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { - DEB_S("cannot register i2c-device. skipping.\n"); - kfree(hexium); - return -EFAULT; - } - - /* set HWControl GPIO number 2 */ - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - - saa7146_write(dev, DD1_INIT, 0x07000700); - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - /* the rest */ - hexium->cur_input = 0; - hexium_init_done(dev); - - hexium_set_standard(hexium, hexium_pal); - hexium->cur_std = V4L2_STD_PAL; - - hexium_set_input(hexium, 0); - hexium->cur_input = 0; - - ret = saa7146_vv_init(dev, &vv_data); - if (ret) { - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return ret; - } - - vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; - vv_data.vid_ops.vidioc_g_input = vidioc_g_input; - vv_data.vid_ops.vidioc_s_input = vidioc_s_input; - ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO); - if (ret < 0) { - pr_err("cannot register capture v4l2 device. skipping.\n"); - saa7146_vv_release(dev); - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return ret; - } - - pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num); - hexium_num++; - - return 0; -} - -static int hexium_detach(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - DEB_EE("dev:%p\n", dev); - - saa7146_unregister_device(&hexium->video_dev, dev); - saa7146_vv_release(dev); - - hexium_num--; - - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return 0; -} - -static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - if (V4L2_STD_PAL == std->id) { - hexium_set_standard(hexium, hexium_pal); - hexium->cur_std = V4L2_STD_PAL; - return 0; - } else if (V4L2_STD_NTSC == std->id) { - hexium_set_standard(hexium, hexium_ntsc); - hexium->cur_std = V4L2_STD_NTSC; - return 0; - } else if (V4L2_STD_SECAM == std->id) { - hexium_set_standard(hexium, hexium_secam); - hexium->cur_std = V4L2_STD_SECAM; - return 0; - } - - return -1; -} - -static struct saa7146_extension hexium_extension; - -static struct saa7146_pci_extension_data hexium_gemini_4bnc = { - .ext_priv = "Hexium Gemini (4 BNC)", - .ext = &hexium_extension, -}; - -static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { - .ext_priv = "Hexium Gemini Dual (4 BNC)", - .ext = &hexium_extension, -}; - -static const struct pci_device_id pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2401, - .driver_data = (unsigned long) &hexium_gemini_4bnc, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2402, - .driver_data = (unsigned long) &hexium_gemini_dual_4bnc, - }, - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_ext_vv vv_data = { - .inputs = HEXIUM_INPUTS, - .capabilities = 0, - .stds = &hexium_standards[0], - .num_stds = ARRAY_SIZE(hexium_standards), - .std_callback = &std_callback, -}; - -static struct saa7146_extension hexium_extension = { - .name = "hexium gemini", - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = &pci_tbl[0], - .module = THIS_MODULE, - - .attach = hexium_attach, - .detach = hexium_detach, - - .irq_mask = 0, - .irq_func = NULL, -}; - -static int __init hexium_init_module(void) -{ - if (0 != saa7146_register_extension(&hexium_extension)) { - DEB_S("failed to register extension\n"); - return -ENODEV; - } - - return 0; -} - -static void __exit hexium_cleanup_module(void) -{ - saa7146_unregister_extension(&hexium_extension); -} - -module_init(hexium_init_module); -module_exit(hexium_cleanup_module); - -MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards"); -MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c deleted file mode 100644 index 2eb4bee16b71..000000000000 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ /dev/null @@ -1,496 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards - - Visit http://www.mihu.de/linux/saa7146/ and follow the link - to "hexium" for further details about this card. - - Copyright (C) 2003 Michael Hunold <michael@mihu.de> - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DEBUG_VARIABLE debug - -#include <media/drv-intf/saa7146_vv.h> -#include <linux/module.h> -#include <linux/kernel.h> - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "debug verbosity"); - -/* global variables */ -static int hexium_num; - -#define HEXIUM_HV_PCI6_ORION 1 -#define HEXIUM_ORION_1SVHS_3BNC 2 -#define HEXIUM_ORION_4BNC 3 - -#define HEXIUM_INPUTS 9 -static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = { - { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, -}; - -#define HEXIUM_AUDIOS 0 - -struct hexium_data -{ - s8 adr; - u8 byte; -}; - -struct hexium -{ - int type; - struct video_device video_dev; - struct i2c_adapter i2c_adapter; - - int cur_input; /* current input */ -}; - -/* Philips SAA7110 decoder default registers */ -static u8 hexium_saa7110[53]={ -/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00, -/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90, -/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA, -/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00, -/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F, -/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03, -/*30*/ 0x44,0x75,0x01,0x8C,0x03 -}; - -static struct { - struct hexium_data data[8]; -} hexium_input_select[] = { -{ - { /* cvbs 1 */ - { 0x06, 0x00 }, - { 0x20, 0xD9 }, - { 0x21, 0x17 }, // 0x16, - { 0x22, 0x40 }, - { 0x2C, 0x03 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, // ?? - { 0x21, 0x16 }, // 0x03, - } -}, { - { /* cvbs 2 */ - { 0x06, 0x00 }, - { 0x20, 0x78 }, - { 0x21, 0x07 }, // 0x03, - { 0x22, 0xD2 }, - { 0x2C, 0x83 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ? - { 0x21, 0x03 }, - } -}, { - { /* cvbs 3 */ - { 0x06, 0x00 }, - { 0x20, 0xBA }, - { 0x21, 0x07 }, // 0x05, - { 0x22, 0x91 }, - { 0x2C, 0x03 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ?? - { 0x21, 0x05 }, // 0x03, - } -}, { - { /* cvbs 4 */ - { 0x06, 0x00 }, - { 0x20, 0xD8 }, - { 0x21, 0x17 }, // 0x16, - { 0x22, 0x40 }, - { 0x2C, 0x03 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, // ?? - { 0x21, 0x16 }, // 0x03, - } -}, { - { /* cvbs 5 */ - { 0x06, 0x00 }, - { 0x20, 0xB8 }, - { 0x21, 0x07 }, // 0x05, - { 0x22, 0x91 }, - { 0x2C, 0x03 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ?? - { 0x21, 0x05 }, // 0x03, - } -}, { - { /* cvbs 6 */ - { 0x06, 0x00 }, - { 0x20, 0x7C }, - { 0x21, 0x07 }, // 0x03 - { 0x22, 0xD2 }, - { 0x2C, 0x83 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, // ?? - { 0x21, 0x03 }, - } -}, { - { /* y/c 1 */ - { 0x06, 0x80 }, - { 0x20, 0x59 }, - { 0x21, 0x17 }, - { 0x22, 0x42 }, - { 0x2C, 0xA3 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, - { 0x21, 0x12 }, - } -}, { - { /* y/c 2 */ - { 0x06, 0x80 }, - { 0x20, 0x9A }, - { 0x21, 0x17 }, - { 0x22, 0xB1 }, - { 0x2C, 0x13 }, - { 0x30, 0x60 }, - { 0x31, 0xB5 }, - { 0x21, 0x14 }, - } -}, { - { /* y/c 3 */ - { 0x06, 0x80 }, - { 0x20, 0x3C }, - { 0x21, 0x27 }, - { 0x22, 0xC1 }, - { 0x2C, 0x23 }, - { 0x30, 0x44 }, - { 0x31, 0x75 }, - { 0x21, 0x21 }, - } -} -}; - -static struct saa7146_standard hexium_standards[] = { - { - .name = "PAL", .id = V4L2_STD_PAL, - .v_offset = 16, .v_field = 288, - .h_offset = 1, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 16, .v_field = 240, - .h_offset = 1, .h_pixels = 640, - .v_max_out = 480, .h_max_out = 640, - }, { - .name = "SECAM", .id = V4L2_STD_SECAM, - .v_offset = 16, .v_field = 288, - .h_offset = 1, .h_pixels = 720, - .v_max_out = 576, .h_max_out = 768, - } -}; - -/* this is only called for old HV-PCI6/Orion cards - without eeprom */ -static int hexium_probe(struct saa7146_dev *dev) -{ - struct hexium *hexium = NULL; - union i2c_smbus_data data; - int err = 0; - - DEB_EE("\n"); - - /* there are no hexium orion cards with revision 0 saa7146s */ - if (0 == dev->revision) { - return -EFAULT; - } - - hexium = kzalloc(sizeof(*hexium), GFP_KERNEL); - if (!hexium) - return -ENOMEM; - - /* enable i2c-port pins */ - saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - - saa7146_write(dev, DD1_INIT, 0x01000100); - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - strscpy(hexium->i2c_adapter.name, "hexium orion", - sizeof(hexium->i2c_adapter.name)); - saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); - if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { - DEB_S("cannot register i2c-device. skipping.\n"); - kfree(hexium); - return -EFAULT; - } - - /* set SAA7110 control GPIO 0 */ - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); - /* set HWControl GPIO number 2 */ - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - - mdelay(10); - - /* detect newer Hexium Orion cards by subsystem ids */ - if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) { - pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n"); - /* we store the pointer in our private data field */ - dev->ext_priv = hexium; - hexium->type = HEXIUM_ORION_1SVHS_3BNC; - return 0; - } - - if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) { - pr_info("device is a Hexium Orion w/ 4 BNC inputs\n"); - /* we store the pointer in our private data field */ - dev->ext_priv = hexium; - hexium->type = HEXIUM_ORION_4BNC; - return 0; - } - - /* check if this is an old hexium Orion card by looking at - a saa7110 at address 0x4e */ - err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, - 0x00, I2C_SMBUS_BYTE_DATA, &data); - if (err == 0) { - pr_info("device is a Hexium HV-PCI6/Orion (old)\n"); - /* we store the pointer in our private data field */ - dev->ext_priv = hexium; - hexium->type = HEXIUM_HV_PCI6_ORION; - return 0; - } - - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return -EFAULT; -} - -/* bring hardware to a sane state. this has to be done, just in case someone - wants to capture from this device before it has been properly initialized. - the capture engine would badly fail, because no valid signal arrives on the - saa7146, thus leading to timeouts and stuff. */ -static int hexium_init_done(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - union i2c_smbus_data data; - int i = 0; - - DEB_D("hexium_init_done called\n"); - - /* initialize the helper ics to useful values */ - for (i = 0; i < sizeof(hexium_saa7110); i++) { - data.byte = hexium_saa7110[i]; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) { - pr_err("failed for address 0x%02x\n", i); - } - } - - return 0; -} - -static int hexium_set_input(struct hexium *hexium, int input) -{ - union i2c_smbus_data data; - int i = 0; - - DEB_D("\n"); - - for (i = 0; i < 8; i++) { - int adr = hexium_input_select[input].data[i].adr; - data.byte = hexium_input_select[input].data[i].byte; - if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) { - return -1; - } - pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte); - } - - return 0; -} - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index); - - if (i->index >= HEXIUM_INPUTS) - return -EINVAL; - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - *input = hexium->cur_input; - - DEB_D("VIDIOC_G_INPUT: %d\n", *input); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - if (input >= HEXIUM_INPUTS) - return -EINVAL; - - hexium->cur_input = input; - hexium_set_input(hexium, input); - - return 0; -} - -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - int ret; - - DEB_EE("\n"); - - ret = saa7146_vv_init(dev, &vv_data); - if (ret) { - pr_err("Error in saa7146_vv_init()\n"); - return ret; - } - - vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; - vv_data.vid_ops.vidioc_g_input = vidioc_g_input; - vv_data.vid_ops.vidioc_s_input = vidioc_s_input; - if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_VIDEO)) { - pr_err("cannot register capture v4l2 device. skipping.\n"); - return -1; - } - - pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num); - hexium_num++; - - /* the rest */ - hexium->cur_input = 0; - hexium_init_done(dev); - - return 0; -} - -static int hexium_detach(struct saa7146_dev *dev) -{ - struct hexium *hexium = (struct hexium *) dev->ext_priv; - - DEB_EE("dev:%p\n", dev); - - saa7146_unregister_device(&hexium->video_dev, dev); - saa7146_vv_release(dev); - - hexium_num--; - - i2c_del_adapter(&hexium->i2c_adapter); - kfree(hexium); - return 0; -} - -static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) -{ - return 0; -} - -static struct saa7146_extension extension; - -static struct saa7146_pci_extension_data hexium_hv_pci6 = { - .ext_priv = "Hexium HV-PCI6 / Orion", - .ext = &extension, -}; - -static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = { - .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)", - .ext = &extension, -}; - -static struct saa7146_pci_extension_data hexium_orion_4bnc = { - .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)", - .ext = &extension, -}; - -static const struct pci_device_id pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, - .driver_data = (unsigned long) &hexium_hv_pci6, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x0101, - .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2101, - .driver_data = (unsigned long) &hexium_orion_4bnc, - }, - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_ext_vv vv_data = { - .inputs = HEXIUM_INPUTS, - .capabilities = 0, - .stds = &hexium_standards[0], - .num_stds = ARRAY_SIZE(hexium_standards), - .std_callback = &std_callback, -}; - -static struct saa7146_extension extension = { - .name = "hexium HV-PCI6 Orion", - .flags = 0, // SAA7146_USE_I2C_IRQ, - - .pci_tbl = &pci_tbl[0], - .module = THIS_MODULE, - - .probe = hexium_probe, - .attach = hexium_attach, - .detach = hexium_detach, - - .irq_mask = 0, - .irq_func = NULL, -}; - -static int __init hexium_init_module(void) -{ - if (0 != saa7146_register_extension(&extension)) { - DEB_S("failed to register extension\n"); - return -ENODEV; - } - - return 0; -} - -static void __exit hexium_cleanup_module(void) -{ - saa7146_unregister_extension(&extension); -} - -module_init(hexium_init_module); -module_exit(hexium_cleanup_module); - -MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards"); -MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c deleted file mode 100644 index 7ded8f5b05cb..000000000000 --- a/drivers/media/pci/saa7146/mxb.c +++ /dev/null @@ -1,873 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - mxb - v4l2 driver for the Multimedia eXtension Board - - Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de> - - Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html - for further details about this card. - -*/ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define DEBUG_VARIABLE debug - -#include <media/drv-intf/saa7146_vv.h> -#include <media/tuner.h> -#include <media/v4l2-common.h> -#include <media/i2c/saa7115.h> -#include <linux/module.h> -#include <linux/kernel.h> - -#include "tea6415c.h" -#include "tea6420.h" - -#define MXB_AUDIOS 6 - -#define I2C_SAA7111A 0x24 -#define I2C_TDA9840 0x42 -#define I2C_TEA6415C 0x43 -#define I2C_TEA6420_1 0x4c -#define I2C_TEA6420_2 0x4d -#define I2C_TUNER 0x60 - -#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) - -/* global variable */ -static int mxb_num; - -/* initial frequence the tuner will be tuned to. - in verden (lower saxony, germany) 4148 is a - channel called "phoenix" */ -static int freq = 4148; -module_param(freq, int, 0644); -MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup"); - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); - -#define MXB_INPUTS 4 -enum { TUNER, AUX1, AUX3, AUX3_YC }; - -static struct v4l2_input mxb_inputs[MXB_INPUTS] = { - { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 0x3f, 0, - V4L2_STD_PAL_BG | V4L2_STD_PAL_I, 0, V4L2_IN_CAP_STD }, - { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0, - V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0, - V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, - { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0, - V4L2_STD_ALL, 0, V4L2_IN_CAP_STD }, -}; - -/* this array holds the information, which port of the saa7146 each - input actually uses. the mxb uses port 0 for every input */ -static struct { - int hps_source; - int hps_sync; -} input_port_selection[MXB_INPUTS] = { - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, - { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, -}; - -/* this array holds the information of the audio source (mxb_audios), - which has to be switched corresponding to the video source (mxb_channels) */ -static int video_audio_connect[MXB_INPUTS] = - { 0, 1, 3, 3 }; - -struct mxb_routing { - u32 input; - u32 output; -}; - -/* these are the available audio sources, which can switched - to the line- and cd-output individually */ -static struct v4l2_audio mxb_audios[MXB_AUDIOS] = { - { - .index = 0, - .name = "Tuner", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 1, - .name = "AUX1", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 2, - .name = "AUX2", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 3, - .name = "AUX3", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 4, - .name = "Radio (X9)", - .capability = V4L2_AUDCAP_STEREO, - } , { - .index = 5, - .name = "CD-ROM (X10)", - .capability = V4L2_AUDCAP_STEREO, - } -}; - -/* These are the necessary input-output-pins for bringing one audio source - (see above) to the CD-output. Note that gain is set to 0 in this table. */ -static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = { - { { 1, 1 }, { 1, 1 } }, /* Tuner */ - { { 5, 1 }, { 6, 1 } }, /* AUX 1 */ - { { 4, 1 }, { 6, 1 } }, /* AUX 2 */ - { { 3, 1 }, { 6, 1 } }, /* AUX 3 */ - { { 1, 1 }, { 3, 1 } }, /* Radio */ - { { 1, 1 }, { 2, 1 } }, /* CD-Rom */ - { { 6, 1 }, { 6, 1 } } /* Mute */ -}; - -/* These are the necessary input-output-pins for bringing one audio source - (see above) to the line-output. Note that gain is set to 0 in this table. */ -static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = { - { { 2, 3 }, { 1, 2 } }, - { { 5, 3 }, { 6, 2 } }, - { { 4, 3 }, { 6, 2 } }, - { { 3, 3 }, { 6, 2 } }, - { { 2, 3 }, { 3, 2 } }, - { { 2, 3 }, { 2, 2 } }, - { { 6, 3 }, { 6, 2 } } /* Mute */ -}; - -struct mxb -{ - struct video_device video_dev; - struct video_device vbi_dev; - - struct i2c_adapter i2c_adapter; - - struct v4l2_subdev *saa7111a; - struct v4l2_subdev *tda9840; - struct v4l2_subdev *tea6415c; - struct v4l2_subdev *tuner; - struct v4l2_subdev *tea6420_1; - struct v4l2_subdev *tea6420_2; - - int cur_mode; /* current audio mode (mono, stereo, ...) */ - int cur_input; /* current input */ - int cur_audinput; /* current audio input */ - int cur_mute; /* current mute status */ - struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */ -}; - -#define saa7111a_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->saa7111a, o, f, ##args) -#define tda9840_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->tda9840, o, f, ##args) -#define tea6415c_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->tea6415c, o, f, ##args) -#define tuner_call(mxb, o, f, args...) \ - v4l2_subdev_call(mxb->tuner, o, f, ##args) -#define call_all(dev, o, f, args...) \ - v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args) - -static void mxb_update_audmode(struct mxb *mxb) -{ - struct v4l2_tuner t = { - .audmode = mxb->cur_mode, - }; - - tda9840_call(mxb, tuner, s_tuner, &t); -} - -static inline void tea6420_route(struct mxb *mxb, int idx) -{ - v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, - TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0); - v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, - TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0); - v4l2_subdev_call(mxb->tea6420_1, audio, s_routing, - TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0); - v4l2_subdev_call(mxb->tea6420_2, audio, s_routing, - TEA6420_line[idx][1].input, TEA6420_line[idx][1].output, 0); -} - -static struct saa7146_extension extension; - -static int mxb_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct saa7146_dev *dev = container_of(ctrl->handler, - struct saa7146_dev, ctrl_handler); - struct mxb *mxb = dev->ext_priv; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - mxb->cur_mute = ctrl->val; - /* switch the audio-source */ - tea6420_route(mxb, ctrl->val ? 6 : - video_audio_connect[mxb->cur_input]); - break; - default: - return -EINVAL; - } - return 0; -} - -static const struct v4l2_ctrl_ops mxb_ctrl_ops = { - .s_ctrl = mxb_s_ctrl, -}; - -static int mxb_probe(struct saa7146_dev *dev) -{ - struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler; - struct mxb *mxb = NULL; - - v4l2_ctrl_new_std(hdl, &mxb_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); - if (hdl->error) - return hdl->error; - mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); - if (mxb == NULL) { - DEB_D("not enough kernel memory\n"); - return -ENOMEM; - } - - - snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num); - - saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); - if (i2c_add_adapter(&mxb->i2c_adapter) < 0) { - DEB_S("cannot register i2c-device. skipping.\n"); - kfree(mxb); - return -EFAULT; - } - - mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "saa7111", I2C_SAA7111A, NULL); - mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tea6420", I2C_TEA6420_1, NULL); - mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tea6420", I2C_TEA6420_2, NULL); - mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tea6415c", I2C_TEA6415C, NULL); - mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tda9840", I2C_TDA9840, NULL); - mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter, - "tuner", I2C_TUNER, NULL); - - /* check if all devices are present */ - if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c || - !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) { - pr_err("did not find all i2c devices. aborting\n"); - i2c_del_adapter(&mxb->i2c_adapter); - kfree(mxb); - return -ENODEV; - } - - /* all devices are present, probe was successful */ - - /* we store the pointer in our private data field */ - dev->ext_priv = mxb; - - v4l2_ctrl_handler_setup(hdl); - - return 0; -} - -/* some init data for the saa7740, the so-called 'sound arena module'. - there are no specs available, so we simply use some init values */ -static struct { - int length; - char data[9]; -} mxb_saa7740_init[] = { - { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } }, - { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } }, - { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } }, - { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } }, - { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } }, - { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } }, - { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } }, - { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } }, - { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } }, - { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } }, - { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } }, - { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } }, - { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } }, - { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } }, - { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } }, - { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } }, - { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } }, - { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } }, - { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } }, - { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } }, - { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } }, - { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } }, - { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } }, - { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } }, - { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } }, - { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } }, - { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } }, - { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } }, - { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } }, - { 3, { 0x48, 0x00, 0x01 } }, - { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, - { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } }, - { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, - { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } }, - { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, - { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } }, - { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, - { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } }, - { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, - { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } }, - { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, - { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } }, - { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, - { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } }, - { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, - { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } }, - { 3, { 0x80, 0xb3, 0x0a } }, - {-1, { 0 } } -}; - -/* bring hardware to a sane state. this has to be done, just in case someone - wants to capture from this device before it has been properly initialized. - the capture engine would badly fail, because no valid signal arrives on the - saa7146, thus leading to timeouts and stuff. */ -static int mxb_init_done(struct saa7146_dev* dev) -{ - struct mxb* mxb = (struct mxb*)dev->ext_priv; - struct i2c_msg msg; - struct tuner_setup tun_setup; - v4l2_std_id std = V4L2_STD_PAL_BG; - - int i, err = 0; - - /* mute audio on tea6420s */ - tea6420_route(mxb, 6); - - /* select video mode in saa7111a */ - saa7111a_call(mxb, video, s_std, std); - - /* select tuner-output on saa7111a */ - saa7111a_call(mxb, video, s_routing, SAA7115_COMPOSITE0, - SAA7111_FMT_CCIR, 0); - - /* select a tuner type */ - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.addr = ADDR_UNSET; - tun_setup.type = TUNER_PHILIPS_PAL; - tuner_call(mxb, tuner, s_type_addr, &tun_setup); - /* tune in some frequency on tuner */ - mxb->cur_freq.tuner = 0; - mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV; - mxb->cur_freq.frequency = freq; - tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq); - - /* set a default video standard */ - /* These two gpio calls set the GPIO pins that control the tda9820 */ - saa7146_write(dev, GPIO_CTRL, 0x00404050); - saa7111a_call(mxb, core, s_gpio, 1); - saa7111a_call(mxb, video, s_std, std); - tuner_call(mxb, video, s_std, std); - - /* switch to tuner-channel on tea6415c */ - tea6415c_call(mxb, video, s_routing, 3, 17, 0); - - /* select tuner-output on multicable on tea6415c */ - tea6415c_call(mxb, video, s_routing, 3, 13, 0); - - /* the rest for mxb */ - mxb->cur_input = 0; - mxb->cur_audinput = video_audio_connect[mxb->cur_input]; - mxb->cur_mute = 1; - - mxb->cur_mode = V4L2_TUNER_MODE_STEREO; - mxb_update_audmode(mxb); - - /* check if the saa7740 (aka 'sound arena module') is present - on the mxb. if so, we must initialize it. due to lack of - information about the saa7740, the values were reverse - engineered. */ - msg.addr = 0x1b; - msg.flags = 0; - msg.len = mxb_saa7740_init[0].length; - msg.buf = &mxb_saa7740_init[0].data[0]; - - err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); - if (err == 1) { - /* the sound arena module is a pos, that's probably the reason - philips refuses to hand out a datasheet for the saa7740... - it seems to screw up the i2c bus, so we disable fast irq - based i2c transactions here and rely on the slow and safe - polling method ... */ - extension.flags &= ~SAA7146_USE_I2C_IRQ; - for (i = 1; ; i++) { - if (-1 == mxb_saa7740_init[i].length) - break; - - msg.len = mxb_saa7740_init[i].length; - msg.buf = &mxb_saa7740_init[i].data[0]; - err = i2c_transfer(&mxb->i2c_adapter, &msg, 1); - if (err != 1) { - DEB_D("failed to initialize 'sound arena module'\n"); - goto err; - } - } - pr_info("'sound arena module' detected\n"); - } -err: - /* the rest for saa7146: you should definitely set some basic values - for the input-port handling of the saa7146. */ - - /* ext->saa has been filled by the core driver */ - - /* some stuff is done via variables */ - saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, - input_port_selection[mxb->cur_input].hps_sync); - - /* some stuff is done via direct write to the registers */ - - /* this is ugly, but because of the fact that this is completely - hardware dependend, it should be done directly... */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, DD1_INIT, 0x02000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - return 0; -} - -/* interrupt-handler. this gets called when irq_mask is != 0. - it must clear the interrupt-bits in irq_mask it has handled */ -/* -void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask) -{ - struct mxb* mxb = (struct mxb*)dev->ext_priv; -} -*/ - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index); - if (i->index >= MXB_INPUTS) - return -EINVAL; - memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - *i = mxb->cur_input; - - DEB_EE("VIDIOC_G_INPUT %d\n", *i); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - int err = 0; - int i = 0; - - DEB_EE("VIDIOC_S_INPUT %d\n", input); - - if (input >= MXB_INPUTS) - return -EINVAL; - - mxb->cur_input = input; - - saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, - input_port_selection[input].hps_sync); - - /* prepare switching of tea6415c and saa7111a; - have a look at the 'background'-file for further information */ - switch (input) { - case TUNER: - i = SAA7115_COMPOSITE0; - - err = tea6415c_call(mxb, video, s_routing, 3, 17, 0); - - /* connect tuner-output always to multicable */ - if (!err) - err = tea6415c_call(mxb, video, s_routing, 3, 13, 0); - break; - case AUX3_YC: - /* nothing to be done here. aux3_yc is - directly connected to the saa711a */ - i = SAA7115_SVIDEO1; - break; - case AUX3: - /* nothing to be done here. aux3 is - directly connected to the saa711a */ - i = SAA7115_COMPOSITE1; - break; - case AUX1: - i = SAA7115_COMPOSITE0; - err = tea6415c_call(mxb, video, s_routing, 1, 17, 0); - break; - } - - if (err) - return err; - - /* switch video in saa7111a */ - if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0)) - pr_err("VIDIOC_S_INPUT: could not address saa7111a\n"); - - mxb->cur_audinput = video_audio_connect[input]; - /* switch the audio-source only if necessary */ - if (0 == mxb->cur_mute) - tea6420_route(mxb, mxb->cur_audinput); - if (mxb->cur_audinput == 0) - mxb_update_audmode(mxb); - - return 0; -} - -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (t->index) { - DEB_D("VIDIOC_G_TUNER: channel %d does not have a tuner attached\n", - t->index); - return -EINVAL; - } - - DEB_EE("VIDIOC_G_TUNER: %d\n", t->index); - - memset(t, 0, sizeof(*t)); - strscpy(t->name, "TV Tuner", sizeof(t->name)); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - t->audmode = mxb->cur_mode; - return call_all(dev, tuner, g_tuner, t); -} - -static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (t->index) { - DEB_D("VIDIOC_S_TUNER: channel %d does not have a tuner attached\n", - t->index); - return -EINVAL; - } - - mxb->cur_mode = t->audmode; - return call_all(dev, tuner, s_tuner, t); -} - -static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *norm) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - - return call_all(dev, video, querystd, norm); -} - -static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (f->tuner) - return -EINVAL; - *f = mxb->cur_freq; - - DEB_EE("VIDIOC_G_FREQ: freq:0x%08x\n", mxb->cur_freq.frequency); - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - struct saa7146_vv *vv = dev->vv_data; - - if (f->tuner) - return -EINVAL; - - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - - DEB_EE("VIDIOC_S_FREQUENCY: freq:0x%08x\n", mxb->cur_freq.frequency); - - /* tune in desired frequency */ - tuner_call(mxb, tuner, s_frequency, f); - /* let the tuner subdev clamp the frequency to the tuner range */ - mxb->cur_freq = *f; - tuner_call(mxb, tuner, g_frequency, &mxb->cur_freq); - if (mxb->cur_audinput == 0) - mxb_update_audmode(mxb); - - if (mxb->cur_input) - return 0; - - /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ - spin_lock(&dev->slock); - vv->vbi_fieldcount = 0; - spin_unlock(&dev->slock); - - return 0; -} - -static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) -{ - if (a->index >= MXB_AUDIOS) - return -EINVAL; - *a = mxb_audios[a->index]; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - DEB_EE("VIDIOC_G_AUDIO\n"); - *a = mxb_audios[mxb->cur_audinput]; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - DEB_D("VIDIOC_S_AUDIO %d\n", a->index); - if (a->index >= 32 || - !(mxb_inputs[mxb->cur_input].audioset & (1 << a->index))) - return -EINVAL; - - if (mxb->cur_audinput != a->index) { - mxb->cur_audinput = a->index; - tea6420_route(mxb, a->index); - if (mxb->cur_audinput == 0) - mxb_update_audmode(mxb); - } - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - - if (reg->reg > pci_resource_len(dev->pci, 0) - 4) - return -EINVAL; - reg->val = saa7146_read(dev, reg->reg); - reg->size = 4; - return 0; -} - -static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - - if (reg->reg > pci_resource_len(dev->pci, 0) - 4) - return -EINVAL; - saa7146_write(dev, reg->reg, reg->val); - return 0; -} -#endif - -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct mxb *mxb; - int ret; - - DEB_EE("dev:%p\n", dev); - - ret = saa7146_vv_init(dev, &vv_data); - if (ret) { - ERR("Error in saa7146_vv_init()"); - return ret; - } - - if (mxb_probe(dev)) { - saa7146_vv_release(dev); - return -1; - } - mxb = (struct mxb *)dev->ext_priv; - - vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; - vv_data.vid_ops.vidioc_g_input = vidioc_g_input; - vv_data.vid_ops.vidioc_s_input = vidioc_s_input; - vv_data.vid_ops.vidioc_querystd = vidioc_querystd; - vv_data.vid_ops.vidioc_g_tuner = vidioc_g_tuner; - vv_data.vid_ops.vidioc_s_tuner = vidioc_s_tuner; - vv_data.vid_ops.vidioc_g_frequency = vidioc_g_frequency; - vv_data.vid_ops.vidioc_s_frequency = vidioc_s_frequency; - vv_data.vid_ops.vidioc_enumaudio = vidioc_enumaudio; - vv_data.vid_ops.vidioc_g_audio = vidioc_g_audio; - vv_data.vid_ops.vidioc_s_audio = vidioc_s_audio; -#ifdef CONFIG_VIDEO_ADV_DEBUG - vv_data.vid_ops.vidioc_g_register = vidioc_g_register; - vv_data.vid_ops.vidioc_s_register = vidioc_s_register; -#endif - if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_VIDEO)) { - ERR("cannot register capture v4l2 device. skipping.\n"); - saa7146_vv_release(dev); - return -1; - } - - /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ - if (MXB_BOARD_CAN_DO_VBI(dev)) { - if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { - ERR("cannot register vbi v4l2 device. skipping.\n"); - } - } - - pr_info("found Multimedia eXtension Board #%d\n", mxb_num); - - mxb_num++; - mxb_init_done(dev); - return 0; -} - -static int mxb_detach(struct saa7146_dev *dev) -{ - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - DEB_EE("dev:%p\n", dev); - - /* mute audio on tea6420s */ - tea6420_route(mxb, 6); - - saa7146_unregister_device(&mxb->video_dev,dev); - if (MXB_BOARD_CAN_DO_VBI(dev)) - saa7146_unregister_device(&mxb->vbi_dev, dev); - saa7146_vv_release(dev); - - mxb_num--; - - i2c_del_adapter(&mxb->i2c_adapter); - kfree(mxb); - - return 0; -} - -static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard) -{ - struct mxb *mxb = (struct mxb *)dev->ext_priv; - - if (V4L2_STD_PAL_I == standard->id) { - v4l2_std_id std = V4L2_STD_PAL_I; - - DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n"); - /* These two gpio calls set the GPIO pins that control the tda9820 */ - saa7146_write(dev, GPIO_CTRL, 0x00404050); - saa7111a_call(mxb, core, s_gpio, 0); - saa7111a_call(mxb, video, s_std, std); - if (mxb->cur_input == 0) - tuner_call(mxb, video, s_std, std); - } else { - v4l2_std_id std = V4L2_STD_PAL_BG; - - if (mxb->cur_input) - std = standard->id; - DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n"); - /* These two gpio calls set the GPIO pins that control the tda9820 */ - saa7146_write(dev, GPIO_CTRL, 0x00404050); - saa7111a_call(mxb, core, s_gpio, 1); - saa7111a_call(mxb, video, s_std, std); - if (mxb->cur_input == 0) - tuner_call(mxb, video, s_std, std); - } - return 0; -} - -static struct saa7146_standard standard[] = { - { - .name = "PAL-BG", .id = V4L2_STD_PAL_BG, - .v_offset = 0x17, .v_field = 288, - .h_offset = 0x14, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "PAL-I", .id = V4L2_STD_PAL_I, - .v_offset = 0x17, .v_field = 288, - .h_offset = 0x14, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x16, .v_field = 240, - .h_offset = 0x06, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - }, { - .name = "SECAM", .id = V4L2_STD_SECAM, - .v_offset = 0x14, .v_field = 288, - .h_offset = 0x14, .h_pixels = 720, - .v_max_out = 576, .h_max_out = 768, - } -}; - -static struct saa7146_pci_extension_data mxb = { - .ext_priv = "Multimedia eXtension Board", - .ext = &extension, -}; - -static const struct pci_device_id pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, - .driver_data = (unsigned long)&mxb, - }, { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_ext_vv vv_data = { - .inputs = MXB_INPUTS, - .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_AUDIO, - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), - .std_callback = &std_callback, -}; - -static struct saa7146_extension extension = { - .name = "Multimedia eXtension Board", - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = &pci_tbl[0], - .module = THIS_MODULE, - - .attach = mxb_attach, - .detach = mxb_detach, - - .irq_mask = 0, - .irq_func = NULL, -}; - -static int __init mxb_init_module(void) -{ - if (saa7146_register_extension(&extension)) { - DEB_S("failed to register extension\n"); - return -ENODEV; - } - - return 0; -} - -static void __exit mxb_cleanup_module(void) -{ - saa7146_unregister_extension(&extension); -} - -module_init(mxb_init_module); -module_exit(mxb_cleanup_module); - -MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'"); -MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 7973ae42873a..d5f32e3ff544 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -626,7 +626,7 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) portf = &dev->ports[SAA7164_PORT_VBI2]; /* Check that the hardware is accessible. If the status bytes are - * 0xFF then the device is not accessible, the the IRQ belongs + * 0xFF then the device is not accessible, the IRQ belongs * to another driver. * 4 x u32 interrupt registers. */ diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 80d20e2a2099..0adf3d80f248 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -1020,7 +1020,7 @@ static int solo_g_parm(struct file *file, void *priv, cp->timeperframe.numerator = solo_enc->interval; cp->timeperframe.denominator = solo_enc->solo_dev->fps; cp->capturemode = 0; - /* XXX: Shouldn't we be able to get/set this from videobuf? */ + /* XXX: Shouldn't we be able to get/set this from vb2? */ cp->readbuffers = 2; return 0; diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig deleted file mode 100644 index 65a6832a6b96..000000000000 --- a/drivers/media/pci/ttpci/Kconfig +++ /dev/null @@ -1,86 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" - depends on DVB_CORE && PCI && I2C - select VIDEO_SAA7146 - select TTPCI_EEPROM - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. - -config DVB_BUDGET - tristate "Budget cards" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT - select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT - select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT - help - Support for simple SAA7146 based DVB cards (so called Budget- - or Nova-PCI cards) without onboard MPEG2 decoder, and without - analog inputs or an onboard Common Interface connector. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget. - -config DVB_BUDGET_CI - tristate "Budget cards with onboard CI connector" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT - depends on RC_CORE - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with onboard Common Interface connector. - - Note: The Common Interface is not yet supported by this driver - due to lack of information from the vendor. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-ci. - -config DVB_BUDGET_AV - tristate "Budget cards with analog video inputs" - depends on DVB_BUDGET_CORE && I2C - select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA8261 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUA6100 if MEDIA_SUBDRV_AUTOSELECT - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with one or more analog video inputs. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-av. diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile deleted file mode 100644 index b0708f6e40cc..000000000000 --- a/drivers/media/pci/ttpci/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the kernel SAA7146 FULL TS DVB device driver -# - -obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o -obj-$(CONFIG_DVB_BUDGET) += budget.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o - -ccflags-y += -I $(srctree)/drivers/media/dvb-frontends/ -ccflags-y += -I $(srctree)/drivers/media/tuners -ccflags-y += -I $(srctree)/drivers/media/common diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c deleted file mode 100644 index 3cb83005cf09..000000000000 --- a/drivers/media/pci/ttpci/budget-av.c +++ /dev/null @@ -1,1622 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * budget-av.c: driver for the SAA7146 based Budget DVB cards - * with analog video in - * - * Compiled from various sources by Michael Hunold <michael@mihu.de> - * - * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> & - * Andrew de Quincey <adq_dvb@lidskialf.net> - * - * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * the project's page is at https://linuxtv.org - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "budget.h" -#include "stv0299.h" -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" -#include "tda8261.h" -#include "tda8261_cfg.h" -#include "tda1002x.h" -#include "tda1004x.h" -#include "tua6100.h" -#include "dvb-pll.h" -#include <media/drv-intf/saa7146_vv.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/spinlock.h> - -#include <media/dvb_ca_en50221.h> - -#define DEBICICAM 0x02420000 - -#define SLOTSTATUS_NONE 1 -#define SLOTSTATUS_PRESENT 2 -#define SLOTSTATUS_RESET 4 -#define SLOTSTATUS_READY 8 -#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct budget_av { - struct budget budget; - struct video_device vd; - int cur_input; - int has_saa7113; - struct tasklet_struct ciintf_irq_tasklet; - int slot_status; - struct dvb_ca_en50221 ca; - u8 reinitialise_demod:1; -}; - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); - - -/* GPIO Connections: - * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! - * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory - * 2 - CI Card Enable (Active Low) - * 3 - CI Card Detect - */ - -/**************************************************************************** - * INITIALIZATION - ****************************************************************************/ - -static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg) -{ - u8 mm1[] = { 0x00 }; - u8 mm2[] = { 0x00 }; - struct i2c_msg msgs[2]; - - msgs[0].flags = 0; - msgs[1].flags = I2C_M_RD; - msgs[0].addr = msgs[1].addr = id / 2; - mm1[0] = reg; - msgs[0].len = 1; - msgs[1].len = 1; - msgs[0].buf = mm1; - msgs[1].buf = mm2; - - i2c_transfer(i2c, msgs, 2); - - return mm2[0]; -} - -static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len) -{ - u8 mm1[] = { reg }; - struct i2c_msg msgs[2] = { - {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1}, - {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len} - }; - - if (i2c_transfer(i2c, msgs, 2) != 2) - return -EIO; - - return 0; -} - -static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val) -{ - u8 msg[2] = { reg, val }; - struct i2c_msg msgs; - - msgs.flags = 0; - msgs.addr = id / 2; - msgs.len = 2; - msgs.buf = msg; - return i2c_transfer(i2c, &msgs, 1); -} - -static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); - udelay(1); - - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 1\n"); - } - return result; -} - -static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); - udelay(1); - - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 2\n"); - } - return result; -} - -static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - udelay(1); - - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 3\n"); - return -ETIMEDOUT; - } - return result; -} - -static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - int result; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - udelay(1); - - result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); - if (result == -ETIMEDOUT) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 5\n"); - } - return result; -} - -static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_reset\n"); - budget_av->slot_status = SLOTSTATUS_RESET; - - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ - msleep(2); - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ - msleep(20); /* 20 ms Vcc settling time */ - - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - msleep(20); - - /* reinitialise the frontend if necessary */ - if (budget_av->reinitialise_demod) - dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); - - return 0; -} - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_shutdown\n"); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - budget_av->slot_status = SLOTSTATUS_NONE; - - return 0; -} - -static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - - if (slot != 0) - return -EINVAL; - - dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); - - return 0; -} - -static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct budget_av *budget_av = (struct budget_av *) ca->data; - struct saa7146_dev *saa = budget_av->budget.dev; - int result; - - if (slot != 0) - return -EINVAL; - - /* test the card detect line - needs to be done carefully - * since it never goes high for some CAMs on this interface (e.g. topuptv) */ - if (budget_av->slot_status == SLOTSTATUS_NONE) { - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - udelay(1); - if (saa7146_read(saa, PSR) & MASK_06) { - if (budget_av->slot_status == SLOTSTATUS_NONE) { - budget_av->slot_status = SLOTSTATUS_PRESENT; - pr_info("cam inserted A\n"); - } - } - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - } - - /* We also try and read from IO memory to work round the above detection bug. If - * there is no CAM, we will get a timeout. Only done if there is no cam - * present, since this test actually breaks some cams :( - * - * if the CI interface is not open, we also do the above test since we - * don't care if the cam has problems - we'll be resetting it on open() anyway */ - if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); - if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { - budget_av->slot_status = SLOTSTATUS_PRESENT; - pr_info("cam inserted B\n"); - } else if (result < 0) { - if (budget_av->slot_status != SLOTSTATUS_NONE) { - ciintf_slot_shutdown(ca, slot); - pr_info("cam ejected 5\n"); - return 0; - } - } - } - - /* read from attribute memory in reset/ready state to know when the CAM is ready */ - if (budget_av->slot_status == SLOTSTATUS_RESET) { - result = ciintf_read_attribute_mem(ca, slot, 0); - if (result == 0x1d) { - budget_av->slot_status = SLOTSTATUS_READY; - } - } - - /* work out correct return code */ - if (budget_av->slot_status != SLOTSTATUS_NONE) { - if (budget_av->slot_status & SLOTSTATUS_READY) { - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } - return DVB_CA_EN50221_POLL_CAM_PRESENT; - } - return 0; -} - -static int ciintf_init(struct budget_av *budget_av) -{ - struct saa7146_dev *saa = budget_av->budget.dev; - int result; - - memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); - - /* Enable DEBI pins */ - saa7146_write(saa, MC1, MASK_27 | MASK_11); - - /* register CI interface */ - budget_av->ca.owner = THIS_MODULE; - budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; - budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; - budget_av->ca.read_cam_control = ciintf_read_cam_control; - budget_av->ca.write_cam_control = ciintf_write_cam_control; - budget_av->ca.slot_reset = ciintf_slot_reset; - budget_av->ca.slot_shutdown = ciintf_slot_shutdown; - budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; - budget_av->ca.poll_slot_status = ciintf_poll_slot_status; - budget_av->ca.data = budget_av; - budget_av->budget.ci_present = 1; - budget_av->slot_status = SLOTSTATUS_NONE; - - if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, - &budget_av->ca, 0, 1)) != 0) { - pr_err("ci initialisation failed\n"); - goto error; - } - - pr_info("ci interface initialised\n"); - return 0; - -error: - saa7146_write(saa, MC1, MASK_27); - return result; -} - -static void ciintf_deinit(struct budget_av *budget_av) -{ - struct saa7146_dev *saa = budget_av->budget.dev; - - saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - - /* release the CA device */ - dvb_ca_en50221_release(&budget_av->ca); - - /* disable DEBI pins */ - saa7146_write(saa, MC1, MASK_27); -} - - -static const u8 saa7113_tab[] = { - 0x01, 0x08, - 0x02, 0xc0, - 0x03, 0x33, - 0x04, 0x00, - 0x05, 0x00, - 0x06, 0xeb, - 0x07, 0xe0, - 0x08, 0x28, - 0x09, 0x00, - 0x0a, 0x80, - 0x0b, 0x47, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x01, - 0x0f, 0x44, - - 0x10, 0x08, - 0x11, 0x0c, - 0x12, 0x7b, - 0x13, 0x00, - 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, - - 0x57, 0xff, - 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, - 0x5b, 0x83, 0x5e, 0x00, - 0xff -}; - -static int saa7113_init(struct budget_av *budget_av) -{ - struct budget *budget = &budget_av->budget; - struct saa7146_dev *saa = budget->dev; - const u8 *data = saa7113_tab; - - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); - msleep(200); - - if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { - dprintk(1, "saa7113 not found on KNC card\n"); - return -ENODEV; - } - - dprintk(1, "saa7113 detected and initializing\n"); - - while (*data != 0xff) { - i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1)); - data += 2; - } - - dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)); - - return 0; -} - -static int saa7113_setinput(struct budget_av *budget_av, int input) -{ - struct budget *budget = &budget_av->budget; - - if (1 != budget_av->has_saa7113) - return -ENODEV; - - if (input == 1) { - i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7); - i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80); - } else if (input == 0) { - i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0); - i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00); - } else - return -EINVAL; - - budget_av->cur_input = input; - return 0; -} - - -static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - u8 m1; - - aclk = 0xb5; - if (srate < 2000000) - bclk = 0x86; - else if (srate < 5000000) - bclk = 0x89; - else if (srate < 15000000) - bclk = 0x8f; - else if (srate < 45000000) - bclk = 0x95; - - m1 = 0x14; - if (srate < 4000000) - m1 = 0x10; - - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - stv0299_writereg(fe, 0x0f, 0x80 | m1); - - return 0; -} - -static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - u32 div; - u8 buf[4]; - struct budget *budget = (struct budget *) fe->dvb->priv; - struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((c->frequency < 950000) || (c->frequency > 2150000)) - return -EINVAL; - - div = (c->frequency + (125 - 1)) / 125; /* round correctly */ - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; - buf[3] = 0x20; - - if (c->symbol_rate < 4000000) - buf[3] |= 1; - - if (c->frequency < 1250000) - buf[3] |= 0; - else if (c->frequency < 1550000) - buf[3] |= 0x40; - else if (c->frequency < 2050000) - buf[3] |= 0x80; - else if (c->frequency < 2150000) - buf[3] |= 0xC0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static u8 typhoon_cinergy1200s_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - 0x08, 0x40, /* DiSEqC off */ - 0x09, 0x00, /* FIFO */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - 0x10, 0x3f, // AGC2 0x3d - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, // lock detector threshold - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - 0x31, 0x1f, // test all FECs - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control - 0x0f, 0x92, - 0xff, 0xff -}; - -static const struct stv0299_config typhoon_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - - -static const struct stv0299_config cinergy_1200s_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_0, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - -static const struct stv0299_config cinergy_1200s_1894_0010_config = { - .demod_address = 0x68, - .inittab = typhoon_cinergy1200s_inittab, - .mclk = 88000000UL, - .invert = 1, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, -}; - -static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget *budget = (struct budget *) fe->dvb->priv; - u8 buf[6]; - struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - int i; - -#define CU1216_IF 36125000 -#define TUNER_MUL 62500 - - u32 div = (c->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0xce; - buf[3] = (c->frequency < 150000000 ? 0x01 : - c->frequency < 445000000 ? 0x02 : 0x04); - buf[4] = 0xde; - buf[5] = 0x20; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - - /* wait for the pll lock */ - msg.flags = I2C_M_RD; - msg.len = 1; - for (i = 0; i < 20; i++) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) == 1 && (buf[0] & 0x40)) - break; - msleep(10); - } - - /* switch the charge pump to the lower current */ - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[2]; - buf[2] &= ~0x40; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static struct tda1002x_config philips_cu1216_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static struct tda1002x_config philips_cu1216_config_altaddress = { - .demod_address = 0x0d, - .invert = 0, -}; - -static struct tda10023_config philips_cu1216_tda10023_config = { - .demod_address = 0x0c, - .invert = 1, -}; - -static int philips_tu1216_tuner_init(struct dvb_frontend *fe) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - return 0; -} - -static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget *budget = (struct budget *) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = - sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = c->frequency + 36166000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - // determine band - if (c->frequency < 49000000) - return -EINVAL; - else if (c->frequency < 161000000) - band = 1; - else if (c->frequency < 444000000) - band = 2; - else if (c->frequency < 861000000) - band = 4; - else - return -EINVAL; - - // setup PLL filter - switch (c->bandwidth_hz) { - case 6000000: - filter = 0; - break; - - case 7000000: - filter = 0; - break; - - case 8000000: - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((c->frequency / 1000) * 6) + 217496) / 1000; - - // setup tuner buffer - tuner_buf[0] = (tuner_frequency >> 8) & 0x7f; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tu1216_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - - return request_firmware(fw, name, &budget->dev->pci->dev); -} - -static struct tda1004x_config philips_tu1216_config = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 1, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tu1216_request_firmware, -}; - -static u8 philips_sd1878_inittab[] = { - 0x01, 0x15, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x7d, - 0x05, 0x35, - 0x06, 0x40, - 0x07, 0x00, - 0x08, 0x43, - 0x09, 0x02, - 0x0C, 0x51, - 0x0D, 0x82, - 0x0E, 0x23, - 0x10, 0x3f, - 0x11, 0x84, - 0x12, 0xb9, - 0x15, 0xc9, - 0x16, 0x19, - 0x17, 0x8c, - 0x18, 0x59, - 0x19, 0xf8, - 0x1a, 0xfe, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x09, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x93, - 0xff, 0xff -}; - -static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) -{ - u8 aclk = 0; - u8 bclk = 0; - u8 m1; - - aclk = 0xb5; - if (srate < 2000000) - bclk = 0x86; - else if (srate < 5000000) - bclk = 0x89; - else if (srate < 15000000) - bclk = 0x8f; - else if (srate < 45000000) - bclk = 0x95; - - m1 = 0x14; - if (srate < 4000000) - m1 = 0x10; - - stv0299_writereg(fe, 0x0e, 0x23); - stv0299_writereg(fe, 0x0f, 0x94); - stv0299_writereg(fe, 0x10, 0x39); - stv0299_writereg(fe, 0x13, aclk); - stv0299_writereg(fe, 0x14, bclk); - stv0299_writereg(fe, 0x15, 0xc9); - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - stv0299_writereg(fe, 0x0f, 0x80 | m1); - - return 0; -} - -static const struct stv0299_config philips_sd1878_config = { - .demod_address = 0x68, - .inittab = philips_sd1878_inittab, - .mclk = 88000000UL, - .invert = 0, - .skip_reinit = 0, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP0, - .min_delay_ms = 100, - .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, -}; - -/* KNC1 DVB-S (STB0899) Inittab */ -static const struct stb0899_s1_reg knc1_stb0899_s1_init_1[] = { - - { STB0899_DEV_ID , 0x81 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x8c }, - { STB0899_DISF22RX , 0x9a }, - { STB0899_SYSREG , 0x0b }, - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0x30 }, - { STB0899_IRQSTATUS_2 , 0x00 }, - { STB0899_IRQSTATUS_1 , 0x00 }, - { STB0899_IRQSTATUS_0 , 0x00 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x58 }, /* Repeater=8, Stop=disabled */ - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x20 }, - { STB0899_IOPVALUE3 , 0xc9 }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x40 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x08 }, /* 0x1c */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x00 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x41 }, - { STB0899_AGC1REF , 0x08 }, - { STB0899_RTC , 0x7a }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x33 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xee }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xdd }, - { STB0899_LDT2 , 0xc9 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfb }, - { STB0899_QDCCOMP , 0x03 }, - { STB0899_POWERI , 0x3b }, - { STB0899_POWERQ , 0x3d }, - { STB0899_RCOMP , 0x81 }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x04 }, - { STB0899_AGC2I2 , 0xf5 }, - { STB0899_TLIR , 0x25 }, - { STB0899_RTF , 0x80 }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xca }, - { STB0899_CFRM , 0xf1 }, - { STB0899_CFRL , 0xf3 }, - { STB0899_NIRM , 0x2a }, - { STB0899_NIRL , 0x05 }, - { STB0899_ISYMB , 0x17 }, - { STB0899_QSYMB , 0xfa }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0xfd }, - { STB0899_EQUAQ1 , 0x04 }, - { STB0899_EQUAI2 , 0x0f }, - { STB0899_EQUAQ2 , 0xff }, - { STB0899_EQUAI3 , 0xdf }, - { STB0899_EQUAQ3 , 0xfa }, - { STB0899_EQUAI4 , 0x37 }, - { STB0899_EQUAQ4 , 0x0d }, - { STB0899_EQUAI5 , 0xbd }, - { STB0899_EQUAQ5 , 0xf7 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0xff }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x00 }, - { STB0899_ECNT3L , 0x00 }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xf0 }, - { STB0899_VTH23 , 0xa0 }, - { STB0899_VTH34 , 0x78 }, - { STB0899_VTH56 , 0x4e }, - { STB0899_VTH67 , 0x48 }, - { STB0899_VTH78 , 0x38 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x40 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x0c }, - { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x00 }, - { STB0899_TSLLSTKL , 0x00 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0xab }, - { STB0899_PCKLENUL , 0x00 }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xcc }, - { STB0899_TSSTATUS , 0x80 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x96 }, - { STB0899_ERRCTRL3 , 0x89 }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x1f }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0x00 }, - { STB0899_MATSTRL , 0x00 }, - { STB0899_UPLSTRM , 0x00 }, - { STB0899_UPLSTRL , 0x00 }, - { STB0899_DFLSTRM , 0x00 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x00 }, - { STB0899_SYNCDSTRM , 0x00 }, - { STB0899_SYNCDSTRL , 0x00 }, - { STB0899_CFGPDELSTATUS1 , 0x10 }, - { STB0899_CFGPDELSTATUS2 , 0x00 }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x00 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -/* STB0899 demodulator config for the KNC1 and clones */ -static struct stb0899_config knc1_dvbs2_config = { - .init_dev = knc1_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = knc1_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .postproc = NULL, - - .demod_address = 0x68, -// .ts_output_mode = STB0899_OUT_PARALLEL, /* types = SERIAL/PARALLEL */ - .block_sync_mode = STB0899_SYNC_FORCED, /* DSS, SYNC_FORCED/UNSYNCED */ -// .ts_pfbit_toggle = STB0899_MPEG_NORMAL, /* DirecTV, MPEG toggling seq */ - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_OFF, - - .lo_clk = 76500000, - .hi_clk = 90000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = tda8261_get_frequency, - .tuner_set_frequency = tda8261_set_frequency, - .tuner_set_bandwidth = NULL, - .tuner_get_bandwidth = tda8261_get_bandwidth, - .tuner_set_rfsiggain = NULL -}; - -/* - * SD1878/SHA tuner config - * 1F, Single I/P, Horizontal mount, High Sensitivity - */ -static const struct tda8261_config sd1878c_config = { -// .name = "SD1878/SHA", - .addr = 0x60, - .step_size = TDA8261_STEP_1000 /* kHz */ -}; - -static u8 read_pwm(struct budget_av *budget_av) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1}, - {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} - }; - - if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) - || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -#define SUBID_DVBS_KNC1 0x0010 -#define SUBID_DVBS_KNC1_PLUS 0x0011 -#define SUBID_DVBS_TYPHOON 0x4f56 -#define SUBID_DVBS_CINERGY1200 0x1154 -#define SUBID_DVBS_CYNERGY1200N 0x1155 -#define SUBID_DVBS_TV_STAR 0x0014 -#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 -#define SUBID_DVBS_TV_STAR_CI 0x0016 -#define SUBID_DVBS2_KNC1 0x0018 -#define SUBID_DVBS2_KNC1_OEM 0x0019 -#define SUBID_DVBS_EASYWATCH_1 0x001a -#define SUBID_DVBS_EASYWATCH_2 0x001b -#define SUBID_DVBS2_EASYWATCH 0x001d -#define SUBID_DVBS_EASYWATCH 0x001e - -#define SUBID_DVBC_EASYWATCH 0x002a -#define SUBID_DVBC_EASYWATCH_MK3 0x002c -#define SUBID_DVBC_KNC1 0x0020 -#define SUBID_DVBC_KNC1_PLUS 0x0021 -#define SUBID_DVBC_KNC1_MK3 0x0022 -#define SUBID_DVBC_KNC1_TDA10024 0x0028 -#define SUBID_DVBC_KNC1_PLUS_MK3 0x0023 -#define SUBID_DVBC_CINERGY1200 0x1156 -#define SUBID_DVBC_CINERGY1200_MK3 0x1176 - -#define SUBID_DVBT_EASYWATCH 0x003a -#define SUBID_DVBT_KNC1_PLUS 0x0031 -#define SUBID_DVBT_KNC1 0x0030 -#define SUBID_DVBT_CINERGY1200 0x1157 - -static void frontend_init(struct budget_av *budget_av) -{ - struct saa7146_dev * saa = budget_av->budget.dev; - struct dvb_frontend * fe = NULL; - - /* Enable / PowerON Frontend */ - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); - - /* Wait for PowerON */ - msleep(100); - - /* additional setup necessary for the PLUS cards */ - switch (saa->pci->subsystem_device) { - case SUBID_DVBS_KNC1_PLUS: - case SUBID_DVBC_KNC1_PLUS: - case SUBID_DVBT_KNC1_PLUS: - case SUBID_DVBC_EASYWATCH: - case SUBID_DVBC_KNC1_PLUS_MK3: - case SUBID_DVBS2_KNC1: - case SUBID_DVBS2_KNC1_OEM: - case SUBID_DVBS2_EASYWATCH: - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); - break; - } - - switch (saa->pci->subsystem_device) { - - case SUBID_DVBS_KNC1: - /* - * maybe that setting is needed for other dvb-s cards as well, - * but so far it has been only confirmed for this type - */ - budget_av->reinitialise_demod = 1; - fallthrough; - case SUBID_DVBS_KNC1_PLUS: - case SUBID_DVBS_EASYWATCH_1: - if (saa->pci->subsystem_vendor == 0x1894) { - fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config, - &budget_av->budget.i2c_adap); - if (fe) { - dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap); - } - } else { - fe = dvb_attach(stv0299_attach, &typhoon_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - } - break; - - case SUBID_DVBS_TV_STAR: - case SUBID_DVBS_TV_STAR_PLUS_X4: - case SUBID_DVBS_TV_STAR_CI: - case SUBID_DVBS_CYNERGY1200N: - case SUBID_DVBS_EASYWATCH: - case SUBID_DVBS_EASYWATCH_2: - fe = dvb_attach(stv0299_attach, &philips_sd1878_config, - &budget_av->budget.i2c_adap); - if (fe) { - dvb_attach(dvb_pll_attach, fe, 0x60, - &budget_av->budget.i2c_adap, - DVB_PLL_PHILIPS_SD1878_TDA8261); - } - break; - - case SUBID_DVBS_TYPHOON: - fe = dvb_attach(stv0299_attach, &typhoon_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - break; - case SUBID_DVBS2_KNC1: - case SUBID_DVBS2_KNC1_OEM: - case SUBID_DVBS2_EASYWATCH: - budget_av->reinitialise_demod = 1; - if ((fe = dvb_attach(stb0899_attach, &knc1_dvbs2_config, &budget_av->budget.i2c_adap))) - dvb_attach(tda8261_attach, fe, &sd1878c_config, &budget_av->budget.i2c_adap); - - break; - case SUBID_DVBS_CINERGY1200: - fe = dvb_attach(stv0299_attach, &cinergy_1200s_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; - } - break; - - case SUBID_DVBC_KNC1: - case SUBID_DVBC_KNC1_PLUS: - case SUBID_DVBC_CINERGY1200: - case SUBID_DVBC_EASYWATCH: - budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10021_attach, &philips_cu1216_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe == NULL) - fe = dvb_attach(tda10021_attach, &philips_cu1216_config_altaddress, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe) { - fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; - } - break; - - case SUBID_DVBC_EASYWATCH_MK3: - case SUBID_DVBC_CINERGY1200_MK3: - case SUBID_DVBC_KNC1_MK3: - case SUBID_DVBC_KNC1_TDA10024: - case SUBID_DVBC_KNC1_PLUS_MK3: - budget_av->reinitialise_demod = 1; - budget_av->budget.dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; - fe = dvb_attach(tda10023_attach, - &philips_cu1216_tda10023_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - if (fe) { - fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; - } - break; - - case SUBID_DVBT_EASYWATCH: - case SUBID_DVBT_KNC1: - case SUBID_DVBT_KNC1_PLUS: - case SUBID_DVBT_CINERGY1200: - budget_av->reinitialise_demod = 1; - fe = dvb_attach(tda10046_attach, &philips_tu1216_config, - &budget_av->budget.i2c_adap); - if (fe) { - fe->ops.tuner_ops.init = philips_tu1216_tuner_init; - fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params; - } - break; - } - - if (fe == NULL) { - pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - saa->pci->vendor, - saa->pci->device, - saa->pci->subsystem_vendor, - saa->pci->subsystem_device); - return; - } - - budget_av->budget.dvb_frontend = fe; - - if (dvb_register_frontend(&budget_av->budget.dvb_adapter, - budget_av->budget.dvb_frontend)) { - pr_err("Frontend registration failed!\n"); - dvb_frontend_detach(budget_av->budget.dvb_frontend); - budget_av->budget.dvb_frontend = NULL; - } -} - - -static void budget_av_irq(struct saa7146_dev *dev, u32 * isr) -{ - struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; - - dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av); - - if (*isr & MASK_10) - ttpci_budget_irq10_handler(dev, isr); -} - -static int budget_av_detach(struct saa7146_dev *dev) -{ - struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; - int err; - - dprintk(2, "dev: %p\n", dev); - - if (1 == budget_av->has_saa7113) { - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO); - - msleep(200); - - saa7146_unregister_device(&budget_av->vd, dev); - - saa7146_vv_release(dev); - } - - if (budget_av->budget.ci_present) - ciintf_deinit(budget_av); - - if (budget_av->budget.dvb_frontend != NULL) { - dvb_unregister_frontend(budget_av->budget.dvb_frontend); - dvb_frontend_detach(budget_av->budget.dvb_frontend); - } - err = ttpci_budget_deinit(&budget_av->budget); - - kfree(budget_av); - - return err; -} - -#define KNC1_INPUTS 2 -static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { - { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, - V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, - { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, - V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD }, -}; - -static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) -{ - dprintk(1, "VIDIOC_ENUMINPUT %d\n", i->index); - if (i->index >= KNC1_INPUTS) - return -EINVAL; - memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); - return 0; -} - -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; - - *i = budget_av->cur_input; - - dprintk(1, "VIDIOC_G_INPUT %d\n", *i); - return 0; -} - -static int vidioc_s_input(struct file *file, void *fh, unsigned int input) -{ - struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; - struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; - - dprintk(1, "VIDIOC_S_INPUT %d\n", input); - return saa7113_setinput(budget_av, input); -} - -static struct saa7146_ext_vv vv_data; - -static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct budget_av *budget_av; - u8 *mac; - int err; - - dprintk(2, "dev: %p\n", dev); - - if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL))) - return -ENOMEM; - - budget_av->has_saa7113 = 0; - budget_av->budget.ci_present = 0; - - dev->ext_priv = budget_av; - - err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE, - adapter_nr); - if (err) { - kfree(budget_av); - return err; - } - - /* knc1 initialization */ - saa7146_write(dev, DD1_STREAM_B, 0x04000000); - saa7146_write(dev, DD1_INIT, 0x07000600); - saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); - - if (saa7113_init(budget_av) == 0) { - budget_av->has_saa7113 = 1; - err = saa7146_vv_init(dev, &vv_data); - if (err != 0) { - /* fixme: proper cleanup here */ - ERR("cannot init vv subsystem\n"); - return err; - } - vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; - vv_data.vid_ops.vidioc_g_input = vidioc_g_input; - vv_data.vid_ops.vidioc_s_input = vidioc_s_input; - - if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_VIDEO))) { - /* fixme: proper cleanup here */ - ERR("cannot register capture v4l2 device\n"); - saa7146_vv_release(dev); - return err; - } - - /* beware: this modifies dev->vv ... */ - saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A, - SAA7146_HPS_SYNC_PORT_A); - - saa7113_setinput(budget_av, 0); - } - - /* fixme: find some sane values here... */ - saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - - mac = budget_av->budget.dvb_adapter.proposed_mac; - if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) { - pr_err("KNC1-%d: Could not read MAC from KNC1 card\n", - budget_av->budget.dvb_adapter.num); - eth_zero_addr(mac); - } else { - pr_info("KNC1-%d: MAC addr = %pM\n", - budget_av->budget.dvb_adapter.num, mac); - } - - budget_av->budget.dvb_adapter.priv = budget_av; - frontend_init(budget_av); - ciintf_init(budget_av); - - ttpci_budget_init_hooks(&budget_av->budget); - - return 0; -} - -static struct saa7146_standard standard[] = { - {.name = "PAL",.id = V4L2_STD_PAL, - .v_offset = 0x17,.v_field = 288, - .h_offset = 0x14,.h_pixels = 680, - .v_max_out = 576,.h_max_out = 768 }, - - {.name = "NTSC",.id = V4L2_STD_NTSC, - .v_offset = 0x16,.v_field = 240, - .h_offset = 0x06,.h_pixels = 708, - .v_max_out = 480,.h_max_out = 640, }, -}; - -static struct saa7146_ext_vv vv_data = { - .inputs = 2, - .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113 - .flags = 0, - .stds = &standard[0], - .num_stds = ARRAY_SIZE(standard), -}; - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); -MAKE_BUDGET_INFO(knc1s2,"KNC1 DVB-S2", BUDGET_KNC1S2); -MAKE_BUDGET_INFO(sates2,"Satelco EasyWatch DVB-S2", BUDGET_KNC1S2); -MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); -MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); -MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); -MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); -MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); -MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); -MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); -MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T); -MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); -MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); -MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); -MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); -MAKE_BUDGET_INFO(knc1ctda10024, "KNC1 DVB-C TDA10024", BUDGET_KNC1C_TDA10024); -MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); -MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); -MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); -MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); -MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); -MAKE_BUDGET_INFO(cin1200cmk3, "Terratec Cinergy 1200 DVB-C MK3", BUDGET_CIN1200C_MK3); -MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); - -static const struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), - MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010), - MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010), - MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), - MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011), - MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), - MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), - MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), - MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0018), - MAKE_EXTENSION_PCI(knc1s2, 0x1894, 0x0019), - MAKE_EXTENSION_PCI(sates2, 0x1894, 0x001d), - MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), - MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), - MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), - MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), - MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), - MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a), - MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), - MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), - MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), - MAKE_EXTENSION_PCI(knc1ctda10024, 0x1894, 0x0028), - MAKE_EXTENSION_PCI(knc1cpmk3, 0x1894, 0x0023), - MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), - MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031), - MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), - MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155), - MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), - MAKE_EXTENSION_PCI(cin1200cmk3, 0x153b, 0x1176), - MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget_av", - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = pci_tbl, - - .module = THIS_MODULE, - .attach = budget_av_attach, - .detach = budget_av_detach, - - .irq_mask = MASK_10, - .irq_func = budget_av_irq, -}; - -static int __init budget_av_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_av_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_av_init); -module_exit(budget_av_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c deleted file mode 100644 index d59d18647371..000000000000 --- a/drivers/media/pci/ttpci/budget-ci.c +++ /dev/null @@ -1,1574 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * budget-ci.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold <michael@mihu.de> - * - * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM> - * partially based on the Siemens DVB driver by Ralph+Marcus Metzler - * - * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> - * - * the project's page is at https://linuxtv.org - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <media/rc-core.h> - -#include "budget.h" - -#include <media/dvb_ca_en50221.h> -#include "stv0299.h" -#include "stv0297.h" -#include "tda1004x.h" -#include "stb0899_drv.h" -#include "stb0899_reg.h" -#include "stb0899_cfg.h" -#include "stb6100.h" -#include "stb6100_cfg.h" -#include "lnbp21.h" -#include "bsbe1.h" -#include "bsru6.h" -#include "tda1002x.h" -#include "tda827x.h" -#include "bsbe1-d01a.h" - -#define MODULE_NAME "budget_ci" - -/* - * Regarding DEBIADDR_IR: - * Some CI modules hang if random addresses are read. - * Using address 0x4000 for the IR read means that we - * use the same address as for CI version, which should - * be a safe default. - */ -#define DEBIADDR_IR 0x4000 -#define DEBIADDR_CICONTROL 0x0000 -#define DEBIADDR_CIVERSION 0x4000 -#define DEBIADDR_IO 0x1000 -#define DEBIADDR_ATTR 0x3000 - -#define CICONTROL_RESET 0x01 -#define CICONTROL_ENABLETS 0x02 -#define CICONTROL_CAMDETECT 0x08 - -#define DEBICICTL 0x00420000 -#define DEBICICAM 0x02420000 - -#define SLOTSTATUS_NONE 1 -#define SLOTSTATUS_PRESENT 2 -#define SLOTSTATUS_RESET 4 -#define SLOTSTATUS_READY 8 -#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) - -/* RC5 device wildcard */ -#define IR_DEVICE_ANY 255 - -static int rc5_device = -1; -module_param(rc5_device, int, 0644); -MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)"); - -static int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct budget_ci_ir { - struct rc_dev *dev; - struct tasklet_struct msp430_irq_tasklet; - char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ - char phys[32]; - int rc5_device; - u32 ir_key; - bool have_command; - bool full_rc5; /* Outputs a full RC5 code */ -}; - -struct budget_ci { - struct budget budget; - struct tasklet_struct ciintf_irq_tasklet; - int slot_status; - int ci_irq; - struct dvb_ca_en50221 ca; - struct budget_ci_ir ir; - u8 tuner_pll_address; /* used for philips_tdm1316l configs */ -}; - -static void msp430_ir_interrupt(struct tasklet_struct *t) -{ - struct budget_ci_ir *ir = from_tasklet(ir, t, msp430_irq_tasklet); - struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir); - struct rc_dev *dev = budget_ci->ir.dev; - u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; - - /* - * The msp430 chip can generate two different bytes, command and device - * - * type1: X1CCCCCC, C = command bits (0 - 63) - * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit - * - * Each signal from the remote control can generate one or more command - * bytes and one or more device bytes. For the repeated bytes, the - * highest bit (X) is set. The first command byte is always generated - * before the first device byte. Other than that, no specific order - * seems to apply. To make life interesting, bytes can also be lost. - * - * Only when we have a command and device byte, a keypress is - * generated. - */ - - if (ir_debug) - printk("budget_ci: received byte 0x%02x\n", command); - - /* Remove repeat bit, we use every command */ - command = command & 0x7f; - - /* Is this a RC5 command byte? */ - if (command & 0x40) { - budget_ci->ir.have_command = true; - budget_ci->ir.ir_key = command & 0x3f; - return; - } - - /* It's a RC5 device byte */ - if (!budget_ci->ir.have_command) - return; - budget_ci->ir.have_command = false; - - if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && - budget_ci->ir.rc5_device != (command & 0x1f)) - return; - - if (budget_ci->ir.full_rc5) { - rc_keydown(dev, RC_PROTO_RC5, - RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key), - !!(command & 0x20)); - return; - } - - /* FIXME: We should generate complete scancodes for all devices */ - rc_keydown(dev, RC_PROTO_UNKNOWN, budget_ci->ir.ir_key, - !!(command & 0x20)); -} - -static int msp430_ir_init(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - struct rc_dev *dev; - int error; - - dev = rc_allocate_device(RC_DRIVER_SCANCODE); - if (!dev) { - printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); - return -ENOMEM; - } - - snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), - "Budget-CI dvb ir receiver %s", saa->name); - snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys), - "pci-%s/ir0", pci_name(saa->pci)); - - dev->driver_name = MODULE_NAME; - dev->device_name = budget_ci->ir.name; - dev->input_phys = budget_ci->ir.phys; - dev->input_id.bustype = BUS_PCI; - dev->input_id.version = 1; - if (saa->pci->subsystem_vendor) { - dev->input_id.vendor = saa->pci->subsystem_vendor; - dev->input_id.product = saa->pci->subsystem_device; - } else { - dev->input_id.vendor = saa->pci->vendor; - dev->input_id.product = saa->pci->device; - } - dev->dev.parent = &saa->pci->dev; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = IR_DEVICE_ANY; - else - budget_ci->ir.rc5_device = rc5_device; - - /* Select keymap and address */ - switch (budget_ci->budget.dev->pci->subsystem_device) { - case 0x100c: - case 0x100f: - case 0x1011: - case 0x1012: - /* The hauppauge keymap is a superset of these remotes */ - dev->map_name = RC_MAP_HAUPPAUGE; - budget_ci->ir.full_rc5 = true; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = 0x1f; - break; - case 0x1010: - case 0x1017: - case 0x1019: - case 0x101a: - case 0x101b: - /* for the Technotrend 1500 bundled remote */ - dev->map_name = RC_MAP_TT_1500; - break; - default: - /* unknown remote */ - dev->map_name = RC_MAP_BUDGET_CI_OLD; - break; - } - if (!budget_ci->ir.full_rc5) - dev->scancode_mask = 0xff; - - error = rc_register_device(dev); - if (error) { - printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); - rc_free_device(dev); - return error; - } - - budget_ci->ir.dev = dev; - - tasklet_setup(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt); - - SAA7146_IER_ENABLE(saa, MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); - - return 0; -} - -static void msp430_ir_deinit(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - - SAA7146_IER_DISABLE(saa, MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); - tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); - - rc_unregister_device(budget_ci->ir.dev); -} - -static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, - DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0); -} - -static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, - DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0); -} - -static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, - DEBIADDR_IO | (address & 3), 1, 1, 0); -} - -static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - - if (slot != 0) - return -EINVAL; - - return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, - DEBIADDR_IO | (address & 3), 1, value, 1, 0); -} - -static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - - if (slot != 0) - return -EINVAL; - - if (budget_ci->ci_irq) { - // trigger on RISING edge during reset so we know when READY is re-asserted - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - } - budget_ci->slot_status = SLOTSTATUS_RESET; - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); - msleep(1); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - return 0; -} - -static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - return 0; -} - -static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - struct saa7146_dev *saa = budget_ci->budget.dev; - int tmp; - - if (slot != 0) - return -EINVAL; - - saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); - - tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - tmp | CICONTROL_ENABLETS, 1, 0); - - ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); - return 0; -} - -static void ciintf_interrupt(struct tasklet_struct *t) -{ - struct budget_ci *budget_ci = from_tasklet(budget_ci, t, - ciintf_irq_tasklet); - struct saa7146_dev *saa = budget_ci->budget.dev; - unsigned int flags; - - // ensure we don't get spurious IRQs during initialisation - if (!budget_ci->budget.ci_present) - return; - - // read the CAM status - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - if (flags & CICONTROL_CAMDETECT) { - - // GPIO should be set to trigger on falling edge if a CAM is present - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); - - if (budget_ci->slot_status & SLOTSTATUS_NONE) { - // CAM insertion IRQ - budget_ci->slot_status = SLOTSTATUS_PRESENT; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, - DVB_CA_EN50221_CAMCHANGE_INSERTED); - - } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { - // CAM ready (reset completed) - budget_ci->slot_status = SLOTSTATUS_READY; - dvb_ca_en50221_camready_irq(&budget_ci->ca, 0); - - } else if (budget_ci->slot_status & SLOTSTATUS_READY) { - // FR/DA IRQ - dvb_ca_en50221_frda_irq(&budget_ci->ca, 0); - } - } else { - - // trigger on rising edge if a CAM is not present - when a CAM is inserted, we - // only want to get the IRQ when it sets READY. If we trigger on the falling edge, - // the CAM might not actually be ready yet. - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - - // generate a CAM removal IRQ if we haven't already - if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { - // CAM removal IRQ - budget_ci->slot_status = SLOTSTATUS_NONE; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, - DVB_CA_EN50221_CAMCHANGE_REMOVED); - } - } -} - -static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct budget_ci *budget_ci = (struct budget_ci *) ca->data; - unsigned int flags; - - // ensure we don't get spurious IRQs during initialisation - if (!budget_ci->budget.ci_present) - return -EINVAL; - - // read the CAM status - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - if (flags & CICONTROL_CAMDETECT) { - // mark it as present if it wasn't before - if (budget_ci->slot_status & SLOTSTATUS_NONE) { - budget_ci->slot_status = SLOTSTATUS_PRESENT; - } - - // during a RESET, we check if we can read from IO memory to see when CAM is ready - if (budget_ci->slot_status & SLOTSTATUS_RESET) { - if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) { - budget_ci->slot_status = SLOTSTATUS_READY; - } - } - } else { - budget_ci->slot_status = SLOTSTATUS_NONE; - } - - if (budget_ci->slot_status != SLOTSTATUS_NONE) { - if (budget_ci->slot_status & SLOTSTATUS_READY) { - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - } - return DVB_CA_EN50221_POLL_CAM_PRESENT; - } - - return 0; -} - -static int ciintf_init(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - int flags; - int result; - int ci_version; - int ca_flags; - - memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); - - // enable DEBI pins - saa7146_write(saa, MC1, MASK_27 | MASK_11); - - // test if it is there - ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0); - if ((ci_version & 0xa0) != 0xa0) { - result = -ENODEV; - goto error; - } - - // determine whether a CAM is present or not - flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); - budget_ci->slot_status = SLOTSTATUS_NONE; - if (flags & CICONTROL_CAMDETECT) - budget_ci->slot_status = SLOTSTATUS_PRESENT; - - // version 0xa2 of the CI firmware doesn't generate interrupts - if (ci_version == 0xa2) { - ca_flags = 0; - budget_ci->ci_irq = 0; - } else { - ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | - DVB_CA_EN50221_FLAG_IRQ_FR | - DVB_CA_EN50221_FLAG_IRQ_DA; - budget_ci->ci_irq = 1; - } - - // register CI interface - budget_ci->ca.owner = THIS_MODULE; - budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; - budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; - budget_ci->ca.read_cam_control = ciintf_read_cam_control; - budget_ci->ca.write_cam_control = ciintf_write_cam_control; - budget_ci->ca.slot_reset = ciintf_slot_reset; - budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; - budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; - budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; - budget_ci->ca.data = budget_ci; - if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter, - &budget_ci->ca, - ca_flags, 1)) != 0) { - printk("budget_ci: CI interface detected, but initialisation failed.\n"); - goto error; - } - - // Setup CI slot IRQ - if (budget_ci->ci_irq) { - tasklet_setup(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt); - if (budget_ci->slot_status != SLOTSTATUS_NONE) { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); - } else { - saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); - } - SAA7146_IER_ENABLE(saa, MASK_03); - } - - // enable interface - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - // success! - printk("budget_ci: CI interface initialised\n"); - budget_ci->budget.ci_present = 1; - - // forge a fake CI IRQ so the CAM state is setup correctly - if (budget_ci->ci_irq) { - flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; - if (budget_ci->slot_status != SLOTSTATUS_NONE) - flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); - } - - return 0; - -error: - saa7146_write(saa, MC1, MASK_27); - return result; -} - -static void ciintf_deinit(struct budget_ci *budget_ci) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - - // disable CI interrupts - if (budget_ci->ci_irq) { - SAA7146_IER_DISABLE(saa, MASK_03); - saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); - tasklet_kill(&budget_ci->ciintf_irq_tasklet); - } - - // reset interface - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); - msleep(1); - ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, - CICONTROL_RESET, 1, 0); - - // disable TS data stream to CI interface - saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); - - // release the CA device - dvb_ca_en50221_release(&budget_ci->ca); - - // disable DEBI pins - saa7146_write(saa, MC1, MASK_27); -} - -static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) -{ - struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; - - dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); - - if (*isr & MASK_06) - tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); - - if (*isr & MASK_10) - ttpci_budget_irq10_handler(dev, isr); - - if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) - tasklet_schedule(&budget_ci->ciintf_irq_tasklet); -} - -static u8 philips_su1278_tt_inittab[] = { - 0x01, 0x0f, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x5b, - 0x05, 0x85, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0x02, - 0x09, 0x00, - 0x0C, 0x01, - 0x0D, 0x81, - 0x0E, 0x44, - 0x0f, 0x14, - 0x10, 0x3c, - 0x11, 0x84, - 0x12, 0xda, - 0x13, 0x97, - 0x14, 0x95, - 0x15, 0xc9, - 0x16, 0x19, - 0x17, 0x8c, - 0x18, 0x59, - 0x19, 0xf8, - 0x1a, 0xfe, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x09, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x93, - 0xff, 0xff -}; - -static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) -{ - stv0299_writereg(fe, 0x0e, 0x44); - if (srate >= 10000000) { - stv0299_writereg(fe, 0x13, 0x97); - stv0299_writereg(fe, 0x14, 0x95); - stv0299_writereg(fe, 0x15, 0xc9); - stv0299_writereg(fe, 0x17, 0x8c); - stv0299_writereg(fe, 0x1a, 0xfe); - stv0299_writereg(fe, 0x1c, 0x7f); - stv0299_writereg(fe, 0x2d, 0x09); - } else { - stv0299_writereg(fe, 0x13, 0x99); - stv0299_writereg(fe, 0x14, 0x8d); - stv0299_writereg(fe, 0x15, 0xce); - stv0299_writereg(fe, 0x17, 0x43); - stv0299_writereg(fe, 0x1a, 0x1d); - stv0299_writereg(fe, 0x1c, 0x12); - stv0299_writereg(fe, 0x2d, 0x05); - } - stv0299_writereg(fe, 0x0e, 0x23); - stv0299_writereg(fe, 0x0f, 0x94); - stv0299_writereg(fe, 0x10, 0x39); - stv0299_writereg(fe, 0x15, 0xc9); - - stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg(fe, 0x21, (ratio) & 0xf0); - - return 0; -} - -static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u32 div; - u8 buf[4]; - struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; - - if ((p->frequency < 950000) || (p->frequency > 2150000)) - return -EINVAL; - - div = (p->frequency + (500 - 1)) / 500; /* round correctly */ - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; - buf[3] = 0x20; - - if (p->symbol_rate < 4000000) - buf[3] |= 1; - - if (p->frequency < 1250000) - buf[3] |= 0; - else if (p->frequency < 1550000) - buf[3] |= 0x40; - else if (p->frequency < 2050000) - buf[3] |= 0x80; - else if (p->frequency < 2150000) - buf[3] |= 0xC0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) - return -EIO; - return 0; -} - -static const struct stv0299_config philips_su1278_tt_config = { - - .demod_address = 0x68, - .inittab = philips_su1278_tt_inittab, - .mclk = 64000000UL, - .invert = 0, - .skip_reinit = 1, - .lock_output = STV0299_LOCKOUTPUT_1, - .volt13_op0_op1 = STV0299_VOLT13_OP1, - .min_delay_ms = 50, - .set_symbol_rate = philips_su1278_tt_set_symbol_rate, -}; - - - -static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = - sizeof(td1316_init) }; - - // setup PLL configuration - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - msleep(1); - - // disable the mc44BC374c (do not check for errors) - tuner_msg.addr = 0x65; - tuner_msg.buf = disable_mc44BC374c; - tuner_msg.len = sizeof(disable_mc44BC374c); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); - } - - return 0; -} - -static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = p->frequency + 36130000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) - cp = 3; - else if (tuner_frequency < 160000000) - cp = 5; - else if (tuner_frequency < 200000000) - cp = 6; - else if (tuner_frequency < 290000000) - cp = 3; - else if (tuner_frequency < 420000000) - cp = 5; - else if (tuner_frequency < 480000000) - cp = 6; - else if (tuner_frequency < 620000000) - cp = 3; - else if (tuner_frequency < 830000000) - cp = 5; - else if (tuner_frequency < 895000000) - cp = 7; - else - return -EINVAL; - - // determine band - if (p->frequency < 49000000) - return -EINVAL; - else if (p->frequency < 159000000) - band = 1; - else if (p->frequency < 444000000) - band = 2; - else if (p->frequency < 861000000) - band = 4; - else - return -EINVAL; - - // setup PLL filter and TDA9889 - switch (p->bandwidth_hz) { - case 6000000: - tda1004x_writereg(fe, 0x0C, 0x14); - filter = 0; - break; - - case 7000000: - tda1004x_writereg(fe, 0x0C, 0x80); - filter = 0; - break; - - case 8000000: - tda1004x_writereg(fe, 0x0C, 0x14); - filter = 1; - break; - - default: - return -EINVAL; - } - - // calculate divisor - // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, - const struct firmware **fw, char *name) -{ - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - - return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); -} - -static struct tda1004x_config philips_tdm1316l_config = { - - .demod_address = 0x8, - .invert = 0, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static struct tda1004x_config philips_tdm1316l_config_invert = { - - .demod_address = 0x8, - .invert = 1, - .invert_oclk = 0, - .xtal_freq = TDA10046_XTAL_4M, - .agc_config = TDA10046_AGC_DEFAULT, - .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tdm1316l_request_firmware, -}; - -static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; - u8 tuner_buf[5]; - struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, - .flags = 0, - .buf = tuner_buf, - .len = sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - - // determine charge pump - tuner_frequency = p->frequency + 36125000; - if (tuner_frequency < 87000000) - return -EINVAL; - else if (tuner_frequency < 130000000) { - cp = 3; - band = 1; - } else if (tuner_frequency < 160000000) { - cp = 5; - band = 1; - } else if (tuner_frequency < 200000000) { - cp = 6; - band = 1; - } else if (tuner_frequency < 290000000) { - cp = 3; - band = 2; - } else if (tuner_frequency < 420000000) { - cp = 5; - band = 2; - } else if (tuner_frequency < 480000000) { - cp = 6; - band = 2; - } else if (tuner_frequency < 620000000) { - cp = 3; - band = 4; - } else if (tuner_frequency < 830000000) { - cp = 5; - band = 4; - } else if (tuner_frequency < 895000000) { - cp = 7; - band = 4; - } else - return -EINVAL; - - // assume PLL filter should always be 8MHz for the moment. - filter = 1; - - // calculate divisor - tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xc8; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - tuner_buf[4] = 0x80; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(50); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) - return -EIO; - - msleep(1); - - return 0; -} - -static u8 dvbc_philips_tdm1316l_inittab[] = { - 0x80, 0x01, - 0x80, 0x00, - 0x81, 0x01, - 0x81, 0x00, - 0x00, 0x09, - 0x01, 0x69, - 0x03, 0x00, - 0x04, 0x00, - 0x07, 0x00, - 0x08, 0x00, - 0x20, 0x00, - 0x21, 0x40, - 0x22, 0x00, - 0x23, 0x00, - 0x24, 0x40, - 0x25, 0x88, - 0x30, 0xff, - 0x31, 0x00, - 0x32, 0xff, - 0x33, 0x00, - 0x34, 0x50, - 0x35, 0x7f, - 0x36, 0x00, - 0x37, 0x20, - 0x38, 0x00, - 0x40, 0x1c, - 0x41, 0xff, - 0x42, 0x29, - 0x43, 0x20, - 0x44, 0xff, - 0x45, 0x00, - 0x46, 0x00, - 0x49, 0x04, - 0x4a, 0x00, - 0x4b, 0x7b, - 0x52, 0x30, - 0x55, 0xae, - 0x56, 0x47, - 0x57, 0xe1, - 0x58, 0x3a, - 0x5a, 0x1e, - 0x5b, 0x34, - 0x60, 0x00, - 0x63, 0x00, - 0x64, 0x00, - 0x65, 0x00, - 0x66, 0x00, - 0x67, 0x00, - 0x68, 0x00, - 0x69, 0x00, - 0x6a, 0x02, - 0x6b, 0x00, - 0x70, 0xff, - 0x71, 0x00, - 0x72, 0x00, - 0x73, 0x00, - 0x74, 0x0c, - 0x80, 0x00, - 0x81, 0x00, - 0x82, 0x00, - 0x83, 0x00, - 0x84, 0x04, - 0x85, 0x80, - 0x86, 0x24, - 0x87, 0x78, - 0x88, 0x10, - 0x89, 0x00, - 0x90, 0x01, - 0x91, 0x01, - 0xa0, 0x04, - 0xa1, 0x00, - 0xa2, 0x00, - 0xb0, 0x91, - 0xb1, 0x0b, - 0xc0, 0x53, - 0xc1, 0x70, - 0xc2, 0x12, - 0xd0, 0x00, - 0xd1, 0x00, - 0xd2, 0x00, - 0xd3, 0x00, - 0xd4, 0x00, - 0xd5, 0x00, - 0xde, 0x00, - 0xdf, 0x00, - 0x61, 0x38, - 0x62, 0x0a, - 0x53, 0x13, - 0x59, 0x08, - 0xff, 0xff, -}; - -static struct stv0297_config dvbc_philips_tdm1316l_config = { - .demod_address = 0x1c, - .inittab = dvbc_philips_tdm1316l_inittab, - .invert = 0, - .stop_during_read = 1, -}; - -static struct tda10023_config tda10023_config = { - .demod_address = 0xc, - .invert = 0, - .xtal = 16000000, - .pll_m = 11, - .pll_p = 3, - .pll_n = 1, - .deltaf = 0xa511, -}; - -static struct tda827x_config tda827x_config = { - .config = 0, -}; - -/* TT S2-3200 DVB-S (STB0899) Inittab */ -static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { - - { STB0899_DEV_ID , 0x81 }, - { STB0899_DISCNTRL1 , 0x32 }, - { STB0899_DISCNTRL2 , 0x80 }, - { STB0899_DISRX_ST0 , 0x04 }, - { STB0899_DISRX_ST1 , 0x00 }, - { STB0899_DISPARITY , 0x00 }, - { STB0899_DISSTATUS , 0x20 }, - { STB0899_DISF22 , 0x8c }, - { STB0899_DISF22RX , 0x9a }, - { STB0899_SYSREG , 0x0b }, - { STB0899_ACRPRESC , 0x11 }, - { STB0899_ACRDIV1 , 0x0a }, - { STB0899_ACRDIV2 , 0x05 }, - { STB0899_DACR1 , 0x00 }, - { STB0899_DACR2 , 0x00 }, - { STB0899_OUTCFG , 0x00 }, - { STB0899_MODECFG , 0x00 }, - { STB0899_IRQSTATUS_3 , 0x30 }, - { STB0899_IRQSTATUS_2 , 0x00 }, - { STB0899_IRQSTATUS_1 , 0x00 }, - { STB0899_IRQSTATUS_0 , 0x00 }, - { STB0899_IRQMSK_3 , 0xf3 }, - { STB0899_IRQMSK_2 , 0xfc }, - { STB0899_IRQMSK_1 , 0xff }, - { STB0899_IRQMSK_0 , 0xff }, - { STB0899_IRQCFG , 0x00 }, - { STB0899_I2CCFG , 0x88 }, - { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ - { STB0899_IOPVALUE5 , 0x00 }, - { STB0899_IOPVALUE4 , 0x20 }, - { STB0899_IOPVALUE3 , 0xc9 }, - { STB0899_IOPVALUE2 , 0x90 }, - { STB0899_IOPVALUE1 , 0x40 }, - { STB0899_IOPVALUE0 , 0x00 }, - { STB0899_GPIO00CFG , 0x82 }, - { STB0899_GPIO01CFG , 0x82 }, - { STB0899_GPIO02CFG , 0x82 }, - { STB0899_GPIO03CFG , 0x82 }, - { STB0899_GPIO04CFG , 0x82 }, - { STB0899_GPIO05CFG , 0x82 }, - { STB0899_GPIO06CFG , 0x82 }, - { STB0899_GPIO07CFG , 0x82 }, - { STB0899_GPIO08CFG , 0x82 }, - { STB0899_GPIO09CFG , 0x82 }, - { STB0899_GPIO10CFG , 0x82 }, - { STB0899_GPIO11CFG , 0x82 }, - { STB0899_GPIO12CFG , 0x82 }, - { STB0899_GPIO13CFG , 0x82 }, - { STB0899_GPIO14CFG , 0x82 }, - { STB0899_GPIO15CFG , 0x82 }, - { STB0899_GPIO16CFG , 0x82 }, - { STB0899_GPIO17CFG , 0x82 }, - { STB0899_GPIO18CFG , 0x82 }, - { STB0899_GPIO19CFG , 0x82 }, - { STB0899_GPIO20CFG , 0x82 }, - { STB0899_SDATCFG , 0xb8 }, - { STB0899_SCLTCFG , 0xba }, - { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ - { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ - { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ - { STB0899_DIRCLKCFG , 0x82 }, - { STB0899_CLKOUT27CFG , 0x7e }, - { STB0899_STDBYCFG , 0x82 }, - { STB0899_CS0CFG , 0x82 }, - { STB0899_CS1CFG , 0x82 }, - { STB0899_DISEQCOCFG , 0x20 }, - { STB0899_GPIO32CFG , 0x82 }, - { STB0899_GPIO33CFG , 0x82 }, - { STB0899_GPIO34CFG , 0x82 }, - { STB0899_GPIO35CFG , 0x82 }, - { STB0899_GPIO36CFG , 0x82 }, - { STB0899_GPIO37CFG , 0x82 }, - { STB0899_GPIO38CFG , 0x82 }, - { STB0899_GPIO39CFG , 0x82 }, - { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ - { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ - { STB0899_FILTCTRL , 0x00 }, - { STB0899_SYSCTRL , 0x00 }, - { STB0899_STOPCLK1 , 0x20 }, - { STB0899_STOPCLK2 , 0x00 }, - { STB0899_INTBUFSTATUS , 0x00 }, - { STB0899_INTBUFCTRL , 0x0a }, - { 0xffff , 0xff }, -}; - -static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { - { STB0899_DEMOD , 0x00 }, - { STB0899_RCOMPC , 0xc9 }, - { STB0899_AGC1CN , 0x41 }, - { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x7a }, - { STB0899_TMGCFG , 0x4e }, - { STB0899_AGC2REF , 0x34 }, - { STB0899_TLSR , 0x84 }, - { STB0899_CFD , 0xc7 }, - { STB0899_ACLC , 0x87 }, - { STB0899_BCLC , 0x94 }, - { STB0899_EQON , 0x41 }, - { STB0899_LDT , 0xdd }, - { STB0899_LDT2 , 0xc9 }, - { STB0899_EQUALREF , 0xb4 }, - { STB0899_TMGRAMP , 0x10 }, - { STB0899_TMGTHD , 0x30 }, - { STB0899_IDCCOMP , 0xfb }, - { STB0899_QDCCOMP , 0x03 }, - { STB0899_POWERI , 0x3b }, - { STB0899_POWERQ , 0x3d }, - { STB0899_RCOMP , 0x81 }, - { STB0899_AGCIQIN , 0x80 }, - { STB0899_AGC2I1 , 0x04 }, - { STB0899_AGC2I2 , 0xf5 }, - { STB0899_TLIR , 0x25 }, - { STB0899_RTF , 0x80 }, - { STB0899_DSTATUS , 0x00 }, - { STB0899_LDI , 0xca }, - { STB0899_CFRM , 0xf1 }, - { STB0899_CFRL , 0xf3 }, - { STB0899_NIRM , 0x2a }, - { STB0899_NIRL , 0x05 }, - { STB0899_ISYMB , 0x17 }, - { STB0899_QSYMB , 0xfa }, - { STB0899_SFRH , 0x2f }, - { STB0899_SFRM , 0x68 }, - { STB0899_SFRL , 0x40 }, - { STB0899_SFRUPH , 0x2f }, - { STB0899_SFRUPM , 0x68 }, - { STB0899_SFRUPL , 0x40 }, - { STB0899_EQUAI1 , 0xfd }, - { STB0899_EQUAQ1 , 0x04 }, - { STB0899_EQUAI2 , 0x0f }, - { STB0899_EQUAQ2 , 0xff }, - { STB0899_EQUAI3 , 0xdf }, - { STB0899_EQUAQ3 , 0xfa }, - { STB0899_EQUAI4 , 0x37 }, - { STB0899_EQUAQ4 , 0x0d }, - { STB0899_EQUAI5 , 0xbd }, - { STB0899_EQUAQ5 , 0xf7 }, - { STB0899_DSTATUS2 , 0x00 }, - { STB0899_VSTATUS , 0x00 }, - { STB0899_VERROR , 0xff }, - { STB0899_IQSWAP , 0x2a }, - { STB0899_ECNT1M , 0x00 }, - { STB0899_ECNT1L , 0x00 }, - { STB0899_ECNT2M , 0x00 }, - { STB0899_ECNT2L , 0x00 }, - { STB0899_ECNT3M , 0x00 }, - { STB0899_ECNT3L , 0x00 }, - { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, - { STB0899_VTH12 , 0xf0 }, - { STB0899_VTH23 , 0xa0 }, - { STB0899_VTH34 , 0x78 }, - { STB0899_VTH56 , 0x4e }, - { STB0899_VTH67 , 0x48 }, - { STB0899_VTH78 , 0x38 }, - { STB0899_PRVIT , 0xff }, - { STB0899_VITSYNC , 0x19 }, - { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ - { STB0899_TSULC , 0x42 }, - { STB0899_RSLLC , 0x40 }, - { STB0899_TSLPL , 0x12 }, - { STB0899_TSCFGH , 0x0c }, - { STB0899_TSCFGM , 0x00 }, - { STB0899_TSCFGL , 0x0c }, - { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ - { STB0899_RSSYNCDEL , 0x00 }, - { STB0899_TSINHDELH , 0x02 }, - { STB0899_TSINHDELM , 0x00 }, - { STB0899_TSINHDELL , 0x00 }, - { STB0899_TSLLSTKM , 0x00 }, - { STB0899_TSLLSTKL , 0x00 }, - { STB0899_TSULSTKM , 0x00 }, - { STB0899_TSULSTKL , 0xab }, - { STB0899_PCKLENUL , 0x00 }, - { STB0899_PCKLENLL , 0xcc }, - { STB0899_RSPCKLEN , 0xcc }, - { STB0899_TSSTATUS , 0x80 }, - { STB0899_ERRCTRL1 , 0xb6 }, - { STB0899_ERRCTRL2 , 0x96 }, - { STB0899_ERRCTRL3 , 0x89 }, - { STB0899_DMONMSK1 , 0x27 }, - { STB0899_DMONMSK0 , 0x03 }, - { STB0899_DEMAPVIT , 0x5c }, - { STB0899_PLPARM , 0x1f }, - { STB0899_PDELCTRL , 0x48 }, - { STB0899_PDELCTRL2 , 0x00 }, - { STB0899_BBHCTRL1 , 0x00 }, - { STB0899_BBHCTRL2 , 0x00 }, - { STB0899_HYSTTHRESH , 0x77 }, - { STB0899_MATCSTM , 0x00 }, - { STB0899_MATCSTL , 0x00 }, - { STB0899_UPLCSTM , 0x00 }, - { STB0899_UPLCSTL , 0x00 }, - { STB0899_DFLCSTM , 0x00 }, - { STB0899_DFLCSTL , 0x00 }, - { STB0899_SYNCCST , 0x00 }, - { STB0899_SYNCDCSTM , 0x00 }, - { STB0899_SYNCDCSTL , 0x00 }, - { STB0899_ISI_ENTRY , 0x00 }, - { STB0899_ISI_BIT_EN , 0x00 }, - { STB0899_MATSTRM , 0x00 }, - { STB0899_MATSTRL , 0x00 }, - { STB0899_UPLSTRM , 0x00 }, - { STB0899_UPLSTRL , 0x00 }, - { STB0899_DFLSTRM , 0x00 }, - { STB0899_DFLSTRL , 0x00 }, - { STB0899_SYNCSTR , 0x00 }, - { STB0899_SYNCDSTRM , 0x00 }, - { STB0899_SYNCDSTRL , 0x00 }, - { STB0899_CFGPDELSTATUS1 , 0x10 }, - { STB0899_CFGPDELSTATUS2 , 0x00 }, - { STB0899_BBFERRORM , 0x00 }, - { STB0899_BBFERRORL , 0x00 }, - { STB0899_UPKTERRORM , 0x00 }, - { STB0899_UPKTERRORL , 0x00 }, - { 0xffff , 0xff }, -}; - -static struct stb0899_config tt3200_config = { - .init_dev = tt3200_stb0899_s1_init_1, - .init_s2_demod = stb0899_s2_init_2, - .init_s1_demod = tt3200_stb0899_s1_init_3, - .init_s2_fec = stb0899_s2_init_4, - .init_tst = stb0899_s1_init_5, - - .postproc = NULL, - - .demod_address = 0x68, - - .xtal_freq = 27000000, - .inversion = IQ_SWAP_ON, - - .lo_clk = 76500000, - .hi_clk = 99000000, - - .esno_ave = STB0899_DVBS2_ESNO_AVE, - .esno_quant = STB0899_DVBS2_ESNO_QUANT, - .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, - .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, - .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, - .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, - .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, - .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, - .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, - - .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, - .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, - .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, - .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, - - .tuner_get_frequency = stb6100_get_frequency, - .tuner_set_frequency = stb6100_set_frequency, - .tuner_set_bandwidth = stb6100_set_bandwidth, - .tuner_get_bandwidth = stb6100_get_bandwidth, - .tuner_set_rfsiggain = NULL -}; - -static struct stb6100_config tt3200_stb6100_config = { - .tuner_address = 0x60, - .refclock = 27000000, -}; - -static void frontend_init(struct budget_ci *budget_ci) -{ - switch (budget_ci->budget.dev->pci->subsystem_device) { - case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) - budget_ci->budget.dvb_frontend = - dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; - break; - } - break; - - case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) - budget_ci->budget.dvb_frontend = - dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; - break; - } - break; - - case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) - budget_ci->tuner_pll_address = 0x61; - budget_ci->budget.dvb_frontend = - dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) - budget_ci->tuner_pll_address = 0x63; - budget_ci->budget.dvb_frontend = - dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) - budget_ci->tuner_pll_address = 0x60; - budget_ci->budget.dvb_frontend = - dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; - break; - } - break; - - case 0x1017: // TT S-1500 PCI - budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; - - budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ - budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) { - printk(KERN_ERR "%s: No tda827x found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */ - budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) { - if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { - printk(KERN_ERR "%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } else { - printk(KERN_ERR "%s: No STB6000 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - case 0x1019: // TT S2-3200 PCI - /* - * NOTE! on some STB0899 versions, the internal PLL takes a longer time - * to settle, aka LOCK. On the older revisions of the chip, we don't see - * this, as a result on the newer chips the entire clock tree, will not - * be stable after a freshly POWER 'ed up situation. - * In this case, we should RESET the STB0899 (Active LOW) and wait for - * PLL stabilization. - * - * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is - * connected to the SAA7146 GPIO, GPIO2, Pin 142 - */ - /* Reset Demodulator */ - saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO); - /* Wait for everything to die */ - msleep(50); - /* Pull it up out of Reset state */ - saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI); - /* Wait for PLL to stabilize */ - msleep(250); - /* - * PLL state should be stable now. Ideally, we should check - * for PLL LOCK status. But well, never mind! - */ - budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); - if (budget_ci->budget.dvb_frontend) { - if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { - if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { - printk("%s: No LNBP21 found!\n", __func__); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } else { - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } - break; - - } - - if (budget_ci->budget.dvb_frontend == NULL) { - printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget_ci->budget.dev->pci->vendor, - budget_ci->budget.dev->pci->device, - budget_ci->budget.dev->pci->subsystem_vendor, - budget_ci->budget.dev->pci->subsystem_device); - } else { - if (dvb_register_frontend - (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { - printk("budget-ci: Frontend registration failed!\n"); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - budget_ci->budget.dvb_frontend = NULL; - } - } -} - -static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) -{ - struct budget_ci *budget_ci; - int err; - - budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL); - if (!budget_ci) { - err = -ENOMEM; - goto out1; - } - - dprintk(2, "budget_ci: %p\n", budget_ci); - - dev->ext_priv = budget_ci; - - err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE, - adapter_nr); - if (err) - goto out2; - - err = msp430_ir_init(budget_ci); - if (err) - goto out3; - - ciintf_init(budget_ci); - - budget_ci->budget.dvb_adapter.priv = budget_ci; - frontend_init(budget_ci); - - ttpci_budget_init_hooks(&budget_ci->budget); - - return 0; - -out3: - ttpci_budget_deinit(&budget_ci->budget); -out2: - kfree(budget_ci); -out1: - return err; -} - -static int budget_ci_detach(struct saa7146_dev *dev) -{ - struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv; - struct saa7146_dev *saa = budget_ci->budget.dev; - int err; - - if (budget_ci->budget.ci_present) - ciintf_deinit(budget_ci); - msp430_ir_deinit(budget_ci); - if (budget_ci->budget.dvb_frontend) { - dvb_unregister_frontend(budget_ci->budget.dvb_frontend); - dvb_frontend_detach(budget_ci->budget.dvb_frontend); - } - err = ttpci_budget_deinit(&budget_ci->budget); - - // disable frontend and CI interface - saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); - - kfree(budget_ci); - - return err; -} - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC); -MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT); - -static const struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), - MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), - MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), - MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), - MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), - MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), - MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), - MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), - MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget_ci dvb", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = &pci_tbl[0], - .attach = budget_ci_attach, - .detach = budget_ci_detach, - - .irq_mask = MASK_03 | MASK_06 | MASK_10, - .irq_func = budget_ci_irq, -}; - -static int __init budget_ci_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_ci_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_ci_init); -module_exit(budget_ci_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards w/ CI-module produced by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c deleted file mode 100644 index 5d5796f24469..000000000000 --- a/drivers/media/pci/ttpci/budget-core.c +++ /dev/null @@ -1,603 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * budget-core.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold <michael@mihu.de> - * - * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 26feb2004 Support for FS Activy Card (Grundig tuner) by - * Michael Dreher <michael@5dot1.de>, - * Oliver Endriss <o.endriss@gmx.de>, - * Andreas 'randy' Weinberger - * - * the project's page is at https://linuxtv.org - */ - - -#include "budget.h" -#include "ttpci-eeprom.h" - -#define TS_WIDTH (2 * TS_SIZE) -#define TS_WIDTH_ACTIVY TS_SIZE -#define TS_WIDTH_DVBC TS_SIZE -#define TS_HEIGHT_MASK 0xf00 -#define TS_HEIGHT_MASK_ACTIVY 0xc00 -#define TS_HEIGHT_MASK_DVBC 0xe00 -#define TS_MIN_BUFSIZE_K 188 -#define TS_MAX_BUFSIZE_K 1410 -#define TS_MAX_BUFSIZE_K_ACTIVY 564 -#define TS_MAX_BUFSIZE_K_DVBC 1316 -#define BUFFER_WARNING_WAIT (30*HZ) - -int budget_debug; -static int dma_buffer_size = TS_MIN_BUFSIZE_K; -module_param_named(debug, budget_debug, int, 0644); -module_param_named(bufsize, dma_buffer_size, int, 0444); -MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); -MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); - -/**************************************************************************** - * TT budget / WinTV Nova - ****************************************************************************/ - -static int stop_ts_capture(struct budget *budget) -{ - dprintk(2, "budget: %p\n", budget); - - saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off - SAA7146_IER_DISABLE(budget->dev, MASK_10); - return 0; -} - -static int start_ts_capture(struct budget *budget) -{ - struct saa7146_dev *dev = budget->dev; - - dprintk(2, "budget: %p\n", budget); - - if (!budget->feeding || !budget->fe_synced) - return 0; - - saa7146_write(dev, MC1, MASK_20); // DMA3 off - - memset(budget->grabbing, 0x00, budget->buffer_size); - - saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); - - budget->ttbp = 0; - - /* - * Signal path on the Activy: - * - * tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory - * - * Since the tuner feeds 204 bytes packets into the SAA7146, - * DMA3 is configured to strip the trailing 16 FEC bytes: - * Pitch: 188, NumBytes3: 188, NumLines3: 1024 - */ - - switch(budget->card->type) { - case BUDGET_FS_ACTIVY: - saa7146_write(dev, DD1_INIT, 0x04000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - break; - case BUDGET_PATCH: - saa7146_write(dev, DD1_INIT, 0x00000200); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - break; - case BUDGET_CIN1200C_MK3: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1C_TDA10024: - case BUDGET_KNC1CP_MK3: - if (budget->video_port == BUDGET_VIDEO_PORTA) { - saa7146_write(dev, DD1_INIT, 0x06000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { - saa7146_write(dev, DD1_INIT, 0x00000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - } - break; - default: - if (budget->video_port == BUDGET_VIDEO_PORTA) { - saa7146_write(dev, DD1_INIT, 0x06000200); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { - saa7146_write(dev, DD1_INIT, 0x02000600); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - saa7146_write(dev, BRS_CTRL, 0x60000000); - } - } - - saa7146_write(dev, MC2, (MASK_08 | MASK_24)); - mdelay(10); - - saa7146_write(dev, BASE_ODD3, 0); - if (budget->buffer_size > budget->buffer_height * budget->buffer_width) { - // using odd/even buffers - saa7146_write(dev, BASE_EVEN3, budget->buffer_height * budget->buffer_width); - } else { - // using a single buffer - saa7146_write(dev, BASE_EVEN3, 0); - } - saa7146_write(dev, PROT_ADDR3, budget->buffer_size); - saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); - - saa7146_write(dev, PITCH3, budget->buffer_width); - saa7146_write(dev, NUM_LINE_BYTE3, - (budget->buffer_height << 16) | budget->buffer_width); - - saa7146_write(dev, MC2, (MASK_04 | MASK_20)); - - SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ - SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ - saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ - - return 0; -} - -static int budget_read_fe_status(struct dvb_frontend *fe, - enum fe_status *status) -{ - struct budget *budget = (struct budget *) fe->dvb->priv; - int synced; - int ret; - - if (budget->read_fe_status) - ret = budget->read_fe_status(fe, status); - else - ret = -EINVAL; - - if (!ret) { - synced = (*status & FE_HAS_LOCK); - if (synced != budget->fe_synced) { - budget->fe_synced = synced; - spin_lock(&budget->feedlock); - if (synced) - start_ts_capture(budget); - else - stop_ts_capture(budget); - spin_unlock(&budget->feedlock); - } - } - return ret; -} - -static void vpeirq(struct tasklet_struct *t) -{ - struct budget *budget = from_tasklet(budget, t, vpe_tasklet); - u8 *mem = (u8 *) (budget->grabbing); - u32 olddma = budget->ttbp; - u32 newdma = saa7146_read(budget->dev, PCI_VDP3); - u32 count; - - /* Ensure streamed PCI data is synced to CPU */ - dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist, - budget->pt.nents, DMA_FROM_DEVICE); - - /* nearest lower position divisible by 188 */ - newdma -= newdma % 188; - - if (newdma >= budget->buffer_size) - return; - - budget->ttbp = newdma; - - if (budget->feeding == 0 || newdma == olddma) - return; - - if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ - count = newdma - olddma; - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); - } else { /* wraparound, dump olddma..buflen and 0..newdma */ - count = budget->buffer_size - olddma; - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); - count += newdma; - dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); - } - - if (count > budget->buffer_warning_threshold) - budget->buffer_warnings++; - - if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) { - printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n", - budget->dev->name, __func__, budget->buffer_warnings, count); - budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT; - budget->buffer_warnings = 0; - } -} - - -static int ttpci_budget_debiread_nolock(struct budget *budget, u32 config, - int addr, int count, int nobusyloop) -{ - struct saa7146_dev *saa = budget->dev; - int result; - - result = saa7146_wait_for_debi_done(saa, nobusyloop); - if (result < 0) - return result; - - saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, MC2, (2 << 16) | 2); - - result = saa7146_wait_for_debi_done(saa, nobusyloop); - if (result < 0) - return result; - - result = saa7146_read(saa, DEBI_AD); - result &= (0xffffffffUL >> ((4 - count) * 8)); - return result; -} - -int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop) -{ - if (count > 4 || count <= 0) - return 0; - - if (uselocks) { - unsigned long flags; - int result; - - spin_lock_irqsave(&budget->debilock, flags); - result = ttpci_budget_debiread_nolock(budget, config, addr, - count, nobusyloop); - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - return ttpci_budget_debiread_nolock(budget, config, addr, - count, nobusyloop); -} - -static int ttpci_budget_debiwrite_nolock(struct budget *budget, u32 config, - int addr, int count, u32 value, int nobusyloop) -{ - struct saa7146_dev *saa = budget->dev; - int result; - - result = saa7146_wait_for_debi_done(saa, nobusyloop); - if (result < 0) - return result; - - saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, DEBI_AD, value); - saa7146_write(saa, MC2, (2 << 16) | 2); - - result = saa7146_wait_for_debi_done(saa, nobusyloop); - return result < 0 ? result : 0; -} - -int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, - int count, u32 value, int uselocks, int nobusyloop) -{ - if (count > 4 || count <= 0) - return 0; - - if (uselocks) { - unsigned long flags; - int result; - - spin_lock_irqsave(&budget->debilock, flags); - result = ttpci_budget_debiwrite_nolock(budget, config, addr, - count, value, nobusyloop); - spin_unlock_irqrestore(&budget->debilock, flags); - return result; - } - return ttpci_budget_debiwrite_nolock(budget, config, addr, - count, value, nobusyloop); -} - - -/**************************************************************************** - * DVB API SECTION - ****************************************************************************/ - -static int budget_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct budget *budget = (struct budget *) demux->priv; - int status = 0; - - dprintk(2, "budget: %p\n", budget); - - if (!demux->dmx.frontend) - return -EINVAL; - - spin_lock(&budget->feedlock); - feed->pusi_seen = false; /* have a clean section start */ - if (budget->feeding++ == 0) - status = start_ts_capture(budget); - spin_unlock(&budget->feedlock); - return status; -} - -static int budget_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct budget *budget = (struct budget *) demux->priv; - int status = 0; - - dprintk(2, "budget: %p\n", budget); - - spin_lock(&budget->feedlock); - if (--budget->feeding == 0) - status = stop_ts_capture(budget); - spin_unlock(&budget->feedlock); - return status; -} - -static int budget_register(struct budget *budget) -{ - struct dvb_demux *dvbdemux = &budget->demux; - int ret; - - dprintk(2, "budget: %p\n", budget); - - dvbdemux->priv = (void *) budget; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = budget_start_feed; - dvbdemux->stop_feed = budget_stop_feed; - dvbdemux->write_to_decoder = NULL; - - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING); - - dvb_dmx_init(&budget->demux); - - budget->dmxdev.filternum = 256; - budget->dmxdev.demux = &dvbdemux->dmx; - budget->dmxdev.capabilities = 0; - - dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter); - - budget->hw_frontend.source = DMX_FRONTEND_0; - - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend); - - if (ret < 0) - goto err_release_dmx; - - budget->mem_frontend.source = DMX_MEMORY_FE; - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); - if (ret < 0) - goto err_release_dmx; - - ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); - if (ret < 0) - goto err_release_dmx; - - dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx); - - return 0; - -err_release_dmx: - dvb_dmxdev_release(&budget->dmxdev); - dvb_dmx_release(&budget->demux); - return ret; -} - -static void budget_unregister(struct budget *budget) -{ - struct dvb_demux *dvbdemux = &budget->demux; - - dprintk(2, "budget: %p\n", budget); - - dvb_net_release(&budget->dvb_net); - - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend); - - dvb_dmxdev_release(&budget->dmxdev); - dvb_dmx_release(&budget->demux); -} - -int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, - struct saa7146_pci_extension_data *info, - struct module *owner, short *adapter_nums) -{ - int ret = 0; - struct budget_info *bi = info->ext_priv; - int max_bufsize; - int height_mask; - - memset(budget, 0, sizeof(struct budget)); - - dprintk(2, "dev: %p, budget: %p\n", dev, budget); - - budget->card = bi; - budget->dev = (struct saa7146_dev *) dev; - - switch(budget->card->type) { - case BUDGET_FS_ACTIVY: - budget->buffer_width = TS_WIDTH_ACTIVY; - max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; - height_mask = TS_HEIGHT_MASK_ACTIVY; - break; - - case BUDGET_KNC1C: - case BUDGET_KNC1CP: - case BUDGET_CIN1200C: - case BUDGET_KNC1C_MK3: - case BUDGET_KNC1C_TDA10024: - case BUDGET_KNC1CP_MK3: - case BUDGET_CIN1200C_MK3: - budget->buffer_width = TS_WIDTH_DVBC; - max_bufsize = TS_MAX_BUFSIZE_K_DVBC; - height_mask = TS_HEIGHT_MASK_DVBC; - break; - - default: - budget->buffer_width = TS_WIDTH; - max_bufsize = TS_MAX_BUFSIZE_K; - height_mask = TS_HEIGHT_MASK; - } - - if (dma_buffer_size < TS_MIN_BUFSIZE_K) - dma_buffer_size = TS_MIN_BUFSIZE_K; - else if (dma_buffer_size > max_bufsize) - dma_buffer_size = max_bufsize; - - budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; - if (budget->buffer_height > 0xfff) { - budget->buffer_height /= 2; - budget->buffer_height &= height_mask; - budget->buffer_size = 2 * budget->buffer_height * budget->buffer_width; - } else { - budget->buffer_height &= height_mask; - budget->buffer_size = budget->buffer_height * budget->buffer_width; - } - budget->buffer_warning_threshold = budget->buffer_size * 80/100; - budget->buffer_warnings = 0; - budget->buffer_warning_time = jiffies; - - dprintk(2, "%s: buffer type = %s, width = %d, height = %d\n", - budget->dev->name, - budget->buffer_size > budget->buffer_width * budget->buffer_height ? "odd/even" : "single", - budget->buffer_width, budget->buffer_height); - printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); - - ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, - owner, &budget->dev->pci->dev, adapter_nums); - if (ret < 0) - return ret; - - /* set dd1 stream a & b */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25)); - saa7146_write(dev, MC2, (MASK_10 | MASK_26)); - saa7146_write(dev, DD1_INIT, 0x02000000); - saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - - if (bi->type != BUDGET_FS_ACTIVY) - budget->video_port = BUDGET_VIDEO_PORTB; - else - budget->video_port = BUDGET_VIDEO_PORTA; - spin_lock_init(&budget->feedlock); - spin_lock_init(&budget->debilock); - - /* the Siemens DVB needs this if you want to have the i2c chips - get recognized before the main driver is loaded */ - if (bi->type != BUDGET_FS_ACTIVY) - saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */ - - strscpy(budget->i2c_adap.name, budget->card->name, - sizeof(budget->i2c_adap.name)); - - saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); - strscpy(budget->i2c_adap.name, budget->card->name, - sizeof(budget->i2c_adap.name)); - - if (i2c_add_adapter(&budget->i2c_adap) < 0) { - ret = -ENOMEM; - goto err_dvb_unregister; - } - - ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); - - budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt); - if (NULL == budget->grabbing) { - ret = -ENOMEM; - goto err_del_i2c; - } - - saa7146_write(dev, PCI_BT_V1, 0x001c0000); - /* upload all */ - saa7146_write(dev, GPIO_CTRL, 0x000000); - - tasklet_setup(&budget->vpe_tasklet, vpeirq); - - /* frontend power on */ - if (bi->type != BUDGET_FS_ACTIVY) - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - - if ((ret = budget_register(budget)) == 0) - return 0; /* Everything OK */ - - /* An error occurred, cleanup resources */ - saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); - -err_del_i2c: - i2c_del_adapter(&budget->i2c_adap); - -err_dvb_unregister: - dvb_unregister_adapter(&budget->dvb_adapter); - - return ret; -} - -void ttpci_budget_init_hooks(struct budget *budget) -{ - if (budget->dvb_frontend && !budget->read_fe_status) { - budget->read_fe_status = budget->dvb_frontend->ops.read_status; - budget->dvb_frontend->ops.read_status = budget_read_fe_status; - } -} - -int ttpci_budget_deinit(struct budget *budget) -{ - struct saa7146_dev *dev = budget->dev; - - dprintk(2, "budget: %p\n", budget); - - budget_unregister(budget); - - tasklet_kill(&budget->vpe_tasklet); - - saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); - - i2c_del_adapter(&budget->i2c_adap); - - dvb_unregister_adapter(&budget->dvb_adapter); - - return 0; -} - -void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr) -{ - struct budget *budget = (struct budget *) dev->ext_priv; - - dprintk(8, "dev: %p, budget: %p\n", dev, budget); - - if (*isr & MASK_10) - tasklet_schedule(&budget->vpe_tasklet); -} - -void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) -{ - struct budget *budget = (struct budget *) dev->ext_priv; - - spin_lock(&budget->feedlock); - budget->video_port = video_port; - if (budget->feeding) { - stop_ts_capture(budget); - start_ts_capture(budget); - } - spin_unlock(&budget->feedlock); -} - -EXPORT_SYMBOL_GPL(ttpci_budget_debiread); -EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite); -EXPORT_SYMBOL_GPL(ttpci_budget_init); -EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks); -EXPORT_SYMBOL_GPL(ttpci_budget_deinit); -EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); -EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); -EXPORT_SYMBOL_GPL(budget_debug); - -MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c deleted file mode 100644 index a88711a3ac7f..000000000000 --- a/drivers/media/pci/ttpci/budget.c +++ /dev/null @@ -1,883 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * budget.c: driver for the SAA7146 based Budget DVB cards - * - * Compiled from various sources by Michael Hunold <michael@mihu.de> - * - * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> - * - * Copyright (C) 1999-2002 Ralph Metzler - * & Marcus Metzler for convergence integrated media GmbH - * - * 26feb2004 Support for FS Activy Card (Grundig tuner) by - * Michael Dreher <michael@5dot1.de>, - * Oliver Endriss <o.endriss@gmx.de> and - * Andreas 'randy' Weinberger - * - * the project's page is at https://linuxtv.org - */ - -#include "budget.h" -#include "stv0299.h" -#include "ves1x93.h" -#include "ves1820.h" -#include "l64781.h" -#include "tda8083.h" -#include "s5h1420.h" -#include "tda10086.h" -#include "tda826x.h" -#include "lnbp21.h" -#include "bsru6.h" -#include "bsbe1.h" -#include "tdhd1.h" -#include "stv6110x.h" -#include "stv090x.h" -#include "isl6423.h" -#include "lnbh24.h" - - -static int diseqc_method; -module_param(diseqc_method, int, 0444); -MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -static void Set22K (struct budget *budget, int state) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); -} - -/* Diseqc functions only for TT Budget card */ -/* taken from the Skyvision DVB driver by - Ralph Metzler <rjkm@metzlerbros.de> */ - -static void DiseqcSendBit (struct budget *budget, int data) -{ - struct saa7146_dev *dev=budget->dev; - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(data ? 500 : 1000); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - udelay(data ? 1000 : 500); -} - -static void DiseqcSendByte (struct budget *budget, int data) -{ - int i, par=1, d; - - dprintk(2, "budget: %p\n", budget); - - for (i=7; i>=0; i--) { - d = (data>>i)&1; - par ^= d; - DiseqcSendBit(budget, d); - } - - DiseqcSendBit(budget, par); -} - -static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) -{ - struct saa7146_dev *dev=budget->dev; - int i; - - dprintk(2, "budget: %p\n", budget); - - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - mdelay(16); - - for (i=0; i<len; i++) - DiseqcSendByte(budget, msg[i]); - - mdelay(16); - - if (burst!=-1) { - if (burst) - DiseqcSendByte(budget, 0xff); - else { - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - mdelay(12); - udelay(500); - saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); - } - msleep(20); - } - - return 0; -} - -/* - * Routines for the Fujitsu Siemens Activy budget card - * 22 kHz tone and DiSEqC are handled by the frontend. - * Voltage must be set here. - * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL - */ -static int SetVoltage_Activy(struct budget *budget, - enum fe_sec_voltage voltage) -{ - struct saa7146_dev *dev=budget->dev; - - dprintk(2, "budget: %p\n", budget); - - switch (voltage) { - case SEC_VOLTAGE_13: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); - break; - case SEC_VOLTAGE_18: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - break; - case SEC_VOLTAGE_OFF: - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int siemens_budget_set_voltage(struct dvb_frontend *fe, - enum fe_sec_voltage voltage) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - return SetVoltage_Activy (budget, voltage); -} - -static int budget_set_tone(struct dvb_frontend *fe, - enum fe_sec_tone_mode tone) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - switch (tone) { - case SEC_TONE_ON: - Set22K (budget, 1); - break; - - case SEC_TONE_OFF: - Set22K (budget, 0); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); - - return 0; -} - -static int budget_diseqc_send_burst(struct dvb_frontend *fe, - enum fe_sec_mini_cmd minicmd) -{ - struct budget* budget = (struct budget*) fe->dvb->priv; - - SendDiSEqCMsg (budget, 0, NULL, minicmd); - - return 0; -} - -static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u8 pwr = 0; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - u32 div = (c->frequency + 479500) / 125; - - if (c->frequency > 2000000) - pwr = 3; - else if (c->frequency > 1800000) - pwr = 2; - else if (c->frequency > 1600000) - pwr = 1; - else if (c->frequency > 1200000) - pwr = 0; - else if (c->frequency >= 1100000) - pwr = 1; - else pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct ves1x93_config alps_bsrv2_config = -{ - .demod_address = 0x08, - .xin = 90100000UL, - .invert_pwm = 0, -}; - -static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = (c->frequency + 35937500 + 31250) / 62500; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x85 | ((div >> 10) & 0x60); - data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct ves1820_config alps_tdbe2_config = { - .demod_address = 0x09, - .xin = 57840000UL, - .invert = 1, - .selagc = VES1820_SELAGC_SIGNAMPERR, -}; - -static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget *budget = fe->dvb->priv; - u8 *tuner_addr = fe->tuner_priv; - u32 div; - u8 cfg, cpump, band_select; - u8 data[4]; - struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) }; - - if (tuner_addr) - msg.addr = *tuner_addr; - else - msg.addr = 0x61; - - div = (36125000 + c->frequency) / 166666; - - cfg = 0x88; - - if (c->frequency < 175000000) - cpump = 2; - else if (c->frequency < 390000000) - cpump = 1; - else if (c->frequency < 470000000) - cpump = 2; - else if (c->frequency < 750000000) - cpump = 1; - else - cpump = 3; - - if (c->frequency < 175000000) - band_select = 0x0e; - else if (c->frequency < 470000000) - band_select = 0x05; - else - band_select = 0x03; - - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = (cpump << 6) | band_select; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct l64781_config grundig_29504_401_config = { - .demod_address = 0x55, -}; - -static struct l64781_config grundig_29504_401_config_activy = { - .demod_address = 0x54, -}; - -static u8 tuner_address_grundig_29504_401_activy = 0x60; - -static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = c->frequency / 125; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0x8e; - data[3] = 0x00; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - return 0; -} - -static struct tda8083_config grundig_29504_451_config = { - .demod_address = 0x68, -}; - -static int s5h1420_tuner_set_params(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct budget* budget = (struct budget*) fe->dvb->priv; - u32 div; - u8 data[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; - - div = c->frequency / 1000; - data[0] = (div >> 8) & 0x7f; - data[1] = div & 0xff; - data[2] = 0xc2; - - if (div < 1450) - data[3] = 0x00; - else if (div < 1850) - data[3] = 0x40; - else if (div < 2000) - data[3] = 0x80; - else - data[3] = 0xc0; - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - - return 0; -} - -static struct s5h1420_config s5h1420_config = { - .demod_address = 0x53, - .invert = 1, - .cdclk_polarity = 1, -}; - -static struct tda10086_config tda10086_config = { - .demod_address = 0x0e, - .invert = 0, - .diseqc_tone = 1, - .xtal_freq = TDA10086_XTAL_16M, -}; - -static const struct stv0299_config alps_bsru6_config_activy = { - .demod_address = 0x68, - .inittab = alps_bsru6_inittab, - .mclk = 88000000UL, - .invert = 1, - .op0_off = 1, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsru6_set_symbol_rate, -}; - -static const struct stv0299_config alps_bsbe1_config_activy = { - .demod_address = 0x68, - .inittab = alps_bsbe1_inittab, - .mclk = 88000000UL, - .invert = 1, - .op0_off = 1, - .min_delay_ms = 100, - .set_symbol_rate = alps_bsbe1_set_symbol_rate, -}; - -static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) -{ - struct budget *budget = (struct budget *)fe->dvb->priv; - - return request_firmware(fw, name, &budget->dev->pci->dev); -} - - -static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) -{ - u8 val; - struct i2c_msg msg[] = { - { .addr = adr, .flags = 0, .buf = ®, .len = 1 }, - { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 } - }; - - return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val; -} - -static u8 read_pwm(struct budget* budget) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, - { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; - - if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - return pwm; -} - -static struct stv090x_config tt1600_stv090x_config = { - .device = STV0903, - .demod_mode = STV090x_SINGLE, - .clk_mode = STV090x_CLK_EXT, - - .xtal = 13500000, - .address = 0x68, - - .ts1_mode = STV090x_TSMODE_DVBCI, - .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, - - .repeater_level = STV090x_RPTLEVEL_16, - - .tuner_init = NULL, - .tuner_sleep = NULL, - .tuner_set_mode = NULL, - .tuner_set_frequency = NULL, - .tuner_get_frequency = NULL, - .tuner_set_bandwidth = NULL, - .tuner_get_bandwidth = NULL, - .tuner_set_bbgain = NULL, - .tuner_get_bbgain = NULL, - .tuner_set_refclk = NULL, - .tuner_get_status = NULL, -}; - -static struct stv6110x_config tt1600_stv6110x_config = { - .addr = 0x60, - .refclk = 27000000, - .clk_div = 2, -}; - -static struct isl6423_config tt1600_isl6423_config = { - .current_max = SEC_CURRENT_515m, - .curlim = SEC_CURRENT_LIM_ON, - .mod_extern = 1, - .addr = 0x08, -}; - -static void frontend_init(struct budget *budget) -{ - (void)alps_bsbe1_config; /* avoid warning */ - - switch(budget->dev->pci->subsystem_device) { - case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) - case 0x1013: - // try the ALPS BSRV2 first of all - budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - break; - } - - // try the ALPS BSRU6 now - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) { - budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops.set_tone = budget_set_tone; - } - break; - } - break; - - case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) - - budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; - break; - } - break; - - case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) - - budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - budget->dvb_frontend->tuner_priv = NULL; - break; - } - break; - - case 0x4f52: /* Cards based on Philips Semi Sylt PCI ref. design */ - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: tuner ALPS BSRU6 in Philips Semi. Sylt detected\n"); - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - break; - } - break; - - case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */ - { - int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67); - - if (subtype < 0) - break; - /* fixme: find a better way to identify the card */ - if (subtype < 0x36) { - /* assume ALPS BSRU6 */ - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n"); - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - break; - } - } else { - /* assume ALPS BSBE1 */ - /* reset tuner */ - saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI); - msleep(250); - budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n"); - budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - break; - } - } - break; - } - - case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522)) - budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; - budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; - } - break; - - case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ - budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; - budget->dvb_frontend->tuner_priv = &budget->i2c_adap; - } - break; - - case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ - budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); - if (budget->dvb_frontend) { - budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy; - budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; - } - break; - - case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) - { - struct dvb_frontend *fe; - - fe = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap); - if (fe) { - fe->ops.tuner_ops.set_params = s5h1420_tuner_set_params; - budget->dvb_frontend = fe; - if (dvb_attach(lnbp21_attach, fe, &budget->i2c_adap, - 0, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - goto error_out; - } - break; - } - } - fallthrough; - case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262) - { - struct dvb_frontend *fe; - - // gpio2 is connected to CLB - reset it + leave it high - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(1); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(1); - - fe = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap); - if (fe) { - budget->dvb_frontend = fe; - if (dvb_attach(tda826x_attach, fe, 0x60, - &budget->i2c_adap, 0) == NULL) - printk("%s: No tda826x found!\n", __func__); - if (dvb_attach(lnbp21_attach, fe, - &budget->i2c_adap, 0, 0) == NULL) { - printk("%s: No LNBP21 found!\n", __func__); - goto error_out; - } - break; - } - } - fallthrough; - - case 0x101c: { /* TT S2-1600 */ - const struct stv6110x_devctl *ctl; - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(250); - - budget->dvb_frontend = dvb_attach(stv090x_attach, - &tt1600_stv090x_config, - &budget->i2c_adap, - STV090x_DEMODULATOR_0); - - if (budget->dvb_frontend) { - - ctl = dvb_attach(stv6110x_attach, - budget->dvb_frontend, - &tt1600_stv6110x_config, - &budget->i2c_adap); - - if (ctl) { - tt1600_stv090x_config.tuner_init = ctl->tuner_init; - tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; - tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; - tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; - tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; - tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; - tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; - tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; - tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; - tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; - tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; - - /* call the init function once to initialize - tuner's clock output divider and demod's - master clock */ - if (budget->dvb_frontend->ops.init) - budget->dvb_frontend->ops.init(budget->dvb_frontend); - - if (dvb_attach(isl6423_attach, - budget->dvb_frontend, - &budget->i2c_adap, - &tt1600_isl6423_config) == NULL) { - printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__); - goto error_out; - } - } else { - printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); - goto error_out; - } - } - } - break; - - case 0x1020: { /* Omicom S2 */ - const struct stv6110x_devctl *ctl; - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); - msleep(50); - saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); - msleep(250); - - budget->dvb_frontend = dvb_attach(stv090x_attach, - &tt1600_stv090x_config, - &budget->i2c_adap, - STV090x_DEMODULATOR_0); - - if (budget->dvb_frontend) { - printk(KERN_INFO "budget: Omicom S2 detected\n"); - - ctl = dvb_attach(stv6110x_attach, - budget->dvb_frontend, - &tt1600_stv6110x_config, - &budget->i2c_adap); - - if (ctl) { - tt1600_stv090x_config.tuner_init = ctl->tuner_init; - tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; - tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; - tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; - tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; - tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; - tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; - tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; - tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; - tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; - tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; - - /* call the init function once to initialize - tuner's clock output divider and demod's - master clock */ - if (budget->dvb_frontend->ops.init) - budget->dvb_frontend->ops.init(budget->dvb_frontend); - - if (dvb_attach(lnbh24_attach, - budget->dvb_frontend, - &budget->i2c_adap, - LNBH24_PCL | LNBH24_TTX, - LNBH24_TEN, 0x14>>1) == NULL) { - printk(KERN_ERR - "No LNBH24 found!\n"); - goto error_out; - } - } else { - printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); - goto error_out; - } - } - } - break; - } - - if (budget->dvb_frontend == NULL) { - printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", - budget->dev->pci->vendor, - budget->dev->pci->device, - budget->dev->pci->subsystem_vendor, - budget->dev->pci->subsystem_device); - } else { - if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) - goto error_out; - } - return; - -error_out: - printk("budget: Frontend registration failed!\n"); - dvb_frontend_detach(budget->dvb_frontend); - budget->dvb_frontend = NULL; - return; -} - -static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) -{ - struct budget *budget = NULL; - int err; - - budget = kmalloc(sizeof(struct budget), GFP_KERNEL); - if( NULL == budget ) { - return -ENOMEM; - } - - dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget); - - dev->ext_priv = budget; - - err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); - if (err) { - printk("==> failed\n"); - kfree (budget); - return err; - } - - budget->dvb_adapter.priv = budget; - frontend_init(budget); - - ttpci_budget_init_hooks(budget); - - return 0; -} - -static int budget_detach (struct saa7146_dev* dev) -{ - struct budget *budget = (struct budget*) dev->ext_priv; - int err; - - if (budget->dvb_frontend) { - dvb_unregister_frontend(budget->dvb_frontend); - dvb_frontend_detach(budget->dvb_frontend); - } - - err = ttpci_budget_deinit (budget); - - kfree (budget); - dev->ext_priv = NULL; - - return err; -} - -static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); -MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); -MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); -MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); -MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT); -MAKE_BUDGET_INFO(sylt, "Philips Semi Sylt PCI", BUDGET_TT_HW_DISEQC); - -static const struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), - MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), - MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), - MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), - MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), - MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), - MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c), - MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), - MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), - MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), - MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), - MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020), - MAKE_EXTENSION_PCI(sylt, 0x1131, 0x4f52), - { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_extension budget_extension = { - .name = "budget dvb", - .flags = SAA7146_USE_I2C_IRQ, - - .module = THIS_MODULE, - .pci_tbl = pci_tbl, - .attach = budget_attach, - .detach = budget_detach, - - .irq_mask = MASK_10, - .irq_func = ttpci_budget_irq10_handler, -}; - -static int __init budget_init(void) -{ - return saa7146_register_extension(&budget_extension); -} - -static void __exit budget_exit(void) -{ - saa7146_unregister_extension(&budget_extension); -} - -module_init(budget_init); -module_exit(budget_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h deleted file mode 100644 index bd87432e6cde..000000000000 --- a/drivers/media/pci/ttpci/budget.h +++ /dev/null @@ -1,129 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#ifndef __BUDGET_DVB__ -#define __BUDGET_DVB__ - -#include <media/dvb_frontend.h> -#include <media/dvbdev.h> -#include <media/demux.h> -#include <media/dvb_demux.h> -#include <media/dmxdev.h> -#include <media/dvb_net.h> - -#include <linux/module.h> -#include <linux/mutex.h> - -#include <media/drv-intf/saa7146.h> - -extern int budget_debug; - -#ifdef dprintk -#undef dprintk -#endif - -#define dprintk(level, fmt, arg...) do { \ - if (level & budget_debug) \ - printk(KERN_DEBUG KBUILD_MODNAME ": %s(): " fmt, \ - __func__, ##arg); \ -} while (0) - -#define TS_SIZE 188 - -struct budget_info { - char *name; - int type; -}; - -/* place to store all the necessary device information */ -struct budget { - - /* devices */ - struct dvb_device dvb_dev; - struct dvb_net dvb_net; - - struct saa7146_dev *dev; - - struct i2c_adapter i2c_adap; - struct budget_info *card; - - unsigned char *grabbing; - struct saa7146_pgtable pt; - - struct tasklet_struct fidb_tasklet; - struct tasklet_struct vpe_tasklet; - - struct dmxdev dmxdev; - struct dvb_demux demux; - - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - - int ci_present; - int video_port; - - u32 buffer_width; - u32 buffer_height; - u32 buffer_size; - u32 buffer_warning_threshold; - u32 buffer_warnings; - unsigned long buffer_warning_time; - - u32 ttbp; - int feeding; - - spinlock_t feedlock; - - spinlock_t debilock; - - struct dvb_adapter dvb_adapter; - struct dvb_frontend *dvb_frontend; - int (*read_fe_status)(struct dvb_frontend *fe, enum fe_status *status); - int fe_synced; - - void *priv; -}; - -#define MAKE_BUDGET_INFO(x_var,x_name,x_type) \ -static struct budget_info x_var ## _info = { \ - .name=x_name, \ - .type=x_type }; \ -static struct saa7146_pci_extension_data x_var = { \ - .ext_priv = &x_var ## _info, \ - .ext = &budget_extension }; - -#define BUDGET_TT 0 -#define BUDGET_TT_HW_DISEQC 1 -#define BUDGET_PATCH 3 -#define BUDGET_FS_ACTIVY 4 -#define BUDGET_CIN1200S 5 -#define BUDGET_CIN1200C 6 -#define BUDGET_CIN1200T 7 -#define BUDGET_KNC1S 8 -#define BUDGET_KNC1C 9 -#define BUDGET_KNC1T 10 -#define BUDGET_KNC1SP 11 -#define BUDGET_KNC1CP 12 -#define BUDGET_KNC1TP 13 -#define BUDGET_TVSTAR 14 -#define BUDGET_CIN1200C_MK3 15 -#define BUDGET_KNC1C_MK3 16 -#define BUDGET_KNC1CP_MK3 17 -#define BUDGET_KNC1S2 18 -#define BUDGET_KNC1C_TDA10024 19 - -#define BUDGET_VIDEO_PORTA 0 -#define BUDGET_VIDEO_PORTB 1 - -extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, - struct saa7146_pci_extension_data *info, - struct module *owner, short *adapter_nums); -extern void ttpci_budget_init_hooks(struct budget *budget); -extern int ttpci_budget_deinit(struct budget *budget); -extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr); -extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port); -extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, - int uselocks, int nobusyloop); -extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value, - int uselocks, int nobusyloop); - -#endif diff --git a/drivers/media/pci/zoran/Kconfig b/drivers/media/pci/zoran/Kconfig new file mode 100644 index 000000000000..3fb3e27e04a8 --- /dev/null +++ b/drivers/media/pci/zoran/Kconfig @@ -0,0 +1,74 @@ +config VIDEO_ZORAN + tristate "Zoran ZR36057/36067 Video For Linux (Deprecated)" + depends on PCI && I2C_ALGOBIT && VIDEO_DEV + depends on !ALPHA + depends on DEBUG_FS + select VIDEOBUF2_DMA_CONTIG + select VIDEO_ADV7170 if VIDEO_ZORAN_LML33R10 + select VIDEO_ADV7175 if VIDEO_ZORAN_DC10 || VIDEO_ZORAN_DC30 + select VIDEO_BT819 if VIDEO_ZORAN_LML33 + select VIDEO_BT856 if VIDEO_ZORAN_LML33 || VIDEO_ZORAN_AVS6EYES + select VIDEO_BT866 if VIDEO_ZORAN_AVS6EYES + select VIDEO_KS0127 if VIDEO_ZORAN_AVS6EYES + select VIDEO_SAA711X if VIDEO_ZORAN_BUZ || VIDEO_ZORAN_LML33R10 + select VIDEO_SAA7110 if VIDEO_ZORAN_DC10 + select VIDEO_SAA7185 if VIDEO_ZORAN_BUZ + select VIDEO_VPX3220 if VIDEO_ZORAN_DC30 + help + Say Y for support for MJPEG capture cards based on the Zoran + 36057/36067 PCI controller chipset. This includes the Iomega + Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is + a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For + more information, check <file:Documentation/driver-api/media/drivers/zoran.rst>. + + To compile this driver as a module, choose M here: the + module will be called zr36067. + +config VIDEO_ZORAN_DC30 + bool "Pinnacle/Miro DC30(+) support" + depends on VIDEO_ZORAN + help + Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback + card. This also supports really old DC10 cards based on the + zr36050 MJPEG codec and zr36016 VFE. + +config VIDEO_ZORAN_ZR36060 + bool "Zoran ZR36060" + depends on VIDEO_ZORAN + help + Say Y to support Zoran boards based on 36060 chips. + This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 + and 33 R10 and AverMedia 6 boards. + +config VIDEO_ZORAN_BUZ + bool "Iomega Buz support" + depends on VIDEO_ZORAN_ZR36060 + help + Support for the Iomega Buz MJPEG capture/playback card. + +config VIDEO_ZORAN_DC10 + bool "Pinnacle/Miro DC10(+) support" + depends on VIDEO_ZORAN_ZR36060 + help + Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback + card. + +config VIDEO_ZORAN_LML33 + bool "Linux Media Labs LML33 support" + depends on VIDEO_ZORAN_ZR36060 + help + Support for the Linux Media Labs LML33 MJPEG capture/playback + card. + +config VIDEO_ZORAN_LML33R10 + bool "Linux Media Labs LML33R10 support" + depends on VIDEO_ZORAN_ZR36060 + help + support for the Linux Media Labs LML33R10 MJPEG capture/playback + card. + +config VIDEO_ZORAN_AVS6EYES + bool "AverMedia 6 Eyes support" + depends on VIDEO_ZORAN_ZR36060 + help + Support for the AverMedia 6 Eyes video surveillance card. diff --git a/drivers/media/pci/zoran/Makefile b/drivers/media/pci/zoran/Makefile new file mode 100644 index 000000000000..9603bac0195c --- /dev/null +++ b/drivers/media/pci/zoran/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +zr36067-objs := zoran_device.o \ + zoran_driver.o zoran_card.o videocodec.o + +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o +zr36067-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o +zr36067-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o diff --git a/drivers/media/pci/zoran/videocodec.c b/drivers/media/pci/zoran/videocodec.c new file mode 100644 index 000000000000..8efc5e06b0f7 --- /dev/null +++ b/drivers/media/pci/zoran/videocodec.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * VIDEO MOTION CODECs internal API for video devices + * + * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's + * bound to a master device. + * + * (c) 2002 Wolfgang Scherr <scherr@net4you.at> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/slab.h> + +#include "videocodec.h" + +struct attached_list { + struct videocodec *codec; + struct attached_list *next; +}; + +struct codec_list { + const struct videocodec *codec; + int attached; + struct attached_list *list; + struct codec_list *next; +}; + +static struct codec_list *codeclist_top; + +/* ================================================= */ +/* function prototypes of the master/slave interface */ +/* ================================================= */ + +struct videocodec *videocodec_attach(struct videocodec_master *master) +{ + struct codec_list *h = codeclist_top; + struct zoran *zr; + struct attached_list *a, *ptr; + struct videocodec *codec; + int res; + + if (!master) { + pr_err("%s: no data\n", __func__); + return NULL; + } + + zr = videocodec_master_to_zoran(master); + + zrdev_dbg(zr, "%s: '%s', flags %lx, magic %lx\n", __func__, + master->name, master->flags, master->magic); + + if (!h) { + zrdev_err(zr, "%s: no device available\n", __func__); + return NULL; + } + + while (h) { + // attach only if the slave has at least the flags + // expected by the master + if ((master->flags & h->codec->flags) == master->flags) { + zrdev_dbg(zr, "%s: try '%s'\n", __func__, h->codec->name); + + codec = kmemdup(h->codec, sizeof(struct videocodec), GFP_KERNEL); + if (!codec) + goto out_kfree; + + res = strlen(codec->name); + snprintf(codec->name + res, sizeof(codec->name) - res, "[%d]", h->attached); + codec->master_data = master; + res = codec->setup(codec); + if (res == 0) { + zrdev_dbg(zr, "%s: '%s'\n", __func__, codec->name); + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + if (!ptr) + goto out_kfree; + ptr->codec = codec; + + a = h->list; + if (!a) { + h->list = ptr; + zrdev_dbg(zr, "videocodec: first element\n"); + } else { + while (a->next) + a = a->next; // find end + a->next = ptr; + zrdev_dbg(zr, "videocodec: in after '%s'\n", + h->codec->name); + } + + h->attached += 1; + return codec; + } + kfree(codec); + } + h = h->next; + } + + zrdev_err(zr, "%s: no codec found!\n", __func__); + return NULL; + + out_kfree: + kfree(codec); + return NULL; +} + +int videocodec_detach(struct videocodec *codec) +{ + struct codec_list *h = codeclist_top; + struct zoran *zr; + struct attached_list *a, *prev; + int res; + + if (!codec) { + pr_err("%s: no data\n", __func__); + return -EINVAL; + } + + zr = videocodec_to_zoran(codec); + + zrdev_dbg(zr, "%s: '%s', type: %x, flags %lx, magic %lx\n", __func__, + codec->name, codec->type, codec->flags, codec->magic); + + if (!h) { + zrdev_err(zr, "%s: no device left...\n", __func__); + return -ENXIO; + } + + while (h) { + a = h->list; + prev = NULL; + while (a) { + if (codec == a->codec) { + res = a->codec->unset(a->codec); + if (res >= 0) { + zrdev_dbg(zr, "%s: '%s'\n", __func__, + a->codec->name); + a->codec->master_data = NULL; + } else { + zrdev_err(zr, "%s: '%s'\n", __func__, a->codec->name); + a->codec->master_data = NULL; + } + if (!prev) { + h->list = a->next; + zrdev_dbg(zr, "videocodec: delete first\n"); + } else { + prev->next = a->next; + zrdev_dbg(zr, "videocodec: delete middle\n"); + } + kfree(a->codec); + kfree(a); + h->attached -= 1; + return 0; + } + prev = a; + a = a->next; + } + h = h->next; + } + + zrdev_err(zr, "%s: given codec not found!\n", __func__); + return -EINVAL; +} + +int videocodec_register(const struct videocodec *codec) +{ + struct codec_list *ptr, *h = codeclist_top; + struct zoran *zr; + + if (!codec) { + pr_err("%s: no data!\n", __func__); + return -EINVAL; + } + + zr = videocodec_to_zoran((struct videocodec *)codec); + + zrdev_dbg(zr, + "videocodec: register '%s', type: %x, flags %lx, magic %lx\n", + codec->name, codec->type, codec->flags, codec->magic); + + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + ptr->codec = codec; + + if (!h) { + codeclist_top = ptr; + zrdev_dbg(zr, "videocodec: hooked in as first element\n"); + } else { + while (h->next) + h = h->next; // find the end + h->next = ptr; + zrdev_dbg(zr, "videocodec: hooked in after '%s'\n", + h->codec->name); + } + + return 0; +} + +int videocodec_unregister(const struct videocodec *codec) +{ + struct codec_list *prev = NULL, *h = codeclist_top; + struct zoran *zr; + + if (!codec) { + pr_err("%s: no data!\n", __func__); + return -EINVAL; + } + + zr = videocodec_to_zoran((struct videocodec *)codec); + + zrdev_dbg(zr, + "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n", + codec->name, codec->type, codec->flags, codec->magic); + + if (!h) { + zrdev_err(zr, "%s: no device left...\n", __func__); + return -ENXIO; + } + + while (h) { + if (codec == h->codec) { + if (h->attached) { + zrdev_err(zr, "videocodec: '%s' is used\n", + h->codec->name); + return -EBUSY; + } + zrdev_dbg(zr, "videocodec: unregister '%s' is ok.\n", + h->codec->name); + if (!prev) { + codeclist_top = h->next; + zrdev_dbg(zr, + "videocodec: delete first element\n"); + } else { + prev->next = h->next; + zrdev_dbg(zr, + "videocodec: delete middle element\n"); + } + kfree(h); + return 0; + } + prev = h; + h = h->next; + } + + zrdev_err(zr, "%s: given codec not found!\n", __func__); + return -EINVAL; +} + +int videocodec_debugfs_show(struct seq_file *m) +{ + struct codec_list *h = codeclist_top; + struct attached_list *a; + + seq_puts(m, "<S>lave or attached <M>aster name type flags magic "); + seq_puts(m, "(connected as)\n"); + + while (h) { + seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n", + h->codec->name, h->codec->type, + h->codec->flags, h->codec->magic); + a = h->list; + while (a) { + seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n", + a->codec->master_data->name, + a->codec->master_data->type, + a->codec->master_data->flags, + a->codec->master_data->magic, + a->codec->name); + a = a->next; + } + h = h->next; + } + + return 0; +} diff --git a/drivers/media/pci/zoran/videocodec.h b/drivers/media/pci/zoran/videocodec.h new file mode 100644 index 000000000000..6b69f69667f9 --- /dev/null +++ b/drivers/media/pci/zoran/videocodec.h @@ -0,0 +1,325 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * VIDEO MOTION CODECs internal API for video devices + * + * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's + * bound to a master device. + * + * (c) 2002 Wolfgang Scherr <scherr@net4you.at> + */ + +/* =================== */ +/* general description */ +/* =================== */ + +/* + * Should ease the (re-)usage of drivers supporting cards with (different) + * video codecs. The codecs register to this module their functionality, + * and the processors (masters) can attach to them if they fit. + * + * The codecs are typically have a "strong" binding to their master - so I + * don't think it makes sense to have a full blown interfacing as with e.g. + * i2c. If you have an other opinion, let's discuss & implement it :-))) + * + * Usage: + * + * The slave has just to setup the videocodec structure and use two functions: + * videocodec_register(codecdata); + * videocodec_unregister(codecdata); + * The best is just calling them at module (de-)initialisation. + * + * The master sets up the structure videocodec_master and calls: + * codecdata=videocodec_attach(master_codecdata); + * videocodec_detach(codecdata); + * + * The slave is called during attach/detach via functions setup previously + * during register. At that time, the master_data pointer is set up + * and the slave can access any io registers of the master device (in the case + * the slave is bound to it). Otherwise it doesn't need this functions and + * therefor they may not be initialized. + * + * The other functions are just for convenience, as they are for sure used by + * most/all of the codecs. The last ones may be omitted, too. + * + * See the structure declaration below for more information and which data has + * to be set up for the master and the slave. + * + * ---------------------------------------------------------------------------- + * The master should have "knowledge" of the slave and vice versa. So the data + * structures sent to/from slave via set_data/get_data set_image/get_image are + * device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!) + * ---------------------------------------------------------------------------- + */ + +/* ========================================== */ +/* description of the videocodec_io structure */ +/* ========================================== */ + +/* + * ==== master setup ==== + * name -> name of the device structure for reference and debugging + * master_data -> data ref. for the master (e.g. the zr36055,57,67) + * readreg -> ref. to read-fn from register (setup by master, used by slave) + * writereg -> ref. to write-fn to register (setup by master, used by slave) + * this two functions do the lowlevel I/O job + * + * ==== slave functionality setup ==== + * slave_data -> data ref. for the slave (e.g. the zr36050,60) + * check -> fn-ref. checks availability of an device, returns -EIO on failure or + * the type on success + * this makes espcecially sense if a driver module supports more than + * one codec which may be quite similar to access, nevertheless it + * is good for a first functionality check + * + * -- main functions you always need for compression/decompression -- + * + * set_mode -> this fn-ref. resets the entire codec, and sets up the mode + * with the last defined norm/size (or device default if not + * available) - it returns 0 if the mode is possible + * set_size -> this fn-ref. sets the norm and image size for + * compression/decompression (returns 0 on success) + * the norm param is defined in videodev2.h (V4L2_STD_*) + * + * additional setup may be available, too - but the codec should work with + * some default values even without this + * + * set_data -> sets device-specific data (tables, quality etc.) + * get_data -> query device-specific data (tables, quality etc.) + * + * if the device delivers interrupts, they may be setup/handled here + * setup_interrupt -> codec irq setup (not needed for 36050/60) + * handle_interrupt -> codec irq handling (not needed for 36050/60) + + * if the device delivers pictures, they may be handled here + * put_image -> puts image data to the codec (not needed for 36050/60) + * get_image -> gets image data from the codec (not needed for 36050/60) + * the calls include frame numbers and flags (even/odd/...) + * if needed and a flag which allows blocking until its ready + */ + +/* ============== */ +/* user interface */ +/* ============== */ + +/* + * Currently there is only a information display planned, as the layer + * is not visible for the user space at all. + * + * Information is available via procfs. The current entry is "/proc/videocodecs" + * but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--. + * + * A example for such an output is: + * + * <S>lave or attached <M>aster name type flags magic (connected as) + * S zr36050 0002 0000d001 00000000 (TEMPLATE) + * M zr36055[0] 0001 0000c001 00000000 (zr36050[0]) + * M zr36055[1] 0001 0000c001 00000000 (zr36050[1]) + */ + +/* =============================================== */ +/* special defines for the videocodec_io structure */ +/* =============================================== */ + +#ifndef __LINUX_VIDEOCODEC_H +#define __LINUX_VIDEOCODEC_H + +#include <linux/debugfs.h> +#include <linux/videodev2.h> + +#define CODEC_DO_COMPRESSION 0 +#define CODEC_DO_EXPANSION 1 + +/* this are the current codec flags I think they are needed */ +/* -> type value in structure */ +#define CODEC_FLAG_JPEG 0x00000001L // JPEG codec +#define CODEC_FLAG_MPEG 0x00000002L // MPEG1/2/4 codec +#define CODEC_FLAG_DIVX 0x00000004L // DIVX codec +#define CODEC_FLAG_WAVELET 0x00000008L // WAVELET codec + // room for other types + +#define CODEC_FLAG_MAGIC 0x00000800L // magic key must match +#define CODEC_FLAG_HARDWARE 0x00001000L // is a hardware codec +#define CODEC_FLAG_VFE 0x00002000L // has direct video frontend +#define CODEC_FLAG_ENCODER 0x00004000L // compression capability +#define CODEC_FLAG_DECODER 0x00008000L // decompression capability +#define CODEC_FLAG_NEEDIRQ 0x00010000L // needs irq handling +#define CODEC_FLAG_RDWRPIC 0x00020000L // handles picture I/O + +/* a list of modes, some are just examples (is there any HW?) */ +#define CODEC_MODE_BJPG 0x0001 // Baseline JPEG +#define CODEC_MODE_LJPG 0x0002 // Lossless JPEG +#define CODEC_MODE_MPEG1 0x0003 // MPEG 1 +#define CODEC_MODE_MPEG2 0x0004 // MPEG 2 +#define CODEC_MODE_MPEG4 0x0005 // MPEG 4 +#define CODEC_MODE_MSDIVX 0x0006 // MS DivX +#define CODEC_MODE_ODIVX 0x0007 // Open DivX +#define CODEC_MODE_WAVELET 0x0008 // Wavelet + +/* this are the current codec types I want to implement */ +/* -> type value in structure */ +#define CODEC_TYPE_NONE 0 +#define CODEC_TYPE_L64702 1 +#define CODEC_TYPE_ZR36050 2 +#define CODEC_TYPE_ZR36016 3 +#define CODEC_TYPE_ZR36060 4 + +/* the type of data may be enhanced by future implementations (data-fn.'s) */ +/* -> used in command */ +#define CODEC_G_STATUS 0x0000 /* codec status (query only) */ +#define CODEC_S_CODEC_MODE 0x0001 /* codec mode (baseline JPEG, MPEG1,... */ +#define CODEC_G_CODEC_MODE 0x8001 +#define CODEC_S_VFE 0x0002 /* additional video frontend setup */ +#define CODEC_G_VFE 0x8002 +#define CODEC_S_MMAP 0x0003 /* MMAP setup (if available) */ + +#define CODEC_S_JPEG_TDS_BYTE 0x0010 /* target data size in bytes */ +#define CODEC_G_JPEG_TDS_BYTE 0x8010 +#define CODEC_S_JPEG_SCALE 0x0011 /* scaling factor for quant. tables */ +#define CODEC_G_JPEG_SCALE 0x8011 +#define CODEC_S_JPEG_HDT_DATA 0x0018 /* huffman-tables */ +#define CODEC_G_JPEG_HDT_DATA 0x8018 +#define CODEC_S_JPEG_QDT_DATA 0x0019 /* quantizing-tables */ +#define CODEC_G_JPEG_QDT_DATA 0x8019 +#define CODEC_S_JPEG_APP_DATA 0x001A /* APP marker */ +#define CODEC_G_JPEG_APP_DATA 0x801A +#define CODEC_S_JPEG_COM_DATA 0x001B /* COM marker */ +#define CODEC_G_JPEG_COM_DATA 0x801B + +#define CODEC_S_PRIVATE 0x1000 /* "private" commands start here */ +#define CODEC_G_PRIVATE 0x9000 + +#define CODEC_G_FLAG 0x8000 /* this is how 'get' is detected */ + +/* types of transfer, directly user space or a kernel buffer (image-fn.'s) */ +/* -> used in get_image, put_image */ +#define CODEC_TRANSFER_KERNEL 0 /* use "memcopy" */ +#define CODEC_TRANSFER_USER 1 /* use "to/from_user" */ + +/* ========================= */ +/* the structures itself ... */ +/* ========================= */ + +struct vfe_polarity { + unsigned int vsync_pol:1; + unsigned int hsync_pol:1; + unsigned int field_pol:1; + unsigned int blank_pol:1; + unsigned int subimg_pol:1; + unsigned int poe_pol:1; + unsigned int pvalid_pol:1; + unsigned int vclk_pol:1; +}; + +struct vfe_settings { + __u32 x, y; /* Offsets into image */ + __u32 width, height; /* Area to capture */ + __u16 decimation; /* Decimation divider */ + __u16 flags; /* Flags for capture */ + __u16 quality; /* quality of the video */ +}; + +struct tvnorm { + u16 wt, wa, h_start, h_sync_start, ht, ha, v_start; +}; + +struct jpeg_com_marker { + int len; /* number of usable bytes in data */ + char data[60]; +}; + +struct jpeg_app_marker { + int appn; /* number app segment */ + int len; /* number of usable bytes in data */ + char data[60]; +}; + +struct videocodec { + /* -- filled in by slave device during register -- */ + char name[32]; + unsigned long magic; /* may be used for client<->master attaching */ + unsigned long flags; /* functionality flags */ + unsigned int type; /* codec type */ + + /* -- these is filled in later during master device attach -- */ + + struct videocodec_master *master_data; + + /* -- these are filled in by the slave device during register -- */ + + void *data; /* private slave data */ + + /* attach/detach client functions (indirect call) */ + int (*setup)(struct videocodec *codec); + int (*unset)(struct videocodec *codec); + + /* main functions, every client needs them for sure! */ + // set compression or decompression (or freeze, stop, standby, etc) + int (*set_mode)(struct videocodec *codec, int mode); + // setup picture size and norm (for the codec's video frontend) + int (*set_video)(struct videocodec *codec, const struct tvnorm *norm, + struct vfe_settings *cap, struct vfe_polarity *pol); + // other control commands, also mmap setup etc. + int (*control)(struct videocodec *codec, int type, int size, void *data); + + /* additional setup/query/processing (may be NULL pointer) */ + // interrupt setup / handling (for irq's delivered by master) + int (*setup_interrupt)(struct videocodec *codec, long mode); + int (*handle_interrupt)(struct videocodec *codec, int source, long flag); + // picture interface (if any) + long (*put_image)(struct videocodec *codec, int tr_type, int block, + long *fr_num, long *flag, long size, void *buf); + long (*get_image)(struct videocodec *codec, int tr_type, int block, + long *fr_num, long *flag, long size, void *buf); +}; + +struct videocodec_master { + /* -- filled in by master device for registration -- */ + char name[32]; + unsigned long magic; /* may be used for client<->master attaching */ + unsigned long flags; /* functionality flags */ + unsigned int type; /* master type */ + + void *data; /* private master data */ + + __u32 (*readreg)(struct videocodec *codec, __u16 reg); + void (*writereg)(struct videocodec *codec, __u16 reg, __u32 value); +}; + +/* ================================================= */ +/* function prototypes of the master/slave interface */ +/* ================================================= */ + +/* attach and detach commands for the master */ +// * master structure needs to be kmalloc'ed before calling attach +// and free'd after calling detach +// * returns pointer on success, NULL on failure +struct videocodec *videocodec_attach(struct videocodec_master *master); +// * 0 on success, <0 (errno) on failure +int videocodec_detach(struct videocodec *codec); + +/* register and unregister commands for the slaves */ +// * 0 on success, <0 (errno) on failure +int videocodec_register(const struct videocodec *codec); +// * 0 on success, <0 (errno) on failure +int videocodec_unregister(const struct videocodec *codec); + +/* the other calls are directly done via the videocodec structure! */ + +int videocodec_debugfs_show(struct seq_file *m); + +#include "zoran.h" +static inline struct zoran *videocodec_master_to_zoran(struct videocodec_master *master) +{ + struct zoran *zr = master->data; + + return zr; +} + +static inline struct zoran *videocodec_to_zoran(struct videocodec *codec) +{ + struct videocodec_master *master = codec->master_data; + + return videocodec_master_to_zoran(master); +} + +#endif /*ifndef __LINUX_VIDEOCODEC_H */ diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h new file mode 100644 index 000000000000..56340553b282 --- /dev/null +++ b/drivers/media/pci/zoran/zoran.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * zoran - Iomega Buz driver + * + * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> + * + * based on + * + * zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> + * + * and + * + * bttv - Bt848 frame grabber driver + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + * & Marcus Metzler (mocm@thp.uni-koeln.de) + */ + +#ifndef _BUZ_H_ +#define _BUZ_H_ + +#include <linux/debugfs.h> +#include <linux/pci.h> +#include <linux/i2c-algo-bit.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-v4l2.h> +#include <media/videobuf2-dma-contig.h> + +#define ZR_NORM_PAL 0 +#define ZR_NORM_NTSC 1 +#define ZR_NORM_SECAM 2 + +struct zr_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_v4l2_buffer vbuf; + struct list_head queue; +}; + +static inline struct zr_buffer *vb2_to_zr_buffer(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + return container_of(vbuf, struct zr_buffer, vbuf); +} + +#define ZORAN_NAME "ZORAN" /* name of the device */ + +#define ZR_DEVNAME(zr) ((zr)->name) + +#define BUZ_MAX_WIDTH (zr->timing->wa) +#define BUZ_MAX_HEIGHT (zr->timing->ha) +#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ +#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ + +#define BUZ_NUM_STAT_COM 4 +#define BUZ_MASK_STAT_COM 3 + +#define BUZ_MAX_INPUT 16 + +#include "zr36057.h" + +enum card_type { + UNKNOWN = -1, + + /* Pinnacle/Miro */ + DC10_OLD, /* DC30 like */ + DC10_NEW, /* DC10_PLUS like */ + DC10_PLUS, + DC30, + DC30_PLUS, + + /* Linux Media Labs */ + LML33, + LML33R10, + + /* Iomega */ + BUZ, + + /* AverMedia */ + AVS6EYES, + + /* total number of cards */ + NUM_CARDS +}; + +enum zoran_codec_mode { + BUZ_MODE_IDLE, /* nothing going on */ + BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ + BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ + BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ + BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ +}; + +enum zoran_map_mode { + ZORAN_MAP_MODE_NONE, + ZORAN_MAP_MODE_RAW, + ZORAN_MAP_MODE_JPG_REC, + ZORAN_MAP_MODE_JPG_PLAY, +}; + +enum gpio_type { + ZR_GPIO_JPEG_SLEEP = 0, + ZR_GPIO_JPEG_RESET, + ZR_GPIO_JPEG_FRAME, + ZR_GPIO_VID_DIR, + ZR_GPIO_VID_EN, + ZR_GPIO_VID_RESET, + ZR_GPIO_CLK_SEL1, + ZR_GPIO_CLK_SEL2, + ZR_GPIO_MAX, +}; + +enum gpcs_type { + GPCS_JPEG_RESET = 0, + GPCS_JPEG_START, + GPCS_MAX, +}; + +struct zoran_format { + char *name; + __u32 fourcc; + int colorspace; + int depth; + __u32 flags; + __u32 vfespfr; +}; + +/* flags */ +#define ZORAN_FORMAT_COMPRESSED BIT(0) +#define ZORAN_FORMAT_OVERLAY BIT(1) +#define ZORAN_FORMAT_CAPTURE BIT(2) +#define ZORAN_FORMAT_PLAYBACK BIT(3) + +/* v4l-capture settings */ +struct zoran_v4l_settings { + int width, height, bytesperline; /* capture size */ + const struct zoran_format *format; /* capture format */ +}; + +/* jpg-capture/-playback settings */ +struct zoran_jpg_settings { + /* this bit is used to set everything to default */ + int decimation; + /* capture decimation settings (tmp_dcm=1 means both fields) */ + int hor_dcm, ver_dcm, tmp_dcm; + /* field-settings (odd_even=1 (+tmp_dcm=1) means top-field-first) */ + int field_per_buff, odd_even; + /* crop settings (subframe capture) */ + int img_x, img_y, img_width, img_height; + /* JPEG-specific capture settings */ + struct v4l2_jpegcompression jpg_comp; +}; + +struct zoran; + +/* zoran_fh contains per-open() settings */ +struct zoran_fh { + struct v4l2_fh fh; + struct zoran *zr; +}; + +struct card_info { + enum card_type type; + char name[32]; + const char *i2c_decoder; /* i2c decoder device */ + const unsigned short *addrs_decoder; + const char *i2c_encoder; /* i2c encoder device */ + const unsigned short *addrs_encoder; + u16 video_vfe, video_codec; /* videocodec types */ + u16 audio_chip; /* audio type */ + + int inputs; /* number of video inputs */ + struct input { + int muxsel; + char name[32]; + } input[BUZ_MAX_INPUT]; + + v4l2_std_id norms; + const struct tvnorm *tvn[3]; /* supported TV norms */ + + u32 jpeg_int; /* JPEG interrupt */ + u32 vsync_int; /* VSYNC interrupt */ + s8 gpio[ZR_GPIO_MAX]; + u8 gpcs[GPCS_MAX]; + + struct vfe_polarity vfe_pol; + u8 gpio_pol[ZR_GPIO_MAX]; + + /* is the /GWS line connected? */ + u8 gws_not_connected; + + /* avs6eyes mux setting */ + u8 input_mux; + + void (*init)(struct zoran *zr); +}; + +struct zoran { + struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler hdl; + struct video_device *video_dev; + struct vb2_queue vq; + + struct i2c_adapter i2c_adapter; /* */ + struct i2c_algo_bit_data i2c_algo; /* */ + u32 i2cbr; + + struct v4l2_subdev *decoder; /* video decoder sub-device */ + struct v4l2_subdev *encoder; /* video encoder sub-device */ + + struct videocodec *codec; /* video codec */ + struct videocodec *vfe; /* video front end */ + + struct mutex lock; /* file ops serialize lock */ + + u8 initialized; /* flag if zoran has been correctly initialized */ + struct card_info card; + const struct tvnorm *timing; + + unsigned short id; /* number of this device */ + char name[32]; /* name of this device */ + struct pci_dev *pci_dev; /* PCI device */ + unsigned char revision; /* revision of zr36057 */ + unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */ + + spinlock_t spinlock; /* Spinlock */ + + /* Video for Linux parameters */ + int input; /* card's norm and input */ + v4l2_std_id norm; + + /* Current buffer params */ + unsigned int buffer_size; + + struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */ + + /* Buz MJPEG parameters */ + enum zoran_codec_mode codec_mode; /* status of codec */ + struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */ + + /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ + /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ + /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ + unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ + unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ + unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ + unsigned long jpg_que_tail; /* Index of last buffer in queue */ + unsigned long jpg_seq_num; /* count of frames since grab/play started */ + unsigned long jpg_err_seq; /* last seq_num before error */ + unsigned long jpg_err_shift; + unsigned long jpg_queued_num; /* count of frames queued since grab/play started */ + unsigned long vbseq; + + /* zr36057's code buffer table */ + /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + __le32 *stat_com; + + /* Additional stuff for testing */ + unsigned int ghost_int; + int intr_counter_GIRQ1; + int intr_counter_GIRQ0; + int intr_counter_cod_rep_irq; + int intr_counter_jpeg_rep_irq; + int field_counter; + int irq1_in; + int irq1_out; + int jpeg_in; + int jpeg_out; + int JPEG_0; + int JPEG_1; + int end_event_missed; + int jpeg_missed; + int jpeg_error; + int num_errors; + int jpeg_max_missed; + int jpeg_min_missed; + unsigned int prepared; + unsigned int queued; + + u32 last_isr; + unsigned long frame_num; + int running; + int buf_in_reserve; + + dma_addr_t p_sc; + __le32 *stat_comb; + dma_addr_t p_scb; + enum zoran_map_mode map_mode; + struct list_head queued_bufs; + spinlock_t queued_bufs_lock; /* Protects queued_bufs */ + struct zr_buffer *inuse[BUZ_NUM_STAT_COM * 2]; + struct dentry *dbgfs_dir; +}; + +static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct zoran, v4l2_dev); +} + +/* + * There was something called _ALPHA_BUZ that used the PCI address instead of + * the kernel iomapped address for btread/btwrite. + */ +#define btwrite(dat, adr) writel((dat), zr->zr36057_mem + (adr)) +#define btread(adr) readl(zr->zr36057_mem + (adr)) + +#define btand(dat, adr) btwrite((dat) & btread(adr), (adr)) +#define btor(dat, adr) btwrite((dat) | btread(adr), (adr)) +#define btaor(dat, mask, adr) btwrite((dat) | ((mask) & btread(adr)), (adr)) + +#endif + +/* + * Debugging macros + */ +#define zrdev_dbg(zr, format, args...) \ + pci_dbg((zr)->pci_dev, format, ##args) \ + +#define zrdev_err(zr, format, args...) \ + pci_err((zr)->pci_dev, format, ##args) \ + +#define zrdev_info(zr, format, args...) \ + pci_info((zr)->pci_dev, format, ##args) \ + +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir); +void zoran_queue_exit(struct zoran *zr); +int zr_set_buf(struct zoran *zr); diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c new file mode 100644 index 000000000000..3975fc1b2ee3 --- /dev/null +++ b/drivers/media/pci/zoran/zoran_card.c @@ -0,0 +1,1440 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zoran zr36057/zr36067 PCI controller driver, for the + * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux + * Media Labs LML33/LML33R10. + * + * This part handles card-specific data and detection + * + * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + */ + +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/videodev2.h> +#include <linux/spinlock.h> + +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <media/v4l2-common.h> +#include <media/i2c/bt819.h> + +#include "videocodec.h" +#include "zoran.h" +#include "zoran_card.h" +#include "zoran_device.h" +#include "zr36016.h" +#include "zr36050.h" +#include "zr36060.h" + +extern const struct zoran_format zoran_formats[]; + +static int card[BUZ_MAX] = { [0 ... (BUZ_MAX - 1)] = -1 }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "Card type"); + +/* Default input and video norm at startup of the driver. */ + +static unsigned int default_input; /* default 0 = Composite, 1 = S-Video */ +module_param(default_input, uint, 0444); +MODULE_PARM_DESC(default_input, + "Default input (0=Composite, 1=S-Video, 2=Internal)"); + +static int default_mux = 1; /* 6 Eyes input selection */ +module_param(default_mux, int, 0644); +MODULE_PARM_DESC(default_mux, + "Default 6 Eyes mux setting (Input selection)"); + +static int default_norm; /* default 0 = PAL, 1 = NTSC 2 = SECAM */ +module_param(default_norm, int, 0444); +MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)"); + +/* /dev/videoN, -1 for autodetect */ +static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX - 1)] = -1 }; +module_param_array(video_nr, int, NULL, 0444); +MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)"); + +/* 1=Pass through TV signal when device is not used */ +/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ +int pass_through; +module_param(pass_through, int, 0644); +MODULE_PARM_DESC(pass_through, + "Pass TV signal through to TV-out when idling"); + +int zr36067_debug = 1; +module_param_named(debug, zr36067_debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-5)"); + +#define ZORAN_VERSION "0.10.1" + +MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); +MODULE_AUTHOR("Serguei Miridonov"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(ZORAN_VERSION); + +#define ZR_DEVICE(subven, subdev, data) { \ + .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ + .subvendor = (subven), .subdevice = (subdev), .driver_data = (data) } + +static const struct pci_device_id zr36067_pci_tbl[] = { + ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10_PLUS), + ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC30PLUS, DC30_PLUS), + ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10), + ZR_DEVICE(PCI_VENDOR_ID_IOMEGA, PCI_DEVICE_ID_IOMEGA_BUZ, BUZ), + ZR_DEVICE(PCI_ANY_ID, PCI_ANY_ID, NUM_CARDS), + {0} +}; +MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); + +static unsigned int zoran_num; /* number of cards found */ + +/* videocodec bus functions ZR36060 */ +static u32 zr36060_read(struct videocodec *codec, u16 reg) +{ + struct zoran *zr = (struct zoran *)codec->master_data->data; + __u32 data; + + if (post_office_wait(zr) || post_office_write(zr, 0, 1, reg >> 8) || + post_office_write(zr, 0, 2, reg & 0xff)) + return -1; + + data = post_office_read(zr, 0, 3) & 0xff; + return data; +} + +static void zr36060_write(struct videocodec *codec, u16 reg, u32 val) +{ + struct zoran *zr = (struct zoran *)codec->master_data->data; + + if (post_office_wait(zr) || post_office_write(zr, 0, 1, reg >> 8) || + post_office_write(zr, 0, 2, reg & 0xff)) + return; + + post_office_write(zr, 0, 3, val & 0xff); +} + +/* videocodec bus functions ZR36050 */ +static u32 zr36050_read(struct videocodec *codec, u16 reg) +{ + struct zoran *zr = (struct zoran *)codec->master_data->data; + __u32 data; + + if (post_office_wait(zr) || post_office_write(zr, 1, 0, reg >> 2)) // reg. HIGHBYTES + return -1; + + data = post_office_read(zr, 0, reg & 0x03) & 0xff; // reg. LOWBYTES + read + return data; +} + +static void zr36050_write(struct videocodec *codec, u16 reg, u32 val) +{ + struct zoran *zr = (struct zoran *)codec->master_data->data; + + if (post_office_wait(zr) || post_office_write(zr, 1, 0, reg >> 2)) // reg. HIGHBYTES + return; + + post_office_write(zr, 0, reg & 0x03, val & 0xff); // reg. LOWBYTES + wr. data +} + +/* videocodec bus functions ZR36016 */ +static u32 zr36016_read(struct videocodec *codec, u16 reg) +{ + struct zoran *zr = (struct zoran *)codec->master_data->data; + __u32 data; + + if (post_office_wait(zr)) + return -1; + + data = post_office_read(zr, 2, reg & 0x03) & 0xff; // read + return data; +} + +/* hack for in zoran_device.c */ +void zr36016_write(struct videocodec *codec, u16 reg, u32 val) +{ + struct zoran *zr = (struct zoran *)codec->master_data->data; + + if (post_office_wait(zr)) + return; + + post_office_write(zr, 2, reg & 0x03, val & 0x0ff); // wr. data +} + +/* + * Board specific information + */ + +static void dc10_init(struct zoran *zr) +{ + /* Pixel clock selection */ + GPIO(zr, 4, 0); + GPIO(zr, 5, 1); + /* Enable the video bus sync signals */ + GPIO(zr, 7, 0); +} + +static void dc10plus_init(struct zoran *zr) +{ +} + +static void buz_init(struct zoran *zr) +{ + /* some stuff from Iomega */ + pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15); + pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020); + pci_write_config_dword(zr->pci_dev, 0xe8, 0xc0200000); +} + +static void lml33_init(struct zoran *zr) +{ + GPIO(zr, 2, 1); // Set Composite input/output +} + +static void avs6eyes_init(struct zoran *zr) +{ + // AverMedia 6-Eyes original driver by Christer Weinigel + + // Lifted straight from Christer's old driver and + // modified slightly by Martin Samuelsson. + + int mux = default_mux; /* 1 = BT866, 7 = VID1 */ + + GPIO(zr, 4, 1); /* Bt866 SLEEP on */ + udelay(2); + + GPIO(zr, 0, 1); /* ZR36060 /RESET on */ + GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */ + GPIO(zr, 2, mux & 1); /* MUX S0 */ + GPIO(zr, 3, 0); /* /FRAME on */ + GPIO(zr, 4, 0); /* Bt866 SLEEP off */ + GPIO(zr, 5, mux & 2); /* MUX S1 */ + GPIO(zr, 6, 0); /* ? */ + GPIO(zr, 7, mux & 4); /* MUX S2 */ +} + +static const char *codecid_to_modulename(u16 codecid) +{ + const char *name = NULL; + + switch (codecid) { + case CODEC_TYPE_ZR36060: + name = "zr36060"; + break; + case CODEC_TYPE_ZR36050: + name = "zr36050"; + break; + case CODEC_TYPE_ZR36016: + name = "zr36016"; + break; + } + + return name; +} + +static int codec_init(struct zoran *zr, u16 codecid) +{ + switch (codecid) { + case CODEC_TYPE_ZR36060: +#ifdef CONFIG_VIDEO_ZORAN_ZR36060 + return zr36060_init_module(); +#else + pci_err(zr->pci_dev, "ZR36060 support is not enabled\n"); + return -EINVAL; +#endif + break; + case CODEC_TYPE_ZR36050: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + return zr36050_init_module(); +#else + pci_err(zr->pci_dev, "ZR36050 support is not enabled\n"); + return -EINVAL; +#endif + break; + case CODEC_TYPE_ZR36016: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + return zr36016_init_module(); +#else + pci_err(zr->pci_dev, "ZR36016 support is not enabled\n"); + return -EINVAL; +#endif + break; + } + + pci_err(zr->pci_dev, "unknown codec id %x\n", codecid); + return -EINVAL; +} + +static void codec_exit(struct zoran *zr, u16 codecid) +{ + switch (codecid) { + case CODEC_TYPE_ZR36060: +#ifdef CONFIG_VIDEO_ZORAN_ZR36060 + zr36060_cleanup_module(); +#endif + break; + case CODEC_TYPE_ZR36050: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + zr36050_cleanup_module(); +#endif + break; + case CODEC_TYPE_ZR36016: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + zr36016_cleanup_module(); +#endif + break; + } +} + +static int videocodec_init(struct zoran *zr) +{ + const char *codec_name, *vfe_name; + int result; + + codec_name = codecid_to_modulename(zr->card.video_codec); + if (codec_name) { + result = codec_init(zr, zr->card.video_codec); + if (result < 0) { + pci_err(zr->pci_dev, "failed to load video codec %s: %d\n", + codec_name, result); + return result; + } + } + vfe_name = codecid_to_modulename(zr->card.video_vfe); + if (vfe_name) { + result = codec_init(zr, zr->card.video_vfe); + if (result < 0) { + pci_err(zr->pci_dev, "failed to load video vfe %s: %d\n", + vfe_name, result); + if (codec_name) + codec_exit(zr, zr->card.video_codec); + return result; + } + } + return 0; +} + +static void videocodec_exit(struct zoran *zr) +{ + if (zr->card.video_codec != CODEC_TYPE_NONE) + codec_exit(zr, zr->card.video_codec); + if (zr->card.video_vfe != CODEC_TYPE_NONE) + codec_exit(zr, zr->card.video_vfe); +} + +static const struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 }; +static const struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 }; +static const struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 }; +static const struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 }; + +static const struct tvnorm f50ccir601_lml33 = { 864, 720, 75 + 34, 804, 625, 576, 18 }; +static const struct tvnorm f60ccir601_lml33 = { 858, 720, 57 + 34, 788, 525, 480, 16 }; + +/* The DC10 (57/16/50) uses VActive as HSync, so h_start must be 0 */ +static const struct tvnorm f50sqpixel_dc10 = { 944, 768, 0, 880, 625, 576, 0 }; +static const struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 }; + +/* + * FIXME: I cannot swap U and V in saa7114, so i do one pixel left shift in zoran (75 -> 74) + * (Maxim Yevtyushkin <max@linuxmedialabs.com>) + */ +static const struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74 + 54, 804, 625, 576, 18 }; +static const struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56 + 54, 788, 525, 480, 16 }; + +/* + * FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I copy Maxim's left + * shift hack for the 6 Eyes. + * + * Christer's driver used the unshifted norms, though... + * /Sam + */ +static const struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 }; +static const struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 }; + +static const unsigned short vpx3220_addrs[] = { 0x43, 0x47, I2C_CLIENT_END }; +static const unsigned short saa7110_addrs[] = { 0x4e, 0x4f, I2C_CLIENT_END }; +static const unsigned short saa7111_addrs[] = { 0x25, 0x24, I2C_CLIENT_END }; +static const unsigned short saa7114_addrs[] = { 0x21, 0x20, I2C_CLIENT_END }; +static const unsigned short adv717x_addrs[] = { 0x6a, 0x6b, 0x2a, 0x2b, I2C_CLIENT_END }; +static const unsigned short ks0127_addrs[] = { 0x6c, 0x6d, I2C_CLIENT_END }; +static const unsigned short saa7185_addrs[] = { 0x44, I2C_CLIENT_END }; +static const unsigned short bt819_addrs[] = { 0x45, I2C_CLIENT_END }; +static const unsigned short bt856_addrs[] = { 0x44, I2C_CLIENT_END }; +static const unsigned short bt866_addrs[] = { 0x44, I2C_CLIENT_END }; + +static struct card_info zoran_cards[NUM_CARDS] = { + { + .type = DC10_OLD, + .name = "DC10(old)", + .i2c_decoder = "vpx3220a", + .addrs_decoder = vpx3220_addrs, + .video_codec = CODEC_TYPE_ZR36050, + .video_vfe = CODEC_TYPE_ZR36016, + + .inputs = 3, + .input = { + { 1, "Composite" }, + { 2, "S-Video" }, + { 0, "Internal/comp" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .tvn = { + &f50sqpixel_dc10, + &f60sqpixel_dc10, + &f50sqpixel_dc10 + }, + .jpeg_int = 0, + .vsync_int = ZR36057_ISR_GIRQ1, + .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, + .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, + .gpcs = { -1, 0 }, + .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .gws_not_connected = 0, + .input_mux = 0, + .init = &dc10_init, + }, { + .type = DC10_NEW, + .name = "DC10(new)", + .i2c_decoder = "saa7110", + .addrs_decoder = saa7110_addrs, + .i2c_encoder = "adv7175", + .addrs_encoder = adv717x_addrs, + .video_codec = CODEC_TYPE_ZR36060, + + .inputs = 3, + .input = { + { 0, "Composite" }, + { 7, "S-Video" }, + { 5, "Internal/comp" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .tvn = { + &f50sqpixel, + &f60sqpixel, + &f50sqpixel}, + .jpeg_int = ZR36057_ISR_GIRQ0, + .vsync_int = ZR36057_ISR_GIRQ1, + .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 }, + .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .gpcs = { -1, 1}, + .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 }, + .gws_not_connected = 0, + .input_mux = 0, + .init = &dc10plus_init, + }, { + .type = DC10_PLUS, + .name = "DC10_PLUS", + .i2c_decoder = "saa7110", + .addrs_decoder = saa7110_addrs, + .i2c_encoder = "adv7175", + .addrs_encoder = adv717x_addrs, + .video_codec = CODEC_TYPE_ZR36060, + + .inputs = 3, + .input = { + { 0, "Composite" }, + { 7, "S-Video" }, + { 5, "Internal/comp" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .tvn = { + &f50sqpixel, + &f60sqpixel, + &f50sqpixel + }, + .jpeg_int = ZR36057_ISR_GIRQ0, + .vsync_int = ZR36057_ISR_GIRQ1, + .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 }, + .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .gpcs = { -1, 1 }, + .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 }, + .gws_not_connected = 0, + .input_mux = 0, + .init = &dc10plus_init, + }, { + .type = DC30, + .name = "DC30", + .i2c_decoder = "vpx3220a", + .addrs_decoder = vpx3220_addrs, + .i2c_encoder = "adv7175", + .addrs_encoder = adv717x_addrs, + .video_codec = CODEC_TYPE_ZR36050, + .video_vfe = CODEC_TYPE_ZR36016, + + .inputs = 3, + .input = { + { 1, "Composite" }, + { 2, "S-Video" }, + { 0, "Internal/comp" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .tvn = { + &f50sqpixel_dc10, + &f60sqpixel_dc10, + &f50sqpixel_dc10 + }, + .jpeg_int = 0, + .vsync_int = ZR36057_ISR_GIRQ1, + .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, + .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, + .gpcs = { -1, 0 }, + .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .gws_not_connected = 0, + .input_mux = 0, + .init = &dc10_init, + }, { + .type = DC30_PLUS, + .name = "DC30_PLUS", + .i2c_decoder = "vpx3220a", + .addrs_decoder = vpx3220_addrs, + .i2c_encoder = "adv7175", + .addrs_encoder = adv717x_addrs, + .video_codec = CODEC_TYPE_ZR36050, + .video_vfe = CODEC_TYPE_ZR36016, + + .inputs = 3, + .input = { + { 1, "Composite" }, + { 2, "S-Video" }, + { 0, "Internal/comp" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .tvn = { + &f50sqpixel_dc10, + &f60sqpixel_dc10, + &f50sqpixel_dc10 + }, + .jpeg_int = 0, + .vsync_int = ZR36057_ISR_GIRQ1, + .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, + .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, + .gpcs = { -1, 0 }, + .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .gws_not_connected = 0, + .input_mux = 0, + .init = &dc10_init, + }, { + .type = LML33, + .name = "LML33", + .i2c_decoder = "bt819a", + .addrs_decoder = bt819_addrs, + .i2c_encoder = "bt856", + .addrs_encoder = bt856_addrs, + .video_codec = CODEC_TYPE_ZR36060, + + .inputs = 2, + .input = { + { 0, "Composite" }, + { 7, "S-Video" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL, + .tvn = { + &f50ccir601_lml33, + &f60ccir601_lml33, + NULL + }, + .jpeg_int = ZR36057_ISR_GIRQ1, + .vsync_int = ZR36057_ISR_GIRQ0, + .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 }, + .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 }, + .gpcs = { 3, 1 }, + .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, + .gws_not_connected = 1, + .input_mux = 0, + .init = &lml33_init, + }, { + .type = LML33R10, + .name = "LML33R10", + .i2c_decoder = "saa7114", + .addrs_decoder = saa7114_addrs, + .i2c_encoder = "adv7170", + .addrs_encoder = adv717x_addrs, + .video_codec = CODEC_TYPE_ZR36060, + + .inputs = 2, + .input = { + { 0, "Composite" }, + { 7, "S-Video" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL, + .tvn = { + &f50ccir601_lm33r10, + &f60ccir601_lm33r10, + NULL + }, + .jpeg_int = ZR36057_ISR_GIRQ1, + .vsync_int = ZR36057_ISR_GIRQ0, + .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 }, + .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 }, + .gpcs = { 3, 1 }, + .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, + .gws_not_connected = 1, + .input_mux = 0, + .init = &lml33_init, + }, { + .type = BUZ, + .name = "Buz", + .i2c_decoder = "saa7111", + .addrs_decoder = saa7111_addrs, + .i2c_encoder = "saa7185", + .addrs_encoder = saa7185_addrs, + .video_codec = CODEC_TYPE_ZR36060, + + .inputs = 2, + .input = { + { 3, "Composite" }, + { 7, "S-Video" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, + .tvn = { + &f50ccir601, + &f60ccir601, + &f50ccir601 + }, + .jpeg_int = ZR36057_ISR_GIRQ1, + .vsync_int = ZR36057_ISR_GIRQ0, + .gpio = { 1, -1, 3, -1, -1, -1, -1, -1 }, + .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, + .gpcs = { 3, 1 }, + .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, + .gws_not_connected = 1, + .input_mux = 0, + .init = &buz_init, + }, { + .type = AVS6EYES, + .name = "6-Eyes", + /* + * AverMedia chose not to brand the 6-Eyes. Thus it can't be + * autodetected, and requires card=x. + */ + .i2c_decoder = "ks0127", + .addrs_decoder = ks0127_addrs, + .i2c_encoder = "bt866", + .addrs_encoder = bt866_addrs, + .video_codec = CODEC_TYPE_ZR36060, + + .inputs = 10, + .input = { + { 0, "Composite 1" }, + { 1, "Composite 2" }, + { 2, "Composite 3" }, + { 4, "Composite 4" }, + { 5, "Composite 5" }, + { 6, "Composite 6" }, + { 8, "S-Video 1" }, + { 9, "S-Video 2" }, + {10, "S-Video 3" }, + {15, "YCbCr" } + }, + .norms = V4L2_STD_NTSC | V4L2_STD_PAL, + .tvn = { + &f50ccir601_avs6eyes, + &f60ccir601_avs6eyes, + NULL + }, + .jpeg_int = ZR36057_ISR_GIRQ1, + .vsync_int = ZR36057_ISR_GIRQ0, + .gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam + .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam + .gpcs = { 3, 1 }, // Validity unknown /Sam + .vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 }, // Validity unknown /Sam + .gws_not_connected = 1, + .input_mux = 1, + .init = &avs6eyes_init, + } + +}; + +/* + * I2C functions + */ +/* software I2C functions */ +static int zoran_i2c_getsda(void *data) +{ + struct zoran *zr = (struct zoran *)data; + + return (btread(ZR36057_I2CBR) >> 1) & 1; +} + +static int zoran_i2c_getscl(void *data) +{ + struct zoran *zr = (struct zoran *)data; + + return btread(ZR36057_I2CBR) & 1; +} + +static void zoran_i2c_setsda(void *data, int state) +{ + struct zoran *zr = (struct zoran *)data; + + if (state) + zr->i2cbr |= 2; + else + zr->i2cbr &= ~2; + btwrite(zr->i2cbr, ZR36057_I2CBR); +} + +static void zoran_i2c_setscl(void *data, int state) +{ + struct zoran *zr = (struct zoran *)data; + + if (state) + zr->i2cbr |= 1; + else + zr->i2cbr &= ~1; + btwrite(zr->i2cbr, ZR36057_I2CBR); +} + +static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = { + .setsda = zoran_i2c_setsda, + .setscl = zoran_i2c_setscl, + .getsda = zoran_i2c_getsda, + .getscl = zoran_i2c_getscl, + .udelay = 10, + .timeout = 100, +}; + +static int zoran_register_i2c(struct zoran *zr) +{ + zr->i2c_algo = zoran_i2c_bit_data_template; + zr->i2c_algo.data = zr; + strscpy(zr->i2c_adapter.name, ZR_DEVNAME(zr), + sizeof(zr->i2c_adapter.name)); + i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev); + zr->i2c_adapter.algo_data = &zr->i2c_algo; + zr->i2c_adapter.dev.parent = &zr->pci_dev->dev; + return i2c_bit_add_bus(&zr->i2c_adapter); +} + +static void zoran_unregister_i2c(struct zoran *zr) +{ + i2c_del_adapter(&zr->i2c_adapter); +} + +/* Check a zoran_params struct for correctness, insert default params */ +int zoran_check_jpg_settings(struct zoran *zr, + struct zoran_jpg_settings *settings, int try) +{ + int err = 0, err0 = 0; + + pci_dbg(zr->pci_dev, "%s - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n", + __func__, settings->decimation, settings->hor_dcm, + settings->ver_dcm, settings->tmp_dcm); + pci_dbg(zr->pci_dev, "%s - x: %d, y: %d, w: %d, y: %d\n", __func__, + settings->img_x, settings->img_y, + settings->img_width, settings->img_height); + /* Check decimation, set default values for decimation = 1, 2, 4 */ + switch (settings->decimation) { + case 1: + + settings->hor_dcm = 1; + settings->ver_dcm = 1; + settings->tmp_dcm = 1; + settings->field_per_buff = 2; + settings->img_x = 0; + settings->img_y = 0; + settings->img_width = BUZ_MAX_WIDTH; + settings->img_height = BUZ_MAX_HEIGHT / 2; + break; + case 2: + + settings->hor_dcm = 2; + settings->ver_dcm = 1; + settings->tmp_dcm = 2; + settings->field_per_buff = 1; + settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; + settings->img_y = 0; + settings->img_width = + (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; + settings->img_height = BUZ_MAX_HEIGHT / 2; + break; + case 4: + + if (zr->card.type == DC10_NEW) { + pci_dbg(zr->pci_dev, + "%s - HDec by 4 is not supported on the DC10\n", + __func__); + err0++; + break; + } + + settings->hor_dcm = 4; + settings->ver_dcm = 2; + settings->tmp_dcm = 2; + settings->field_per_buff = 1; + settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; + settings->img_y = 0; + settings->img_width = + (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; + settings->img_height = BUZ_MAX_HEIGHT / 2; + break; + case 0: + + /* We have to check the data the user has set */ + + if (settings->hor_dcm != 1 && settings->hor_dcm != 2 && + (zr->card.type == DC10_NEW || settings->hor_dcm != 4)) { + settings->hor_dcm = clamp(settings->hor_dcm, 1, 2); + err0++; + } + if (settings->ver_dcm != 1 && settings->ver_dcm != 2) { + settings->ver_dcm = clamp(settings->ver_dcm, 1, 2); + err0++; + } + if (settings->tmp_dcm != 1 && settings->tmp_dcm != 2) { + settings->tmp_dcm = clamp(settings->tmp_dcm, 1, 2); + err0++; + } + if (settings->field_per_buff != 1 && + settings->field_per_buff != 2) { + settings->field_per_buff = clamp(settings->field_per_buff, 1, 2); + err0++; + } + if (settings->img_x < 0) { + settings->img_x = 0; + err0++; + } + if (settings->img_y < 0) { + settings->img_y = 0; + err0++; + } + if (settings->img_width < 0 || settings->img_width > BUZ_MAX_WIDTH) { + settings->img_width = clamp(settings->img_width, 0, (int)BUZ_MAX_WIDTH); + err0++; + } + if (settings->img_height < 0 || settings->img_height > BUZ_MAX_HEIGHT / 2) { + settings->img_height = clamp(settings->img_height, 0, BUZ_MAX_HEIGHT / 2); + err0++; + } + if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH) { + settings->img_x = BUZ_MAX_WIDTH - settings->img_width; + err0++; + } + if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2) { + settings->img_y = BUZ_MAX_HEIGHT / 2 - settings->img_height; + err0++; + } + if (settings->img_width % (16 * settings->hor_dcm) != 0) { + settings->img_width -= settings->img_width % (16 * settings->hor_dcm); + if (settings->img_width == 0) + settings->img_width = 16 * settings->hor_dcm; + err0++; + } + if (settings->img_height % (8 * settings->ver_dcm) != 0) { + settings->img_height -= settings->img_height % (8 * settings->ver_dcm); + if (settings->img_height == 0) + settings->img_height = 8 * settings->ver_dcm; + err0++; + } + + if (!try && err0) { + pci_err(zr->pci_dev, "%s - error in params for decimation = 0\n", __func__); + err++; + } + break; + default: + pci_err(zr->pci_dev, "%s - decimation = %d, must be 0, 1, 2 or 4\n", + __func__, settings->decimation); + err++; + break; + } + + if (settings->jpg_comp.quality > 100) + settings->jpg_comp.quality = 100; + if (settings->jpg_comp.quality < 5) + settings->jpg_comp.quality = 5; + if (settings->jpg_comp.APPn < 0) + settings->jpg_comp.APPn = 0; + if (settings->jpg_comp.APPn > 15) + settings->jpg_comp.APPn = 15; + if (settings->jpg_comp.APP_len < 0) + settings->jpg_comp.APP_len = 0; + if (settings->jpg_comp.APP_len > 60) + settings->jpg_comp.APP_len = 60; + if (settings->jpg_comp.COM_len < 0) + settings->jpg_comp.COM_len = 0; + if (settings->jpg_comp.COM_len > 60) + settings->jpg_comp.COM_len = 60; + if (err) + return -EINVAL; + return 0; +} + +static int zoran_init_video_device(struct zoran *zr, struct video_device *video_dev, int dir) +{ + int err; + + /* Now add the template and register the device unit. */ + *video_dev = zoran_template; + video_dev->v4l2_dev = &zr->v4l2_dev; + video_dev->lock = &zr->lock; + video_dev->device_caps = V4L2_CAP_STREAMING | dir; + + strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); + video_dev->vfl_dir = VFL_DIR_RX; + zoran_queue_init(zr, &zr->vq, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + err = video_register_device(video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); + if (err < 0) + return err; + video_set_drvdata(video_dev, zr); + return 0; +} + +static void zoran_exit_video_devices(struct zoran *zr) +{ + video_unregister_device(zr->video_dev); + kfree(zr->video_dev); +} + +static int zoran_init_video_devices(struct zoran *zr) +{ + int err; + + zr->video_dev = video_device_alloc(); + if (!zr->video_dev) + return -ENOMEM; + + err = zoran_init_video_device(zr, zr->video_dev, V4L2_CAP_VIDEO_CAPTURE); + if (err) + kfree(zr->video_dev); + return err; +} + +/* + * v4l2_device_unregister() will care about removing zr->encoder/zr->decoder + * via v4l2_i2c_subdev_unregister() + */ +static int zoran_i2c_init(struct zoran *zr) +{ + int err; + + pci_info(zr->pci_dev, "Initializing i2c bus...\n"); + + err = zoran_register_i2c(zr); + if (err) { + pci_err(zr->pci_dev, "%s - cannot initialize i2c bus\n", __func__); + return err; + } + + zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, &zr->i2c_adapter, + zr->card.i2c_decoder, 0, + zr->card.addrs_decoder); + if (!zr->decoder) { + pci_err(zr->pci_dev, "Fail to get decoder %s\n", zr->card.i2c_decoder); + err = -EINVAL; + goto error_decoder; + } + + if (zr->card.i2c_encoder) { + zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, &zr->i2c_adapter, + zr->card.i2c_encoder, 0, + zr->card.addrs_encoder); + if (!zr->encoder) { + pci_err(zr->pci_dev, "Fail to get encoder %s\n", zr->card.i2c_encoder); + err = -EINVAL; + goto error_decoder; + } + } + return 0; + +error_decoder: + zoran_unregister_i2c(zr); + return err; +} + +static void zoran_i2c_exit(struct zoran *zr) +{ + zoran_unregister_i2c(zr); +} + +void zoran_open_init_params(struct zoran *zr) +{ + int i; + + zr->v4l_settings.width = 192; + zr->v4l_settings.height = 144; + zr->v4l_settings.format = &zoran_formats[7]; /* YUY2 - YUV-4:2:2 packed */ + zr->v4l_settings.bytesperline = zr->v4l_settings.width * + ((zr->v4l_settings.format->depth + 7) / 8); + + /* Set necessary params and call zoran_check_jpg_settings to set the defaults */ + zr->jpg_settings.decimation = 1; + zr->jpg_settings.jpg_comp.quality = 50; /* default compression factor 8 */ + if (zr->card.type != BUZ) + zr->jpg_settings.odd_even = 1; + else + zr->jpg_settings.odd_even = 0; + zr->jpg_settings.jpg_comp.APPn = 0; + zr->jpg_settings.jpg_comp.APP_len = 0; /* No APPn marker */ + memset(zr->jpg_settings.jpg_comp.APP_data, 0, + sizeof(zr->jpg_settings.jpg_comp.APP_data)); + zr->jpg_settings.jpg_comp.COM_len = 0; /* No COM marker */ + memset(zr->jpg_settings.jpg_comp.COM_data, 0, + sizeof(zr->jpg_settings.jpg_comp.COM_data)); + zr->jpg_settings.jpg_comp.jpeg_markers = + V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT; + i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0); + if (i) + pci_err(zr->pci_dev, "%s internal error\n", __func__); + + zr->buffer_size = zr->v4l_settings.bytesperline * zr->v4l_settings.height; + + clear_interrupt_counters(zr); +} + +static int zr36057_init(struct zoran *zr) +{ + int j, err; + + pci_info(zr->pci_dev, "initializing card[%d]\n", zr->id); + + /* Avoid nonsense settings from user for default input/norm */ + if (default_norm < 0 || default_norm > 2) + default_norm = 0; + if (default_norm == 0) { + zr->norm = V4L2_STD_PAL; + zr->timing = zr->card.tvn[ZR_NORM_PAL]; + } else if (default_norm == 1) { + zr->norm = V4L2_STD_NTSC; + zr->timing = zr->card.tvn[ZR_NORM_NTSC]; + } else { + zr->norm = V4L2_STD_SECAM; + zr->timing = zr->card.tvn[ZR_NORM_SECAM]; + } + if (!zr->timing) { + pci_warn(zr->pci_dev, + "%s - default TV standard not supported by hardware. PAL will be used.\n", + __func__); + zr->norm = V4L2_STD_PAL; + zr->timing = zr->card.tvn[ZR_NORM_PAL]; + } + + if (default_input > zr->card.inputs - 1) { + pci_warn(zr->pci_dev, "default_input value %d out of range (0-%d)\n", + default_input, zr->card.inputs - 1); + default_input = 0; + } + zr->input = default_input; + + /* default setup (will be repeated at every open) */ + zoran_open_init_params(zr); + + /* allocate memory *before* doing anything to the hardware in case allocation fails */ + zr->stat_com = dma_alloc_coherent(&zr->pci_dev->dev, + BUZ_NUM_STAT_COM * sizeof(u32), + &zr->p_sc, GFP_KERNEL); + if (!zr->stat_com) + return -ENOMEM; + + for (j = 0; j < BUZ_NUM_STAT_COM; j++) + zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ + + zr->stat_comb = dma_alloc_coherent(&zr->pci_dev->dev, + BUZ_NUM_STAT_COM * sizeof(u32) * 2, + &zr->p_scb, GFP_KERNEL); + if (!zr->stat_comb) { + err = -ENOMEM; + goto exit_statcom; + } + + err = zoran_init_video_devices(zr); + if (err) + goto exit_statcomb; + + zoran_init_hardware(zr); + if (!pass_through) { + decoder_call(zr, video, s_stream, 0); + encoder_call(zr, video, s_routing, 2, 0, 0); + } + + zr->initialized = 1; + return 0; + +exit_statcomb: + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, + zr->stat_comb, zr->p_scb); +exit_statcom: + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), + zr->stat_com, zr->p_sc); + return err; +} + +static void zoran_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct zoran *zr = to_zoran(v4l2_dev); + + if (!zr->initialized) + goto exit_free; + + debugfs_remove_recursive(zr->dbgfs_dir); + + zoran_queue_exit(zr); + + /* unregister videocodec bus */ + if (zr->codec) + videocodec_detach(zr->codec); + if (zr->vfe) + videocodec_detach(zr->vfe); + videocodec_exit(zr); + + /* unregister i2c bus */ + zoran_i2c_exit(zr); + /* disable PCI bus-mastering */ + zoran_set_pci_master(zr, 0); + /* put chip into reset */ + btwrite(0, ZR36057_SPGPPCR); + pci_free_irq(zr->pci_dev, 0, zr); + /* unmap and free memory */ + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), + zr->stat_com, zr->p_sc); + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, + zr->stat_comb, zr->p_scb); + pci_release_regions(pdev); + pci_disable_device(zr->pci_dev); + zoran_exit_video_devices(zr); +exit_free: + v4l2_ctrl_handler_free(&zr->hdl); + v4l2_device_unregister(&zr->v4l2_dev); +} + +void zoran_vdev_release(struct video_device *vdev) +{ + kfree(vdev); +} + +static struct videocodec_master *zoran_setup_videocodec(struct zoran *zr, + int type) +{ + struct videocodec_master *m = NULL; + + m = devm_kmalloc(&zr->pci_dev->dev, sizeof(*m), GFP_KERNEL); + if (!m) + return m; + + /* + * magic and type are unused for master struct. Makes sense only at codec structs. + * In the past, .type were initialized to the old V4L1 .hardware value, + * as VID_HARDWARE_ZR36067 + */ + m->magic = 0L; + m->type = 0; + + m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER; + strscpy(m->name, ZR_DEVNAME(zr), sizeof(m->name)); + m->data = zr; + + switch (type) { + case CODEC_TYPE_ZR36060: + m->readreg = zr36060_read; + m->writereg = zr36060_write; + m->flags |= CODEC_FLAG_JPEG | CODEC_FLAG_VFE; + break; + case CODEC_TYPE_ZR36050: + m->readreg = zr36050_read; + m->writereg = zr36050_write; + m->flags |= CODEC_FLAG_JPEG; + break; + case CODEC_TYPE_ZR36016: + m->readreg = zr36016_read; + m->writereg = zr36016_write; + m->flags |= CODEC_FLAG_VFE; + break; + } + + return m; +} + +static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct zoran *zr = to_zoran(sd->v4l2_dev); + + /* + * Bt819 needs to reset its FIFO buffer using #FRST pin and + * LML33 card uses GPIO(7) for that. + */ + if (cmd == BT819_FIFO_RESET_LOW) + GPIO(zr, 7, 0); + else if (cmd == BT819_FIFO_RESET_HIGH) + GPIO(zr, 7, 1); +} + +static int zoran_video_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct zoran *zr = container_of(ctrl->handler, struct zoran, hdl); + + switch (ctrl->id) { + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + zr->jpg_settings.jpg_comp.quality = ctrl->val; + return zoran_check_jpg_settings(zr, &zr->jpg_settings, 0); + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops zoran_video_ctrl_ops = { + .s_ctrl = zoran_video_set_ctrl, +}; + +static int zoran_debugfs_show(struct seq_file *seq, void *v) +{ + struct zoran *zr = seq->private; + + seq_printf(seq, "Running mode %x\n", zr->running); + seq_printf(seq, "Codec mode %x\n", zr->codec_mode); + seq_printf(seq, "Norm %llx\n", zr->norm); + seq_printf(seq, "Input %d\n", zr->input); + seq_printf(seq, "Buffersize %d\n", zr->buffer_size); + + seq_printf(seq, "V4L width %dx%d\n", zr->v4l_settings.width, zr->v4l_settings.height); + seq_printf(seq, "V4L bytesperline %d\n", zr->v4l_settings.bytesperline); + + seq_printf(seq, "JPG decimation %u\n", zr->jpg_settings.decimation); + seq_printf(seq, "JPG hor_dcm %u\n", zr->jpg_settings.hor_dcm); + seq_printf(seq, "JPG ver_dcm %u\n", zr->jpg_settings.ver_dcm); + seq_printf(seq, "JPG tmp_dcm %u\n", zr->jpg_settings.tmp_dcm); + seq_printf(seq, "JPG odd_even %u\n", zr->jpg_settings.odd_even); + seq_printf(seq, "JPG crop %dx%d %d %d\n", + zr->jpg_settings.img_x, + zr->jpg_settings.img_y, + zr->jpg_settings.img_width, + zr->jpg_settings.img_height); + + seq_printf(seq, "Prepared %u\n", zr->prepared); + seq_printf(seq, "Queued %u\n", zr->queued); + + videocodec_debugfs_show(seq); + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(zoran_debugfs); + +/* + * Scan for a Buz card (actually for the PCI controller ZR36057), + * request the irq and map the io memory + */ +static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + unsigned char latency, need_latency; + struct zoran *zr; + int result; + struct videocodec_master *master_vfe = NULL; + struct videocodec_master *master_codec = NULL; + int card_num; + unsigned int nr; + int err; + + pci_info(pdev, "Zoran MJPEG board driver version %s\n", ZORAN_VERSION); + + /* some mainboards might not do PCI-PCI data transfer well */ + if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) + pci_warn(pdev, "%s: chipset does not support reliable PCI-PCI DMA\n", + ZORAN_NAME); + + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + return err; + err = vb2_dma_contig_set_max_seg_size(&pdev->dev, U32_MAX); + if (err) + return err; + + nr = zoran_num++; + if (nr >= BUZ_MAX) { + pci_err(pdev, "driver limited to %d card(s) maximum\n", BUZ_MAX); + return -ENOENT; + } + + zr = devm_kzalloc(&pdev->dev, sizeof(*zr), GFP_KERNEL); + if (!zr) + return -ENOMEM; + + zr->v4l2_dev.notify = zoran_subdev_notify; + if (v4l2_device_register(&pdev->dev, &zr->v4l2_dev)) + goto zr_free_mem; + zr->pci_dev = pdev; + zr->id = nr; + snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id); + if (v4l2_ctrl_handler_init(&zr->hdl, 10)) + goto zr_unreg; + zr->v4l2_dev.ctrl_handler = &zr->hdl; + v4l2_ctrl_new_std(&zr->hdl, &zoran_video_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, + 100, 1, 50); + spin_lock_init(&zr->spinlock); + mutex_init(&zr->lock); + if (pci_enable_device(pdev)) + goto zr_unreg; + zr->revision = zr->pci_dev->revision; + + pci_info(zr->pci_dev, "Zoran ZR360%c7 (rev %d), irq: %d, memory: 0x%08llx\n", + zr->revision < 2 ? '5' : '6', zr->revision, + zr->pci_dev->irq, (uint64_t)pci_resource_start(zr->pci_dev, 0)); + if (zr->revision >= 2) + pci_info(zr->pci_dev, "Subsystem vendor=0x%04x id=0x%04x\n", + zr->pci_dev->subsystem_vendor, zr->pci_dev->subsystem_device); + + /* Use auto-detected card type? */ + if (card[nr] == -1) { + if (zr->revision < 2) { + pci_err(pdev, "No card type specified, please use the card=X module parameter\n"); + pci_err(pdev, "It is not possible to auto-detect ZR36057 based cards\n"); + goto zr_unreg; + } + + card_num = ent->driver_data; + if (card_num >= NUM_CARDS) { + pci_err(pdev, "Unknown card, try specifying card=X module parameter\n"); + goto zr_unreg; + } + pci_info(zr->pci_dev, "%s() - card %s detected\n", __func__, + zoran_cards[card_num].name); + } else { + card_num = card[nr]; + if (card_num >= NUM_CARDS || card_num < 0) { + pci_err(pdev, "User specified card type %d out of range (0 .. %d)\n", + card_num, NUM_CARDS - 1); + goto zr_unreg; + } + } + + /* + * even though we make this a non pointer and thus + * theoretically allow for making changes to this struct + * on a per-individual card basis at runtime, this is + * strongly discouraged. This structure is intended to + * keep general card information, no settings or anything + */ + zr->card = zoran_cards[card_num]; + snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "%s[%u]", + zr->card.name, zr->id); + + err = pci_request_regions(pdev, ZR_DEVNAME(zr)); + if (err) + goto zr_unreg; + + zr->zr36057_mem = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!zr->zr36057_mem) { + pci_err(pdev, "%s() - ioremap failed\n", __func__); + goto zr_pci_release; + } + + result = pci_request_irq(pdev, 0, zoran_irq, NULL, zr, ZR_DEVNAME(zr)); + if (result < 0) { + if (result == -EINVAL) { + pci_err(pdev, "%s - bad IRQ number or handler\n", __func__); + } else if (result == -EBUSY) { + pci_err(pdev, "%s - IRQ %d busy, change your PnP config in BIOS\n", + __func__, zr->pci_dev->irq); + } else { + pci_err(pdev, "%s - cannot assign IRQ, error code %d\n", __func__, result); + } + goto zr_pci_release; + } + + /* set PCI latency timer */ + pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, + &latency); + need_latency = zr->revision > 1 ? 32 : 48; + if (latency != need_latency) { + pci_info(zr->pci_dev, "Changing PCI latency from %d to %d\n", + latency, need_latency); + pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, need_latency); + } + + zr36057_restart(zr); + + err = zoran_i2c_init(zr); + if (err) + goto zr_free_irq; + + pci_info(zr->pci_dev, "Initializing videocodec bus...\n"); + err = videocodec_init(zr); + if (err) + goto zr_unreg_i2c; + + /* reset JPEG codec */ + jpeg_codec_sleep(zr, 1); + jpeg_codec_reset(zr); + /* video bus enabled */ + /* display codec revision */ + if (zr->card.video_codec != 0) { + master_codec = zoran_setup_videocodec(zr, zr->card.video_codec); + if (!master_codec) + goto zr_unreg_videocodec; + zr->codec = videocodec_attach(master_codec); + if (!zr->codec) { + pci_err(pdev, "%s - no codec found\n", __func__); + goto zr_unreg_videocodec; + } + if (zr->codec->type != zr->card.video_codec) { + pci_err(pdev, "%s - wrong codec\n", __func__); + goto zr_unreg_videocodec; + } + } + if (zr->card.video_vfe != 0) { + master_vfe = zoran_setup_videocodec(zr, zr->card.video_vfe); + if (!master_vfe) + goto zr_detach_codec; + zr->vfe = videocodec_attach(master_vfe); + if (!zr->vfe) { + pci_err(pdev, "%s - no VFE found\n", __func__); + goto zr_detach_codec; + } + if (zr->vfe->type != zr->card.video_vfe) { + pci_err(pdev, "%s = wrong VFE\n", __func__); + goto zr_detach_vfe; + } + } + + /* take care of Natoma chipset and a revision 1 zr36057 */ + if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) + pci_info(zr->pci_dev, "ZR36057/Natoma bug, max. buffer size is 128K\n"); + + if (zr36057_init(zr) < 0) + goto zr_detach_vfe; + + zr->map_mode = ZORAN_MAP_MODE_RAW; + + zr->dbgfs_dir = debugfs_create_dir(ZR_DEVNAME(zr), NULL); + debugfs_create_file("debug", 0444, zr->dbgfs_dir, zr, + &zoran_debugfs_fops); + return 0; + +zr_detach_vfe: + videocodec_detach(zr->vfe); +zr_detach_codec: + videocodec_detach(zr->codec); +zr_unreg_videocodec: + videocodec_exit(zr); +zr_unreg_i2c: + zoran_i2c_exit(zr); +zr_free_irq: + btwrite(0, ZR36057_SPGPPCR); + pci_free_irq(zr->pci_dev, 0, zr); +zr_pci_release: + pci_release_regions(pdev); +zr_unreg: + v4l2_ctrl_handler_free(&zr->hdl); + v4l2_device_unregister(&zr->v4l2_dev); +zr_free_mem: + + return -ENODEV; +} + +static struct pci_driver zoran_driver = { + .name = "zr36067", + .id_table = zr36067_pci_tbl, + .probe = zoran_probe, + .remove = zoran_remove, +}; + +module_pci_driver(zoran_driver); diff --git a/drivers/media/pci/zoran/zoran_card.h b/drivers/media/pci/zoran/zoran_card.h new file mode 100644 index 000000000000..518cb426b446 --- /dev/null +++ b/drivers/media/pci/zoran/zoran_card.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Zoran zr36057/zr36067 PCI controller driver, for the + * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux + * Media Labs LML33/LML33R10. + * + * This part handles card-specific data and detection + * + * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + */ + +#ifndef __ZORAN_CARD_H__ +#define __ZORAN_CARD_H__ + +extern int zr36067_debug; + +/* Anybody who uses more than four? */ +#define BUZ_MAX 4 + +extern const struct video_device zoran_template; + +int zoran_check_jpg_settings(struct zoran *zr, + struct zoran_jpg_settings *settings, int try); +void zoran_open_init_params(struct zoran *zr); +void zoran_vdev_release(struct video_device *vdev); + +void zr36016_write(struct videocodec *codec, u16 reg, u32 val); + +#endif /* __ZORAN_CARD_H__ */ diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c new file mode 100644 index 000000000000..31f049b55529 --- /dev/null +++ b/drivers/media/pci/zoran/zoran_device.c @@ -0,0 +1,956 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zoran zr36057/zr36067 PCI controller driver, for the + * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux + * Media Labs LML33/LML33R10. + * + * This part handles device access (PCI/I2C/codec/...) + * + * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <linux/spinlock.h> + +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/dma-mapping.h> + +#include <linux/io.h> + +#include "videocodec.h" +#include "zoran.h" +#include "zoran_device.h" +#include "zoran_card.h" + +#define IRQ_MASK (ZR36057_ISR_GIRQ0 | \ + ZR36057_ISR_GIRQ1 | \ + ZR36057_ISR_JPEG_REP_IRQ) + +static bool lml33dpath; /* default = 0 + * 1 will use digital path in capture + * mode instead of analog. It can be + * used for picture adjustments using + * tool like xawtv while watching image + * on TV monitor connected to the output. + * However, due to absence of 75 Ohm + * load on Bt819 input, there will be + * some image imperfections + */ + +module_param(lml33dpath, bool, 0644); +MODULE_PARM_DESC(lml33dpath, "Use digital path capture mode (on LML33 cards)"); + +/* + * initialize video front end + */ +static void zr36057_init_vfe(struct zoran *zr) +{ + u32 reg; + + reg = btread(ZR36057_VFESPFR); + reg |= ZR36057_VFESPFR_LITTLE_ENDIAN; + reg &= ~ZR36057_VFESPFR_VCLK_POL; + reg |= ZR36057_VFESPFR_EXT_FL; + reg |= ZR36057_VFESPFR_TOP_FIELD; + btwrite(reg, ZR36057_VFESPFR); + reg = btread(ZR36057_VDCR); + if (pci_pci_problems & PCIPCI_TRITON) + // || zr->revision < 1) // Revision 1 has also Triton support + reg &= ~ZR36057_VDCR_TRITON; + else + reg |= ZR36057_VDCR_TRITON; + btwrite(reg, ZR36057_VDCR); +} + +/* + * General Purpose I/O and Guest bus access + */ + +/* + * This is a bit tricky. When a board lacks a GPIO function, the corresponding + * GPIO bit number in the card_info structure is set to 0. + */ + +void GPIO(struct zoran *zr, int bit, unsigned int value) +{ + u32 reg; + u32 mask; + + /* Make sure the bit number is legal + * A bit number of -1 (lacking) gives a mask of 0, + * making it harmless + */ + mask = (1 << (24 + bit)) & 0xff000000; + reg = btread(ZR36057_GPPGCR1) & ~mask; + if (value) + reg |= mask; + + btwrite(reg, ZR36057_GPPGCR1); + udelay(1); +} + +/* + * Wait til post office is no longer busy + */ + +int post_office_wait(struct zoran *zr) +{ + u32 por; + + while ((por = btread(ZR36057_POR)) & ZR36057_POR_PO_PEN) { + /* wait for something to happen */ + /* TODO add timeout */ + } + if ((por & ZR36057_POR_PO_TIME) && !zr->card.gws_not_connected) { + /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */ + pci_info(zr->pci_dev, "pop timeout %08x\n", por); + return -1; + } + + return 0; +} + +int post_office_write(struct zoran *zr, unsigned int guest, + unsigned int reg, unsigned int value) +{ + u32 por; + + por = + ZR36057_POR_PO_DIR | ZR36057_POR_PO_TIME | ((guest & 7) << 20) | + ((reg & 7) << 16) | (value & 0xFF); + btwrite(por, ZR36057_POR); + + return post_office_wait(zr); +} + +int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg) +{ + u32 por; + + por = ZR36057_POR_PO_TIME | ((guest & 7) << 20) | ((reg & 7) << 16); + btwrite(por, ZR36057_POR); + if (post_office_wait(zr) < 0) + return -1; + + return btread(ZR36057_POR) & 0xFF; +} + +/* + * JPEG Codec access + */ + +void jpeg_codec_sleep(struct zoran *zr, int sleep) +{ + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep); + if (!sleep) { + pci_dbg(zr->pci_dev, "%s() - wake GPIO=0x%08x\n", + __func__, btread(ZR36057_GPPGCR1)); + usleep_range(500, 1000); + } else { + pci_dbg(zr->pci_dev, "%s() - sleep GPIO=0x%08x\n", + __func__, btread(ZR36057_GPPGCR1)); + udelay(2); + } +} + +int jpeg_codec_reset(struct zoran *zr) +{ + /* Take the codec out of sleep */ + jpeg_codec_sleep(zr, 0); + + if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) { + post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0, + 0); + udelay(2); + } else { + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0); + udelay(2); + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1); + udelay(2); + } + + return 0; +} + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the ZR36057 manual in front of + * you [AC]. + */ +static void zr36057_adjust_vfe(struct zoran *zr, enum zoran_codec_mode mode) +{ + u32 reg; + + switch (mode) { + case BUZ_MODE_MOTION_DECOMPRESS: + btand(~ZR36057_VFESPFR_EXT_FL, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if ((reg & (1 << 10)) && zr->card.type != LML33R10) + reg += ((1 << 10) | 1); + + btwrite(reg, ZR36057_VFEHCR); + break; + case BUZ_MODE_MOTION_COMPRESS: + case BUZ_MODE_IDLE: + default: + if ((zr->norm & V4L2_STD_NTSC) || + (zr->card.type == LML33R10 && + (zr->norm & V4L2_STD_PAL))) + btand(~ZR36057_VFESPFR_EXT_FL, ZR36057_VFESPFR); + else + btor(ZR36057_VFESPFR_EXT_FL, ZR36057_VFESPFR); + reg = btread(ZR36057_VFEHCR); + if (!(reg & (1 << 10)) && zr->card.type != LML33R10) + reg -= ((1 << 10) | 1); + + btwrite(reg, ZR36057_VFEHCR); + break; + } +} + +/* + * set geometry + */ + +static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, + const struct zoran_format *format) +{ + const struct tvnorm *tvn; + unsigned int h_start, h_end, v_start, v_end; + unsigned int disp_mode; + unsigned int vid_win_wid, vid_win_ht; + unsigned int hcrop1, hcrop2, vcrop1, vcrop2; + unsigned int wa, we, ha, he; + unsigned int X, Y, hor_dcm, ver_dcm; + u32 reg; + + tvn = zr->timing; + + wa = tvn->wa; + ha = tvn->ha; + + pci_dbg(zr->pci_dev, "set_vfe() - width = %d, height = %d\n", video_width, video_height); + + if (video_width < BUZ_MIN_WIDTH || + video_height < BUZ_MIN_HEIGHT || + video_width > wa || video_height > ha) { + pci_err(zr->pci_dev, "set_vfe: w=%d h=%d not valid\n", video_width, video_height); + return; + } + + /**** zr36057 ****/ + + /* horizontal */ + vid_win_wid = video_width; + X = DIV_ROUND_UP(vid_win_wid * 64, tvn->wa); + we = (vid_win_wid * 64) / X; + hor_dcm = 64 - X; + hcrop1 = 2 * ((tvn->wa - we) / 4); + hcrop2 = tvn->wa - we - hcrop1; + h_start = tvn->h_start ? tvn->h_start : 1; + /* (Ronald) Original comment: + * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+" + * this is false. It inverses chroma values on the LML33R10 (so Cr + * suddenly is shown as Cb and reverse, really cool effect if you + * want to see blue faces, not useful otherwise). So don't use |1. + * However, the DC10 has '0' as h_start, but does need |1, so we + * use a dirty check... + */ + h_end = h_start + tvn->wa - 1; + h_start += hcrop1; + h_end -= hcrop2; + reg = ((h_start & ZR36057_VFEHCR_HMASK) << ZR36057_VFEHCR_H_START) + | ((h_end & ZR36057_VFEHCR_HMASK) << ZR36057_VFEHCR_H_END); + if (zr->card.vfe_pol.hsync_pol) + reg |= ZR36057_VFEHCR_HS_POL; + btwrite(reg, ZR36057_VFEHCR); + + /* Vertical */ + disp_mode = !(video_height > BUZ_MAX_HEIGHT / 2); + vid_win_ht = disp_mode ? video_height : video_height / 2; + Y = DIV_ROUND_UP(vid_win_ht * 64 * 2, tvn->ha); + he = (vid_win_ht * 64) / Y; + ver_dcm = 64 - Y; + vcrop1 = (tvn->ha / 2 - he) / 2; + vcrop2 = tvn->ha / 2 - he - vcrop1; + v_start = tvn->v_start; + // FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP + v_end = v_start + tvn->ha / 2; // - 1; + v_start += vcrop1; + v_end -= vcrop2; + reg = ((v_start & ZR36057_VFEVCR_VMASK) << ZR36057_VFEVCR_V_START) + | ((v_end & ZR36057_VFEVCR_VMASK) << ZR36057_VFEVCR_V_END); + if (zr->card.vfe_pol.vsync_pol) + reg |= ZR36057_VFEVCR_VS_POL; + btwrite(reg, ZR36057_VFEVCR); + + /* scaler and pixel format */ + reg = 0; + reg |= (hor_dcm << ZR36057_VFESPFR_HOR_DCM); + reg |= (ver_dcm << ZR36057_VFESPFR_VER_DCM); + reg |= (disp_mode << ZR36057_VFESPFR_DISP_MODE); + /* + * RJ: I don't know, why the following has to be the opposite + * of the corresponding ZR36060 setting, but only this way + * we get the correct colors when uncompressing to the screen + */ + //reg |= ZR36057_VFESPFR_VCLK_POL; + /* RJ: Don't know if that is needed for NTSC also */ + if (!(zr->norm & V4L2_STD_NTSC)) + reg |= ZR36057_VFESPFR_EXT_FL; // NEEDED!!!!!!! Wolfgang + reg |= ZR36057_VFESPFR_TOP_FIELD; + if (hor_dcm >= 48) + reg |= 3 << ZR36057_VFESPFR_H_FILTER; /* 5 tap filter */ + else if (hor_dcm >= 32) + reg |= 2 << ZR36057_VFESPFR_H_FILTER; /* 4 tap filter */ + else if (hor_dcm >= 16) + reg |= 1 << ZR36057_VFESPFR_H_FILTER; /* 3 tap filter */ + + reg |= format->vfespfr; + btwrite(reg, ZR36057_VFESPFR); + + /* display configuration */ + reg = (16 << ZR36057_VDCR_MIN_PIX) + | (vid_win_ht << ZR36057_VDCR_VID_WIN_HT) + | (vid_win_wid << ZR36057_VDCR_VID_WIN_WID); + if (pci_pci_problems & PCIPCI_TRITON) + // || zr->revision < 1) // Revision 1 has also Triton support + reg &= ~ZR36057_VDCR_TRITON; + else + reg |= ZR36057_VDCR_TRITON; + btwrite(reg, ZR36057_VDCR); + + zr36057_adjust_vfe(zr, zr->codec_mode); +} + +/* Enable/Disable uncompressed memory grabbing of the 36057 */ +void zr36057_set_memgrab(struct zoran *zr, int mode) +{ + if (mode) { + /* We only check SnapShot and not FrameGrab here. SnapShot==1 + * means a capture is already in progress, but FrameGrab==1 + * doesn't necessary mean that. It's more correct to say a 1 + * to 0 transition indicates a capture completed. If a + * capture is pending when capturing is tuned off, FrameGrab + * will be stuck at 1 until capturing is turned back on. + */ + if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SNAP_SHOT) + pci_warn(zr->pci_dev, "%s(1) with SnapShot on!?\n", __func__); + + /* switch on VSync interrupts */ + btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts + btor(zr->card.vsync_int, ZR36057_ICR); // SW + + /* enable SnapShot */ + btor(ZR36057_VSSFGR_SNAP_SHOT, ZR36057_VSSFGR); + + /* Set zr36057 video front end and enable video */ + zr36057_set_vfe(zr, zr->v4l_settings.width, + zr->v4l_settings.height, + zr->v4l_settings.format); + } else { + /* switch off VSync interrupts */ + btand(~zr->card.vsync_int, ZR36057_ICR); // SW + + /* re-enable grabbing to screen if it was running */ + btand(~ZR36057_VDCR_VID_EN, ZR36057_VDCR); + btand(~ZR36057_VSSFGR_SNAP_SHOT, ZR36057_VSSFGR); + } +} + +/***************************************************************************** + * * + * Set up the Buz-specific MJPEG part * + * * + *****************************************************************************/ + +static inline void set_frame(struct zoran *zr, int val) +{ + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val); +} + +static void set_videobus_dir(struct zoran *zr, int val) +{ + switch (zr->card.type) { + case LML33: + case LML33R10: + if (!lml33dpath) + GPIO(zr, 5, val); + else + GPIO(zr, 5, 1); + break; + default: + GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR], + zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val); + break; + } +} + +static void init_jpeg_queue(struct zoran *zr) +{ + int i; + + /* re-initialize DMA ring stuff */ + zr->jpg_que_head = 0; + zr->jpg_dma_head = 0; + zr->jpg_dma_tail = 0; + zr->jpg_que_tail = 0; + zr->jpg_seq_num = 0; + zr->jpeg_error = 0; + zr->num_errors = 0; + zr->jpg_err_seq = 0; + zr->jpg_err_shift = 0; + zr->jpg_queued_num = 0; + for (i = 0; i < BUZ_NUM_STAT_COM; i++) + zr->stat_com[i] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ +} + +static void zr36057_set_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + const struct tvnorm *tvn; + u32 reg; + + tvn = zr->timing; + + /* assert P_Reset, disable code transfer, deassert Active */ + btwrite(0, ZR36057_JPC); + + /* MJPEG compression mode */ + switch (mode) { + case BUZ_MODE_MOTION_COMPRESS: + default: + reg = ZR36057_JMC_MJPG_CMP_MODE; + break; + + case BUZ_MODE_MOTION_DECOMPRESS: + reg = ZR36057_JMC_MJPG_EXP_MODE; + reg |= ZR36057_JMC_SYNC_MSTR; + /* RJ: The following is experimental - improves the output to screen */ + //if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM + break; + + case BUZ_MODE_STILL_COMPRESS: + reg = ZR36057_JMC_JPG_CMP_MODE; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + reg = ZR36057_JMC_JPG_EXP_MODE; + break; + } + reg |= ZR36057_JMC_JPG; + if (zr->jpg_settings.field_per_buff == 1) + reg |= ZR36057_JMC_FLD_PER_BUFF; + btwrite(reg, ZR36057_JMC); + + /* vertical */ + btor(ZR36057_VFEVCR_VS_POL, ZR36057_VFEVCR); + reg = (6 << ZR36057_VSP_VSYNC_SIZE) | + (tvn->ht << ZR36057_VSP_FRM_TOT); + btwrite(reg, ZR36057_VSP); + reg = ((zr->jpg_settings.img_y + tvn->v_start) << ZR36057_FVAP_NAY) | + (zr->jpg_settings.img_height << ZR36057_FVAP_PAY); + btwrite(reg, ZR36057_FVAP); + + /* horizontal */ + if (zr->card.vfe_pol.hsync_pol) + btor(ZR36057_VFEHCR_HS_POL, ZR36057_VFEHCR); + else + btand(~ZR36057_VFEHCR_HS_POL, ZR36057_VFEHCR); + reg = ((tvn->h_sync_start) << ZR36057_HSP_HSYNC_START) | + (tvn->wt << ZR36057_HSP_LINE_TOT); + btwrite(reg, ZR36057_HSP); + reg = ((zr->jpg_settings.img_x + + tvn->h_start + 4) << ZR36057_FHAP_NAX) | + (zr->jpg_settings.img_width << ZR36057_FHAP_PAX); + btwrite(reg, ZR36057_FHAP); + + /* field process parameters */ + if (zr->jpg_settings.odd_even) + reg = ZR36057_FPP_ODD_EVEN; + else + reg = 0; + + btwrite(reg, ZR36057_FPP); + + /* Set proper VCLK Polarity, else colors will be wrong during playback */ + //btor(ZR36057_VFESPFR_VCLK_POL, ZR36057_VFESPFR); + + /* code base address */ + btwrite(zr->p_sc, ZR36057_JCBA); + + /* FIFO threshold (FIFO is 160. double words) */ + /* NOTE: decimal values here */ + switch (mode) { + case BUZ_MODE_STILL_COMPRESS: + case BUZ_MODE_MOTION_COMPRESS: + if (zr->card.type != BUZ) + reg = 140; + else + reg = 60; + break; + + case BUZ_MODE_STILL_DECOMPRESS: + case BUZ_MODE_MOTION_DECOMPRESS: + reg = 20; + break; + + default: + reg = 80; + break; + } + btwrite(reg, ZR36057_JCFT); + zr36057_adjust_vfe(zr, mode); +} + +void clear_interrupt_counters(struct zoran *zr) +{ + zr->intr_counter_GIRQ1 = 0; + zr->intr_counter_GIRQ0 = 0; + zr->intr_counter_cod_rep_irq = 0; + zr->intr_counter_jpeg_rep_irq = 0; + zr->field_counter = 0; + zr->irq1_in = 0; + zr->irq1_out = 0; + zr->jpeg_in = 0; + zr->jpeg_out = 0; + zr->JPEG_0 = 0; + zr->JPEG_1 = 0; + zr->end_event_missed = 0; + zr->jpeg_missed = 0; + zr->jpeg_max_missed = 0; + zr->jpeg_min_missed = 0x7fffffff; +} + +static u32 count_reset_interrupt(struct zoran *zr) +{ + u32 isr; + + isr = btread(ZR36057_ISR) & 0x78000000; + if (isr) { + if (isr & ZR36057_ISR_GIRQ1) { + btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR); + zr->intr_counter_GIRQ1++; + } + if (isr & ZR36057_ISR_GIRQ0) { + btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR); + zr->intr_counter_GIRQ0++; + } + if (isr & ZR36057_ISR_COD_REP_IRQ) { + btwrite(ZR36057_ISR_COD_REP_IRQ, ZR36057_ISR); + zr->intr_counter_cod_rep_irq++; + } + if (isr & ZR36057_ISR_JPEG_REP_IRQ) { + btwrite(ZR36057_ISR_JPEG_REP_IRQ, ZR36057_ISR); + zr->intr_counter_jpeg_rep_irq++; + } + } + return isr; +} + +void jpeg_start(struct zoran *zr) +{ + int reg; + + zr->frame_num = 0; + + /* deassert P_reset, disable code transfer, deassert Active */ + btwrite(ZR36057_JPC_P_RESET, ZR36057_JPC); + /* stop flushing the internal code buffer */ + btand(~ZR36057_MCTCR_C_FLUSH, ZR36057_MCTCR); + /* enable code transfer */ + btor(ZR36057_JPC_COD_TRNS_EN, ZR36057_JPC); + + /* clear IRQs */ + btwrite(IRQ_MASK, ZR36057_ISR); + /* enable the JPEG IRQs */ + btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEG_REP_IRQ | ZR36057_ICR_INT_PIN_EN, + ZR36057_ICR); + + set_frame(zr, 0); // \FRAME + + /* set the JPEG codec guest ID */ + reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPE_GUEST_ID) | + (0 << ZR36057_JCGI_JPE_GUEST_REG); + btwrite(reg, ZR36057_JCGI); + + if (zr->card.video_vfe == CODEC_TYPE_ZR36016 && + zr->card.video_codec == CODEC_TYPE_ZR36050) { + /* Enable processing on the ZR36016 */ + if (zr->vfe) + zr36016_write(zr->vfe, 0, 1); + + /* load the address of the GO register in the ZR36050 latch */ + post_office_write(zr, 0, 0, 0); + } + + /* assert Active */ + btor(ZR36057_JPC_ACTIVE, ZR36057_JPC); + + /* enable the Go generation */ + btor(ZR36057_JMC_GO_EN, ZR36057_JMC); + usleep_range(30, 100); + + set_frame(zr, 1); // /FRAME +} + +void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) +{ + struct vfe_settings cap; + int field_size = zr->buffer_size / zr->jpg_settings.field_per_buff; + + zr->codec_mode = mode; + + cap.x = zr->jpg_settings.img_x; + cap.y = zr->jpg_settings.img_y; + cap.width = zr->jpg_settings.img_width; + cap.height = zr->jpg_settings.img_height; + cap.decimation = + zr->jpg_settings.hor_dcm | (zr->jpg_settings.ver_dcm << 8); + cap.quality = zr->jpg_settings.jpg_comp.quality; + + switch (mode) { + case BUZ_MODE_MOTION_COMPRESS: { + struct jpeg_app_marker app; + struct jpeg_com_marker com; + + /* In motion compress mode, the decoder output must be enabled, and + * the video bus direction set to input. + */ + set_videobus_dir(zr, 0); + decoder_call(zr, video, s_stream, 1); + encoder_call(zr, video, s_routing, 0, 0, 0); + + /* Take the JPEG codec and the VFE out of sleep */ + jpeg_codec_sleep(zr, 0); + + /* set JPEG app/com marker */ + app.appn = zr->jpg_settings.jpg_comp.APPn; + app.len = zr->jpg_settings.jpg_comp.APP_len; + memcpy(app.data, zr->jpg_settings.jpg_comp.APP_data, 60); + zr->codec->control(zr->codec, CODEC_S_JPEG_APP_DATA, + sizeof(struct jpeg_app_marker), &app); + + com.len = zr->jpg_settings.jpg_comp.COM_len; + memcpy(com.data, zr->jpg_settings.jpg_comp.COM_data, 60); + zr->codec->control(zr->codec, CODEC_S_JPEG_COM_DATA, + sizeof(struct jpeg_com_marker), &com); + + /* Setup the JPEG codec */ + zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE, + sizeof(int), &field_size); + zr->codec->set_video(zr->codec, zr->timing, &cap, + &zr->card.vfe_pol); + zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION); + + /* Setup the VFE */ + if (zr->vfe) { + zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE, + sizeof(int), &field_size); + zr->vfe->set_video(zr->vfe, zr->timing, &cap, + &zr->card.vfe_pol); + zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION); + } + + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + pci_dbg(zr->pci_dev, "enable_jpg(MOTION_COMPRESS)\n"); + break; + } + + case BUZ_MODE_MOTION_DECOMPRESS: + /* In motion decompression mode, the decoder output must be disabled, and + * the video bus direction set to output. + */ + decoder_call(zr, video, s_stream, 0); + set_videobus_dir(zr, 1); + encoder_call(zr, video, s_routing, 1, 0, 0); + + /* Take the JPEG codec and the VFE out of sleep */ + jpeg_codec_sleep(zr, 0); + /* Setup the VFE */ + if (zr->vfe) { + zr->vfe->set_video(zr->vfe, zr->timing, &cap, + &zr->card.vfe_pol); + zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION); + } + /* Setup the JPEG codec */ + zr->codec->set_video(zr->codec, zr->timing, &cap, + &zr->card.vfe_pol); + zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION); + + init_jpeg_queue(zr); + zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO + + clear_interrupt_counters(zr); + pci_dbg(zr->pci_dev, "enable_jpg(MOTION_DECOMPRESS)\n"); + break; + + case BUZ_MODE_IDLE: + default: + /* shut down processing */ + btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEG_REP_IRQ), + ZR36057_ICR); + btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEG_REP_IRQ, + ZR36057_ISR); + btand(~ZR36057_JMC_GO_EN, ZR36057_JMC); // \Go_en + + msleep(50); + + set_videobus_dir(zr, 0); + set_frame(zr, 1); // /FRAME + btor(ZR36057_MCTCR_C_FLUSH, ZR36057_MCTCR); // /CFlush + btwrite(0, ZR36057_JPC); // \P_Reset,\CodTrnsEn,\Active + btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); + btand(~ZR36057_JMC_SYNC_MSTR, ZR36057_JMC); + jpeg_codec_reset(zr); + jpeg_codec_sleep(zr, 1); + zr36057_adjust_vfe(zr, mode); + + decoder_call(zr, video, s_stream, 1); + encoder_call(zr, video, s_routing, 0, 0, 0); + + pci_dbg(zr->pci_dev, "enable_jpg(IDLE)\n"); + break; + } +} + +/* when this is called the spinlock must be held */ +void zoran_feed_stat_com(struct zoran *zr) +{ + /* move frames from pending queue to DMA */ + + int i, max_stat_com; + struct zr_buffer *buf; + struct vb2_v4l2_buffer *vbuf; + dma_addr_t phys_addr = 0; + unsigned long flags; + unsigned long payload; + + max_stat_com = + (zr->jpg_settings.tmp_dcm == + 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); + + spin_lock_irqsave(&zr->queued_bufs_lock, flags); + while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com) { + buf = list_first_entry_or_null(&zr->queued_bufs, struct zr_buffer, queue); + if (!buf) { + pci_err(zr->pci_dev, "No buffer available to queue\n"); + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + return; + } + list_del(&buf->queue); + zr->buf_in_reserve--; + vbuf = &buf->vbuf; + vbuf->vb2_buf.state = VB2_BUF_STATE_ACTIVE; + phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); + payload = vb2_get_plane_payload(&vbuf->vb2_buf, 0); + if (payload == 0) + payload = zr->buffer_size; + if (zr->jpg_settings.tmp_dcm == 1) { + /* fill 1 stat_com entry */ + i = (zr->jpg_dma_head - + zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + if (!(zr->stat_com[i] & cpu_to_le32(1))) + break; + zr->stat_comb[i * 2] = cpu_to_le32(phys_addr); + zr->stat_comb[i * 2 + 1] = cpu_to_le32((payload >> 1) | 1); + zr->inuse[i] = buf; + zr->stat_com[i] = cpu_to_le32(zr->p_scb + i * 2 * 4); + } else { + /* fill 2 stat_com entries */ + i = ((zr->jpg_dma_head - + zr->jpg_err_shift) & 1) * 2; + if (!(zr->stat_com[i] & cpu_to_le32(1))) + break; + zr->stat_com[i] = cpu_to_le32(zr->p_scb + i * 2 * 4); + zr->stat_com[i + 1] = cpu_to_le32(zr->p_scb + i * 2 * 4); + + zr->stat_comb[i * 2] = cpu_to_le32(phys_addr); + zr->stat_comb[i * 2 + 1] = cpu_to_le32((payload >> 1) | 1); + + zr->inuse[i] = buf; + zr->inuse[i + 1] = NULL; + } + zr->jpg_dma_head++; + } + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_queued_num++; +} + +/* when this is called the spinlock must be held */ +static void zoran_reap_stat_com(struct zoran *zr) +{ + /* move frames from DMA queue to done queue */ + + int i; + u32 stat_com; + unsigned int seq; + unsigned int dif; + unsigned long flags; + struct zr_buffer *buf; + unsigned int size = 0; + u32 fcnt; + + /* + * In motion decompress we don't have a hardware frame counter, + * we just count the interrupts here + */ + + if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) + zr->jpg_seq_num++; + + spin_lock_irqsave(&zr->queued_bufs_lock, flags); + while (zr->jpg_dma_tail < zr->jpg_dma_head) { + if (zr->jpg_settings.tmp_dcm == 1) + i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; + else + i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; + + stat_com = le32_to_cpu(zr->stat_com[i]); + if ((stat_com & 1) == 0) { + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + return; + } + + fcnt = (stat_com & GENMASK(31, 24)) >> 24; + size = (stat_com & GENMASK(22, 1)) >> 1; + + buf = zr->inuse[i]; + if (!buf) { + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + pci_err(zr->pci_dev, "No buffer at slot %d\n", i); + return; + } + buf->vbuf.vb2_buf.timestamp = ktime_get_ns(); + + if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { + vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, size); + + /* update sequence number with the help of the counter in stat_com */ + seq = (fcnt + zr->jpg_err_seq) & 0xff; + dif = (seq - zr->jpg_seq_num) & 0xff; + zr->jpg_seq_num += dif; + } + buf->vbuf.sequence = zr->jpg_settings.tmp_dcm == + 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; + zr->inuse[i] = NULL; + if (zr->jpg_settings.tmp_dcm != 1) + buf->vbuf.field = zr->jpg_settings.odd_even ? + V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; + else + buf->vbuf.field = zr->jpg_settings.odd_even ? + V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT; + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE); + + zr->jpg_dma_tail++; + } + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); +} + +irqreturn_t zoran_irq(int irq, void *dev_id) +{ + struct zoran *zr = dev_id; + u32 stat, astat; + + stat = count_reset_interrupt(zr); + astat = stat & IRQ_MASK; + if (astat & zr->card.vsync_int) { + if (zr->running == ZORAN_MAP_MODE_RAW) { + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SNAP_SHOT) == 0) + pci_warn(zr->pci_dev, "BuzIRQ with SnapShot off ???\n"); + if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FRAME_GRAB) == 0) + zr_set_buf(zr); + return IRQ_HANDLED; + } + if (astat & ZR36057_ISR_JPEG_REP_IRQ) { + if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && + zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { + pci_err(zr->pci_dev, "JPG IRQ when not in good mode\n"); + return IRQ_HANDLED; + } + zr->frame_num++; + zoran_reap_stat_com(zr); + zoran_feed_stat_com(zr); + return IRQ_HANDLED; + } + /* unused interrupts */ + } + zr->ghost_int++; + return IRQ_HANDLED; +} + +void zoran_set_pci_master(struct zoran *zr, int set_master) +{ + if (set_master) { + pci_set_master(zr->pci_dev); + } else { + u16 command; + + pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command); + command &= ~PCI_COMMAND_MASTER; + pci_write_config_word(zr->pci_dev, PCI_COMMAND, command); + } +} + +void zoran_init_hardware(struct zoran *zr) +{ + /* Enable bus-mastering */ + zoran_set_pci_master(zr, 1); + + /* Initialize the board */ + if (zr->card.init) + zr->card.init(zr); + + decoder_call(zr, core, init, 0); + decoder_call(zr, video, s_std, zr->norm); + decoder_call(zr, video, s_routing, + zr->card.input[zr->input].muxsel, 0, 0); + + encoder_call(zr, core, init, 0); + encoder_call(zr, video, s_std_output, zr->norm); + encoder_call(zr, video, s_routing, 0, 0, 0); + + /* toggle JPEG codec sleep to sync PLL */ + jpeg_codec_sleep(zr, 1); + jpeg_codec_sleep(zr, 0); + + /* + * set individual interrupt enables (without GIRQ1) + * but don't global enable until zoran_open() + */ + zr36057_init_vfe(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + + btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts +} + +void zr36057_restart(struct zoran *zr) +{ + btwrite(0, ZR36057_SPGPPCR); + usleep_range(1000, 2000); + btor(ZR36057_SPGPPCR_SOFT_RESET, ZR36057_SPGPPCR); + usleep_range(1000, 2000); + + /* assert P_Reset */ + btwrite(0, ZR36057_JPC); + /* set up GPIO direction - all output */ + btwrite(ZR36057_SPGPPCR_SOFT_RESET | 0, ZR36057_SPGPPCR); + + /* set up GPIO pins and guest bus timing */ + btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1); +} + diff --git a/drivers/media/pci/zoran/zoran_device.h b/drivers/media/pci/zoran/zoran_device.h new file mode 100644 index 000000000000..34fd5cc914eb --- /dev/null +++ b/drivers/media/pci/zoran/zoran_device.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Zoran zr36057/zr36067 PCI controller driver, for the + * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux + * Media Labs LML33/LML33R10. + * + * This part handles card-specific data and detection + * + * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + */ + +#ifndef __ZORAN_DEVICE_H__ +#define __ZORAN_DEVICE_H__ + +/* general purpose I/O */ +void GPIO(struct zoran *zr, int bit, unsigned int value); + +/* codec (or actually: guest bus) access */ +int post_office_wait(struct zoran *zr); +int post_office_write(struct zoran *zr, unsigned int guest, unsigned int reg, + unsigned int value); +int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg); + +void jpeg_codec_sleep(struct zoran *zr, int sleep); +int jpeg_codec_reset(struct zoran *zr); + +/* zr360x7 access to raw capture */ +void zr36057_overlay(struct zoran *zr, int on); +void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count); +void zr36057_set_memgrab(struct zoran *zr, int mode); +int wait_grab_pending(struct zoran *zr); + +/* interrupts */ +void print_interrupts(struct zoran *zr); +void clear_interrupt_counters(struct zoran *zr); +irqreturn_t zoran_irq(int irq, void *dev_id); + +/* JPEG codec access */ +void jpeg_start(struct zoran *zr); +void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode); +void zoran_feed_stat_com(struct zoran *zr); + +/* general */ +void zoran_set_pci_master(struct zoran *zr, int set_master); +void zoran_init_hardware(struct zoran *zr); +void zr36057_restart(struct zoran *zr); + +extern const struct zoran_format zoran_formats[]; + +extern int v4l_bufsize; +extern int jpg_bufsize; +extern int pass_through; + +/* i2c */ +#define decoder_call(zr, o, f, args...) \ + v4l2_subdev_call((zr)->decoder, o, f, ##args) +#define encoder_call(zr, o, f, args...) \ + v4l2_subdev_call((zr)->encoder, o, f, ##args) + +#endif /* __ZORAN_DEVICE_H__ */ diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c new file mode 100644 index 000000000000..fa672cc8bc67 --- /dev/null +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -0,0 +1,986 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zoran zr36057/zr36067 PCI controller driver, for the + * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux + * Media Labs LML33/LML33R10. + * + * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + * + * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> + * + * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be> + * + * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com> + * + * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net> + * + * Based on + * + * Miro DC10 driver + * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> + * + * Iomega Buz driver version 1.0 + * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> + * + * buz.0.0.3 + * Copyright (C) 1998 Dave Perks <dperks@ibm.net> + * + * bttv - Bt848 frame grabber driver + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + * & Marcus Metzler (mocm@thp.uni-koeln.de) + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/wait.h> + +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include <linux/spinlock.h> + +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include "videocodec.h" + +#include <linux/io.h> +#include <linux/uaccess.h> + +#include <linux/mutex.h> +#include "zoran.h" +#include "zoran_device.h" +#include "zoran_card.h" + +const struct zoran_format zoran_formats[] = { + { + .name = "15-bit RGB LE", + .fourcc = V4L2_PIX_FMT_RGB555, + .colorspace = V4L2_COLORSPACE_SRGB, + .depth = 15, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ERR_DIF | + ZR36057_VFESPFR_LITTLE_ENDIAN, + }, { + .name = "15-bit RGB BE", + .fourcc = V4L2_PIX_FMT_RGB555X, + .colorspace = V4L2_COLORSPACE_SRGB, + .depth = 15, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ERR_DIF, + }, { + .name = "16-bit RGB LE", + .fourcc = V4L2_PIX_FMT_RGB565, + .colorspace = V4L2_COLORSPACE_SRGB, + .depth = 16, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ERR_DIF | + ZR36057_VFESPFR_LITTLE_ENDIAN, + }, { + .name = "16-bit RGB BE", + .fourcc = V4L2_PIX_FMT_RGB565X, + .colorspace = V4L2_COLORSPACE_SRGB, + .depth = 16, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ERR_DIF, + }, { + .name = "24-bit RGB", + .fourcc = V4L2_PIX_FMT_BGR24, + .colorspace = V4L2_COLORSPACE_SRGB, + .depth = 24, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_PACK24, + }, { + .name = "32-bit RGB LE", + .fourcc = V4L2_PIX_FMT_BGR32, + .colorspace = V4L2_COLORSPACE_SRGB, + .depth = 32, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_LITTLE_ENDIAN, + }, { + .name = "32-bit RGB BE", + .fourcc = V4L2_PIX_FMT_RGB32, + .colorspace = V4L2_COLORSPACE_SRGB, + .depth = 32, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_RGB888, + }, { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .colorspace = V4L2_COLORSPACE_SMPTE170M, + .depth = 16, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_YUV422, + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .colorspace = V4L2_COLORSPACE_SMPTE170M, + .depth = 16, + .flags = ZORAN_FORMAT_CAPTURE, + .vfespfr = ZR36057_VFESPFR_YUV422 | ZR36057_VFESPFR_LITTLE_ENDIAN, + }, { + .name = "Hardware-encoded Motion-JPEG", + .fourcc = V4L2_PIX_FMT_MJPEG, + .colorspace = V4L2_COLORSPACE_SMPTE170M, + .depth = 0, + .flags = ZORAN_FORMAT_CAPTURE | + ZORAN_FORMAT_PLAYBACK | + ZORAN_FORMAT_COMPRESSED, + } +}; + +#define NUM_FORMATS ARRAY_SIZE(zoran_formats) + + /* + * small helper function for calculating buffersizes for v4l2 + * we calculate the nearest higher power-of-two, which + * will be the recommended buffersize + */ +static __u32 zoran_v4l2_calc_bufsize(struct zoran_jpg_settings *settings) +{ + __u8 div = settings->ver_dcm * settings->hor_dcm * settings->tmp_dcm; + __u32 num = (1024 * 512) / (div); + __u32 result = 2; + + num--; + while (num) { + num >>= 1; + result <<= 1; + } + + if (result < 8192) + return 8192; + + return result; +} + +/* + * V4L Buffer grabbing + */ +static int zoran_v4l_set_format(struct zoran *zr, int width, int height, + const struct zoran_format *format) +{ + int bpp; + + /* Check size and format of the grab wanted */ + + if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || + height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { + pci_dbg(zr->pci_dev, "%s - wrong frame size (%dx%d)\n", __func__, width, height); + return -EINVAL; + } + + bpp = (format->depth + 7) / 8; + + zr->buffer_size = height * width * bpp; + + /* Check against available buffer size */ + if (height * width * bpp > zr->buffer_size) { + pci_dbg(zr->pci_dev, "%s - video buffer size (%d kB) is too small\n", + __func__, zr->buffer_size >> 10); + return -EINVAL; + } + + /* The video front end needs 4-byte alinged line sizes */ + + if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { + pci_dbg(zr->pci_dev, "%s - wrong frame alignment\n", __func__); + return -EINVAL; + } + + zr->v4l_settings.width = width; + zr->v4l_settings.height = height; + zr->v4l_settings.format = format; + zr->v4l_settings.bytesperline = bpp * zr->v4l_settings.width; + + return 0; +} + +static int zoran_set_norm(struct zoran *zr, v4l2_std_id norm) +{ + if (!(norm & zr->card.norms)) { + pci_dbg(zr->pci_dev, "%s - unsupported norm %llx\n", __func__, norm); + return -EINVAL; + } + + if (norm & V4L2_STD_SECAM) + zr->timing = zr->card.tvn[ZR_NORM_SECAM]; + else if (norm & V4L2_STD_NTSC) + zr->timing = zr->card.tvn[ZR_NORM_NTSC]; + else + zr->timing = zr->card.tvn[ZR_NORM_PAL]; + + decoder_call(zr, video, s_std, norm); + encoder_call(zr, video, s_std_output, norm); + + /* Make sure the changes come into effect */ + zr->norm = norm; + + return 0; +} + +static int zoran_set_input(struct zoran *zr, int input) +{ + if (input == zr->input) + return 0; + + if (input < 0 || input >= zr->card.inputs) { + pci_dbg(zr->pci_dev, "%s - unsupported input %d\n", __func__, input); + return -EINVAL; + } + + zr->input = input; + + decoder_call(zr, video, s_routing, zr->card.input[input].muxsel, 0, 0); + + return 0; +} + +/* + * ioctl routine + */ + +static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) +{ + struct zoran *zr = video_drvdata(file); + + strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)); + strscpy(cap->driver, "zoran", sizeof(cap->driver)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(zr->pci_dev)); + return 0; +} + +static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) +{ + unsigned int num, i; + + if (fmt->index >= ARRAY_SIZE(zoran_formats)) + return -EINVAL; + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + for (num = i = 0; i < NUM_FORMATS; i++) { + if (zoran_formats[i].flags & flag && num++ == fmt->index) { + strscpy(fmt->description, zoran_formats[i].name, + sizeof(fmt->description)); + /* fmt struct pre-zeroed, so adding '\0' not needed */ + fmt->pixelformat = zoran_formats[i].fourcc; + if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED) + fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; + return 0; + } + } + return -EINVAL; +} + +static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, + struct v4l2_fmtdesc *f) +{ + struct zoran *zr = video_drvdata(file); + + return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); +} + +static int zoran_g_fmt_vid_out(struct file *file, void *__fh, + struct v4l2_format *fmt) +{ + struct zoran *zr = video_drvdata(file); + + fmt->fmt.pix.width = zr->jpg_settings.img_width / zr->jpg_settings.hor_dcm; + fmt->fmt.pix.height = zr->jpg_settings.img_height * 2 / + (zr->jpg_settings.ver_dcm * zr->jpg_settings.tmp_dcm); + fmt->fmt.pix.sizeimage = zr->buffer_size; + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; + if (zr->jpg_settings.tmp_dcm == 1) + fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? + V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); + else + fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? + V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); + fmt->fmt.pix.bytesperline = 0; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + return 0; +} + +static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, + struct v4l2_format *fmt) +{ + struct zoran *zr = video_drvdata(file); + + if (zr->map_mode != ZORAN_MAP_MODE_RAW) + return zoran_g_fmt_vid_out(file, __fh, fmt); + fmt->fmt.pix.width = zr->v4l_settings.width; + fmt->fmt.pix.height = zr->v4l_settings.height; + fmt->fmt.pix.sizeimage = zr->buffer_size; + fmt->fmt.pix.pixelformat = zr->v4l_settings.format->fourcc; + fmt->fmt.pix.colorspace = zr->v4l_settings.format->colorspace; + fmt->fmt.pix.bytesperline = zr->v4l_settings.bytesperline; + if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) + fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; + else + fmt->fmt.pix.field = V4L2_FIELD_TOP; + return 0; +} + +static int zoran_try_fmt_vid_out(struct file *file, void *__fh, + struct v4l2_format *fmt) +{ + struct zoran *zr = video_drvdata(file); + struct zoran_jpg_settings settings; + int res = 0; + + if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + + settings = zr->jpg_settings; + + /* we actually need to set 'real' parameters now */ + if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT) + settings.tmp_dcm = 1; + else + settings.tmp_dcm = 2; + settings.decimation = 0; + if (fmt->fmt.pix.height <= zr->jpg_settings.img_height / 2) + settings.ver_dcm = 2; + else + settings.ver_dcm = 1; + if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 4) + settings.hor_dcm = 4; + else if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 2) + settings.hor_dcm = 2; + else + settings.hor_dcm = 1; + if (settings.tmp_dcm == 1) + settings.field_per_buff = 2; + else + settings.field_per_buff = 1; + + if (settings.hor_dcm > 1) { + settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; + settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; + } else { + settings.img_x = 0; + settings.img_width = BUZ_MAX_WIDTH; + } + + /* check */ + res = zoran_check_jpg_settings(zr, &settings, 1); + if (res) + return res; + + /* tell the user what we actually did */ + fmt->fmt.pix.width = settings.img_width / settings.hor_dcm; + fmt->fmt.pix.height = settings.img_height * 2 / + (settings.tmp_dcm * settings.ver_dcm); + if (settings.tmp_dcm == 1) + fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? + V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); + else + fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? + V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); + + fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings); + fmt->fmt.pix.bytesperline = 0; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + return res; +} + +static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, + struct v4l2_format *fmt) +{ + struct zoran *zr = video_drvdata(file); + int bpp; + int i; + + if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) + return zoran_try_fmt_vid_out(file, __fh, fmt); + + for (i = 0; i < NUM_FORMATS; i++) + if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) + break; + + if (i == NUM_FORMATS) { + /* TODO do not return here to fix the TRY_FMT cannot handle an invalid pixelformat*/ + return -EINVAL; + } + + fmt->fmt.pix.pixelformat = zoran_formats[i].fourcc; + fmt->fmt.pix.colorspace = zoran_formats[i].colorspace; + if (BUZ_MAX_HEIGHT < (fmt->fmt.pix.height * 2)) + fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; + else + fmt->fmt.pix.field = V4L2_FIELD_TOP; + + bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8); + v4l_bound_align_image(&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, + bpp == 2 ? 1 : 2, + &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, + 0, 0); + fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * bpp; + fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * fmt->fmt.pix.height; + return 0; +} + +static int zoran_s_fmt_vid_out(struct file *file, void *__fh, + struct v4l2_format *fmt) +{ + struct zoran *zr = video_drvdata(file); + __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat); + struct zoran_jpg_settings settings; + int res = 0; + + pci_dbg(zr->pci_dev, "size=%dx%d, fmt=0x%x (%4.4s)\n", + fmt->fmt.pix.width, fmt->fmt.pix.height, + fmt->fmt.pix.pixelformat, + (char *)&printformat); + if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + + if (!fmt->fmt.pix.height || !fmt->fmt.pix.width) + return -EINVAL; + + settings = zr->jpg_settings; + + /* we actually need to set 'real' parameters now */ + if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT) + settings.tmp_dcm = 1; + else + settings.tmp_dcm = 2; + settings.decimation = 0; + if (fmt->fmt.pix.height <= zr->jpg_settings.img_height / 2) + settings.ver_dcm = 2; + else + settings.ver_dcm = 1; + if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 4) + settings.hor_dcm = 4; + else if (fmt->fmt.pix.width <= zr->jpg_settings.img_width / 2) + settings.hor_dcm = 2; + else + settings.hor_dcm = 1; + if (settings.tmp_dcm == 1) + settings.field_per_buff = 2; + else + settings.field_per_buff = 1; + + if (settings.hor_dcm > 1) { + settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; + settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; + } else { + settings.img_x = 0; + settings.img_width = BUZ_MAX_WIDTH; + } + + /* check */ + res = zoran_check_jpg_settings(zr, &settings, 0); + if (res) + return res; + + /* it's ok, so set them */ + zr->jpg_settings = settings; + + if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + zr->map_mode = ZORAN_MAP_MODE_JPG_REC; + else + zr->map_mode = ZORAN_MAP_MODE_JPG_PLAY; + + zr->buffer_size = zoran_v4l2_calc_bufsize(&zr->jpg_settings); + + /* tell the user what we actually did */ + fmt->fmt.pix.width = settings.img_width / settings.hor_dcm; + fmt->fmt.pix.height = settings.img_height * 2 / + (settings.tmp_dcm * settings.ver_dcm); + if (settings.tmp_dcm == 1) + fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? + V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); + else + fmt->fmt.pix.field = (zr->jpg_settings.odd_even ? + V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); + fmt->fmt.pix.bytesperline = 0; + fmt->fmt.pix.sizeimage = zr->buffer_size; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + return res; +} + +static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, + struct v4l2_format *fmt) +{ + struct zoran *zr = video_drvdata(file); + struct zoran_fh *fh = __fh; + int i; + int res = 0; + + if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) + return zoran_s_fmt_vid_out(file, fh, fmt); + + for (i = 0; i < NUM_FORMATS; i++) + if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) + break; + if (i == NUM_FORMATS) { + pci_dbg(zr->pci_dev, "VIDIOC_S_FMT - unknown/unsupported format 0x%x\n", + fmt->fmt.pix.pixelformat); + /* TODO do not return here to fix the TRY_FMT cannot handle an invalid pixelformat*/ + return -EINVAL; + } + + fmt->fmt.pix.pixelformat = zoran_formats[i].fourcc; + if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) + fmt->fmt.pix.height = BUZ_MAX_HEIGHT; + if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) + fmt->fmt.pix.width = BUZ_MAX_WIDTH; + if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT) + fmt->fmt.pix.height = BUZ_MIN_HEIGHT; + if (fmt->fmt.pix.width < BUZ_MIN_WIDTH) + fmt->fmt.pix.width = BUZ_MIN_WIDTH; + + zr->map_mode = ZORAN_MAP_MODE_RAW; + + res = zoran_v4l_set_format(zr, fmt->fmt.pix.width, fmt->fmt.pix.height, + &zoran_formats[i]); + if (res) + return res; + + /* tell the user the results/missing stuff */ + fmt->fmt.pix.bytesperline = zr->v4l_settings.bytesperline; + fmt->fmt.pix.sizeimage = zr->buffer_size; + fmt->fmt.pix.colorspace = zr->v4l_settings.format->colorspace; + if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) + fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; + else + fmt->fmt.pix.field = V4L2_FIELD_TOP; + return res; +} + +static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) +{ + struct zoran *zr = video_drvdata(file); + + *std = zr->norm; + return 0; +} + +static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) +{ + struct zoran *zr = video_drvdata(file); + int res = 0; + + if (zr->norm == std) + return 0; + + if (zr->running != ZORAN_MAP_MODE_NONE) + return -EBUSY; + + res = zoran_set_norm(zr, std); + return res; +} + +static int zoran_enum_input(struct file *file, void *__fh, + struct v4l2_input *inp) +{ + struct zoran *zr = video_drvdata(file); + + if (inp->index >= zr->card.inputs) + return -EINVAL; + + strscpy(inp->name, zr->card.input[inp->index].name, sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; + + /* Get status of video decoder */ + decoder_call(zr, video, g_input_status, &inp->status); + return 0; +} + +static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) +{ + struct zoran *zr = video_drvdata(file); + + *input = zr->input; + + return 0; +} + +static int zoran_s_input(struct file *file, void *__fh, unsigned int input) +{ + struct zoran *zr = video_drvdata(file); + int res; + + if (zr->running != ZORAN_MAP_MODE_NONE) + return -EBUSY; + + res = zoran_set_input(zr, input); + return res; +} + +/* cropping (sub-frame capture) */ +static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel) +{ + struct zoran *zr = video_drvdata(file); + + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pci_dbg(zr->pci_dev, "%s invalid selection type combination\n", __func__); + return -EINVAL; + } + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r.top = zr->jpg_settings.img_y; + sel->r.left = zr->jpg_settings.img_x; + sel->r.width = zr->jpg_settings.img_width; + sel->r.height = zr->jpg_settings.img_height; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = BUZ_MIN_WIDTH; + sel->r.height = BUZ_MIN_HEIGHT; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = BUZ_MAX_WIDTH; + sel->r.height = BUZ_MAX_HEIGHT; + break; + default: + return -EINVAL; + } + return 0; +} + +static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selection *sel) +{ + struct zoran *zr = video_drvdata(file); + struct zoran_jpg_settings settings; + int res; + + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (!sel->r.width || !sel->r.height) + return -EINVAL; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + if (zr->map_mode == ZORAN_MAP_MODE_RAW) { + pci_dbg(zr->pci_dev, "VIDIOC_S_SELECTION - subcapture only supported for compressed capture\n"); + return -EINVAL; + } + + settings = zr->jpg_settings; + + /* move into a form that we understand */ + settings.img_x = sel->r.left; + settings.img_y = sel->r.top; + settings.img_width = sel->r.width; + settings.img_height = sel->r.height; + + /* check validity */ + res = zoran_check_jpg_settings(zr, &settings, 0); + if (res) + return res; + + /* accept */ + zr->jpg_settings = settings; + return res; +} + +/* + * Output is disabled temporarily + * Zoran is picky about jpeg data it accepts. At least it seems to unsupport COM and APPn. + * So until a way to filter data will be done, disable output. + */ +static const struct v4l2_ioctl_ops zoran_ioctl_ops = { + .vidioc_querycap = zoran_querycap, + .vidioc_s_selection = zoran_s_selection, + .vidioc_g_selection = zoran_g_selection, + .vidioc_enum_input = zoran_enum_input, + .vidioc_g_input = zoran_g_input, + .vidioc_s_input = zoran_s_input, + .vidioc_g_std = zoran_g_std, + .vidioc_s_std = zoran_s_std, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_file_operations zoran_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +const struct video_device zoran_template = { + .name = ZORAN_NAME, + .fops = &zoran_fops, + .ioctl_ops = &zoran_ioctl_ops, + .release = &zoran_vdev_release, + .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, +}; + +static int zr_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct zoran *zr = vb2_get_drv_priv(vq); + unsigned int size = zr->buffer_size; + + pci_dbg(zr->pci_dev, "%s nbuf=%u nplanes=%u", __func__, *nbuffers, *nplanes); + + zr->buf_in_reserve = 0; + + if (*nbuffers < vq->min_buffers_needed) + *nbuffers = vq->min_buffers_needed; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + else + return 0; + } + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static void zr_vb2_queue(struct vb2_buffer *vb) +{ + struct zoran *zr = vb2_get_drv_priv(vb->vb2_queue); + struct zr_buffer *buf = vb2_to_zr_buffer(vb); + unsigned long flags; + + spin_lock_irqsave(&zr->queued_bufs_lock, flags); + list_add_tail(&buf->queue, &zr->queued_bufs); + zr->buf_in_reserve++; + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + if (zr->running == ZORAN_MAP_MODE_JPG_REC) + zoran_feed_stat_com(zr); + zr->queued++; +} + +static int zr_vb2_prepare(struct vb2_buffer *vb) +{ + struct zoran *zr = vb2_get_drv_priv(vb->vb2_queue); + + if (vb2_plane_size(vb, 0) < zr->buffer_size) + return -EINVAL; + zr->prepared++; + + return 0; +} + +int zr_set_buf(struct zoran *zr) +{ + struct zr_buffer *buf; + struct vb2_v4l2_buffer *vbuf; + dma_addr_t phys_addr; + unsigned long flags; + u32 reg; + + if (zr->running == ZORAN_MAP_MODE_NONE) + return 0; + + if (zr->inuse[0]) { + buf = zr->inuse[0]; + buf->vbuf.vb2_buf.timestamp = ktime_get_ns(); + buf->vbuf.sequence = zr->vbseq++; + vbuf = &buf->vbuf; + + buf->vbuf.field = V4L2_FIELD_INTERLACED; + if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) + buf->vbuf.field = V4L2_FIELD_INTERLACED; + else + buf->vbuf.field = V4L2_FIELD_TOP; + vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, zr->buffer_size); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE); + zr->inuse[0] = NULL; + } + + spin_lock_irqsave(&zr->queued_bufs_lock, flags); + if (list_empty(&zr->queued_bufs)) { + btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); + vb2_queue_error(zr->video_dev->queue); + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + return -EINVAL; + } + buf = list_first_entry_or_null(&zr->queued_bufs, struct zr_buffer, queue); + if (!buf) { + btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); + vb2_queue_error(zr->video_dev->queue); + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + return -EINVAL; + } + list_del(&buf->queue); + zr->buf_in_reserve--; + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + + vbuf = &buf->vbuf; + vbuf->vb2_buf.state = VB2_BUF_STATE_ACTIVE; + phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); + + if (!phys_addr) + return -EINVAL; + + zr->inuse[0] = buf; + + reg = phys_addr; + btwrite(reg, ZR36057_VDTR); + if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) + reg += zr->v4l_settings.bytesperline; + btwrite(reg, ZR36057_VDBR); + + reg = 0; + if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) + reg += zr->v4l_settings.bytesperline; + reg = (reg << ZR36057_VSSFGR_DISP_STRIDE); + reg |= ZR36057_VSSFGR_VID_OVF; + reg |= ZR36057_VSSFGR_SNAP_SHOT; + reg |= ZR36057_VSSFGR_FRAME_GRAB; + btwrite(reg, ZR36057_VSSFGR); + + btor(ZR36057_VDCR_VID_EN, ZR36057_VDCR); + return 0; +} + +static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct zoran *zr = vq->drv_priv; + int j; + + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = cpu_to_le32(1); + zr->inuse[j] = NULL; + } + zr->vbseq = 0; + + if (zr->map_mode != ZORAN_MAP_MODE_RAW) { + pci_dbg(zr->pci_dev, "START JPG\n"); + zr36057_restart(zr); + zoran_init_hardware(zr); + if (zr->map_mode == ZORAN_MAP_MODE_JPG_REC) + zr36057_enable_jpg(zr, BUZ_MODE_MOTION_DECOMPRESS); + else + zr36057_enable_jpg(zr, BUZ_MODE_MOTION_COMPRESS); + zoran_feed_stat_com(zr); + jpeg_start(zr); + zr->running = zr->map_mode; + btor(ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); + return 0; + } + + pci_dbg(zr->pci_dev, "START RAW\n"); + zr36057_restart(zr); + zoran_init_hardware(zr); + + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + zr36057_set_memgrab(zr, 1); + zr->running = zr->map_mode; + btor(ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); + return 0; +} + +static void zr_vb2_stop_streaming(struct vb2_queue *vq) +{ + struct zoran *zr = vq->drv_priv; + struct zr_buffer *buf; + unsigned long flags; + int j; + + btand(~ZR36057_ICR_INT_PIN_EN, ZR36057_ICR); + if (zr->map_mode != ZORAN_MAP_MODE_RAW) + zr36057_enable_jpg(zr, BUZ_MODE_IDLE); + zr36057_set_memgrab(zr, 0); + zr->running = ZORAN_MAP_MODE_NONE; + + zoran_set_pci_master(zr, 0); + + if (!pass_through) { /* Switch to color bar */ + decoder_call(zr, video, s_stream, 0); + encoder_call(zr, video, s_routing, 2, 0, 0); + } + + for (j = 0; j < BUZ_NUM_STAT_COM; j++) { + zr->stat_com[j] = cpu_to_le32(1); + if (!zr->inuse[j]) + continue; + buf = zr->inuse[j]; + pci_dbg(zr->pci_dev, "%s clean buf %d\n", __func__, j); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + zr->inuse[j] = NULL; + } + + spin_lock_irqsave(&zr->queued_bufs_lock, flags); + while (!list_empty(&zr->queued_bufs)) { + buf = list_entry(zr->queued_bufs.next, struct zr_buffer, queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + zr->buf_in_reserve--; + } + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + if (zr->buf_in_reserve) + pci_dbg(zr->pci_dev, "Buffer remaining %d\n", zr->buf_in_reserve); + zr->map_mode = ZORAN_MAP_MODE_RAW; +} + +static const struct vb2_ops zr_video_qops = { + .queue_setup = zr_vb2_queue_setup, + .buf_queue = zr_vb2_queue, + .buf_prepare = zr_vb2_prepare, + .start_streaming = zr_vb2_start_streaming, + .stop_streaming = zr_vb2_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) +{ + int err; + + spin_lock_init(&zr->queued_bufs_lock); + INIT_LIST_HEAD(&zr->queued_bufs); + + vq->dev = &zr->pci_dev->dev; + vq->type = dir; + + vq->io_modes = VB2_DMABUF | VB2_MMAP; + vq->drv_priv = zr; + vq->buf_struct_size = sizeof(struct zr_buffer); + vq->ops = &zr_video_qops; + vq->mem_ops = &vb2_dma_contig_memops; + vq->gfp_flags = GFP_DMA32; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->min_buffers_needed = 9; + vq->lock = &zr->lock; + err = vb2_queue_init(vq); + if (err) + return err; + zr->video_dev->queue = vq; + return 0; +} + +void zoran_queue_exit(struct zoran *zr) +{ + vb2_queue_release(zr->video_dev->queue); +} diff --git a/drivers/media/pci/zoran/zr36016.c b/drivers/media/pci/zoran/zr36016.c new file mode 100644 index 000000000000..4b328ad6083f --- /dev/null +++ b/drivers/media/pci/zoran/zr36016.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zoran ZR36016 basic configuration functions + * + * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> + +/* headerfile of this module */ +#include "zr36016.h" + +/* codec io API */ +#include "videocodec.h" + +/* + * it doesn't make sense to have more than 20 or so, + * just to prevent some unwanted loops + */ +#define MAX_CODECS 20 + +/* amount of chips attached via this driver */ +static int zr36016_codecs; + +/* + * Local hardware I/O functions: read/write via codec layer + * (registers are located in the master device) + */ + +/* read and write functions */ +static u8 zr36016_read(struct zr36016 *ptr, u16 reg) +{ + u8 value = 0; + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + /* just in case something is wrong... */ + if (ptr->codec->master_data->readreg) + value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF; + else + zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name); + + zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value); + + return value; +} + +static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg); + + // just in case something is wrong... + if (ptr->codec->master_data->writereg) + ptr->codec->master_data->writereg(ptr->codec, reg, value); + else + zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name); +} + +/* + * indirect read and write functions + * + * the 016 supports auto-addr-increment, but + * writing it all time cost not much and is safer... + */ +static u8 zr36016_readi(struct zr36016 *ptr, u16 reg) +{ + u8 value = 0; + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + /* just in case something is wrong... */ + if ((ptr->codec->master_data->writereg) && (ptr->codec->master_data->readreg)) { + ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); + value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; + } else { + zrdev_err(zr, "%s: invalid I/O setup, nothing read (i)!\n", ptr->name); + } + + zrdev_dbg(zr, "%s: reading indirect from 0x%04x: %02x\n", + ptr->name, reg, value); + return value; +} + +static void zr36016_writei(struct zr36016 *ptr, u16 reg, u8 value) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, + value, reg); + + /* just in case something is wrong... */ + if (ptr->codec->master_data->writereg) { + ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); + ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); + } else { + zrdev_err(zr, "%s: invalid I/O setup, nothing written (i)!\n", ptr->name); + } +} + +/* Local helper function: version read */ + +/* version kept in datastructure */ +static u8 zr36016_read_version(struct zr36016 *ptr) +{ + ptr->version = zr36016_read(ptr, 0) >> 4; + return ptr->version; +} + +/* + * Local helper function: basic test of "connectivity", writes/reads + * to/from PAX-Lo register + */ + +static int zr36016_basic_test(struct zr36016 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + if (*KERN_INFO <= CONSOLE_LOGLEVEL_DEFAULT) { + int i; + + zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); + zrdev_dbg(zr, "%s: registers: ", ptr->name); + for (i = 0; i <= 0x0b; i++) + zrdev_dbg(zr, "%02x ", zr36016_readi(ptr, i)); + zrdev_dbg(zr, "\n"); + } + // for testing just write 0, then the default value to a register and read + // it back in both cases + zr36016_writei(ptr, ZR016I_PAX_LO, 0x00); + if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) { + zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name); + return -ENXIO; + } + zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0); + if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) { + zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name); + return -ENXIO; + } + // we allow version numbers from 0-3, should be enough, though + zr36016_read_version(ptr); + if (ptr->version & 0x0c) { + zrdev_err(zr, "%s: attach failed, suspicious version %d found...\n", ptr->name, + ptr->version); + return -ENXIO; + } + + return 0; /* looks good! */ +} + +/* Basic datasets & init */ + +static void zr36016_init(struct zr36016 *ptr) +{ + // stop any processing + zr36016_write(ptr, ZR016_GOSTOP, 0); + + // mode setup (yuv422 in and out, compression/expansuon due to mode) + zr36016_write(ptr, ZR016_MODE, + ZR016_YUV422 | ZR016_YUV422_YUV422 | + (ptr->mode == CODEC_DO_COMPRESSION ? + ZR016_COMPRESSION : ZR016_EXPANSION)); + + // misc setup + zr36016_writei(ptr, ZR016I_SETUP1, + (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) | + (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI); + zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR); + + // Window setup + // (no extra offset for now, norm defines offset, default width height) + zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8); + zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF); + zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8); + zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF); + zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8); + zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF); + zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8); + zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF); + + /* shall we continue now, please? */ + zr36016_write(ptr, ZR016_GOSTOP, 1); +} + +/* + * CODEC API FUNCTIONS + * + * These functions are accessed by the master via the API structure + */ + +/* + * set compression/expansion mode and launches codec - + * this should be the last call from the master before starting processing + */ +static int zr36016_set_mode(struct videocodec *codec, int mode) +{ + struct zr36016 *ptr = (struct zr36016 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + + zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode); + + if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) + return -EINVAL; + + ptr->mode = mode; + zr36016_init(ptr); + + return 0; +} + +/* set picture size */ +static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm, + struct vfe_settings *cap, struct vfe_polarity *pol) +{ + struct zr36016 *ptr = (struct zr36016 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + + zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", + ptr->name, norm->h_start, norm->v_start, + cap->x, cap->y, cap->width, cap->height, + cap->decimation); + + /* + * if () return -EINVAL; + * trust the master driver that it knows what it does - so + * we allow invalid startx/y for now ... + */ + ptr->width = cap->width; + ptr->height = cap->height; + /* + * (Ronald) This is ugly. zoran_device.c, line 387 + * already mentions what happens if h_start is even + * (blue faces, etc., cr/cb inversed). There's probably + * some good reason why h_start is 0 instead of 1, so I'm + * leaving it to this for now, but really... This can be + * done a lot simpler + */ + ptr->xoff = (norm->h_start ? norm->h_start : 1) + cap->x; + /* + * Something to note here (I don't understand it), setting + * v_start too high will cause the codec to 'not work'. I + * really don't get it. values of 16 (v_start) already break + * it here. Just '0' seems to work. More testing needed! + */ + ptr->yoff = norm->v_start + cap->y; + /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */ + ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1; + ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1; + + return 0; +} + +/* additional control functions */ +static int zr36016_control(struct videocodec *codec, int type, int size, void *data) +{ + struct zr36016 *ptr = (struct zr36016 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + int *ival = (int *)data; + + zrdev_dbg(zr, "%s: control %d call with %d byte\n", + ptr->name, type, size); + + switch (type) { + case CODEC_G_STATUS: /* get last status - we don't know it ... */ + if (size != sizeof(int)) + return -EFAULT; + *ival = 0; + break; + + case CODEC_G_CODEC_MODE: + if (size != sizeof(int)) + return -EFAULT; + *ival = 0; + break; + + case CODEC_S_CODEC_MODE: + if (size != sizeof(int)) + return -EFAULT; + if (*ival != 0) + return -EINVAL; + /* not needed, do nothing */ + return 0; + + case CODEC_G_VFE: + case CODEC_S_VFE: + return 0; + + case CODEC_S_MMAP: + /* not available, give an error */ + return -ENXIO; + + default: + return -EINVAL; + } + + return size; +} + +/* + * Exit and unregister function: + * + * Deinitializes Zoran's JPEG processor + */ + +static int zr36016_unset(struct videocodec *codec) +{ + struct zr36016 *ptr = codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + + if (ptr) { + /* do wee need some codec deinit here, too ???? */ + + zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num); + kfree(ptr); + codec->data = NULL; + + zr36016_codecs--; + return 0; + } + + return -EFAULT; +} + +/* + * Setup and registry function: + * + * Initializes Zoran's JPEG processor + * + * Also sets pixel size, average code size, mode (compr./decompr.) + * (the given size is determined by the processor with the video interface) + */ + +static int zr36016_setup(struct videocodec *codec) +{ + struct zr36016 *ptr; + struct zoran *zr = videocodec_to_zoran(codec); + int res; + + zrdev_dbg(zr, "zr36016: initializing VFE subsystem #%d.\n", zr36016_codecs); + + if (zr36016_codecs == MAX_CODECS) { + zrdev_err(zr, "zr36016: Can't attach more codecs!\n"); + return -ENOSPC; + } + //mem structure init + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + codec->data = ptr; + if (!ptr) + return -ENOMEM; + + snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]", zr36016_codecs); + ptr->num = zr36016_codecs++; + ptr->codec = codec; + + //testing + res = zr36016_basic_test(ptr); + if (res < 0) { + zr36016_unset(codec); + return res; + } + //final setup + ptr->mode = CODEC_DO_COMPRESSION; + ptr->width = 768; + ptr->height = 288; + ptr->xdec = 1; + ptr->ydec = 0; + zr36016_init(ptr); + + zrdev_dbg(zr, "%s: codec v%d attached and running\n", + ptr->name, ptr->version); + + return 0; +} + +static const struct videocodec zr36016_codec = { + .name = "zr36016", + .magic = 0L, /* magic not used */ + .flags = + CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER | + CODEC_FLAG_DECODER, + .type = CODEC_TYPE_ZR36016, + .setup = zr36016_setup, /* functionality */ + .unset = zr36016_unset, + .set_mode = zr36016_set_mode, + .set_video = zr36016_set_video, + .control = zr36016_control, + /* others are not used */ +}; + +/* HOOK IN DRIVER AS KERNEL MODULE */ + +int zr36016_init_module(void) +{ + zr36016_codecs = 0; + return videocodec_register(&zr36016_codec); +} + +void zr36016_cleanup_module(void) +{ + if (zr36016_codecs) { + pr_debug("zr36016: something's wrong - %d codecs left somehow.\n", + zr36016_codecs); + } + videocodec_unregister(&zr36016_codec); +} diff --git a/drivers/media/pci/zoran/zr36016.h b/drivers/media/pci/zoran/zr36016.h new file mode 100644 index 000000000000..04afba35669d --- /dev/null +++ b/drivers/media/pci/zoran/zr36016.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Zoran ZR36016 basic configuration functions - header file + * + * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> + */ + +#ifndef ZR36016_H +#define ZR36016_H + +/* data stored for each zoran jpeg codec chip */ +struct zr36016 { + char name[32]; + int num; + /* io datastructure */ + struct videocodec *codec; + // coder status + __u8 version; + // actual coder setup + int mode; + + __u16 xoff; + __u16 yoff; + __u16 width; + __u16 height; + __u16 xdec; + __u16 ydec; +}; + +/* direct register addresses */ +#define ZR016_GOSTOP 0x00 +#define ZR016_MODE 0x01 +#define ZR016_IADDR 0x02 +#define ZR016_IDATA 0x03 + +/* indirect register addresses */ +#define ZR016I_SETUP1 0x00 +#define ZR016I_SETUP2 0x01 +#define ZR016I_NAX_LO 0x02 +#define ZR016I_NAX_HI 0x03 +#define ZR016I_PAX_LO 0x04 +#define ZR016I_PAX_HI 0x05 +#define ZR016I_NAY_LO 0x06 +#define ZR016I_NAY_HI 0x07 +#define ZR016I_PAY_LO 0x08 +#define ZR016I_PAY_HI 0x09 +#define ZR016I_NOL_LO 0x0a +#define ZR016I_NOL_HI 0x0b + +/* possible values for mode register */ +#define ZR016_RGB444_YUV444 0x00 +#define ZR016_RGB444_YUV422 0x01 +#define ZR016_RGB444_YUV411 0x02 +#define ZR016_RGB444_Y400 0x03 +#define ZR016_RGB444_RGB444 0x04 +#define ZR016_YUV444_YUV444 0x08 +#define ZR016_YUV444_YUV422 0x09 +#define ZR016_YUV444_YUV411 0x0a +#define ZR016_YUV444_Y400 0x0b +#define ZR016_YUV444_RGB444 0x0c +#define ZR016_YUV422_YUV422 0x11 +#define ZR016_YUV422_YUV411 0x12 +#define ZR016_YUV422_Y400 0x13 +#define ZR016_YUV411_YUV411 0x16 +#define ZR016_YUV411_Y400 0x17 +#define ZR016_4444_4444 0x19 +#define ZR016_100_100 0x1b + +#define ZR016_RGB444 0x00 +#define ZR016_YUV444 0x20 +#define ZR016_YUV422 0x40 + +#define ZR016_COMPRESSION 0x80 +#define ZR016_EXPANSION 0x80 + +/* possible values for setup 1 register */ +#define ZR016_CKRT 0x80 +#define ZR016_VERT 0x40 +#define ZR016_HORZ 0x20 +#define ZR016_HRFL 0x10 +#define ZR016_DSFL 0x08 +#define ZR016_SBFL 0x04 +#define ZR016_RSTR 0x02 +#define ZR016_CNTI 0x01 + +/* possible values for setup 2 register */ +#define ZR016_SYEN 0x40 +#define ZR016_CCIR 0x04 +#define ZR016_SIGN 0x02 +#define ZR016_YMCS 0x01 + +int zr36016_init_module(void); +void zr36016_cleanup_module(void); +#endif /*fndef ZR36016_H */ diff --git a/drivers/media/pci/zoran/zr36050.c b/drivers/media/pci/zoran/zr36050.c new file mode 100644 index 000000000000..b07d7e5c1b4a --- /dev/null +++ b/drivers/media/pci/zoran/zr36050.c @@ -0,0 +1,817 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zoran ZR36050 basic configuration functions + * + * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#include <linux/types.h> +#include <linux/wait.h> + +/* I/O commands, error codes */ +#include <linux/io.h> + +/* headerfile of this module */ +#include "zr36050.h" + +/* codec io API */ +#include "videocodec.h" + +/* + * it doesn't make sense to have more than 20 or so, + * just to prevent some unwanted loops + */ +#define MAX_CODECS 20 + +/* amount of chips attached via this driver */ +static int zr36050_codecs; + +/* + * Local hardware I/O functions: + * + * read/write via codec layer (registers are located in the master device) + */ + +/* read and write functions */ +static u8 zr36050_read(struct zr36050 *ptr, u16 reg) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + u8 value = 0; + + /* just in case something is wrong... */ + if (ptr->codec->master_data->readreg) + value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF; + else + zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name); + + zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value); + + return value; +} + +static void zr36050_write(struct zr36050 *ptr, u16 reg, u8 value) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg); + + /* just in case something is wrong... */ + if (ptr->codec->master_data->writereg) + ptr->codec->master_data->writereg(ptr->codec, reg, value); + else + zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", + ptr->name); +} + +/* status is kept in datastructure */ +static u8 zr36050_read_status1(struct zr36050 *ptr) +{ + ptr->status1 = zr36050_read(ptr, ZR050_STATUS_1); + + zr36050_read(ptr, 0); + return ptr->status1; +} + +/* scale factor is kept in datastructure */ +static u16 zr36050_read_scalefactor(struct zr36050 *ptr) +{ + ptr->scalefact = (zr36050_read(ptr, ZR050_SF_HI) << 8) | + (zr36050_read(ptr, ZR050_SF_LO) & 0xFF); + + /* leave 0 selected for an eventually GO from master */ + zr36050_read(ptr, 0); + return ptr->scalefact; +} + +/* + * Local helper function: + * + * wait if codec is ready to proceed (end of processing) or time is over + */ + +static void zr36050_wait_end(struct zr36050 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + int i = 0; + + while (!(zr36050_read_status1(ptr) & 0x4)) { + udelay(1); + if (i++ > 200000) { // 200ms, there is for sure something wrong!!! + zrdev_err(zr, + "%s: timeout at wait_end (last status: 0x%02x)\n", + ptr->name, ptr->status1); + break; + } + } +} + +/* + * Local helper function: basic test of "connectivity", writes/reads + * to/from memory the SOF marker + */ + +static int zr36050_basic_test(struct zr36050 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zr36050_write(ptr, ZR050_SOF_IDX, 0x00); + zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00); + if ((zr36050_read(ptr, ZR050_SOF_IDX) | + zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) { + zrdev_err(zr, + "%s: attach failed, can't connect to jpeg processor!\n", + ptr->name); + return -ENXIO; + } + zr36050_write(ptr, ZR050_SOF_IDX, 0xff); + zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0); + if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) | + zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) { + zrdev_err(zr, + "%s: attach failed, can't connect to jpeg processor!\n", + ptr->name); + return -ENXIO; + } + + zr36050_wait_end(ptr); + if ((ptr->status1 & 0x4) == 0) { + zrdev_err(zr, + "%s: attach failed, jpeg processor failed (end flag)!\n", + ptr->name); + return -EBUSY; + } + + return 0; /* looks good! */ +} + +/* Local helper function: simple loop for pushing the init datasets */ + +static int zr36050_pushit(struct zr36050 *ptr, u16 startreg, u16 len, const char *data) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + int i = 0; + + zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, + startreg, len); + while (i < len) + zr36050_write(ptr, startreg++, data[i++]); + + return i; +} + +/* + * Basic datasets: + * + * jpeg baseline setup data (you find it on lots places in internet, or just + * extract it from any regular .jpg image...) + * + * Could be variable, but until it's not needed it they are just fixed to save + * memory. Otherwise expand zr36050 structure with arrays, push the values to + * it and initialize from there, as e.g. the linux zr36057/60 driver does it. + */ + +static const char zr36050_dqt[0x86] = { + 0xff, 0xdb, //Marker: DQT + 0x00, 0x84, //Length: 2*65+2 + 0x00, //Pq,Tq first table + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0x01, //Pq,Tq second table + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 +}; + +static const char zr36050_dht[0x1a4] = { + 0xff, 0xc4, //Marker: DHT + 0x01, 0xa2, //Length: 2*AC, 2*DC + 0x00, //DC first table + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x01, //DC second table + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x10, //AC first table + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, + 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, + 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, + 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, + 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, + 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, + 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, + 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, + 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, + 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, + 0x11, //AC second table + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, + 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, + 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, + 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, + 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, + 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, + 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, + 0xF9, 0xFA +}; + +/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */ +#define NO_OF_COMPONENTS 0x3 //Y,U,V +#define BASELINE_PRECISION 0x8 //MCU size (?) +static const char zr36050_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT +static const char zr36050_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC +static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC + +/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */ +static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; +static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; + +/* + * Local helper functions: + * + * calculation and setup of parameter-dependent JPEG baseline segments + * (needed for compression only) + */ + +/* ------------------------------------------------------------------------- */ + +/* + * SOF (start of frame) segment depends on width, height and sampling ratio + * of each color component + */ +static int zr36050_set_sof(struct zr36050 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + char sof_data[34]; // max. size of register set + int i; + + zrdev_dbg(zr, "%s: write SOF (%dx%d, %d components)\n", ptr->name, + ptr->width, ptr->height, NO_OF_COMPONENTS); + sof_data[0] = 0xff; + sof_data[1] = 0xc0; + sof_data[2] = 0x00; + sof_data[3] = (3 * NO_OF_COMPONENTS) + 8; + sof_data[4] = BASELINE_PRECISION; // only '8' possible with zr36050 + sof_data[5] = (ptr->height) >> 8; + sof_data[6] = (ptr->height) & 0xff; + sof_data[7] = (ptr->width) >> 8; + sof_data[8] = (ptr->width) & 0xff; + sof_data[9] = NO_OF_COMPONENTS; + for (i = 0; i < NO_OF_COMPONENTS; i++) { + sof_data[10 + (i * 3)] = i; // index identifier + sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | + (ptr->v_samp_ratio[i]); // sampling ratios + sof_data[12 + (i * 3)] = zr36050_tq[i]; // Q table selection + } + return zr36050_pushit(ptr, ZR050_SOF_IDX, + (3 * NO_OF_COMPONENTS) + 10, sof_data); +} + +/* ------------------------------------------------------------------------- */ + +/* + * SOS (start of scan) segment depends on the used scan components + * of each color component + */ + +static int zr36050_set_sos(struct zr36050 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + char sos_data[16]; // max. size of register set + int i; + + zrdev_dbg(zr, "%s: write SOS\n", ptr->name); + sos_data[0] = 0xff; + sos_data[1] = 0xda; + sos_data[2] = 0x00; + sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3; + sos_data[4] = NO_OF_COMPONENTS; + for (i = 0; i < NO_OF_COMPONENTS; i++) { + sos_data[5 + (i * 2)] = i; // index + sos_data[6 + (i * 2)] = (zr36050_td[i] << 4) | zr36050_ta[i]; // AC/DC tbl.sel. + } + sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00; // scan start + sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3F; + sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00; + return zr36050_pushit(ptr, ZR050_SOS1_IDX, + 4 + 1 + (2 * NO_OF_COMPONENTS) + 3, + sos_data); +} + +/* ------------------------------------------------------------------------- */ + +/* DRI (define restart interval) */ + +static int zr36050_set_dri(struct zr36050 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + char dri_data[6]; // max. size of register set + + zrdev_dbg(zr, "%s: write DRI\n", ptr->name); + dri_data[0] = 0xff; + dri_data[1] = 0xdd; + dri_data[2] = 0x00; + dri_data[3] = 0x04; + dri_data[4] = ptr->dri >> 8; + dri_data[5] = ptr->dri & 0xff; + return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data); +} + +/* + * Setup function: + * + * Setup compression/decompression of Zoran's JPEG processor + * ( see also zoran 36050 manual ) + * + * ... sorry for the spaghetti code ... + */ +static void zr36050_init(struct zr36050 *ptr) +{ + int sum = 0; + long bitcnt, tmp; + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + if (ptr->mode == CODEC_DO_COMPRESSION) { + zrdev_dbg(zr, "%s: COMPRESSION SETUP\n", ptr->name); + + /* 050 communicates with 057 in master mode */ + zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR); + + /* encoding table preload for compression */ + zr36050_write(ptr, ZR050_MODE, + ZR050_MO_COMP | ZR050_MO_TLM); + zr36050_write(ptr, ZR050_OPTIONS, 0); + + /* disable all IRQs */ + zr36050_write(ptr, ZR050_INT_REQ_0, 0); + zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 + + /* volume control settings */ + /*zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol);*/ + zr36050_write(ptr, ZR050_SF_HI, ptr->scalefact >> 8); + zr36050_write(ptr, ZR050_SF_LO, ptr->scalefact & 0xff); + + zr36050_write(ptr, ZR050_AF_HI, 0xff); + zr36050_write(ptr, ZR050_AF_M, 0xff); + zr36050_write(ptr, ZR050_AF_LO, 0xff); + + /* setup the variable jpeg tables */ + sum += zr36050_set_sof(ptr); + sum += zr36050_set_sos(ptr); + sum += zr36050_set_dri(ptr); + + /* + * setup the fixed jpeg tables - maybe variable, though - + * (see table init section above) + */ + zrdev_dbg(zr, "%s: write DQT, DHT, APP\n", ptr->name); + sum += zr36050_pushit(ptr, ZR050_DQT_IDX, + sizeof(zr36050_dqt), zr36050_dqt); + sum += zr36050_pushit(ptr, ZR050_DHT_IDX, + sizeof(zr36050_dht), zr36050_dht); + zr36050_write(ptr, ZR050_APP_IDX, 0xff); + zr36050_write(ptr, ZR050_APP_IDX + 1, 0xe0 + ptr->app.appn); + zr36050_write(ptr, ZR050_APP_IDX + 2, 0x00); + zr36050_write(ptr, ZR050_APP_IDX + 3, ptr->app.len + 2); + sum += zr36050_pushit(ptr, ZR050_APP_IDX + 4, 60, + ptr->app.data) + 4; + zr36050_write(ptr, ZR050_COM_IDX, 0xff); + zr36050_write(ptr, ZR050_COM_IDX + 1, 0xfe); + zr36050_write(ptr, ZR050_COM_IDX + 2, 0x00); + zr36050_write(ptr, ZR050_COM_IDX + 3, ptr->com.len + 2); + sum += zr36050_pushit(ptr, ZR050_COM_IDX + 4, 60, + ptr->com.data) + 4; + + /* do the internal huffman table preload */ + zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); + + zr36050_write(ptr, ZR050_GO, 1); // launch codec + zr36050_wait_end(ptr); + zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n", + ptr->name, ptr->status1); + + if ((ptr->status1 & 0x4) == 0) { + zrdev_err(zr, "%s: init aborted!\n", ptr->name); + return; // something is wrong, its timed out!!!! + } + + /* setup misc. data for compression (target code sizes) */ + + /* size of compressed code to reach without header data */ + sum = ptr->real_code_vol - sum; + bitcnt = sum << 3; /* need the size in bits */ + + tmp = bitcnt >> 16; + zrdev_dbg(zr, + "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", + ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); + zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8); + zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff); + tmp = bitcnt & 0xffff; + zr36050_write(ptr, ZR050_TCV_NET_ML, tmp >> 8); + zr36050_write(ptr, ZR050_TCV_NET_LO, tmp & 0xff); + + bitcnt -= bitcnt >> 7; // bits without stuffing + bitcnt -= ((bitcnt * 5) >> 6); // bits without eob + + tmp = bitcnt >> 16; + zrdev_dbg(zr, "%s: code: nettobit=%ld, highnettobits=%ld\n", + ptr->name, bitcnt, tmp); + zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8); + zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff); + tmp = bitcnt & 0xffff; + zr36050_write(ptr, ZR050_TCV_DATA_ML, tmp >> 8); + zr36050_write(ptr, ZR050_TCV_DATA_LO, tmp & 0xff); + + /* compression setup with or without bitrate control */ + zr36050_write(ptr, ZR050_MODE, + ZR050_MO_COMP | ZR050_MO_PASS2 | + (ptr->bitrate_ctrl ? ZR050_MO_BRC : 0)); + + /* this headers seem to deliver "valid AVI" jpeg frames */ + zr36050_write(ptr, ZR050_MARKERS_EN, + ZR050_ME_DQT | ZR050_ME_DHT | + ((ptr->app.len > 0) ? ZR050_ME_APP : 0) | + ((ptr->com.len > 0) ? ZR050_ME_COM : 0)); + } else { + zrdev_dbg(zr, "%s: EXPANSION SETUP\n", ptr->name); + + /* 050 communicates with 055 in master mode */ + zr36050_write(ptr, ZR050_HARDWARE, + ZR050_HW_MSTR | ZR050_HW_CFIS_2_CLK); + + /* encoding table preload */ + zr36050_write(ptr, ZR050_MODE, ZR050_MO_TLM); + + /* disable all IRQs */ + zr36050_write(ptr, ZR050_INT_REQ_0, 0); + zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 + + zrdev_dbg(zr, "%s: write DHT\n", ptr->name); + zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht), + zr36050_dht); + + /* do the internal huffman table preload */ + zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); + + zr36050_write(ptr, ZR050_GO, 1); // launch codec + zr36050_wait_end(ptr); + zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n", + ptr->name, ptr->status1); + + if ((ptr->status1 & 0x4) == 0) { + zrdev_err(zr, "%s: init aborted!\n", ptr->name); + return; // something is wrong, its timed out!!!! + } + + /* setup misc. data for expansion */ + zr36050_write(ptr, ZR050_MODE, 0); + zr36050_write(ptr, ZR050_MARKERS_EN, 0); + } + + /* adr on selected, to allow GO from master */ + zr36050_read(ptr, 0); +} + +/* + * CODEC API FUNCTIONS + * + * this functions are accessed by the master via the API structure + */ + +/* + * set compression/expansion mode and launches codec - + * this should be the last call from the master before starting processing + */ +static int zr36050_set_mode(struct videocodec *codec, int mode) +{ + struct zr36050 *ptr = (struct zr36050 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + + zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode); + + if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) + return -EINVAL; + + ptr->mode = mode; + zr36050_init(ptr); + + return 0; +} + +/* set picture size (norm is ignored as the codec doesn't know about it) */ +static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm, + struct vfe_settings *cap, struct vfe_polarity *pol) +{ + struct zr36050 *ptr = (struct zr36050 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + int size; + + zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n", + ptr->name, norm->h_start, norm->v_start, + cap->x, cap->y, cap->width, cap->height, + cap->decimation, cap->quality); + /* + * trust the master driver that it knows what it does - so + * we allow invalid startx/y and norm for now ... + */ + ptr->width = cap->width / (cap->decimation & 0xff); + ptr->height = cap->height / ((cap->decimation >> 8) & 0xff); + + /* (KM) JPEG quality */ + size = ptr->width * ptr->height; + size *= 16; /* size in bits */ + /* apply quality setting */ + size = size * cap->quality / 200; + + /* Minimum: 1kb */ + if (size < 8192) + size = 8192; + /* Maximum: 7/8 of code buffer */ + if (size > ptr->total_code_vol * 7) + size = ptr->total_code_vol * 7; + + ptr->real_code_vol = size >> 3; /* in bytes */ + + /* + * Set max_block_vol here (previously in zr36050_init, moved + * here for consistency with zr36060 code + */ + zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol); + + return 0; +} + +/* additional control functions */ +static int zr36050_control(struct videocodec *codec, int type, int size, void *data) +{ + struct zr36050 *ptr = (struct zr36050 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + int *ival = (int *)data; + + zrdev_dbg(zr, "%s: control %d call with %d byte\n", ptr->name, type, + size); + + switch (type) { + case CODEC_G_STATUS: /* get last status */ + if (size != sizeof(int)) + return -EFAULT; + zr36050_read_status1(ptr); + *ival = ptr->status1; + break; + + case CODEC_G_CODEC_MODE: + if (size != sizeof(int)) + return -EFAULT; + *ival = CODEC_MODE_BJPG; + break; + + case CODEC_S_CODEC_MODE: + if (size != sizeof(int)) + return -EFAULT; + if (*ival != CODEC_MODE_BJPG) + return -EINVAL; + /* not needed, do nothing */ + return 0; + + case CODEC_G_VFE: + case CODEC_S_VFE: + /* not needed, do nothing */ + return 0; + + case CODEC_S_MMAP: + /* not available, give an error */ + return -ENXIO; + + case CODEC_G_JPEG_TDS_BYTE: /* get target volume in byte */ + if (size != sizeof(int)) + return -EFAULT; + *ival = ptr->total_code_vol; + break; + + case CODEC_S_JPEG_TDS_BYTE: /* get target volume in byte */ + if (size != sizeof(int)) + return -EFAULT; + ptr->total_code_vol = *ival; + ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; + break; + + case CODEC_G_JPEG_SCALE: /* get scaling factor */ + if (size != sizeof(int)) + return -EFAULT; + *ival = zr36050_read_scalefactor(ptr); + break; + + case CODEC_S_JPEG_SCALE: /* set scaling factor */ + if (size != sizeof(int)) + return -EFAULT; + ptr->scalefact = *ival; + break; + + case CODEC_G_JPEG_APP_DATA: { /* get appn marker data */ + struct jpeg_app_marker *app = data; + + if (size != sizeof(struct jpeg_app_marker)) + return -EFAULT; + + *app = ptr->app; + break; + } + + case CODEC_S_JPEG_APP_DATA: { /* set appn marker data */ + struct jpeg_app_marker *app = data; + + if (size != sizeof(struct jpeg_app_marker)) + return -EFAULT; + + ptr->app = *app; + break; + } + + case CODEC_G_JPEG_COM_DATA: { /* get comment marker data */ + struct jpeg_com_marker *com = data; + + if (size != sizeof(struct jpeg_com_marker)) + return -EFAULT; + + *com = ptr->com; + break; + } + + case CODEC_S_JPEG_COM_DATA: { /* set comment marker data */ + struct jpeg_com_marker *com = data; + + if (size != sizeof(struct jpeg_com_marker)) + return -EFAULT; + + ptr->com = *com; + break; + } + + default: + return -EINVAL; + } + + return size; +} + +/* Exit and unregister function: Deinitializes Zoran's JPEG processor */ + +static int zr36050_unset(struct videocodec *codec) +{ + struct zr36050 *ptr = codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + + if (ptr) { + /* do wee need some codec deinit here, too ???? */ + + zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, + ptr->num); + kfree(ptr); + codec->data = NULL; + + zr36050_codecs--; + return 0; + } + + return -EFAULT; +} + +/* + * Setup and registry function: + * + * Initializes Zoran's JPEG processor + * + * Also sets pixel size, average code size, mode (compr./decompr.) + * (the given size is determined by the processor with the video interface) + */ + +static int zr36050_setup(struct videocodec *codec) +{ + struct zr36050 *ptr; + struct zoran *zr = videocodec_to_zoran(codec); + int res; + + zrdev_dbg(zr, "zr36050: initializing MJPEG subsystem #%d.\n", + zr36050_codecs); + + if (zr36050_codecs == MAX_CODECS) { + zrdev_err(zr, + "zr36050: Can't attach more codecs!\n"); + return -ENOSPC; + } + //mem structure init + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + codec->data = ptr; + if (!ptr) + return -ENOMEM; + + snprintf(ptr->name, sizeof(ptr->name), "zr36050[%d]", + zr36050_codecs); + ptr->num = zr36050_codecs++; + ptr->codec = codec; + + //testing + res = zr36050_basic_test(ptr); + if (res < 0) { + zr36050_unset(codec); + return res; + } + //final setup + memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8); + memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8); + + /* 0 or 1 - fixed file size flag (what is the difference?) */ + ptr->bitrate_ctrl = 0; + ptr->mode = CODEC_DO_COMPRESSION; + ptr->width = 384; + ptr->height = 288; + ptr->total_code_vol = 16000; + ptr->max_block_vol = 240; + ptr->scalefact = 0x100; + ptr->dri = 1; + + /* no app/com marker by default */ + ptr->app.appn = 0; + ptr->app.len = 0; + ptr->com.len = 0; + + zr36050_init(ptr); + + zrdev_info(zr, "%s: codec attached and running\n", + ptr->name); + + return 0; +} + +static const struct videocodec zr36050_codec = { + .name = "zr36050", + .magic = 0L, // magic not used + .flags = + CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER | + CODEC_FLAG_DECODER, + .type = CODEC_TYPE_ZR36050, + .setup = zr36050_setup, // functionality + .unset = zr36050_unset, + .set_mode = zr36050_set_mode, + .set_video = zr36050_set_video, + .control = zr36050_control, + // others are not used +}; + +/* HOOK IN DRIVER AS KERNEL MODULE */ + +int zr36050_init_module(void) +{ + zr36050_codecs = 0; + return videocodec_register(&zr36050_codec); +} + +void zr36050_cleanup_module(void) +{ + if (zr36050_codecs) { + pr_debug("zr36050: something's wrong - %d codecs left somehow.\n", + zr36050_codecs); + } + videocodec_unregister(&zr36050_codec); +} diff --git a/drivers/media/pci/zoran/zr36050.h b/drivers/media/pci/zoran/zr36050.h new file mode 100644 index 000000000000..f9b58f4c77b9 --- /dev/null +++ b/drivers/media/pci/zoran/zr36050.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Zoran ZR36050 basic configuration functions - header file + * + * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> + */ + +#ifndef ZR36050_H +#define ZR36050_H + +#include "videocodec.h" + +/* data stored for each zoran jpeg codec chip */ +struct zr36050 { + char name[32]; + int num; + /* io datastructure */ + struct videocodec *codec; + // last coder status + __u8 status1; + // actual coder setup + int mode; + + __u16 width; + __u16 height; + + __u16 bitrate_ctrl; + + __u32 total_code_vol; + __u32 real_code_vol; + __u16 max_block_vol; + + __u8 h_samp_ratio[8]; + __u8 v_samp_ratio[8]; + __u16 scalefact; + __u16 dri; + + /* com/app marker */ + struct jpeg_com_marker com; + struct jpeg_app_marker app; +}; + +/* zr36050 register addresses */ +#define ZR050_GO 0x000 +#define ZR050_HARDWARE 0x002 +#define ZR050_MODE 0x003 +#define ZR050_OPTIONS 0x004 +#define ZR050_MBCV 0x005 +#define ZR050_MARKERS_EN 0x006 +#define ZR050_INT_REQ_0 0x007 +#define ZR050_INT_REQ_1 0x008 +#define ZR050_TCV_NET_HI 0x009 +#define ZR050_TCV_NET_MH 0x00a +#define ZR050_TCV_NET_ML 0x00b +#define ZR050_TCV_NET_LO 0x00c +#define ZR050_TCV_DATA_HI 0x00d +#define ZR050_TCV_DATA_MH 0x00e +#define ZR050_TCV_DATA_ML 0x00f +#define ZR050_TCV_DATA_LO 0x010 +#define ZR050_SF_HI 0x011 +#define ZR050_SF_LO 0x012 +#define ZR050_AF_HI 0x013 +#define ZR050_AF_M 0x014 +#define ZR050_AF_LO 0x015 +#define ZR050_ACV_HI 0x016 +#define ZR050_ACV_MH 0x017 +#define ZR050_ACV_ML 0x018 +#define ZR050_ACV_LO 0x019 +#define ZR050_ACT_HI 0x01a +#define ZR050_ACT_MH 0x01b +#define ZR050_ACT_ML 0x01c +#define ZR050_ACT_LO 0x01d +#define ZR050_ACV_TURN_HI 0x01e +#define ZR050_ACV_TURN_MH 0x01f +#define ZR050_ACV_TURN_ML 0x020 +#define ZR050_ACV_TURN_LO 0x021 +#define ZR050_STATUS_0 0x02e +#define ZR050_STATUS_1 0x02f + +#define ZR050_SOF_IDX 0x040 +#define ZR050_SOS1_IDX 0x07a +#define ZR050_SOS2_IDX 0x08a +#define ZR050_SOS3_IDX 0x09a +#define ZR050_SOS4_IDX 0x0aa +#define ZR050_DRI_IDX 0x0c0 +#define ZR050_DNL_IDX 0x0c6 +#define ZR050_DQT_IDX 0x0cc +#define ZR050_DHT_IDX 0x1d4 +#define ZR050_APP_IDX 0x380 +#define ZR050_COM_IDX 0x3c0 + +/* zr36050 hardware register bits */ + +#define ZR050_HW_BSWD 0x80 +#define ZR050_HW_MSTR 0x40 +#define ZR050_HW_DMA 0x20 +#define ZR050_HW_CFIS_1_CLK 0x00 +#define ZR050_HW_CFIS_2_CLK 0x04 +#define ZR050_HW_CFIS_3_CLK 0x08 +#define ZR050_HW_CFIS_4_CLK 0x0C +#define ZR050_HW_CFIS_5_CLK 0x10 +#define ZR050_HW_CFIS_6_CLK 0x14 +#define ZR050_HW_CFIS_7_CLK 0x18 +#define ZR050_HW_CFIS_8_CLK 0x1C +#define ZR050_HW_BELE 0x01 + +/* zr36050 mode register bits */ + +#define ZR050_MO_COMP 0x80 +#define ZR050_MO_ATP 0x40 +#define ZR050_MO_PASS2 0x20 +#define ZR050_MO_TLM 0x10 +#define ZR050_MO_DCONLY 0x08 +#define ZR050_MO_BRC 0x04 + +#define ZR050_MO_ATP 0x40 +#define ZR050_MO_PASS2 0x20 +#define ZR050_MO_TLM 0x10 +#define ZR050_MO_DCONLY 0x08 + +/* zr36050 option register bits */ + +#define ZR050_OP_NSCN_1 0x00 +#define ZR050_OP_NSCN_2 0x20 +#define ZR050_OP_NSCN_3 0x40 +#define ZR050_OP_NSCN_4 0x60 +#define ZR050_OP_NSCN_5 0x80 +#define ZR050_OP_NSCN_6 0xA0 +#define ZR050_OP_NSCN_7 0xC0 +#define ZR050_OP_NSCN_8 0xE0 +#define ZR050_OP_OVF 0x10 + +/* zr36050 markers-enable register bits */ + +#define ZR050_ME_APP 0x80 +#define ZR050_ME_COM 0x40 +#define ZR050_ME_DRI 0x20 +#define ZR050_ME_DQT 0x10 +#define ZR050_ME_DHT 0x08 +#define ZR050_ME_DNL 0x04 +#define ZR050_ME_DQTI 0x02 +#define ZR050_ME_DHTI 0x01 + +/* zr36050 status0/1 register bit masks */ + +#define ZR050_ST_RST_MASK 0x20 +#define ZR050_ST_SOF_MASK 0x02 +#define ZR050_ST_SOS_MASK 0x02 +#define ZR050_ST_DATRDY_MASK 0x80 +#define ZR050_ST_MRKDET_MASK 0x40 +#define ZR050_ST_RFM_MASK 0x10 +#define ZR050_ST_RFD_MASK 0x08 +#define ZR050_ST_END_MASK 0x04 +#define ZR050_ST_TCVOVF_MASK 0x02 +#define ZR050_ST_DATOVF_MASK 0x01 + +/* pixel component idx */ + +#define ZR050_Y_COMPONENT 0 +#define ZR050_U_COMPONENT 1 +#define ZR050_V_COMPONENT 2 + +int zr36050_init_module(void); +void zr36050_cleanup_module(void); +#endif /*fndef ZR36050_H */ diff --git a/drivers/media/pci/zoran/zr36057.h b/drivers/media/pci/zoran/zr36057.h new file mode 100644 index 000000000000..45d8afc62b37 --- /dev/null +++ b/drivers/media/pci/zoran/zr36057.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * zr36057.h - zr36057 register offsets + * + * Copyright (C) 1998 Dave Perks <dperks@ibm.net> + */ + +#ifndef _ZR36057_H_ +#define _ZR36057_H_ + +/* Zoran ZR36057 registers */ + +#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ +#define ZR36057_VFEHCR_HS_POL BIT(30) +#define ZR36057_VFEHCR_H_START 10 +#define ZR36057_VFEHCR_H_END 0 +#define ZR36057_VFEHCR_HMASK 0x3ff + +#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ +#define ZR36057_VFEVCR_VS_POL BIT(30) +#define ZR36057_VFEVCR_V_START 10 +#define ZR36057_VFEVCR_V_END 0 +#define ZR36057_VFEVCR_VMASK 0x3ff + +#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ +#define ZR36057_VFESPFR_EXT_FL BIT(26) +#define ZR36057_VFESPFR_TOP_FIELD BIT(25) +#define ZR36057_VFESPFR_VCLK_POL BIT(24) +#define ZR36057_VFESPFR_H_FILTER 21 +#define ZR36057_VFESPFR_HOR_DCM 14 +#define ZR36057_VFESPFR_VER_DCM 8 +#define ZR36057_VFESPFR_DISP_MODE 6 +#define ZR36057_VFESPFR_YUV422 (0 << 3) +#define ZR36057_VFESPFR_RGB888 (1 << 3) +#define ZR36057_VFESPFR_RGB565 (2 << 3) +#define ZR36057_VFESPFR_RGB555 (3 << 3) +#define ZR36057_VFESPFR_ERR_DIF BIT(2) +#define ZR36057_VFESPFR_PACK24 BIT(1) +#define ZR36057_VFESPFR_LITTLE_ENDIAN BIT(0) + +#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ + +#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ + +#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ +#define ZR36057_VSSFGR_DISP_STRIDE 16 +#define ZR36057_VSSFGR_VID_OVF BIT(8) +#define ZR36057_VSSFGR_SNAP_SHOT BIT(1) +#define ZR36057_VSSFGR_FRAME_GRAB BIT(0) + +#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ +#define ZR36057_VDCR_VID_EN BIT(31) +#define ZR36057_VDCR_MIN_PIX 24 +#define ZR36057_VDCR_TRITON BIT(24) +#define ZR36057_VDCR_VID_WIN_HT 12 +#define ZR36057_VDCR_VID_WIN_WID 0 + +#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ + +#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ + +#define ZR36057_OCR 0x024 /* Overlay Control Register */ +#define ZR36057_OCR_OVL_ENABLE BIT(15) +#define ZR36057_OCR_MASK_STRIDE 0 + +#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ +#define ZR36057_SPGPPCR_SOFT_RESET BIT(24) + +#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ + +#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ + +#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ +#define ZR36057_MCTCR_COD_TIME BIT(30) +#define ZR36057_MCTCR_C_EMPTY BIT(29) +#define ZR36057_MCTCR_C_FLUSH BIT(28) +#define ZR36057_MCTCR_COD_GUEST_ID 20 +#define ZR36057_MCTCR_COD_GUEST_REG 16 + +#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ + +#define ZR36057_ISR 0x03c /* Interrupt Status Register */ +#define ZR36057_ISR_GIRQ1 BIT(30) +#define ZR36057_ISR_GIRQ0 BIT(29) +#define ZR36057_ISR_COD_REP_IRQ BIT(28) +#define ZR36057_ISR_JPEG_REP_IRQ BIT(27) + +#define ZR36057_ICR 0x040 /* Interrupt Control Register */ +#define ZR36057_ICR_GIRQ1 BIT(30) +#define ZR36057_ICR_GIRQ0 BIT(29) +#define ZR36057_ICR_COD_REP_IRQ BIT(28) +#define ZR36057_ICR_JPEG_REP_IRQ BIT(27) +#define ZR36057_ICR_INT_PIN_EN BIT(24) + +#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ +#define ZR36057_I2CBR_SDA BIT(1) +#define ZR36057_I2CBR_SCL BIT(0) + +#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ +#define ZR36057_JMC_JPG BIT(31) +#define ZR36057_JMC_JPG_EXP_MODE (0 << 29) +#define ZR36057_JMC_JPG_CMP_MODE BIT(29) +#define ZR36057_JMC_MJPG_EXP_MODE (2 << 29) +#define ZR36057_JMC_MJPG_CMP_MODE (3 << 29) +#define ZR36057_JMC_RTBUSY_FB BIT(6) +#define ZR36057_JMC_GO_EN BIT(5) +#define ZR36057_JMC_SYNC_MSTR BIT(4) +#define ZR36057_JMC_FLD_PER_BUFF BIT(3) +#define ZR36057_JMC_VFIFO_FB BIT(2) +#define ZR36057_JMC_CFIFO_FB BIT(1) +#define ZR36057_JMC_STLL_LIT_ENDIAN BIT(0) + +#define ZR36057_JPC 0x104 /* JPEG Process Control */ +#define ZR36057_JPC_P_RESET BIT(7) +#define ZR36057_JPC_COD_TRNS_EN BIT(5) +#define ZR36057_JPC_ACTIVE BIT(0) + +#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ +#define ZR36057_VSP_VSYNC_SIZE 16 +#define ZR36057_VSP_FRM_TOT 0 + +#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ +#define ZR36057_HSP_HSYNC_START 16 +#define ZR36057_HSP_LINE_TOT 0 + +#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ +#define ZR36057_FHAP_NAX 16 +#define ZR36057_FHAP_PAX 0 + +#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ +#define ZR36057_FVAP_NAY 16 +#define ZR36057_FVAP_PAY 0 + +#define ZR36057_FPP 0x118 /* Field Process Parameters */ +#define ZR36057_FPP_ODD_EVEN BIT(0) + +#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ + +#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ + +#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ +#define ZR36057_JCGI_JPE_GUEST_ID 4 +#define ZR36057_JCGI_JPE_GUEST_REG 0 + +#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ + +#define ZR36057_POR 0x200 /* Post Office Register */ +#define ZR36057_POR_PO_PEN BIT(25) +#define ZR36057_POR_PO_TIME BIT(24) +#define ZR36057_POR_PO_DIR BIT(23) + +#define ZR36057_STR 0x300 /* "Still" Transfer Register */ + +#endif diff --git a/drivers/media/pci/zoran/zr36060.c b/drivers/media/pci/zoran/zr36060.c new file mode 100644 index 000000000000..75fd167603dc --- /dev/null +++ b/drivers/media/pci/zoran/zr36060.c @@ -0,0 +1,870 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Zoran ZR36060 basic configuration functions + * + * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be> + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/delay.h> + +#include <linux/types.h> +#include <linux/wait.h> + +/* I/O commands, error codes */ +#include <linux/io.h> + +/* headerfile of this module */ +#include "zr36060.h" + +/* codec io API */ +#include "videocodec.h" + +/* it doesn't make sense to have more than 20 or so, just to prevent some unwanted loops */ +#define MAX_CODECS 20 + +/* amount of chips attached via this driver */ +static int zr36060_codecs; + +static bool low_bitrate; +module_param(low_bitrate, bool, 0); +MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate"); + +/* ========================================================================= + * Local hardware I/O functions: + * read/write via codec layer (registers are located in the master device) + * ========================================================================= + */ + +static u8 zr36060_read(struct zr36060 *ptr, u16 reg) +{ + u8 value = 0; + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + // just in case something is wrong... + if (ptr->codec->master_data->readreg) + value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xff; + else + zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name); + + return value; +} + +static void zr36060_write(struct zr36060 *ptr, u16 reg, u8 value) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + zrdev_dbg(zr, "0x%02x @0x%04x\n", value, reg); + + // just in case something is wrong... + if (ptr->codec->master_data->writereg) + ptr->codec->master_data->writereg(ptr->codec, reg, value); + else + zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name); +} + +/* ========================================================================= + * Local helper function: + * status read + * ========================================================================= + */ + +/* status is kept in datastructure */ +static u8 zr36060_read_status(struct zr36060 *ptr) +{ + ptr->status = zr36060_read(ptr, ZR060_CFSR); + + zr36060_read(ptr, 0); + return ptr->status; +} + +/* scale factor is kept in datastructure */ +static u16 zr36060_read_scalefactor(struct zr36060 *ptr) +{ + ptr->scalefact = (zr36060_read(ptr, ZR060_SF_HI) << 8) | + (zr36060_read(ptr, ZR060_SF_LO) & 0xFF); + + /* leave 0 selected for an eventually GO from master */ + zr36060_read(ptr, 0); + return ptr->scalefact; +} + +/* wait if codec is ready to proceed (end of processing) or time is over */ +static void zr36060_wait_end(struct zr36060 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + int i = 0; + + while (zr36060_read_status(ptr) & ZR060_CFSR_BUSY) { + udelay(1); + if (i++ > 200000) { // 200ms, there is for sure something wrong!!! + zrdev_dbg(zr, + "%s: timeout at wait_end (last status: 0x%02x)\n", + ptr->name, ptr->status); + break; + } + } +} + +/* Basic test of "connectivity", writes/reads to/from memory the SOF marker */ +static int zr36060_basic_test(struct zr36060 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + if ((zr36060_read(ptr, ZR060_IDR_DEV) != 0x33) && + (zr36060_read(ptr, ZR060_IDR_REV) != 0x01)) { + zrdev_err(zr, "%s: attach failed, can't connect to jpeg processor!\n", ptr->name); + return -ENXIO; + } + + zr36060_wait_end(ptr); + if (ptr->status & ZR060_CFSR_BUSY) { + zrdev_err(zr, "%s: attach failed, jpeg processor failed (end flag)!\n", ptr->name); + return -EBUSY; + } + + return 0; /* looks good! */ +} + +/* simple loop for pushing the init datasets */ +static int zr36060_pushit(struct zr36060 *ptr, u16 startreg, u16 len, const char *data) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + int i = 0; + + zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, + startreg, len); + while (i < len) + zr36060_write(ptr, startreg++, data[i++]); + + return i; +} + +/* ========================================================================= + * Basic datasets: + * jpeg baseline setup data (you find it on lots places in internet, or just + * extract it from any regular .jpg image...) + * + * Could be variable, but until it's not needed it they are just fixed to save + * memory. Otherwise expand zr36060 structure with arrays, push the values to + * it and initialize from there, as e.g. the linux zr36057/60 driver does it. + * ========================================================================= + */ +static const char zr36060_dqt[0x86] = { + 0xff, 0xdb, //Marker: DQT + 0x00, 0x84, //Length: 2*65+2 + 0x00, //Pq,Tq first table + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0x01, //Pq,Tq second table + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 +}; + +static const char zr36060_dht[0x1a4] = { + 0xff, 0xc4, //Marker: DHT + 0x01, 0xa2, //Length: 2*AC, 2*DC + 0x00, //DC first table + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x01, //DC second table + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x10, //AC first table + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, + 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, + 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, + 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, + 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, + 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, + 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, + 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, + 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, + 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, + 0x11, //AC second table + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, + 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, + 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, + 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, + 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, + 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, + 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, + 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, + 0xF9, 0xFA +}; + +/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */ +#define NO_OF_COMPONENTS 0x3 //Y,U,V +#define BASELINE_PRECISION 0x8 //MCU size (?) +static const char zr36060_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT +static const char zr36060_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC +static const char zr36060_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC + +/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */ +static const char zr36060_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; +static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; + +/* + * SOF (start of frame) segment depends on width, height and sampling ratio + * of each color component + */ +static int zr36060_set_sof(struct zr36060 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + char sof_data[34]; // max. size of register set + int i; + + zrdev_dbg(zr, "%s: write SOF (%dx%d, %d components)\n", ptr->name, + ptr->width, ptr->height, NO_OF_COMPONENTS); + sof_data[0] = 0xff; + sof_data[1] = 0xc0; + sof_data[2] = 0x00; + sof_data[3] = (3 * NO_OF_COMPONENTS) + 8; + sof_data[4] = BASELINE_PRECISION; // only '8' possible with zr36060 + sof_data[5] = (ptr->height) >> 8; + sof_data[6] = (ptr->height) & 0xff; + sof_data[7] = (ptr->width) >> 8; + sof_data[8] = (ptr->width) & 0xff; + sof_data[9] = NO_OF_COMPONENTS; + for (i = 0; i < NO_OF_COMPONENTS; i++) { + sof_data[10 + (i * 3)] = i; // index identifier + sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | + (ptr->v_samp_ratio[i]); // sampling ratios + sof_data[12 + (i * 3)] = zr36060_tq[i]; // Q table selection + } + return zr36060_pushit(ptr, ZR060_SOF_IDX, + (3 * NO_OF_COMPONENTS) + 10, sof_data); +} + +/* SOS (start of scan) segment depends on the used scan components of each color component */ +static int zr36060_set_sos(struct zr36060 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + char sos_data[16]; // max. size of register set + int i; + + zrdev_dbg(zr, "%s: write SOS\n", ptr->name); + sos_data[0] = 0xff; + sos_data[1] = 0xda; + sos_data[2] = 0x00; + sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3; + sos_data[4] = NO_OF_COMPONENTS; + for (i = 0; i < NO_OF_COMPONENTS; i++) { + sos_data[5 + (i * 2)] = i; // index + sos_data[6 + (i * 2)] = (zr36060_td[i] << 4) | + zr36060_ta[i]; // AC/DC tbl.sel. + } + sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00; // scan start + sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3f; + sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00; + return zr36060_pushit(ptr, ZR060_SOS_IDX, + 4 + 1 + (2 * NO_OF_COMPONENTS) + 3, + sos_data); +} + +/* DRI (define restart interval) */ +static int zr36060_set_dri(struct zr36060 *ptr) +{ + struct zoran *zr = videocodec_to_zoran(ptr->codec); + char dri_data[6]; // max. size of register set + + zrdev_dbg(zr, "%s: write DRI\n", ptr->name); + dri_data[0] = 0xff; + dri_data[1] = 0xdd; + dri_data[2] = 0x00; + dri_data[3] = 0x04; + dri_data[4] = (ptr->dri) >> 8; + dri_data[5] = (ptr->dri) & 0xff; + return zr36060_pushit(ptr, ZR060_DRI_IDX, 6, dri_data); +} + +/* Setup compression/decompression of Zoran's JPEG processor ( see also zoran 36060 manual ) + * ... sorry for the spaghetti code ... + */ +static void zr36060_init(struct zr36060 *ptr) +{ + int sum = 0; + long bitcnt, tmp; + struct zoran *zr = videocodec_to_zoran(ptr->codec); + + if (ptr->mode == CODEC_DO_COMPRESSION) { + zrdev_dbg(zr, "%s: COMPRESSION SETUP\n", ptr->name); + + zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST); + + /* 060 communicates with 067 in master mode */ + zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CODE_MSTR); + + /* Compression with or without variable scale factor */ + /*FIXME: What about ptr->bitrate_ctrl? */ + zr36060_write(ptr, ZR060_CMR, ZR060_CMR_COMP | ZR060_CMR_PASS2 | ZR060_CMR_BRB); + + /* Must be zero */ + zr36060_write(ptr, ZR060_MBZ, 0x00); + zr36060_write(ptr, ZR060_TCR_HI, 0x00); + zr36060_write(ptr, ZR060_TCR_LO, 0x00); + + /* Disable all IRQs - no DataErr means autoreset */ + zr36060_write(ptr, ZR060_IMR, 0); + + /* volume control settings */ + zr36060_write(ptr, ZR060_SF_HI, ptr->scalefact >> 8); + zr36060_write(ptr, ZR060_SF_LO, ptr->scalefact & 0xff); + + zr36060_write(ptr, ZR060_AF_HI, 0xff); + zr36060_write(ptr, ZR060_AF_M, 0xff); + zr36060_write(ptr, ZR060_AF_LO, 0xff); + + /* setup the variable jpeg tables */ + sum += zr36060_set_sof(ptr); + sum += zr36060_set_sos(ptr); + sum += zr36060_set_dri(ptr); + +/* setup the fixed jpeg tables - maybe variable, though - (see table init section above) */ + sum += zr36060_pushit(ptr, ZR060_DQT_IDX, sizeof(zr36060_dqt), zr36060_dqt); + sum += zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht), zr36060_dht); + zr36060_write(ptr, ZR060_APP_IDX, 0xff); + zr36060_write(ptr, ZR060_APP_IDX + 1, 0xe0 + ptr->app.appn); + zr36060_write(ptr, ZR060_APP_IDX + 2, 0x00); + zr36060_write(ptr, ZR060_APP_IDX + 3, ptr->app.len + 2); + sum += zr36060_pushit(ptr, ZR060_APP_IDX + 4, 60, ptr->app.data) + 4; + zr36060_write(ptr, ZR060_COM_IDX, 0xff); + zr36060_write(ptr, ZR060_COM_IDX + 1, 0xfe); + zr36060_write(ptr, ZR060_COM_IDX + 2, 0x00); + zr36060_write(ptr, ZR060_COM_IDX + 3, ptr->com.len + 2); + sum += zr36060_pushit(ptr, ZR060_COM_IDX + 4, 60, ptr->com.data) + 4; + + /* setup misc. data for compression (target code sizes) */ + + /* size of compressed code to reach without header data */ + sum = ptr->real_code_vol - sum; + bitcnt = sum << 3; /* need the size in bits */ + + tmp = bitcnt >> 16; + zrdev_dbg(zr, + "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", + ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); + zr36060_write(ptr, ZR060_TCV_NET_HI, tmp >> 8); + zr36060_write(ptr, ZR060_TCV_NET_MH, tmp & 0xff); + tmp = bitcnt & 0xffff; + zr36060_write(ptr, ZR060_TCV_NET_ML, tmp >> 8); + zr36060_write(ptr, ZR060_TCV_NET_LO, tmp & 0xff); + + bitcnt -= bitcnt >> 7; // bits without stuffing + bitcnt -= ((bitcnt * 5) >> 6); // bits without eob + + tmp = bitcnt >> 16; + zrdev_dbg(zr, "%s: code: nettobit=%ld, highnettobits=%ld\n", + ptr->name, bitcnt, tmp); + zr36060_write(ptr, ZR060_TCV_DATA_HI, tmp >> 8); + zr36060_write(ptr, ZR060_TCV_DATA_MH, tmp & 0xff); + tmp = bitcnt & 0xffff; + zr36060_write(ptr, ZR060_TCV_DATA_ML, tmp >> 8); + zr36060_write(ptr, ZR060_TCV_DATA_LO, tmp & 0xff); + + /* JPEG markers to be included in the compressed stream */ + zr36060_write(ptr, ZR060_MER, + ZR060_MER_DQT | ZR060_MER_DHT | + ((ptr->com.len > 0) ? ZR060_MER_COM : 0) | + ((ptr->app.len > 0) ? ZR060_MER_APP : 0)); + + /* Setup the Video Frontend */ + /* Limit pixel range to 16..235 as per CCIR-601 */ + zr36060_write(ptr, ZR060_VCR, ZR060_VCR_RANGE); + + } else { + zrdev_dbg(zr, "%s: EXPANSION SETUP\n", ptr->name); + + zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST); + + /* 060 communicates with 067 in master mode */ + zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CODE_MSTR); + + /* Decompression */ + zr36060_write(ptr, ZR060_CMR, 0); + + /* Must be zero */ + zr36060_write(ptr, ZR060_MBZ, 0x00); + zr36060_write(ptr, ZR060_TCR_HI, 0x00); + zr36060_write(ptr, ZR060_TCR_LO, 0x00); + + /* Disable all IRQs - no DataErr means autoreset */ + zr36060_write(ptr, ZR060_IMR, 0); + + /* setup misc. data for expansion */ + zr36060_write(ptr, ZR060_MER, 0); + +/* setup the fixed jpeg tables - maybe variable, though - (see table init section above) */ + zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht), zr36060_dht); + + /* Setup the Video Frontend */ + //zr36060_write(ptr, ZR060_VCR, ZR060_VCR_FI_EXT); + //this doesn't seem right and doesn't work... + zr36060_write(ptr, ZR060_VCR, ZR060_VCR_RANGE); + } + + /* Load the tables */ + zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST | ZR060_LOAD_LOAD); + zr36060_wait_end(ptr); + zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n", + ptr->name, ptr->status); + + if (ptr->status & ZR060_CFSR_BUSY) { + zrdev_err(zr, "%s: init aborted!\n", ptr->name); + return; // something is wrong, its timed out!!!! + } +} + +/* ========================================================================= + * CODEC API FUNCTIONS + * this functions are accessed by the master via the API structure + * ========================================================================= + */ + +/* set compressiion/expansion mode and launches codec - + * this should be the last call from the master before starting processing + */ +static int zr36060_set_mode(struct videocodec *codec, int mode) +{ + struct zr36060 *ptr = (struct zr36060 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + + zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode); + + if (mode != CODEC_DO_EXPANSION && mode != CODEC_DO_COMPRESSION) + return -EINVAL; + + ptr->mode = mode; + zr36060_init(ptr); + + return 0; +} + +/* set picture size (norm is ignored as the codec doesn't know about it) */ +static int zr36060_set_video(struct videocodec *codec, const struct tvnorm *norm, + struct vfe_settings *cap, struct vfe_polarity *pol) +{ + struct zr36060 *ptr = (struct zr36060 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + u32 reg; + int size; + + zrdev_dbg(zr, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name, + cap->x, cap->y, cap->width, cap->height, cap->decimation); + + /* if () return -EINVAL; + * trust the master driver that it knows what it does - so + * we allow invalid startx/y and norm for now ... + */ + ptr->width = cap->width / (cap->decimation & 0xff); + ptr->height = cap->height / (cap->decimation >> 8); + + zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST); + + /* Note that VSPol/HSPol bits in zr36060 have the opposite + * meaning of their zr360x7 counterparts with the same names + * N.b. for VSPol this is only true if FIVEdge = 0 (default, + * left unchanged here - in accordance with datasheet). + */ + reg = (!pol->vsync_pol ? ZR060_VPR_VS_POL : 0) + | (!pol->hsync_pol ? ZR060_VPR_HS_POL : 0) + | (pol->field_pol ? ZR060_VPR_FI_POL : 0) + | (pol->blank_pol ? ZR060_VPR_BL_POL : 0) + | (pol->subimg_pol ? ZR060_VPR_S_IMG_POL : 0) + | (pol->poe_pol ? ZR060_VPR_POE_POL : 0) + | (pol->pvalid_pol ? ZR060_VPR_P_VAL_POL : 0) + | (pol->vclk_pol ? ZR060_VPR_VCLK_POL : 0); + zr36060_write(ptr, ZR060_VPR, reg); + + reg = 0; + switch (cap->decimation & 0xff) { + default: + case 1: + break; + + case 2: + reg |= ZR060_SR_H_SCALE2; + break; + + case 4: + reg |= ZR060_SR_H_SCALE4; + break; + } + + switch (cap->decimation >> 8) { + default: + case 1: + break; + + case 2: + reg |= ZR060_SR_V_SCALE; + break; + } + zr36060_write(ptr, ZR060_SR, reg); + + zr36060_write(ptr, ZR060_BCR_Y, 0x00); + zr36060_write(ptr, ZR060_BCR_U, 0x80); + zr36060_write(ptr, ZR060_BCR_V, 0x80); + + /* sync generator */ + + reg = norm->ht - 1; /* Vtotal */ + zr36060_write(ptr, ZR060_SGR_VTOTAL_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SGR_VTOTAL_LO, (reg >> 0) & 0xff); + + reg = norm->wt - 1; /* Htotal */ + zr36060_write(ptr, ZR060_SGR_HTOTAL_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SGR_HTOTAL_LO, (reg >> 0) & 0xff); + + reg = 6 - 1; /* VsyncSize */ + zr36060_write(ptr, ZR060_SGR_VSYNC, reg); + + reg = 68; + zr36060_write(ptr, ZR060_SGR_HSYNC, reg); + + reg = norm->v_start - 1; /* BVstart */ + zr36060_write(ptr, ZR060_SGR_BVSTART, reg); + + reg += norm->ha / 2; /* BVend */ + zr36060_write(ptr, ZR060_SGR_BVEND_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SGR_BVEND_LO, (reg >> 0) & 0xff); + + reg = norm->h_start - 1; /* BHstart */ + zr36060_write(ptr, ZR060_SGR_BHSTART, reg); + + reg += norm->wa; /* BHend */ + zr36060_write(ptr, ZR060_SGR_BHEND_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SGR_BHEND_LO, (reg >> 0) & 0xff); + + /* active area */ + reg = cap->y + norm->v_start; /* Vstart */ + zr36060_write(ptr, ZR060_AAR_VSTART_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_AAR_VSTART_LO, (reg >> 0) & 0xff); + + reg += cap->height; /* Vend */ + zr36060_write(ptr, ZR060_AAR_VEND_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_AAR_VEND_LO, (reg >> 0) & 0xff); + + reg = cap->x + norm->h_start; /* Hstart */ + zr36060_write(ptr, ZR060_AAR_HSTART_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_AAR_HSTART_LO, (reg >> 0) & 0xff); + + reg += cap->width; /* Hend */ + zr36060_write(ptr, ZR060_AAR_HEND_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_AAR_HEND_LO, (reg >> 0) & 0xff); + + /* subimage area */ + reg = norm->v_start - 4; /* SVstart */ + zr36060_write(ptr, ZR060_SWR_VSTART_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SWR_VSTART_LO, (reg >> 0) & 0xff); + + reg += norm->ha / 2 + 8; /* SVend */ + zr36060_write(ptr, ZR060_SWR_VEND_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SWR_VEND_LO, (reg >> 0) & 0xff); + + reg = norm->h_start /*+ 64 */ - 4; /* SHstart */ + zr36060_write(ptr, ZR060_SWR_HSTART_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SWR_HSTART_LO, (reg >> 0) & 0xff); + + reg += norm->wa + 8; /* SHend */ + zr36060_write(ptr, ZR060_SWR_HEND_HI, (reg >> 8) & 0xff); + zr36060_write(ptr, ZR060_SWR_HEND_LO, (reg >> 0) & 0xff); + + size = ptr->width * ptr->height; + /* Target compressed field size in bits: */ + size = size * 16; /* uncompressed size in bits */ + /* (Ronald) by default, quality = 100 is a compression + * ratio 1:2. Setting low_bitrate (insmod option) sets + * it to 1:4 (instead of 1:2, zr36060 max) as limit because the + * buz can't handle more at decimation=1... Use low_bitrate if + * you have a Buz, unless you know what you're doing + */ + size = size * cap->quality / (low_bitrate ? 400 : 200); + /* Lower limit (arbitrary, 1 KB) */ + if (size < 8192) + size = 8192; + /* Upper limit: 7/8 of the code buffers */ + if (size > ptr->total_code_vol * 7) + size = ptr->total_code_vol * 7; + + ptr->real_code_vol = size >> 3; /* in bytes */ + + /* the MBCVR is the *maximum* block volume, according to the + * JPEG ISO specs, this shouldn't be used, since that allows + * for the best encoding quality. So set it to it's max value + */ + reg = ptr->max_block_vol; + zr36060_write(ptr, ZR060_MBCVR, reg); + + return 0; +} + +/* additional control functions */ +static int zr36060_control(struct videocodec *codec, int type, int size, void *data) +{ + struct zr36060 *ptr = (struct zr36060 *)codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + int *ival = (int *)data; + + zrdev_dbg(zr, "%s: control %d call with %d byte\n", ptr->name, type, + size); + + switch (type) { + case CODEC_G_STATUS: /* get last status */ + if (size != sizeof(int)) + return -EFAULT; + zr36060_read_status(ptr); + *ival = ptr->status; + break; + + case CODEC_G_CODEC_MODE: + if (size != sizeof(int)) + return -EFAULT; + *ival = CODEC_MODE_BJPG; + break; + + case CODEC_S_CODEC_MODE: + if (size != sizeof(int)) + return -EFAULT; + if (*ival != CODEC_MODE_BJPG) + return -EINVAL; + /* not needed, do nothing */ + return 0; + + case CODEC_G_VFE: + case CODEC_S_VFE: + /* not needed, do nothing */ + return 0; + + case CODEC_S_MMAP: + /* not available, give an error */ + return -ENXIO; + + case CODEC_G_JPEG_TDS_BYTE: /* get target volume in byte */ + if (size != sizeof(int)) + return -EFAULT; + *ival = ptr->total_code_vol; + break; + + case CODEC_S_JPEG_TDS_BYTE: /* get target volume in byte */ + if (size != sizeof(int)) + return -EFAULT; + ptr->total_code_vol = *ival; + ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; + break; + + case CODEC_G_JPEG_SCALE: /* get scaling factor */ + if (size != sizeof(int)) + return -EFAULT; + *ival = zr36060_read_scalefactor(ptr); + break; + + case CODEC_S_JPEG_SCALE: /* set scaling factor */ + if (size != sizeof(int)) + return -EFAULT; + ptr->scalefact = *ival; + break; + + case CODEC_G_JPEG_APP_DATA: { /* get appn marker data */ + struct jpeg_app_marker *app = data; + + if (size != sizeof(struct jpeg_app_marker)) + return -EFAULT; + + *app = ptr->app; + break; + } + + case CODEC_S_JPEG_APP_DATA: { /* set appn marker data */ + struct jpeg_app_marker *app = data; + + if (size != sizeof(struct jpeg_app_marker)) + return -EFAULT; + + ptr->app = *app; + break; + } + + case CODEC_G_JPEG_COM_DATA: { /* get comment marker data */ + struct jpeg_com_marker *com = data; + + if (size != sizeof(struct jpeg_com_marker)) + return -EFAULT; + + *com = ptr->com; + break; + } + + case CODEC_S_JPEG_COM_DATA: { /* set comment marker data */ + struct jpeg_com_marker *com = data; + + if (size != sizeof(struct jpeg_com_marker)) + return -EFAULT; + + ptr->com = *com; + break; + } + + default: + return -EINVAL; + } + + return size; +} + +/* ========================================================================= + * Exit and unregister function: + * Deinitializes Zoran's JPEG processor + * ========================================================================= + */ +static int zr36060_unset(struct videocodec *codec) +{ + struct zr36060 *ptr = codec->data; + struct zoran *zr = videocodec_to_zoran(codec); + + if (ptr) { + /* do wee need some codec deinit here, too ???? */ + + zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num); + kfree(ptr); + codec->data = NULL; + + zr36060_codecs--; + return 0; + } + + return -EFAULT; +} + +/* ========================================================================= + * Setup and registry function: + * Initializes Zoran's JPEG processor + * Also sets pixel size, average code size, mode (compr./decompr.) + * (the given size is determined by the processor with the video interface) + * ========================================================================= + */ +static int zr36060_setup(struct videocodec *codec) +{ + struct zr36060 *ptr; + struct zoran *zr = videocodec_to_zoran(codec); + int res; + + zrdev_dbg(zr, "zr36060: initializing MJPEG subsystem #%d.\n", + zr36060_codecs); + + if (zr36060_codecs == MAX_CODECS) { + zrdev_err(zr, "zr36060: Can't attach more codecs!\n"); + return -ENOSPC; + } + //mem structure init + ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); + codec->data = ptr; + if (!ptr) + return -ENOMEM; + + snprintf(ptr->name, sizeof(ptr->name), "zr36060[%d]", zr36060_codecs); + ptr->num = zr36060_codecs++; + ptr->codec = codec; + + //testing + res = zr36060_basic_test(ptr); + if (res < 0) { + zr36060_unset(codec); + return res; + } + //final setup + memcpy(ptr->h_samp_ratio, zr36060_decimation_h, 8); + memcpy(ptr->v_samp_ratio, zr36060_decimation_v, 8); + + ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag (what is the difference?) */ + ptr->mode = CODEC_DO_COMPRESSION; + ptr->width = 384; + ptr->height = 288; + ptr->total_code_vol = 16000; /* CHECKME */ + ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; + ptr->max_block_vol = 240; /* CHECKME, was 120 is 240 */ + ptr->scalefact = 0x100; + ptr->dri = 1; /* CHECKME, was 8 is 1 */ + + /* by default, no COM or APP markers - app should set those */ + ptr->com.len = 0; + ptr->app.appn = 0; + ptr->app.len = 0; + + zr36060_init(ptr); + + zrdev_info(zr, "%s: codec attached and running\n", ptr->name); + + return 0; +} + +static const struct videocodec zr36060_codec = { + .name = "zr36060", + .magic = 0L, // magic not used + .flags = + CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER | + CODEC_FLAG_DECODER | CODEC_FLAG_VFE, + .type = CODEC_TYPE_ZR36060, + .setup = zr36060_setup, // functionality + .unset = zr36060_unset, + .set_mode = zr36060_set_mode, + .set_video = zr36060_set_video, + .control = zr36060_control, + // others are not used +}; + +int zr36060_init_module(void) +{ + zr36060_codecs = 0; + return videocodec_register(&zr36060_codec); +} + +void zr36060_cleanup_module(void) +{ + if (zr36060_codecs) { + pr_debug("zr36060: something's wrong - %d codecs left somehow.\n", + zr36060_codecs); + } + + /* however, we can't just stay alive */ + videocodec_unregister(&zr36060_codec); +} diff --git a/drivers/media/pci/zoran/zr36060.h b/drivers/media/pci/zoran/zr36060.h new file mode 100644 index 000000000000..75c88677a4bd --- /dev/null +++ b/drivers/media/pci/zoran/zr36060.h @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Zoran ZR36060 basic configuration functions - header file + * + * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be> + */ + +#ifndef ZR36060_H +#define ZR36060_H + +#include "videocodec.h" + +/* data stored for each zoran jpeg codec chip */ +struct zr36060 { + char name[32]; + int num; + /* io datastructure */ + struct videocodec *codec; + // last coder status + __u8 status; + // actual coder setup + int mode; + + __u16 width; + __u16 height; + + __u16 bitrate_ctrl; + + __u32 total_code_vol; + __u32 real_code_vol; + __u16 max_block_vol; + + __u8 h_samp_ratio[8]; + __u8 v_samp_ratio[8]; + __u16 scalefact; + __u16 dri; + + /* app/com marker data */ + struct jpeg_app_marker app; + struct jpeg_com_marker com; +}; + +/* ZR36060 register addresses */ +#define ZR060_LOAD 0x000 +#define ZR060_CFSR 0x001 +#define ZR060_CIR 0x002 +#define ZR060_CMR 0x003 +#define ZR060_MBZ 0x004 +#define ZR060_MBCVR 0x005 +#define ZR060_MER 0x006 +#define ZR060_IMR 0x007 +#define ZR060_ISR 0x008 +#define ZR060_TCV_NET_HI 0x009 +#define ZR060_TCV_NET_MH 0x00a +#define ZR060_TCV_NET_ML 0x00b +#define ZR060_TCV_NET_LO 0x00c +#define ZR060_TCV_DATA_HI 0x00d +#define ZR060_TCV_DATA_MH 0x00e +#define ZR060_TCV_DATA_ML 0x00f +#define ZR060_TCV_DATA_LO 0x010 +#define ZR060_SF_HI 0x011 +#define ZR060_SF_LO 0x012 +#define ZR060_AF_HI 0x013 +#define ZR060_AF_M 0x014 +#define ZR060_AF_LO 0x015 +#define ZR060_ACV_HI 0x016 +#define ZR060_ACV_MH 0x017 +#define ZR060_ACV_ML 0x018 +#define ZR060_ACV_LO 0x019 +#define ZR060_ACT_HI 0x01a +#define ZR060_ACT_MH 0x01b +#define ZR060_ACT_ML 0x01c +#define ZR060_ACT_LO 0x01d +#define ZR060_ACV_TURN_HI 0x01e +#define ZR060_ACV_TURN_MH 0x01f +#define ZR060_ACV_TURN_ML 0x020 +#define ZR060_ACV_TURN_LO 0x021 +#define ZR060_IDR_DEV 0x022 +#define ZR060_IDR_REV 0x023 +#define ZR060_TCR_HI 0x024 +#define ZR060_TCR_LO 0x025 +#define ZR060_VCR 0x030 +#define ZR060_VPR 0x031 +#define ZR060_SR 0x032 +#define ZR060_BCR_Y 0x033 +#define ZR060_BCR_U 0x034 +#define ZR060_BCR_V 0x035 +#define ZR060_SGR_VTOTAL_HI 0x036 +#define ZR060_SGR_VTOTAL_LO 0x037 +#define ZR060_SGR_HTOTAL_HI 0x038 +#define ZR060_SGR_HTOTAL_LO 0x039 +#define ZR060_SGR_VSYNC 0x03a +#define ZR060_SGR_HSYNC 0x03b +#define ZR060_SGR_BVSTART 0x03c +#define ZR060_SGR_BHSTART 0x03d +#define ZR060_SGR_BVEND_HI 0x03e +#define ZR060_SGR_BVEND_LO 0x03f +#define ZR060_SGR_BHEND_HI 0x040 +#define ZR060_SGR_BHEND_LO 0x041 +#define ZR060_AAR_VSTART_HI 0x042 +#define ZR060_AAR_VSTART_LO 0x043 +#define ZR060_AAR_VEND_HI 0x044 +#define ZR060_AAR_VEND_LO 0x045 +#define ZR060_AAR_HSTART_HI 0x046 +#define ZR060_AAR_HSTART_LO 0x047 +#define ZR060_AAR_HEND_HI 0x048 +#define ZR060_AAR_HEND_LO 0x049 +#define ZR060_SWR_VSTART_HI 0x04a +#define ZR060_SWR_VSTART_LO 0x04b +#define ZR060_SWR_VEND_HI 0x04c +#define ZR060_SWR_VEND_LO 0x04d +#define ZR060_SWR_HSTART_HI 0x04e +#define ZR060_SWR_HSTART_LO 0x04f +#define ZR060_SWR_HEND_HI 0x050 +#define ZR060_SWR_HEND_LO 0x051 + +#define ZR060_SOF_IDX 0x060 +#define ZR060_SOS_IDX 0x07a +#define ZR060_DRI_IDX 0x0c0 +#define ZR060_DQT_IDX 0x0cc +#define ZR060_DHT_IDX 0x1d4 +#define ZR060_APP_IDX 0x380 +#define ZR060_COM_IDX 0x3c0 + +/* ZR36060 LOAD register bits */ + +#define ZR060_LOAD_LOAD BIT(7) +#define ZR060_LOAD_SYNC_RST BIT(0) + +/* ZR36060 Code FIFO Status register bits */ + +#define ZR060_CFSR_BUSY BIT(7) +#define ZR060_CFSR_C_BUSY BIT(2) +#define ZR060_CFSR_CFIFO (3 << 0) + +/* ZR36060 Code Interface register */ + +#define ZR060_CIR_CODE16 BIT(7) +#define ZR060_CIR_ENDIAN BIT(6) +#define ZR060_CIR_CFIS BIT(2) +#define ZR060_CIR_CODE_MSTR BIT(0) + +/* ZR36060 Codec Mode register */ + +#define ZR060_CMR_COMP BIT(7) +#define ZR060_CMR_ATP BIT(6) +#define ZR060_CMR_PASS2 BIT(5) +#define ZR060_CMR_TLM BIT(4) +#define ZR060_CMR_BRB BIT(2) +#define ZR060_CMR_FSF BIT(1) + +/* ZR36060 Markers Enable register */ + +#define ZR060_MER_APP BIT(7) +#define ZR060_MER_COM BIT(6) +#define ZR060_MER_DRI BIT(5) +#define ZR060_MER_DQT BIT(4) +#define ZR060_MER_DHT BIT(3) + +/* ZR36060 Interrupt Mask register */ + +#define ZR060_IMR_EOAV BIT(3) +#define ZR060_IMR_EOI BIT(2) +#define ZR060_IMR_END BIT(1) +#define ZR060_IMR_DATA_ERR BIT(0) + +/* ZR36060 Interrupt Status register */ + +#define ZR060_ISR_PRO_CNT (3 << 6) +#define ZR060_ISR_EOAV BIT(3) +#define ZR060_ISR_EOI BIT(2) +#define ZR060_ISR_END BIT(1) +#define ZR060_ISR_DATA_ERR BIT(0) + +/* ZR36060 Video Control register */ + +#define ZR060_VCR_VIDEO8 BIT(7) +#define ZR060_VCR_RANGE BIT(6) +#define ZR060_VCR_FI_DET BIT(3) +#define ZR060_VCR_FI_VEDGE BIT(2) +#define ZR060_VCR_FI_EXT BIT(1) +#define ZR060_VCR_SYNC_MSTR BIT(0) + +/* ZR36060 Video Polarity register */ + +#define ZR060_VPR_VCLK_POL BIT(7) +#define ZR060_VPR_P_VAL_POL BIT(6) +#define ZR060_VPR_POE_POL BIT(5) +#define ZR060_VPR_S_IMG_POL BIT(4) +#define ZR060_VPR_BL_POL BIT(3) +#define ZR060_VPR_FI_POL BIT(2) +#define ZR060_VPR_HS_POL BIT(1) +#define ZR060_VPR_VS_POL BIT(0) + +/* ZR36060 Scaling register */ + +#define ZR060_SR_V_SCALE BIT(2) +#define ZR060_SR_H_SCALE2 BIT(0) +#define ZR060_SR_H_SCALE4 (2 << 0) + +int zr36060_init_module(void); +void zr36060_cleanup_module(void); +#endif /*fndef ZR36060_H */ |