blob: 30cc2d3ba52d44b055c18420612d087790ff2c88 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3 bttv - Bt848 frame grabber driver
4
5 Copyright (C) 1996,97,98 Ralph Metzler <rjkm@thp.uni-koeln.de>
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08006 & Marcus Metzler <mocm@thp.uni-koeln.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
8
9 some v4l2 code lines are taken from Justin's bttv2 driver which is
10 (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
11
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -030012 V4L1 removal from:
13 (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
14
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -030015 Fixes to be fully V4L2 compliant by
16 (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
17
Michael Schimeke5bd0262007-01-18 16:17:39 -030018 Cropping and overscan support
19 Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
20 Sponsored by OPQ Systems AB
21
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 This program is free software; you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24 the Free Software Foundation; either version 2 of the License, or
25 (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35*/
36
37#include <linux/init.h>
38#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/delay.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>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020046#include "bttvp.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020047#include <media/v4l2-common.h>
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -030048#include <media/tvaudio.h>
Hans Verkuil2474ed42006-03-19 12:35:57 -030049#include <media/msp3400.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020050
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -070051#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#include <asm/io.h>
54#include <asm/byteorder.h>
55
Mauro Carvalho Chehabfa3fcce2006-03-23 21:45:24 -030056#include <media/rds.h>
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070057
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059unsigned int bttv_num; /* number of Bt848s in use */
60struct bttv bttvs[BTTV_MAX];
61
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020062unsigned int bttv_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063unsigned int bttv_verbose = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020064unsigned int bttv_gpio;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66/* config variables */
67#ifdef __BIG_ENDIAN
68static unsigned int bigendian=1;
69#else
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020070static unsigned int bigendian;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#endif
72static unsigned int radio[BTTV_MAX];
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020073static unsigned int irq_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static unsigned int gbuffers = 8;
75static unsigned int gbufsize = 0x208000;
Michael Schimeke5bd0262007-01-18 16:17:39 -030076static unsigned int reset_crop = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static int video_nr = -1;
79static int radio_nr = -1;
80static int vbi_nr = -1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020081static int debug_latency;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020083static unsigned int fdsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* options */
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020086static unsigned int combfilter;
87static unsigned int lumafilter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static unsigned int automute = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020089static unsigned int chroma_agc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static unsigned int adc_crush = 1;
91static unsigned int whitecrush_upper = 0xCF;
92static unsigned int whitecrush_lower = 0x7F;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020093static unsigned int vcr_hack;
94static unsigned int irq_iswitch;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070095static unsigned int uv_ratio = 50;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020096static unsigned int full_luma_range;
97static unsigned int coring;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070098extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100/* API features (turn on/off stuff for testing) */
101static unsigned int v4l2 = 1;
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/* insmod args */
104module_param(bttv_verbose, int, 0644);
105module_param(bttv_gpio, int, 0644);
106module_param(bttv_debug, int, 0644);
107module_param(irq_debug, int, 0644);
108module_param(debug_latency, int, 0644);
109
110module_param(fdsr, int, 0444);
111module_param(video_nr, int, 0444);
112module_param(radio_nr, int, 0444);
113module_param(vbi_nr, int, 0444);
114module_param(gbuffers, int, 0444);
115module_param(gbufsize, int, 0444);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300116module_param(reset_crop, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118module_param(v4l2, int, 0644);
119module_param(bigendian, int, 0644);
120module_param(irq_iswitch, int, 0644);
121module_param(combfilter, int, 0444);
122module_param(lumafilter, int, 0444);
123module_param(automute, int, 0444);
124module_param(chroma_agc, int, 0444);
125module_param(adc_crush, int, 0444);
126module_param(whitecrush_upper, int, 0444);
127module_param(whitecrush_lower, int, 0444);
128module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700129module_param(uv_ratio, int, 0444);
130module_param(full_luma_range, int, 0444);
131module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133module_param_array(radio, int, NULL, 0444);
134
135MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
136MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
137MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
138MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
139MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
140MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
141MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
142MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
Michael Schimeke5bd0262007-01-18 16:17:39 -0300143MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
144 "is 1 (yes) for compatibility with older applications");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
146MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
147MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
148MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
149MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
150MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
151MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700152MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
153MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
154MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
157MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
158MODULE_LICENSE("GPL");
159
160/* ----------------------------------------------------------------------- */
161/* sysfs */
162
Kay Sievers54bd5b62007-10-08 16:26:13 -0300163static ssize_t show_card(struct device *cd,
164 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -0300166 struct video_device *vfd = container_of(cd, struct video_device, class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 struct bttv *btv = dev_get_drvdata(vfd->dev);
168 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
169}
Kay Sievers54bd5b62007-10-08 16:26:13 -0300170static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172/* ----------------------------------------------------------------------- */
Jarod Wilsonf992a492007-03-24 15:23:50 -0300173/* dvb auto-load setup */
174#if defined(CONFIG_MODULES) && defined(MODULE)
175static void request_module_async(struct work_struct *work)
176{
177 request_module("dvb-bt8xx");
178}
179
180static void request_modules(struct bttv *dev)
181{
182 INIT_WORK(&dev->request_module_wk, request_module_async);
183 schedule_work(&dev->request_module_wk);
184}
185#else
186#define request_modules(dev)
187#endif /* CONFIG_MODULES */
188
189
190/* ----------------------------------------------------------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191/* static data */
192
193/* special timing tables from conexant... */
194static u8 SRAM_Table[][60] =
195{
196 /* PAL digital input over GPIO[7:0] */
197 {
198 45, // 45 bytes following
199 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
200 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
201 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
202 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
203 0x37,0x00,0xAF,0x21,0x00
204 },
205 /* NTSC digital input over GPIO[7:0] */
206 {
207 51, // 51 bytes following
208 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
209 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
210 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
211 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
212 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
213 0x00,
214 },
215 // TGB_NTSC392 // quartzsight
216 // This table has been modified to be used for Fusion Rev D
217 {
218 0x2A, // size of table = 42
219 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
220 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
221 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
222 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
223 0x20, 0x00
224 }
225};
226
Michael Schimeke5bd0262007-01-18 16:17:39 -0300227/* minhdelayx1 first video pixel we can capture on a line and
228 hdelayx1 start of active video, both relative to rising edge of
229 /HRESET pulse (0H) in 1 / fCLKx1.
230 swidth width of active video and
231 totalwidth total line width, both in 1 / fCLKx1.
232 sqwidth total line width in square pixels.
233 vdelay start of active video in 2 * field lines relative to
234 trailing edge of /VRESET pulse (VDELAY register).
235 sheight height of active video in 2 * field lines.
236 videostart0 ITU-R frame line number of the line corresponding
237 to vdelay in the first field. */
238#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
239 vdelay, sheight, videostart0) \
240 .cropcap.bounds.left = minhdelayx1, \
241 /* * 2 because vertically we count field lines times two, */ \
242 /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
243 .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
244 /* 4 is a safety margin at the end of the line. */ \
245 .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
246 .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
247 .cropcap.defrect.left = hdelayx1, \
248 .cropcap.defrect.top = (videostart0) * 2, \
249 .cropcap.defrect.width = swidth, \
250 .cropcap.defrect.height = sheight, \
251 .cropcap.pixelaspect.numerator = totalwidth, \
252 .cropcap.pixelaspect.denominator = sqwidth,
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254const struct bttv_tvnorm bttv_tvnorms[] = {
255 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800256 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
257 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 {
259 .v4l2_id = V4L2_STD_PAL,
260 .name = "PAL",
261 .Fsc = 35468950,
262 .swidth = 924,
263 .sheight = 576,
264 .totalwidth = 1135,
265 .adelay = 0x7f,
266 .bdelay = 0x72,
267 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
268 .scaledtwidth = 1135,
269 .hdelayx1 = 186,
270 .hactivex1 = 924,
271 .vdelay = 0x20,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300272 .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200274 /* ITU-R frame line number of the first VBI line
Michael Schimeke5bd0262007-01-18 16:17:39 -0300275 we can capture, of the first and second field.
276 The last line is determined by cropcap.bounds. */
277 .vbistart = { 7, 320 },
278 CROPCAP(/* minhdelayx1 */ 68,
279 /* hdelayx1 */ 186,
280 /* Should be (768 * 1135 + 944 / 2) / 944.
281 cropcap.defrect is used for image width
282 checks, so we keep the old value 924. */
283 /* swidth */ 924,
284 /* totalwidth */ 1135,
285 /* sqwidth */ 944,
286 /* vdelay */ 0x20,
287 /* sheight */ 576,
288 /* videostart0 */ 23)
289 /* bt878 (and bt848?) can capture another
290 line below active video. */
291 .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 },{
Hans Verkuild97a11e2006-02-07 06:48:40 -0200293 .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 .name = "NTSC",
295 .Fsc = 28636363,
296 .swidth = 768,
297 .sheight = 480,
298 .totalwidth = 910,
299 .adelay = 0x68,
300 .bdelay = 0x5d,
301 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
302 .scaledtwidth = 910,
303 .hdelayx1 = 128,
304 .hactivex1 = 910,
305 .vdelay = 0x1a,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300306 .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200308 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300309 CROPCAP(/* minhdelayx1 */ 68,
310 /* hdelayx1 */ 128,
311 /* Should be (640 * 910 + 780 / 2) / 780? */
312 /* swidth */ 768,
313 /* totalwidth */ 910,
314 /* sqwidth */ 780,
315 /* vdelay */ 0x1a,
316 /* sheight */ 480,
317 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 },{
319 .v4l2_id = V4L2_STD_SECAM,
320 .name = "SECAM",
321 .Fsc = 35468950,
322 .swidth = 924,
323 .sheight = 576,
324 .totalwidth = 1135,
325 .adelay = 0x7f,
326 .bdelay = 0xb0,
327 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
328 .scaledtwidth = 1135,
329 .hdelayx1 = 186,
330 .hactivex1 = 922,
331 .vdelay = 0x20,
332 .vbipack = 255,
333 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200334 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300335 CROPCAP(/* minhdelayx1 */ 68,
336 /* hdelayx1 */ 186,
337 /* swidth */ 924,
338 /* totalwidth */ 1135,
339 /* sqwidth */ 944,
340 /* vdelay */ 0x20,
341 /* sheight */ 576,
342 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 },{
344 .v4l2_id = V4L2_STD_PAL_Nc,
345 .name = "PAL-Nc",
346 .Fsc = 28636363,
347 .swidth = 640,
348 .sheight = 576,
349 .totalwidth = 910,
350 .adelay = 0x68,
351 .bdelay = 0x5d,
352 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
353 .scaledtwidth = 780,
354 .hdelayx1 = 130,
355 .hactivex1 = 734,
356 .vdelay = 0x1a,
357 .vbipack = 144,
358 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200359 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300360 CROPCAP(/* minhdelayx1 */ 68,
361 /* hdelayx1 */ 130,
362 /* swidth */ (640 * 910 + 780 / 2) / 780,
363 /* totalwidth */ 910,
364 /* sqwidth */ 780,
365 /* vdelay */ 0x1a,
366 /* sheight */ 576,
367 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 },{
369 .v4l2_id = V4L2_STD_PAL_M,
370 .name = "PAL-M",
371 .Fsc = 28636363,
372 .swidth = 640,
373 .sheight = 480,
374 .totalwidth = 910,
375 .adelay = 0x68,
376 .bdelay = 0x5d,
377 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
378 .scaledtwidth = 780,
379 .hdelayx1 = 135,
380 .hactivex1 = 754,
381 .vdelay = 0x1a,
382 .vbipack = 144,
383 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200384 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300385 CROPCAP(/* minhdelayx1 */ 68,
386 /* hdelayx1 */ 135,
387 /* swidth */ (640 * 910 + 780 / 2) / 780,
388 /* totalwidth */ 910,
389 /* sqwidth */ 780,
390 /* vdelay */ 0x1a,
391 /* sheight */ 480,
392 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 },{
394 .v4l2_id = V4L2_STD_PAL_N,
395 .name = "PAL-N",
396 .Fsc = 35468950,
397 .swidth = 768,
398 .sheight = 576,
399 .totalwidth = 1135,
400 .adelay = 0x7f,
401 .bdelay = 0x72,
402 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
403 .scaledtwidth = 944,
404 .hdelayx1 = 186,
405 .hactivex1 = 922,
406 .vdelay = 0x20,
407 .vbipack = 144,
408 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300409 .vbistart = { 7, 320 },
410 CROPCAP(/* minhdelayx1 */ 68,
411 /* hdelayx1 */ 186,
412 /* swidth */ (768 * 1135 + 944 / 2) / 944,
413 /* totalwidth */ 1135,
414 /* sqwidth */ 944,
415 /* vdelay */ 0x20,
416 /* sheight */ 576,
417 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 },{
419 .v4l2_id = V4L2_STD_NTSC_M_JP,
420 .name = "NTSC-JP",
421 .Fsc = 28636363,
422 .swidth = 640,
423 .sheight = 480,
424 .totalwidth = 910,
425 .adelay = 0x68,
426 .bdelay = 0x5d,
427 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
428 .scaledtwidth = 780,
429 .hdelayx1 = 135,
430 .hactivex1 = 754,
431 .vdelay = 0x16,
432 .vbipack = 144,
433 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300434 .vbistart = { 10, 273 },
435 CROPCAP(/* minhdelayx1 */ 68,
436 /* hdelayx1 */ 135,
437 /* swidth */ (640 * 910 + 780 / 2) / 780,
438 /* totalwidth */ 910,
439 /* sqwidth */ 780,
440 /* vdelay */ 0x16,
441 /* sheight */ 480,
442 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 },{
444 /* that one hopefully works with the strange timing
445 * which video recorders produce when playing a NTSC
446 * tape on a PAL TV ... */
447 .v4l2_id = V4L2_STD_PAL_60,
448 .name = "PAL-60",
449 .Fsc = 35468950,
450 .swidth = 924,
451 .sheight = 480,
452 .totalwidth = 1135,
453 .adelay = 0x7f,
454 .bdelay = 0x72,
455 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
456 .scaledtwidth = 1135,
457 .hdelayx1 = 186,
458 .hactivex1 = 924,
459 .vdelay = 0x1a,
460 .vbipack = 255,
461 .vtotal = 524,
462 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200463 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300464 CROPCAP(/* minhdelayx1 */ 68,
465 /* hdelayx1 */ 186,
466 /* swidth */ 924,
467 /* totalwidth */ 1135,
468 /* sqwidth */ 944,
469 /* vdelay */ 0x1a,
470 /* sheight */ 480,
471 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
473};
474static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
475
476/* ----------------------------------------------------------------------- */
477/* bttv format list
478 packed pixel formats must come first */
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -0300479static const struct bttv_format formats[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 {
481 .name = "8 bpp, gray",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 .fourcc = V4L2_PIX_FMT_GREY,
483 .btformat = BT848_COLOR_FMT_Y8,
484 .depth = 8,
485 .flags = FORMAT_FLAGS_PACKED,
486 },{
487 .name = "8 bpp, dithered color",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 .fourcc = V4L2_PIX_FMT_HI240,
489 .btformat = BT848_COLOR_FMT_RGB8,
490 .depth = 8,
491 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
492 },{
493 .name = "15 bpp RGB, le",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 .fourcc = V4L2_PIX_FMT_RGB555,
495 .btformat = BT848_COLOR_FMT_RGB15,
496 .depth = 16,
497 .flags = FORMAT_FLAGS_PACKED,
498 },{
499 .name = "15 bpp RGB, be",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 .fourcc = V4L2_PIX_FMT_RGB555X,
501 .btformat = BT848_COLOR_FMT_RGB15,
502 .btswap = 0x03, /* byteswap */
503 .depth = 16,
504 .flags = FORMAT_FLAGS_PACKED,
505 },{
506 .name = "16 bpp RGB, le",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 .fourcc = V4L2_PIX_FMT_RGB565,
508 .btformat = BT848_COLOR_FMT_RGB16,
509 .depth = 16,
510 .flags = FORMAT_FLAGS_PACKED,
511 },{
512 .name = "16 bpp RGB, be",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 .fourcc = V4L2_PIX_FMT_RGB565X,
514 .btformat = BT848_COLOR_FMT_RGB16,
515 .btswap = 0x03, /* byteswap */
516 .depth = 16,
517 .flags = FORMAT_FLAGS_PACKED,
518 },{
519 .name = "24 bpp RGB, le",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 .fourcc = V4L2_PIX_FMT_BGR24,
521 .btformat = BT848_COLOR_FMT_RGB24,
522 .depth = 24,
523 .flags = FORMAT_FLAGS_PACKED,
524 },{
525 .name = "32 bpp RGB, le",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 .fourcc = V4L2_PIX_FMT_BGR32,
527 .btformat = BT848_COLOR_FMT_RGB32,
528 .depth = 32,
529 .flags = FORMAT_FLAGS_PACKED,
530 },{
531 .name = "32 bpp RGB, be",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 .fourcc = V4L2_PIX_FMT_RGB32,
533 .btformat = BT848_COLOR_FMT_RGB32,
534 .btswap = 0x0f, /* byte+word swap */
535 .depth = 32,
536 .flags = FORMAT_FLAGS_PACKED,
537 },{
538 .name = "4:2:2, packed, YUYV",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 .fourcc = V4L2_PIX_FMT_YUYV,
540 .btformat = BT848_COLOR_FMT_YUY2,
541 .depth = 16,
542 .flags = FORMAT_FLAGS_PACKED,
543 },{
544 .name = "4:2:2, packed, YUYV",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 .fourcc = V4L2_PIX_FMT_YUYV,
546 .btformat = BT848_COLOR_FMT_YUY2,
547 .depth = 16,
548 .flags = FORMAT_FLAGS_PACKED,
549 },{
550 .name = "4:2:2, packed, UYVY",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 .fourcc = V4L2_PIX_FMT_UYVY,
552 .btformat = BT848_COLOR_FMT_YUY2,
553 .btswap = 0x03, /* byteswap */
554 .depth = 16,
555 .flags = FORMAT_FLAGS_PACKED,
556 },{
557 .name = "4:2:2, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 .fourcc = V4L2_PIX_FMT_YUV422P,
559 .btformat = BT848_COLOR_FMT_YCrCb422,
560 .depth = 16,
561 .flags = FORMAT_FLAGS_PLANAR,
562 .hshift = 1,
563 .vshift = 0,
564 },{
565 .name = "4:2:0, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 .fourcc = V4L2_PIX_FMT_YUV420,
567 .btformat = BT848_COLOR_FMT_YCrCb422,
568 .depth = 12,
569 .flags = FORMAT_FLAGS_PLANAR,
570 .hshift = 1,
571 .vshift = 1,
572 },{
573 .name = "4:2:0, planar, Y-Cr-Cb",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 .fourcc = V4L2_PIX_FMT_YVU420,
575 .btformat = BT848_COLOR_FMT_YCrCb422,
576 .depth = 12,
577 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
578 .hshift = 1,
579 .vshift = 1,
580 },{
581 .name = "4:1:1, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 .fourcc = V4L2_PIX_FMT_YUV411P,
583 .btformat = BT848_COLOR_FMT_YCrCb411,
584 .depth = 12,
585 .flags = FORMAT_FLAGS_PLANAR,
586 .hshift = 2,
587 .vshift = 0,
588 },{
589 .name = "4:1:0, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 .fourcc = V4L2_PIX_FMT_YUV410,
591 .btformat = BT848_COLOR_FMT_YCrCb411,
592 .depth = 9,
593 .flags = FORMAT_FLAGS_PLANAR,
594 .hshift = 2,
595 .vshift = 2,
596 },{
597 .name = "4:1:0, planar, Y-Cr-Cb",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 .fourcc = V4L2_PIX_FMT_YVU410,
599 .btformat = BT848_COLOR_FMT_YCrCb411,
600 .depth = 9,
601 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
602 .hshift = 2,
603 .vshift = 2,
604 },{
605 .name = "raw scanlines",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 .fourcc = -1,
607 .btformat = BT848_COLOR_FMT_RAW,
608 .depth = 8,
609 .flags = FORMAT_FLAGS_RAW,
610 }
611};
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -0300612static const unsigned int FORMATS = ARRAY_SIZE(formats);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614/* ----------------------------------------------------------------------- */
615
616#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
617#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
618#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
619#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
620#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
621#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
622#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
623#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700624#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
625#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
626#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
627#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629static const struct v4l2_queryctrl no_ctl = {
630 .name = "42",
631 .flags = V4L2_CTRL_FLAG_DISABLED,
632};
633static const struct v4l2_queryctrl bttv_ctls[] = {
634 /* --- video --- */
635 {
636 .id = V4L2_CID_BRIGHTNESS,
637 .name = "Brightness",
638 .minimum = 0,
639 .maximum = 65535,
640 .step = 256,
641 .default_value = 32768,
642 .type = V4L2_CTRL_TYPE_INTEGER,
643 },{
644 .id = V4L2_CID_CONTRAST,
645 .name = "Contrast",
646 .minimum = 0,
647 .maximum = 65535,
648 .step = 128,
649 .default_value = 32768,
650 .type = V4L2_CTRL_TYPE_INTEGER,
651 },{
652 .id = V4L2_CID_SATURATION,
653 .name = "Saturation",
654 .minimum = 0,
655 .maximum = 65535,
656 .step = 128,
657 .default_value = 32768,
658 .type = V4L2_CTRL_TYPE_INTEGER,
659 },{
660 .id = V4L2_CID_HUE,
661 .name = "Hue",
662 .minimum = 0,
663 .maximum = 65535,
664 .step = 256,
665 .default_value = 32768,
666 .type = V4L2_CTRL_TYPE_INTEGER,
667 },
668 /* --- audio --- */
669 {
670 .id = V4L2_CID_AUDIO_MUTE,
671 .name = "Mute",
672 .minimum = 0,
673 .maximum = 1,
674 .type = V4L2_CTRL_TYPE_BOOLEAN,
675 },{
676 .id = V4L2_CID_AUDIO_VOLUME,
677 .name = "Volume",
678 .minimum = 0,
679 .maximum = 65535,
680 .step = 65535/100,
681 .default_value = 65535,
682 .type = V4L2_CTRL_TYPE_INTEGER,
683 },{
684 .id = V4L2_CID_AUDIO_BALANCE,
685 .name = "Balance",
686 .minimum = 0,
687 .maximum = 65535,
688 .step = 65535/100,
689 .default_value = 32768,
690 .type = V4L2_CTRL_TYPE_INTEGER,
691 },{
692 .id = V4L2_CID_AUDIO_BASS,
693 .name = "Bass",
694 .minimum = 0,
695 .maximum = 65535,
696 .step = 65535/100,
697 .default_value = 32768,
698 .type = V4L2_CTRL_TYPE_INTEGER,
699 },{
700 .id = V4L2_CID_AUDIO_TREBLE,
701 .name = "Treble",
702 .minimum = 0,
703 .maximum = 65535,
704 .step = 65535/100,
705 .default_value = 32768,
706 .type = V4L2_CTRL_TYPE_INTEGER,
707 },
708 /* --- private --- */
709 {
710 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
711 .name = "chroma agc",
712 .minimum = 0,
713 .maximum = 1,
714 .type = V4L2_CTRL_TYPE_BOOLEAN,
715 },{
716 .id = V4L2_CID_PRIVATE_COMBFILTER,
717 .name = "combfilter",
718 .minimum = 0,
719 .maximum = 1,
720 .type = V4L2_CTRL_TYPE_BOOLEAN,
721 },{
722 .id = V4L2_CID_PRIVATE_AUTOMUTE,
723 .name = "automute",
724 .minimum = 0,
725 .maximum = 1,
726 .type = V4L2_CTRL_TYPE_BOOLEAN,
727 },{
728 .id = V4L2_CID_PRIVATE_LUMAFILTER,
729 .name = "luma decimation filter",
730 .minimum = 0,
731 .maximum = 1,
732 .type = V4L2_CTRL_TYPE_BOOLEAN,
733 },{
734 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
735 .name = "agc crush",
736 .minimum = 0,
737 .maximum = 1,
738 .type = V4L2_CTRL_TYPE_BOOLEAN,
739 },{
740 .id = V4L2_CID_PRIVATE_VCR_HACK,
741 .name = "vcr hack",
742 .minimum = 0,
743 .maximum = 1,
744 .type = V4L2_CTRL_TYPE_BOOLEAN,
745 },{
746 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
747 .name = "whitecrush upper",
748 .minimum = 0,
749 .maximum = 255,
750 .step = 1,
751 .default_value = 0xCF,
752 .type = V4L2_CTRL_TYPE_INTEGER,
753 },{
754 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
755 .name = "whitecrush lower",
756 .minimum = 0,
757 .maximum = 255,
758 .step = 1,
759 .default_value = 0x7F,
760 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700761 },{
762 .id = V4L2_CID_PRIVATE_UV_RATIO,
763 .name = "uv ratio",
764 .minimum = 0,
765 .maximum = 100,
766 .step = 1,
767 .default_value = 50,
768 .type = V4L2_CTRL_TYPE_INTEGER,
769 },{
770 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
771 .name = "full luma range",
772 .minimum = 0,
773 .maximum = 1,
774 .type = V4L2_CTRL_TYPE_BOOLEAN,
775 },{
776 .id = V4L2_CID_PRIVATE_CORING,
777 .name = "coring",
778 .minimum = 0,
779 .maximum = 3,
780 .step = 1,
781 .default_value = 0,
782 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700785
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787};
788static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
789
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -0300790static const struct v4l2_queryctrl *ctrl_by_id(int id)
791{
792 int i;
793
794 for (i = 0; i < BTTV_CTLS; i++)
795 if (bttv_ctls[i].id == id)
796 return bttv_ctls+i;
797 return NULL;
798}
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800/* ----------------------------------------------------------------------- */
801/* resource management */
802
Michael Schimeke5bd0262007-01-18 16:17:39 -0300803/*
804 RESOURCE_ allocated by freed by
805
806 VIDEO_READ bttv_read 1) bttv_read 2)
807
808 VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
809 VIDIOC_QBUF 1) bttv_release
810 VIDIOCMCAPTURE 1)
811
812 OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
813 VIDIOC_OVERLAY on VIDIOC_OVERLAY off
814 3) bttv_release
815
816 VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
817 VIDIOC_QBUF 1) bttv_release
818 bttv_read, bttv_poll 1) 4)
819
820 1) The resource must be allocated when we enter buffer prepare functions
821 and remain allocated while buffers are in the DMA queue.
822 2) This is a single frame read.
823 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
824 RESOURCE_OVERLAY is allocated.
825 4) This is a continuous read, implies VIDIOC_STREAMON.
826
827 Note this driver permits video input and standard changes regardless if
828 resources are allocated.
829*/
830
831#define VBI_RESOURCES (RESOURCE_VBI)
832#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
833 RESOURCE_VIDEO_STREAM | \
834 RESOURCE_OVERLAY)
835
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836static
837int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
838{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300839 int xbits; /* mutual exclusive resources */
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (fh->resources & bit)
842 /* have it already allocated */
843 return 1;
844
Michael Schimeke5bd0262007-01-18 16:17:39 -0300845 xbits = bit;
846 if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
847 xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 /* is it free? */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300850 mutex_lock(&btv->lock);
851 if (btv->resources & xbits) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 /* no, someone else uses it */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300853 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300855
856 if ((bit & VIDEO_RESOURCES)
857 && 0 == (btv->resources & VIDEO_RESOURCES)) {
858 /* Do crop - use current, don't - use default parameters. */
859 __s32 top = btv->crop[!!fh->do_crop].rect.top;
860
861 if (btv->vbi_end > top)
862 goto fail;
863
864 /* We cannot capture the same line as video and VBI data.
865 Claim scan lines crop[].rect.top to bottom. */
866 btv->crop_start = top;
867 } else if (bit & VBI_RESOURCES) {
868 __s32 end = fh->vbi_fmt.end;
869
870 if (end > btv->crop_start)
871 goto fail;
872
873 /* Claim scan lines above fh->vbi_fmt.end. */
874 btv->vbi_end = end;
875 }
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /* it's free, grab it */
878 fh->resources |= bit;
879 btv->resources |= bit;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300880 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 return 1;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300882
883 fail:
884 mutex_unlock(&btv->lock);
885 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886}
887
888static
889int check_btres(struct bttv_fh *fh, int bit)
890{
891 return (fh->resources & bit);
892}
893
894static
895int locked_btres(struct bttv *btv, int bit)
896{
897 return (btv->resources & bit);
898}
899
Michael Schimeke5bd0262007-01-18 16:17:39 -0300900/* Call with btv->lock down. */
901static void
902disclaim_vbi_lines(struct bttv *btv)
903{
904 btv->vbi_end = 0;
905}
906
907/* Call with btv->lock down. */
908static void
909disclaim_video_lines(struct bttv *btv)
910{
911 const struct bttv_tvnorm *tvnorm;
912 u8 crop;
913
914 tvnorm = &bttv_tvnorms[btv->tvnorm];
915 btv->crop_start = tvnorm->cropcap.bounds.top
916 + tvnorm->cropcap.bounds.height;
917
918 /* VBI capturing ends at VDELAY, start of video capturing, no
919 matter how many lines the VBI RISC program expects. When video
920 capturing is off, it shall no longer "preempt" VBI capturing,
921 so we set VDELAY to maximum. */
922 crop = btread(BT848_E_CROP) | 0xc0;
923 btwrite(crop, BT848_E_CROP);
924 btwrite(0xfe, BT848_E_VDELAY_LO);
925 btwrite(crop, BT848_O_CROP);
926 btwrite(0xfe, BT848_O_VDELAY_LO);
927}
928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929static
930void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
931{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if ((fh->resources & bits) != bits) {
933 /* trying to free ressources not allocated by us ... */
934 printk("bttv: BUG! (btres)\n");
935 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300936 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 fh->resources &= ~bits;
938 btv->resources &= ~bits;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300939
940 bits = btv->resources;
941
942 if (0 == (bits & VIDEO_RESOURCES))
943 disclaim_video_lines(btv);
944
945 if (0 == (bits & VBI_RESOURCES))
946 disclaim_vbi_lines(btv);
947
948 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949}
950
951/* ----------------------------------------------------------------------- */
952/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
953
954/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
955 PLL_X = Reference pre-divider (0=1, 1=2)
956 PLL_C = Post divider (0=6, 1=4)
957 PLL_I = Integer input
958 PLL_F = Fractional input
959
960 F_input = 28.636363 MHz:
961 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
962*/
963
964static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
965{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800966 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800968 /* prevent overflows */
969 fin/=4;
970 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800972 fout*=12;
973 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800975 fout=(fout%fin)*256;
976 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800978 fout=(fout%fin)*256;
979 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800981 btwrite(fl, BT848_PLL_F_LO);
982 btwrite(fh, BT848_PLL_F_HI);
983 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984}
985
986static void set_pll(struct bttv *btv)
987{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800988 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800990 if (!btv->pll.pll_crystal)
991 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
994 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800995 return;
996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800998 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
999 /* no PLL needed */
1000 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001001 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001002 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001003 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001004 btwrite(0x00,BT848_TGCTRL);
1005 btwrite(0x00,BT848_PLL_XCI);
1006 btv->pll.pll_current = 0;
1007 return;
1008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001010 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001011 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
1013
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001014 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001016 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 msleep(10);
1018
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001019 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001021 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001022 btwrite(0x08,BT848_TGCTRL);
1023 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001024 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001025 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001026 }
1027 }
1028 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001029 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001030 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031}
1032
1033/* used to switch between the bt848's analog/digital video capture modes */
1034static void bt848A_set_timing(struct bttv *btv)
1035{
1036 int i, len;
1037 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
1038 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
1039
1040 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
1041 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
1042 btv->c.nr,table_idx);
1043
1044 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001045 btwrite(0x00, BT848_TGCTRL);
1046 btwrite(0x02, BT848_TGCTRL);
1047 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
1049 len=SRAM_Table[table_idx][0];
1050 for(i = 1; i <= len; i++)
1051 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
1052 btv->pll.pll_ofreq = 27000000;
1053
1054 set_pll(btv);
1055 btwrite(0x11, BT848_TGCTRL);
1056 btwrite(0x41, BT848_DVSIF);
1057 } else {
1058 btv->pll.pll_ofreq = fsc;
1059 set_pll(btv);
1060 btwrite(0x0, BT848_DVSIF);
1061 }
1062}
1063
1064/* ----------------------------------------------------------------------- */
1065
1066static void bt848_bright(struct bttv *btv, int bright)
1067{
1068 int value;
1069
1070 // printk("bttv: set bright: %d\n",bright); // DEBUG
1071 btv->bright = bright;
1072
1073 /* We want -128 to 127 we get 0-65535 */
1074 value = (bright >> 8) - 128;
1075 btwrite(value & 0xff, BT848_BRIGHT);
1076}
1077
1078static void bt848_hue(struct bttv *btv, int hue)
1079{
1080 int value;
1081
1082 btv->hue = hue;
1083
1084 /* -128 to 127 */
1085 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001086 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087}
1088
1089static void bt848_contrast(struct bttv *btv, int cont)
1090{
1091 int value,hibit;
1092
1093 btv->contrast = cont;
1094
1095 /* 0-511 */
1096 value = (cont >> 7);
1097 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001098 btwrite(value & 0xff, BT848_CONTRAST_LO);
1099 btaor(hibit, ~4, BT848_E_CONTROL);
1100 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101}
1102
1103static void bt848_sat(struct bttv *btv, int color)
1104{
1105 int val_u,val_v,hibits;
1106
1107 btv->saturation = color;
1108
1109 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001110 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
1111 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001112 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001114 btwrite(val_u & 0xff, BT848_SAT_U_LO);
1115 btwrite(val_v & 0xff, BT848_SAT_V_LO);
1116 btaor(hibits, ~3, BT848_E_CONTROL);
1117 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118}
1119
1120/* ----------------------------------------------------------------------- */
1121
1122static int
1123video_mux(struct bttv *btv, unsigned int input)
1124{
1125 int mux,mask2;
1126
1127 if (input >= bttv_tvcards[btv->c.type].video_inputs)
1128 return -EINVAL;
1129
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001130 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
1132 if (mask2)
1133 gpio_inout(mask2,mask2);
1134
1135 if (input == btv->svhs) {
1136 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
1137 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
1138 } else {
1139 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
1140 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
1141 }
1142 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
1143 btaor(mux<<5, ~(3<<5), BT848_IFORM);
1144 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
1145 btv->c.nr,input,mux);
1146
1147 /* card specific hook */
1148 if(bttv_tvcards[btv->c.type].muxsel_hook)
1149 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
1150 return 0;
1151}
1152
1153static char *audio_modes[] = {
1154 "audio: tuner", "audio: radio", "audio: extern",
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001155 "audio: intern", "audio: mute"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156};
1157
1158static int
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001159audio_mux(struct bttv *btv, int input, int mute)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160{
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001161 int gpio_val, signal;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001162 struct v4l2_control ctrl;
1163 struct i2c_client *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164
1165 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
1166 bttv_tvcards[btv->c.type].gpiomask);
1167 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
1168
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001169 btv->mute = mute;
1170 btv->audio = input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001172 /* automute */
1173 mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
1174
1175 if (mute)
1176 gpio_val = bttv_tvcards[btv->c.type].gpiomute;
1177 else
1178 gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001179
1180 gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 if (bttv_gpio)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001182 bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
1183 if (in_interrupt())
1184 return 0;
1185
1186 ctrl.id = V4L2_CID_AUDIO_MUTE;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001187 ctrl.value = btv->mute;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001188 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
1189 c = btv->i2c_msp34xx_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001190 if (c) {
1191 struct v4l2_routing route;
1192
1193 /* Note: the inputs tuner/radio/extern/intern are translated
1194 to msp routings. This assumes common behavior for all msp3400
1195 based TV cards. When this assumption fails, then the
1196 specific MSP routing must be added to the card table.
1197 For now this is sufficient. */
1198 switch (input) {
1199 case TVAUDIO_INPUT_RADIO:
Hans Verkuil07151722006-04-01 18:03:23 -03001200 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1201 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001202 break;
1203 case TVAUDIO_INPUT_EXTERN:
Hans Verkuil07151722006-04-01 18:03:23 -03001204 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
1205 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001206 break;
1207 case TVAUDIO_INPUT_INTERN:
1208 /* Yes, this is the same input as for RADIO. I doubt
1209 if this is ever used. The only board with an INTERN
1210 input is the BTTV_BOARD_AVERMEDIA98. I wonder how
1211 that was tested. My guess is that the whole INTERN
1212 input does not work. */
Hans Verkuil07151722006-04-01 18:03:23 -03001213 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1214 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001215 break;
1216 case TVAUDIO_INPUT_TUNER:
1217 default:
Wade Berrier434b2522007-06-25 13:02:16 -03001218 /* This is the only card that uses TUNER2, and afaik,
1219 is the only difference between the VOODOOTV_FM
1220 and VOODOOTV_200 */
1221 if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
1222 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
1223 MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
1224 else
1225 route.input = MSP_INPUT_DEFAULT;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001226 break;
1227 }
1228 route.output = MSP_OUTPUT_DEFAULT;
1229 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1230 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001231 c = btv->i2c_tvaudio_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001232 if (c) {
1233 struct v4l2_routing route;
1234
1235 route.input = input;
1236 route.output = 0;
1237 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 return 0;
1240}
1241
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001242static inline int
1243audio_mute(struct bttv *btv, int mute)
1244{
1245 return audio_mux(btv, btv->audio, mute);
1246}
1247
1248static inline int
1249audio_input(struct bttv *btv, int input)
1250{
1251 return audio_mux(btv, input, btv->mute);
1252}
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254static void
Michael Schimeke5bd0262007-01-18 16:17:39 -03001255bttv_crop_calc_limits(struct bttv_crop *c)
1256{
1257 /* Scale factor min. 1:1, max. 16:1. Min. image size
1258 48 x 32. Scaled width must be a multiple of 4. */
1259
1260 if (1) {
1261 /* For bug compatibility with VIDIOCGCAP and image
1262 size checks in earlier driver versions. */
1263 c->min_scaled_width = 48;
1264 c->min_scaled_height = 32;
1265 } else {
1266 c->min_scaled_width =
1267 (max(48, c->rect.width >> 4) + 3) & ~3;
1268 c->min_scaled_height =
1269 max(32, c->rect.height >> 4);
1270 }
1271
1272 c->max_scaled_width = c->rect.width & ~3;
1273 c->max_scaled_height = c->rect.height;
1274}
1275
1276static void
1277bttv_crop_reset(struct bttv_crop *c, int norm)
1278{
1279 c->rect = bttv_tvnorms[norm].cropcap.defrect;
1280 bttv_crop_calc_limits(c);
1281}
1282
1283/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284static int
1285set_tvnorm(struct bttv *btv, unsigned int norm)
1286{
1287 const struct bttv_tvnorm *tvnorm;
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001288 v4l2_std_id id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 if (norm < 0 || norm >= BTTV_TVNORMS)
1291 return -EINVAL;
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 tvnorm = &bttv_tvnorms[norm];
1294
Michael Schimeke5bd0262007-01-18 16:17:39 -03001295 if (btv->tvnorm < 0 ||
1296 btv->tvnorm >= BTTV_TVNORMS ||
1297 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
1298 &tvnorm->cropcap,
1299 sizeof (tvnorm->cropcap))) {
1300 bttv_crop_reset(&btv->crop[0], norm);
1301 btv->crop[1] = btv->crop[0]; /* current = default */
1302
1303 if (0 == (btv->resources & VIDEO_RESOURCES)) {
1304 btv->crop_start = tvnorm->cropcap.bounds.top
1305 + tvnorm->cropcap.bounds.height;
1306 }
1307 }
1308
1309 btv->tvnorm = norm;
1310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 btwrite(tvnorm->adelay, BT848_ADELAY);
1312 btwrite(tvnorm->bdelay, BT848_BDELAY);
1313 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1314 BT848_IFORM);
1315 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1316 btwrite(1, BT848_VBI_PACK_DEL);
1317 bt848A_set_timing(btv);
1318
1319 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001320 case BTTV_BOARD_VOODOOTV_FM:
Wade Berrier434b2522007-06-25 13:02:16 -03001321 case BTTV_BOARD_VOODOOTV_200:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 bttv_tda9880_setnorm(btv,norm);
1323 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 }
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001325 id = tvnorm->v4l2_id;
1326 bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
1327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 return 0;
1329}
1330
Michael Schimeke5bd0262007-01-18 16:17:39 -03001331/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332static void
Trent Piepho333408f2007-07-03 15:08:10 -03001333set_input(struct bttv *btv, unsigned int input, unsigned int norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334{
1335 unsigned long flags;
1336
1337 btv->input = input;
1338 if (irq_iswitch) {
1339 spin_lock_irqsave(&btv->s_lock,flags);
1340 if (btv->curr.frame_irq) {
1341 /* active capture -> delayed input switch */
1342 btv->new_input = input;
1343 } else {
1344 video_mux(btv,input);
1345 }
1346 spin_unlock_irqrestore(&btv->s_lock,flags);
1347 } else {
1348 video_mux(btv,input);
1349 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001350 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1351 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Trent Piepho333408f2007-07-03 15:08:10 -03001352 set_tvnorm(btv, norm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353}
1354
1355static void init_irqreg(struct bttv *btv)
1356{
1357 /* clear status */
1358 btwrite(0xfffffUL, BT848_INT_STAT);
1359
1360 if (bttv_tvcards[btv->c.type].no_video) {
1361 /* i2c only */
1362 btwrite(BT848_INT_I2CDONE,
1363 BT848_INT_MASK);
1364 } else {
1365 /* full video */
1366 btwrite((btv->triton1) |
1367 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1368 BT848_INT_SCERR |
1369 (fdsr ? BT848_INT_FDSR : 0) |
1370 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1371 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1372 BT848_INT_I2CDONE,
1373 BT848_INT_MASK);
1374 }
1375}
1376
1377static void init_bt848(struct bttv *btv)
1378{
1379 int val;
1380
1381 if (bttv_tvcards[btv->c.type].no_video) {
1382 /* very basic init only */
1383 init_irqreg(btv);
1384 return;
1385 }
1386
1387 btwrite(0x00, BT848_CAP_CTL);
1388 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1389 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1390
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001391 /* set planar and packed mode trigger points and */
1392 /* set rising edge of inverted GPINTR pin as irq trigger */
1393 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1394 BT848_GPIO_DMA_CTL_PLTP1_16|
1395 BT848_GPIO_DMA_CTL_PLTP23_16|
1396 BT848_GPIO_DMA_CTL_GPINTC|
1397 BT848_GPIO_DMA_CTL_GPINTI,
1398 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
1400 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001401 btwrite(val, BT848_E_SCLOOP);
1402 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001404 btwrite(0x20, BT848_E_VSCALE_HI);
1405 btwrite(0x20, BT848_O_VSCALE_HI);
1406 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 BT848_ADC);
1408
1409 btwrite(whitecrush_upper, BT848_WC_UP);
1410 btwrite(whitecrush_lower, BT848_WC_DOWN);
1411
1412 if (btv->opt_lumafilter) {
1413 btwrite(0, BT848_E_CONTROL);
1414 btwrite(0, BT848_O_CONTROL);
1415 } else {
1416 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1417 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1418 }
1419
1420 bt848_bright(btv, btv->bright);
1421 bt848_hue(btv, btv->hue);
1422 bt848_contrast(btv, btv->contrast);
1423 bt848_sat(btv, btv->saturation);
1424
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001425 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 init_irqreg(btv);
1427}
1428
1429static void bttv_reinit_bt848(struct bttv *btv)
1430{
1431 unsigned long flags;
1432
1433 if (bttv_verbose)
1434 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1435 spin_lock_irqsave(&btv->s_lock,flags);
1436 btv->errors=0;
1437 bttv_set_dma(btv,0);
1438 spin_unlock_irqrestore(&btv->s_lock,flags);
1439
1440 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001441 btv->pll.pll_current = -1;
Trent Piepho333408f2007-07-03 15:08:10 -03001442 set_input(btv, btv->input, btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443}
1444
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445/* ----------------------------------------------------------------------- */
1446
1447void bttv_gpio_tracking(struct bttv *btv, char *comment)
1448{
1449 unsigned int outbits, data;
1450 outbits = btread(BT848_GPIO_OUT_EN);
1451 data = btread(BT848_GPIO_DATA);
1452 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1453 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1454}
1455
1456static void bttv_field_count(struct bttv *btv)
1457{
1458 int need_count = 0;
1459
1460 if (btv->users)
1461 need_count++;
1462
1463 if (need_count) {
1464 /* start field counter */
1465 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1466 } else {
1467 /* stop field counter */
1468 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1469 btv->field_count = 0;
1470 }
1471}
1472
1473static const struct bttv_format*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474format_by_fourcc(int fourcc)
1475{
1476 unsigned int i;
1477
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001478 for (i = 0; i < FORMATS; i++) {
1479 if (-1 == formats[i].fourcc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 continue;
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001481 if (formats[i].fourcc == fourcc)
1482 return formats+i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 }
1484 return NULL;
1485}
1486
1487/* ----------------------------------------------------------------------- */
1488/* misc helpers */
1489
1490static int
1491bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1492 struct bttv_buffer *new)
1493{
1494 struct bttv_buffer *old;
1495 unsigned long flags;
1496 int retval = 0;
1497
1498 dprintk("switch_overlay: enter [new=%p]\n",new);
1499 if (new)
Brandon Philips0fc06862007-11-06 20:02:36 -03001500 new->vb.state = VIDEOBUF_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 spin_lock_irqsave(&btv->s_lock,flags);
1502 old = btv->screen;
1503 btv->screen = new;
1504 btv->loop_irq |= 1;
1505 bttv_set_dma(btv, 0x03);
1506 spin_unlock_irqrestore(&btv->s_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 if (NULL != old) {
1508 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001509 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 kfree(old);
1511 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03001512 if (NULL == new)
1513 free_btres(btv,fh,RESOURCE_OVERLAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 dprintk("switch_overlay: done\n");
1515 return retval;
1516}
1517
1518/* ----------------------------------------------------------------------- */
1519/* video4linux (1) interface */
1520
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001521static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1522 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001523 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 unsigned int width, unsigned int height,
1525 enum v4l2_field field)
1526{
Michael Schimeke5bd0262007-01-18 16:17:39 -03001527 struct bttv_fh *fh = q->priv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 int redo_dma_risc = 0;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001529 struct bttv_crop c;
1530 int norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 int rc;
1532
1533 /* check settings */
1534 if (NULL == fmt)
1535 return -EINVAL;
1536 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1537 width = RAW_BPL;
1538 height = RAW_LINES*2;
1539 if (width*height > buf->vb.bsize)
1540 return -EINVAL;
1541 buf->vb.size = buf->vb.bsize;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001542
1543 /* Make sure tvnorm and vbi_end remain consistent
1544 until we're done. */
1545 mutex_lock(&btv->lock);
1546
1547 norm = btv->tvnorm;
1548
1549 /* In this mode capturing always starts at defrect.top
1550 (default VDELAY), ignoring cropping parameters. */
1551 if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
1552 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001554 }
1555
1556 mutex_unlock(&btv->lock);
1557
1558 c.rect = bttv_tvnorms[norm].cropcap.defrect;
1559 } else {
1560 mutex_lock(&btv->lock);
1561
1562 norm = btv->tvnorm;
1563 c = btv->crop[!!fh->do_crop];
1564
1565 mutex_unlock(&btv->lock);
1566
1567 if (width < c.min_scaled_width ||
1568 width > c.max_scaled_width ||
1569 height < c.min_scaled_height)
1570 return -EINVAL;
1571
1572 switch (field) {
1573 case V4L2_FIELD_TOP:
1574 case V4L2_FIELD_BOTTOM:
1575 case V4L2_FIELD_ALTERNATE:
1576 /* btv->crop counts frame lines. Max. scale
1577 factor is 16:1 for frames, 8:1 for fields. */
1578 if (height * 2 > c.max_scaled_height)
1579 return -EINVAL;
1580 break;
1581
1582 default:
1583 if (height > c.max_scaled_height)
1584 return -EINVAL;
1585 break;
1586 }
1587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 buf->vb.size = (width * height * fmt->depth) >> 3;
1589 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1590 return -EINVAL;
1591 }
1592
1593 /* alloc + fill struct bttv_buffer (if changed) */
1594 if (buf->vb.width != width || buf->vb.height != height ||
1595 buf->vb.field != field ||
Michael Schimeke5bd0262007-01-18 16:17:39 -03001596 buf->tvnorm != norm || buf->fmt != fmt ||
1597 buf->crop.top != c.rect.top ||
1598 buf->crop.left != c.rect.left ||
1599 buf->crop.width != c.rect.width ||
1600 buf->crop.height != c.rect.height) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 buf->vb.width = width;
1602 buf->vb.height = height;
1603 buf->vb.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001604 buf->tvnorm = norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 buf->fmt = fmt;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001606 buf->crop = c.rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 redo_dma_risc = 1;
1608 }
1609
1610 /* alloc risc memory */
Brandon Philips0fc06862007-11-06 20:02:36 -03001611 if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001613 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 goto fail;
1615 }
1616
1617 if (redo_dma_risc)
1618 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1619 goto fail;
1620
Brandon Philips0fc06862007-11-06 20:02:36 -03001621 buf->vb.state = VIDEOBUF_PREPARED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 return 0;
1623
1624 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001625 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 return rc;
1627}
1628
1629static int
1630buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1631{
1632 struct bttv_fh *fh = q->priv_data;
1633
1634 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1635 if (0 == *count)
1636 *count = gbuffers;
1637 while (*size * *count > gbuffers * gbufsize)
1638 (*count)--;
1639 return 0;
1640}
1641
1642static int
1643buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1644 enum v4l2_field field)
1645{
1646 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1647 struct bttv_fh *fh = q->priv_data;
1648
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001649 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 fh->width, fh->height, field);
1651}
1652
1653static void
1654buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1655{
1656 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1657 struct bttv_fh *fh = q->priv_data;
1658 struct bttv *btv = fh->btv;
1659
Brandon Philips0fc06862007-11-06 20:02:36 -03001660 buf->vb.state = VIDEOBUF_QUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 list_add_tail(&buf->vb.queue,&btv->capture);
1662 if (!btv->curr.frame_irq) {
1663 btv->loop_irq |= 1;
1664 bttv_set_dma(btv, 0x03);
1665 }
1666}
1667
1668static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1669{
1670 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1671 struct bttv_fh *fh = q->priv_data;
1672
Michael Schimekfeaba7a2007-01-26 08:30:05 -03001673 bttv_dma_free(q,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674}
1675
1676static struct videobuf_queue_ops bttv_video_qops = {
1677 .buf_setup = buffer_setup,
1678 .buf_prepare = buffer_prepare,
1679 .buf_queue = buffer_queue,
1680 .buf_release = buffer_release,
1681};
1682
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001683static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001685 struct bttv_fh *fh = priv;
1686 struct bttv *btv = fh->btv;
1687 unsigned int i;
1688 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001690 err = v4l2_prio_check(&btv->prio, &fh->prio);
1691 if (0 != err)
1692 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001694 for (i = 0; i < BTTV_TVNORMS; i++)
1695 if (*id & bttv_tvnorms[i].v4l2_id)
1696 break;
1697 if (i == BTTV_TVNORMS)
1698 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001700 mutex_lock(&btv->lock);
1701 set_tvnorm(btv, i);
1702 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001704 return 0;
1705}
1706
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001707static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001708{
1709 struct bttv_fh *fh = f;
1710 struct bttv *btv = fh->btv;
1711
1712 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1713 *id = V4L2_STD_625_50;
1714 else
1715 *id = V4L2_STD_525_60;
1716 return 0;
1717}
1718
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001719static int bttv_enum_input(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001720 struct v4l2_input *i)
1721{
1722 struct bttv_fh *fh = priv;
1723 struct bttv *btv = fh->btv;
1724 unsigned int n;
1725
1726 n = i->index;
1727
1728 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1729 return -EINVAL;
1730
1731 memset(i, 0, sizeof(*i));
1732
1733 i->index = n;
1734 i->type = V4L2_INPUT_TYPE_CAMERA;
1735 i->audioset = 1;
1736
1737 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1738 sprintf(i->name, "Television");
1739 i->type = V4L2_INPUT_TYPE_TUNER;
1740 i->tuner = 0;
1741 } else if (i->index == btv->svhs) {
1742 sprintf(i->name, "S-Video");
1743 } else {
1744 sprintf(i->name, "Composite%d", i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 }
1746
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001747 if (i->index == btv->input) {
1748 __u32 dstatus = btread(BT848_DSTATUS);
1749 if (0 == (dstatus & BT848_DSTATUS_PRES))
1750 i->status |= V4L2_IN_ST_NO_SIGNAL;
1751 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1752 i->status |= V4L2_IN_ST_NO_H_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 }
1754
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001755 for (n = 0; n < BTTV_TVNORMS; n++)
1756 i->std |= bttv_tvnorms[n].v4l2_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001758 return 0;
1759}
Nickolay V. Shmyrev4b9b9362006-08-25 16:53:04 -03001760
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001761static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001762{
1763 struct bttv_fh *fh = priv;
1764 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001766 *i = btv->input;
1767 return 0;
1768}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001770static int bttv_s_input(struct file *file, void *priv, unsigned int i)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001771{
1772 struct bttv_fh *fh = priv;
1773 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001775 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001777 err = v4l2_prio_check(&btv->prio, &fh->prio);
1778 if (0 != err)
1779 return err;
1780
1781 if (i > bttv_tvcards[btv->c.type].video_inputs)
1782 return -EINVAL;
1783
1784 mutex_lock(&btv->lock);
1785 set_input(btv, i, btv->tvnorm);
1786 mutex_unlock(&btv->lock);
1787 return 0;
1788}
1789
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001790static int bttv_s_tuner(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001791 struct v4l2_tuner *t)
1792{
1793 struct bttv_fh *fh = priv;
1794 struct bttv *btv = fh->btv;
1795 int err;
1796
1797 err = v4l2_prio_check(&btv->prio, &fh->prio);
1798 if (0 != err)
1799 return err;
1800
1801 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1802 return -EINVAL;
1803
1804 if (0 != t->index)
1805 return -EINVAL;
1806
1807 mutex_lock(&btv->lock);
1808 bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
1809
1810 if (btv->audio_mode_gpio)
1811 btv->audio_mode_gpio(btv, t, 1);
1812
1813 mutex_unlock(&btv->lock);
1814
1815 return 0;
1816}
1817
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001818static int bttv_g_frequency(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001819 struct v4l2_frequency *f)
1820{
1821 struct bttv_fh *fh = priv;
1822 struct bttv *btv = fh->btv;
1823 int err;
1824
1825 err = v4l2_prio_check(&btv->prio, &fh->prio);
1826 if (0 != err)
1827 return err;
1828
1829 f->type = V4L2_TUNER_ANALOG_TV;
1830 f->frequency = btv->freq;
1831
1832 return 0;
1833}
1834
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001835static int bttv_s_frequency(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001836 struct v4l2_frequency *f)
1837{
1838 struct bttv_fh *fh = priv;
1839 struct bttv *btv = fh->btv;
1840 int err;
1841
1842 err = v4l2_prio_check(&btv->prio, &fh->prio);
1843 if (0 != err)
1844 return err;
1845
1846 if (unlikely(f->tuner != 0))
1847 return -EINVAL;
1848 if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
1849 return -EINVAL;
1850 mutex_lock(&btv->lock);
1851 btv->freq = f->frequency;
1852 bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f);
1853 if (btv->has_matchbox && btv->radio_user)
1854 tea5757_set_freq(btv, btv->freq);
1855 mutex_unlock(&btv->lock);
1856 return 0;
1857}
1858
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001859static int bttv_log_status(struct file *file, void *f)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001860{
1861 struct bttv_fh *fh = f;
1862 struct bttv *btv = fh->btv;
1863
1864 printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n",
1865 btv->c.nr, btv->c.nr);
1866 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
1867 printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n",
1868 btv->c.nr, btv->c.nr);
1869 return 0;
1870}
1871
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001872static int bttv_g_ctrl(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001873 struct v4l2_control *c)
1874{
1875 struct bttv_fh *fh = priv;
1876 struct bttv *btv = fh->btv;
1877
1878 switch (c->id) {
1879 case V4L2_CID_BRIGHTNESS:
1880 c->value = btv->bright;
1881 break;
1882 case V4L2_CID_HUE:
1883 c->value = btv->hue;
1884 break;
1885 case V4L2_CID_CONTRAST:
1886 c->value = btv->contrast;
1887 break;
1888 case V4L2_CID_SATURATION:
1889 c->value = btv->saturation;
1890 break;
1891
1892 case V4L2_CID_AUDIO_MUTE:
1893 case V4L2_CID_AUDIO_VOLUME:
1894 case V4L2_CID_AUDIO_BALANCE:
1895 case V4L2_CID_AUDIO_BASS:
1896 case V4L2_CID_AUDIO_TREBLE:
1897 bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c);
1898 break;
1899
1900 case V4L2_CID_PRIVATE_CHROMA_AGC:
1901 c->value = btv->opt_chroma_agc;
1902 break;
1903 case V4L2_CID_PRIVATE_COMBFILTER:
1904 c->value = btv->opt_combfilter;
1905 break;
1906 case V4L2_CID_PRIVATE_LUMAFILTER:
1907 c->value = btv->opt_lumafilter;
1908 break;
1909 case V4L2_CID_PRIVATE_AUTOMUTE:
1910 c->value = btv->opt_automute;
1911 break;
1912 case V4L2_CID_PRIVATE_AGC_CRUSH:
1913 c->value = btv->opt_adc_crush;
1914 break;
1915 case V4L2_CID_PRIVATE_VCR_HACK:
1916 c->value = btv->opt_vcr_hack;
1917 break;
1918 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1919 c->value = btv->opt_whitecrush_upper;
1920 break;
1921 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1922 c->value = btv->opt_whitecrush_lower;
1923 break;
1924 case V4L2_CID_PRIVATE_UV_RATIO:
1925 c->value = btv->opt_uv_ratio;
1926 break;
1927 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1928 c->value = btv->opt_full_luma_range;
1929 break;
1930 case V4L2_CID_PRIVATE_CORING:
1931 c->value = btv->opt_coring;
1932 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 default:
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001934 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 }
1936 return 0;
1937}
1938
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03001939static int bttv_s_ctrl(struct file *file, void *f,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03001940 struct v4l2_control *c)
1941{
1942 int err;
1943 int val;
1944 struct bttv_fh *fh = f;
1945 struct bttv *btv = fh->btv;
1946
1947 err = v4l2_prio_check(&btv->prio, &fh->prio);
1948 if (0 != err)
1949 return err;
1950
1951 switch (c->id) {
1952 case V4L2_CID_BRIGHTNESS:
1953 bt848_bright(btv, c->value);
1954 break;
1955 case V4L2_CID_HUE:
1956 bt848_hue(btv, c->value);
1957 break;
1958 case V4L2_CID_CONTRAST:
1959 bt848_contrast(btv, c->value);
1960 break;
1961 case V4L2_CID_SATURATION:
1962 bt848_sat(btv, c->value);
1963 break;
1964 case V4L2_CID_AUDIO_MUTE:
1965 audio_mute(btv, c->value);
1966 /* fall through */
1967 case V4L2_CID_AUDIO_VOLUME:
1968 if (btv->volume_gpio)
1969 btv->volume_gpio(btv, c->value);
1970
1971 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
1972 break;
1973 case V4L2_CID_AUDIO_BALANCE:
1974 case V4L2_CID_AUDIO_BASS:
1975 case V4L2_CID_AUDIO_TREBLE:
1976 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c);
1977 break;
1978
1979 case V4L2_CID_PRIVATE_CHROMA_AGC:
1980 btv->opt_chroma_agc = c->value;
1981 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1982 btwrite(val, BT848_E_SCLOOP);
1983 btwrite(val, BT848_O_SCLOOP);
1984 break;
1985 case V4L2_CID_PRIVATE_COMBFILTER:
1986 btv->opt_combfilter = c->value;
1987 break;
1988 case V4L2_CID_PRIVATE_LUMAFILTER:
1989 btv->opt_lumafilter = c->value;
1990 if (btv->opt_lumafilter) {
1991 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1992 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1993 } else {
1994 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1995 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1996 }
1997 break;
1998 case V4L2_CID_PRIVATE_AUTOMUTE:
1999 btv->opt_automute = c->value;
2000 break;
2001 case V4L2_CID_PRIVATE_AGC_CRUSH:
2002 btv->opt_adc_crush = c->value;
2003 btwrite(BT848_ADC_RESERVED |
2004 (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
2005 BT848_ADC);
2006 break;
2007 case V4L2_CID_PRIVATE_VCR_HACK:
2008 btv->opt_vcr_hack = c->value;
2009 break;
2010 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
2011 btv->opt_whitecrush_upper = c->value;
2012 btwrite(c->value, BT848_WC_UP);
2013 break;
2014 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
2015 btv->opt_whitecrush_lower = c->value;
2016 btwrite(c->value, BT848_WC_DOWN);
2017 break;
2018 case V4L2_CID_PRIVATE_UV_RATIO:
2019 btv->opt_uv_ratio = c->value;
2020 bt848_sat(btv, btv->saturation);
2021 break;
2022 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
2023 btv->opt_full_luma_range = c->value;
2024 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
2025 break;
2026 case V4L2_CID_PRIVATE_CORING:
2027 btv->opt_coring = c->value;
2028 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
2029 break;
2030 default:
2031 return -EINVAL;
2032 }
2033 return 0;
2034}
2035
2036#ifdef CONFIG_VIDEO_ADV_DEBUG
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002037static int bttv_g_register(struct file *file, void *f,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002038 struct v4l2_register *reg)
2039{
2040 struct bttv_fh *fh = f;
2041 struct bttv *btv = fh->btv;
2042
2043 if (!capable(CAP_SYS_ADMIN))
2044 return -EPERM;
2045
2046 if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
2047 return -EINVAL;
2048
2049 /* bt848 has a 12-bit register space */
2050 reg->reg &= 0xfff;
2051 reg->val = btread(reg->reg);
2052
2053 return 0;
2054}
2055
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002056static int bttv_s_register(struct file *file, void *f,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002057 struct v4l2_register *reg)
2058{
2059 struct bttv_fh *fh = f;
2060 struct bttv *btv = fh->btv;
2061
2062 if (!capable(CAP_SYS_ADMIN))
2063 return -EPERM;
2064
2065 if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
2066 return -EINVAL;
2067
2068 /* bt848 has a 12-bit register space */
2069 reg->reg &= 0xfff;
2070 btwrite(reg->val, reg->reg);
2071
2072 return 0;
2073}
2074#endif
2075
Michael Schimeke5bd0262007-01-18 16:17:39 -03002076/* Given cropping boundaries b and the scaled width and height of a
2077 single field or frame, which must not exceed hardware limits, this
2078 function adjusts the cropping parameters c. */
2079static void
2080bttv_crop_adjust (struct bttv_crop * c,
2081 const struct v4l2_rect * b,
2082 __s32 width,
2083 __s32 height,
2084 enum v4l2_field field)
2085{
2086 __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
2087 __s32 max_left;
2088 __s32 max_top;
2089
2090 if (width < c->min_scaled_width) {
2091 /* Max. hor. scale factor 16:1. */
2092 c->rect.width = width * 16;
2093 } else if (width > c->max_scaled_width) {
2094 /* Min. hor. scale factor 1:1. */
2095 c->rect.width = width;
2096
2097 max_left = b->left + b->width - width;
2098 max_left = min(max_left, (__s32) MAX_HDELAY);
2099 if (c->rect.left > max_left)
2100 c->rect.left = max_left;
2101 }
2102
2103 if (height < c->min_scaled_height) {
2104 /* Max. vert. scale factor 16:1, single fields 8:1. */
2105 c->rect.height = height * 16;
2106 } else if (frame_height > c->max_scaled_height) {
2107 /* Min. vert. scale factor 1:1.
2108 Top and height count field lines times two. */
2109 c->rect.height = (frame_height + 1) & ~1;
2110
2111 max_top = b->top + b->height - c->rect.height;
2112 if (c->rect.top > max_top)
2113 c->rect.top = max_top;
2114 }
2115
2116 bttv_crop_calc_limits(c);
2117}
2118
2119/* Returns an error if scaling to a frame or single field with the given
2120 width and height is not possible with the current cropping parameters
2121 and width aligned according to width_mask. If adjust_size is TRUE the
2122 function may adjust the width and/or height instead, rounding width
2123 to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
2124 also adjust the current cropping parameters to get closer to the
2125 desired image size. */
2126static int
2127limit_scaled_size (struct bttv_fh * fh,
2128 __s32 * width,
2129 __s32 * height,
2130 enum v4l2_field field,
2131 unsigned int width_mask,
2132 unsigned int width_bias,
2133 int adjust_size,
2134 int adjust_crop)
2135{
2136 struct bttv *btv = fh->btv;
2137 const struct v4l2_rect *b;
2138 struct bttv_crop *c;
2139 __s32 min_width;
2140 __s32 min_height;
2141 __s32 max_width;
2142 __s32 max_height;
2143 int rc;
2144
2145 BUG_ON((int) width_mask >= 0 ||
2146 width_bias >= (unsigned int) -width_mask);
2147
2148 /* Make sure tvnorm, vbi_end and the current cropping parameters
2149 remain consistent until we're done. */
2150 mutex_lock(&btv->lock);
2151
2152 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
2153
2154 /* Do crop - use current, don't - use default parameters. */
2155 c = &btv->crop[!!fh->do_crop];
2156
2157 if (fh->do_crop
2158 && adjust_size
2159 && adjust_crop
2160 && !locked_btres(btv, VIDEO_RESOURCES)) {
2161 min_width = 48;
2162 min_height = 32;
2163
2164 /* We cannot scale up. When the scaled image is larger
2165 than crop.rect we adjust the crop.rect as required
2166 by the V4L2 spec, hence cropcap.bounds are our limit. */
2167 max_width = min(b->width, (__s32) MAX_HACTIVE);
2168 max_height = b->height;
2169
2170 /* We cannot capture the same line as video and VBI data.
2171 Note btv->vbi_end is really a minimum, see
2172 bttv_vbi_try_fmt(). */
2173 if (btv->vbi_end > b->top) {
2174 max_height -= btv->vbi_end - b->top;
2175 rc = -EBUSY;
2176 if (min_height > max_height)
2177 goto fail;
2178 }
2179 } else {
2180 rc = -EBUSY;
2181 if (btv->vbi_end > c->rect.top)
2182 goto fail;
2183
2184 min_width = c->min_scaled_width;
2185 min_height = c->min_scaled_height;
2186 max_width = c->max_scaled_width;
2187 max_height = c->max_scaled_height;
2188
2189 adjust_crop = 0;
2190 }
2191
2192 min_width = (min_width - width_mask - 1) & width_mask;
2193 max_width = max_width & width_mask;
2194
2195 /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
2196 min_height = min_height;
2197 /* Min. scale factor is 1:1. */
2198 max_height >>= !V4L2_FIELD_HAS_BOTH(field);
2199
2200 if (adjust_size) {
2201 *width = clamp(*width, min_width, max_width);
2202 *height = clamp(*height, min_height, max_height);
2203
2204 /* Round after clamping to avoid overflow. */
2205 *width = (*width + width_bias) & width_mask;
2206
2207 if (adjust_crop) {
2208 bttv_crop_adjust(c, b, *width, *height, field);
2209
2210 if (btv->vbi_end > c->rect.top) {
2211 /* Move the crop window out of the way. */
2212 c->rect.top = btv->vbi_end;
2213 }
2214 }
2215 } else {
2216 rc = -EINVAL;
2217 if (*width < min_width ||
2218 *height < min_height ||
2219 *width > max_width ||
2220 *height > max_height ||
2221 0 != (*width & ~width_mask))
2222 goto fail;
2223 }
2224
2225 rc = 0; /* success */
2226
2227 fail:
2228 mutex_unlock(&btv->lock);
2229
2230 return rc;
2231}
2232
2233/* Returns an error if the given overlay window dimensions are not
2234 possible with the current cropping parameters. If adjust_size is
2235 TRUE the function may adjust the window width and/or height
2236 instead, however it always rounds the horizontal position and
2237 width as btcx_align() does. If adjust_crop is TRUE the function
2238 may also adjust the current cropping parameters to get closer
2239 to the desired window size. */
2240static int
2241verify_window (struct bttv_fh * fh,
2242 struct v4l2_window * win,
2243 int adjust_size,
2244 int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245{
2246 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002247 unsigned int width_mask;
2248 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
2250 if (win->w.width < 48 || win->w.height < 32)
2251 return -EINVAL;
2252 if (win->clipcount > 2048)
2253 return -EINVAL;
2254
2255 field = win->field;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257 if (V4L2_FIELD_ANY == field) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03002258 __s32 height2;
2259
2260 height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
2261 field = (win->w.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 ? V4L2_FIELD_INTERLACED
2263 : V4L2_FIELD_TOP;
2264 }
2265 switch (field) {
2266 case V4L2_FIELD_TOP:
2267 case V4L2_FIELD_BOTTOM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 case V4L2_FIELD_INTERLACED:
2269 break;
2270 default:
2271 return -EINVAL;
2272 }
2273
Michael Schimeke5bd0262007-01-18 16:17:39 -03002274 /* 4-byte alignment. */
2275 if (NULL == fh->ovfmt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002277 width_mask = ~0;
2278 switch (fh->ovfmt->depth) {
2279 case 8:
2280 case 24:
2281 width_mask = ~3;
2282 break;
2283 case 16:
2284 width_mask = ~1;
2285 break;
2286 case 32:
2287 break;
2288 default:
2289 BUG();
2290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
Michael Schimeke5bd0262007-01-18 16:17:39 -03002292 win->w.width -= win->w.left & ~width_mask;
2293 win->w.left = (win->w.left - width_mask - 1) & width_mask;
2294
2295 rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
2296 field, width_mask,
2297 /* width_bias: round down */ 0,
2298 adjust_size, adjust_crop);
2299 if (0 != rc)
2300 return rc;
2301
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 win->field = field;
2303 return 0;
2304}
2305
2306static int setup_window(struct bttv_fh *fh, struct bttv *btv,
2307 struct v4l2_window *win, int fixup)
2308{
2309 struct v4l2_clip *clips = NULL;
2310 int n,size,retval = 0;
2311
2312 if (NULL == fh->ovfmt)
2313 return -EINVAL;
2314 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
2315 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002316 retval = verify_window(fh, win,
2317 /* adjust_size */ fixup,
2318 /* adjust_crop */ fixup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 if (0 != retval)
2320 return retval;
2321
2322 /* copy clips -- luckily v4l1 + v4l2 are binary
2323 compatible here ...*/
2324 n = win->clipcount;
2325 size = sizeof(*clips)*(n+4);
2326 clips = kmalloc(size,GFP_KERNEL);
2327 if (NULL == clips)
2328 return -ENOMEM;
2329 if (n > 0) {
2330 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
2331 kfree(clips);
2332 return -EFAULT;
2333 }
2334 }
2335 /* clip against screen */
2336 if (NULL != btv->fbuf.base)
2337 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
2338 &win->w, clips, n);
2339 btcx_sort_clips(clips,n);
2340
2341 /* 4-byte alignments */
2342 switch (fh->ovfmt->depth) {
2343 case 8:
2344 case 24:
2345 btcx_align(&win->w, clips, n, 3);
2346 break;
2347 case 16:
2348 btcx_align(&win->w, clips, n, 1);
2349 break;
2350 case 32:
2351 /* no alignment fixups needed */
2352 break;
2353 default:
2354 BUG();
2355 }
2356
Ingo Molnar3593cab2006-02-07 06:49:14 -02002357 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002358 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 fh->ov.clips = clips;
2360 fh->ov.nclips = n;
2361
2362 fh->ov.w = win->w;
2363 fh->ov.field = win->field;
2364 fh->ov.setup_ok = 1;
2365 btv->init.ov.w.width = win->w.width;
2366 btv->init.ov.w.height = win->w.height;
2367 btv->init.ov.field = win->field;
2368
2369 /* update overlay if needed */
2370 retval = 0;
2371 if (check_btres(fh, RESOURCE_OVERLAY)) {
2372 struct bttv_buffer *new;
2373
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03002374 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03002375 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2377 retval = bttv_switch_overlay(btv,fh,new);
2378 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002379 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 return retval;
2381}
2382
2383/* ----------------------------------------------------------------------- */
2384
2385static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2386{
2387 struct videobuf_queue* q = NULL;
2388
2389 switch (fh->type) {
2390 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2391 q = &fh->cap;
2392 break;
2393 case V4L2_BUF_TYPE_VBI_CAPTURE:
2394 q = &fh->vbi;
2395 break;
2396 default:
2397 BUG();
2398 }
2399 return q;
2400}
2401
2402static int bttv_resource(struct bttv_fh *fh)
2403{
2404 int res = 0;
2405
2406 switch (fh->type) {
2407 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002408 res = RESOURCE_VIDEO_STREAM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 break;
2410 case V4L2_BUF_TYPE_VBI_CAPTURE:
2411 res = RESOURCE_VBI;
2412 break;
2413 default:
2414 BUG();
2415 }
2416 return res;
2417}
2418
2419static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2420{
2421 struct videobuf_queue *q = bttv_queue(fh);
2422 int res = bttv_resource(fh);
2423
2424 if (check_btres(fh,res))
2425 return -EBUSY;
2426 if (videobuf_queue_is_busy(q))
2427 return -EBUSY;
2428 fh->type = type;
2429 return 0;
2430}
2431
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002432static void
2433pix_format_set_size (struct v4l2_pix_format * f,
2434 const struct bttv_format * fmt,
2435 unsigned int width,
2436 unsigned int height)
2437{
2438 f->width = width;
2439 f->height = height;
2440
2441 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2442 f->bytesperline = width; /* Y plane */
2443 f->sizeimage = (width * height * fmt->depth) >> 3;
2444 } else {
2445 f->bytesperline = (width * fmt->depth) >> 3;
2446 f->sizeimage = height * f->bytesperline;
2447 }
2448}
2449
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002450static int bttv_g_fmt_cap(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002451 struct v4l2_format *f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002453 struct bttv_fh *fh = priv;
2454
2455 pix_format_set_size(&f->fmt.pix, fh->fmt,
2456 fh->width, fh->height);
2457 f->fmt.pix.field = fh->cap.field;
2458 f->fmt.pix.pixelformat = fh->fmt->fourcc;
2459
2460 return 0;
2461}
2462
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002463static int bttv_g_fmt_overlay(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002464 struct v4l2_format *f)
2465{
2466 struct bttv_fh *fh = priv;
2467
2468 f->fmt.win.w = fh->ov.w;
2469 f->fmt.win.field = fh->ov.field;
2470
2471 return 0;
2472}
2473
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002474static int bttv_try_fmt_cap(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002475 struct v4l2_format *f)
2476{
2477 const struct bttv_format *fmt;
2478 struct bttv_fh *fh = priv;
2479 struct bttv *btv = fh->btv;
2480 enum v4l2_field field;
2481 __s32 width, height;
2482
2483 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2484 if (NULL == fmt)
2485 return -EINVAL;
2486
2487 field = f->fmt.pix.field;
2488
2489 if (V4L2_FIELD_ANY == field) {
2490 __s32 height2;
2491
2492 height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
2493 field = (f->fmt.pix.height > height2)
2494 ? V4L2_FIELD_INTERLACED
2495 : V4L2_FIELD_BOTTOM;
2496 }
2497
2498 if (V4L2_FIELD_SEQ_BT == field)
2499 field = V4L2_FIELD_SEQ_TB;
2500
2501 switch (field) {
2502 case V4L2_FIELD_TOP:
2503 case V4L2_FIELD_BOTTOM:
2504 case V4L2_FIELD_ALTERNATE:
2505 case V4L2_FIELD_INTERLACED:
2506 break;
2507 case V4L2_FIELD_SEQ_TB:
2508 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2509 return -EINVAL;
2510 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 default:
2512 return -EINVAL;
2513 }
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002514
2515 width = f->fmt.pix.width;
2516 height = f->fmt.pix.height;
2517
2518 /* update data for the application */
2519 f->fmt.pix.field = field;
2520 pix_format_set_size(&f->fmt.pix, fmt, width, height);
2521
2522 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523}
2524
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002525static int bttv_try_fmt_overlay(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002526 struct v4l2_format *f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002528 struct bttv_fh *fh = priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002530 return verify_window(fh, &f->fmt.win,
2531 /* adjust_size */ 1,
2532 /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533}
2534
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002535static int bttv_s_fmt_cap(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002536 struct v4l2_format *f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537{
2538 int retval;
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002539 const struct bttv_format *fmt;
2540 struct bttv_fh *fh = priv;
2541 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002543 retval = bttv_switch_type(fh, f->type);
2544 if (0 != retval)
2545 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002547 retval = bttv_try_fmt_cap(file, priv, f);
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002548 if (0 != retval)
2549 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002551 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002553 /* update our state informations */
2554 mutex_lock(&fh->cap.lock);
2555 fh->fmt = fmt;
2556 fh->cap.field = f->fmt.pix.field;
2557 fh->cap.last = V4L2_FIELD_NONE;
2558 fh->width = f->fmt.pix.width;
2559 fh->height = f->fmt.pix.height;
2560 btv->init.fmt = fmt;
2561 btv->init.width = f->fmt.pix.width;
2562 btv->init.height = f->fmt.pix.height;
2563 mutex_unlock(&fh->cap.lock);
2564
2565 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566}
2567
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002568static int bttv_s_fmt_overlay(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002569 struct v4l2_format *f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002571 struct bttv_fh *fh = priv;
2572 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002574 if (no_overlay > 0)
2575 return -EINVAL;
Michael Krufky5e453dc2006-01-09 15:32:31 -02002576
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002577 return setup_window(fh, btv, &f->fmt.win, 1);
2578}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002580#ifdef CONFIG_VIDEO_V4L1_COMPAT
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002581static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
2582{
2583 int retval;
2584 unsigned int i;
2585 struct bttv_fh *fh = priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002587 mutex_lock(&fh->cap.lock);
2588 retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
2589 V4L2_MEMORY_MMAP);
2590 if (retval < 0) {
2591 mutex_unlock(&fh->cap.lock);
2592 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 }
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002594
2595 gbuffers = retval;
2596 memset(mbuf, 0, sizeof(*mbuf));
2597 mbuf->frames = gbuffers;
2598 mbuf->size = gbuffers * gbufsize;
2599
2600 for (i = 0; i < gbuffers; i++)
2601 mbuf->offsets[i] = i * gbufsize;
2602
2603 mutex_unlock(&fh->cap.lock);
2604 return 0;
2605}
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002606#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002608static int bttv_querycap(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002609 struct v4l2_capability *cap)
2610{
2611 struct bttv_fh *fh = priv;
2612 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002614 if (0 == v4l2)
2615 return -EINVAL;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002616
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002617 strlcpy(cap->driver, "bttv", sizeof(cap->driver));
2618 strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card));
2619 snprintf(cap->bus_info, sizeof(cap->bus_info),
2620 "PCI:%s", pci_name(btv->c.pci));
2621 cap->version = BTTV_VERSION_CODE;
2622 cap->capabilities =
2623 V4L2_CAP_VIDEO_CAPTURE |
2624 V4L2_CAP_VBI_CAPTURE |
2625 V4L2_CAP_READWRITE |
2626 V4L2_CAP_STREAMING;
2627 if (no_overlay <= 0)
2628 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002630 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2631 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2632 cap->capabilities |= V4L2_CAP_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return 0;
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002634}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002636static int bttv_enum_fmt_cap(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002637 struct v4l2_fmtdesc *f)
2638{
2639 if (f->index >= FORMATS)
2640 return -EINVAL;
2641
2642 strlcpy(f->description, formats[f->index].name, sizeof(f->description));
2643 f->pixelformat = formats[f->index].fourcc;
2644
2645 return 0;
2646}
2647
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002648static int bttv_enum_fmt_overlay(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002649 struct v4l2_fmtdesc *f)
2650{
2651 if (no_overlay > 0) {
2652 printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2653 return -EINVAL;
2654 }
2655
2656 if (f->index >= FORMATS)
2657 return -EINVAL;
2658
2659 strlcpy(f->description, formats[f->index].name,
2660 sizeof(f->description));
2661
2662 f->pixelformat = formats[f->index].fourcc;
2663
2664 return 0;
2665}
2666
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002667static int bttv_enum_fmt_vbi(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002668 struct v4l2_fmtdesc *f)
2669{
2670 if (0 != f->index)
2671 return -EINVAL;
2672
2673 f->pixelformat = V4L2_PIX_FMT_GREY;
2674 strcpy(f->description, "vbi data");
2675
2676 return 0;
2677}
2678
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002679static int bttv_g_fbuf(struct file *file, void *f,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002680 struct v4l2_framebuffer *fb)
2681{
2682 struct bttv_fh *fh = f;
2683 struct bttv *btv = fh->btv;
2684
2685 *fb = btv->fbuf;
2686 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2687 if (fh->ovfmt)
2688 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2689 return 0;
2690}
2691
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002692static int bttv_overlay(struct file *file, void *f, unsigned int on)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002693{
2694 struct bttv_fh *fh = f;
2695 struct bttv *btv = fh->btv;
2696 struct bttv_buffer *new;
2697 int retval;
2698
2699 if (on) {
2700 /* verify args */
2701 if (NULL == btv->fbuf.base)
2702 return -EINVAL;
2703 if (!fh->ov.setup_ok) {
2704 dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
2705 return -EINVAL;
2706 }
2707 }
2708
2709 if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
2710 return -EBUSY;
2711
2712 mutex_lock(&fh->cap.lock);
2713 if (on) {
2714 fh->ov.tvnorm = btv->tvnorm;
2715 new = videobuf_pci_alloc(sizeof(*new));
2716 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2717 } else {
2718 new = NULL;
2719 }
2720
2721 /* switch over */
2722 retval = bttv_switch_overlay(btv, fh, new);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002723 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 return retval;
2725}
2726
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002727static int bttv_s_fbuf(struct file *file, void *f,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002728 struct v4l2_framebuffer *fb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002730 struct bttv_fh *fh = f;
2731 struct bttv *btv = fh->btv;
2732 const struct bttv_format *fmt;
2733 int retval;
2734
2735 if (!capable(CAP_SYS_ADMIN) &&
2736 !capable(CAP_SYS_RAWIO))
2737 return -EPERM;
2738
2739 /* check args */
2740 fmt = format_by_fourcc(fb->fmt.pixelformat);
2741 if (NULL == fmt)
2742 return -EINVAL;
2743 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2744 return -EINVAL;
2745
2746 retval = -EINVAL;
2747 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2748 __s32 width = fb->fmt.width;
2749 __s32 height = fb->fmt.height;
2750
2751 retval = limit_scaled_size(fh, &width, &height,
2752 V4L2_FIELD_INTERLACED,
2753 /* width_mask */ ~3,
2754 /* width_bias */ 2,
2755 /* adjust_size */ 0,
2756 /* adjust_crop */ 0);
2757 if (0 != retval)
2758 return retval;
2759 }
2760
2761 /* ok, accept it */
2762 mutex_lock(&fh->cap.lock);
2763 btv->fbuf.base = fb->base;
2764 btv->fbuf.fmt.width = fb->fmt.width;
2765 btv->fbuf.fmt.height = fb->fmt.height;
2766 if (0 != fb->fmt.bytesperline)
2767 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2768 else
2769 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2770
2771 retval = 0;
2772 fh->ovfmt = fmt;
2773 btv->init.ovfmt = fmt;
2774 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2775 fh->ov.w.left = 0;
2776 fh->ov.w.top = 0;
2777 fh->ov.w.width = fb->fmt.width;
2778 fh->ov.w.height = fb->fmt.height;
2779 btv->init.ov.w.width = fb->fmt.width;
2780 btv->init.ov.w.height = fb->fmt.height;
2781 kfree(fh->ov.clips);
2782 fh->ov.clips = NULL;
2783 fh->ov.nclips = 0;
2784
2785 if (check_btres(fh, RESOURCE_OVERLAY)) {
2786 struct bttv_buffer *new;
2787
2788 new = videobuf_pci_alloc(sizeof(*new));
2789 new->crop = btv->crop[!!fh->do_crop].rect;
2790 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2791 retval = bttv_switch_overlay(btv, fh, new);
2792 }
2793 }
2794 mutex_unlock(&fh->cap.lock);
2795 return retval;
2796}
2797
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002798static int bttv_reqbufs(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002799 struct v4l2_requestbuffers *p)
2800{
2801 struct bttv_fh *fh = priv;
2802 return videobuf_reqbufs(bttv_queue(fh), p);
2803}
2804
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002805static int bttv_querybuf(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002806 struct v4l2_buffer *b)
2807{
2808 struct bttv_fh *fh = priv;
2809 return videobuf_querybuf(bttv_queue(fh), b);
2810}
2811
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002812static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002813{
2814 struct bttv_fh *fh = priv;
2815 struct bttv *btv = fh->btv;
2816 int res = bttv_resource(fh);
2817
2818 if (!check_alloc_btres(btv, fh, res))
2819 return -EBUSY;
2820
2821 return videobuf_qbuf(bttv_queue(fh), b);
2822}
2823
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002824static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002825{
2826 struct bttv_fh *fh = priv;
2827 return videobuf_dqbuf(bttv_queue(fh), b,
2828 file->f_flags & O_NONBLOCK);
2829}
2830
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002831static int bttv_streamon(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002832 enum v4l2_buf_type type)
2833{
2834 struct bttv_fh *fh = priv;
2835 struct bttv *btv = fh->btv;
2836 int res = bttv_resource(fh);
2837
2838 if (!check_alloc_btres(btv, fh, res))
2839 return -EBUSY;
2840 return videobuf_streamon(bttv_queue(fh));
2841}
2842
2843
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002844static int bttv_streamoff(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002845 enum v4l2_buf_type type)
2846{
2847 struct bttv_fh *fh = priv;
2848 struct bttv *btv = fh->btv;
2849 int retval;
2850 int res = bttv_resource(fh);
2851
2852
2853 retval = videobuf_streamoff(bttv_queue(fh));
2854 if (retval < 0)
2855 return retval;
2856 free_btres(btv, fh, res);
2857 return 0;
2858}
2859
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002860static int bttv_queryctrl(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002861 struct v4l2_queryctrl *c)
2862{
2863 struct bttv_fh *fh = priv;
2864 struct bttv *btv = fh->btv;
2865 const struct v4l2_queryctrl *ctrl;
2866
2867 if ((c->id < V4L2_CID_BASE ||
2868 c->id >= V4L2_CID_LASTP1) &&
2869 (c->id < V4L2_CID_PRIVATE_BASE ||
2870 c->id >= V4L2_CID_PRIVATE_LASTP1))
2871 return -EINVAL;
2872
2873 ctrl = ctrl_by_id(c->id);
2874 *c = (NULL != ctrl) ? *ctrl : no_ctl;
2875
2876 if (!btv->volume_gpio &&
2877 (ctrl->id == V4L2_CID_AUDIO_VOLUME))
2878 * c = no_ctl;
2879
2880 return 0;
2881}
2882
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002883static int bttv_g_parm(struct file *file, void *f,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002884 struct v4l2_streamparm *parm)
2885{
2886 struct bttv_fh *fh = f;
2887 struct bttv *btv = fh->btv;
2888 struct v4l2_standard s;
2889
2890 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2891 return -EINVAL;
2892 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2893 bttv_tvnorms[btv->tvnorm].name);
2894 parm->parm.capture.timeperframe = s.frameperiod;
2895 return 0;
2896}
2897
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002898static int bttv_g_tuner(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002899 struct v4l2_tuner *t)
2900{
2901 struct bttv_fh *fh = priv;
2902 struct bttv *btv = fh->btv;
2903
2904 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2905 return -EINVAL;
2906 if (0 != t->index)
2907 return -EINVAL;
2908
2909 mutex_lock(&btv->lock);
2910 memset(t, 0, sizeof(*t));
2911 t->rxsubchans = V4L2_TUNER_SUB_MONO;
2912 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
2913 strcpy(t->name, "Television");
2914 t->capability = V4L2_TUNER_CAP_NORM;
2915 t->type = V4L2_TUNER_ANALOG_TV;
2916 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
2917 t->signal = 0xffff;
2918
2919 if (btv->audio_mode_gpio)
2920 btv->audio_mode_gpio(btv, t, 0);
2921
2922 mutex_unlock(&btv->lock);
2923 return 0;
2924}
2925
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002926static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002927{
2928 struct bttv_fh *fh = f;
2929 struct bttv *btv = fh->btv;
2930
2931 *p = v4l2_prio_max(&btv->prio);
2932
2933 return 0;
2934}
2935
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002936static int bttv_s_priority(struct file *file, void *f,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002937 enum v4l2_priority prio)
2938{
2939 struct bttv_fh *fh = f;
2940 struct bttv *btv = fh->btv;
2941
2942 return v4l2_prio_change(&btv->prio, &fh->prio, prio);
2943}
2944
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002945static int bttv_cropcap(struct file *file, void *priv,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002946 struct v4l2_cropcap *cap)
2947{
2948 struct bttv_fh *fh = priv;
2949 struct bttv *btv = fh->btv;
2950
2951 if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2952 cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
2953 return -EINVAL;
2954
2955 *cap = bttv_tvnorms[btv->tvnorm].cropcap;
2956
2957 return 0;
2958}
2959
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002960static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002961{
2962 struct bttv_fh *fh = f;
2963 struct bttv *btv = fh->btv;
2964
2965 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2966 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
2967 return -EINVAL;
2968
2969 /* No fh->do_crop = 1; because btv->crop[1] may be
2970 inconsistent with fh->width or fh->height and apps
2971 do not expect a change here. */
2972
2973 crop->c = btv->crop[!!fh->do_crop].rect;
2974
2975 return 0;
2976}
2977
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03002978static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03002979{
2980 struct bttv_fh *fh = f;
2981 struct bttv *btv = fh->btv;
2982 const struct v4l2_rect *b;
2983 int retval;
2984 struct bttv_crop c;
2985 __s32 b_left;
2986 __s32 b_top;
2987 __s32 b_right;
2988 __s32 b_bottom;
2989
2990 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2991 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
2992 return -EINVAL;
2993
2994 retval = v4l2_prio_check(&btv->prio, &fh->prio);
2995 if (0 != retval)
2996 return retval;
2997
2998 /* Make sure tvnorm, vbi_end and the current cropping
2999 parameters remain consistent until we're done. Note
3000 read() may change vbi_end in check_alloc_btres(). */
3001 mutex_lock(&btv->lock);
3002
3003 retval = -EBUSY;
3004
3005 if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
3006 mutex_unlock(&btv->lock);
3007 return retval;
3008 }
3009
3010 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
3011
3012 b_left = b->left;
3013 b_right = b_left + b->width;
3014 b_bottom = b->top + b->height;
3015
3016 b_top = max(b->top, btv->vbi_end);
3017 if (b_top + 32 >= b_bottom) {
3018 mutex_unlock(&btv->lock);
3019 return retval;
3020 }
3021
3022 /* Min. scaled size 48 x 32. */
3023 c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
3024 c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
3025
3026 c.rect.width = clamp(crop->c.width,
3027 48, b_right - c.rect.left);
3028
3029 c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
3030 /* Top and height must be a multiple of two. */
3031 c.rect.top = (c.rect.top + 1) & ~1;
3032
3033 c.rect.height = clamp(crop->c.height,
3034 32, b_bottom - c.rect.top);
3035 c.rect.height = (c.rect.height + 1) & ~1;
3036
3037 bttv_crop_calc_limits(&c);
3038
3039 btv->crop[1] = c;
3040
3041 mutex_unlock(&btv->lock);
3042
3043 fh->do_crop = 1;
3044
3045 mutex_lock(&fh->cap.lock);
3046
3047 if (fh->width < c.min_scaled_width) {
3048 fh->width = c.min_scaled_width;
3049 btv->init.width = c.min_scaled_width;
3050 } else if (fh->width > c.max_scaled_width) {
3051 fh->width = c.max_scaled_width;
3052 btv->init.width = c.max_scaled_width;
3053 }
3054
3055 if (fh->height < c.min_scaled_height) {
3056 fh->height = c.min_scaled_height;
3057 btv->init.height = c.min_scaled_height;
3058 } else if (fh->height > c.max_scaled_height) {
3059 fh->height = c.max_scaled_height;
3060 btv->init.height = c.max_scaled_height;
3061 }
3062
3063 mutex_unlock(&fh->cap.lock);
3064
3065 return 0;
3066}
3067
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03003068static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003069{
3070 strcpy(a->name, "audio");
3071 return 0;
3072}
3073
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03003074static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003075{
3076 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077}
3078
3079static ssize_t bttv_read(struct file *file, char __user *data,
3080 size_t count, loff_t *ppos)
3081{
3082 struct bttv_fh *fh = file->private_data;
3083 int retval = 0;
3084
3085 if (fh->btv->errors)
3086 bttv_reinit_bt848(fh->btv);
3087 dprintk("bttv%d: read count=%d type=%s\n",
3088 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
3089
3090 switch (fh->type) {
3091 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003092 if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
3093 /* VIDEO_READ in use by another fh,
3094 or VIDEO_STREAM by any fh. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 return -EBUSY;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 retval = videobuf_read_one(&fh->cap, data, count, ppos,
3098 file->f_flags & O_NONBLOCK);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003099 free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 break;
3101 case V4L2_BUF_TYPE_VBI_CAPTURE:
3102 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3103 return -EBUSY;
3104 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
3105 file->f_flags & O_NONBLOCK);
3106 break;
3107 default:
3108 BUG();
3109 }
3110 return retval;
3111}
3112
3113static unsigned int bttv_poll(struct file *file, poll_table *wait)
3114{
3115 struct bttv_fh *fh = file->private_data;
3116 struct bttv_buffer *buf;
3117 enum v4l2_field field;
3118
3119 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
3120 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3121 return POLLERR;
3122 return videobuf_poll_stream(file, &fh->vbi, wait);
3123 }
3124
Michael Schimeke5bd0262007-01-18 16:17:39 -03003125 if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 /* streaming capture */
3127 if (list_empty(&fh->cap.stream))
3128 return POLLERR;
3129 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
3130 } else {
3131 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02003132 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 if (NULL == fh->cap.read_buf) {
3134 /* need to capture a new frame */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003135 if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003136 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 return POLLERR;
3138 }
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003139 fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003141 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 return POLLERR;
3143 }
3144 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
3145 field = videobuf_next_field(&fh->cap);
3146 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08003147 kfree (fh->cap.read_buf);
3148 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003149 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 return POLLERR;
3151 }
3152 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3153 fh->cap.read_off = 0;
3154 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003155 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 buf = (struct bttv_buffer*)fh->cap.read_buf;
3157 }
3158
3159 poll_wait(file, &buf->vb.done, wait);
Brandon Philips0fc06862007-11-06 20:02:36 -03003160 if (buf->vb.state == VIDEOBUF_DONE ||
3161 buf->vb.state == VIDEOBUF_ERROR)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 return POLLIN|POLLRDNORM;
3163 return 0;
3164}
3165
3166static int bttv_open(struct inode *inode, struct file *file)
3167{
3168 int minor = iminor(inode);
3169 struct bttv *btv = NULL;
3170 struct bttv_fh *fh;
3171 enum v4l2_buf_type type = 0;
3172 unsigned int i;
3173
3174 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3175
3176 for (i = 0; i < bttv_num; i++) {
3177 if (bttvs[i].video_dev &&
3178 bttvs[i].video_dev->minor == minor) {
3179 btv = &bttvs[i];
3180 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3181 break;
3182 }
3183 if (bttvs[i].vbi_dev &&
3184 bttvs[i].vbi_dev->minor == minor) {
3185 btv = &bttvs[i];
3186 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3187 break;
3188 }
3189 }
3190 if (NULL == btv)
3191 return -ENODEV;
3192
3193 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3194 btv->c.nr,v4l2_type_names[type]);
3195
3196 /* allocate per filehandle data */
3197 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3198 if (NULL == fh)
3199 return -ENOMEM;
3200 file->private_data = fh;
3201 *fh = btv->init;
3202 fh->type = type;
3203 fh->ov.setup_ok = 0;
3204 v4l2_prio_open(&btv->prio,&fh->prio);
3205
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003206 videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 btv->c.pci, &btv->s_lock,
3208 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3209 V4L2_FIELD_INTERLACED,
3210 sizeof(struct bttv_buffer),
3211 fh);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003212 videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 btv->c.pci, &btv->s_lock,
3214 V4L2_BUF_TYPE_VBI_CAPTURE,
3215 V4L2_FIELD_SEQ_TB,
3216 sizeof(struct bttv_buffer),
3217 fh);
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03003218 set_tvnorm(btv,btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220 btv->users++;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003221
3222 /* The V4L2 spec requires one global set of cropping parameters
3223 which only change on request. These are stored in btv->crop[1].
3224 However for compatibility with V4L apps and cropping unaware
3225 V4L2 apps we now reset the cropping parameters as seen through
3226 this fh, which is to say VIDIOC_G_CROP and scaling limit checks
3227 will use btv->crop[0], the default cropping parameters for the
3228 current video standard, and VIDIOC_S_FMT will not implicitely
3229 change the cropping parameters until VIDIOC_S_CROP has been
3230 called. */
3231 fh->do_crop = !reset_crop; /* module parameter */
3232
3233 /* Likewise there should be one global set of VBI capture
3234 parameters, but for compatibility with V4L apps and earlier
3235 driver versions each fh has its own parameters. */
3236 bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
3237
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 bttv_field_count(btv);
3239 return 0;
3240}
3241
3242static int bttv_release(struct inode *inode, struct file *file)
3243{
3244 struct bttv_fh *fh = file->private_data;
3245 struct bttv *btv = fh->btv;
3246
3247 /* turn off overlay */
3248 if (check_btres(fh, RESOURCE_OVERLAY))
3249 bttv_switch_overlay(btv,fh,NULL);
3250
3251 /* stop video capture */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003252 if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 videobuf_streamoff(&fh->cap);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003254 free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 }
3256 if (fh->cap.read_buf) {
3257 buffer_release(&fh->cap,fh->cap.read_buf);
3258 kfree(fh->cap.read_buf);
3259 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03003260 if (check_btres(fh, RESOURCE_VIDEO_READ)) {
3261 free_btres(btv, fh, RESOURCE_VIDEO_READ);
3262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263
3264 /* stop vbi capture */
3265 if (check_btres(fh, RESOURCE_VBI)) {
Brandon Philips053fcb62007-11-13 20:11:26 -03003266 videobuf_stop(&fh->vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 free_btres(btv,fh,RESOURCE_VBI);
3268 }
3269
3270 /* free stuff */
3271 videobuf_mmap_free(&fh->cap);
3272 videobuf_mmap_free(&fh->vbi);
3273 v4l2_prio_close(&btv->prio,&fh->prio);
3274 file->private_data = NULL;
3275 kfree(fh);
3276
3277 btv->users--;
3278 bttv_field_count(btv);
3279 return 0;
3280}
3281
3282static int
3283bttv_mmap(struct file *file, struct vm_area_struct *vma)
3284{
3285 struct bttv_fh *fh = file->private_data;
3286
3287 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3288 fh->btv->c.nr, v4l2_type_names[fh->type],
3289 vma->vm_start, vma->vm_end - vma->vm_start);
3290 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3291}
3292
Arjan van de Venfa027c22007-02-12 00:55:33 -08003293static const struct file_operations bttv_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294{
3295 .owner = THIS_MODULE,
3296 .open = bttv_open,
3297 .release = bttv_release,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003298 .ioctl = video_ioctl2,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003299 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 .llseek = no_llseek,
3301 .read = bttv_read,
3302 .mmap = bttv_mmap,
3303 .poll = bttv_poll,
3304};
3305
3306static struct video_device bttv_video_template =
3307{
3308 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003309 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003310 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 .fops = &bttv_fops,
3312 .minor = -1,
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03003313 .vidioc_querycap = bttv_querycap,
3314 .vidioc_enum_fmt_cap = bttv_enum_fmt_cap,
3315 .vidioc_g_fmt_cap = bttv_g_fmt_cap,
3316 .vidioc_try_fmt_cap = bttv_try_fmt_cap,
3317 .vidioc_s_fmt_cap = bttv_s_fmt_cap,
3318 .vidioc_enum_fmt_overlay = bttv_enum_fmt_overlay,
3319 .vidioc_g_fmt_overlay = bttv_g_fmt_overlay,
3320 .vidioc_try_fmt_overlay = bttv_try_fmt_overlay,
3321 .vidioc_s_fmt_overlay = bttv_s_fmt_overlay,
3322 .vidioc_enum_fmt_vbi = bttv_enum_fmt_vbi,
3323 .vidioc_g_fmt_vbi = bttv_g_fmt_vbi,
3324 .vidioc_try_fmt_vbi = bttv_try_fmt_vbi,
3325 .vidioc_s_fmt_vbi = bttv_s_fmt_vbi,
3326 .vidioc_g_audio = bttv_g_audio,
3327 .vidioc_s_audio = bttv_s_audio,
3328 .vidioc_cropcap = bttv_cropcap,
3329 .vidioc_reqbufs = bttv_reqbufs,
3330 .vidioc_querybuf = bttv_querybuf,
3331 .vidioc_qbuf = bttv_qbuf,
3332 .vidioc_dqbuf = bttv_dqbuf,
3333 .vidioc_s_std = bttv_s_std,
3334 .vidioc_enum_input = bttv_enum_input,
3335 .vidioc_g_input = bttv_g_input,
3336 .vidioc_s_input = bttv_s_input,
3337 .vidioc_queryctrl = bttv_queryctrl,
3338 .vidioc_g_ctrl = bttv_g_ctrl,
3339 .vidioc_s_ctrl = bttv_s_ctrl,
3340 .vidioc_streamon = bttv_streamon,
3341 .vidioc_streamoff = bttv_streamoff,
3342 .vidioc_g_tuner = bttv_g_tuner,
3343 .vidioc_s_tuner = bttv_s_tuner,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003344#ifdef CONFIG_VIDEO_V4L1_COMPAT
3345 .vidiocgmbuf = vidiocgmbuf,
3346#endif
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03003347 .vidioc_g_crop = bttv_g_crop,
3348 .vidioc_g_crop = bttv_g_crop,
3349 .vidioc_s_crop = bttv_s_crop,
3350 .vidioc_g_fbuf = bttv_g_fbuf,
3351 .vidioc_s_fbuf = bttv_s_fbuf,
3352 .vidioc_overlay = bttv_overlay,
3353 .vidioc_g_priority = bttv_g_priority,
3354 .vidioc_s_priority = bttv_s_priority,
3355 .vidioc_g_parm = bttv_g_parm,
3356 .vidioc_g_frequency = bttv_g_frequency,
3357 .vidioc_s_frequency = bttv_s_frequency,
3358 .vidioc_log_status = bttv_log_status,
3359 .vidioc_querystd = bttv_querystd,
3360 .vidioc_g_register = bttv_g_register,
3361 .vidioc_s_register = bttv_s_register,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003362 .tvnorms = BTTV_NORMS,
3363 .current_norm = V4L2_STD_PAL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364};
3365
3366static struct video_device bttv_vbi_template =
3367{
3368 .name = "bt848/878 vbi",
3369 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 .fops = &bttv_fops,
3371 .minor = -1,
3372};
3373
3374/* ----------------------------------------------------------------------- */
3375/* radio interface */
3376
3377static int radio_open(struct inode *inode, struct file *file)
3378{
3379 int minor = iminor(inode);
3380 struct bttv *btv = NULL;
3381 unsigned int i;
3382
3383 dprintk("bttv: open minor=%d\n",minor);
3384
3385 for (i = 0; i < bttv_num; i++) {
3386 if (bttvs[i].radio_dev->minor == minor) {
3387 btv = &bttvs[i];
3388 break;
3389 }
3390 }
3391 if (NULL == btv)
3392 return -ENODEV;
3393
3394 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003395 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003396
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 file->private_data = btv;
3400
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003401 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3402 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003404 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003405 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406}
3407
3408static int radio_release(struct inode *inode, struct file *file)
3409{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003410 struct bttv *btv = file->private_data;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003411 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412
3413 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003414
3415 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3416
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 return 0;
3418}
3419
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003420static int radio_querycap(struct file *file, void *priv,
3421 struct v4l2_capability *cap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003423 struct bttv_fh *fh = priv;
3424 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003426 strcpy(cap->driver, "bttv");
3427 strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card));
3428 sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci));
3429 cap->version = BTTV_VERSION_CODE;
3430 cap->capabilities = V4L2_CAP_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 return 0;
3433}
3434
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003435static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436{
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003437 struct bttv_fh *fh = priv;
3438 struct bttv *btv = fh->btv;
3439
3440 if (UNSET == bttv_tvcards[btv->c.type].tuner)
3441 return -EINVAL;
3442 if (0 != t->index)
3443 return -EINVAL;
3444 mutex_lock(&btv->lock);
3445 memset(t, 0, sizeof(*t));
3446 strcpy(t->name, "Radio");
3447 t->type = V4L2_TUNER_RADIO;
3448
3449 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
3450
3451 if (btv->audio_mode_gpio)
3452 btv->audio_mode_gpio(btv, t, 0);
3453
3454 mutex_unlock(&btv->lock);
3455
3456 return 0;
3457}
3458
3459static int radio_enum_input(struct file *file, void *priv,
3460 struct v4l2_input *i)
3461{
3462 if (i->index != 0)
3463 return -EINVAL;
3464
3465 strcpy(i->name, "Radio");
3466 i->type = V4L2_INPUT_TYPE_TUNER;
3467
3468 return 0;
3469}
3470
3471static int radio_g_audio(struct file *file, void *priv,
3472 struct v4l2_audio *a)
3473{
3474 memset(a, 0, sizeof(*a));
3475 strcpy(a->name, "Radio");
3476 return 0;
3477}
3478
3479static int radio_s_tuner(struct file *file, void *priv,
3480 struct v4l2_tuner *t)
3481{
3482 struct bttv_fh *fh = priv;
3483 struct bttv *btv = fh->btv;
3484
3485 if (0 != t->index)
3486 return -EINVAL;
3487
3488 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
3489 return 0;
3490}
3491
3492static int radio_s_audio(struct file *file, void *priv,
3493 struct v4l2_audio *a)
3494{
3495 return 0;
3496}
3497
3498static int radio_s_input(struct file *filp, void *priv, unsigned int i)
3499{
3500 return 0;
3501}
3502
3503static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm)
3504{
3505 return 0;
3506}
3507
3508static int radio_queryctrl(struct file *file, void *priv,
3509 struct v4l2_queryctrl *c)
3510{
3511 const struct v4l2_queryctrl *ctrl;
3512
3513 if (c->id < V4L2_CID_BASE ||
3514 c->id >= V4L2_CID_LASTP1)
3515 return -EINVAL;
3516
3517 if (c->id == V4L2_CID_AUDIO_MUTE) {
3518 ctrl = ctrl_by_id(c->id);
3519 *c = *ctrl;
3520 } else
3521 *c = no_ctl;
3522
3523 return 0;
3524}
3525
3526static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
3527{
3528 *i = 0;
3529 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530}
3531
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003532static ssize_t radio_read(struct file *file, char __user *data,
3533 size_t count, loff_t *ppos)
3534{
3535 struct bttv *btv = file->private_data;
3536 struct rds_command cmd;
3537 cmd.block_count = count/3;
3538 cmd.buffer = data;
3539 cmd.instance = file;
3540 cmd.result = -ENODEV;
3541
3542 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3543
3544 return cmd.result;
3545}
3546
3547static unsigned int radio_poll(struct file *file, poll_table *wait)
3548{
3549 struct bttv *btv = file->private_data;
3550 struct rds_command cmd;
3551 cmd.instance = file;
3552 cmd.event_list = wait;
3553 cmd.result = -ENODEV;
3554 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3555
3556 return cmd.result;
3557}
3558
Arjan van de Venfa027c22007-02-12 00:55:33 -08003559static const struct file_operations radio_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560{
3561 .owner = THIS_MODULE,
3562 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003563 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 .release = radio_release,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003565 .ioctl = video_ioctl2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003567 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568};
3569
3570static struct video_device radio_template =
3571{
3572 .name = "bt848/878 radio",
3573 .type = VID_TYPE_TUNER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 .fops = &radio_fops,
3575 .minor = -1,
Douglas Schilling Landgraf402aa762007-12-27 22:20:58 -03003576 .vidioc_querycap = radio_querycap,
3577 .vidioc_g_tuner = radio_g_tuner,
3578 .vidioc_enum_input = radio_enum_input,
3579 .vidioc_g_audio = radio_g_audio,
3580 .vidioc_s_tuner = radio_s_tuner,
3581 .vidioc_s_audio = radio_s_audio,
3582 .vidioc_s_input = radio_s_input,
3583 .vidioc_s_std = radio_s_std,
3584 .vidioc_queryctrl = radio_queryctrl,
3585 .vidioc_g_input = radio_g_input,
Mauro Carvalho Chehabe5ae3db2007-12-27 22:22:59 -03003586 .vidioc_g_ctrl = bttv_g_ctrl,
3587 .vidioc_s_ctrl = bttv_s_ctrl,
3588 .vidioc_g_frequency = bttv_g_frequency,
3589 .vidioc_s_frequency = bttv_s_frequency,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590};
3591
3592/* ----------------------------------------------------------------------- */
3593/* some debug code */
3594
Adrian Bunk408b6642005-05-01 08:59:29 -07003595static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596{
3597 static char *instr[16] = {
3598 [ BT848_RISC_WRITE >> 28 ] = "write",
3599 [ BT848_RISC_SKIP >> 28 ] = "skip",
3600 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3601 [ BT848_RISC_JUMP >> 28 ] = "jump",
3602 [ BT848_RISC_SYNC >> 28 ] = "sync",
3603 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3604 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3605 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3606 };
3607 static int incr[16] = {
3608 [ BT848_RISC_WRITE >> 28 ] = 2,
3609 [ BT848_RISC_JUMP >> 28 ] = 2,
3610 [ BT848_RISC_SYNC >> 28 ] = 2,
3611 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3612 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3613 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3614 };
3615 static char *bits[] = {
3616 "be0", "be1", "be2", "be3/resync",
3617 "set0", "set1", "set2", "set3",
3618 "clr0", "clr1", "clr2", "clr3",
3619 "irq", "res", "eol", "sol",
3620 };
3621 int i;
3622
3623 printk("0x%08x [ %s", risc,
3624 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3625 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3626 if (risc & (1 << (i + 12)))
3627 printk(" %s",bits[i]);
3628 printk(" count=%d ]\n", risc & 0xfff);
3629 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3630}
3631
Adrian Bunk408b6642005-05-01 08:59:29 -07003632static void bttv_risc_disasm(struct bttv *btv,
3633 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634{
3635 unsigned int i,j,n;
3636
3637 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3638 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3639 for (i = 0; i < (risc->size >> 2); i += n) {
3640 printk("%s: 0x%lx: ", btv->c.name,
3641 (unsigned long)(risc->dma + (i<<2)));
3642 n = bttv_risc_decode(risc->cpu[i]);
3643 for (j = 1; j < n; j++)
3644 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3645 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3646 risc->cpu[i+j], j);
3647 if (0 == risc->cpu[i])
3648 break;
3649 }
3650}
3651
3652static void bttv_print_riscaddr(struct bttv *btv)
3653{
3654 printk(" main: %08Lx\n",
3655 (unsigned long long)btv->main.dma);
3656 printk(" vbi : o=%08Lx e=%08Lx\n",
3657 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3658 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3659 printk(" cap : o=%08Lx e=%08Lx\n",
3660 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3661 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3662 printk(" scr : o=%08Lx e=%08Lx\n",
3663 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3664 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3665 bttv_risc_disasm(btv, &btv->main);
3666}
3667
3668/* ----------------------------------------------------------------------- */
3669/* irq handler */
3670
3671static char *irq_name[] = {
3672 "FMTCHG", // format change detected (525 vs. 625)
3673 "VSYNC", // vertical sync (new field)
3674 "HSYNC", // horizontal sync
3675 "OFLOW", // chroma/luma AGC overflow
3676 "HLOCK", // horizontal lock changed
3677 "VPRES", // video presence changed
3678 "6", "7",
3679 "I2CDONE", // hw irc operation finished
3680 "GPINT", // gpio port triggered irq
3681 "10",
3682 "RISCI", // risc instruction triggered irq
3683 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3684 "FTRGT", // pixel data fifo overrun
3685 "FDSR", // fifo data stream resyncronisation
3686 "PPERR", // parity error (data transfer)
3687 "RIPERR", // parity error (read risc instructions)
3688 "PABORT", // pci abort
3689 "OCERR", // risc instruction error
3690 "SCERR", // syncronisation error
3691};
3692
3693static void bttv_print_irqbits(u32 print, u32 mark)
3694{
3695 unsigned int i;
3696
3697 printk("bits:");
3698 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3699 if (print & (1 << i))
3700 printk(" %s",irq_name[i]);
3701 if (mark & (1 << i))
3702 printk("*");
3703 }
3704}
3705
3706static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3707{
3708 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3709 btv->c.nr,
3710 (unsigned long)btv->main.dma,
3711 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3712 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3713 (unsigned long)rc);
3714
3715 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3716 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3717 "Ok, then this is harmless, don't worry ;)\n",
3718 btv->c.nr);
3719 return;
3720 }
3721 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3722 btv->c.nr);
3723 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3724 btv->c.nr);
3725 dump_stack();
3726}
3727
3728static int
3729bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3730{
3731 struct bttv_buffer *item;
3732
3733 memset(set,0,sizeof(*set));
3734
3735 /* capture request ? */
3736 if (!list_empty(&btv->capture)) {
3737 set->frame_irq = 1;
3738 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3739 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3740 set->top = item;
3741 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3742 set->bottom = item;
3743
3744 /* capture request for other field ? */
3745 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3746 (item->vb.queue.next != &btv->capture)) {
3747 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3748 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3749 if (NULL == set->top &&
3750 V4L2_FIELD_TOP == item->vb.field) {
3751 set->top = item;
3752 }
3753 if (NULL == set->bottom &&
3754 V4L2_FIELD_BOTTOM == item->vb.field) {
3755 set->bottom = item;
3756 }
3757 if (NULL != set->top && NULL != set->bottom)
3758 set->top_irq = 2;
3759 }
3760 }
3761 }
3762
3763 /* screen overlay ? */
3764 if (NULL != btv->screen) {
3765 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3766 if (NULL == set->top && NULL == set->bottom) {
3767 set->top = btv->screen;
3768 set->bottom = btv->screen;
3769 }
3770 } else {
3771 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3772 NULL == set->top) {
3773 set->top = btv->screen;
3774 }
3775 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3776 NULL == set->bottom) {
3777 set->bottom = btv->screen;
3778 }
3779 }
3780 }
3781
3782 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3783 btv->c.nr,set->top, set->bottom,
3784 btv->screen,set->frame_irq,set->top_irq);
3785 return 0;
3786}
3787
3788static void
3789bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3790 struct bttv_buffer_set *curr, unsigned int state)
3791{
3792 struct timeval ts;
3793
3794 do_gettimeofday(&ts);
3795
3796 if (wakeup->top == wakeup->bottom) {
3797 if (NULL != wakeup->top && curr->top != wakeup->top) {
3798 if (irq_debug > 1)
3799 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3800 wakeup->top->vb.ts = ts;
3801 wakeup->top->vb.field_count = btv->field_count;
3802 wakeup->top->vb.state = state;
3803 wake_up(&wakeup->top->vb.done);
3804 }
3805 } else {
3806 if (NULL != wakeup->top && curr->top != wakeup->top) {
3807 if (irq_debug > 1)
3808 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3809 wakeup->top->vb.ts = ts;
3810 wakeup->top->vb.field_count = btv->field_count;
3811 wakeup->top->vb.state = state;
3812 wake_up(&wakeup->top->vb.done);
3813 }
3814 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3815 if (irq_debug > 1)
3816 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3817 wakeup->bottom->vb.ts = ts;
3818 wakeup->bottom->vb.field_count = btv->field_count;
3819 wakeup->bottom->vb.state = state;
3820 wake_up(&wakeup->bottom->vb.done);
3821 }
3822 }
3823}
3824
3825static void
3826bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3827 unsigned int state)
3828{
3829 struct timeval ts;
3830
3831 if (NULL == wakeup)
3832 return;
3833
3834 do_gettimeofday(&ts);
3835 wakeup->vb.ts = ts;
3836 wakeup->vb.field_count = btv->field_count;
3837 wakeup->vb.state = state;
3838 wake_up(&wakeup->vb.done);
3839}
3840
3841static void bttv_irq_timeout(unsigned long data)
3842{
3843 struct bttv *btv = (struct bttv *)data;
3844 struct bttv_buffer_set old,new;
3845 struct bttv_buffer *ovbi;
3846 struct bttv_buffer *item;
3847 unsigned long flags;
3848
3849 if (bttv_verbose) {
3850 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3851 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3852 btread(BT848_RISC_COUNT));
3853 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3854 printk("\n");
3855 }
3856
3857 spin_lock_irqsave(&btv->s_lock,flags);
3858
3859 /* deactivate stuff */
3860 memset(&new,0,sizeof(new));
3861 old = btv->curr;
3862 ovbi = btv->cvbi;
3863 btv->curr = new;
3864 btv->cvbi = NULL;
3865 btv->loop_irq = 0;
3866 bttv_buffer_activate_video(btv, &new);
3867 bttv_buffer_activate_vbi(btv, NULL);
3868 bttv_set_dma(btv, 0);
3869
3870 /* wake up */
Brandon Philips0fc06862007-11-06 20:02:36 -03003871 bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR);
3872 bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
3874 /* cancel all outstanding capture / vbi requests */
3875 while (!list_empty(&btv->capture)) {
3876 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3877 list_del(&item->vb.queue);
Brandon Philips0fc06862007-11-06 20:02:36 -03003878 item->vb.state = VIDEOBUF_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 wake_up(&item->vb.done);
3880 }
3881 while (!list_empty(&btv->vcapture)) {
3882 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3883 list_del(&item->vb.queue);
Brandon Philips0fc06862007-11-06 20:02:36 -03003884 item->vb.state = VIDEOBUF_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 wake_up(&item->vb.done);
3886 }
3887
3888 btv->errors++;
3889 spin_unlock_irqrestore(&btv->s_lock,flags);
3890}
3891
3892static void
3893bttv_irq_wakeup_top(struct bttv *btv)
3894{
3895 struct bttv_buffer *wakeup = btv->curr.top;
3896
3897 if (NULL == wakeup)
3898 return;
3899
3900 spin_lock(&btv->s_lock);
3901 btv->curr.top_irq = 0;
3902 btv->curr.top = NULL;
3903 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3904
3905 do_gettimeofday(&wakeup->vb.ts);
3906 wakeup->vb.field_count = btv->field_count;
Brandon Philips0fc06862007-11-06 20:02:36 -03003907 wakeup->vb.state = VIDEOBUF_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 wake_up(&wakeup->vb.done);
3909 spin_unlock(&btv->s_lock);
3910}
3911
3912static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3913{
3914 if (rc < risc->dma)
3915 return 0;
3916 if (rc > risc->dma + risc->size)
3917 return 0;
3918 return 1;
3919}
3920
3921static void
3922bttv_irq_switch_video(struct bttv *btv)
3923{
3924 struct bttv_buffer_set new;
3925 struct bttv_buffer_set old;
3926 dma_addr_t rc;
3927
3928 spin_lock(&btv->s_lock);
3929
3930 /* new buffer set */
3931 bttv_irq_next_video(btv, &new);
3932 rc = btread(BT848_RISC_COUNT);
3933 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3934 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3935 btv->framedrop++;
3936 if (debug_latency)
3937 bttv_irq_debug_low_latency(btv, rc);
3938 spin_unlock(&btv->s_lock);
3939 return;
3940 }
3941
3942 /* switch over */
3943 old = btv->curr;
3944 btv->curr = new;
3945 btv->loop_irq &= ~1;
3946 bttv_buffer_activate_video(btv, &new);
3947 bttv_set_dma(btv, 0);
3948
3949 /* switch input */
3950 if (UNSET != btv->new_input) {
3951 video_mux(btv,btv->new_input);
3952 btv->new_input = UNSET;
3953 }
3954
3955 /* wake up finished buffers */
Brandon Philips0fc06862007-11-06 20:02:36 -03003956 bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 spin_unlock(&btv->s_lock);
3958}
3959
3960static void
3961bttv_irq_switch_vbi(struct bttv *btv)
3962{
3963 struct bttv_buffer *new = NULL;
3964 struct bttv_buffer *old;
3965 u32 rc;
3966
3967 spin_lock(&btv->s_lock);
3968
3969 if (!list_empty(&btv->vcapture))
3970 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3971 old = btv->cvbi;
3972
3973 rc = btread(BT848_RISC_COUNT);
3974 if (NULL != old && (is_active(&old->top, rc) ||
3975 is_active(&old->bottom, rc))) {
3976 btv->framedrop++;
3977 if (debug_latency)
3978 bttv_irq_debug_low_latency(btv, rc);
3979 spin_unlock(&btv->s_lock);
3980 return;
3981 }
3982
3983 /* switch */
3984 btv->cvbi = new;
3985 btv->loop_irq &= ~4;
3986 bttv_buffer_activate_vbi(btv, new);
3987 bttv_set_dma(btv, 0);
3988
Brandon Philips0fc06862007-11-06 20:02:36 -03003989 bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 spin_unlock(&btv->s_lock);
3991}
3992
David Howells7d12e782006-10-05 14:55:46 +01003993static irqreturn_t bttv_irq(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994{
3995 u32 stat,astat;
3996 u32 dstat;
3997 int count;
3998 struct bttv *btv;
3999 int handled = 0;
4000
4001 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08004002
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004003 if (btv->custom_irq)
4004 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08004005
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 count=0;
4007 while (1) {
4008 /* get/clear interrupt status bits */
4009 stat=btread(BT848_INT_STAT);
4010 astat=stat&btread(BT848_INT_MASK);
4011 if (!astat)
4012 break;
4013 handled = 1;
4014 btwrite(stat,BT848_INT_STAT);
4015
4016 /* get device status bits */
4017 dstat=btread(BT848_DSTATUS);
4018
4019 if (irq_debug) {
4020 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
4021 "riscs=%x, riscc=%08x, ",
4022 btv->c.nr, count, btv->field_count,
4023 stat>>28, btread(BT848_RISC_COUNT));
4024 bttv_print_irqbits(stat,astat);
4025 if (stat & BT848_INT_HLOCK)
4026 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
4027 ? "yes" : "no");
4028 if (stat & BT848_INT_VPRES)
4029 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
4030 ? "yes" : "no");
4031 if (stat & BT848_INT_FMTCHG)
4032 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
4033 ? "625" : "525");
4034 printk("\n");
4035 }
4036
4037 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004038 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004040 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004042 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 }
4044
4045 if (astat & BT848_INT_I2CDONE) {
4046 btv->i2c_done = stat;
4047 wake_up(&btv->i2c_queue);
4048 }
4049
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004050 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 bttv_irq_switch_vbi(btv);
4052
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004053 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 bttv_irq_wakeup_top(btv);
4055
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004056 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 bttv_irq_switch_video(btv);
4058
4059 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004060 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061
4062 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
4063 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
4064 (astat & BT848_INT_SCERR) ? "SCERR" : "",
4065 (astat & BT848_INT_OCERR) ? "OCERR" : "",
4066 btread(BT848_RISC_COUNT));
4067 bttv_print_irqbits(stat,astat);
4068 printk("\n");
4069 if (bttv_debug)
4070 bttv_print_riscaddr(btv);
4071 }
4072 if (fdsr && astat & BT848_INT_FDSR) {
4073 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
4074 btv->c.nr,btread(BT848_RISC_COUNT));
4075 if (bttv_debug)
4076 bttv_print_riscaddr(btv);
4077 }
4078
4079 count++;
4080 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004081
4082 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004083 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004084
4085 printk(KERN_ERR
4086 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
4087 } else {
4088 printk(KERN_ERR
4089 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
4090
4091 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
4092 BT848_INT_MASK);
4093 };
4094
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004096
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097 printk("]\n");
4098 }
4099 }
4100 btv->irq_total++;
4101 if (handled)
4102 btv->irq_me++;
4103 return IRQ_RETVAL(handled);
4104}
4105
4106
4107/* ----------------------------------------------------------------------- */
4108/* initialitation */
4109
4110static struct video_device *vdev_init(struct bttv *btv,
4111 struct video_device *template,
4112 char *type)
4113{
4114 struct video_device *vfd;
4115
4116 vfd = video_device_alloc();
4117 if (NULL == vfd)
4118 return NULL;
4119 *vfd = *template;
4120 vfd->minor = -1;
4121 vfd->dev = &btv->c.pci->dev;
4122 vfd->release = video_device_release;
4123 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
4124 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
4125 type, bttv_tvcards[btv->c.type].name);
4126 return vfd;
4127}
4128
4129static void bttv_unregister_video(struct bttv *btv)
4130{
4131 if (btv->video_dev) {
4132 if (-1 != btv->video_dev->minor)
4133 video_unregister_device(btv->video_dev);
4134 else
4135 video_device_release(btv->video_dev);
4136 btv->video_dev = NULL;
4137 }
4138 if (btv->vbi_dev) {
4139 if (-1 != btv->vbi_dev->minor)
4140 video_unregister_device(btv->vbi_dev);
4141 else
4142 video_device_release(btv->vbi_dev);
4143 btv->vbi_dev = NULL;
4144 }
4145 if (btv->radio_dev) {
4146 if (-1 != btv->radio_dev->minor)
4147 video_unregister_device(btv->radio_dev);
4148 else
4149 video_device_release(btv->radio_dev);
4150 btv->radio_dev = NULL;
4151 }
4152}
4153
4154/* register video4linux devices */
4155static int __devinit bttv_register_video(struct bttv *btv)
4156{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07004157 if (no_overlay <= 0) {
4158 bttv_video_template.type |= VID_TYPE_OVERLAY;
4159 } else {
4160 printk("bttv: Overlay support disabled.\n");
4161 }
4162
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 /* video */
4164 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004165 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 goto err;
4167 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
4168 goto err;
4169 printk(KERN_INFO "bttv%d: registered device video%d\n",
4170 btv->c.nr,btv->video_dev->minor & 0x1f);
Kay Sievers54bd5b62007-10-08 16:26:13 -03004171 if (device_create_file(&btv->video_dev->class_dev,
4172 &dev_attr_card)<0) {
4173 printk(KERN_ERR "bttv%d: device_create_file 'card' "
Trent Piephod94fc9a2006-07-29 17:18:06 -03004174 "failed\n", btv->c.nr);
4175 goto err;
4176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177
4178 /* vbi */
4179 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004180 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004182 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 goto err;
4184 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
4185 btv->c.nr,btv->vbi_dev->minor & 0x1f);
4186
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004187 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 return 0;
4189 /* radio */
4190 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004191 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 goto err;
4193 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
4194 goto err;
4195 printk(KERN_INFO "bttv%d: registered device radio%d\n",
4196 btv->c.nr,btv->radio_dev->minor & 0x1f);
4197
4198 /* all done */
4199 return 0;
4200
4201 err:
4202 bttv_unregister_video(btv);
4203 return -1;
4204}
4205
4206
4207/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
4208/* response on cards with no firmware is not enabled by OF */
4209static void pci_set_command(struct pci_dev *dev)
4210{
4211#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004212 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004214 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
4215 cmd = (cmd | PCI_COMMAND_MEMORY );
4216 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217#endif
4218}
4219
4220static int __devinit bttv_probe(struct pci_dev *dev,
4221 const struct pci_device_id *pci_id)
4222{
4223 int result;
4224 unsigned char lat;
4225 struct bttv *btv;
4226
4227 if (bttv_num == BTTV_MAX)
4228 return -ENOMEM;
4229 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004230 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 memset(btv,0,sizeof(*btv));
4232 btv->c.nr = bttv_num;
4233 sprintf(btv->c.name,"bttv%d",btv->c.nr);
4234
4235 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02004236 mutex_init(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004237 spin_lock_init(&btv->s_lock);
4238 spin_lock_init(&btv->gpio_lock);
4239 init_waitqueue_head(&btv->gpioq);
4240 init_waitqueue_head(&btv->i2c_queue);
4241 INIT_LIST_HEAD(&btv->c.subs);
4242 INIT_LIST_HEAD(&btv->capture);
4243 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 v4l2_prio_init(&btv->prio);
4245
4246 init_timer(&btv->timeout);
4247 btv->timeout.function = bttv_irq_timeout;
4248 btv->timeout.data = (unsigned long)btv;
4249
Michael Krufky7c08fb02005-11-08 21:36:21 -08004250 btv->i2c_rc = -1;
4251 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 btv->has_radio=radio[btv->c.nr];
4254
4255 /* pci stuff (init, get irq/mmio, ... */
4256 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08004257 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08004259 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 btv->c.nr);
4261 return -EIO;
4262 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004263 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
4264 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 btv->c.nr);
4266 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 if (!request_mem_region(pci_resource_start(dev,0),
4269 pci_resource_len(dev,0),
4270 btv->c.name)) {
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004271 printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
4272 btv->c.nr,
4273 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 return -EBUSY;
4275 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004276 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 pci_set_command(dev);
4278 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004280 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
4281 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
4282 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
4283 bttv_num,btv->id, btv->revision, pci_name(dev));
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004284 printk("irq: %d, latency: %d, mmio: 0x%llx\n",
4285 btv->c.pci->irq, lat,
4286 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 schedule();
4288
Akinobu Mita5f1693f2006-12-20 10:08:56 -03004289 btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
4290 if (NULL == btv->bt848_mmio) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4292 result = -EIO;
4293 goto fail1;
4294 }
4295
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004296 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 bttv_idcard(btv);
4298
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004299 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004301 result = request_irq(btv->c.pci->irq, bttv_irq,
Thomas Gleixner8076fe32006-07-01 19:29:37 -07004302 IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004303 if (result < 0) {
4304 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 bttv_num,btv->c.pci->irq);
4306 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308
4309 if (0 != bttv_handle_chipset(btv)) {
4310 result = -EIO;
4311 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313
4314 /* init options from insmod args */
4315 btv->opt_combfilter = combfilter;
4316 btv->opt_lumafilter = lumafilter;
4317 btv->opt_automute = automute;
4318 btv->opt_chroma_agc = chroma_agc;
4319 btv->opt_adc_crush = adc_crush;
4320 btv->opt_vcr_hack = vcr_hack;
4321 btv->opt_whitecrush_upper = whitecrush_upper;
4322 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004323 btv->opt_uv_ratio = uv_ratio;
4324 btv->opt_full_luma_range = full_luma_range;
4325 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326
4327 /* fill struct bttv with some useful defaults */
4328 btv->init.btv = btv;
4329 btv->init.ov.w.width = 320;
4330 btv->init.ov.w.height = 240;
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03004331 btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 btv->init.width = 320;
4333 btv->init.height = 240;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 btv->input = 0;
4335
4336 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004337 if (bttv_gpio)
4338 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
4340 bttv_risc_init_main(btv);
4341 init_bt848(btv);
4342
4343 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004344 btwrite(0x00, BT848_GPIO_REG_INP);
4345 btwrite(0x00, BT848_GPIO_OUT_EN);
4346 if (bttv_verbose)
4347 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004349 /* needs to be done before i2c is registered */
4350 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004352 /* register i2c + gpio */
4353 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004355 /* some card-specific stuff (needs working i2c) */
4356 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 init_irqreg(btv);
4358
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004359 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 if (!bttv_tvcards[btv->c.type].no_video) {
4361 bttv_register_video(btv);
4362 bt848_bright(btv,32768);
4363 bt848_contrast(btv,32768);
4364 bt848_hue(btv,32768);
4365 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004366 audio_mute(btv, 1);
Trent Piepho333408f2007-07-03 15:08:10 -03004367 set_input(btv, 0, btv->tvnorm);
Michael Schimeke5bd0262007-01-18 16:17:39 -03004368 bttv_crop_reset(&btv->crop[0], btv->tvnorm);
4369 btv->crop[1] = btv->crop[0]; /* current = default */
4370 disclaim_vbi_lines(btv);
4371 disclaim_video_lines(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 }
4373
Jarod Wilsonf992a492007-03-24 15:23:50 -03004374 /* add subdevices and autoload dvb-bt8xx if needed */
4375 if (bttv_tvcards[btv->c.type].has_dvb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 bttv_sub_add_device(&btv->c, "dvb");
Jarod Wilsonf992a492007-03-24 15:23:50 -03004377 request_modules(btv);
4378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004380 bttv_input_init(btv);
4381
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 /* everything is fine */
4383 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004384 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
4386 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004387 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388
4389 fail1:
4390 if (btv->bt848_mmio)
4391 iounmap(btv->bt848_mmio);
4392 release_mem_region(pci_resource_start(btv->c.pci,0),
4393 pci_resource_len(btv->c.pci,0));
4394 pci_set_drvdata(dev,NULL);
4395 return result;
4396}
4397
4398static void __devexit bttv_remove(struct pci_dev *pci_dev)
4399{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004400 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401
4402 if (bttv_verbose)
4403 printk("bttv%d: unloading\n",btv->c.nr);
4404
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004405 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 btand(~15, BT848_GPIO_DMA_CTL);
4407 btwrite(0, BT848_INT_MASK);
4408 btwrite(~0x0, BT848_INT_STAT);
4409 btwrite(0x0, BT848_GPIO_OUT_EN);
4410 if (bttv_gpio)
4411 bttv_gpio_tracking(btv,"cleanup");
4412
4413 /* tell gpio modules we are leaving ... */
4414 btv->shutdown=1;
4415 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004416 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004417 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004419 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 fini_bttv_i2c(btv);
4421
4422 /* unregister video4linux */
4423 bttv_unregister_video(btv);
4424
4425 /* free allocated memory */
4426 btcx_riscmem_free(btv->c.pci,&btv->main);
4427
4428 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004429 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004431 release_mem_region(pci_resource_start(btv->c.pci,0),
4432 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
4434 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004435 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436}
4437
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004438#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4440{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004441 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 struct bttv_buffer_set idle;
4443 unsigned long flags;
4444
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004445 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446
4447 /* stop dma + irqs */
4448 spin_lock_irqsave(&btv->s_lock,flags);
4449 memset(&idle, 0, sizeof(idle));
4450 btv->state.video = btv->curr;
4451 btv->state.vbi = btv->cvbi;
4452 btv->state.loop_irq = btv->loop_irq;
4453 btv->curr = idle;
4454 btv->loop_irq = 0;
4455 bttv_buffer_activate_video(btv, &idle);
4456 bttv_buffer_activate_vbi(btv, NULL);
4457 bttv_set_dma(btv, 0);
4458 btwrite(0, BT848_INT_MASK);
4459 spin_unlock_irqrestore(&btv->s_lock,flags);
4460
4461 /* save bt878 state */
4462 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4463 btv->state.gpio_data = gpio_read();
4464
4465 /* save pci state */
4466 pci_save_state(pci_dev);
4467 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4468 pci_disable_device(pci_dev);
4469 btv->state.disabled = 1;
4470 }
4471 return 0;
4472}
4473
4474static int bttv_resume(struct pci_dev *pci_dev)
4475{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004476 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004478 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479
4480 dprintk("bttv%d: resume\n", btv->c.nr);
4481
4482 /* restore pci state */
4483 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004484 err=pci_enable_device(pci_dev);
4485 if (err) {
4486 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4487 btv->c.nr);
4488 return err;
4489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 btv->state.disabled = 0;
4491 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004492 err=pci_set_power_state(pci_dev, PCI_D0);
4493 if (err) {
4494 pci_disable_device(pci_dev);
4495 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4496 btv->c.nr);
4497 btv->state.disabled = 1;
4498 return err;
4499 }
4500
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 pci_restore_state(pci_dev);
4502
4503 /* restore bt878 state */
4504 bttv_reinit_bt848(btv);
4505 gpio_inout(0xffffff, btv->state.gpio_enable);
4506 gpio_write(btv->state.gpio_data);
4507
4508 /* restart dma */
4509 spin_lock_irqsave(&btv->s_lock,flags);
4510 btv->curr = btv->state.video;
4511 btv->cvbi = btv->state.vbi;
4512 btv->loop_irq = btv->state.loop_irq;
4513 bttv_buffer_activate_video(btv, &btv->curr);
4514 bttv_buffer_activate_vbi(btv, btv->cvbi);
4515 bttv_set_dma(btv, 0);
4516 spin_unlock_irqrestore(&btv->s_lock,flags);
4517 return 0;
4518}
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004519#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
4521static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004522 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4523 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004525 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004527 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004529 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4530 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531};
4532
4533MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4534
4535static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004536 .name = "bttv",
4537 .id_table = bttv_pci_tbl,
4538 .probe = bttv_probe,
4539 .remove = __devexit_p(bttv_remove),
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004540#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 .suspend = bttv_suspend,
4542 .resume = bttv_resume,
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004543#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544};
4545
Adrian Bunk7d44e892007-12-11 19:23:43 -03004546static int __init bttv_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547{
Randy Dunlapc526e222006-07-15 09:08:26 -03004548 int ret;
4549
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 bttv_num = 0;
4551
4552 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4553 (BTTV_VERSION_CODE >> 16) & 0xff,
4554 (BTTV_VERSION_CODE >> 8) & 0xff,
4555 BTTV_VERSION_CODE & 0xff);
4556#ifdef SNAPSHOT
4557 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4558 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4559#endif
4560 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4561 gbuffers = 2;
4562 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4563 gbufsize = BTTV_MAX_FBUF;
4564 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4565 if (bttv_verbose)
4566 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4567 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4568
4569 bttv_check_chipset();
4570
Randy Dunlapc526e222006-07-15 09:08:26 -03004571 ret = bus_register(&bttv_sub_bus_type);
4572 if (ret < 0) {
4573 printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
4574 return ret;
4575 }
Akinobu Mita9e7e85e2007-12-17 14:26:29 -03004576 ret = pci_register_driver(&bttv_pci_driver);
4577 if (ret < 0)
4578 bus_unregister(&bttv_sub_bus_type);
4579
4580 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581}
4582
Adrian Bunk7d44e892007-12-11 19:23:43 -03004583static void __exit bttv_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584{
4585 pci_unregister_driver(&bttv_pci_driver);
4586 bus_unregister(&bttv_sub_bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587}
4588
4589module_init(bttv_init_module);
4590module_exit(bttv_cleanup_module);
4591
4592/*
4593 * Local variables:
4594 * c-basic-offset: 8
4595 * End:
4596 */