/drivers/media/video/bt8xx/bttv-driver.c
https://gitlab.com/TeamCarbonXtreme/android_kernel_samsung_msm7x27 · C · 4686 lines · 3673 code · 648 blank · 365 comment · 526 complexity · 3ad34d4704e6da8f65252d4e13f90884 MD5 · raw file
Large files are truncated click here to view the full file
- /*
- bttv - Bt848 frame grabber driver
- Copyright (C) 1996,97,98 Ralph Metzler <rjkm@thp.uni-koeln.de>
- & Marcus Metzler <mocm@thp.uni-koeln.de>
- (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
- some v4l2 code lines are taken from Justin's bttv2 driver which is
- (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
- V4L1 removal from:
- (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
- Fixes to be fully V4L2 compliant by
- (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
- Cropping and overscan support
- Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
- Sponsored by OPQ Systems AB
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/errno.h>
- #include <linux/fs.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/smp_lock.h>
- #include <linux/interrupt.h>
- #include <linux/kdev_t.h>
- #include "bttvp.h"
- #include <media/v4l2-common.h>
- #include <media/v4l2-ioctl.h>
- #include <media/tvaudio.h>
- #include <media/msp3400.h>
- #include <linux/dma-mapping.h>
- #include <asm/io.h>
- #include <asm/byteorder.h>
- #include <media/rds.h>
- unsigned int bttv_num; /* number of Bt848s in use */
- struct bttv *bttvs[BTTV_MAX];
- unsigned int bttv_debug;
- unsigned int bttv_verbose = 1;
- unsigned int bttv_gpio;
- /* config variables */
- #ifdef __BIG_ENDIAN
- static unsigned int bigendian=1;
- #else
- static unsigned int bigendian;
- #endif
- static unsigned int radio[BTTV_MAX];
- static unsigned int irq_debug;
- static unsigned int gbuffers = 8;
- static unsigned int gbufsize = 0x208000;
- static unsigned int reset_crop = 1;
- static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
- static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
- static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
- static int debug_latency;
- static int disable_ir;
- static unsigned int fdsr;
- /* options */
- static unsigned int combfilter;
- static unsigned int lumafilter;
- static unsigned int automute = 1;
- static unsigned int chroma_agc;
- static unsigned int adc_crush = 1;
- static unsigned int whitecrush_upper = 0xCF;
- static unsigned int whitecrush_lower = 0x7F;
- static unsigned int vcr_hack;
- static unsigned int irq_iswitch;
- static unsigned int uv_ratio = 50;
- static unsigned int full_luma_range;
- static unsigned int coring;
- /* API features (turn on/off stuff for testing) */
- static unsigned int v4l2 = 1;
- /* insmod args */
- module_param(bttv_verbose, int, 0644);
- module_param(bttv_gpio, int, 0644);
- module_param(bttv_debug, int, 0644);
- module_param(irq_debug, int, 0644);
- module_param(debug_latency, int, 0644);
- module_param(disable_ir, int, 0444);
- module_param(fdsr, int, 0444);
- module_param(gbuffers, int, 0444);
- module_param(gbufsize, int, 0444);
- module_param(reset_crop, int, 0444);
- module_param(v4l2, int, 0644);
- module_param(bigendian, int, 0644);
- module_param(irq_iswitch, int, 0644);
- module_param(combfilter, int, 0444);
- module_param(lumafilter, int, 0444);
- module_param(automute, int, 0444);
- module_param(chroma_agc, int, 0444);
- module_param(adc_crush, int, 0444);
- module_param(whitecrush_upper, int, 0444);
- module_param(whitecrush_lower, int, 0444);
- module_param(vcr_hack, int, 0444);
- module_param(uv_ratio, int, 0444);
- module_param(full_luma_range, int, 0444);
- module_param(coring, int, 0444);
- module_param_array(radio, int, NULL, 0444);
- module_param_array(video_nr, int, NULL, 0444);
- module_param_array(radio_nr, int, NULL, 0444);
- module_param_array(vbi_nr, int, NULL, 0444);
- MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
- MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
- MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
- MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
- MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
- MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
- MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
- MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
- MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
- MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
- "is 1 (yes) for compatibility with older applications");
- MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
- MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
- MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
- MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
- MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
- MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
- MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
- MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
- MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
- MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
- MODULE_PARM_DESC(video_nr, "video device numbers");
- MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
- MODULE_PARM_DESC(radio_nr, "radio device numbers");
- MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
- MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
- MODULE_LICENSE("GPL");
- /* ----------------------------------------------------------------------- */
- /* sysfs */
- static ssize_t show_card(struct device *cd,
- struct device_attribute *attr, char *buf)
- {
- struct video_device *vfd = container_of(cd, struct video_device, dev);
- struct bttv *btv = video_get_drvdata(vfd);
- return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
- }
- static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
- /* ----------------------------------------------------------------------- */
- /* dvb auto-load setup */
- #if defined(CONFIG_MODULES) && defined(MODULE)
- static void request_module_async(struct work_struct *work)
- {
- request_module("dvb-bt8xx");
- }
- static void request_modules(struct bttv *dev)
- {
- INIT_WORK(&dev->request_module_wk, request_module_async);
- schedule_work(&dev->request_module_wk);
- }
- #else
- #define request_modules(dev)
- #endif /* CONFIG_MODULES */
- /* ----------------------------------------------------------------------- */
- /* static data */
- /* special timing tables from conexant... */
- static u8 SRAM_Table[][60] =
- {
- /* PAL digital input over GPIO[7:0] */
- {
- 45, // 45 bytes following
- 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
- 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
- 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
- 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
- 0x37,0x00,0xAF,0x21,0x00
- },
- /* NTSC digital input over GPIO[7:0] */
- {
- 51, // 51 bytes following
- 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
- 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
- 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
- 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
- 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
- 0x00,
- },
- // TGB_NTSC392 // quartzsight
- // This table has been modified to be used for Fusion Rev D
- {
- 0x2A, // size of table = 42
- 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
- 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
- 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
- 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
- 0x20, 0x00
- }
- };
- /* minhdelayx1 first video pixel we can capture on a line and
- hdelayx1 start of active video, both relative to rising edge of
- /HRESET pulse (0H) in 1 / fCLKx1.
- swidth width of active video and
- totalwidth total line width, both in 1 / fCLKx1.
- sqwidth total line width in square pixels.
- vdelay start of active video in 2 * field lines relative to
- trailing edge of /VRESET pulse (VDELAY register).
- sheight height of active video in 2 * field lines.
- videostart0 ITU-R frame line number of the line corresponding
- to vdelay in the first field. */
- #define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
- vdelay, sheight, videostart0) \
- .cropcap.bounds.left = minhdelayx1, \
- /* * 2 because vertically we count field lines times two, */ \
- /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
- .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
- /* 4 is a safety margin at the end of the line. */ \
- .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
- .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
- .cropcap.defrect.left = hdelayx1, \
- .cropcap.defrect.top = (videostart0) * 2, \
- .cropcap.defrect.width = swidth, \
- .cropcap.defrect.height = sheight, \
- .cropcap.pixelaspect.numerator = totalwidth, \
- .cropcap.pixelaspect.denominator = sqwidth,
- const struct bttv_tvnorm bttv_tvnorms[] = {
- /* PAL-BDGHI */
- /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
- /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
- {
- .v4l2_id = V4L2_STD_PAL,
- .name = "PAL",
- .Fsc = 35468950,
- .swidth = 924,
- .sheight = 576,
- .totalwidth = 1135,
- .adelay = 0x7f,
- .bdelay = 0x72,
- .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- .scaledtwidth = 1135,
- .hdelayx1 = 186,
- .hactivex1 = 924,
- .vdelay = 0x20,
- .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
- .sram = 0,
- /* ITU-R frame line number of the first VBI line
- we can capture, of the first and second field.
- The last line is determined by cropcap.bounds. */
- .vbistart = { 7, 320 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 186,
- /* Should be (768 * 1135 + 944 / 2) / 944.
- cropcap.defrect is used for image width
- checks, so we keep the old value 924. */
- /* swidth */ 924,
- /* totalwidth */ 1135,
- /* sqwidth */ 944,
- /* vdelay */ 0x20,
- /* sheight */ 576,
- /* videostart0 */ 23)
- /* bt878 (and bt848?) can capture another
- line below active video. */
- .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
- },{
- .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
- .name = "NTSC",
- .Fsc = 28636363,
- .swidth = 768,
- .sheight = 480,
- .totalwidth = 910,
- .adelay = 0x68,
- .bdelay = 0x5d,
- .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
- .scaledtwidth = 910,
- .hdelayx1 = 128,
- .hactivex1 = 910,
- .vdelay = 0x1a,
- .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
- .sram = 1,
- .vbistart = { 10, 273 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 128,
- /* Should be (640 * 910 + 780 / 2) / 780? */
- /* swidth */ 768,
- /* totalwidth */ 910,
- /* sqwidth */ 780,
- /* vdelay */ 0x1a,
- /* sheight */ 480,
- /* videostart0 */ 23)
- },{
- .v4l2_id = V4L2_STD_SECAM,
- .name = "SECAM",
- .Fsc = 35468950,
- .swidth = 924,
- .sheight = 576,
- .totalwidth = 1135,
- .adelay = 0x7f,
- .bdelay = 0xb0,
- .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
- .scaledtwidth = 1135,
- .hdelayx1 = 186,
- .hactivex1 = 922,
- .vdelay = 0x20,
- .vbipack = 255,
- .sram = 0, /* like PAL, correct? */
- .vbistart = { 7, 320 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 186,
- /* swidth */ 924,
- /* totalwidth */ 1135,
- /* sqwidth */ 944,
- /* vdelay */ 0x20,
- /* sheight */ 576,
- /* videostart0 */ 23)
- },{
- .v4l2_id = V4L2_STD_PAL_Nc,
- .name = "PAL-Nc",
- .Fsc = 28636363,
- .swidth = 640,
- .sheight = 576,
- .totalwidth = 910,
- .adelay = 0x68,
- .bdelay = 0x5d,
- .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
- .scaledtwidth = 780,
- .hdelayx1 = 130,
- .hactivex1 = 734,
- .vdelay = 0x1a,
- .vbipack = 144,
- .sram = -1,
- .vbistart = { 7, 320 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 130,
- /* swidth */ (640 * 910 + 780 / 2) / 780,
- /* totalwidth */ 910,
- /* sqwidth */ 780,
- /* vdelay */ 0x1a,
- /* sheight */ 576,
- /* videostart0 */ 23)
- },{
- .v4l2_id = V4L2_STD_PAL_M,
- .name = "PAL-M",
- .Fsc = 28636363,
- .swidth = 640,
- .sheight = 480,
- .totalwidth = 910,
- .adelay = 0x68,
- .bdelay = 0x5d,
- .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
- .scaledtwidth = 780,
- .hdelayx1 = 135,
- .hactivex1 = 754,
- .vdelay = 0x1a,
- .vbipack = 144,
- .sram = -1,
- .vbistart = { 10, 273 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 135,
- /* swidth */ (640 * 910 + 780 / 2) / 780,
- /* totalwidth */ 910,
- /* sqwidth */ 780,
- /* vdelay */ 0x1a,
- /* sheight */ 480,
- /* videostart0 */ 23)
- },{
- .v4l2_id = V4L2_STD_PAL_N,
- .name = "PAL-N",
- .Fsc = 35468950,
- .swidth = 768,
- .sheight = 576,
- .totalwidth = 1135,
- .adelay = 0x7f,
- .bdelay = 0x72,
- .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
- .scaledtwidth = 944,
- .hdelayx1 = 186,
- .hactivex1 = 922,
- .vdelay = 0x20,
- .vbipack = 144,
- .sram = -1,
- .vbistart = { 7, 320 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 186,
- /* swidth */ (768 * 1135 + 944 / 2) / 944,
- /* totalwidth */ 1135,
- /* sqwidth */ 944,
- /* vdelay */ 0x20,
- /* sheight */ 576,
- /* videostart0 */ 23)
- },{
- .v4l2_id = V4L2_STD_NTSC_M_JP,
- .name = "NTSC-JP",
- .Fsc = 28636363,
- .swidth = 640,
- .sheight = 480,
- .totalwidth = 910,
- .adelay = 0x68,
- .bdelay = 0x5d,
- .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
- .scaledtwidth = 780,
- .hdelayx1 = 135,
- .hactivex1 = 754,
- .vdelay = 0x16,
- .vbipack = 144,
- .sram = -1,
- .vbistart = { 10, 273 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 135,
- /* swidth */ (640 * 910 + 780 / 2) / 780,
- /* totalwidth */ 910,
- /* sqwidth */ 780,
- /* vdelay */ 0x16,
- /* sheight */ 480,
- /* videostart0 */ 23)
- },{
- /* that one hopefully works with the strange timing
- * which video recorders produce when playing a NTSC
- * tape on a PAL TV ... */
- .v4l2_id = V4L2_STD_PAL_60,
- .name = "PAL-60",
- .Fsc = 35468950,
- .swidth = 924,
- .sheight = 480,
- .totalwidth = 1135,
- .adelay = 0x7f,
- .bdelay = 0x72,
- .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- .scaledtwidth = 1135,
- .hdelayx1 = 186,
- .hactivex1 = 924,
- .vdelay = 0x1a,
- .vbipack = 255,
- .vtotal = 524,
- .sram = -1,
- .vbistart = { 10, 273 },
- CROPCAP(/* minhdelayx1 */ 68,
- /* hdelayx1 */ 186,
- /* swidth */ 924,
- /* totalwidth */ 1135,
- /* sqwidth */ 944,
- /* vdelay */ 0x1a,
- /* sheight */ 480,
- /* videostart0 */ 23)
- }
- };
- static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
- /* ----------------------------------------------------------------------- */
- /* bttv format list
- packed pixel formats must come first */
- static const struct bttv_format formats[] = {
- {
- .name = "8 bpp, gray",
- .fourcc = V4L2_PIX_FMT_GREY,
- .btformat = BT848_COLOR_FMT_Y8,
- .depth = 8,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "8 bpp, dithered color",
- .fourcc = V4L2_PIX_FMT_HI240,
- .btformat = BT848_COLOR_FMT_RGB8,
- .depth = 8,
- .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
- },{
- .name = "15 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_RGB555,
- .btformat = BT848_COLOR_FMT_RGB15,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "15 bpp RGB, be",
- .fourcc = V4L2_PIX_FMT_RGB555X,
- .btformat = BT848_COLOR_FMT_RGB15,
- .btswap = 0x03, /* byteswap */
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "16 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_RGB565,
- .btformat = BT848_COLOR_FMT_RGB16,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "16 bpp RGB, be",
- .fourcc = V4L2_PIX_FMT_RGB565X,
- .btformat = BT848_COLOR_FMT_RGB16,
- .btswap = 0x03, /* byteswap */
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "24 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_BGR24,
- .btformat = BT848_COLOR_FMT_RGB24,
- .depth = 24,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "32 bpp RGB, le",
- .fourcc = V4L2_PIX_FMT_BGR32,
- .btformat = BT848_COLOR_FMT_RGB32,
- .depth = 32,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "32 bpp RGB, be",
- .fourcc = V4L2_PIX_FMT_RGB32,
- .btformat = BT848_COLOR_FMT_RGB32,
- .btswap = 0x0f, /* byte+word swap */
- .depth = 32,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "4:2:2, packed, YUYV",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .btformat = BT848_COLOR_FMT_YUY2,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "4:2:2, packed, YUYV",
- .fourcc = V4L2_PIX_FMT_YUYV,
- .btformat = BT848_COLOR_FMT_YUY2,
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "4:2:2, packed, UYVY",
- .fourcc = V4L2_PIX_FMT_UYVY,
- .btformat = BT848_COLOR_FMT_YUY2,
- .btswap = 0x03, /* byteswap */
- .depth = 16,
- .flags = FORMAT_FLAGS_PACKED,
- },{
- .name = "4:2:2, planar, Y-Cb-Cr",
- .fourcc = V4L2_PIX_FMT_YUV422P,
- .btformat = BT848_COLOR_FMT_YCrCb422,
- .depth = 16,
- .flags = FORMAT_FLAGS_PLANAR,
- .hshift = 1,
- .vshift = 0,
- },{
- .name = "4:2:0, planar, Y-Cb-Cr",
- .fourcc = V4L2_PIX_FMT_YUV420,
- .btformat = BT848_COLOR_FMT_YCrCb422,
- .depth = 12,
- .flags = FORMAT_FLAGS_PLANAR,
- .hshift = 1,
- .vshift = 1,
- },{
- .name = "4:2:0, planar, Y-Cr-Cb",
- .fourcc = V4L2_PIX_FMT_YVU420,
- .btformat = BT848_COLOR_FMT_YCrCb422,
- .depth = 12,
- .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
- .hshift = 1,
- .vshift = 1,
- },{
- .name = "4:1:1, planar, Y-Cb-Cr",
- .fourcc = V4L2_PIX_FMT_YUV411P,
- .btformat = BT848_COLOR_FMT_YCrCb411,
- .depth = 12,
- .flags = FORMAT_FLAGS_PLANAR,
- .hshift = 2,
- .vshift = 0,
- },{
- .name = "4:1:0, planar, Y-Cb-Cr",
- .fourcc = V4L2_PIX_FMT_YUV410,
- .btformat = BT848_COLOR_FMT_YCrCb411,
- .depth = 9,
- .flags = FORMAT_FLAGS_PLANAR,
- .hshift = 2,
- .vshift = 2,
- },{
- .name = "4:1:0, planar, Y-Cr-Cb",
- .fourcc = V4L2_PIX_FMT_YVU410,
- .btformat = BT848_COLOR_FMT_YCrCb411,
- .depth = 9,
- .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
- .hshift = 2,
- .vshift = 2,
- },{
- .name = "raw scanlines",
- .fourcc = -1,
- .btformat = BT848_COLOR_FMT_RAW,
- .depth = 8,
- .flags = FORMAT_FLAGS_RAW,
- }
- };
- static const unsigned int FORMATS = ARRAY_SIZE(formats);
- /* ----------------------------------------------------------------------- */
- #define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
- #define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
- #define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
- #define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
- #define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
- #define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
- #define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
- #define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
- #define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
- #define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
- #define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
- #define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
- static const struct v4l2_queryctrl no_ctl = {
- .name = "42",
- .flags = V4L2_CTRL_FLAG_DISABLED,
- };
- static const struct v4l2_queryctrl bttv_ctls[] = {
- /* --- video --- */
- {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 65535,
- .step = 256,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 65535,
- .step = 128,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 65535,
- .step = 128,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .minimum = 0,
- .maximum = 65535,
- .step = 256,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- /* --- audio --- */
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 65535,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_BALANCE,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_BASS,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_TREBLE,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },
- /* --- private --- */
- {
- .id = V4L2_CID_PRIVATE_CHROMA_AGC,
- .name = "chroma agc",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_COMBFILTER,
- .name = "combfilter",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_AUTOMUTE,
- .name = "automute",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_LUMAFILTER,
- .name = "luma decimation filter",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_AGC_CRUSH,
- .name = "agc crush",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_VCR_HACK,
- .name = "vcr hack",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
- .name = "whitecrush upper",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 0xCF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
- .name = "whitecrush lower",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 0x7F,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_PRIVATE_UV_RATIO,
- .name = "uv ratio",
- .minimum = 0,
- .maximum = 100,
- .step = 1,
- .default_value = 50,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
- .name = "full luma range",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_PRIVATE_CORING,
- .name = "coring",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
- };
- static const struct v4l2_queryctrl *ctrl_by_id(int id)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)
- if (bttv_ctls[i].id == id)
- return bttv_ctls+i;
- return NULL;
- }
- /* ----------------------------------------------------------------------- */
- /* resource management */
- /*
- RESOURCE_ allocated by freed by
- VIDEO_READ bttv_read 1) bttv_read 2)
- VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
- VIDIOC_QBUF 1) bttv_release
- VIDIOCMCAPTURE 1)
- OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
- VIDIOC_OVERLAY on VIDIOC_OVERLAY off
- 3) bttv_release
- VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
- VIDIOC_QBUF 1) bttv_release
- bttv_read, bttv_poll 1) 4)
- 1) The resource must be allocated when we enter buffer prepare functions
- and remain allocated while buffers are in the DMA queue.
- 2) This is a single frame read.
- 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
- RESOURCE_OVERLAY is allocated.
- 4) This is a continuous read, implies VIDIOC_STREAMON.
- Note this driver permits video input and standard changes regardless if
- resources are allocated.
- */
- #define VBI_RESOURCES (RESOURCE_VBI)
- #define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
- RESOURCE_VIDEO_STREAM | \
- RESOURCE_OVERLAY)
- static
- int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
- {
- int xbits; /* mutual exclusive resources */
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
- xbits = bit;
- if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
- xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
- /* is it free? */
- mutex_lock(&btv->lock);
- if (btv->resources & xbits) {
- /* no, someone else uses it */
- goto fail;
- }
- if ((bit & VIDEO_RESOURCES)
- && 0 == (btv->resources & VIDEO_RESOURCES)) {
- /* Do crop - use current, don't - use default parameters. */
- __s32 top = btv->crop[!!fh->do_crop].rect.top;
- if (btv->vbi_end > top)
- goto fail;
- /* We cannot capture the same line as video and VBI data.
- Claim scan lines crop[].rect.top to bottom. */
- btv->crop_start = top;
- } else if (bit & VBI_RESOURCES) {
- __s32 end = fh->vbi_fmt.end;
- if (end > btv->crop_start)
- goto fail;
- /* Claim scan lines above fh->vbi_fmt.end. */
- btv->vbi_end = end;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- btv->resources |= bit;
- mutex_unlock(&btv->lock);
- return 1;
- fail:
- mutex_unlock(&btv->lock);
- return 0;
- }
- static
- int check_btres(struct bttv_fh *fh, int bit)
- {
- return (fh->resources & bit);
- }
- static
- int locked_btres(struct bttv *btv, int bit)
- {
- return (btv->resources & bit);
- }
- /* Call with btv->lock down. */
- static void
- disclaim_vbi_lines(struct bttv *btv)
- {
- btv->vbi_end = 0;
- }
- /* Call with btv->lock down. */
- static void
- disclaim_video_lines(struct bttv *btv)
- {
- const struct bttv_tvnorm *tvnorm;
- u8 crop;
- tvnorm = &bttv_tvnorms[btv->tvnorm];
- btv->crop_start = tvnorm->cropcap.bounds.top
- + tvnorm->cropcap.bounds.height;
- /* VBI capturing ends at VDELAY, start of video capturing, no
- matter how many lines the VBI RISC program expects. When video
- capturing is off, it shall no longer "preempt" VBI capturing,
- so we set VDELAY to maximum. */
- crop = btread(BT848_E_CROP) | 0xc0;
- btwrite(crop, BT848_E_CROP);
- btwrite(0xfe, BT848_E_VDELAY_LO);
- btwrite(crop, BT848_O_CROP);
- btwrite(0xfe, BT848_O_VDELAY_LO);
- }
- static
- void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
- {
- if ((fh->resources & bits) != bits) {
- /* trying to free ressources not allocated by us ... */
- printk("bttv: BUG! (btres)\n");
- }
- mutex_lock(&btv->lock);
- fh->resources &= ~bits;
- btv->resources &= ~bits;
- bits = btv->resources;
- if (0 == (bits & VIDEO_RESOURCES))
- disclaim_video_lines(btv);
- if (0 == (bits & VBI_RESOURCES))
- disclaim_vbi_lines(btv);
- mutex_unlock(&btv->lock);
- }
- /* ----------------------------------------------------------------------- */
- /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
- /* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
- PLL_X = Reference pre-divider (0=1, 1=2)
- PLL_C = Post divider (0=6, 1=4)
- PLL_I = Integer input
- PLL_F = Fractional input
- F_input = 28.636363 MHz:
- PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
- */
- static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
- {
- unsigned char fl, fh, fi;
- /* prevent overflows */
- fin/=4;
- fout/=4;
- fout*=12;
- fi=fout/fin;
- fout=(fout%fin)*256;
- fh=fout/fin;
- fout=(fout%fin)*256;
- fl=fout/fin;
- btwrite(fl, BT848_PLL_F_LO);
- btwrite(fh, BT848_PLL_F_HI);
- btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
- }
- static void set_pll(struct bttv *btv)
- {
- int i;
- if (!btv->pll.pll_crystal)
- return;
- if (btv->pll.pll_ofreq == btv->pll.pll_current) {
- dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
- return;
- }
- if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
- /* no PLL needed */
- if (btv->pll.pll_current == 0)
- return;
- bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
- btv->c.nr,btv->pll.pll_ifreq);
- btwrite(0x00,BT848_TGCTRL);
- btwrite(0x00,BT848_PLL_XCI);
- btv->pll.pll_current = 0;
- return;
- }
- bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
- btv->pll.pll_ifreq, btv->pll.pll_ofreq);
- set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
- for (i=0; i<10; i++) {
- /* Let other people run while the PLL stabilizes */
- bttv_printk(".");
- msleep(10);
- if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
- btwrite(0,BT848_DSTATUS);
- } else {
- btwrite(0x08,BT848_TGCTRL);
- btv->pll.pll_current = btv->pll.pll_ofreq;
- bttv_printk(" ok\n");
- return;
- }
- }
- btv->pll.pll_current = -1;
- bttv_printk("failed\n");
- return;
- }
- /* used to switch between the bt848's analog/digital video capture modes */
- static void bt848A_set_timing(struct bttv *btv)
- {
- int i, len;
- int table_idx = bttv_tvnorms[btv->tvnorm].sram;
- int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
- if (btv->input == btv->dig) {
- dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
- btv->c.nr,table_idx);
- /* timing change...reset timing generator address */
- btwrite(0x00, BT848_TGCTRL);
- btwrite(0x02, BT848_TGCTRL);
- btwrite(0x00, BT848_TGCTRL);
- len=SRAM_Table[table_idx][0];
- for(i = 1; i <= len; i++)
- btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
- btv->pll.pll_ofreq = 27000000;
- set_pll(btv);
- btwrite(0x11, BT848_TGCTRL);
- btwrite(0x41, BT848_DVSIF);
- } else {
- btv->pll.pll_ofreq = fsc;
- set_pll(btv);
- btwrite(0x0, BT848_DVSIF);
- }
- }
- /* ----------------------------------------------------------------------- */
- static void bt848_bright(struct bttv *btv, int bright)
- {
- int value;
- // printk("bttv: set bright: %d\n",bright); // DEBUG
- btv->bright = bright;
- /* We want -128 to 127 we get 0-65535 */
- value = (bright >> 8) - 128;
- btwrite(value & 0xff, BT848_BRIGHT);
- }
- static void bt848_hue(struct bttv *btv, int hue)
- {
- int value;
- btv->hue = hue;
- /* -128 to 127 */
- value = (hue >> 8) - 128;
- btwrite(value & 0xff, BT848_HUE);
- }
- static void bt848_contrast(struct bttv *btv, int cont)
- {
- int value,hibit;
- btv->contrast = cont;
- /* 0-511 */
- value = (cont >> 7);
- hibit = (value >> 6) & 4;
- btwrite(value & 0xff, BT848_CONTRAST_LO);
- btaor(hibit, ~4, BT848_E_CONTROL);
- btaor(hibit, ~4, BT848_O_CONTROL);
- }
- static void bt848_sat(struct bttv *btv, int color)
- {
- int val_u,val_v,hibits;
- btv->saturation = color;
- /* 0-511 for the color */
- val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
- val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
- hibits = (val_u >> 7) & 2;
- hibits |= (val_v >> 8) & 1;
- btwrite(val_u & 0xff, BT848_SAT_U_LO);
- btwrite(val_v & 0xff, BT848_SAT_V_LO);
- btaor(hibits, ~3, BT848_E_CONTROL);
- btaor(hibits, ~3, BT848_O_CONTROL);
- }
- /* ----------------------------------------------------------------------- */
- static int
- video_mux(struct bttv *btv, unsigned int input)
- {
- int mux,mask2;
- if (input >= bttv_tvcards[btv->c.type].video_inputs)
- return -EINVAL;
- /* needed by RemoteVideo MX */
- mask2 = bttv_tvcards[btv->c.type].gpiomask2;
- if (mask2)
- gpio_inout(mask2,mask2);
- if (input == btv->svhs) {
- btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
- btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
- } else {
- btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
- btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
- }
- mux = bttv_muxsel(btv, input);
- btaor(mux<<5, ~(3<<5), BT848_IFORM);
- dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
- btv->c.nr,input,mux);
- /* card specific hook */
- if(bttv_tvcards[btv->c.type].muxsel_hook)
- bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
- return 0;
- }
- static char *audio_modes[] = {
- "audio: tuner", "audio: radio", "audio: extern",
- "audio: intern", "audio: mute"
- };
- static int
- audio_mux(struct bttv *btv, int input, int mute)
- {
- int gpio_val, signal;
- struct v4l2_control ctrl;
- gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
- bttv_tvcards[btv->c.type].gpiomask);
- signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
- btv->mute = mute;
- btv->audio = input;
- /* automute */
- mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
- if (mute)
- gpio_val = bttv_tvcards[btv->c.type].gpiomute;
- else
- gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
- switch (btv->c.type) {
- case BTTV_BOARD_VOODOOTV_FM:
- case BTTV_BOARD_VOODOOTV_200:
- gpio_val = bttv_tda9880_setnorm(btv, gpio_val);
- break;
- default:
- gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
- }
- if (bttv_gpio)
- bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
- if (in_interrupt())
- return 0;
- ctrl.id = V4L2_CID_AUDIO_MUTE;
- ctrl.value = btv->mute;
- bttv_call_all(btv, core, s_ctrl, &ctrl);
- if (btv->sd_msp34xx) {
- u32 in;
- /* Note: the inputs tuner/radio/extern/intern are translated
- to msp routings. This assumes common behavior for all msp3400
- based TV cards. When this assumption fails, then the
- specific MSP routing must be added to the card table.
- For now this is sufficient. */
- switch (input) {
- case TVAUDIO_INPUT_RADIO:
- in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
- MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
- break;
- case TVAUDIO_INPUT_EXTERN:
- in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
- MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
- break;
- case TVAUDIO_INPUT_INTERN:
- /* Yes, this is the same input as for RADIO. I doubt
- if this is ever used. The only board with an INTERN
- input is the BTTV_BOARD_AVERMEDIA98. I wonder how
- that was tested. My guess is that the whole INTERN
- input does not work. */
- in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
- MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
- break;
- case TVAUDIO_INPUT_TUNER:
- default:
- /* This is the only card that uses TUNER2, and afaik,
- is the only difference between the VOODOOTV_FM
- and VOODOOTV_200 */
- if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
- in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
- MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
- else
- in = MSP_INPUT_DEFAULT;
- break;
- }
- v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing,
- in, MSP_OUTPUT_DEFAULT, 0);
- }
- if (btv->sd_tvaudio) {
- v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,
- input, 0, 0);
- }
- return 0;
- }
- static inline int
- audio_mute(struct bttv *btv, int mute)
- {
- return audio_mux(btv, btv->audio, mute);
- }
- static inline int
- audio_input(struct bttv *btv, int input)
- {
- return audio_mux(btv, input, btv->mute);
- }
- static void
- bttv_crop_calc_limits(struct bttv_crop *c)
- {
- /* Scale factor min. 1:1, max. 16:1. Min. image size
- 48 x 32. Scaled width must be a multiple of 4. */
- if (1) {
- /* For bug compatibility with VIDIOCGCAP and image
- size checks in earlier driver versions. */
- c->min_scaled_width = 48;
- c->min_scaled_height = 32;
- } else {
- c->min_scaled_width =
- (max(48, c->rect.width >> 4) + 3) & ~3;
- c->min_scaled_height =
- max(32, c->rect.height >> 4);
- }
- c->max_scaled_width = c->rect.width & ~3;
- c->max_scaled_height = c->rect.height;
- }
- static void
- bttv_crop_reset(struct bttv_crop *c, unsigned int norm)
- {
- c->rect = bttv_tvnorms[norm].cropcap.defrect;
- bttv_crop_calc_limits(c);
- }
- /* Call with btv->lock down. */
- static int
- set_tvnorm(struct bttv *btv, unsigned int norm)
- {
- const struct bttv_tvnorm *tvnorm;
- v4l2_std_id id;
- BUG_ON(norm >= BTTV_TVNORMS);
- BUG_ON(btv->tvnorm >= BTTV_TVNORMS);
- tvnorm = &bttv_tvnorms[norm];
- if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap,
- sizeof (tvnorm->cropcap))) {
- bttv_crop_reset(&btv->crop[0], norm);
- btv->crop[1] = btv->crop[0]; /* current = default */
- if (0 == (btv->resources & VIDEO_RESOURCES)) {
- btv->crop_start = tvnorm->cropcap.bounds.top
- + tvnorm->cropcap.bounds.height;
- }
- }
- btv->tvnorm = norm;
- btwrite(tvnorm->adelay, BT848_ADELAY);
- btwrite(tvnorm->bdelay, BT848_BDELAY);
- btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
- BT848_IFORM);
- btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
- btwrite(1, BT848_VBI_PACK_DEL);
- bt848A_set_timing(btv);
- switch (btv->c.type) {
- case BTTV_BOARD_VOODOOTV_FM:
- case BTTV_BOARD_VOODOOTV_200:
- bttv_tda9880_setnorm(btv, gpio_read());
- break;
- }
- id = tvnorm->v4l2_id;
- bttv_call_all(btv, core, s_std, id);
- return 0;
- }
- /* Call with btv->lock down. */
- static void
- set_input(struct bttv *btv, unsigned int input, unsigned int norm)
- {
- unsigned long flags;
- btv->input = input;
- if (irq_iswitch) {
- spin_lock_irqsave(&btv->s_lock,flags);
- if (btv->curr.frame_irq) {
- /* active capture -> delayed input switch */
- btv->new_input = input;
- } else {
- video_mux(btv,input);
- }
- spin_unlock_irqrestore(&btv->s_lock,flags);
- } else {
- video_mux(btv,input);
- }
- audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ?
- TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN);
- set_tvnorm(btv, norm);
- }
- static void init_irqreg(struct bttv *btv)
- {
- /* clear status */
- btwrite(0xfffffUL, BT848_INT_STAT);
- if (bttv_tvcards[btv->c.type].no_video) {
- /* i2c only */
- btwrite(BT848_INT_I2CDONE,
- BT848_INT_MASK);
- } else {
- /* full video */
- btwrite((btv->triton1) |
- (btv->gpioirq ? BT848_INT_GPINT : 0) |
- BT848_INT_SCERR |
- (fdsr ? BT848_INT_FDSR : 0) |
- BT848_INT_RISCI | BT848_INT_OCERR |
- BT848_INT_FMTCHG|BT848_INT_HLOCK|
- BT848_INT_I2CDONE,
- BT848_INT_MASK);
- }
- }
- static void init_bt848(struct bttv *btv)
- {
- int val;
- if (bttv_tvcards[btv->c.type].no_video) {
- /* very basic init only */
- init_irqreg(btv);
- return;
- }
- btwrite(0x00, BT848_CAP_CTL);
- btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
- btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
- /* set planar and packed mode trigger points and */
- /* set rising edge of inverted GPINTR pin as irq trigger */
- btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
- BT848_GPIO_DMA_CTL_PLTP1_16|
- BT848_GPIO_DMA_CTL_PLTP23_16|
- BT848_GPIO_DMA_CTL_GPINTC|
- BT848_GPIO_DMA_CTL_GPINTI,
- BT848_GPIO_DMA_CTL);
- val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
- btwrite(val, BT848_E_SCLOOP);
- btwrite(val, BT848_O_SCLOOP);
- btwrite(0x20, BT848_E_VSCALE_HI);
- btwrite(0x20, BT848_O_VSCALE_HI);
- btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
- BT848_ADC);
- btwrite(whitecrush_upper, BT848_WC_UP);
- btwrite(whitecrush_lower, BT848_WC_DOWN);
- if (btv->opt_lumafilter) {
- btwrite(0, BT848_E_CONTROL);
- btwrite(0, BT848_O_CONTROL);
- } else {
- btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
- btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
- }
- bt848_bright(btv, btv->bright);
- bt848_hue(btv, btv->hue);
- bt848_contrast(btv, btv->contrast);
- bt848_sat(btv, btv->saturation);
- /* interrupt */
- init_irqreg(btv);
- }
- static void bttv_reinit_bt848(struct bttv *btv)
- {
- unsigned long flags;
- if (bttv_verbose)
- printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
- spin_lock_irqsave(&btv->s_lock,flags);
- btv->errors=0;
- bttv_set_dma(btv,0);
- spin_unlock_irqrestore(&btv->s_lock,flags);
- init_bt848(btv);
- btv->pll.pll_current = -1;
- set_input(btv, btv->input, btv->tvnorm);
- }
- static int bttv_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *c)
- {
- struct bttv_fh *fh = priv;
- struct bttv *btv = fh->btv;
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- c->value = btv->bright;
- break;
- case V4L2_CID_HUE:
- c->value = btv->hue;
- break;
- case V4L2_CID_CONTRAST:
- c->value = btv->contrast;
- break;
- case V4L2_CID_SATURATION:
- c->value = btv->saturation;
- break;
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- bttv_call_all(btv, core, g_ctrl, c);
- break;
- case V4L2_CID_PRIVATE_CHROMA_AGC:
- c->value = btv->opt_chroma_agc;
- break;
- case V4L2_CID_PRIVATE_COMBFILTER:
- c->value = btv->opt_combfilter;
- break;
- case V4L2_CID_PRIVATE_LUMAFILTER:
- c->value = btv->opt_lumafilter;
- break;
- case V4L2_CID_PRIVATE_AUTOMUTE:
- c->value = btv->opt_automute;
- break;
- case V4L2_CID_PRIVATE_AGC_CRUSH:
- c->value = btv->opt_adc_crush;
- break;
- case V4L2_CID_PRIVATE_VCR_HACK:
- c->value = btv->opt_vcr_hack;
- break;
- case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
- c->value = btv->opt_whitecrush_upper;
- break;
- case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
- c->value = btv->opt_whitecrush_lower;
- break;
- case V4L2_CID_PRIVATE_UV_RATIO:
- c->value = btv->opt_uv_ratio;
- break;
- case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
- c->value = btv->opt_full_luma_range;
- break;
- case V4L2_CID_PRIVATE_CORING:
- c->value = btv->opt_coring;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int bttv_s_ctrl(struct file *file, void *f,
- struct v4l2_control *c)
- {
- int err;
- int val;
- struct bttv_fh *fh = f;
- struct bttv *btv = fh->btv;
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- bt848_bright(btv, c->value);
- break;
- case V4L2_CID_HUE:
- bt848_hue(btv, c->value);
- break;
- case V4L2_CID_CONTRAST:
- bt848_contrast(btv, c->value);
- break;
- case V4L2_CID_SATURATION:
- bt848_sat(btv, c->value);
- break;
- case V4L2_CID_AUDIO_MUTE:
- audio_mute(btv, c->value);
- /* fall through */
- case V4L2_CID_AUDIO_VOLUME:
- if (btv->volume_gpio)
- btv->volume_gpio(btv, c->value);
- bttv_call_all(btv, core, s_ctrl, c);
- break;
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- bttv_call_all(btv, core, s_ctrl, c);
- break;
- case V4L2_CID_PRIVATE_CHROMA_AGC:
- btv->opt_chroma_agc = c->value;
- val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
- btwrite(val, BT848_E_SCLOOP);
- btwrite(val, BT848_O_SCLOOP);
- break;
- case V4L2_CID_PRIVATE_COMBFILTER:
- btv->opt_combfilter = c->value;
- break;
- case V4L2_CID_PRIVATE_LUMAFILTER:
- btv->opt_lumafilter = c->value;
- if (btv->opt_lumafilter) {
- btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
- btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
- } else {
- btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
- btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
- }
- break;
- case V4L2_CID_PRIVATE_AUTOMUTE:
- btv->opt_automute = c->value;
- break;
- case V4L2_CID_PRIVATE_AGC_CRUSH:
- btv->opt_adc_crush = c->value;
- btwrite(BT848_ADC_RESERVED |
- (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
- BT848_ADC);
- break;
- case V4L2_CID_PRIVATE_VCR_HACK:
- btv->opt_vcr_hack = c->value;
- break;
- case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
- btv->opt_whitecrush_upper = c->value;
- btwrite(c->value, BT848_WC_UP);
- break;
- case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
- btv->opt_whitecrush_lower = c->value;
- btwrite(c->value, BT848_WC_DOWN);
- break;
- case V4L2_CID_PRIVATE_UV_RATIO:
- btv->opt_uv_ratio = c->value;
- bt848_sat(btv, btv->saturation);
- break;
- case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
- btv->opt_full_luma_range = c->value;
- btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
- break;
- case V4L2_CID_PRIVATE_CORING:
- btv->opt_coring = c->value;
- btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- /* ----------------------------------------------------------------------- */
- void bttv_gpio_tracking(struct bttv *btv, char *comment)
- {
- unsigned int outbits, data;
- outbits = btread(BT848_GPIO_OUT_EN);
- data = btread(BT848_GPIO_DATA);
- printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
- btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
- }
- static void bttv_field_count(struct bttv *btv)
- {
- int need_count = 0;
- if (btv->users)
- need_count++;
- if (need_count) {
- /* start field counter */
- btor(BT848_INT_VSYNC,BT848_INT_MASK);
- } else {
- /* stop field counter */
- btand(~BT848_INT_VSYNC,BT848_INT_MASK);
- btv->field_count = 0;
- }
- }
- static const struct bttv_format*
- format_by_fourcc(int fourcc)
- {
- unsigned int i;
- for (i = 0; i < FORMATS; i++) {
- if (-1 == formats[i].fourcc)
- continue;
- if (formats[i].fourcc == fourcc)
- return formats+i;
- }
- return NULL;
- }
- /* ----------------------------------------------------------------------- */
- /* misc helpers */
- static int
- bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
- struct bttv_buffer *new)
- {
- struct bttv_buffer *old;
- unsigned long flags;
- int retval = 0;
- dprintk("switch_overlay: enter [new=%p]\n",new);
- if (new)
- new->vb.state = VIDEOBUF_DONE;
- spin_lock_irqsave(&btv->s_lock,flags);
- old = btv->screen;
- btv->screen = new;
- btv->loop_irq |= 1;
- bttv_set_dma(btv, 0x03);
- spin_unlock_irqrestore(&btv->s_lock,flags);
- if (NULL != old) {
- dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
- bttv_dma_free(&fh->cap,btv, old);
- kfree(old);
- }
- if (NULL == new)
- free_btres(btv,fh,RESOURCE_OVERLAY);
- dprintk("switch_overlay: done\n");
- return retval;
- }
- /* ----------------------------------------------------------------------- */
- /* video4linux (1) interface */
- static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
- struct bttv_buffer *buf,
- const struct bttv_format *fmt,
- unsigned int width, unsigned int height,
- enum v4l2_field field)
- {
- struct bttv_fh *fh = q->priv_data;
- int redo_dma_risc = 0;
- struct bttv_crop c;
- int norm;
- int rc;
- /* check settings */
- if (NULL == fmt)
- return -EINVAL;
- if (fmt->btformat == BT848_COLOR_FMT_RAW) {
- width = RAW_BPL;
- height = RAW_LINES*2;
- if (width*height > buf->vb.bsize)
- return -EINVAL;
- buf->vb.size = buf->vb.bsize;
- /* Make sure tvnorm and vbi_end remain consistent
- until we're done. */
- mutex_lock(&btv->lock);
- norm = btv->tvnorm;
- /* In this mode capturing always starts at defrect.top
- (default VDELAY), ignoring cropping parameters. */
- if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
- mutex_unlock(&btv->lock);
- return -EINVAL;
- }
- mutex_unlock(&btv->lock);
- c.rect = bttv_tvnorms[norm].cropcap.defrect;
- } else {
- mutex_lock(&btv->lock);
- norm = btv->tvnorm;
- c = btv->crop[!!fh->do_crop];
- mutex_unlock(&btv->lock);
- if (width < c.min_scaled_width ||
- width > c.max_scaled_width ||
- height < c.min_scaled_height)
- return -EINVAL;
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- case V4L2_FIELD_ALTERNATE:
- /* btv->crop counts frame lines. Max. scale
- factor is 16:1 for frames, 8:1 for fields. */
- if (height * 2 > c.max_scaled_height)
- return -EINVAL;
- break;
- default:
- if (height > c.max_scaled_height)
- return -EINVAL;
- break;
- }
- buf->vb.size = (width * height * fmt->depth) >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
- }
- /* alloc + fill struct bttv_buffer (if changed) */
- if (buf->vb.width != width || buf->vb.height != height ||
- buf->vb.field != field ||
- buf->tvnorm != norm || buf->fmt != fmt ||
- buf->crop.top != c.rect.top ||
- buf->crop.left != c.rect.left ||
- buf->crop.width != c.rect.width ||
- buf->crop.height != c.rect.height) {
- buf->vb.width = width;
- buf->vb.height = height;
- buf->vb.field = field;
- buf->tvnorm = norm;
- buf->fmt = fmt;
- buf->crop = c.rect;
- redo_dma_risc = 1;
- }
- /* alloc risc memory */
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- redo_dma_risc = 1;
- if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
- goto fail;
- }
- if (redo_dma_risc)
- if (0 != (rc = bttv_buffer_risc(btv,buf)))
- goto fail;
- buf->vb.state = VIDEOBUF_PREPARED;…