bttv-driver.c 116 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5
/*

    bttv - Bt848 frame grabber driver

    Copyright (C) 1996,97,98 Ralph  Metzler <rjkm@thp.uni-koeln.de>
6
			   & Marcus Metzler <mocm@thp.uni-koeln.de>
Linus Torvalds's avatar
Linus Torvalds committed
7 8 9 10 11
    (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>

    some v4l2 code lines are taken from Justin's bttv2 driver which is
    (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>

12 13 14
    V4L1 removal from:
    (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>

15
    Fixes to be fully V4L2 compliant by
16
    (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org>
17

18 19 20 21
    Cropping and overscan support
    Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
    Sponsored by OPQ Systems AB

Linus Torvalds's avatar
Linus Torvalds committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

37 38
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Linus Torvalds's avatar
Linus Torvalds committed
39 40 41
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
42
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
43 44 45 46 47 48
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
49
#include "bttvp.h"
50
#include <media/v4l2-common.h>
51
#include <media/v4l2-ioctl.h>
52
#include <media/v4l2-event.h>
53
#include <media/i2c/tvaudio.h>
54
#include <media/drv-intf/msp3400.h>
55

56
#include <linux/dma-mapping.h>
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59 60

#include <asm/io.h>
#include <asm/byteorder.h>

61
#include <media/i2c/saa6588.h>
62

63
#define BTTV_VERSION "0.9.19"
64

Linus Torvalds's avatar
Linus Torvalds committed
65
unsigned int bttv_num;			/* number of Bt848s in use */
66
struct bttv *bttvs[BTTV_MAX];
Linus Torvalds's avatar
Linus Torvalds committed
67

68
unsigned int bttv_debug;
Linus Torvalds's avatar
Linus Torvalds committed
69
unsigned int bttv_verbose = 1;
70
unsigned int bttv_gpio;
Linus Torvalds's avatar
Linus Torvalds committed
71 72 73 74 75

/* config variables */
#ifdef __BIG_ENDIAN
static unsigned int bigendian=1;
#else
76
static unsigned int bigendian;
Linus Torvalds's avatar
Linus Torvalds committed
77 78
#endif
static unsigned int radio[BTTV_MAX];
79
static unsigned int irq_debug;
Linus Torvalds's avatar
Linus Torvalds committed
80 81
static unsigned int gbuffers = 8;
static unsigned int gbufsize = 0x208000;
82
static unsigned int reset_crop = 1;
Linus Torvalds's avatar
Linus Torvalds committed
83

84 85 86
static int video_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
static int radio_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
static int vbi_nr[BTTV_MAX] = { [0 ... (BTTV_MAX-1)] = -1 };
87
static int debug_latency;
88
static int disable_ir;
Linus Torvalds's avatar
Linus Torvalds committed
89

90
static unsigned int fdsr;
Linus Torvalds's avatar
Linus Torvalds committed
91 92

/* options */
93 94
static unsigned int combfilter;
static unsigned int lumafilter;
Linus Torvalds's avatar
Linus Torvalds committed
95
static unsigned int automute    = 1;
96
static unsigned int chroma_agc;
97
static unsigned int agc_crush   = 1;
Linus Torvalds's avatar
Linus Torvalds committed
98 99
static unsigned int whitecrush_upper = 0xCF;
static unsigned int whitecrush_lower = 0x7F;
100 101
static unsigned int vcr_hack;
static unsigned int irq_iswitch;
102
static unsigned int uv_ratio    = 50;
103 104
static unsigned int full_luma_range;
static unsigned int coring;
Linus Torvalds's avatar
Linus Torvalds committed
105 106 107 108 109 110 111 112 113 114

/* API features (turn on/off stuff for testing) */
static unsigned int v4l2        = 1;

/* insmod args */
module_param(bttv_verbose,      int, 0644);
module_param(bttv_gpio,         int, 0644);
module_param(bttv_debug,        int, 0644);
module_param(irq_debug,         int, 0644);
module_param(debug_latency,     int, 0644);
115
module_param(disable_ir,        int, 0444);
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118 119

module_param(fdsr,              int, 0444);
module_param(gbuffers,          int, 0444);
module_param(gbufsize,          int, 0444);
120
module_param(reset_crop,        int, 0444);
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124 125 126 127 128

module_param(v4l2,              int, 0644);
module_param(bigendian,         int, 0644);
module_param(irq_iswitch,       int, 0644);
module_param(combfilter,        int, 0444);
module_param(lumafilter,        int, 0444);
module_param(automute,          int, 0444);
module_param(chroma_agc,        int, 0444);
129
module_param(agc_crush,         int, 0444);
Linus Torvalds's avatar
Linus Torvalds committed
130 131 132
module_param(whitecrush_upper,  int, 0444);
module_param(whitecrush_lower,  int, 0444);
module_param(vcr_hack,          int, 0444);
133 134 135
module_param(uv_ratio,          int, 0444);
module_param(full_luma_range,   int, 0444);
module_param(coring,            int, 0444);
Linus Torvalds's avatar
Linus Torvalds committed
136

137 138 139 140
module_param_array(radio,       int, NULL, 0444);
module_param_array(video_nr,    int, NULL, 0444);
module_param_array(radio_nr,    int, NULL, 0444);
module_param_array(vbi_nr,      int, NULL, 0444);
Linus Torvalds's avatar
Linus Torvalds committed
141

142 143 144 145 146 147
MODULE_PARM_DESC(radio, "The TV card supports radio, default is 0 (no)");
MODULE_PARM_DESC(bigendian, "byte order of the framebuffer, default is native endian");
MODULE_PARM_DESC(bttv_verbose, "verbose startup messages, default is 1 (yes)");
MODULE_PARM_DESC(bttv_gpio, "log gpio changes, default is 0 (no)");
MODULE_PARM_DESC(bttv_debug, "debug messages, default is 0 (no)");
MODULE_PARM_DESC(irq_debug, "irq handler debug messages, default is 0 (no)");
148
MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
149 150
MODULE_PARM_DESC(gbuffers, "number of capture buffers. range 2-32, default 8");
MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 0x208000");
151
MODULE_PARM_DESC(reset_crop, "reset cropping parameters at open(), default is 1 (yes) for compatibility with older applications");
152 153 154 155 156 157 158 159 160 161
MODULE_PARM_DESC(automute, "mute audio on bad/missing video signal, default is 1 (yes)");
MODULE_PARM_DESC(chroma_agc, "enables the AGC of chroma signal, default is 0 (no)");
MODULE_PARM_DESC(agc_crush, "enables the luminance AGC crush, default is 1 (yes)");
MODULE_PARM_DESC(whitecrush_upper, "sets the white crush upper value, default is 207");
MODULE_PARM_DESC(whitecrush_lower, "sets the white crush lower value, default is 127");
MODULE_PARM_DESC(vcr_hack, "enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
MODULE_PARM_DESC(irq_iswitch, "switch inputs in irq handler");
MODULE_PARM_DESC(uv_ratio, "ratio between u and v gains, default is 50");
MODULE_PARM_DESC(full_luma_range, "use the full luma range, default is 0 (no)");
MODULE_PARM_DESC(coring, "set the luma coring level, default is 0 (no)");
162 163 164
MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167 168

MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
MODULE_LICENSE("GPL");
169
MODULE_VERSION(BTTV_VERSION);
Linus Torvalds's avatar
Linus Torvalds committed
170

171 172 173 174 175 176 177 178 179 180 181
#define V4L2_CID_PRIVATE_COMBFILTER		(V4L2_CID_USER_BTTV_BASE + 0)
#define V4L2_CID_PRIVATE_AUTOMUTE		(V4L2_CID_USER_BTTV_BASE + 1)
#define V4L2_CID_PRIVATE_LUMAFILTER		(V4L2_CID_USER_BTTV_BASE + 2)
#define V4L2_CID_PRIVATE_AGC_CRUSH		(V4L2_CID_USER_BTTV_BASE + 3)
#define V4L2_CID_PRIVATE_VCR_HACK		(V4L2_CID_USER_BTTV_BASE + 4)
#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER	(V4L2_CID_USER_BTTV_BASE + 5)
#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER	(V4L2_CID_USER_BTTV_BASE + 6)
#define V4L2_CID_PRIVATE_UV_RATIO		(V4L2_CID_USER_BTTV_BASE + 7)
#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE	(V4L2_CID_USER_BTTV_BASE + 8)
#define V4L2_CID_PRIVATE_CORING			(V4L2_CID_USER_BTTV_BASE + 9)

Linus Torvalds's avatar
Linus Torvalds committed
182 183 184
/* ----------------------------------------------------------------------- */
/* sysfs                                                                   */

185 186
static ssize_t show_card(struct device *cd,
			 struct device_attribute *attr, char *buf)
Linus Torvalds's avatar
Linus Torvalds committed
187
{
188
	struct video_device *vfd = to_video_device(cd);
189
	struct bttv *btv = video_get_drvdata(vfd);
Linus Torvalds's avatar
Linus Torvalds committed
190 191
	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
}
192
static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
193

194 195 196 197 198 199 200 201 202 203 204 205 206
/* ----------------------------------------------------------------------- */
/* dvb auto-load setup                                                     */
#if defined(CONFIG_MODULES) && defined(MODULE)
static void request_module_async(struct work_struct *work)
{
	request_module("dvb-bt8xx");
}

static void request_modules(struct bttv *dev)
{
	INIT_WORK(&dev->request_module_wk, request_module_async);
	schedule_work(&dev->request_module_wk);
}
207 208 209

static void flush_request_modules(struct bttv *dev)
{
210
	flush_work(&dev->request_module_wk);
211
}
212 213
#else
#define request_modules(dev)
214
#define flush_request_modules(dev) do {} while(0)
215 216 217
#endif /* CONFIG_MODULES */


Linus Torvalds's avatar
Linus Torvalds committed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
/* ----------------------------------------------------------------------- */
/* static data                                                             */

/* special timing tables from conexant... */
static u8 SRAM_Table[][60] =
{
	/* PAL digital input over GPIO[7:0] */
	{
		45, // 45 bytes following
		0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
		0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
		0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
		0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
		0x37,0x00,0xAF,0x21,0x00
	},
	/* NTSC digital input over GPIO[7:0] */
	{
		51, // 51 bytes following
		0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
		0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
		0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
		0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
		0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
		0x00,
	},
	// TGB_NTSC392 // quartzsight
	// This table has been modified to be used for Fusion Rev D
	{
		0x2A, // size of table = 42
		0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
		0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
		0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
		0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
		0x20, 0x00
	}
};

255 256 257 258 259 260 261 262 263
/* minhdelayx1	first video pixel we can capture on a line and
   hdelayx1	start of active video, both relative to rising edge of
		/HRESET pulse (0H) in 1 / fCLKx1.
   swidth	width of active video and
   totalwidth	total line width, both in 1 / fCLKx1.
   sqwidth	total line width in square pixels.
   vdelay	start of active video in 2 * field lines relative to
		trailing edge of /VRESET pulse (VDELAY register).
   sheight	height of active video in 2 * field lines.
264
   extraheight	Added to sheight for cropcap.bounds.height only
265 266 267
   videostart0	ITU-R frame line number of the line corresponding
		to vdelay in the first field. */
#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth,	 \
268
		vdelay, sheight, extraheight, videostart0)		 \
269 270 271 272 273 274
	.cropcap.bounds.left = minhdelayx1,				 \
	/* * 2 because vertically we count field lines times two, */	 \
	/* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */		 \
	.cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
	/* 4 is a safety margin at the end of the line. */		 \
	.cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4,	 \
275 276
	.cropcap.bounds.height = (sheight) + (extraheight) + (vdelay) -	 \
				 MIN_VDELAY,				 \
277 278 279 280 281 282 283
	.cropcap.defrect.left = hdelayx1,				 \
	.cropcap.defrect.top = (videostart0) * 2,			 \
	.cropcap.defrect.width = swidth,				 \
	.cropcap.defrect.height = sheight,				 \
	.cropcap.pixelaspect.numerator = totalwidth,			 \
	.cropcap.pixelaspect.denominator = sqwidth,

Linus Torvalds's avatar
Linus Torvalds committed
284 285
const struct bttv_tvnorm bttv_tvnorms[] = {
	/* PAL-BDGHI */
286 287
	/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds's avatar
Linus Torvalds committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301
	{
		.v4l2_id        = V4L2_STD_PAL,
		.name           = "PAL",
		.Fsc            = 35468950,
		.swidth         = 924,
		.sheight        = 576,
		.totalwidth     = 1135,
		.adelay         = 0x7f,
		.bdelay         = 0x72,
		.iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
		.scaledtwidth   = 1135,
		.hdelayx1       = 186,
		.hactivex1      = 924,
		.vdelay         = 0x20,
302
		.vbipack        = 255, /* min (2048 / 4, 0x1ff) & 0xff */
Linus Torvalds's avatar
Linus Torvalds committed
303
		.sram           = 0,
304
		/* ITU-R frame line number of the first VBI line
305 306 307 308 309 310 311 312 313 314 315 316
		   we can capture, of the first and second field.
		   The last line is determined by cropcap.bounds. */
		.vbistart       = { 7, 320 },
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 186,
			/* Should be (768 * 1135 + 944 / 2) / 944.
			   cropcap.defrect is used for image width
			   checks, so we keep the old value 924. */
			/* swidth */ 924,
			/* totalwidth */ 1135,
			/* sqwidth */ 944,
			/* vdelay */ 0x20,
317 318 319 320
			/* sheight */ 576,
			/* bt878 (and bt848?) can capture another
			   line below active video. */
			/* extraheight */ 2,
321
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
322
	},{
323
		.v4l2_id        = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds's avatar
Linus Torvalds committed
324 325 326 327 328 329 330 331 332 333 334 335
		.name           = "NTSC",
		.Fsc            = 28636363,
		.swidth         = 768,
		.sheight        = 480,
		.totalwidth     = 910,
		.adelay         = 0x68,
		.bdelay         = 0x5d,
		.iform          = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
		.scaledtwidth   = 910,
		.hdelayx1       = 128,
		.hactivex1      = 910,
		.vdelay         = 0x1a,
336
		.vbipack        = 144, /* min (1600 / 4, 0x1ff) & 0xff */
Linus Torvalds's avatar
Linus Torvalds committed
337
		.sram           = 1,
338
		.vbistart	= { 10, 273 },
339 340 341 342 343 344 345 346
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 128,
			/* Should be (640 * 910 + 780 / 2) / 780? */
			/* swidth */ 768,
			/* totalwidth */ 910,
			/* sqwidth */ 780,
			/* vdelay */ 0x1a,
			/* sheight */ 480,
347
			/* extraheight */ 0,
348
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
	},{
		.v4l2_id        = V4L2_STD_SECAM,
		.name           = "SECAM",
		.Fsc            = 35468950,
		.swidth         = 924,
		.sheight        = 576,
		.totalwidth     = 1135,
		.adelay         = 0x7f,
		.bdelay         = 0xb0,
		.iform          = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
		.scaledtwidth   = 1135,
		.hdelayx1       = 186,
		.hactivex1      = 922,
		.vdelay         = 0x20,
		.vbipack        = 255,
		.sram           = 0, /* like PAL, correct? */
365
		.vbistart	= { 7, 320 },
366 367 368 369 370 371 372
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 186,
			/* swidth */ 924,
			/* totalwidth */ 1135,
			/* sqwidth */ 944,
			/* vdelay */ 0x20,
			/* sheight */ 576,
373
			/* extraheight */ 0,
374
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
	},{
		.v4l2_id        = V4L2_STD_PAL_Nc,
		.name           = "PAL-Nc",
		.Fsc            = 28636363,
		.swidth         = 640,
		.sheight        = 576,
		.totalwidth     = 910,
		.adelay         = 0x68,
		.bdelay         = 0x5d,
		.iform          = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
		.scaledtwidth   = 780,
		.hdelayx1       = 130,
		.hactivex1      = 734,
		.vdelay         = 0x1a,
		.vbipack        = 144,
		.sram           = -1,
391
		.vbistart	= { 7, 320 },
392 393 394 395 396 397 398
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 130,
			/* swidth */ (640 * 910 + 780 / 2) / 780,
			/* totalwidth */ 910,
			/* sqwidth */ 780,
			/* vdelay */ 0x1a,
			/* sheight */ 576,
399
			/* extraheight */ 0,
400
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
	},{
		.v4l2_id        = V4L2_STD_PAL_M,
		.name           = "PAL-M",
		.Fsc            = 28636363,
		.swidth         = 640,
		.sheight        = 480,
		.totalwidth     = 910,
		.adelay         = 0x68,
		.bdelay         = 0x5d,
		.iform          = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
		.scaledtwidth   = 780,
		.hdelayx1       = 135,
		.hactivex1      = 754,
		.vdelay         = 0x1a,
		.vbipack        = 144,
		.sram           = -1,
417
		.vbistart	= { 10, 273 },
418 419 420 421 422 423 424
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 135,
			/* swidth */ (640 * 910 + 780 / 2) / 780,
			/* totalwidth */ 910,
			/* sqwidth */ 780,
			/* vdelay */ 0x1a,
			/* sheight */ 480,
425
			/* extraheight */ 0,
426
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
	},{
		.v4l2_id        = V4L2_STD_PAL_N,
		.name           = "PAL-N",
		.Fsc            = 35468950,
		.swidth         = 768,
		.sheight        = 576,
		.totalwidth     = 1135,
		.adelay         = 0x7f,
		.bdelay         = 0x72,
		.iform          = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
		.scaledtwidth   = 944,
		.hdelayx1       = 186,
		.hactivex1      = 922,
		.vdelay         = 0x20,
		.vbipack        = 144,
		.sram           = -1,
443 444 445 446 447 448 449 450
		.vbistart       = { 7, 320 },
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 186,
			/* swidth */ (768 * 1135 + 944 / 2) / 944,
			/* totalwidth */ 1135,
			/* sqwidth */ 944,
			/* vdelay */ 0x20,
			/* sheight */ 576,
451
			/* extraheight */ 0,
452
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
	},{
		.v4l2_id        = V4L2_STD_NTSC_M_JP,
		.name           = "NTSC-JP",
		.Fsc            = 28636363,
		.swidth         = 640,
		.sheight        = 480,
		.totalwidth     = 910,
		.adelay         = 0x68,
		.bdelay         = 0x5d,
		.iform          = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
		.scaledtwidth   = 780,
		.hdelayx1       = 135,
		.hactivex1      = 754,
		.vdelay         = 0x16,
		.vbipack        = 144,
		.sram           = -1,
469 470 471 472 473 474 475 476
		.vbistart       = { 10, 273 },
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 135,
			/* swidth */ (640 * 910 + 780 / 2) / 780,
			/* totalwidth */ 910,
			/* sqwidth */ 780,
			/* vdelay */ 0x16,
			/* sheight */ 480,
477
			/* extraheight */ 0,
478
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
	},{
		/* that one hopefully works with the strange timing
		 * which video recorders produce when playing a NTSC
		 * tape on a PAL TV ... */
		.v4l2_id        = V4L2_STD_PAL_60,
		.name           = "PAL-60",
		.Fsc            = 35468950,
		.swidth         = 924,
		.sheight        = 480,
		.totalwidth     = 1135,
		.adelay         = 0x7f,
		.bdelay         = 0x72,
		.iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
		.scaledtwidth   = 1135,
		.hdelayx1       = 186,
		.hactivex1      = 924,
		.vdelay         = 0x1a,
		.vbipack        = 255,
		.vtotal         = 524,
		.sram           = -1,
499
		.vbistart	= { 10, 273 },
500 501 502 503 504 505 506
		CROPCAP(/* minhdelayx1 */ 68,
			/* hdelayx1 */ 186,
			/* swidth */ 924,
			/* totalwidth */ 1135,
			/* sqwidth */ 944,
			/* vdelay */ 0x1a,
			/* sheight */ 480,
507
			/* extraheight */ 0,
508
			/* videostart0 */ 23)
Linus Torvalds's avatar
Linus Torvalds committed
509 510 511 512 513 514 515
	}
};
static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);

/* ----------------------------------------------------------------------- */
/* bttv format list
   packed pixel formats must come first */
516
static const struct bttv_format formats[] = {
Linus Torvalds's avatar
Linus Torvalds committed
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
	{
		.name     = "8 bpp, gray",
		.fourcc   = V4L2_PIX_FMT_GREY,
		.btformat = BT848_COLOR_FMT_Y8,
		.depth    = 8,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "8 bpp, dithered color",
		.fourcc   = V4L2_PIX_FMT_HI240,
		.btformat = BT848_COLOR_FMT_RGB8,
		.depth    = 8,
		.flags    = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
	},{
		.name     = "15 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_RGB555,
		.btformat = BT848_COLOR_FMT_RGB15,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "15 bpp RGB, be",
		.fourcc   = V4L2_PIX_FMT_RGB555X,
		.btformat = BT848_COLOR_FMT_RGB15,
		.btswap   = 0x03, /* byteswap */
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "16 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_RGB565,
		.btformat = BT848_COLOR_FMT_RGB16,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "16 bpp RGB, be",
		.fourcc   = V4L2_PIX_FMT_RGB565X,
		.btformat = BT848_COLOR_FMT_RGB16,
		.btswap   = 0x03, /* byteswap */
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "24 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_BGR24,
		.btformat = BT848_COLOR_FMT_RGB24,
		.depth    = 24,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "32 bpp RGB, le",
		.fourcc   = V4L2_PIX_FMT_BGR32,
		.btformat = BT848_COLOR_FMT_RGB32,
		.depth    = 32,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "32 bpp RGB, be",
		.fourcc   = V4L2_PIX_FMT_RGB32,
		.btformat = BT848_COLOR_FMT_RGB32,
		.btswap   = 0x0f, /* byte+word swap */
		.depth    = 32,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "4:2:2, packed, YUYV",
		.fourcc   = V4L2_PIX_FMT_YUYV,
		.btformat = BT848_COLOR_FMT_YUY2,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "4:2:2, packed, UYVY",
		.fourcc   = V4L2_PIX_FMT_UYVY,
		.btformat = BT848_COLOR_FMT_YUY2,
		.btswap   = 0x03, /* byteswap */
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PACKED,
	},{
		.name     = "4:2:2, planar, Y-Cb-Cr",
		.fourcc   = V4L2_PIX_FMT_YUV422P,
		.btformat = BT848_COLOR_FMT_YCrCb422,
		.depth    = 16,
		.flags    = FORMAT_FLAGS_PLANAR,
		.hshift   = 1,
		.vshift   = 0,
	},{
		.name     = "4:2:0, planar, Y-Cb-Cr",
		.fourcc   = V4L2_PIX_FMT_YUV420,
		.btformat = BT848_COLOR_FMT_YCrCb422,
		.depth    = 12,
		.flags    = FORMAT_FLAGS_PLANAR,
		.hshift   = 1,
		.vshift   = 1,
	},{
		.name     = "4:2:0, planar, Y-Cr-Cb",
		.fourcc   = V4L2_PIX_FMT_YVU420,
		.btformat = BT848_COLOR_FMT_YCrCb422,
		.depth    = 12,
		.flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
		.hshift   = 1,
		.vshift   = 1,
	},{
		.name     = "4:1:1, planar, Y-Cb-Cr",
		.fourcc   = V4L2_PIX_FMT_YUV411P,
		.btformat = BT848_COLOR_FMT_YCrCb411,
		.depth    = 12,
		.flags    = FORMAT_FLAGS_PLANAR,
		.hshift   = 2,
		.vshift   = 0,
	},{
		.name     = "4:1:0, planar, Y-Cb-Cr",
		.fourcc   = V4L2_PIX_FMT_YUV410,
		.btformat = BT848_COLOR_FMT_YCrCb411,
		.depth    = 9,
		.flags    = FORMAT_FLAGS_PLANAR,
		.hshift   = 2,
		.vshift   = 2,
	},{
		.name     = "4:1:0, planar, Y-Cr-Cb",
		.fourcc   = V4L2_PIX_FMT_YVU410,
		.btformat = BT848_COLOR_FMT_YCrCb411,
		.depth    = 9,
		.flags    = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
		.hshift   = 2,
		.vshift   = 2,
	},{
		.name     = "raw scanlines",
		.fourcc   = -1,
		.btformat = BT848_COLOR_FMT_RAW,
		.depth    = 8,
		.flags    = FORMAT_FLAGS_RAW,
	}
};
643
static const unsigned int FORMATS = ARRAY_SIZE(formats);
Linus Torvalds's avatar
Linus Torvalds committed
644 645 646 647

/* ----------------------------------------------------------------------- */
/* resource management                                                     */

648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680
/*
   RESOURCE_    allocated by                freed by

   VIDEO_READ   bttv_read 1)                bttv_read 2)

   VIDEO_STREAM VIDIOC_STREAMON             VIDIOC_STREAMOFF
		 VIDIOC_QBUF 1)              bttv_release
		 VIDIOCMCAPTURE 1)

   OVERLAY	 VIDIOCCAPTURE on            VIDIOCCAPTURE off
		 VIDIOC_OVERLAY on           VIDIOC_OVERLAY off
		 3)                          bttv_release

   VBI		 VIDIOC_STREAMON             VIDIOC_STREAMOFF
		 VIDIOC_QBUF 1)              bttv_release
		 bttv_read, bttv_poll 1) 4)

   1) The resource must be allocated when we enter buffer prepare functions
      and remain allocated while buffers are in the DMA queue.
   2) This is a single frame read.
   3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
      RESOURCE_OVERLAY is allocated.
   4) This is a continuous read, implies VIDIOC_STREAMON.

   Note this driver permits video input and standard changes regardless if
   resources are allocated.
*/

#define VBI_RESOURCES (RESOURCE_VBI)
#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
			 RESOURCE_VIDEO_STREAM | \
			 RESOURCE_OVERLAY)

Linus Torvalds's avatar
Linus Torvalds committed
681
static
682
int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
Linus Torvalds's avatar
Linus Torvalds committed
683
{
684 685
	int xbits; /* mutual exclusive resources */

Linus Torvalds's avatar
Linus Torvalds committed
686 687 688 689
	if (fh->resources & bit)
		/* have it already allocated */
		return 1;

690 691 692 693
	xbits = bit;
	if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
		xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;

Linus Torvalds's avatar
Linus Torvalds committed
694
	/* is it free? */
695
	if (btv->resources & xbits) {
Linus Torvalds's avatar
Linus Torvalds committed
696
		/* no, someone else uses it */
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
		goto fail;
	}

	if ((bit & VIDEO_RESOURCES)
	    && 0 == (btv->resources & VIDEO_RESOURCES)) {
		/* Do crop - use current, don't - use default parameters. */
		__s32 top = btv->crop[!!fh->do_crop].rect.top;

		if (btv->vbi_end > top)
			goto fail;

		/* We cannot capture the same line as video and VBI data.
		   Claim scan lines crop[].rect.top to bottom. */
		btv->crop_start = top;
	} else if (bit & VBI_RESOURCES) {
		__s32 end = fh->vbi_fmt.end;

		if (end > btv->crop_start)
			goto fail;

		/* Claim scan lines above fh->vbi_fmt.end. */
		btv->vbi_end = end;
Linus Torvalds's avatar
Linus Torvalds committed
719
	}
720

Linus Torvalds's avatar
Linus Torvalds committed
721 722 723 724
	/* it's free, grab it */
	fh->resources  |= bit;
	btv->resources |= bit;
	return 1;
725 726 727

 fail:
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
728 729 730 731 732 733 734 735 736 737 738 739 740 741
}

static
int check_btres(struct bttv_fh *fh, int bit)
{
	return (fh->resources & bit);
}

static
int locked_btres(struct bttv *btv, int bit)
{
	return (btv->resources & bit);
}

742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
/* Call with btv->lock down. */
static void
disclaim_vbi_lines(struct bttv *btv)
{
	btv->vbi_end = 0;
}

/* Call with btv->lock down. */
static void
disclaim_video_lines(struct bttv *btv)
{
	const struct bttv_tvnorm *tvnorm;
	u8 crop;

	tvnorm = &bttv_tvnorms[btv->tvnorm];
	btv->crop_start = tvnorm->cropcap.bounds.top
		+ tvnorm->cropcap.bounds.height;

	/* VBI capturing ends at VDELAY, start of video capturing, no
	   matter how many lines the VBI RISC program expects. When video
	   capturing is off, it shall no longer "preempt" VBI capturing,
	   so we set VDELAY to maximum. */
	crop = btread(BT848_E_CROP) | 0xc0;
	btwrite(crop, BT848_E_CROP);
	btwrite(0xfe, BT848_E_VDELAY_LO);
	btwrite(crop, BT848_O_CROP);
	btwrite(0xfe, BT848_O_VDELAY_LO);
}

Linus Torvalds's avatar
Linus Torvalds committed
771
static
772
void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
Linus Torvalds's avatar
Linus Torvalds committed
773 774
{
	if ((fh->resources & bits) != bits) {
775 776
		/* trying to free resources not allocated by us ... */
		pr_err("BUG! (btres)\n");
Linus Torvalds's avatar
Linus Torvalds committed
777 778 779
	}
	fh->resources  &= ~bits;
	btv->resources &= ~bits;
780 781 782 783 784 785 786 787

	bits = btv->resources;

	if (0 == (bits & VIDEO_RESOURCES))
		disclaim_video_lines(btv);

	if (0 == (bits & VBI_RESOURCES))
		disclaim_vbi_lines(btv);
Linus Torvalds's avatar
Linus Torvalds committed
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
}

/* ----------------------------------------------------------------------- */
/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC          */

/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
   PLL_X = Reference pre-divider (0=1, 1=2)
   PLL_C = Post divider (0=6, 1=4)
   PLL_I = Integer input
   PLL_F = Fractional input

   F_input = 28.636363 MHz:
   PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
*/

static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
{
805
	unsigned char fl, fh, fi;
Linus Torvalds's avatar
Linus Torvalds committed
806

807 808 809
	/* prevent overflows */
	fin/=4;
	fout/=4;
Linus Torvalds's avatar
Linus Torvalds committed
810

811 812
	fout*=12;
	fi=fout/fin;
Linus Torvalds's avatar
Linus Torvalds committed
813

814 815
	fout=(fout%fin)*256;
	fh=fout/fin;
Linus Torvalds's avatar
Linus Torvalds committed
816

817 818
	fout=(fout%fin)*256;
	fl=fout/fin;
Linus Torvalds's avatar
Linus Torvalds committed
819

820 821 822
	btwrite(fl, BT848_PLL_F_LO);
	btwrite(fh, BT848_PLL_F_HI);
	btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds's avatar
Linus Torvalds committed
823 824 825 826
}

static void set_pll(struct bttv *btv)
{
827
	int i;
Linus Torvalds's avatar
Linus Torvalds committed
828

829 830
	if (!btv->pll.pll_crystal)
		return;
Linus Torvalds's avatar
Linus Torvalds committed
831 832

	if (btv->pll.pll_ofreq == btv->pll.pll_current) {
833
		dprintk("%d: PLL: no change required\n", btv->c.nr);
834 835
		return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
836

837 838 839
	if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
		/* no PLL needed */
		if (btv->pll.pll_current == 0)
840
			return;
841 842 843
		if (bttv_verbose)
			pr_info("%d: PLL can sleep, using XTAL (%d)\n",
				btv->c.nr, btv->pll.pll_ifreq);
844 845 846 847 848
		btwrite(0x00,BT848_TGCTRL);
		btwrite(0x00,BT848_PLL_XCI);
		btv->pll.pll_current = 0;
		return;
	}
Linus Torvalds's avatar
Linus Torvalds committed
849

850 851 852 853
	if (bttv_verbose)
		pr_info("%d: Setting PLL: %d => %d (needs up to 100ms)\n",
			btv->c.nr,
			btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds's avatar
Linus Torvalds committed
854 855
	set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);

856
	for (i=0; i<10; i++) {
Linus Torvalds's avatar
Linus Torvalds committed
857 858 859
		/*  Let other people run while the PLL stabilizes */
		msleep(10);

860
		if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds's avatar
Linus Torvalds committed
861
			btwrite(0,BT848_DSTATUS);
862
		} else {
863 864
			btwrite(0x08,BT848_TGCTRL);
			btv->pll.pll_current = btv->pll.pll_ofreq;
865 866
			if (bttv_verbose)
				pr_info("PLL set ok\n");
867
			return;
868 869 870
		}
	}
	btv->pll.pll_current = -1;
871 872
	if (bttv_verbose)
		pr_info("Setting PLL failed\n");
873
	return;
Linus Torvalds's avatar
Linus Torvalds committed
874 875 876 877 878 879 880 881 882
}

/* used to switch between the bt848's analog/digital video capture modes */
static void bt848A_set_timing(struct bttv *btv)
{
	int i, len;
	int table_idx = bttv_tvnorms[btv->tvnorm].sram;
	int fsc       = bttv_tvnorms[btv->tvnorm].Fsc;

883
	if (btv->input == btv->dig) {
884
		dprintk("%d: load digital timing table (table_idx=%d)\n",
Linus Torvalds's avatar
Linus Torvalds committed
885 886 887
			btv->c.nr,table_idx);

		/* timing change...reset timing generator address */
888 889 890
		btwrite(0x00, BT848_TGCTRL);
		btwrite(0x02, BT848_TGCTRL);
		btwrite(0x00, BT848_TGCTRL);
Linus Torvalds's avatar
Linus Torvalds committed
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912

		len=SRAM_Table[table_idx][0];
		for(i = 1; i <= len; i++)
			btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
		btv->pll.pll_ofreq = 27000000;

		set_pll(btv);
		btwrite(0x11, BT848_TGCTRL);
		btwrite(0x41, BT848_DVSIF);
	} else {
		btv->pll.pll_ofreq = fsc;
		set_pll(btv);
		btwrite(0x0, BT848_DVSIF);
	}
}

/* ----------------------------------------------------------------------- */

static void bt848_bright(struct bttv *btv, int bright)
{
	int value;

913
	// printk("set bright: %d\n", bright); // DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
	btv->bright = bright;

	/* We want -128 to 127 we get 0-65535 */
	value = (bright >> 8) - 128;
	btwrite(value & 0xff, BT848_BRIGHT);
}

static void bt848_hue(struct bttv *btv, int hue)
{
	int value;

	btv->hue = hue;

	/* -128 to 127 */
	value = (hue >> 8) - 128;
929
	btwrite(value & 0xff, BT848_HUE);
Linus Torvalds's avatar
Linus Torvalds committed
930 931 932 933 934 935 936 937 938 939 940
}

static void bt848_contrast(struct bttv *btv, int cont)
{
	int value,hibit;

	btv->contrast = cont;

	/* 0-511 */
	value = (cont  >> 7);
	hibit = (value >> 6) & 4;
941 942 943
	btwrite(value & 0xff, BT848_CONTRAST_LO);
	btaor(hibit, ~4, BT848_E_CONTROL);
	btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds's avatar
Linus Torvalds committed
944 945 946 947 948 949 950 951 952
}

static void bt848_sat(struct bttv *btv, int color)
{
	int val_u,val_v,hibits;

	btv->saturation = color;

	/* 0-511 for the color */
953 954
	val_u   = ((color * btv->opt_uv_ratio) / 50) >> 7;
	val_v   = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
955
	hibits  = (val_u >> 7) & 2;
Linus Torvalds's avatar
Linus Torvalds committed
956
	hibits |= (val_v >> 8) & 1;
957 958 959 960
	btwrite(val_u & 0xff, BT848_SAT_U_LO);
	btwrite(val_v & 0xff, BT848_SAT_V_LO);
	btaor(hibits, ~3, BT848_E_CONTROL);
	btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds's avatar
Linus Torvalds committed
961 962 963 964 965 966 967 968 969 970 971 972
}

/* ----------------------------------------------------------------------- */

static int
video_mux(struct bttv *btv, unsigned int input)
{
	int mux,mask2;

	if (input >= bttv_tvcards[btv->c.type].video_inputs)
		return -EINVAL;

973
	/* needed by RemoteVideo MX */
Linus Torvalds's avatar
Linus Torvalds committed
974 975 976 977 978 979 980 981 982 983 984
	mask2 = bttv_tvcards[btv->c.type].gpiomask2;
	if (mask2)
		gpio_inout(mask2,mask2);

	if (input == btv->svhs)  {
		btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
		btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
	} else {
		btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
		btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
	}
985
	mux = bttv_muxsel(btv, input);
Linus Torvalds's avatar
Linus Torvalds committed
986
	btaor(mux<<5, ~(3<<5), BT848_IFORM);
987
	dprintk("%d: video mux: input=%d mux=%d\n", btv->c.nr, input, mux);
Linus Torvalds's avatar
Linus Torvalds committed
988 989 990 991 992 993 994 995 996

	/* card specific hook */
	if(bttv_tvcards[btv->c.type].muxsel_hook)
		bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
	return 0;
}

static char *audio_modes[] = {
	"audio: tuner", "audio: radio", "audio: extern",
997
	"audio: intern", "audio: mute"
Linus Torvalds's avatar
Linus Torvalds committed
998 999
};

1000 1001
static void
audio_mux_gpio(struct bttv *btv, int input, int mute)
Linus Torvalds's avatar
Linus Torvalds committed
1002
{
1003
	int gpio_val, signal, mute_gpio;
Linus Torvalds's avatar
Linus Torvalds committed
1004 1005 1006 1007 1008

	gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
		   bttv_tvcards[btv->c.type].gpiomask);
	signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;

1009
	/* automute */
1010
	mute_gpio = mute || (btv->opt_automute && (!signal || !btv->users)
1011
				&& !btv->has_radio_tuner);
1012

1013
	if (mute_gpio)
1014 1015 1016 1017
		gpio_val = bttv_tvcards[btv->c.type].gpiomute;
	else
		gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
	switch (btv->c.type) {
	case BTTV_BOARD_VOODOOTV_FM:
	case BTTV_BOARD_VOODOOTV_200:
		gpio_val = bttv_tda9880_setnorm(btv, gpio_val);
		break;

	default:
		gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
	}

Linus Torvalds's avatar
Linus Torvalds committed
1028
	if (bttv_gpio)
1029
		bttv_gpio_tracking(btv, audio_modes[mute_gpio ? 4 : input]);
1030 1031 1032
}

static int
1033
audio_mute(struct bttv *btv, int mute)
1034 1035 1036
{
	struct v4l2_ctrl *ctrl;

1037
	audio_mux_gpio(btv, btv->audio_input, mute);
1038

1039
	if (btv->sd_msp34xx) {
1040 1041
		ctrl = v4l2_ctrl_find(btv->sd_msp34xx->ctrl_handler, V4L2_CID_AUDIO_MUTE);
		if (ctrl)
1042
			v4l2_ctrl_s_ctrl(ctrl, mute);
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
	}
	if (btv->sd_tvaudio) {
		ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE);
		if (ctrl)
			v4l2_ctrl_s_ctrl(ctrl, mute);
	}
	if (btv->sd_tda7432) {
		ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE);
		if (ctrl)
			v4l2_ctrl_s_ctrl(ctrl, mute);
	}
	return 0;
}

static int
audio_input(struct bttv *btv, int input)
{
	audio_mux_gpio(btv, input, btv->mute);

	if (btv->sd_msp34xx) {
		u32 in;
1064

1065 1066 1067 1068 1069 1070 1071
		/* Note: the inputs tuner/radio/extern/intern are translated
		   to msp routings. This assumes common behavior for all msp3400
		   based TV cards. When this assumption fails, then the
		   specific MSP routing must be added to the card table.
		   For now this is sufficient. */
		switch (input) {
		case TVAUDIO_INPUT_RADIO:
1072 1073 1074 1075 1076
			/* Some boards need the msp do to the radio demod */
			if (btv->radio_uses_msp_demodulator) {
				in = MSP_INPUT_DEFAULT;
				break;
			}
1077
			in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1078
				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
1079 1080
			break;
		case TVAUDIO_INPUT_EXTERN:
1081
			in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
1082
				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
1083 1084 1085 1086 1087 1088 1089
			break;
		case TVAUDIO_INPUT_INTERN:
			/* Yes, this is the same input as for RADIO. I doubt
			   if this is ever used. The only board with an INTERN
			   input is the BTTV_BOARD_AVERMEDIA98. I wonder how
			   that was tested. My guess is that the whole INTERN
			   input does not work. */
1090
			in = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1091
				    MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
1092 1093 1094
			break;
		case TVAUDIO_INPUT_TUNER:
		default:
1095 1096 1097 1098
			/* This is the only card that uses TUNER2, and afaik,
			   is the only difference between the VOODOOTV_FM
			   and VOODOOTV_200 */
			if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
1099
				in = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
1100 1101
					MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
			else
1102
				in = MSP_INPUT_DEFAULT;
1103 1104
			break;
		}
1105 1106
		v4l2_subdev_call(btv->sd_msp34xx, audio, s_routing,
			       in, MSP_OUTPUT_DEFAULT, 0);
1107
	}
1108
	if (btv->sd_tvaudio) {
1109
		v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing,
1110
				 input, 0, 0);
1111
	}
Linus Torvalds's avatar
Linus Torvalds committed
1112 1113 1114
	return 0;
}

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
static void
bttv_crop_calc_limits(struct bttv_crop *c)
{
	/* Scale factor min. 1:1, max. 16:1. Min. image size
	   48 x 32. Scaled width must be a multiple of 4. */

	if (1) {
		/* For bug compatibility with VIDIOCGCAP and image
		   size checks in earlier driver versions. */
		c->min_scaled_width = 48;
		c->min_scaled_height = 32;
	} else {
		c->min_scaled_width =
1128
			(max_t(unsigned int, 48, c->rect.width >> 4) + 3) & ~3;
1129
		c->min_scaled_height =
1130
			max_t(unsigned int, 32, c->rect.height >> 4);
1131 1132 1133 1134 1135 1136 1137
	}

	c->max_scaled_width  = c->rect.width & ~3;
	c->max_scaled_height = c->rect.height;
}

static void
1138
bttv_crop_reset(struct bttv_crop *c, unsigned int norm)
1139 1140 1141 1142 1143 1144
{
	c->rect = bttv_tvnorms[norm].cropcap.defrect;
	bttv_crop_calc_limits(c);
}

/* Call with btv->lock down. */
Linus Torvalds's avatar
Linus Torvalds committed
1145 1146 1147 1148
static int
set_tvnorm(struct bttv *btv, unsigned int norm)
{
	const struct bttv_tvnorm *tvnorm;
1149
	v4l2_std_id id;
Linus Torvalds's avatar
Linus Torvalds committed
1150

1151 1152
	BUG_ON(norm >= BTTV_TVNORMS);
	BUG_ON(btv->tvnorm >= BTTV_TVNORMS);
Linus Torvalds's avatar
Linus Torvalds committed
1153 1154 1155

	tvnorm = &bttv_tvnorms[norm];

1156
	if (memcmp(&bttv_tvnorms[btv->tvnorm].cropcap, &tvnorm->cropcap,
1157
		    sizeof (tvnorm->cropcap))) {
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
		bttv_crop_reset(&btv->crop[0], norm);
		btv->crop[1] = btv->crop[0]; /* current = default */

		if (0 == (btv->resources & VIDEO_RESOURCES)) {
			btv->crop_start = tvnorm->cropcap.bounds.top
				+ tvnorm->cropcap.bounds.height;
		}
	}

	btv->tvnorm = norm;

Linus Torvalds's avatar
Linus Torvalds committed
1169 1170 1171 1172 1173 1174 1175 1176 1177
	btwrite(tvnorm->adelay, BT848_ADELAY);
	btwrite(tvnorm->bdelay, BT848_BDELAY);
	btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
	      BT848_IFORM);
	btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
	btwrite(1, BT848_VBI_PACK_DEL);
	bt848A_set_timing(btv);

	switch (btv->c.type) {
1178
	case BTTV_BOARD_VOODOOTV_FM:
1179
	case BTTV_BOARD_VOODOOTV_200:
1180
		bttv_tda9880_setnorm(btv, gpio_read());
Linus Torvalds's avatar
Linus Torvalds committed
1181 1182
		break;
	}
1183
	id = tvnorm->v4l2_id;
1184
	bttv_call_all(btv, video, s_std, id);
1185

Linus Torvalds's avatar
Linus Torvalds committed
1186 1187 1188
	return 0;
}

1189
/* Call with btv->lock down. */
Linus Torvalds's avatar
Linus Torvalds committed
1190
static void
1191
set_input(struct bttv *btv, unsigned int input, unsigned int norm)
Linus Torvalds's avatar
Linus Torvalds committed
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
{
	unsigned long flags;

	btv->input = input;
	if (irq_iswitch) {
		spin_lock_irqsave(&btv->s_lock,flags);
		if (btv->curr.frame_irq) {
			/* active capture -> delayed input switch */
			btv->new_input = input;
		} else {
			video_mux(btv,input);
		}
		spin_unlock_irqrestore(&btv->s_lock,flags);
	} else {
		video_mux(btv,input);
	}
1208 1209 1210
	btv->audio_input = (btv->tuner_type != TUNER_ABSENT && input == 0) ?
				TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN;
	audio_input(btv, btv->audio_input);
1211
	set_tvnorm(btv, norm);
Linus Torvalds's avatar
Linus Torvalds committed
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
}

static void init_irqreg(struct bttv *btv)
{
	/* clear status */
	btwrite(0xfffffUL, BT848_INT_STAT);

	if (bttv_tvcards[btv->c.type].no_video) {
		/* i2c only */
		btwrite(BT848_INT_I2CDONE,
			BT848_INT_MASK);
	} else {
		/* full video */
		btwrite((btv->triton1)  |
			(btv->gpioirq ? BT848_INT_GPINT : 0) |
			BT848_INT_SCERR |
			(fdsr ? BT848_INT_FDSR : 0) |
1229
			BT848_INT_RISCI | BT848_INT_OCERR |
Linus Torvalds's avatar
Linus Torvalds committed
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247
			BT848_INT_FMTCHG|BT848_INT_HLOCK|
			BT848_INT_I2CDONE,
			BT848_INT_MASK);
	}
}

static void init_bt848(struct bttv *btv)
{
	if (bttv_tvcards[btv->c.type].no_video) {
		/* very basic init only */
		init_irqreg(btv);
		return;
	}

	btwrite(0x00, BT848_CAP_CTL);
	btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
	btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);

1248 1249 1250 1251 1252 1253 1254 1255
	/* set planar and packed mode trigger points and         */
	/* set rising edge of inverted GPINTR pin as irq trigger */
	btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
		BT848_GPIO_DMA_CTL_PLTP1_16|
		BT848_GPIO_DMA_CTL_PLTP23_16|
		BT848_GPIO_DMA_CTL_GPINTC|
		BT848_GPIO_DMA_CTL_GPINTI,
		BT848_GPIO_DMA_CTL);
Linus Torvalds's avatar
Linus Torvalds committed
1256

1257 1258
	btwrite(0x20, BT848_E_VSCALE_HI);
	btwrite(0x20, BT848_O_VSCALE_HI);
Linus Torvalds's avatar
Linus Torvalds committed
1259

1260
	v4l2_ctrl_handler_setup(&btv->ctrl_handler);
Linus Torvalds's avatar
Linus Torvalds committed
1261

1262
	/* interrupt */
Linus Torvalds's avatar
Linus Torvalds committed
1263 1264 1265 1266 1267 1268 1269 1270
	init_irqreg(btv);
}

static void bttv_reinit_bt848(struct bttv *btv)
{
	unsigned long flags;

	if (bttv_verbose)
1271
		pr_info("%d: reset, reinitialize\n", btv->c.nr);
Linus Torvalds's avatar
Linus Torvalds committed
1272 1273 1274 1275 1276 1277
	spin_lock_irqsave(&btv->s_lock,flags);
	btv->errors=0;
	bttv_set_dma(btv,0);
	spin_unlock_irqrestore(&btv->s_lock,flags);

	init_bt848(btv);
1278
	btv->pll.pll_current = -1;
1279
	set_input(btv, btv->input, btv->tvnorm);
Linus Torvalds's avatar
Linus Torvalds committed
1280 1281
}

1282
static int bttv_s_ctrl(struct v4l2_ctrl *c)
1283
{
1284 1285
	struct bttv *btv = container_of(c->handler, struct bttv, ctrl_handler);
	int val;
1286 1287 1288

	switch (c->id) {
	case V4L2_CID_BRIGHTNESS:
1289
		bt848_bright(btv, c->val);
1290 1291
		break;
	case V4L2_CID_HUE:
1292
		bt848_hue(btv, c->val);
1293 1294
		break;
	case V4L2_CID_CONTRAST:
1295
		bt848_contrast(btv, c->val);
1296 1297
		break;
	case V4L2_CID_SATURATION:
1298
		bt848_sat(btv, c->val);
1299
		break;
1300
	case V4L2_CID_COLOR_KILLER:
1301
		if (c->val) {
1302 1303 1304 1305 1306 1307 1308
			btor(BT848_SCLOOP_CKILL, BT848_E_SCLOOP);
			btor(BT848_SCLOOP_CKILL, BT848_O_SCLOOP);
		} else {
			btand(~BT848_SCLOOP_CKILL, BT848_E_SCLOOP);
			btand(~BT848_SCLOOP_CKILL, BT848_O_SCLOOP);
		}
		break;
1309
	case V4L2_CID_AUDIO_MUTE:
1310
		audio_mute(btv, c->val);
1311
		btv->mute = c->val;
1312
		break;
1313 1314
	case V4L2_CID_AUDIO_VOLUME:
		btv->volume_gpio(btv, c->val);
1315 1316
		break;

1317 1318 1319 1320
	case V4L2_CID_CHROMA_AGC:
		val = c->val ? BT848_SCLOOP_CAGC : 0;
		btwrite(val, BT848_E_SCLOOP);
		btwrite(val, BT848_O_SCLOOP);
1321 1322
		break;
	case V4L2_CID_PRIVATE_COMBFILTER:
1323
		btv->opt_combfilter = c->val;
1324 1325
		break;
	case V4L2_CID_PRIVATE_LUMAFILTER:
1326
		if (c->val) {
1327 1328 1329 1330 1331 1332 1333 1334
			btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
			btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
		} else {
			btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
			btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
		}
		break;
	case V4L2_CID_PRIVATE_AUTOMUTE:
1335
		btv->opt_automute = c->val;
1336 1337 1338
		break;
	case V4L2_CID_PRIVATE_AGC_CRUSH:
		btwrite(BT848_ADC_RESERVED |
1339
				(c->val ? BT848_ADC_CRUSH : 0),
1340 1341 1342
				BT848_ADC);
		break;
	case V4L2_CID_PRIVATE_VCR_HACK:
1343
		btv->opt_vcr_hack = c->val;
1344 1345
		break;
	case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1346
		btwrite(c->val, BT848_WC_UP);
1347 1348
		break;
	case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1349
		btwrite(c->val, BT848_WC_DOWN);
1350 1351
		break;
	case V4L2_CID_PRIVATE_UV_RATIO:
1352
		btv->opt_uv_ratio = c->val;
1353 1354 1355
		bt848_sat(btv, btv->saturation);
		break;
	case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1356
		btaor((c->val << 7), ~BT848_OFORM_RANGE, BT848_OFORM);
1357 1358
		break;
	case V4L2_CID_PRIVATE_CORING:
1359
		btaor((c->val << 5), ~BT848_OFORM_CORE32, BT848_OFORM);
1360 1361 1362 1363 1364 1365 1366
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
/* ----------------------------------------------------------------------- */

static const struct v4l2_ctrl_ops bttv_ctrl_ops = {
	.s_ctrl = bttv_s_ctrl,
};

static struct v4l2_ctrl_config bttv_ctrl_combfilter = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_COMBFILTER,
	.name = "Comb Filter",
	.type = V4L2_CTRL_TYPE_BOOLEAN,
	.min = 0,
	.max = 1,
	.step = 1,
	.def = 1,
};

static struct v4l2_ctrl_config bttv_ctrl_automute = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_AUTOMUTE,
	.name = "Auto Mute",
	.type = V4L2_CTRL_TYPE_BOOLEAN,
	.min = 0,
	.max = 1,
	.step = 1,
	.def = 1,
};

static struct v4l2_ctrl_config bttv_ctrl_lumafilter = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_LUMAFILTER,
	.name = "Luma Decimation Filter",
	.type = V4L2_CTRL_TYPE_BOOLEAN,
	.min = 0,
	.max = 1,
	.step = 1,
	.def = 1,
};

static struct v4l2_ctrl_config bttv_ctrl_agc_crush = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_AGC_CRUSH,
	.name = "AGC Crush",
	.type = V4L2_CTRL_TYPE_BOOLEAN,
	.min = 0,
	.max = 1,
	.step = 1,
	.def = 1,
};

static struct v4l2_ctrl_config bttv_ctrl_vcr_hack = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_VCR_HACK,
	.name = "VCR Hack",
	.type = V4L2_CTRL_TYPE_BOOLEAN,
	.min = 0,
	.max = 1,
	.step = 1,
	.def = 1,
};

static struct v4l2_ctrl_config bttv_ctrl_whitecrush_lower = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
	.name = "Whitecrush Lower",
	.type = V4L2_CTRL_TYPE_INTEGER,
	.min = 0,
	.max = 255,
	.step = 1,
	.def = 0x7f,
};

static struct v4l2_ctrl_config bttv_ctrl_whitecrush_upper = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
	.name = "Whitecrush Upper",
	.type = V4L2_CTRL_TYPE_INTEGER,
	.min = 0,
	.max = 255,
	.step = 1,
	.def = 0xcf,
};

static struct v4l2_ctrl_config bttv_ctrl_uv_ratio = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_UV_RATIO,
	.name = "UV Ratio",
	.type = V4L2_CTRL_TYPE_INTEGER,
	.min = 0,
	.max = 100,
	.step = 1,
	.def = 50,
};

static struct v4l2_ctrl_config bttv_ctrl_full_luma = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
	.name = "Full Luma Range",
	.type = V4L2_CTRL_TYPE_BOOLEAN,
	.min = 0,
	.max = 1,
	.step = 1,
};

static struct v4l2_ctrl_config bttv_ctrl_coring = {
	.ops = &bttv_ctrl_ops,
	.id = V4L2_CID_PRIVATE_CORING,
	.name = "Coring",
	.type = V4L2_CTRL_TYPE_INTEGER,
	.min = 0,
	.max = 3,
	.step = 1,
};


Linus Torvalds's avatar
Linus Torvalds committed
1482 1483 1484 1485 1486 1487 1488
/* ----------------------------------------------------------------------- */

void bttv_gpio_tracking(struct bttv *btv, char *comment)
{
	unsigned int outbits, data;
	outbits = btread(BT848_GPIO_OUT_EN);
	data    = btread(BT848_GPIO_DATA);
1489 1490
	pr_debug("%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
		 btv->c.nr, outbits, data & outbits, data & ~outbits, comment);
Linus Torvalds's avatar
Linus Torvalds committed
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
}

static void bttv_field_count(struct bttv *btv)
{
	int need_count = 0;

	if (btv->users)
		need_count++;

	if (need_count) {
		/* start field counter */
		btor(BT848_INT_VSYNC,BT848_INT_MASK);
	} else {
		/* stop field counter */
		btand(~BT848_INT_VSYNC,BT848_INT_MASK);
		btv->field_count = 0;
	}
}

static const struct bttv_format*
format_by_fourcc(int fourcc)
{
	unsigned int i;

1515 1516
	for (i = 0; i < FORMATS; i++) {
		if (-1 == formats[i].fourcc)
Linus Torvalds's avatar
Linus Torvalds committed
1517
			continue;
1518 1519
		if (formats[i].fourcc == fourcc)
			return formats+i;
Linus Torvalds's avatar
Linus Torvalds committed
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533
	}
	return NULL;
}

/* ----------------------------------------------------------------------- */
/* misc helpers                                                            */

static int
bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
		    struct bttv_buffer *new)
{
	struct bttv_buffer *old;
	unsigned long flags;

1534
	dprintk("switch_overlay: enter [new=%p]\n", new);
Linus Torvalds's avatar
Linus Torvalds committed
1535
	if (new)
1536
		new->vb.state = VIDEOBUF_DONE;
Linus Torvalds's avatar
Linus Torvalds committed
1537 1538 1539 1540 1541 1542 1543
	spin_lock_irqsave(&btv->s_lock,flags);
	old = btv->screen;
	btv->screen = new;
	btv->loop_irq |= 1;
	bttv_set_dma(btv, 0x03);
	spin_unlock_irqrestore(&btv->s_lock,flags);
	if (NULL != old) {
1544 1545
		dprintk("switch_overlay: old=%p state is %d\n",
			old, old->vb.state);
1546
		bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds's avatar
Linus Torvalds committed
1547 1548
		kfree(old);
	}
1549
	if (NULL == new)
1550
		free_btres_lock(btv,fh,RESOURCE_OVERLAY);
Linus Torvalds's avatar
Linus Torvalds committed
1551
	dprintk("switch_overlay: done\n");
1552
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
1553 1554 1555 1556 1557
}

/* ----------------------------------------------------------------------- */
/* video4linux (1) interface                                               */

1558 1559
static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
			       struct bttv_buffer *buf,
1560
			       const struct bttv_format *fmt,
Linus Torvalds's avatar
Linus Torvalds committed
1561 1562 1563
			       unsigned int width, unsigned int height,
			       enum v4l2_field field)
{
1564
	struct bttv_fh *fh = q->priv_data;
Linus Torvalds's avatar
Linus Torvalds committed
1565
	int redo_dma_risc = 0;
1566 1567
	struct bttv_crop c;
	int norm;
Linus Torvalds's avatar
Linus Torvalds committed
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
	int rc;

	/* check settings */
	if (NULL == fmt)
		return -EINVAL;
	if (fmt->btformat == BT848_COLOR_FMT_RAW) {
		width  = RAW_BPL;
		height = RAW_LINES*2;
		if (width*height > buf->vb.bsize)
			return -EINVAL;
		buf->vb.size = buf->vb.bsize;
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591

		/* Make sure tvnorm and vbi_end remain consistent
		   until we're done. */

		norm = btv->tvnorm;

		/* In this mode capturing always starts at defrect.top
		   (default VDELAY), ignoring cropping parameters. */
		if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
			return -EINVAL;
		}

		c.rect = bttv_tvnorms[norm].cropcap.defrect;
Linus Torvalds's avatar
Linus Torvalds committed
1592
	} else {
1593 1594 1595 1596 1597 1598
		norm = btv->tvnorm;
		c = btv->crop[!!fh->do_crop];

		if (width < c.min_scaled_width ||
		    width > c.max_scaled_width ||
		    height < c.min_scaled_height)
Linus Torvalds's avatar
Linus Torvalds committed
1599
			return -EINVAL;
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616

		switch (field) {
		case V4L2_FIELD_TOP:
		case V4L2_FIELD_BOTTOM:
		case V4L2_FIELD_ALTERNATE:
			/* btv->crop counts frame lines. Max. scale
			   factor is 16:1 for frames, 8:1 for fields. */
			if (height * 2 > c.max_scaled_height)
				return -EINVAL;
			break;

		default:
			if (height > c.max_scaled_height)
				return -EINVAL;
			break;
		}

Linus Torvalds's avatar
Linus Torvalds committed
1617 1618 1619 1620 1621 1622 1623 1624
		buf->vb.size = (width * height * fmt->depth) >> 3;
		if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
			return -EINVAL;
	}

	/* alloc + fill struct bttv_buffer (if changed) */
	if (buf->vb.width != width || buf->vb.height != height ||
	    buf->vb.field != field ||
1625 1626 1627 1628 1629
	    buf->tvnorm != norm || buf->fmt != fmt ||
	    buf->crop.top != c.rect.top ||
	    buf->crop.left != c.rect.left ||
	    buf->crop.width != c.rect.width ||
	    buf->crop.height != c.rect.height) {
Linus Torvalds's avatar
Linus Torvalds committed
1630 1631 1632
		buf->vb.width  = width;
		buf->vb.height = height;
		buf->vb.field  = field;
1633
		buf->tvnorm    = norm;
Linus Torvalds's avatar
Linus Torvalds committed
1634
		buf->fmt       = fmt;
1635
		buf->crop      = c.rect;
Linus Torvalds's avatar
Linus Torvalds committed
1636 1637 1638 1639
		redo_dma_risc = 1;
	}

	/* alloc risc memory */
1640
	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Linus Torvalds's avatar
Linus Torvalds committed
1641
		redo_dma_risc = 1;
1642
		if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds's avatar
Linus Torvalds committed
1643 1644 1645 1646 1647 1648 1649
			goto fail;
	}

	if (redo_dma_risc)
		if (0 != (rc = bttv_buffer_risc(btv,buf)))
			goto fail;