Path: blob/master/drivers/media/video/bt8xx/bttv-driver.c
10785 views
/*12bttv - Bt848 frame grabber driver34Copyright (C) 1996,97,98 Ralph Metzler <[email protected]>5& Marcus Metzler <[email protected]>6(c) 1999-2002 Gerd Knorr <[email protected]>78some v4l2 code lines are taken from Justin's bttv2 driver which is9(c) 2000 Justin Schoeman <[email protected]>1011V4L1 removal from:12(c) 2005-2006 Nickolay V. Shmyrev <[email protected]>1314Fixes to be fully V4L2 compliant by15(c) 2006 Mauro Carvalho Chehab <[email protected]>1617Cropping and overscan support18Copyright (C) 2005, 2006 Michael H. Schimek <[email protected]>19Sponsored by OPQ Systems AB2021This program is free software; you can redistribute it and/or modify22it under the terms of the GNU General Public License as published by23the Free Software Foundation; either version 2 of the License, or24(at your option) any later version.2526This program is distributed in the hope that it will be useful,27but WITHOUT ANY WARRANTY; without even the implied warranty of28MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the29GNU General Public License for more details.3031You should have received a copy of the GNU General Public License32along with this program; if not, write to the Free Software33Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.34*/3536#include <linux/init.h>37#include <linux/module.h>38#include <linux/delay.h>39#include <linux/slab.h>40#include <linux/errno.h>41#include <linux/fs.h>42#include <linux/kernel.h>43#include <linux/sched.h>44#include <linux/interrupt.h>45#include <linux/kdev_t.h>46#include "bttvp.h"47#include <media/v4l2-common.h>48#include <media/v4l2-ioctl.h>49#include <media/tvaudio.h>50#include <media/msp3400.h>5152#include <linux/dma-mapping.h>5354#include <asm/io.h>55#include <asm/byteorder.h>5657#include <media/saa6588.h>585960unsigned int bttv_num; /* number of Bt848s in use */61struct bttv *bttvs[BTTV_MAX];6263unsigned int bttv_debug;64unsigned int bttv_verbose = 1;65unsigned int bttv_gpio;6667/* config variables */68#ifdef __BIG_ENDIAN69static unsigned int bigendian=1;70#else71static unsigned int bigendian;72#endif73static unsigned int radio[BTTV_MAX];74static unsigned int irq_debug;75static unsigned int gbuffers = 8;76static unsigned int gbufsize = 0x208000;77static unsigned int reset_crop = 1;7879static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };80static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };81static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };82static int debug_latency;83static int disable_ir;8485static unsigned int fdsr;8687/* options */88static unsigned int combfilter;89static unsigned int lumafilter;90static unsigned int automute = 1;91static unsigned int chroma_agc;92static unsigned int adc_crush = 1;93static unsigned int whitecrush_upper = 0xCF;94static unsigned int whitecrush_lower = 0x7F;95static unsigned int vcr_hack;96static unsigned int irq_iswitch;97static unsigned int uv_ratio = 50;98static unsigned int full_luma_range;99static unsigned int coring;100101/* API features (turn on/off stuff for testing) */102static unsigned int v4l2 = 1;103104/* insmod args */105module_param(bttv_verbose, int, 0644);106module_param(bttv_gpio, int, 0644);107module_param(bttv_debug, int, 0644);108module_param(irq_debug, int, 0644);109module_param(debug_latency, int, 0644);110module_param(disable_ir, int, 0444);111112module_param(fdsr, int, 0444);113module_param(gbuffers, int, 0444);114module_param(gbufsize, int, 0444);115module_param(reset_crop, int, 0444);116117module_param(v4l2, int, 0644);118module_param(bigendian, int, 0644);119module_param(irq_iswitch, int, 0644);120module_param(combfilter, int, 0444);121module_param(lumafilter, int, 0444);122module_param(automute, int, 0444);123module_param(chroma_agc, int, 0444);124module_param(adc_crush, int, 0444);125module_param(whitecrush_upper, int, 0444);126module_param(whitecrush_lower, int, 0444);127module_param(vcr_hack, int, 0444);128module_param(uv_ratio, int, 0444);129module_param(full_luma_range, int, 0444);130module_param(coring, int, 0444);131132module_param_array(radio, int, NULL, 0444);133module_param_array(video_nr, int, NULL, 0444);134module_param_array(radio_nr, int, NULL, 0444);135module_param_array(vbi_nr, int, NULL, 0444);136137MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");138MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");139MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");140MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");141MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");142MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");143MODULE_PARM_DESC(disable_ir, "disable infrared remote support");144MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");145MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");146MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "147"is 1 (yes) for compatibility with older applications");148MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");149MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");150MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");151MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");152MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");153MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");154MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");155MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");156MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");157MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");158MODULE_PARM_DESC(video_nr, "video device numbers");159MODULE_PARM_DESC(vbi_nr, "vbi device numbers");160MODULE_PARM_DESC(radio_nr, "radio device numbers");161162MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");163MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");164MODULE_LICENSE("GPL");165166/* ----------------------------------------------------------------------- */167/* sysfs */168169static ssize_t show_card(struct device *cd,170struct device_attribute *attr, char *buf)171{172struct video_device *vfd = container_of(cd, struct video_device, dev);173struct bttv *btv = video_get_drvdata(vfd);174return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);175}176static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);177178/* ----------------------------------------------------------------------- */179/* dvb auto-load setup */180#if defined(CONFIG_MODULES) && defined(MODULE)181static void request_module_async(struct work_struct *work)182{183request_module("dvb-bt8xx");184}185186static void request_modules(struct bttv *dev)187{188INIT_WORK(&dev->request_module_wk, request_module_async);189schedule_work(&dev->request_module_wk);190}191192static void flush_request_modules(struct bttv *dev)193{194flush_work_sync(&dev->request_module_wk);195}196#else197#define request_modules(dev)198#define flush_request_modules(dev)199#endif /* CONFIG_MODULES */200201202/* ----------------------------------------------------------------------- */203/* static data */204205/* special timing tables from conexant... */206static u8 SRAM_Table[][60] =207{208/* PAL digital input over GPIO[7:0] */209{21045, // 45 bytes following2110x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,2120x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,2130x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,2140x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,2150x37,0x00,0xAF,0x21,0x00216},217/* NTSC digital input over GPIO[7:0] */218{21951, // 51 bytes following2200x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,2210x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,2220x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,2230x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,2240x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,2250x00,226},227// TGB_NTSC392 // quartzsight228// This table has been modified to be used for Fusion Rev D229{2300x2A, // size of table = 422310x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,2320x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,2330x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,2340xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,2350x20, 0x00236}237};238239/* minhdelayx1 first video pixel we can capture on a line and240hdelayx1 start of active video, both relative to rising edge of241/HRESET pulse (0H) in 1 / fCLKx1.242swidth width of active video and243totalwidth total line width, both in 1 / fCLKx1.244sqwidth total line width in square pixels.245vdelay start of active video in 2 * field lines relative to246trailing edge of /VRESET pulse (VDELAY register).247sheight height of active video in 2 * field lines.248videostart0 ITU-R frame line number of the line corresponding249to vdelay in the first field. */250#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \251vdelay, sheight, videostart0) \252.cropcap.bounds.left = minhdelayx1, \253/* * 2 because vertically we count field lines times two, */ \254/* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \255.cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \256/* 4 is a safety margin at the end of the line. */ \257.cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \258.cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \259.cropcap.defrect.left = hdelayx1, \260.cropcap.defrect.top = (videostart0) * 2, \261.cropcap.defrect.width = swidth, \262.cropcap.defrect.height = sheight, \263.cropcap.pixelaspect.numerator = totalwidth, \264.cropcap.pixelaspect.denominator = sqwidth,265266const struct bttv_tvnorm bttv_tvnorms[] = {267/* PAL-BDGHI */268/* max. active video is actually 922, but 924 is divisible by 4 and 3! */269/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */270{271.v4l2_id = V4L2_STD_PAL,272.name = "PAL",273.Fsc = 35468950,274.swidth = 924,275.sheight = 576,276.totalwidth = 1135,277.adelay = 0x7f,278.bdelay = 0x72,279.iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),280.scaledtwidth = 1135,281.hdelayx1 = 186,282.hactivex1 = 924,283.vdelay = 0x20,284.vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */285.sram = 0,286/* ITU-R frame line number of the first VBI line287we can capture, of the first and second field.288The last line is determined by cropcap.bounds. */289.vbistart = { 7, 320 },290CROPCAP(/* minhdelayx1 */ 68,291/* hdelayx1 */ 186,292/* Should be (768 * 1135 + 944 / 2) / 944.293cropcap.defrect is used for image width294checks, so we keep the old value 924. */295/* swidth */ 924,296/* totalwidth */ 1135,297/* sqwidth */ 944,298/* vdelay */ 0x20,299/* sheight */ 576,300/* videostart0 */ 23)301/* bt878 (and bt848?) can capture another302line below active video. */303.cropcap.bounds.height = (576 + 2) + 0x20 - 2,304},{305.v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,306.name = "NTSC",307.Fsc = 28636363,308.swidth = 768,309.sheight = 480,310.totalwidth = 910,311.adelay = 0x68,312.bdelay = 0x5d,313.iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),314.scaledtwidth = 910,315.hdelayx1 = 128,316.hactivex1 = 910,317.vdelay = 0x1a,318.vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */319.sram = 1,320.vbistart = { 10, 273 },321CROPCAP(/* minhdelayx1 */ 68,322/* hdelayx1 */ 128,323/* Should be (640 * 910 + 780 / 2) / 780? */324/* swidth */ 768,325/* totalwidth */ 910,326/* sqwidth */ 780,327/* vdelay */ 0x1a,328/* sheight */ 480,329/* videostart0 */ 23)330},{331.v4l2_id = V4L2_STD_SECAM,332.name = "SECAM",333.Fsc = 35468950,334.swidth = 924,335.sheight = 576,336.totalwidth = 1135,337.adelay = 0x7f,338.bdelay = 0xb0,339.iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),340.scaledtwidth = 1135,341.hdelayx1 = 186,342.hactivex1 = 922,343.vdelay = 0x20,344.vbipack = 255,345.sram = 0, /* like PAL, correct? */346.vbistart = { 7, 320 },347CROPCAP(/* minhdelayx1 */ 68,348/* hdelayx1 */ 186,349/* swidth */ 924,350/* totalwidth */ 1135,351/* sqwidth */ 944,352/* vdelay */ 0x20,353/* sheight */ 576,354/* videostart0 */ 23)355},{356.v4l2_id = V4L2_STD_PAL_Nc,357.name = "PAL-Nc",358.Fsc = 28636363,359.swidth = 640,360.sheight = 576,361.totalwidth = 910,362.adelay = 0x68,363.bdelay = 0x5d,364.iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),365.scaledtwidth = 780,366.hdelayx1 = 130,367.hactivex1 = 734,368.vdelay = 0x1a,369.vbipack = 144,370.sram = -1,371.vbistart = { 7, 320 },372CROPCAP(/* minhdelayx1 */ 68,373/* hdelayx1 */ 130,374/* swidth */ (640 * 910 + 780 / 2) / 780,375/* totalwidth */ 910,376/* sqwidth */ 780,377/* vdelay */ 0x1a,378/* sheight */ 576,379/* videostart0 */ 23)380},{381.v4l2_id = V4L2_STD_PAL_M,382.name = "PAL-M",383.Fsc = 28636363,384.swidth = 640,385.sheight = 480,386.totalwidth = 910,387.adelay = 0x68,388.bdelay = 0x5d,389.iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),390.scaledtwidth = 780,391.hdelayx1 = 135,392.hactivex1 = 754,393.vdelay = 0x1a,394.vbipack = 144,395.sram = -1,396.vbistart = { 10, 273 },397CROPCAP(/* minhdelayx1 */ 68,398/* hdelayx1 */ 135,399/* swidth */ (640 * 910 + 780 / 2) / 780,400/* totalwidth */ 910,401/* sqwidth */ 780,402/* vdelay */ 0x1a,403/* sheight */ 480,404/* videostart0 */ 23)405},{406.v4l2_id = V4L2_STD_PAL_N,407.name = "PAL-N",408.Fsc = 35468950,409.swidth = 768,410.sheight = 576,411.totalwidth = 1135,412.adelay = 0x7f,413.bdelay = 0x72,414.iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),415.scaledtwidth = 944,416.hdelayx1 = 186,417.hactivex1 = 922,418.vdelay = 0x20,419.vbipack = 144,420.sram = -1,421.vbistart = { 7, 320 },422CROPCAP(/* minhdelayx1 */ 68,423/* hdelayx1 */ 186,424/* swidth */ (768 * 1135 + 944 / 2) / 944,425/* totalwidth */ 1135,426/* sqwidth */ 944,427/* vdelay */ 0x20,428/* sheight */ 576,429/* videostart0 */ 23)430},{431.v4l2_id = V4L2_STD_NTSC_M_JP,432.name = "NTSC-JP",433.Fsc = 28636363,434.swidth = 640,435.sheight = 480,436.totalwidth = 910,437.adelay = 0x68,438.bdelay = 0x5d,439.iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),440.scaledtwidth = 780,441.hdelayx1 = 135,442.hactivex1 = 754,443.vdelay = 0x16,444.vbipack = 144,445.sram = -1,446.vbistart = { 10, 273 },447CROPCAP(/* minhdelayx1 */ 68,448/* hdelayx1 */ 135,449/* swidth */ (640 * 910 + 780 / 2) / 780,450/* totalwidth */ 910,451/* sqwidth */ 780,452/* vdelay */ 0x16,453/* sheight */ 480,454/* videostart0 */ 23)455},{456/* that one hopefully works with the strange timing457* which video recorders produce when playing a NTSC458* tape on a PAL TV ... */459.v4l2_id = V4L2_STD_PAL_60,460.name = "PAL-60",461.Fsc = 35468950,462.swidth = 924,463.sheight = 480,464.totalwidth = 1135,465.adelay = 0x7f,466.bdelay = 0x72,467.iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),468.scaledtwidth = 1135,469.hdelayx1 = 186,470.hactivex1 = 924,471.vdelay = 0x1a,472.vbipack = 255,473.vtotal = 524,474.sram = -1,475.vbistart = { 10, 273 },476CROPCAP(/* minhdelayx1 */ 68,477/* hdelayx1 */ 186,478/* swidth */ 924,479/* totalwidth */ 1135,480/* sqwidth */ 944,481/* vdelay */ 0x1a,482/* sheight */ 480,483/* videostart0 */ 23)484}485};486static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);487488/* ----------------------------------------------------------------------- */489/* bttv format list490packed pixel formats must come first */491static const struct bttv_format formats[] = {492{493.name = "8 bpp, gray",494.fourcc = V4L2_PIX_FMT_GREY,495.btformat = BT848_COLOR_FMT_Y8,496.depth = 8,497.flags = FORMAT_FLAGS_PACKED,498},{499.name = "8 bpp, dithered color",500.fourcc = V4L2_PIX_FMT_HI240,501.btformat = BT848_COLOR_FMT_RGB8,502.depth = 8,503.flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,504},{505.name = "15 bpp RGB, le",506.fourcc = V4L2_PIX_FMT_RGB555,507.btformat = BT848_COLOR_FMT_RGB15,508.depth = 16,509.flags = FORMAT_FLAGS_PACKED,510},{511.name = "15 bpp RGB, be",512.fourcc = V4L2_PIX_FMT_RGB555X,513.btformat = BT848_COLOR_FMT_RGB15,514.btswap = 0x03, /* byteswap */515.depth = 16,516.flags = FORMAT_FLAGS_PACKED,517},{518.name = "16 bpp RGB, le",519.fourcc = V4L2_PIX_FMT_RGB565,520.btformat = BT848_COLOR_FMT_RGB16,521.depth = 16,522.flags = FORMAT_FLAGS_PACKED,523},{524.name = "16 bpp RGB, be",525.fourcc = V4L2_PIX_FMT_RGB565X,526.btformat = BT848_COLOR_FMT_RGB16,527.btswap = 0x03, /* byteswap */528.depth = 16,529.flags = FORMAT_FLAGS_PACKED,530},{531.name = "24 bpp RGB, le",532.fourcc = V4L2_PIX_FMT_BGR24,533.btformat = BT848_COLOR_FMT_RGB24,534.depth = 24,535.flags = FORMAT_FLAGS_PACKED,536},{537.name = "32 bpp RGB, le",538.fourcc = V4L2_PIX_FMT_BGR32,539.btformat = BT848_COLOR_FMT_RGB32,540.depth = 32,541.flags = FORMAT_FLAGS_PACKED,542},{543.name = "32 bpp RGB, be",544.fourcc = V4L2_PIX_FMT_RGB32,545.btformat = BT848_COLOR_FMT_RGB32,546.btswap = 0x0f, /* byte+word swap */547.depth = 32,548.flags = FORMAT_FLAGS_PACKED,549},{550.name = "4:2:2, packed, YUYV",551.fourcc = V4L2_PIX_FMT_YUYV,552.btformat = BT848_COLOR_FMT_YUY2,553.depth = 16,554.flags = FORMAT_FLAGS_PACKED,555},{556.name = "4:2:2, packed, YUYV",557.fourcc = V4L2_PIX_FMT_YUYV,558.btformat = BT848_COLOR_FMT_YUY2,559.depth = 16,560.flags = FORMAT_FLAGS_PACKED,561},{562.name = "4:2:2, packed, UYVY",563.fourcc = V4L2_PIX_FMT_UYVY,564.btformat = BT848_COLOR_FMT_YUY2,565.btswap = 0x03, /* byteswap */566.depth = 16,567.flags = FORMAT_FLAGS_PACKED,568},{569.name = "4:2:2, planar, Y-Cb-Cr",570.fourcc = V4L2_PIX_FMT_YUV422P,571.btformat = BT848_COLOR_FMT_YCrCb422,572.depth = 16,573.flags = FORMAT_FLAGS_PLANAR,574.hshift = 1,575.vshift = 0,576},{577.name = "4:2:0, planar, Y-Cb-Cr",578.fourcc = V4L2_PIX_FMT_YUV420,579.btformat = BT848_COLOR_FMT_YCrCb422,580.depth = 12,581.flags = FORMAT_FLAGS_PLANAR,582.hshift = 1,583.vshift = 1,584},{585.name = "4:2:0, planar, Y-Cr-Cb",586.fourcc = V4L2_PIX_FMT_YVU420,587.btformat = BT848_COLOR_FMT_YCrCb422,588.depth = 12,589.flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,590.hshift = 1,591.vshift = 1,592},{593.name = "4:1:1, planar, Y-Cb-Cr",594.fourcc = V4L2_PIX_FMT_YUV411P,595.btformat = BT848_COLOR_FMT_YCrCb411,596.depth = 12,597.flags = FORMAT_FLAGS_PLANAR,598.hshift = 2,599.vshift = 0,600},{601.name = "4:1:0, planar, Y-Cb-Cr",602.fourcc = V4L2_PIX_FMT_YUV410,603.btformat = BT848_COLOR_FMT_YCrCb411,604.depth = 9,605.flags = FORMAT_FLAGS_PLANAR,606.hshift = 2,607.vshift = 2,608},{609.name = "4:1:0, planar, Y-Cr-Cb",610.fourcc = V4L2_PIX_FMT_YVU410,611.btformat = BT848_COLOR_FMT_YCrCb411,612.depth = 9,613.flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,614.hshift = 2,615.vshift = 2,616},{617.name = "raw scanlines",618.fourcc = -1,619.btformat = BT848_COLOR_FMT_RAW,620.depth = 8,621.flags = FORMAT_FLAGS_RAW,622}623};624static const unsigned int FORMATS = ARRAY_SIZE(formats);625626/* ----------------------------------------------------------------------- */627628#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)629#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)630#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)631#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)632#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)633#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)634#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)635#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)636#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)637#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)638#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)639#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)640641static const struct v4l2_queryctrl no_ctl = {642.name = "42",643.flags = V4L2_CTRL_FLAG_DISABLED,644};645static const struct v4l2_queryctrl bttv_ctls[] = {646/* --- video --- */647{648.id = V4L2_CID_BRIGHTNESS,649.name = "Brightness",650.minimum = 0,651.maximum = 65535,652.step = 256,653.default_value = 32768,654.type = V4L2_CTRL_TYPE_INTEGER,655},{656.id = V4L2_CID_CONTRAST,657.name = "Contrast",658.minimum = 0,659.maximum = 65535,660.step = 128,661.default_value = 32768,662.type = V4L2_CTRL_TYPE_INTEGER,663},{664.id = V4L2_CID_SATURATION,665.name = "Saturation",666.minimum = 0,667.maximum = 65535,668.step = 128,669.default_value = 32768,670.type = V4L2_CTRL_TYPE_INTEGER,671},{672.id = V4L2_CID_HUE,673.name = "Hue",674.minimum = 0,675.maximum = 65535,676.step = 256,677.default_value = 32768,678.type = V4L2_CTRL_TYPE_INTEGER,679},680/* --- audio --- */681{682.id = V4L2_CID_AUDIO_MUTE,683.name = "Mute",684.minimum = 0,685.maximum = 1,686.type = V4L2_CTRL_TYPE_BOOLEAN,687},{688.id = V4L2_CID_AUDIO_VOLUME,689.name = "Volume",690.minimum = 0,691.maximum = 65535,692.step = 65535/100,693.default_value = 65535,694.type = V4L2_CTRL_TYPE_INTEGER,695},{696.id = V4L2_CID_AUDIO_BALANCE,697.name = "Balance",698.minimum = 0,699.maximum = 65535,700.step = 65535/100,701.default_value = 32768,702.type = V4L2_CTRL_TYPE_INTEGER,703},{704.id = V4L2_CID_AUDIO_BASS,705.name = "Bass",706.minimum = 0,707.maximum = 65535,708.step = 65535/100,709.default_value = 32768,710.type = V4L2_CTRL_TYPE_INTEGER,711},{712.id = V4L2_CID_AUDIO_TREBLE,713.name = "Treble",714.minimum = 0,715.maximum = 65535,716.step = 65535/100,717.default_value = 32768,718.type = V4L2_CTRL_TYPE_INTEGER,719},720/* --- private --- */721{722.id = V4L2_CID_PRIVATE_CHROMA_AGC,723.name = "chroma agc",724.minimum = 0,725.maximum = 1,726.type = V4L2_CTRL_TYPE_BOOLEAN,727},{728.id = V4L2_CID_PRIVATE_COMBFILTER,729.name = "combfilter",730.minimum = 0,731.maximum = 1,732.type = V4L2_CTRL_TYPE_BOOLEAN,733},{734.id = V4L2_CID_PRIVATE_AUTOMUTE,735.name = "automute",736.minimum = 0,737.maximum = 1,738.type = V4L2_CTRL_TYPE_BOOLEAN,739},{740.id = V4L2_CID_PRIVATE_LUMAFILTER,741.name = "luma decimation filter",742.minimum = 0,743.maximum = 1,744.type = V4L2_CTRL_TYPE_BOOLEAN,745},{746.id = V4L2_CID_PRIVATE_AGC_CRUSH,747.name = "agc crush",748.minimum = 0,749.maximum = 1,750.type = V4L2_CTRL_TYPE_BOOLEAN,751},{752.id = V4L2_CID_PRIVATE_VCR_HACK,753.name = "vcr hack",754.minimum = 0,755.maximum = 1,756.type = V4L2_CTRL_TYPE_BOOLEAN,757},{758.id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,759.name = "whitecrush upper",760.minimum = 0,761.maximum = 255,762.step = 1,763.default_value = 0xCF,764.type = V4L2_CTRL_TYPE_INTEGER,765},{766.id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,767.name = "whitecrush lower",768.minimum = 0,769.maximum = 255,770.step = 1,771.default_value = 0x7F,772.type = V4L2_CTRL_TYPE_INTEGER,773},{774.id = V4L2_CID_PRIVATE_UV_RATIO,775.name = "uv ratio",776.minimum = 0,777.maximum = 100,778.step = 1,779.default_value = 50,780.type = V4L2_CTRL_TYPE_INTEGER,781},{782.id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,783.name = "full luma range",784.minimum = 0,785.maximum = 1,786.type = V4L2_CTRL_TYPE_BOOLEAN,787},{788.id = V4L2_CID_PRIVATE_CORING,789.name = "coring",790.minimum = 0,791.maximum = 3,792.step = 1,793.default_value = 0,794.type = V4L2_CTRL_TYPE_INTEGER,795}796797798799};800801static const struct v4l2_queryctrl *ctrl_by_id(int id)802{803int i;804805for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++)806if (bttv_ctls[i].id == id)807return bttv_ctls+i;808809return NULL;810}811812/* ----------------------------------------------------------------------- */813/* resource management */814815/*816RESOURCE_ allocated by freed by817818VIDEO_READ bttv_read 1) bttv_read 2)819820VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF821VIDIOC_QBUF 1) bttv_release822VIDIOCMCAPTURE 1)823824OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off825VIDIOC_OVERLAY on VIDIOC_OVERLAY off8263) bttv_release827828VBI VIDIOC_STREAMON VIDIOC_STREAMOFF829VIDIOC_QBUF 1) bttv_release830bttv_read, bttv_poll 1) 4)8318321) The resource must be allocated when we enter buffer prepare functions833and remain allocated while buffers are in the DMA queue.8342) This is a single frame read.8353) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when836RESOURCE_OVERLAY is allocated.8374) This is a continuous read, implies VIDIOC_STREAMON.838839Note this driver permits video input and standard changes regardless if840resources are allocated.841*/842843#define VBI_RESOURCES (RESOURCE_VBI)844#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \845RESOURCE_VIDEO_STREAM | \846RESOURCE_OVERLAY)847848static849int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)850{851int xbits; /* mutual exclusive resources */852853if (fh->resources & bit)854/* have it already allocated */855return 1;856857xbits = bit;858if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))859xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;860861/* is it free? */862if (btv->resources & xbits) {863/* no, someone else uses it */864goto fail;865}866867if ((bit & VIDEO_RESOURCES)868&& 0 == (btv->resources & VIDEO_RESOURCES)) {869/* Do crop - use current, don't - use default parameters. */870__s32 top = btv->crop[!!fh->do_crop].rect.top;871872if (btv->vbi_end > top)873goto fail;874875/* We cannot capture the same line as video and VBI data.876Claim scan lines crop[].rect.top to bottom. */877btv->crop_start = top;878} else if (bit & VBI_RESOURCES) {879__s32 end = fh->vbi_fmt.end;880881if (end > btv->crop_start)882goto fail;883884/* Claim scan lines above fh->vbi_fmt.end. */885btv->vbi_end = end;886}887888/* it's free, grab it */889fh->resources |= bit;890btv->resources |= bit;891return 1;892893fail:894return 0;895}896897static898int check_btres(struct bttv_fh *fh, int bit)899{900return (fh->resources & bit);901}902903static904int locked_btres(struct bttv *btv, int bit)905{906return (btv->resources & bit);907}908909/* Call with btv->lock down. */910static void911disclaim_vbi_lines(struct bttv *btv)912{913btv->vbi_end = 0;914}915916/* Call with btv->lock down. */917static void918disclaim_video_lines(struct bttv *btv)919{920const struct bttv_tvnorm *tvnorm;921u8 crop;922923tvnorm = &bttv_tvnorms[btv->tvnorm];924btv->crop_start = tvnorm->cropcap.bounds.top925+ tvnorm->cropcap.bounds.height;926927/* VBI capturing ends at VDELAY, start of video capturing, no928matter how many lines the VBI RISC program expects. When video929capturing is off, it shall no longer "preempt" VBI capturing,930so we set VDELAY to maximum. */931crop = btread(BT848_E_CROP) | 0xc0;932btwrite(crop, BT848_E_CROP);933btwrite(0xfe, BT848_E_VDELAY_LO);934btwrite(crop, BT848_O_CROP);935btwrite(0xfe, BT848_O_VDELAY_LO);936}937938static939void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)940{941if ((fh->resources & bits) != bits) {942/* trying to free ressources not allocated by us ... */943printk("bttv: BUG! (btres)\n");944}945fh->resources &= ~bits;946btv->resources &= ~bits;947948bits = btv->resources;949950if (0 == (bits & VIDEO_RESOURCES))951disclaim_video_lines(btv);952953if (0 == (bits & VBI_RESOURCES))954disclaim_vbi_lines(btv);955}956957/* ----------------------------------------------------------------------- */958/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */959960/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C961PLL_X = Reference pre-divider (0=1, 1=2)962PLL_C = Post divider (0=6, 1=4)963PLL_I = Integer input964PLL_F = Fractional input965966F_input = 28.636363 MHz:967PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0968*/969970static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)971{972unsigned char fl, fh, fi;973974/* prevent overflows */975fin/=4;976fout/=4;977978fout*=12;979fi=fout/fin;980981fout=(fout%fin)*256;982fh=fout/fin;983984fout=(fout%fin)*256;985fl=fout/fin;986987btwrite(fl, BT848_PLL_F_LO);988btwrite(fh, BT848_PLL_F_HI);989btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);990}991992static void set_pll(struct bttv *btv)993{994int i;995996if (!btv->pll.pll_crystal)997return;998999if (btv->pll.pll_ofreq == btv->pll.pll_current) {1000dprintk("bttv%d: PLL: no change required\n",btv->c.nr);1001return;1002}10031004if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {1005/* no PLL needed */1006if (btv->pll.pll_current == 0)1007return;1008bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",1009btv->c.nr,btv->pll.pll_ifreq);1010btwrite(0x00,BT848_TGCTRL);1011btwrite(0x00,BT848_PLL_XCI);1012btv->pll.pll_current = 0;1013return;1014}10151016bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,1017btv->pll.pll_ifreq, btv->pll.pll_ofreq);1018set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);10191020for (i=0; i<10; i++) {1021/* Let other people run while the PLL stabilizes */1022bttv_printk(".");1023msleep(10);10241025if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {1026btwrite(0,BT848_DSTATUS);1027} else {1028btwrite(0x08,BT848_TGCTRL);1029btv->pll.pll_current = btv->pll.pll_ofreq;1030bttv_printk(" ok\n");1031return;1032}1033}1034btv->pll.pll_current = -1;1035bttv_printk("failed\n");1036return;1037}10381039/* used to switch between the bt848's analog/digital video capture modes */1040static void bt848A_set_timing(struct bttv *btv)1041{1042int i, len;1043int table_idx = bttv_tvnorms[btv->tvnorm].sram;1044int fsc = bttv_tvnorms[btv->tvnorm].Fsc;10451046if (btv->input == btv->dig) {1047dprintk("bttv%d: load digital timing table (table_idx=%d)\n",1048btv->c.nr,table_idx);10491050/* timing change...reset timing generator address */1051btwrite(0x00, BT848_TGCTRL);1052btwrite(0x02, BT848_TGCTRL);1053btwrite(0x00, BT848_TGCTRL);10541055len=SRAM_Table[table_idx][0];1056for(i = 1; i <= len; i++)1057btwrite(SRAM_Table[table_idx][i],BT848_TGLB);1058btv->pll.pll_ofreq = 27000000;10591060set_pll(btv);1061btwrite(0x11, BT848_TGCTRL);1062btwrite(0x41, BT848_DVSIF);1063} else {1064btv->pll.pll_ofreq = fsc;1065set_pll(btv);1066btwrite(0x0, BT848_DVSIF);1067}1068}10691070/* ----------------------------------------------------------------------- */10711072static void bt848_bright(struct bttv *btv, int bright)1073{1074int value;10751076// printk("bttv: set bright: %d\n",bright); // DEBUG1077btv->bright = bright;10781079/* We want -128 to 127 we get 0-65535 */1080value = (bright >> 8) - 128;1081btwrite(value & 0xff, BT848_BRIGHT);1082}10831084static void bt848_hue(struct bttv *btv, int hue)1085{1086int value;10871088btv->hue = hue;10891090/* -128 to 127 */1091value = (hue >> 8) - 128;1092btwrite(value & 0xff, BT848_HUE);1093}10941095static void bt848_contrast(struct bttv *btv, int cont)1096{1097int value,hibit;10981099btv->contrast = cont;11001101/* 0-511 */1102value = (cont >> 7);1103hibit = (value >> 6) & 4;1104btwrite(value & 0xff, BT848_CONTRAST_LO);1105btaor(hibit, ~4, BT848_E_CONTROL);1106btaor(hibit, ~4, BT848_O_CONTROL);1107}11081109static void bt848_sat(struct bttv *btv, int color)1110{1111int val_u,val_v,hibits;11121113btv->saturation = color;11141115/* 0-511 for the color */1116val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;1117val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;1118hibits = (val_u >> 7) & 2;1119hibits |= (val_v >> 8) & 1;1120btwrite(val_u & 0xff, BT848_SAT_U_LO);1121btwrite(val_v & 0xff, BT848_SAT_V_LO);1122btaor(hibits, ~3, BT848_E_CONTROL);1123btaor(hibits, ~3, BT848_O_CONTROL);1124}11251126/* ----------------------------------------------------------------------- */11271128static int1129video_mux(struct bttv *btv, unsigned int input)1130{1131int mux,mask2;11321133if (input >= bttv_tvcards[btv->c.type].video_inputs)1134return -EINVAL;11351136/* needed by RemoteVideo MX */1137mask2 = bttv_tvcards[btv->c.type].gpiomask2;1138if (mask2)1139gpio_inout(mask2,mask2);11401141if (input == btv->svhs) {1142btor(BT848_CONTROL_COMP, BT848_E_CONTROL);1143btor(BT848_CONTROL_COMP, BT848_O_CONTROL);1144} else {1145btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);1146btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);1147}1148mux = bttv_muxsel(btv, input);1149btaor(mux<<5, ~(3<<5), BT848_IFORM);1150dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",1151btv->c.nr,input,mux);11521153/* card specific hook */1154if(bttv_tvcards[btv->c.type].muxsel_hook)1155bttv_tvcards[btv->c.type].muxsel_hook (btv, input);1156return 0;1157}11581159static char *audio_modes[] = {1160"audio: tuner", "audio: radio", "audio: extern",1161"audio: intern", "audio: mute"1162};11631164static int1165audio_mux(struct bttv *btv, int input, int mute)1166{1167int gpio_val, signal;1168struct v4l2_control ctrl;11691170gpio_inout(bttv_tvcards[btv->c.type].gpiomask,1171bttv_tvcards[btv->c.type].gpiomask);1172signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;11731174btv->mute = mute;1175btv->audio = input;11761177/* automute */1178mute = mute || (btv->opt_automute && !signal && !btv->radio_user);11791180if (mute)1181gpio_val = bttv_tvcards[btv->c.type].gpiomute;1182else1183gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];11841185switch (btv->c.type) {1186case BTTV_BOARD_VOODOOTV_FM:1187case BTTV_BOARD_VOODOOTV_200:1188gpio_val = bttv_tda9880_setnorm(btv, gpio_val);1189break;11901191default:1192gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);1193}11941195if (bttv_gpio)1196bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);1197if (in_interrupt())1198return 0;11991200ctrl.id = V4L2_CID_AUDIO_MUTE;1201ctrl.value = btv->mute;1202bttv_call_all(btv, core, s_ctrl, &ctrl);1203if (btv->sd_msp34xx) {1204u32 in;12051206/* Note: the inputs tuner/radio/extern/intern are translated1207to msp routings. This assumes common behavior for all msp34001208based TV cards. When this assumption fails, then the1209specific MSP routing must be added to the card table.1210For now this is sufficient. */1211switch (input) {1212case TVAUDIO_INPUT_RADIO:1213in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,1214MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);1215break;1216case TVAUDIO_INPUT_EXTERN:1217in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,1218MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);1219break;1220case TVAUDIO_INPUT_INTERN:1221/* Yes, this is the same input as for RADIO. I doubt1222if this is ever used. The only board with an INTERN1223input is the BTTV_BOARD_AVERMEDIA98. I wonder how1224that was tested. My guess is that the whole INTERN1225input does not work. */1226in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,1227MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);1228break;1229case TVAUDIO_INPUT_TUNER:1230default:1231/* This is the only card that uses TUNER2, and afaik,1232is the only difference between the VOODOOTV_FM1233and VOODOOTV_200 */1234if (btv->c.type == BTTV_BOARD_VOODOOTV_200)1235in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \1236MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);1237else1238in = MSP_INPUT_DEFAULT;1239break;1240}1241v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing,1242in, MSP_OUTPUT_DEFAULT, 0);1243}1244if (btv->sd_tvaudio) {1245v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,1246input, 0, 0);1247}1248return 0;1249}12501251static inline int1252audio_mute(struct bttv *btv, int mute)1253{1254return audio_mux(btv, btv->audio, mute);1255}12561257static inline int1258audio_input(struct bttv *btv, int input)1259{1260return audio_mux(btv, input, btv->mute);1261}12621263static void1264bttv_crop_calc_limits(struct bttv_crop *c)1265{1266/* Scale factor min. 1:1, max. 16:1. Min. image size126748 x 32. Scaled width must be a multiple of 4. */12681269if (1) {1270/* For bug compatibility with VIDIOCGCAP and image1271size checks in earlier driver versions. */1272c->min_scaled_width = 48;1273c->min_scaled_height = 32;1274} else {1275c->min_scaled_width =1276(max(48, c->rect.width >> 4) + 3) & ~3;1277c->min_scaled_height =1278max(32, c->rect.height >> 4);1279}12801281c->max_scaled_width = c->rect.width & ~3;1282c->max_scaled_height = c->rect.height;1283}12841285static void1286bttv_crop_reset(struct bttv_crop *c, unsigned int norm)1287{1288c->rect = bttv_tvnorms[norm].cropcap.defrect;1289bttv_crop_calc_limits(c);1290}12911292/* Call with btv->lock down. */1293static int1294set_tvnorm(struct bttv *btv, unsigned int norm)1295{1296const struct bttv_tvnorm *tvnorm;1297v4l2_std_id id;12981299BUG_ON(norm >= BTTV_TVNORMS);1300BUG_ON(btv->tvnorm >= BTTV_TVNORMS);13011302tvnorm = &bttv_tvnorms[norm];13031304if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap,1305sizeof (tvnorm->cropcap))) {1306bttv_crop_reset(&btv->crop[0], norm);1307btv->crop[1] = btv->crop[0]; /* current = default */13081309if (0 == (btv->resources & VIDEO_RESOURCES)) {1310btv->crop_start = tvnorm->cropcap.bounds.top1311+ tvnorm->cropcap.bounds.height;1312}1313}13141315btv->tvnorm = norm;13161317btwrite(tvnorm->adelay, BT848_ADELAY);1318btwrite(tvnorm->bdelay, BT848_BDELAY);1319btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),1320BT848_IFORM);1321btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);1322btwrite(1, BT848_VBI_PACK_DEL);1323bt848A_set_timing(btv);13241325switch (btv->c.type) {1326case BTTV_BOARD_VOODOOTV_FM:1327case BTTV_BOARD_VOODOOTV_200:1328bttv_tda9880_setnorm(btv, gpio_read());1329break;1330}1331id = tvnorm->v4l2_id;1332bttv_call_all(btv, core, s_std, id);13331334return 0;1335}13361337/* Call with btv->lock down. */1338static void1339set_input(struct bttv *btv, unsigned int input, unsigned int norm)1340{1341unsigned long flags;13421343btv->input = input;1344if (irq_iswitch) {1345spin_lock_irqsave(&btv->s_lock,flags);1346if (btv->curr.frame_irq) {1347/* active capture -> delayed input switch */1348btv->new_input = input;1349} else {1350video_mux(btv,input);1351}1352spin_unlock_irqrestore(&btv->s_lock,flags);1353} else {1354video_mux(btv,input);1355}1356audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ?1357TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN);1358set_tvnorm(btv, norm);1359}13601361static void init_irqreg(struct bttv *btv)1362{1363/* clear status */1364btwrite(0xfffffUL, BT848_INT_STAT);13651366if (bttv_tvcards[btv->c.type].no_video) {1367/* i2c only */1368btwrite(BT848_INT_I2CDONE,1369BT848_INT_MASK);1370} else {1371/* full video */1372btwrite((btv->triton1) |1373(btv->gpioirq ? BT848_INT_GPINT : 0) |1374BT848_INT_SCERR |1375(fdsr ? BT848_INT_FDSR : 0) |1376BT848_INT_RISCI | BT848_INT_OCERR |1377BT848_INT_FMTCHG|BT848_INT_HLOCK|1378BT848_INT_I2CDONE,1379BT848_INT_MASK);1380}1381}13821383static void init_bt848(struct bttv *btv)1384{1385int val;13861387if (bttv_tvcards[btv->c.type].no_video) {1388/* very basic init only */1389init_irqreg(btv);1390return;1391}13921393btwrite(0x00, BT848_CAP_CTL);1394btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);1395btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);13961397/* set planar and packed mode trigger points and */1398/* set rising edge of inverted GPINTR pin as irq trigger */1399btwrite(BT848_GPIO_DMA_CTL_PKTP_32|1400BT848_GPIO_DMA_CTL_PLTP1_16|1401BT848_GPIO_DMA_CTL_PLTP23_16|1402BT848_GPIO_DMA_CTL_GPINTC|1403BT848_GPIO_DMA_CTL_GPINTI,1404BT848_GPIO_DMA_CTL);14051406val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;1407btwrite(val, BT848_E_SCLOOP);1408btwrite(val, BT848_O_SCLOOP);14091410btwrite(0x20, BT848_E_VSCALE_HI);1411btwrite(0x20, BT848_O_VSCALE_HI);1412btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),1413BT848_ADC);14141415btwrite(whitecrush_upper, BT848_WC_UP);1416btwrite(whitecrush_lower, BT848_WC_DOWN);14171418if (btv->opt_lumafilter) {1419btwrite(0, BT848_E_CONTROL);1420btwrite(0, BT848_O_CONTROL);1421} else {1422btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);1423btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);1424}14251426bt848_bright(btv, btv->bright);1427bt848_hue(btv, btv->hue);1428bt848_contrast(btv, btv->contrast);1429bt848_sat(btv, btv->saturation);14301431/* interrupt */1432init_irqreg(btv);1433}14341435static void bttv_reinit_bt848(struct bttv *btv)1436{1437unsigned long flags;14381439if (bttv_verbose)1440printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);1441spin_lock_irqsave(&btv->s_lock,flags);1442btv->errors=0;1443bttv_set_dma(btv,0);1444spin_unlock_irqrestore(&btv->s_lock,flags);14451446init_bt848(btv);1447btv->pll.pll_current = -1;1448set_input(btv, btv->input, btv->tvnorm);1449}14501451static int bttv_g_ctrl(struct file *file, void *priv,1452struct v4l2_control *c)1453{1454struct bttv_fh *fh = priv;1455struct bttv *btv = fh->btv;14561457switch (c->id) {1458case V4L2_CID_BRIGHTNESS:1459c->value = btv->bright;1460break;1461case V4L2_CID_HUE:1462c->value = btv->hue;1463break;1464case V4L2_CID_CONTRAST:1465c->value = btv->contrast;1466break;1467case V4L2_CID_SATURATION:1468c->value = btv->saturation;1469break;14701471case V4L2_CID_AUDIO_MUTE:1472case V4L2_CID_AUDIO_VOLUME:1473case V4L2_CID_AUDIO_BALANCE:1474case V4L2_CID_AUDIO_BASS:1475case V4L2_CID_AUDIO_TREBLE:1476bttv_call_all(btv, core, g_ctrl, c);1477break;14781479case V4L2_CID_PRIVATE_CHROMA_AGC:1480c->value = btv->opt_chroma_agc;1481break;1482case V4L2_CID_PRIVATE_COMBFILTER:1483c->value = btv->opt_combfilter;1484break;1485case V4L2_CID_PRIVATE_LUMAFILTER:1486c->value = btv->opt_lumafilter;1487break;1488case V4L2_CID_PRIVATE_AUTOMUTE:1489c->value = btv->opt_automute;1490break;1491case V4L2_CID_PRIVATE_AGC_CRUSH:1492c->value = btv->opt_adc_crush;1493break;1494case V4L2_CID_PRIVATE_VCR_HACK:1495c->value = btv->opt_vcr_hack;1496break;1497case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:1498c->value = btv->opt_whitecrush_upper;1499break;1500case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:1501c->value = btv->opt_whitecrush_lower;1502break;1503case V4L2_CID_PRIVATE_UV_RATIO:1504c->value = btv->opt_uv_ratio;1505break;1506case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:1507c->value = btv->opt_full_luma_range;1508break;1509case V4L2_CID_PRIVATE_CORING:1510c->value = btv->opt_coring;1511break;1512default:1513return -EINVAL;1514}1515return 0;1516}15171518static int bttv_s_ctrl(struct file *file, void *f,1519struct v4l2_control *c)1520{1521int err;1522int val;1523struct bttv_fh *fh = f;1524struct bttv *btv = fh->btv;15251526err = v4l2_prio_check(&btv->prio, fh->prio);1527if (0 != err)1528return err;15291530switch (c->id) {1531case V4L2_CID_BRIGHTNESS:1532bt848_bright(btv, c->value);1533break;1534case V4L2_CID_HUE:1535bt848_hue(btv, c->value);1536break;1537case V4L2_CID_CONTRAST:1538bt848_contrast(btv, c->value);1539break;1540case V4L2_CID_SATURATION:1541bt848_sat(btv, c->value);1542break;1543case V4L2_CID_AUDIO_MUTE:1544audio_mute(btv, c->value);1545/* fall through */1546case V4L2_CID_AUDIO_VOLUME:1547if (btv->volume_gpio)1548btv->volume_gpio(btv, c->value);15491550bttv_call_all(btv, core, s_ctrl, c);1551break;1552case V4L2_CID_AUDIO_BALANCE:1553case V4L2_CID_AUDIO_BASS:1554case V4L2_CID_AUDIO_TREBLE:1555bttv_call_all(btv, core, s_ctrl, c);1556break;15571558case V4L2_CID_PRIVATE_CHROMA_AGC:1559btv->opt_chroma_agc = c->value;1560val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;1561btwrite(val, BT848_E_SCLOOP);1562btwrite(val, BT848_O_SCLOOP);1563break;1564case V4L2_CID_PRIVATE_COMBFILTER:1565btv->opt_combfilter = c->value;1566break;1567case V4L2_CID_PRIVATE_LUMAFILTER:1568btv->opt_lumafilter = c->value;1569if (btv->opt_lumafilter) {1570btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);1571btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);1572} else {1573btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);1574btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);1575}1576break;1577case V4L2_CID_PRIVATE_AUTOMUTE:1578btv->opt_automute = c->value;1579break;1580case V4L2_CID_PRIVATE_AGC_CRUSH:1581btv->opt_adc_crush = c->value;1582btwrite(BT848_ADC_RESERVED |1583(btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),1584BT848_ADC);1585break;1586case V4L2_CID_PRIVATE_VCR_HACK:1587btv->opt_vcr_hack = c->value;1588break;1589case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:1590btv->opt_whitecrush_upper = c->value;1591btwrite(c->value, BT848_WC_UP);1592break;1593case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:1594btv->opt_whitecrush_lower = c->value;1595btwrite(c->value, BT848_WC_DOWN);1596break;1597case V4L2_CID_PRIVATE_UV_RATIO:1598btv->opt_uv_ratio = c->value;1599bt848_sat(btv, btv->saturation);1600break;1601case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:1602btv->opt_full_luma_range = c->value;1603btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);1604break;1605case V4L2_CID_PRIVATE_CORING:1606btv->opt_coring = c->value;1607btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);1608break;1609default:1610return -EINVAL;1611}1612return 0;1613}16141615/* ----------------------------------------------------------------------- */16161617void bttv_gpio_tracking(struct bttv *btv, char *comment)1618{1619unsigned int outbits, data;1620outbits = btread(BT848_GPIO_OUT_EN);1621data = btread(BT848_GPIO_DATA);1622printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",1623btv->c.nr,outbits,data & outbits, data & ~outbits, comment);1624}16251626static void bttv_field_count(struct bttv *btv)1627{1628int need_count = 0;16291630if (btv->users)1631need_count++;16321633if (need_count) {1634/* start field counter */1635btor(BT848_INT_VSYNC,BT848_INT_MASK);1636} else {1637/* stop field counter */1638btand(~BT848_INT_VSYNC,BT848_INT_MASK);1639btv->field_count = 0;1640}1641}16421643static const struct bttv_format*1644format_by_fourcc(int fourcc)1645{1646unsigned int i;16471648for (i = 0; i < FORMATS; i++) {1649if (-1 == formats[i].fourcc)1650continue;1651if (formats[i].fourcc == fourcc)1652return formats+i;1653}1654return NULL;1655}16561657/* ----------------------------------------------------------------------- */1658/* misc helpers */16591660static int1661bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,1662struct bttv_buffer *new)1663{1664struct bttv_buffer *old;1665unsigned long flags;1666int retval = 0;16671668dprintk("switch_overlay: enter [new=%p]\n",new);1669if (new)1670new->vb.state = VIDEOBUF_DONE;1671spin_lock_irqsave(&btv->s_lock,flags);1672old = btv->screen;1673btv->screen = new;1674btv->loop_irq |= 1;1675bttv_set_dma(btv, 0x03);1676spin_unlock_irqrestore(&btv->s_lock,flags);1677if (NULL != old) {1678dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);1679bttv_dma_free(&fh->cap,btv, old);1680kfree(old);1681}1682if (NULL == new)1683free_btres_lock(btv,fh,RESOURCE_OVERLAY);1684dprintk("switch_overlay: done\n");1685return retval;1686}16871688/* ----------------------------------------------------------------------- */1689/* video4linux (1) interface */16901691static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,1692struct bttv_buffer *buf,1693const struct bttv_format *fmt,1694unsigned int width, unsigned int height,1695enum v4l2_field field)1696{1697struct bttv_fh *fh = q->priv_data;1698int redo_dma_risc = 0;1699struct bttv_crop c;1700int norm;1701int rc;17021703/* check settings */1704if (NULL == fmt)1705return -EINVAL;1706if (fmt->btformat == BT848_COLOR_FMT_RAW) {1707width = RAW_BPL;1708height = RAW_LINES*2;1709if (width*height > buf->vb.bsize)1710return -EINVAL;1711buf->vb.size = buf->vb.bsize;17121713/* Make sure tvnorm and vbi_end remain consistent1714until we're done. */17151716norm = btv->tvnorm;17171718/* In this mode capturing always starts at defrect.top1719(default VDELAY), ignoring cropping parameters. */1720if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {1721return -EINVAL;1722}17231724c.rect = bttv_tvnorms[norm].cropcap.defrect;1725} else {1726norm = btv->tvnorm;1727c = btv->crop[!!fh->do_crop];17281729if (width < c.min_scaled_width ||1730width > c.max_scaled_width ||1731height < c.min_scaled_height)1732return -EINVAL;17331734switch (field) {1735case V4L2_FIELD_TOP:1736case V4L2_FIELD_BOTTOM:1737case V4L2_FIELD_ALTERNATE:1738/* btv->crop counts frame lines. Max. scale1739factor is 16:1 for frames, 8:1 for fields. */1740if (height * 2 > c.max_scaled_height)1741return -EINVAL;1742break;17431744default:1745if (height > c.max_scaled_height)1746return -EINVAL;1747break;1748}17491750buf->vb.size = (width * height * fmt->depth) >> 3;1751if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)1752return -EINVAL;1753}17541755/* alloc + fill struct bttv_buffer (if changed) */1756if (buf->vb.width != width || buf->vb.height != height ||1757buf->vb.field != field ||1758buf->tvnorm != norm || buf->fmt != fmt ||1759buf->crop.top != c.rect.top ||1760buf->crop.left != c.rect.left ||1761buf->crop.width != c.rect.width ||1762buf->crop.height != c.rect.height) {1763buf->vb.width = width;1764buf->vb.height = height;1765buf->vb.field = field;1766buf->tvnorm = norm;1767buf->fmt = fmt;1768buf->crop = c.rect;1769redo_dma_risc = 1;1770}17711772/* alloc risc memory */1773if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {1774redo_dma_risc = 1;1775if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))1776goto fail;1777}17781779if (redo_dma_risc)1780if (0 != (rc = bttv_buffer_risc(btv,buf)))1781goto fail;17821783buf->vb.state = VIDEOBUF_PREPARED;1784return 0;17851786fail:1787bttv_dma_free(q,btv,buf);1788return rc;1789}17901791static int1792buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)1793{1794struct bttv_fh *fh = q->priv_data;17951796*size = fh->fmt->depth*fh->width*fh->height >> 3;1797if (0 == *count)1798*count = gbuffers;1799if (*size * *count > gbuffers * gbufsize)1800*count = (gbuffers * gbufsize) / *size;1801return 0;1802}18031804static int1805buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,1806enum v4l2_field field)1807{1808struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);1809struct bttv_fh *fh = q->priv_data;18101811return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,1812fh->width, fh->height, field);1813}18141815static void1816buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)1817{1818struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);1819struct bttv_fh *fh = q->priv_data;1820struct bttv *btv = fh->btv;18211822buf->vb.state = VIDEOBUF_QUEUED;1823list_add_tail(&buf->vb.queue,&btv->capture);1824if (!btv->curr.frame_irq) {1825btv->loop_irq |= 1;1826bttv_set_dma(btv, 0x03);1827}1828}18291830static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)1831{1832struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);1833struct bttv_fh *fh = q->priv_data;18341835bttv_dma_free(q,fh->btv,buf);1836}18371838static struct videobuf_queue_ops bttv_video_qops = {1839.buf_setup = buffer_setup,1840.buf_prepare = buffer_prepare,1841.buf_queue = buffer_queue,1842.buf_release = buffer_release,1843};18441845static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)1846{1847struct bttv_fh *fh = priv;1848struct bttv *btv = fh->btv;1849unsigned int i;1850int err;18511852err = v4l2_prio_check(&btv->prio, fh->prio);1853if (err)1854goto err;18551856for (i = 0; i < BTTV_TVNORMS; i++)1857if (*id & bttv_tvnorms[i].v4l2_id)1858break;1859if (i == BTTV_TVNORMS) {1860err = -EINVAL;1861goto err;1862}18631864set_tvnorm(btv, i);18651866err:18671868return err;1869}18701871static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)1872{1873struct bttv_fh *fh = f;1874struct bttv *btv = fh->btv;18751876if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)1877*id = V4L2_STD_625_50;1878else1879*id = V4L2_STD_525_60;1880return 0;1881}18821883static int bttv_enum_input(struct file *file, void *priv,1884struct v4l2_input *i)1885{1886struct bttv_fh *fh = priv;1887struct bttv *btv = fh->btv;1888int rc = 0;18891890if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {1891rc = -EINVAL;1892goto err;1893}18941895i->type = V4L2_INPUT_TYPE_CAMERA;1896i->audioset = 1;18971898if (btv->tuner_type != TUNER_ABSENT && i->index == 0) {1899sprintf(i->name, "Television");1900i->type = V4L2_INPUT_TYPE_TUNER;1901i->tuner = 0;1902} else if (i->index == btv->svhs) {1903sprintf(i->name, "S-Video");1904} else {1905sprintf(i->name, "Composite%d", i->index);1906}19071908if (i->index == btv->input) {1909__u32 dstatus = btread(BT848_DSTATUS);1910if (0 == (dstatus & BT848_DSTATUS_PRES))1911i->status |= V4L2_IN_ST_NO_SIGNAL;1912if (0 == (dstatus & BT848_DSTATUS_HLOC))1913i->status |= V4L2_IN_ST_NO_H_LOCK;1914}19151916i->std = BTTV_NORMS;19171918err:19191920return rc;1921}19221923static int bttv_g_input(struct file *file, void *priv, unsigned int *i)1924{1925struct bttv_fh *fh = priv;1926struct bttv *btv = fh->btv;19271928*i = btv->input;19291930return 0;1931}19321933static int bttv_s_input(struct file *file, void *priv, unsigned int i)1934{1935struct bttv_fh *fh = priv;1936struct bttv *btv = fh->btv;19371938int err;19391940err = v4l2_prio_check(&btv->prio, fh->prio);1941if (unlikely(err))1942goto err;19431944if (i > bttv_tvcards[btv->c.type].video_inputs) {1945err = -EINVAL;1946goto err;1947}19481949set_input(btv, i, btv->tvnorm);19501951err:1952return 0;1953}19541955static int bttv_s_tuner(struct file *file, void *priv,1956struct v4l2_tuner *t)1957{1958struct bttv_fh *fh = priv;1959struct bttv *btv = fh->btv;1960int err;19611962if (unlikely(0 != t->index))1963return -EINVAL;19641965if (unlikely(btv->tuner_type == TUNER_ABSENT)) {1966err = -EINVAL;1967goto err;1968}19691970err = v4l2_prio_check(&btv->prio, fh->prio);1971if (unlikely(err))1972goto err;19731974bttv_call_all(btv, tuner, s_tuner, t);19751976if (btv->audio_mode_gpio)1977btv->audio_mode_gpio(btv, t, 1);19781979err:19801981return 0;1982}19831984static int bttv_g_frequency(struct file *file, void *priv,1985struct v4l2_frequency *f)1986{1987struct bttv_fh *fh = priv;1988struct bttv *btv = fh->btv;19891990f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;1991f->frequency = btv->freq;19921993return 0;1994}19951996static int bttv_s_frequency(struct file *file, void *priv,1997struct v4l2_frequency *f)1998{1999struct bttv_fh *fh = priv;2000struct bttv *btv = fh->btv;2001int err;20022003if (unlikely(f->tuner != 0))2004return -EINVAL;20052006err = v4l2_prio_check(&btv->prio, fh->prio);2007if (unlikely(err))2008goto err;20092010if (unlikely(f->type != (btv->radio_user2011? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) {2012err = -EINVAL;2013goto err;2014}2015btv->freq = f->frequency;2016bttv_call_all(btv, tuner, s_frequency, f);2017if (btv->has_matchbox && btv->radio_user)2018tea5757_set_freq(btv, btv->freq);2019err:20202021return 0;2022}20232024static int bttv_log_status(struct file *file, void *f)2025{2026struct bttv_fh *fh = f;2027struct bttv *btv = fh->btv;20282029printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n",2030btv->c.nr, btv->c.nr);2031bttv_call_all(btv, core, log_status);2032printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n",2033btv->c.nr, btv->c.nr);2034return 0;2035}20362037#ifdef CONFIG_VIDEO_ADV_DEBUG2038static int bttv_g_register(struct file *file, void *f,2039struct v4l2_dbg_register *reg)2040{2041struct bttv_fh *fh = f;2042struct bttv *btv = fh->btv;20432044if (!capable(CAP_SYS_ADMIN))2045return -EPERM;20462047if (!v4l2_chip_match_host(®->match))2048return -EINVAL;20492050/* bt848 has a 12-bit register space */2051reg->reg &= 0xfff;2052reg->val = btread(reg->reg);2053reg->size = 1;20542055return 0;2056}20572058static int bttv_s_register(struct file *file, void *f,2059struct v4l2_dbg_register *reg)2060{2061struct bttv_fh *fh = f;2062struct bttv *btv = fh->btv;20632064if (!capable(CAP_SYS_ADMIN))2065return -EPERM;20662067if (!v4l2_chip_match_host(®->match))2068return -EINVAL;20692070/* bt848 has a 12-bit register space */2071reg->reg &= 0xfff;2072btwrite(reg->val, reg->reg);20732074return 0;2075}2076#endif20772078/* Given cropping boundaries b and the scaled width and height of a2079single field or frame, which must not exceed hardware limits, this2080function adjusts the cropping parameters c. */2081static void2082bttv_crop_adjust (struct bttv_crop * c,2083const struct v4l2_rect * b,2084__s32 width,2085__s32 height,2086enum v4l2_field field)2087{2088__s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);2089__s32 max_left;2090__s32 max_top;20912092if (width < c->min_scaled_width) {2093/* Max. hor. scale factor 16:1. */2094c->rect.width = width * 16;2095} else if (width > c->max_scaled_width) {2096/* Min. hor. scale factor 1:1. */2097c->rect.width = width;20982099max_left = b->left + b->width - width;2100max_left = min(max_left, (__s32) MAX_HDELAY);2101if (c->rect.left > max_left)2102c->rect.left = max_left;2103}21042105if (height < c->min_scaled_height) {2106/* Max. vert. scale factor 16:1, single fields 8:1. */2107c->rect.height = height * 16;2108} else if (frame_height > c->max_scaled_height) {2109/* Min. vert. scale factor 1:1.2110Top and height count field lines times two. */2111c->rect.height = (frame_height + 1) & ~1;21122113max_top = b->top + b->height - c->rect.height;2114if (c->rect.top > max_top)2115c->rect.top = max_top;2116}21172118bttv_crop_calc_limits(c);2119}21202121/* Returns an error if scaling to a frame or single field with the given2122width and height is not possible with the current cropping parameters2123and width aligned according to width_mask. If adjust_size is TRUE the2124function may adjust the width and/or height instead, rounding width2125to (width + width_bias) & width_mask. If adjust_crop is TRUE it may2126also adjust the current cropping parameters to get closer to the2127desired image size. */2128static int2129limit_scaled_size_lock (struct bttv_fh * fh,2130__s32 * width,2131__s32 * height,2132enum v4l2_field field,2133unsigned int width_mask,2134unsigned int width_bias,2135int adjust_size,2136int adjust_crop)2137{2138struct bttv *btv = fh->btv;2139const struct v4l2_rect *b;2140struct bttv_crop *c;2141__s32 min_width;2142__s32 min_height;2143__s32 max_width;2144__s32 max_height;2145int rc;21462147BUG_ON((int) width_mask >= 0 ||2148width_bias >= (unsigned int) -width_mask);21492150/* Make sure tvnorm, vbi_end and the current cropping parameters2151remain consistent until we're done. */21522153b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;21542155/* Do crop - use current, don't - use default parameters. */2156c = &btv->crop[!!fh->do_crop];21572158if (fh->do_crop2159&& adjust_size2160&& adjust_crop2161&& !locked_btres(btv, VIDEO_RESOURCES)) {2162min_width = 48;2163min_height = 32;21642165/* We cannot scale up. When the scaled image is larger2166than crop.rect we adjust the crop.rect as required2167by the V4L2 spec, hence cropcap.bounds are our limit. */2168max_width = min(b->width, (__s32) MAX_HACTIVE);2169max_height = b->height;21702171/* We cannot capture the same line as video and VBI data.2172Note btv->vbi_end is really a minimum, see2173bttv_vbi_try_fmt(). */2174if (btv->vbi_end > b->top) {2175max_height -= btv->vbi_end - b->top;2176rc = -EBUSY;2177if (min_height > max_height)2178goto fail;2179}2180} else {2181rc = -EBUSY;2182if (btv->vbi_end > c->rect.top)2183goto fail;21842185min_width = c->min_scaled_width;2186min_height = c->min_scaled_height;2187max_width = c->max_scaled_width;2188max_height = c->max_scaled_height;21892190adjust_crop = 0;2191}21922193min_width = (min_width - width_mask - 1) & width_mask;2194max_width = max_width & width_mask;21952196/* Max. scale factor is 16:1 for frames, 8:1 for fields. */2197min_height = min_height;2198/* Min. scale factor is 1:1. */2199max_height >>= !V4L2_FIELD_HAS_BOTH(field);22002201if (adjust_size) {2202*width = clamp(*width, min_width, max_width);2203*height = clamp(*height, min_height, max_height);22042205/* Round after clamping to avoid overflow. */2206*width = (*width + width_bias) & width_mask;22072208if (adjust_crop) {2209bttv_crop_adjust(c, b, *width, *height, field);22102211if (btv->vbi_end > c->rect.top) {2212/* Move the crop window out of the way. */2213c->rect.top = btv->vbi_end;2214}2215}2216} else {2217rc = -EINVAL;2218if (*width < min_width ||2219*height < min_height ||2220*width > max_width ||2221*height > max_height ||22220 != (*width & ~width_mask))2223goto fail;2224}22252226rc = 0; /* success */22272228fail:22292230return rc;2231}22322233/* Returns an error if the given overlay window dimensions are not2234possible with the current cropping parameters. If adjust_size is2235TRUE the function may adjust the window width and/or height2236instead, however it always rounds the horizontal position and2237width as btcx_align() does. If adjust_crop is TRUE the function2238may also adjust the current cropping parameters to get closer2239to the desired window size. */2240static int2241verify_window_lock (struct bttv_fh * fh,2242struct v4l2_window * win,2243int adjust_size,2244int adjust_crop)2245{2246enum v4l2_field field;2247unsigned int width_mask;2248int rc;22492250if (win->w.width < 48 || win->w.height < 32)2251return -EINVAL;2252if (win->clipcount > 2048)2253return -EINVAL;22542255field = win->field;22562257if (V4L2_FIELD_ANY == field) {2258__s32 height2;22592260height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;2261field = (win->w.height > height2)2262? V4L2_FIELD_INTERLACED2263: V4L2_FIELD_TOP;2264}2265switch (field) {2266case V4L2_FIELD_TOP:2267case V4L2_FIELD_BOTTOM:2268case V4L2_FIELD_INTERLACED:2269break;2270default:2271return -EINVAL;2272}22732274/* 4-byte alignment. */2275if (NULL == fh->ovfmt)2276return -EINVAL;2277width_mask = ~0;2278switch (fh->ovfmt->depth) {2279case 8:2280case 24:2281width_mask = ~3;2282break;2283case 16:2284width_mask = ~1;2285break;2286case 32:2287break;2288default:2289BUG();2290}22912292win->w.width -= win->w.left & ~width_mask;2293win->w.left = (win->w.left - width_mask - 1) & width_mask;22942295rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height,2296field, width_mask,2297/* width_bias: round down */ 0,2298adjust_size, adjust_crop);2299if (0 != rc)2300return rc;23012302win->field = field;2303return 0;2304}23052306static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,2307struct v4l2_window *win, int fixup)2308{2309struct v4l2_clip *clips = NULL;2310int n,size,retval = 0;23112312if (NULL == fh->ovfmt)2313return -EINVAL;2314if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))2315return -EINVAL;2316retval = verify_window_lock(fh, win,2317/* adjust_size */ fixup,2318/* adjust_crop */ fixup);2319if (0 != retval)2320return retval;23212322/* copy clips -- luckily v4l1 + v4l2 are binary2323compatible here ...*/2324n = win->clipcount;2325size = sizeof(*clips)*(n+4);2326clips = kmalloc(size,GFP_KERNEL);2327if (NULL == clips)2328return -ENOMEM;2329if (n > 0) {2330if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {2331kfree(clips);2332return -EFAULT;2333}2334}23352336/* clip against screen */2337if (NULL != btv->fbuf.base)2338n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,2339&win->w, clips, n);2340btcx_sort_clips(clips,n);23412342/* 4-byte alignments */2343switch (fh->ovfmt->depth) {2344case 8:2345case 24:2346btcx_align(&win->w, clips, n, 3);2347break;2348case 16:2349btcx_align(&win->w, clips, n, 1);2350break;2351case 32:2352/* no alignment fixups needed */2353break;2354default:2355BUG();2356}23572358kfree(fh->ov.clips);2359fh->ov.clips = clips;2360fh->ov.nclips = n;23612362fh->ov.w = win->w;2363fh->ov.field = win->field;2364fh->ov.setup_ok = 1;23652366btv->init.ov.w.width = win->w.width;2367btv->init.ov.w.height = win->w.height;2368btv->init.ov.field = win->field;23692370/* update overlay if needed */2371retval = 0;2372if (check_btres(fh, RESOURCE_OVERLAY)) {2373struct bttv_buffer *new;23742375new = videobuf_sg_alloc(sizeof(*new));2376new->crop = btv->crop[!!fh->do_crop].rect;2377bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);2378retval = bttv_switch_overlay(btv,fh,new);2379}2380return retval;2381}23822383/* ----------------------------------------------------------------------- */23842385static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)2386{2387struct videobuf_queue* q = NULL;23882389switch (fh->type) {2390case V4L2_BUF_TYPE_VIDEO_CAPTURE:2391q = &fh->cap;2392break;2393case V4L2_BUF_TYPE_VBI_CAPTURE:2394q = &fh->vbi;2395break;2396default:2397BUG();2398}2399return q;2400}24012402static int bttv_resource(struct bttv_fh *fh)2403{2404int res = 0;24052406switch (fh->type) {2407case V4L2_BUF_TYPE_VIDEO_CAPTURE:2408res = RESOURCE_VIDEO_STREAM;2409break;2410case V4L2_BUF_TYPE_VBI_CAPTURE:2411res = RESOURCE_VBI;2412break;2413default:2414BUG();2415}2416return res;2417}24182419static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)2420{2421struct videobuf_queue *q = bttv_queue(fh);2422int res = bttv_resource(fh);24232424if (check_btres(fh,res))2425return -EBUSY;2426if (videobuf_queue_is_busy(q))2427return -EBUSY;2428fh->type = type;2429return 0;2430}24312432static void2433pix_format_set_size (struct v4l2_pix_format * f,2434const struct bttv_format * fmt,2435unsigned int width,2436unsigned int height)2437{2438f->width = width;2439f->height = height;24402441if (fmt->flags & FORMAT_FLAGS_PLANAR) {2442f->bytesperline = width; /* Y plane */2443f->sizeimage = (width * height * fmt->depth) >> 3;2444} else {2445f->bytesperline = (width * fmt->depth) >> 3;2446f->sizeimage = height * f->bytesperline;2447}2448}24492450static int bttv_g_fmt_vid_cap(struct file *file, void *priv,2451struct v4l2_format *f)2452{2453struct bttv_fh *fh = priv;24542455pix_format_set_size(&f->fmt.pix, fh->fmt,2456fh->width, fh->height);2457f->fmt.pix.field = fh->cap.field;2458f->fmt.pix.pixelformat = fh->fmt->fourcc;24592460return 0;2461}24622463static int bttv_g_fmt_vid_overlay(struct file *file, void *priv,2464struct v4l2_format *f)2465{2466struct bttv_fh *fh = priv;24672468f->fmt.win.w = fh->ov.w;2469f->fmt.win.field = fh->ov.field;24702471return 0;2472}24732474static int bttv_try_fmt_vid_cap(struct file *file, void *priv,2475struct v4l2_format *f)2476{2477const struct bttv_format *fmt;2478struct bttv_fh *fh = priv;2479struct bttv *btv = fh->btv;2480enum v4l2_field field;2481__s32 width, height;2482int rc;24832484fmt = format_by_fourcc(f->fmt.pix.pixelformat);2485if (NULL == fmt)2486return -EINVAL;24872488field = f->fmt.pix.field;24892490if (V4L2_FIELD_ANY == field) {2491__s32 height2;24922493height2 = btv->crop[!!fh->do_crop].rect.height >> 1;2494field = (f->fmt.pix.height > height2)2495? V4L2_FIELD_INTERLACED2496: V4L2_FIELD_BOTTOM;2497}24982499if (V4L2_FIELD_SEQ_BT == field)2500field = V4L2_FIELD_SEQ_TB;25012502switch (field) {2503case V4L2_FIELD_TOP:2504case V4L2_FIELD_BOTTOM:2505case V4L2_FIELD_ALTERNATE:2506case V4L2_FIELD_INTERLACED:2507break;2508case V4L2_FIELD_SEQ_TB:2509if (fmt->flags & FORMAT_FLAGS_PLANAR)2510return -EINVAL;2511break;2512default:2513return -EINVAL;2514}25152516width = f->fmt.pix.width;2517height = f->fmt.pix.height;25182519rc = limit_scaled_size_lock(fh, &width, &height, field,2520/* width_mask: 4 pixels */ ~3,2521/* width_bias: nearest */ 2,2522/* adjust_size */ 1,2523/* adjust_crop */ 0);2524if (0 != rc)2525return rc;25262527/* update data for the application */2528f->fmt.pix.field = field;2529pix_format_set_size(&f->fmt.pix, fmt, width, height);25302531return 0;2532}25332534static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,2535struct v4l2_format *f)2536{2537struct bttv_fh *fh = priv;25382539return verify_window_lock(fh, &f->fmt.win,2540/* adjust_size */ 1,2541/* adjust_crop */ 0);2542}25432544static int bttv_s_fmt_vid_cap(struct file *file, void *priv,2545struct v4l2_format *f)2546{2547int retval;2548const struct bttv_format *fmt;2549struct bttv_fh *fh = priv;2550struct bttv *btv = fh->btv;2551__s32 width, height;2552enum v4l2_field field;25532554retval = bttv_switch_type(fh, f->type);2555if (0 != retval)2556return retval;25572558retval = bttv_try_fmt_vid_cap(file, priv, f);2559if (0 != retval)2560return retval;25612562width = f->fmt.pix.width;2563height = f->fmt.pix.height;2564field = f->fmt.pix.field;25652566retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,2567/* width_mask: 4 pixels */ ~3,2568/* width_bias: nearest */ 2,2569/* adjust_size */ 1,2570/* adjust_crop */ 1);2571if (0 != retval)2572return retval;25732574f->fmt.pix.field = field;25752576fmt = format_by_fourcc(f->fmt.pix.pixelformat);25772578/* update our state informations */2579fh->fmt = fmt;2580fh->cap.field = f->fmt.pix.field;2581fh->cap.last = V4L2_FIELD_NONE;2582fh->width = f->fmt.pix.width;2583fh->height = f->fmt.pix.height;2584btv->init.fmt = fmt;2585btv->init.width = f->fmt.pix.width;2586btv->init.height = f->fmt.pix.height;25872588return 0;2589}25902591static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,2592struct v4l2_format *f)2593{2594struct bttv_fh *fh = priv;2595struct bttv *btv = fh->btv;25962597if (no_overlay > 0) {2598printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");2599return -EINVAL;2600}26012602return setup_window_lock(fh, btv, &f->fmt.win, 1);2603}26042605static int bttv_querycap(struct file *file, void *priv,2606struct v4l2_capability *cap)2607{2608struct bttv_fh *fh = priv;2609struct bttv *btv = fh->btv;26102611if (0 == v4l2)2612return -EINVAL;26132614strlcpy(cap->driver, "bttv", sizeof(cap->driver));2615strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));2616snprintf(cap->bus_info, sizeof(cap->bus_info),2617"PCI:%s", pci_name(btv->c.pci));2618cap->version = BTTV_VERSION_CODE;2619cap->capabilities =2620V4L2_CAP_VIDEO_CAPTURE |2621V4L2_CAP_VBI_CAPTURE |2622V4L2_CAP_READWRITE |2623V4L2_CAP_STREAMING;2624if (no_overlay <= 0)2625cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;26262627/*2628* No need to lock here: those vars are initialized during board2629* probe and remains untouched during the rest of the driver lifecycle2630*/2631if (btv->has_saa6588)2632cap->capabilities |= V4L2_CAP_RDS_CAPTURE;2633if (btv->tuner_type != TUNER_ABSENT)2634cap->capabilities |= V4L2_CAP_TUNER;2635return 0;2636}26372638static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f)2639{2640int index = -1, i;26412642for (i = 0; i < FORMATS; i++) {2643if (formats[i].fourcc != -1)2644index++;2645if ((unsigned int)index == f->index)2646break;2647}2648if (FORMATS == i)2649return -EINVAL;26502651f->pixelformat = formats[i].fourcc;2652strlcpy(f->description, formats[i].name, sizeof(f->description));26532654return i;2655}26562657static int bttv_enum_fmt_vid_cap(struct file *file, void *priv,2658struct v4l2_fmtdesc *f)2659{2660int rc = bttv_enum_fmt_cap_ovr(f);26612662if (rc < 0)2663return rc;26642665return 0;2666}26672668static int bttv_enum_fmt_vid_overlay(struct file *file, void *priv,2669struct v4l2_fmtdesc *f)2670{2671int rc;26722673if (no_overlay > 0) {2674printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");2675return -EINVAL;2676}26772678rc = bttv_enum_fmt_cap_ovr(f);26792680if (rc < 0)2681return rc;26822683if (!(formats[rc].flags & FORMAT_FLAGS_PACKED))2684return -EINVAL;26852686return 0;2687}26882689static int bttv_g_fbuf(struct file *file, void *f,2690struct v4l2_framebuffer *fb)2691{2692struct bttv_fh *fh = f;2693struct bttv *btv = fh->btv;26942695*fb = btv->fbuf;2696fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;2697if (fh->ovfmt)2698fb->fmt.pixelformat = fh->ovfmt->fourcc;2699return 0;2700}27012702static int bttv_overlay(struct file *file, void *f, unsigned int on)2703{2704struct bttv_fh *fh = f;2705struct bttv *btv = fh->btv;2706struct bttv_buffer *new;2707int retval = 0;27082709if (on) {2710/* verify args */2711if (unlikely(!btv->fbuf.base)) {2712return -EINVAL;2713}2714if (unlikely(!fh->ov.setup_ok)) {2715dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);2716retval = -EINVAL;2717}2718if (retval)2719return retval;2720}27212722if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))2723return -EBUSY;27242725if (on) {2726fh->ov.tvnorm = btv->tvnorm;2727new = videobuf_sg_alloc(sizeof(*new));2728new->crop = btv->crop[!!fh->do_crop].rect;2729bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);2730} else {2731new = NULL;2732}27332734/* switch over */2735retval = bttv_switch_overlay(btv, fh, new);2736return retval;2737}27382739static int bttv_s_fbuf(struct file *file, void *f,2740struct v4l2_framebuffer *fb)2741{2742struct bttv_fh *fh = f;2743struct bttv *btv = fh->btv;2744const struct bttv_format *fmt;2745int retval;27462747if (!capable(CAP_SYS_ADMIN) &&2748!capable(CAP_SYS_RAWIO))2749return -EPERM;27502751/* check args */2752fmt = format_by_fourcc(fb->fmt.pixelformat);2753if (NULL == fmt)2754return -EINVAL;2755if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))2756return -EINVAL;27572758retval = -EINVAL;2759if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {2760__s32 width = fb->fmt.width;2761__s32 height = fb->fmt.height;27622763retval = limit_scaled_size_lock(fh, &width, &height,2764V4L2_FIELD_INTERLACED,2765/* width_mask */ ~3,2766/* width_bias */ 2,2767/* adjust_size */ 0,2768/* adjust_crop */ 0);2769if (0 != retval)2770return retval;2771}27722773/* ok, accept it */2774btv->fbuf.base = fb->base;2775btv->fbuf.fmt.width = fb->fmt.width;2776btv->fbuf.fmt.height = fb->fmt.height;2777if (0 != fb->fmt.bytesperline)2778btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;2779else2780btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;27812782retval = 0;2783fh->ovfmt = fmt;2784btv->init.ovfmt = fmt;2785if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {2786fh->ov.w.left = 0;2787fh->ov.w.top = 0;2788fh->ov.w.width = fb->fmt.width;2789fh->ov.w.height = fb->fmt.height;2790btv->init.ov.w.width = fb->fmt.width;2791btv->init.ov.w.height = fb->fmt.height;2792kfree(fh->ov.clips);2793fh->ov.clips = NULL;2794fh->ov.nclips = 0;27952796if (check_btres(fh, RESOURCE_OVERLAY)) {2797struct bttv_buffer *new;27982799new = videobuf_sg_alloc(sizeof(*new));2800new->crop = btv->crop[!!fh->do_crop].rect;2801bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);2802retval = bttv_switch_overlay(btv, fh, new);2803}2804}2805return retval;2806}28072808static int bttv_reqbufs(struct file *file, void *priv,2809struct v4l2_requestbuffers *p)2810{2811struct bttv_fh *fh = priv;2812return videobuf_reqbufs(bttv_queue(fh), p);2813}28142815static int bttv_querybuf(struct file *file, void *priv,2816struct v4l2_buffer *b)2817{2818struct bttv_fh *fh = priv;2819return videobuf_querybuf(bttv_queue(fh), b);2820}28212822static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)2823{2824struct bttv_fh *fh = priv;2825struct bttv *btv = fh->btv;2826int res = bttv_resource(fh);28272828if (!check_alloc_btres_lock(btv, fh, res))2829return -EBUSY;28302831return videobuf_qbuf(bttv_queue(fh), b);2832}28332834static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)2835{2836struct bttv_fh *fh = priv;2837return videobuf_dqbuf(bttv_queue(fh), b,2838file->f_flags & O_NONBLOCK);2839}28402841static int bttv_streamon(struct file *file, void *priv,2842enum v4l2_buf_type type)2843{2844struct bttv_fh *fh = priv;2845struct bttv *btv = fh->btv;2846int res = bttv_resource(fh);28472848if (!check_alloc_btres_lock(btv, fh, res))2849return -EBUSY;2850return videobuf_streamon(bttv_queue(fh));2851}285228532854static int bttv_streamoff(struct file *file, void *priv,2855enum v4l2_buf_type type)2856{2857struct bttv_fh *fh = priv;2858struct bttv *btv = fh->btv;2859int retval;2860int res = bttv_resource(fh);286128622863retval = videobuf_streamoff(bttv_queue(fh));2864if (retval < 0)2865return retval;2866free_btres_lock(btv, fh, res);2867return 0;2868}28692870static int bttv_queryctrl(struct file *file, void *priv,2871struct v4l2_queryctrl *c)2872{2873struct bttv_fh *fh = priv;2874struct bttv *btv = fh->btv;2875const struct v4l2_queryctrl *ctrl;28762877if ((c->id < V4L2_CID_BASE ||2878c->id >= V4L2_CID_LASTP1) &&2879(c->id < V4L2_CID_PRIVATE_BASE ||2880c->id >= V4L2_CID_PRIVATE_LASTP1))2881return -EINVAL;28822883if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))2884*c = no_ctl;2885else {2886ctrl = ctrl_by_id(c->id);28872888*c = (NULL != ctrl) ? *ctrl : no_ctl;2889}28902891return 0;2892}28932894static int bttv_g_parm(struct file *file, void *f,2895struct v4l2_streamparm *parm)2896{2897struct bttv_fh *fh = f;2898struct bttv *btv = fh->btv;28992900v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,2901&parm->parm.capture.timeperframe);29022903return 0;2904}29052906static int bttv_g_tuner(struct file *file, void *priv,2907struct v4l2_tuner *t)2908{2909struct bttv_fh *fh = priv;2910struct bttv *btv = fh->btv;29112912if (btv->tuner_type == TUNER_ABSENT)2913return -EINVAL;2914if (0 != t->index)2915return -EINVAL;29162917t->rxsubchans = V4L2_TUNER_SUB_MONO;2918bttv_call_all(btv, tuner, g_tuner, t);2919strcpy(t->name, "Television");2920t->capability = V4L2_TUNER_CAP_NORM;2921t->type = V4L2_TUNER_ANALOG_TV;2922if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)2923t->signal = 0xffff;29242925if (btv->audio_mode_gpio)2926btv->audio_mode_gpio(btv, t, 0);29272928return 0;2929}29302931static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)2932{2933struct bttv_fh *fh = f;2934struct bttv *btv = fh->btv;29352936*p = v4l2_prio_max(&btv->prio);29372938return 0;2939}29402941static int bttv_s_priority(struct file *file, void *f,2942enum v4l2_priority prio)2943{2944struct bttv_fh *fh = f;2945struct bttv *btv = fh->btv;2946int rc;29472948rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);29492950return rc;2951}29522953static int bttv_cropcap(struct file *file, void *priv,2954struct v4l2_cropcap *cap)2955{2956struct bttv_fh *fh = priv;2957struct bttv *btv = fh->btv;29582959if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&2960cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)2961return -EINVAL;29622963*cap = bttv_tvnorms[btv->tvnorm].cropcap;29642965return 0;2966}29672968static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)2969{2970struct bttv_fh *fh = f;2971struct bttv *btv = fh->btv;29722973if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&2974crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)2975return -EINVAL;29762977/* No fh->do_crop = 1; because btv->crop[1] may be2978inconsistent with fh->width or fh->height and apps2979do not expect a change here. */29802981crop->c = btv->crop[!!fh->do_crop].rect;29822983return 0;2984}29852986static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)2987{2988struct bttv_fh *fh = f;2989struct bttv *btv = fh->btv;2990const struct v4l2_rect *b;2991int retval;2992struct bttv_crop c;2993__s32 b_left;2994__s32 b_top;2995__s32 b_right;2996__s32 b_bottom;29972998if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&2999crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)3000return -EINVAL;30013002/* Make sure tvnorm, vbi_end and the current cropping3003parameters remain consistent until we're done. Note3004read() may change vbi_end in check_alloc_btres_lock(). */3005retval = v4l2_prio_check(&btv->prio, fh->prio);3006if (0 != retval) {3007return retval;3008}30093010retval = -EBUSY;30113012if (locked_btres(fh->btv, VIDEO_RESOURCES)) {3013return retval;3014}30153016b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;30173018b_left = b->left;3019b_right = b_left + b->width;3020b_bottom = b->top + b->height;30213022b_top = max(b->top, btv->vbi_end);3023if (b_top + 32 >= b_bottom) {3024return retval;3025}30263027/* Min. scaled size 48 x 32. */3028c.rect.left = clamp(crop->c.left, b_left, b_right - 48);3029c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);30303031c.rect.width = clamp(crop->c.width,303248, b_right - c.rect.left);30333034c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);3035/* Top and height must be a multiple of two. */3036c.rect.top = (c.rect.top + 1) & ~1;30373038c.rect.height = clamp(crop->c.height,303932, b_bottom - c.rect.top);3040c.rect.height = (c.rect.height + 1) & ~1;30413042bttv_crop_calc_limits(&c);30433044btv->crop[1] = c;30453046fh->do_crop = 1;30473048if (fh->width < c.min_scaled_width) {3049fh->width = c.min_scaled_width;3050btv->init.width = c.min_scaled_width;3051} else if (fh->width > c.max_scaled_width) {3052fh->width = c.max_scaled_width;3053btv->init.width = c.max_scaled_width;3054}30553056if (fh->height < c.min_scaled_height) {3057fh->height = c.min_scaled_height;3058btv->init.height = c.min_scaled_height;3059} else if (fh->height > c.max_scaled_height) {3060fh->height = c.max_scaled_height;3061btv->init.height = c.max_scaled_height;3062}30633064return 0;3065}30663067static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)3068{3069if (unlikely(a->index))3070return -EINVAL;30713072strcpy(a->name, "audio");3073return 0;3074}30753076static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)3077{3078if (unlikely(a->index))3079return -EINVAL;30803081return 0;3082}30833084static ssize_t bttv_read(struct file *file, char __user *data,3085size_t count, loff_t *ppos)3086{3087struct bttv_fh *fh = file->private_data;3088int retval = 0;30893090if (fh->btv->errors)3091bttv_reinit_bt848(fh->btv);3092dprintk("bttv%d: read count=%d type=%s\n",3093fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);30943095switch (fh->type) {3096case V4L2_BUF_TYPE_VIDEO_CAPTURE:3097if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) {3098/* VIDEO_READ in use by another fh,3099or VIDEO_STREAM by any fh. */3100return -EBUSY;3101}3102retval = videobuf_read_one(&fh->cap, data, count, ppos,3103file->f_flags & O_NONBLOCK);3104free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ);3105break;3106case V4L2_BUF_TYPE_VBI_CAPTURE:3107if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))3108return -EBUSY;3109retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,3110file->f_flags & O_NONBLOCK);3111break;3112default:3113BUG();3114}3115return retval;3116}31173118static unsigned int bttv_poll(struct file *file, poll_table *wait)3119{3120struct bttv_fh *fh = file->private_data;3121struct bttv_buffer *buf;3122enum v4l2_field field;3123unsigned int rc = POLLERR;31243125if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {3126if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))3127return POLLERR;3128return videobuf_poll_stream(file, &fh->vbi, wait);3129}31303131if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {3132/* streaming capture */3133if (list_empty(&fh->cap.stream))3134goto err;3135buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);3136} else {3137/* read() capture */3138if (NULL == fh->cap.read_buf) {3139/* need to capture a new frame */3140if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))3141goto err;3142fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize);3143if (NULL == fh->cap.read_buf)3144goto err;3145fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;3146field = videobuf_next_field(&fh->cap);3147if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {3148kfree (fh->cap.read_buf);3149fh->cap.read_buf = NULL;3150goto err;3151}3152fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);3153fh->cap.read_off = 0;3154}3155buf = (struct bttv_buffer*)fh->cap.read_buf;3156}31573158poll_wait(file, &buf->vb.done, wait);3159if (buf->vb.state == VIDEOBUF_DONE ||3160buf->vb.state == VIDEOBUF_ERROR)3161rc = POLLIN|POLLRDNORM;3162else3163rc = 0;3164err:3165return rc;3166}31673168static int bttv_open(struct file *file)3169{3170struct video_device *vdev = video_devdata(file);3171struct bttv *btv = video_drvdata(file);3172struct bttv_fh *fh;3173enum v4l2_buf_type type = 0;31743175dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev));31763177if (vdev->vfl_type == VFL_TYPE_GRABBER) {3178type = V4L2_BUF_TYPE_VIDEO_CAPTURE;3179} else if (vdev->vfl_type == VFL_TYPE_VBI) {3180type = V4L2_BUF_TYPE_VBI_CAPTURE;3181} else {3182WARN_ON(1);3183return -ENODEV;3184}31853186dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",3187btv->c.nr,v4l2_type_names[type]);31883189/* allocate per filehandle data */3190fh = kmalloc(sizeof(*fh), GFP_KERNEL);3191if (unlikely(!fh))3192return -ENOMEM;3193file->private_data = fh;31943195*fh = btv->init;31963197fh->type = type;3198fh->ov.setup_ok = 0;31993200v4l2_prio_open(&btv->prio, &fh->prio);32013202videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,3203&btv->c.pci->dev, &btv->s_lock,3204V4L2_BUF_TYPE_VIDEO_CAPTURE,3205V4L2_FIELD_INTERLACED,3206sizeof(struct bttv_buffer),3207fh, &btv->lock);3208videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,3209&btv->c.pci->dev, &btv->s_lock,3210V4L2_BUF_TYPE_VBI_CAPTURE,3211V4L2_FIELD_SEQ_TB,3212sizeof(struct bttv_buffer),3213fh, &btv->lock);3214set_tvnorm(btv,btv->tvnorm);3215set_input(btv, btv->input, btv->tvnorm);32163217btv->users++;32183219/* The V4L2 spec requires one global set of cropping parameters3220which only change on request. These are stored in btv->crop[1].3221However for compatibility with V4L apps and cropping unaware3222V4L2 apps we now reset the cropping parameters as seen through3223this fh, which is to say VIDIOC_G_CROP and scaling limit checks3224will use btv->crop[0], the default cropping parameters for the3225current video standard, and VIDIOC_S_FMT will not implicitely3226change the cropping parameters until VIDIOC_S_CROP has been3227called. */3228fh->do_crop = !reset_crop; /* module parameter */32293230/* Likewise there should be one global set of VBI capture3231parameters, but for compatibility with V4L apps and earlier3232driver versions each fh has its own parameters. */3233bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);32343235bttv_field_count(btv);3236return 0;3237}32383239static int bttv_release(struct file *file)3240{3241struct bttv_fh *fh = file->private_data;3242struct bttv *btv = fh->btv;32433244/* turn off overlay */3245if (check_btres(fh, RESOURCE_OVERLAY))3246bttv_switch_overlay(btv,fh,NULL);32473248/* stop video capture */3249if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {3250videobuf_streamoff(&fh->cap);3251free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM);3252}3253if (fh->cap.read_buf) {3254buffer_release(&fh->cap,fh->cap.read_buf);3255kfree(fh->cap.read_buf);3256}3257if (check_btres(fh, RESOURCE_VIDEO_READ)) {3258free_btres_lock(btv, fh, RESOURCE_VIDEO_READ);3259}32603261/* stop vbi capture */3262if (check_btres(fh, RESOURCE_VBI)) {3263videobuf_stop(&fh->vbi);3264free_btres_lock(btv,fh,RESOURCE_VBI);3265}32663267/* free stuff */32683269videobuf_mmap_free(&fh->cap);3270videobuf_mmap_free(&fh->vbi);3271v4l2_prio_close(&btv->prio, fh->prio);3272file->private_data = NULL;3273kfree(fh);32743275btv->users--;3276bttv_field_count(btv);32773278if (!btv->users)3279audio_mute(btv, 1);32803281return 0;3282}32833284static int3285bttv_mmap(struct file *file, struct vm_area_struct *vma)3286{3287struct bttv_fh *fh = file->private_data;32883289dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",3290fh->btv->c.nr, v4l2_type_names[fh->type],3291vma->vm_start, vma->vm_end - vma->vm_start);3292return videobuf_mmap_mapper(bttv_queue(fh),vma);3293}32943295static const struct v4l2_file_operations bttv_fops =3296{3297.owner = THIS_MODULE,3298.open = bttv_open,3299.release = bttv_release,3300.unlocked_ioctl = video_ioctl2,3301.read = bttv_read,3302.mmap = bttv_mmap,3303.poll = bttv_poll,3304};33053306static const struct v4l2_ioctl_ops bttv_ioctl_ops = {3307.vidioc_querycap = bttv_querycap,3308.vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap,3309.vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap,3310.vidioc_try_fmt_vid_cap = bttv_try_fmt_vid_cap,3311.vidioc_s_fmt_vid_cap = bttv_s_fmt_vid_cap,3312.vidioc_enum_fmt_vid_overlay = bttv_enum_fmt_vid_overlay,3313.vidioc_g_fmt_vid_overlay = bttv_g_fmt_vid_overlay,3314.vidioc_try_fmt_vid_overlay = bttv_try_fmt_vid_overlay,3315.vidioc_s_fmt_vid_overlay = bttv_s_fmt_vid_overlay,3316.vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap,3317.vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap,3318.vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap,3319.vidioc_g_audio = bttv_g_audio,3320.vidioc_s_audio = bttv_s_audio,3321.vidioc_cropcap = bttv_cropcap,3322.vidioc_reqbufs = bttv_reqbufs,3323.vidioc_querybuf = bttv_querybuf,3324.vidioc_qbuf = bttv_qbuf,3325.vidioc_dqbuf = bttv_dqbuf,3326.vidioc_s_std = bttv_s_std,3327.vidioc_enum_input = bttv_enum_input,3328.vidioc_g_input = bttv_g_input,3329.vidioc_s_input = bttv_s_input,3330.vidioc_queryctrl = bttv_queryctrl,3331.vidioc_g_ctrl = bttv_g_ctrl,3332.vidioc_s_ctrl = bttv_s_ctrl,3333.vidioc_streamon = bttv_streamon,3334.vidioc_streamoff = bttv_streamoff,3335.vidioc_g_tuner = bttv_g_tuner,3336.vidioc_s_tuner = bttv_s_tuner,3337.vidioc_g_crop = bttv_g_crop,3338.vidioc_s_crop = bttv_s_crop,3339.vidioc_g_fbuf = bttv_g_fbuf,3340.vidioc_s_fbuf = bttv_s_fbuf,3341.vidioc_overlay = bttv_overlay,3342.vidioc_g_priority = bttv_g_priority,3343.vidioc_s_priority = bttv_s_priority,3344.vidioc_g_parm = bttv_g_parm,3345.vidioc_g_frequency = bttv_g_frequency,3346.vidioc_s_frequency = bttv_s_frequency,3347.vidioc_log_status = bttv_log_status,3348.vidioc_querystd = bttv_querystd,3349#ifdef CONFIG_VIDEO_ADV_DEBUG3350.vidioc_g_register = bttv_g_register,3351.vidioc_s_register = bttv_s_register,3352#endif3353};33543355static struct video_device bttv_video_template = {3356.fops = &bttv_fops,3357.ioctl_ops = &bttv_ioctl_ops,3358.tvnorms = BTTV_NORMS,3359.current_norm = V4L2_STD_PAL,3360};33613362/* ----------------------------------------------------------------------- */3363/* radio interface */33643365static int radio_open(struct file *file)3366{3367struct video_device *vdev = video_devdata(file);3368struct bttv *btv = video_drvdata(file);3369struct bttv_fh *fh;33703371dprintk("bttv: open dev=%s\n", video_device_node_name(vdev));33723373dprintk("bttv%d: open called (radio)\n",btv->c.nr);33743375/* allocate per filehandle data */3376fh = kmalloc(sizeof(*fh), GFP_KERNEL);3377if (unlikely(!fh))3378return -ENOMEM;3379file->private_data = fh;3380*fh = btv->init;33813382v4l2_prio_open(&btv->prio, &fh->prio);33833384btv->radio_user++;33853386bttv_call_all(btv, tuner, s_radio);3387audio_input(btv,TVAUDIO_INPUT_RADIO);33883389return 0;3390}33913392static int radio_release(struct file *file)3393{3394struct bttv_fh *fh = file->private_data;3395struct bttv *btv = fh->btv;3396struct saa6588_command cmd;33973398v4l2_prio_close(&btv->prio, fh->prio);3399file->private_data = NULL;3400kfree(fh);34013402btv->radio_user--;34033404bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);34053406return 0;3407}34083409static int radio_querycap(struct file *file, void *priv,3410struct v4l2_capability *cap)3411{3412struct bttv_fh *fh = priv;3413struct bttv *btv = fh->btv;34143415strcpy(cap->driver, "bttv");3416strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));3417sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));3418cap->version = BTTV_VERSION_CODE;3419cap->capabilities = V4L2_CAP_TUNER;34203421return 0;3422}34233424static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)3425{3426struct bttv_fh *fh = priv;3427struct bttv *btv = fh->btv;34283429if (btv->tuner_type == TUNER_ABSENT)3430return -EINVAL;3431if (0 != t->index)3432return -EINVAL;3433strcpy(t->name, "Radio");3434t->type = V4L2_TUNER_RADIO;34353436bttv_call_all(btv, tuner, g_tuner, t);34373438if (btv->audio_mode_gpio)3439btv->audio_mode_gpio(btv, t, 0);34403441return 0;3442}34433444static int radio_enum_input(struct file *file, void *priv,3445struct v4l2_input *i)3446{3447if (i->index != 0)3448return -EINVAL;34493450strcpy(i->name, "Radio");3451i->type = V4L2_INPUT_TYPE_TUNER;34523453return 0;3454}34553456static int radio_g_audio(struct file *file, void *priv,3457struct v4l2_audio *a)3458{3459if (unlikely(a->index))3460return -EINVAL;34613462strcpy(a->name, "Radio");34633464return 0;3465}34663467static int radio_s_tuner(struct file *file, void *priv,3468struct v4l2_tuner *t)3469{3470struct bttv_fh *fh = priv;3471struct bttv *btv = fh->btv;34723473if (0 != t->index)3474return -EINVAL;34753476bttv_call_all(btv, tuner, s_tuner, t);3477return 0;3478}34793480static int radio_s_audio(struct file *file, void *priv,3481struct v4l2_audio *a)3482{3483if (unlikely(a->index))3484return -EINVAL;34853486return 0;3487}34883489static int radio_s_input(struct file *filp, void *priv, unsigned int i)3490{3491if (unlikely(i))3492return -EINVAL;34933494return 0;3495}34963497static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)3498{3499return 0;3500}35013502static int radio_queryctrl(struct file *file, void *priv,3503struct v4l2_queryctrl *c)3504{3505const struct v4l2_queryctrl *ctrl;35063507if (c->id < V4L2_CID_BASE ||3508c->id >= V4L2_CID_LASTP1)3509return -EINVAL;35103511if (c->id == V4L2_CID_AUDIO_MUTE) {3512ctrl = ctrl_by_id(c->id);3513*c = *ctrl;3514} else3515*c = no_ctl;35163517return 0;3518}35193520static int radio_g_input(struct file *filp, void *priv, unsigned int *i)3521{3522*i = 0;3523return 0;3524}35253526static ssize_t radio_read(struct file *file, char __user *data,3527size_t count, loff_t *ppos)3528{3529struct bttv_fh *fh = file->private_data;3530struct bttv *btv = fh->btv;3531struct saa6588_command cmd;3532cmd.block_count = count/3;3533cmd.buffer = data;3534cmd.instance = file;3535cmd.result = -ENODEV;35363537bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);35383539return cmd.result;3540}35413542static unsigned int radio_poll(struct file *file, poll_table *wait)3543{3544struct bttv_fh *fh = file->private_data;3545struct bttv *btv = fh->btv;3546struct saa6588_command cmd;3547cmd.instance = file;3548cmd.event_list = wait;3549cmd.result = -ENODEV;3550bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);35513552return cmd.result;3553}35543555static const struct v4l2_file_operations radio_fops =3556{3557.owner = THIS_MODULE,3558.open = radio_open,3559.read = radio_read,3560.release = radio_release,3561.unlocked_ioctl = video_ioctl2,3562.poll = radio_poll,3563};35643565static const struct v4l2_ioctl_ops radio_ioctl_ops = {3566.vidioc_querycap = radio_querycap,3567.vidioc_g_tuner = radio_g_tuner,3568.vidioc_enum_input = radio_enum_input,3569.vidioc_g_audio = radio_g_audio,3570.vidioc_s_tuner = radio_s_tuner,3571.vidioc_s_audio = radio_s_audio,3572.vidioc_s_input = radio_s_input,3573.vidioc_s_std = radio_s_std,3574.vidioc_queryctrl = radio_queryctrl,3575.vidioc_g_input = radio_g_input,3576.vidioc_g_ctrl = bttv_g_ctrl,3577.vidioc_s_ctrl = bttv_s_ctrl,3578.vidioc_g_frequency = bttv_g_frequency,3579.vidioc_s_frequency = bttv_s_frequency,3580};35813582static struct video_device radio_template = {3583.fops = &radio_fops,3584.ioctl_ops = &radio_ioctl_ops,3585};35863587/* ----------------------------------------------------------------------- */3588/* some debug code */35893590static int bttv_risc_decode(u32 risc)3591{3592static char *instr[16] = {3593[ BT848_RISC_WRITE >> 28 ] = "write",3594[ BT848_RISC_SKIP >> 28 ] = "skip",3595[ BT848_RISC_WRITEC >> 28 ] = "writec",3596[ BT848_RISC_JUMP >> 28 ] = "jump",3597[ BT848_RISC_SYNC >> 28 ] = "sync",3598[ BT848_RISC_WRITE123 >> 28 ] = "write123",3599[ BT848_RISC_SKIP123 >> 28 ] = "skip123",3600[ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",3601};3602static int incr[16] = {3603[ BT848_RISC_WRITE >> 28 ] = 2,3604[ BT848_RISC_JUMP >> 28 ] = 2,3605[ BT848_RISC_SYNC >> 28 ] = 2,3606[ BT848_RISC_WRITE123 >> 28 ] = 5,3607[ BT848_RISC_SKIP123 >> 28 ] = 2,3608[ BT848_RISC_WRITE1S23 >> 28 ] = 3,3609};3610static char *bits[] = {3611"be0", "be1", "be2", "be3/resync",3612"set0", "set1", "set2", "set3",3613"clr0", "clr1", "clr2", "clr3",3614"irq", "res", "eol", "sol",3615};3616int i;36173618printk("0x%08x [ %s", risc,3619instr[risc >> 28] ? instr[risc >> 28] : "INVALID");3620for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)3621if (risc & (1 << (i + 12)))3622printk(" %s",bits[i]);3623printk(" count=%d ]\n", risc & 0xfff);3624return incr[risc >> 28] ? incr[risc >> 28] : 1;3625}36263627static void bttv_risc_disasm(struct bttv *btv,3628struct btcx_riscmem *risc)3629{3630unsigned int i,j,n;36313632printk("%s: risc disasm: %p [dma=0x%08lx]\n",3633btv->c.v4l2_dev.name, risc->cpu, (unsigned long)risc->dma);3634for (i = 0; i < (risc->size >> 2); i += n) {3635printk("%s: 0x%lx: ", btv->c.v4l2_dev.name,3636(unsigned long)(risc->dma + (i<<2)));3637n = bttv_risc_decode(le32_to_cpu(risc->cpu[i]));3638for (j = 1; j < n; j++)3639printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",3640btv->c.v4l2_dev.name, (unsigned long)(risc->dma + ((i+j)<<2)),3641risc->cpu[i+j], j);3642if (0 == risc->cpu[i])3643break;3644}3645}36463647static void bttv_print_riscaddr(struct bttv *btv)3648{3649printk(" main: %08Lx\n",3650(unsigned long long)btv->main.dma);3651printk(" vbi : o=%08Lx e=%08Lx\n",3652btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,3653btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);3654printk(" cap : o=%08Lx e=%08Lx\n",3655btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,3656btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);3657printk(" scr : o=%08Lx e=%08Lx\n",3658btv->screen ? (unsigned long long)btv->screen->top.dma : 0,3659btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);3660bttv_risc_disasm(btv, &btv->main);3661}36623663/* ----------------------------------------------------------------------- */3664/* irq handler */36653666static char *irq_name[] = {3667"FMTCHG", // format change detected (525 vs. 625)3668"VSYNC", // vertical sync (new field)3669"HSYNC", // horizontal sync3670"OFLOW", // chroma/luma AGC overflow3671"HLOCK", // horizontal lock changed3672"VPRES", // video presence changed3673"6", "7",3674"I2CDONE", // hw irc operation finished3675"GPINT", // gpio port triggered irq3676"10",3677"RISCI", // risc instruction triggered irq3678"FBUS", // pixel data fifo dropped data (high pci bus latencies)3679"FTRGT", // pixel data fifo overrun3680"FDSR", // fifo data stream resyncronisation3681"PPERR", // parity error (data transfer)3682"RIPERR", // parity error (read risc instructions)3683"PABORT", // pci abort3684"OCERR", // risc instruction error3685"SCERR", // syncronisation error3686};36873688static void bttv_print_irqbits(u32 print, u32 mark)3689{3690unsigned int i;36913692printk("bits:");3693for (i = 0; i < ARRAY_SIZE(irq_name); i++) {3694if (print & (1 << i))3695printk(" %s",irq_name[i]);3696if (mark & (1 << i))3697printk("*");3698}3699}37003701static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)3702{3703printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",3704btv->c.nr,3705(unsigned long)btv->main.dma,3706(unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_VBI+1]),3707(unsigned long)le32_to_cpu(btv->main.cpu[RISC_SLOT_O_FIELD+1]),3708(unsigned long)rc);37093710if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {3711printk("bttv%d: Oh, there (temporarely?) is no input signal. "3712"Ok, then this is harmless, don't worry ;)\n",3713btv->c.nr);3714return;3715}3716printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",3717btv->c.nr);3718printk("bttv%d: Lets try to catch the culpit red-handed ...\n",3719btv->c.nr);3720dump_stack();3721}37223723static int3724bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)3725{3726struct bttv_buffer *item;37273728memset(set,0,sizeof(*set));37293730/* capture request ? */3731if (!list_empty(&btv->capture)) {3732set->frame_irq = 1;3733item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);3734if (V4L2_FIELD_HAS_TOP(item->vb.field))3735set->top = item;3736if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))3737set->bottom = item;37383739/* capture request for other field ? */3740if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&3741(item->vb.queue.next != &btv->capture)) {3742item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);3743/* Mike Isely <[email protected]> - Only check3744* and set up the bottom field in the logic3745* below. Don't ever do the top field. This3746* of course means that if we set up the3747* bottom field in the above code that we'll3748* actually skip a field. But that's OK.3749* Having processed only a single buffer this3750* time, then the next time around the first3751* available buffer should be for a top field.3752* That will then cause us here to set up a3753* top then a bottom field in the normal way.3754* The alternative to this understanding is3755* that we set up the second available buffer3756* as a top field, but that's out of order3757* since this driver always processes the top3758* field first - the effect will be the two3759* buffers being returned in the wrong order,3760* with the second buffer also being delayed3761* by one field time (owing to the fifo nature3762* of videobuf). Worse still, we'll be stuck3763* doing fields out of order now every time3764* until something else causes a field to be3765* dropped. By effectively forcing a field to3766* drop this way then we always get back into3767* sync within a single frame time. (Out of3768* order fields can screw up deinterlacing3769* algorithms.) */3770if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {3771if (NULL == set->bottom &&3772V4L2_FIELD_BOTTOM == item->vb.field) {3773set->bottom = item;3774}3775if (NULL != set->top && NULL != set->bottom)3776set->top_irq = 2;3777}3778}3779}37803781/* screen overlay ? */3782if (NULL != btv->screen) {3783if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {3784if (NULL == set->top && NULL == set->bottom) {3785set->top = btv->screen;3786set->bottom = btv->screen;3787}3788} else {3789if (V4L2_FIELD_TOP == btv->screen->vb.field &&3790NULL == set->top) {3791set->top = btv->screen;3792}3793if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&3794NULL == set->bottom) {3795set->bottom = btv->screen;3796}3797}3798}37993800dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",3801btv->c.nr,set->top, set->bottom,3802btv->screen,set->frame_irq,set->top_irq);3803return 0;3804}38053806static void3807bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,3808struct bttv_buffer_set *curr, unsigned int state)3809{3810struct timeval ts;38113812do_gettimeofday(&ts);38133814if (wakeup->top == wakeup->bottom) {3815if (NULL != wakeup->top && curr->top != wakeup->top) {3816if (irq_debug > 1)3817printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);3818wakeup->top->vb.ts = ts;3819wakeup->top->vb.field_count = btv->field_count;3820wakeup->top->vb.state = state;3821wake_up(&wakeup->top->vb.done);3822}3823} else {3824if (NULL != wakeup->top && curr->top != wakeup->top) {3825if (irq_debug > 1)3826printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);3827wakeup->top->vb.ts = ts;3828wakeup->top->vb.field_count = btv->field_count;3829wakeup->top->vb.state = state;3830wake_up(&wakeup->top->vb.done);3831}3832if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {3833if (irq_debug > 1)3834printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);3835wakeup->bottom->vb.ts = ts;3836wakeup->bottom->vb.field_count = btv->field_count;3837wakeup->bottom->vb.state = state;3838wake_up(&wakeup->bottom->vb.done);3839}3840}3841}38423843static void3844bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,3845unsigned int state)3846{3847struct timeval ts;38483849if (NULL == wakeup)3850return;38513852do_gettimeofday(&ts);3853wakeup->vb.ts = ts;3854wakeup->vb.field_count = btv->field_count;3855wakeup->vb.state = state;3856wake_up(&wakeup->vb.done);3857}38583859static void bttv_irq_timeout(unsigned long data)3860{3861struct bttv *btv = (struct bttv *)data;3862struct bttv_buffer_set old,new;3863struct bttv_buffer *ovbi;3864struct bttv_buffer *item;3865unsigned long flags;38663867if (bttv_verbose) {3868printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",3869btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,3870btread(BT848_RISC_COUNT));3871bttv_print_irqbits(btread(BT848_INT_STAT),0);3872printk("\n");3873}38743875spin_lock_irqsave(&btv->s_lock,flags);38763877/* deactivate stuff */3878memset(&new,0,sizeof(new));3879old = btv->curr;3880ovbi = btv->cvbi;3881btv->curr = new;3882btv->cvbi = NULL;3883btv->loop_irq = 0;3884bttv_buffer_activate_video(btv, &new);3885bttv_buffer_activate_vbi(btv, NULL);3886bttv_set_dma(btv, 0);38873888/* wake up */3889bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);3890bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);38913892/* cancel all outstanding capture / vbi requests */3893while (!list_empty(&btv->capture)) {3894item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);3895list_del(&item->vb.queue);3896item->vb.state = VIDEOBUF_ERROR;3897wake_up(&item->vb.done);3898}3899while (!list_empty(&btv->vcapture)) {3900item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);3901list_del(&item->vb.queue);3902item->vb.state = VIDEOBUF_ERROR;3903wake_up(&item->vb.done);3904}39053906btv->errors++;3907spin_unlock_irqrestore(&btv->s_lock,flags);3908}39093910static void3911bttv_irq_wakeup_top(struct bttv *btv)3912{3913struct bttv_buffer *wakeup = btv->curr.top;39143915if (NULL == wakeup)3916return;39173918spin_lock(&btv->s_lock);3919btv->curr.top_irq = 0;3920btv->curr.top = NULL;3921bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);39223923do_gettimeofday(&wakeup->vb.ts);3924wakeup->vb.field_count = btv->field_count;3925wakeup->vb.state = VIDEOBUF_DONE;3926wake_up(&wakeup->vb.done);3927spin_unlock(&btv->s_lock);3928}39293930static inline int is_active(struct btcx_riscmem *risc, u32 rc)3931{3932if (rc < risc->dma)3933return 0;3934if (rc > risc->dma + risc->size)3935return 0;3936return 1;3937}39383939static void3940bttv_irq_switch_video(struct bttv *btv)3941{3942struct bttv_buffer_set new;3943struct bttv_buffer_set old;3944dma_addr_t rc;39453946spin_lock(&btv->s_lock);39473948/* new buffer set */3949bttv_irq_next_video(btv, &new);3950rc = btread(BT848_RISC_COUNT);3951if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||3952(btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {3953btv->framedrop++;3954if (debug_latency)3955bttv_irq_debug_low_latency(btv, rc);3956spin_unlock(&btv->s_lock);3957return;3958}39593960/* switch over */3961old = btv->curr;3962btv->curr = new;3963btv->loop_irq &= ~1;3964bttv_buffer_activate_video(btv, &new);3965bttv_set_dma(btv, 0);39663967/* switch input */3968if (UNSET != btv->new_input) {3969video_mux(btv,btv->new_input);3970btv->new_input = UNSET;3971}39723973/* wake up finished buffers */3974bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);3975spin_unlock(&btv->s_lock);3976}39773978static void3979bttv_irq_switch_vbi(struct bttv *btv)3980{3981struct bttv_buffer *new = NULL;3982struct bttv_buffer *old;3983u32 rc;39843985spin_lock(&btv->s_lock);39863987if (!list_empty(&btv->vcapture))3988new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);3989old = btv->cvbi;39903991rc = btread(BT848_RISC_COUNT);3992if (NULL != old && (is_active(&old->top, rc) ||3993is_active(&old->bottom, rc))) {3994btv->framedrop++;3995if (debug_latency)3996bttv_irq_debug_low_latency(btv, rc);3997spin_unlock(&btv->s_lock);3998return;3999}40004001/* switch */4002btv->cvbi = new;4003btv->loop_irq &= ~4;4004bttv_buffer_activate_vbi(btv, new);4005bttv_set_dma(btv, 0);40064007bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);4008spin_unlock(&btv->s_lock);4009}40104011static irqreturn_t bttv_irq(int irq, void *dev_id)4012{4013u32 stat,astat;4014u32 dstat;4015int count;4016struct bttv *btv;4017int handled = 0;40184019btv=(struct bttv *)dev_id;40204021count=0;4022while (1) {4023/* get/clear interrupt status bits */4024stat=btread(BT848_INT_STAT);4025astat=stat&btread(BT848_INT_MASK);4026if (!astat)4027break;4028handled = 1;4029btwrite(stat,BT848_INT_STAT);40304031/* get device status bits */4032dstat=btread(BT848_DSTATUS);40334034if (irq_debug) {4035printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "4036"riscs=%x, riscc=%08x, ",4037btv->c.nr, count, btv->field_count,4038stat>>28, btread(BT848_RISC_COUNT));4039bttv_print_irqbits(stat,astat);4040if (stat & BT848_INT_HLOCK)4041printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)4042? "yes" : "no");4043if (stat & BT848_INT_VPRES)4044printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)4045? "yes" : "no");4046if (stat & BT848_INT_FMTCHG)4047printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)4048? "625" : "525");4049printk("\n");4050}40514052if (astat&BT848_INT_VSYNC)4053btv->field_count++;40544055if ((astat & BT848_INT_GPINT) && btv->remote) {4056bttv_input_irq(btv);4057}40584059if (astat & BT848_INT_I2CDONE) {4060btv->i2c_done = stat;4061wake_up(&btv->i2c_queue);4062}40634064if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))4065bttv_irq_switch_vbi(btv);40664067if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))4068bttv_irq_wakeup_top(btv);40694070if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))4071bttv_irq_switch_video(btv);40724073if ((astat & BT848_INT_HLOCK) && btv->opt_automute)4074audio_mute(btv, btv->mute); /* trigger automute */40754076if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {4077printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,4078(astat & BT848_INT_SCERR) ? "SCERR" : "",4079(astat & BT848_INT_OCERR) ? "OCERR" : "",4080btread(BT848_RISC_COUNT));4081bttv_print_irqbits(stat,astat);4082printk("\n");4083if (bttv_debug)4084bttv_print_riscaddr(btv);4085}4086if (fdsr && astat & BT848_INT_FDSR) {4087printk(KERN_INFO "bttv%d: FDSR @ %08x\n",4088btv->c.nr,btread(BT848_RISC_COUNT));4089if (bttv_debug)4090bttv_print_riscaddr(btv);4091}40924093count++;4094if (count > 4) {40954096if (count > 8 || !(astat & BT848_INT_GPINT)) {4097btwrite(0, BT848_INT_MASK);40984099printk(KERN_ERR4100"bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);4101} else {4102printk(KERN_ERR4103"bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);41044105btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),4106BT848_INT_MASK);4107};41084109bttv_print_irqbits(stat,astat);41104111printk("]\n");4112}4113}4114btv->irq_total++;4115if (handled)4116btv->irq_me++;4117return IRQ_RETVAL(handled);4118}411941204121/* ----------------------------------------------------------------------- */4122/* initialitation */41234124static struct video_device *vdev_init(struct bttv *btv,4125const struct video_device *template,4126const char *type_name)4127{4128struct video_device *vfd;41294130vfd = video_device_alloc();4131if (NULL == vfd)4132return NULL;4133*vfd = *template;4134vfd->v4l2_dev = &btv->c.v4l2_dev;4135vfd->release = video_device_release;4136vfd->debug = bttv_debug;4137video_set_drvdata(vfd, btv);4138snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",4139btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",4140type_name, bttv_tvcards[btv->c.type].name);4141return vfd;4142}41434144static void bttv_unregister_video(struct bttv *btv)4145{4146if (btv->video_dev) {4147if (video_is_registered(btv->video_dev))4148video_unregister_device(btv->video_dev);4149else4150video_device_release(btv->video_dev);4151btv->video_dev = NULL;4152}4153if (btv->vbi_dev) {4154if (video_is_registered(btv->vbi_dev))4155video_unregister_device(btv->vbi_dev);4156else4157video_device_release(btv->vbi_dev);4158btv->vbi_dev = NULL;4159}4160if (btv->radio_dev) {4161if (video_is_registered(btv->radio_dev))4162video_unregister_device(btv->radio_dev);4163else4164video_device_release(btv->radio_dev);4165btv->radio_dev = NULL;4166}4167}41684169/* register video4linux devices */4170static int __devinit bttv_register_video(struct bttv *btv)4171{4172if (no_overlay > 0)4173printk("bttv: Overlay support disabled.\n");41744175/* video */4176btv->video_dev = vdev_init(btv, &bttv_video_template, "video");41774178if (NULL == btv->video_dev)4179goto err;4180if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER,4181video_nr[btv->c.nr]) < 0)4182goto err;4183printk(KERN_INFO "bttv%d: registered device %s\n",4184btv->c.nr, video_device_node_name(btv->video_dev));4185if (device_create_file(&btv->video_dev->dev,4186&dev_attr_card)<0) {4187printk(KERN_ERR "bttv%d: device_create_file 'card' "4188"failed\n", btv->c.nr);4189goto err;4190}41914192/* vbi */4193btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi");41944195if (NULL == btv->vbi_dev)4196goto err;4197if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI,4198vbi_nr[btv->c.nr]) < 0)4199goto err;4200printk(KERN_INFO "bttv%d: registered device %s\n",4201btv->c.nr, video_device_node_name(btv->vbi_dev));42024203if (!btv->has_radio)4204return 0;4205/* radio */4206btv->radio_dev = vdev_init(btv, &radio_template, "radio");4207if (NULL == btv->radio_dev)4208goto err;4209if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,4210radio_nr[btv->c.nr]) < 0)4211goto err;4212printk(KERN_INFO "bttv%d: registered device %s\n",4213btv->c.nr, video_device_node_name(btv->radio_dev));42144215/* all done */4216return 0;42174218err:4219bttv_unregister_video(btv);4220return -1;4221}422242234224/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */4225/* response on cards with no firmware is not enabled by OF */4226static void pci_set_command(struct pci_dev *dev)4227{4228#if defined(__powerpc__)4229unsigned int cmd;42304231pci_read_config_dword(dev, PCI_COMMAND, &cmd);4232cmd = (cmd | PCI_COMMAND_MEMORY );4233pci_write_config_dword(dev, PCI_COMMAND, cmd);4234#endif4235}42364237static int __devinit bttv_probe(struct pci_dev *dev,4238const struct pci_device_id *pci_id)4239{4240int result;4241unsigned char lat;4242struct bttv *btv;42434244if (bttv_num == BTTV_MAX)4245return -ENOMEM;4246printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);4247bttvs[bttv_num] = btv = kzalloc(sizeof(*btv), GFP_KERNEL);4248if (btv == NULL) {4249printk(KERN_ERR "bttv: out of memory.\n");4250return -ENOMEM;4251}4252btv->c.nr = bttv_num;4253snprintf(btv->c.v4l2_dev.name, sizeof(btv->c.v4l2_dev.name),4254"bttv%d", btv->c.nr);42554256/* initialize structs / fill in defaults */4257mutex_init(&btv->lock);4258spin_lock_init(&btv->s_lock);4259spin_lock_init(&btv->gpio_lock);4260init_waitqueue_head(&btv->i2c_queue);4261INIT_LIST_HEAD(&btv->c.subs);4262INIT_LIST_HEAD(&btv->capture);4263INIT_LIST_HEAD(&btv->vcapture);4264v4l2_prio_init(&btv->prio);42654266init_timer(&btv->timeout);4267btv->timeout.function = bttv_irq_timeout;4268btv->timeout.data = (unsigned long)btv;42694270btv->i2c_rc = -1;4271btv->tuner_type = UNSET;4272btv->new_input = UNSET;4273btv->has_radio=radio[btv->c.nr];42744275/* pci stuff (init, get irq/mmio, ... */4276btv->c.pci = dev;4277btv->id = dev->device;4278if (pci_enable_device(dev)) {4279printk(KERN_WARNING "bttv%d: Can't enable device.\n",4280btv->c.nr);4281return -EIO;4282}4283if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {4284printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",4285btv->c.nr);4286return -EIO;4287}4288if (!request_mem_region(pci_resource_start(dev,0),4289pci_resource_len(dev,0),4290btv->c.v4l2_dev.name)) {4291printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",4292btv->c.nr,4293(unsigned long long)pci_resource_start(dev,0));4294return -EBUSY;4295}4296pci_set_master(dev);4297pci_set_command(dev);42984299result = v4l2_device_register(&dev->dev, &btv->c.v4l2_dev);4300if (result < 0) {4301printk(KERN_WARNING "bttv%d: v4l2_device_register() failed\n", btv->c.nr);4302goto fail0;4303}43044305btv->revision = dev->revision;4306pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);4307printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",4308bttv_num,btv->id, btv->revision, pci_name(dev));4309printk("irq: %d, latency: %d, mmio: 0x%llx\n",4310btv->c.pci->irq, lat,4311(unsigned long long)pci_resource_start(dev,0));4312schedule();43134314btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);4315if (NULL == btv->bt848_mmio) {4316printk("bttv%d: ioremap() failed\n", btv->c.nr);4317result = -EIO;4318goto fail1;4319}43204321/* identify card */4322bttv_idcard(btv);43234324/* disable irqs, register irq handler */4325btwrite(0, BT848_INT_MASK);4326result = request_irq(btv->c.pci->irq, bttv_irq,4327IRQF_SHARED | IRQF_DISABLED, btv->c.v4l2_dev.name, (void *)btv);4328if (result < 0) {4329printk(KERN_ERR "bttv%d: can't get IRQ %d\n",4330bttv_num,btv->c.pci->irq);4331goto fail1;4332}43334334if (0 != bttv_handle_chipset(btv)) {4335result = -EIO;4336goto fail2;4337}43384339/* init options from insmod args */4340btv->opt_combfilter = combfilter;4341btv->opt_lumafilter = lumafilter;4342btv->opt_automute = automute;4343btv->opt_chroma_agc = chroma_agc;4344btv->opt_adc_crush = adc_crush;4345btv->opt_vcr_hack = vcr_hack;4346btv->opt_whitecrush_upper = whitecrush_upper;4347btv->opt_whitecrush_lower = whitecrush_lower;4348btv->opt_uv_ratio = uv_ratio;4349btv->opt_full_luma_range = full_luma_range;4350btv->opt_coring = coring;43514352/* fill struct bttv with some useful defaults */4353btv->init.btv = btv;4354btv->init.ov.w.width = 320;4355btv->init.ov.w.height = 240;4356btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);4357btv->init.width = 320;4358btv->init.height = 240;4359btv->input = 0;43604361/* initialize hardware */4362if (bttv_gpio)4363bttv_gpio_tracking(btv,"pre-init");43644365bttv_risc_init_main(btv);4366init_bt848(btv);43674368/* gpio */4369btwrite(0x00, BT848_GPIO_REG_INP);4370btwrite(0x00, BT848_GPIO_OUT_EN);4371if (bttv_verbose)4372bttv_gpio_tracking(btv,"init");43734374/* needs to be done before i2c is registered */4375bttv_init_card1(btv);43764377/* register i2c + gpio */4378init_bttv_i2c(btv);43794380/* some card-specific stuff (needs working i2c) */4381bttv_init_card2(btv);4382bttv_init_tuner(btv);4383init_irqreg(btv);43844385/* register video4linux + input */4386if (!bttv_tvcards[btv->c.type].no_video) {4387bttv_register_video(btv);4388bt848_bright(btv,32768);4389bt848_contrast(btv,32768);4390bt848_hue(btv,32768);4391bt848_sat(btv,32768);4392audio_mute(btv, 1);4393set_input(btv, 0, btv->tvnorm);4394bttv_crop_reset(&btv->crop[0], btv->tvnorm);4395btv->crop[1] = btv->crop[0]; /* current = default */4396disclaim_vbi_lines(btv);4397disclaim_video_lines(btv);4398}43994400/* add subdevices and autoload dvb-bt8xx if needed */4401if (bttv_tvcards[btv->c.type].has_dvb) {4402bttv_sub_add_device(&btv->c, "dvb");4403request_modules(btv);4404}44054406if (!disable_ir) {4407init_bttv_i2c_ir(btv);4408bttv_input_init(btv);4409}44104411/* everything is fine */4412bttv_num++;4413return 0;44144415fail2:4416free_irq(btv->c.pci->irq,btv);44174418fail1:4419v4l2_device_unregister(&btv->c.v4l2_dev);44204421fail0:4422if (btv->bt848_mmio)4423iounmap(btv->bt848_mmio);4424release_mem_region(pci_resource_start(btv->c.pci,0),4425pci_resource_len(btv->c.pci,0));4426return result;4427}44284429static void __devexit bttv_remove(struct pci_dev *pci_dev)4430{4431struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);4432struct bttv *btv = to_bttv(v4l2_dev);44334434if (bttv_verbose)4435printk("bttv%d: unloading\n",btv->c.nr);44364437if (bttv_tvcards[btv->c.type].has_dvb)4438flush_request_modules(btv);44394440/* shutdown everything (DMA+IRQs) */4441btand(~15, BT848_GPIO_DMA_CTL);4442btwrite(0, BT848_INT_MASK);4443btwrite(~0x0, BT848_INT_STAT);4444btwrite(0x0, BT848_GPIO_OUT_EN);4445if (bttv_gpio)4446bttv_gpio_tracking(btv,"cleanup");44474448/* tell gpio modules we are leaving ... */4449btv->shutdown=1;4450bttv_input_fini(btv);4451bttv_sub_del_devices(&btv->c);44524453/* unregister i2c_bus + input */4454fini_bttv_i2c(btv);44554456/* unregister video4linux */4457bttv_unregister_video(btv);44584459/* free allocated memory */4460btcx_riscmem_free(btv->c.pci,&btv->main);44614462/* free ressources */4463free_irq(btv->c.pci->irq,btv);4464iounmap(btv->bt848_mmio);4465release_mem_region(pci_resource_start(btv->c.pci,0),4466pci_resource_len(btv->c.pci,0));44674468v4l2_device_unregister(&btv->c.v4l2_dev);4469bttvs[btv->c.nr] = NULL;4470kfree(btv);44714472return;4473}44744475#ifdef CONFIG_PM4476static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)4477{4478struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);4479struct bttv *btv = to_bttv(v4l2_dev);4480struct bttv_buffer_set idle;4481unsigned long flags;44824483dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);44844485/* stop dma + irqs */4486spin_lock_irqsave(&btv->s_lock,flags);4487memset(&idle, 0, sizeof(idle));4488btv->state.video = btv->curr;4489btv->state.vbi = btv->cvbi;4490btv->state.loop_irq = btv->loop_irq;4491btv->curr = idle;4492btv->loop_irq = 0;4493bttv_buffer_activate_video(btv, &idle);4494bttv_buffer_activate_vbi(btv, NULL);4495bttv_set_dma(btv, 0);4496btwrite(0, BT848_INT_MASK);4497spin_unlock_irqrestore(&btv->s_lock,flags);44984499/* save bt878 state */4500btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);4501btv->state.gpio_data = gpio_read();45024503/* save pci state */4504pci_save_state(pci_dev);4505if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {4506pci_disable_device(pci_dev);4507btv->state.disabled = 1;4508}4509return 0;4510}45114512static int bttv_resume(struct pci_dev *pci_dev)4513{4514struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);4515struct bttv *btv = to_bttv(v4l2_dev);4516unsigned long flags;4517int err;45184519dprintk("bttv%d: resume\n", btv->c.nr);45204521/* restore pci state */4522if (btv->state.disabled) {4523err=pci_enable_device(pci_dev);4524if (err) {4525printk(KERN_WARNING "bttv%d: Can't enable device.\n",4526btv->c.nr);4527return err;4528}4529btv->state.disabled = 0;4530}4531err=pci_set_power_state(pci_dev, PCI_D0);4532if (err) {4533pci_disable_device(pci_dev);4534printk(KERN_WARNING "bttv%d: Can't enable device.\n",4535btv->c.nr);4536btv->state.disabled = 1;4537return err;4538}45394540pci_restore_state(pci_dev);45414542/* restore bt878 state */4543bttv_reinit_bt848(btv);4544gpio_inout(0xffffff, btv->state.gpio_enable);4545gpio_write(btv->state.gpio_data);45464547/* restart dma */4548spin_lock_irqsave(&btv->s_lock,flags);4549btv->curr = btv->state.video;4550btv->cvbi = btv->state.vbi;4551btv->loop_irq = btv->state.loop_irq;4552bttv_buffer_activate_video(btv, &btv->curr);4553bttv_buffer_activate_vbi(btv, btv->cvbi);4554bttv_set_dma(btv, 0);4555spin_unlock_irqrestore(&btv->s_lock,flags);4556return 0;4557}4558#endif45594560static struct pci_device_id bttv_pci_tbl[] = {4561{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0},4562{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0},4563{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0},4564{PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0},4565{0,}4566};45674568MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);45694570static struct pci_driver bttv_pci_driver = {4571.name = "bttv",4572.id_table = bttv_pci_tbl,4573.probe = bttv_probe,4574.remove = __devexit_p(bttv_remove),4575#ifdef CONFIG_PM4576.suspend = bttv_suspend,4577.resume = bttv_resume,4578#endif4579};45804581static int __init bttv_init_module(void)4582{4583int ret;45844585bttv_num = 0;45864587printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",4588(BTTV_VERSION_CODE >> 16) & 0xff,4589(BTTV_VERSION_CODE >> 8) & 0xff,4590BTTV_VERSION_CODE & 0xff);4591#ifdef SNAPSHOT4592printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",4593SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);4594#endif4595if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)4596gbuffers = 2;4597if (gbufsize > BTTV_MAX_FBUF)4598gbufsize = BTTV_MAX_FBUF;4599gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;4600if (bttv_verbose)4601printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",4602gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);46034604bttv_check_chipset();46054606ret = bus_register(&bttv_sub_bus_type);4607if (ret < 0) {4608printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);4609return ret;4610}4611ret = pci_register_driver(&bttv_pci_driver);4612if (ret < 0)4613bus_unregister(&bttv_sub_bus_type);46144615return ret;4616}46174618static void __exit bttv_cleanup_module(void)4619{4620pci_unregister_driver(&bttv_pci_driver);4621bus_unregister(&bttv_sub_bus_type);4622}46234624module_init(bttv_init_module);4625module_exit(bttv_cleanup_module);46264627/*4628* Local variables:4629* c-basic-offset: 84630* End:4631*/463246334634