blob: 13221da6e40f7211346ac5b7e9b6f6904ad280cd [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 */
479static const struct bttv_format bttv_formats[] = {
480 {
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};
612static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
613
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
790/* ----------------------------------------------------------------------- */
791/* resource management */
792
Michael Schimeke5bd0262007-01-18 16:17:39 -0300793/*
794 RESOURCE_ allocated by freed by
795
796 VIDEO_READ bttv_read 1) bttv_read 2)
797
798 VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
799 VIDIOC_QBUF 1) bttv_release
800 VIDIOCMCAPTURE 1)
801
802 OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
803 VIDIOC_OVERLAY on VIDIOC_OVERLAY off
804 3) bttv_release
805
806 VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
807 VIDIOC_QBUF 1) bttv_release
808 bttv_read, bttv_poll 1) 4)
809
810 1) The resource must be allocated when we enter buffer prepare functions
811 and remain allocated while buffers are in the DMA queue.
812 2) This is a single frame read.
813 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
814 RESOURCE_OVERLAY is allocated.
815 4) This is a continuous read, implies VIDIOC_STREAMON.
816
817 Note this driver permits video input and standard changes regardless if
818 resources are allocated.
819*/
820
821#define VBI_RESOURCES (RESOURCE_VBI)
822#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
823 RESOURCE_VIDEO_STREAM | \
824 RESOURCE_OVERLAY)
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826static
827int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
828{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300829 int xbits; /* mutual exclusive resources */
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (fh->resources & bit)
832 /* have it already allocated */
833 return 1;
834
Michael Schimeke5bd0262007-01-18 16:17:39 -0300835 xbits = bit;
836 if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
837 xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 /* is it free? */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300840 mutex_lock(&btv->lock);
841 if (btv->resources & xbits) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 /* no, someone else uses it */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300843 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300845
846 if ((bit & VIDEO_RESOURCES)
847 && 0 == (btv->resources & VIDEO_RESOURCES)) {
848 /* Do crop - use current, don't - use default parameters. */
849 __s32 top = btv->crop[!!fh->do_crop].rect.top;
850
851 if (btv->vbi_end > top)
852 goto fail;
853
854 /* We cannot capture the same line as video and VBI data.
855 Claim scan lines crop[].rect.top to bottom. */
856 btv->crop_start = top;
857 } else if (bit & VBI_RESOURCES) {
858 __s32 end = fh->vbi_fmt.end;
859
860 if (end > btv->crop_start)
861 goto fail;
862
863 /* Claim scan lines above fh->vbi_fmt.end. */
864 btv->vbi_end = end;
865 }
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* it's free, grab it */
868 fh->resources |= bit;
869 btv->resources |= bit;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300870 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return 1;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300872
873 fail:
874 mutex_unlock(&btv->lock);
875 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878static
879int check_btres(struct bttv_fh *fh, int bit)
880{
881 return (fh->resources & bit);
882}
883
884static
885int locked_btres(struct bttv *btv, int bit)
886{
887 return (btv->resources & bit);
888}
889
Michael Schimeke5bd0262007-01-18 16:17:39 -0300890/* Call with btv->lock down. */
891static void
892disclaim_vbi_lines(struct bttv *btv)
893{
894 btv->vbi_end = 0;
895}
896
897/* Call with btv->lock down. */
898static void
899disclaim_video_lines(struct bttv *btv)
900{
901 const struct bttv_tvnorm *tvnorm;
902 u8 crop;
903
904 tvnorm = &bttv_tvnorms[btv->tvnorm];
905 btv->crop_start = tvnorm->cropcap.bounds.top
906 + tvnorm->cropcap.bounds.height;
907
908 /* VBI capturing ends at VDELAY, start of video capturing, no
909 matter how many lines the VBI RISC program expects. When video
910 capturing is off, it shall no longer "preempt" VBI capturing,
911 so we set VDELAY to maximum. */
912 crop = btread(BT848_E_CROP) | 0xc0;
913 btwrite(crop, BT848_E_CROP);
914 btwrite(0xfe, BT848_E_VDELAY_LO);
915 btwrite(crop, BT848_O_CROP);
916 btwrite(0xfe, BT848_O_VDELAY_LO);
917}
918
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919static
920void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
921{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 if ((fh->resources & bits) != bits) {
923 /* trying to free ressources not allocated by us ... */
924 printk("bttv: BUG! (btres)\n");
925 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300926 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 fh->resources &= ~bits;
928 btv->resources &= ~bits;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300929
930 bits = btv->resources;
931
932 if (0 == (bits & VIDEO_RESOURCES))
933 disclaim_video_lines(btv);
934
935 if (0 == (bits & VBI_RESOURCES))
936 disclaim_vbi_lines(btv);
937
938 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939}
940
941/* ----------------------------------------------------------------------- */
942/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
943
944/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
945 PLL_X = Reference pre-divider (0=1, 1=2)
946 PLL_C = Post divider (0=6, 1=4)
947 PLL_I = Integer input
948 PLL_F = Fractional input
949
950 F_input = 28.636363 MHz:
951 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
952*/
953
954static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
955{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800956 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800958 /* prevent overflows */
959 fin/=4;
960 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800962 fout*=12;
963 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800965 fout=(fout%fin)*256;
966 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800968 fout=(fout%fin)*256;
969 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800971 btwrite(fl, BT848_PLL_F_LO);
972 btwrite(fh, BT848_PLL_F_HI);
973 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
976static void set_pll(struct bttv *btv)
977{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800978 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800980 if (!btv->pll.pll_crystal)
981 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
984 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800985 return;
986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800988 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
989 /* no PLL needed */
990 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800991 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700992 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800993 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800994 btwrite(0x00,BT848_TGCTRL);
995 btwrite(0x00,BT848_PLL_XCI);
996 btv->pll.pll_current = 0;
997 return;
998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001000 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001001 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
1003
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001004 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001006 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 msleep(10);
1008
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001009 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001011 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001012 btwrite(0x08,BT848_TGCTRL);
1013 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001014 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001015 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001016 }
1017 }
1018 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001019 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001020 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021}
1022
1023/* used to switch between the bt848's analog/digital video capture modes */
1024static void bt848A_set_timing(struct bttv *btv)
1025{
1026 int i, len;
1027 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
1028 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
1029
1030 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
1031 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
1032 btv->c.nr,table_idx);
1033
1034 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001035 btwrite(0x00, BT848_TGCTRL);
1036 btwrite(0x02, BT848_TGCTRL);
1037 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 len=SRAM_Table[table_idx][0];
1040 for(i = 1; i <= len; i++)
1041 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
1042 btv->pll.pll_ofreq = 27000000;
1043
1044 set_pll(btv);
1045 btwrite(0x11, BT848_TGCTRL);
1046 btwrite(0x41, BT848_DVSIF);
1047 } else {
1048 btv->pll.pll_ofreq = fsc;
1049 set_pll(btv);
1050 btwrite(0x0, BT848_DVSIF);
1051 }
1052}
1053
1054/* ----------------------------------------------------------------------- */
1055
1056static void bt848_bright(struct bttv *btv, int bright)
1057{
1058 int value;
1059
1060 // printk("bttv: set bright: %d\n",bright); // DEBUG
1061 btv->bright = bright;
1062
1063 /* We want -128 to 127 we get 0-65535 */
1064 value = (bright >> 8) - 128;
1065 btwrite(value & 0xff, BT848_BRIGHT);
1066}
1067
1068static void bt848_hue(struct bttv *btv, int hue)
1069{
1070 int value;
1071
1072 btv->hue = hue;
1073
1074 /* -128 to 127 */
1075 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001076 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077}
1078
1079static void bt848_contrast(struct bttv *btv, int cont)
1080{
1081 int value,hibit;
1082
1083 btv->contrast = cont;
1084
1085 /* 0-511 */
1086 value = (cont >> 7);
1087 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001088 btwrite(value & 0xff, BT848_CONTRAST_LO);
1089 btaor(hibit, ~4, BT848_E_CONTROL);
1090 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091}
1092
1093static void bt848_sat(struct bttv *btv, int color)
1094{
1095 int val_u,val_v,hibits;
1096
1097 btv->saturation = color;
1098
1099 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001100 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
1101 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001102 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001104 btwrite(val_u & 0xff, BT848_SAT_U_LO);
1105 btwrite(val_v & 0xff, BT848_SAT_V_LO);
1106 btaor(hibits, ~3, BT848_E_CONTROL);
1107 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
1110/* ----------------------------------------------------------------------- */
1111
1112static int
1113video_mux(struct bttv *btv, unsigned int input)
1114{
1115 int mux,mask2;
1116
1117 if (input >= bttv_tvcards[btv->c.type].video_inputs)
1118 return -EINVAL;
1119
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001120 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
1122 if (mask2)
1123 gpio_inout(mask2,mask2);
1124
1125 if (input == btv->svhs) {
1126 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
1127 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
1128 } else {
1129 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
1130 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
1131 }
1132 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
1133 btaor(mux<<5, ~(3<<5), BT848_IFORM);
1134 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
1135 btv->c.nr,input,mux);
1136
1137 /* card specific hook */
1138 if(bttv_tvcards[btv->c.type].muxsel_hook)
1139 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
1140 return 0;
1141}
1142
1143static char *audio_modes[] = {
1144 "audio: tuner", "audio: radio", "audio: extern",
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001145 "audio: intern", "audio: mute"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146};
1147
1148static int
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001149audio_mux(struct bttv *btv, int input, int mute)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150{
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001151 int gpio_val, signal;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001152 struct v4l2_control ctrl;
1153 struct i2c_client *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
1155 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
1156 bttv_tvcards[btv->c.type].gpiomask);
1157 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
1158
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001159 btv->mute = mute;
1160 btv->audio = input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001162 /* automute */
1163 mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
1164
1165 if (mute)
1166 gpio_val = bttv_tvcards[btv->c.type].gpiomute;
1167 else
1168 gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001169
1170 gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (bttv_gpio)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001172 bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
1173 if (in_interrupt())
1174 return 0;
1175
1176 ctrl.id = V4L2_CID_AUDIO_MUTE;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001177 ctrl.value = btv->mute;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001178 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
1179 c = btv->i2c_msp34xx_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001180 if (c) {
1181 struct v4l2_routing route;
1182
1183 /* Note: the inputs tuner/radio/extern/intern are translated
1184 to msp routings. This assumes common behavior for all msp3400
1185 based TV cards. When this assumption fails, then the
1186 specific MSP routing must be added to the card table.
1187 For now this is sufficient. */
1188 switch (input) {
1189 case TVAUDIO_INPUT_RADIO:
Hans Verkuil07151722006-04-01 18:03:23 -03001190 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1191 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001192 break;
1193 case TVAUDIO_INPUT_EXTERN:
Hans Verkuil07151722006-04-01 18:03:23 -03001194 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
1195 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001196 break;
1197 case TVAUDIO_INPUT_INTERN:
1198 /* Yes, this is the same input as for RADIO. I doubt
1199 if this is ever used. The only board with an INTERN
1200 input is the BTTV_BOARD_AVERMEDIA98. I wonder how
1201 that was tested. My guess is that the whole INTERN
1202 input does not work. */
Hans Verkuil07151722006-04-01 18:03:23 -03001203 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1204 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001205 break;
1206 case TVAUDIO_INPUT_TUNER:
1207 default:
Wade Berrier434b2522007-06-25 13:02:16 -03001208 /* This is the only card that uses TUNER2, and afaik,
1209 is the only difference between the VOODOOTV_FM
1210 and VOODOOTV_200 */
1211 if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
1212 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
1213 MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
1214 else
1215 route.input = MSP_INPUT_DEFAULT;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001216 break;
1217 }
1218 route.output = MSP_OUTPUT_DEFAULT;
1219 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1220 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001221 c = btv->i2c_tvaudio_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001222 if (c) {
1223 struct v4l2_routing route;
1224
1225 route.input = input;
1226 route.output = 0;
1227 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return 0;
1230}
1231
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001232static inline int
1233audio_mute(struct bttv *btv, int mute)
1234{
1235 return audio_mux(btv, btv->audio, mute);
1236}
1237
1238static inline int
1239audio_input(struct bttv *btv, int input)
1240{
1241 return audio_mux(btv, input, btv->mute);
1242}
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244static void
Michael Schimeke5bd0262007-01-18 16:17:39 -03001245bttv_crop_calc_limits(struct bttv_crop *c)
1246{
1247 /* Scale factor min. 1:1, max. 16:1. Min. image size
1248 48 x 32. Scaled width must be a multiple of 4. */
1249
1250 if (1) {
1251 /* For bug compatibility with VIDIOCGCAP and image
1252 size checks in earlier driver versions. */
1253 c->min_scaled_width = 48;
1254 c->min_scaled_height = 32;
1255 } else {
1256 c->min_scaled_width =
1257 (max(48, c->rect.width >> 4) + 3) & ~3;
1258 c->min_scaled_height =
1259 max(32, c->rect.height >> 4);
1260 }
1261
1262 c->max_scaled_width = c->rect.width & ~3;
1263 c->max_scaled_height = c->rect.height;
1264}
1265
1266static void
1267bttv_crop_reset(struct bttv_crop *c, int norm)
1268{
1269 c->rect = bttv_tvnorms[norm].cropcap.defrect;
1270 bttv_crop_calc_limits(c);
1271}
1272
1273/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274static int
1275set_tvnorm(struct bttv *btv, unsigned int norm)
1276{
1277 const struct bttv_tvnorm *tvnorm;
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001278 v4l2_std_id id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280 if (norm < 0 || norm >= BTTV_TVNORMS)
1281 return -EINVAL;
1282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 tvnorm = &bttv_tvnorms[norm];
1284
Michael Schimeke5bd0262007-01-18 16:17:39 -03001285 if (btv->tvnorm < 0 ||
1286 btv->tvnorm >= BTTV_TVNORMS ||
1287 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
1288 &tvnorm->cropcap,
1289 sizeof (tvnorm->cropcap))) {
1290 bttv_crop_reset(&btv->crop[0], norm);
1291 btv->crop[1] = btv->crop[0]; /* current = default */
1292
1293 if (0 == (btv->resources & VIDEO_RESOURCES)) {
1294 btv->crop_start = tvnorm->cropcap.bounds.top
1295 + tvnorm->cropcap.bounds.height;
1296 }
1297 }
1298
1299 btv->tvnorm = norm;
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 btwrite(tvnorm->adelay, BT848_ADELAY);
1302 btwrite(tvnorm->bdelay, BT848_BDELAY);
1303 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1304 BT848_IFORM);
1305 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1306 btwrite(1, BT848_VBI_PACK_DEL);
1307 bt848A_set_timing(btv);
1308
1309 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001310 case BTTV_BOARD_VOODOOTV_FM:
Wade Berrier434b2522007-06-25 13:02:16 -03001311 case BTTV_BOARD_VOODOOTV_200:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 bttv_tda9880_setnorm(btv,norm);
1313 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001315 id = tvnorm->v4l2_id;
1316 bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
1317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 return 0;
1319}
1320
Michael Schimeke5bd0262007-01-18 16:17:39 -03001321/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322static void
Trent Piepho333408f2007-07-03 15:08:10 -03001323set_input(struct bttv *btv, unsigned int input, unsigned int norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324{
1325 unsigned long flags;
1326
1327 btv->input = input;
1328 if (irq_iswitch) {
1329 spin_lock_irqsave(&btv->s_lock,flags);
1330 if (btv->curr.frame_irq) {
1331 /* active capture -> delayed input switch */
1332 btv->new_input = input;
1333 } else {
1334 video_mux(btv,input);
1335 }
1336 spin_unlock_irqrestore(&btv->s_lock,flags);
1337 } else {
1338 video_mux(btv,input);
1339 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001340 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1341 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Trent Piepho333408f2007-07-03 15:08:10 -03001342 set_tvnorm(btv, norm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343}
1344
1345static void init_irqreg(struct bttv *btv)
1346{
1347 /* clear status */
1348 btwrite(0xfffffUL, BT848_INT_STAT);
1349
1350 if (bttv_tvcards[btv->c.type].no_video) {
1351 /* i2c only */
1352 btwrite(BT848_INT_I2CDONE,
1353 BT848_INT_MASK);
1354 } else {
1355 /* full video */
1356 btwrite((btv->triton1) |
1357 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1358 BT848_INT_SCERR |
1359 (fdsr ? BT848_INT_FDSR : 0) |
1360 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1361 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1362 BT848_INT_I2CDONE,
1363 BT848_INT_MASK);
1364 }
1365}
1366
1367static void init_bt848(struct bttv *btv)
1368{
1369 int val;
1370
1371 if (bttv_tvcards[btv->c.type].no_video) {
1372 /* very basic init only */
1373 init_irqreg(btv);
1374 return;
1375 }
1376
1377 btwrite(0x00, BT848_CAP_CTL);
1378 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1379 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1380
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001381 /* set planar and packed mode trigger points and */
1382 /* set rising edge of inverted GPINTR pin as irq trigger */
1383 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1384 BT848_GPIO_DMA_CTL_PLTP1_16|
1385 BT848_GPIO_DMA_CTL_PLTP23_16|
1386 BT848_GPIO_DMA_CTL_GPINTC|
1387 BT848_GPIO_DMA_CTL_GPINTI,
1388 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001391 btwrite(val, BT848_E_SCLOOP);
1392 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001394 btwrite(0x20, BT848_E_VSCALE_HI);
1395 btwrite(0x20, BT848_O_VSCALE_HI);
1396 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 BT848_ADC);
1398
1399 btwrite(whitecrush_upper, BT848_WC_UP);
1400 btwrite(whitecrush_lower, BT848_WC_DOWN);
1401
1402 if (btv->opt_lumafilter) {
1403 btwrite(0, BT848_E_CONTROL);
1404 btwrite(0, BT848_O_CONTROL);
1405 } else {
1406 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1407 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1408 }
1409
1410 bt848_bright(btv, btv->bright);
1411 bt848_hue(btv, btv->hue);
1412 bt848_contrast(btv, btv->contrast);
1413 bt848_sat(btv, btv->saturation);
1414
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001415 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 init_irqreg(btv);
1417}
1418
1419static void bttv_reinit_bt848(struct bttv *btv)
1420{
1421 unsigned long flags;
1422
1423 if (bttv_verbose)
1424 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1425 spin_lock_irqsave(&btv->s_lock,flags);
1426 btv->errors=0;
1427 bttv_set_dma(btv,0);
1428 spin_unlock_irqrestore(&btv->s_lock,flags);
1429
1430 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001431 btv->pll.pll_current = -1;
Trent Piepho333408f2007-07-03 15:08:10 -03001432 set_input(btv, btv->input, btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433}
1434
1435static int get_control(struct bttv *btv, struct v4l2_control *c)
1436{
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001437#ifdef CONFIG_VIDEO_V4L1
Nickolay V. Shmyrev40c6e682007-10-26 17:21:30 -03001438 if (btv->audio_hook && (c->id == V4L2_CID_AUDIO_VOLUME)) {
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001439 struct video_audio va;
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001442 btv->audio_hook(btv,&va,0);
1443 switch (c->id) {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001444 case V4L2_CID_AUDIO_VOLUME:
1445 c->value = va.volume;
1446 break;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001447 }
1448 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001450#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 switch (c->id) {
1452 case V4L2_CID_BRIGHTNESS:
1453 c->value = btv->bright;
1454 break;
1455 case V4L2_CID_HUE:
1456 c->value = btv->hue;
1457 break;
1458 case V4L2_CID_CONTRAST:
1459 c->value = btv->contrast;
1460 break;
1461 case V4L2_CID_SATURATION:
1462 c->value = btv->saturation;
1463 break;
1464
1465 case V4L2_CID_AUDIO_MUTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001470 bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 break;
1472
1473 case V4L2_CID_PRIVATE_CHROMA_AGC:
1474 c->value = btv->opt_chroma_agc;
1475 break;
1476 case V4L2_CID_PRIVATE_COMBFILTER:
1477 c->value = btv->opt_combfilter;
1478 break;
1479 case V4L2_CID_PRIVATE_LUMAFILTER:
1480 c->value = btv->opt_lumafilter;
1481 break;
1482 case V4L2_CID_PRIVATE_AUTOMUTE:
1483 c->value = btv->opt_automute;
1484 break;
1485 case V4L2_CID_PRIVATE_AGC_CRUSH:
1486 c->value = btv->opt_adc_crush;
1487 break;
1488 case V4L2_CID_PRIVATE_VCR_HACK:
1489 c->value = btv->opt_vcr_hack;
1490 break;
1491 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1492 c->value = btv->opt_whitecrush_upper;
1493 break;
1494 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1495 c->value = btv->opt_whitecrush_lower;
1496 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001497 case V4L2_CID_PRIVATE_UV_RATIO:
1498 c->value = btv->opt_uv_ratio;
1499 break;
1500 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1501 c->value = btv->opt_full_luma_range;
1502 break;
1503 case V4L2_CID_PRIVATE_CORING:
1504 c->value = btv->opt_coring;
1505 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 default:
1507 return -EINVAL;
1508 }
1509 return 0;
1510}
1511
1512static int set_control(struct bttv *btv, struct v4l2_control *c)
1513{
Nickolay V. Shmyrev40c6e682007-10-26 17:21:30 -03001514 int val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001516#ifdef CONFIG_VIDEO_V4L1
Nickolay V. Shmyrev40c6e682007-10-26 17:21:30 -03001517 if (btv->audio_hook && (c->id == V4L2_CID_AUDIO_VOLUME)) {
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001518 struct video_audio va;
1519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001521 btv->audio_hook(btv,&va,0);
1522 switch (c->id) {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001523 case V4L2_CID_AUDIO_VOLUME:
1524 va.volume = c->value;
1525 break;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001526 }
1527 btv->audio_hook(btv,&va,1);
1528 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001530#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 switch (c->id) {
1532 case V4L2_CID_BRIGHTNESS:
1533 bt848_bright(btv,c->value);
1534 break;
1535 case V4L2_CID_HUE:
1536 bt848_hue(btv,c->value);
1537 break;
1538 case V4L2_CID_CONTRAST:
1539 bt848_contrast(btv,c->value);
1540 break;
1541 case V4L2_CID_SATURATION:
1542 bt848_sat(btv,c->value);
1543 break;
1544 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001545 audio_mute(btv, c->value);
1546 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001551 bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 break;
1553
1554 case V4L2_CID_PRIVATE_CHROMA_AGC:
1555 btv->opt_chroma_agc = c->value;
1556 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1557 btwrite(val, BT848_E_SCLOOP);
1558 btwrite(val, BT848_O_SCLOOP);
1559 break;
1560 case V4L2_CID_PRIVATE_COMBFILTER:
1561 btv->opt_combfilter = c->value;
1562 break;
1563 case V4L2_CID_PRIVATE_LUMAFILTER:
1564 btv->opt_lumafilter = c->value;
1565 if (btv->opt_lumafilter) {
1566 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1567 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1568 } else {
1569 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1570 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1571 }
1572 break;
1573 case V4L2_CID_PRIVATE_AUTOMUTE:
1574 btv->opt_automute = c->value;
1575 break;
1576 case V4L2_CID_PRIVATE_AGC_CRUSH:
1577 btv->opt_adc_crush = c->value;
1578 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1579 BT848_ADC);
1580 break;
1581 case V4L2_CID_PRIVATE_VCR_HACK:
1582 btv->opt_vcr_hack = c->value;
1583 break;
1584 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1585 btv->opt_whitecrush_upper = c->value;
1586 btwrite(c->value, BT848_WC_UP);
1587 break;
1588 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1589 btv->opt_whitecrush_lower = c->value;
1590 btwrite(c->value, BT848_WC_DOWN);
1591 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001592 case V4L2_CID_PRIVATE_UV_RATIO:
1593 btv->opt_uv_ratio = c->value;
1594 bt848_sat(btv, btv->saturation);
1595 break;
1596 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1597 btv->opt_full_luma_range = c->value;
1598 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1599 break;
1600 case V4L2_CID_PRIVATE_CORING:
1601 btv->opt_coring = c->value;
1602 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1603 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 default:
1605 return -EINVAL;
1606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 return 0;
1608}
1609
1610/* ----------------------------------------------------------------------- */
1611
1612void bttv_gpio_tracking(struct bttv *btv, char *comment)
1613{
1614 unsigned int outbits, data;
1615 outbits = btread(BT848_GPIO_OUT_EN);
1616 data = btread(BT848_GPIO_DATA);
1617 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1618 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1619}
1620
1621static void bttv_field_count(struct bttv *btv)
1622{
1623 int need_count = 0;
1624
1625 if (btv->users)
1626 need_count++;
1627
1628 if (need_count) {
1629 /* start field counter */
1630 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1631 } else {
1632 /* stop field counter */
1633 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1634 btv->field_count = 0;
1635 }
1636}
1637
1638static const struct bttv_format*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639format_by_fourcc(int fourcc)
1640{
1641 unsigned int i;
1642
1643 for (i = 0; i < BTTV_FORMATS; i++) {
1644 if (-1 == bttv_formats[i].fourcc)
1645 continue;
1646 if (bttv_formats[i].fourcc == fourcc)
1647 return bttv_formats+i;
1648 }
1649 return NULL;
1650}
1651
1652/* ----------------------------------------------------------------------- */
1653/* misc helpers */
1654
1655static int
1656bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1657 struct bttv_buffer *new)
1658{
1659 struct bttv_buffer *old;
1660 unsigned long flags;
1661 int retval = 0;
1662
1663 dprintk("switch_overlay: enter [new=%p]\n",new);
1664 if (new)
1665 new->vb.state = STATE_DONE;
1666 spin_lock_irqsave(&btv->s_lock,flags);
1667 old = btv->screen;
1668 btv->screen = new;
1669 btv->loop_irq |= 1;
1670 bttv_set_dma(btv, 0x03);
1671 spin_unlock_irqrestore(&btv->s_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (NULL != old) {
1673 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001674 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 kfree(old);
1676 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03001677 if (NULL == new)
1678 free_btres(btv,fh,RESOURCE_OVERLAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 dprintk("switch_overlay: done\n");
1680 return retval;
1681}
1682
1683/* ----------------------------------------------------------------------- */
1684/* video4linux (1) interface */
1685
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001686static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1687 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001688 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 unsigned int width, unsigned int height,
1690 enum v4l2_field field)
1691{
Michael Schimeke5bd0262007-01-18 16:17:39 -03001692 struct bttv_fh *fh = q->priv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 int redo_dma_risc = 0;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001694 struct bttv_crop c;
1695 int norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 int rc;
1697
1698 /* check settings */
1699 if (NULL == fmt)
1700 return -EINVAL;
1701 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1702 width = RAW_BPL;
1703 height = RAW_LINES*2;
1704 if (width*height > buf->vb.bsize)
1705 return -EINVAL;
1706 buf->vb.size = buf->vb.bsize;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001707
1708 /* Make sure tvnorm and vbi_end remain consistent
1709 until we're done. */
1710 mutex_lock(&btv->lock);
1711
1712 norm = btv->tvnorm;
1713
1714 /* In this mode capturing always starts at defrect.top
1715 (default VDELAY), ignoring cropping parameters. */
1716 if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
1717 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001719 }
1720
1721 mutex_unlock(&btv->lock);
1722
1723 c.rect = bttv_tvnorms[norm].cropcap.defrect;
1724 } else {
1725 mutex_lock(&btv->lock);
1726
1727 norm = btv->tvnorm;
1728 c = btv->crop[!!fh->do_crop];
1729
1730 mutex_unlock(&btv->lock);
1731
1732 if (width < c.min_scaled_width ||
1733 width > c.max_scaled_width ||
1734 height < c.min_scaled_height)
1735 return -EINVAL;
1736
1737 switch (field) {
1738 case V4L2_FIELD_TOP:
1739 case V4L2_FIELD_BOTTOM:
1740 case V4L2_FIELD_ALTERNATE:
1741 /* btv->crop counts frame lines. Max. scale
1742 factor is 16:1 for frames, 8:1 for fields. */
1743 if (height * 2 > c.max_scaled_height)
1744 return -EINVAL;
1745 break;
1746
1747 default:
1748 if (height > c.max_scaled_height)
1749 return -EINVAL;
1750 break;
1751 }
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 buf->vb.size = (width * height * fmt->depth) >> 3;
1754 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1755 return -EINVAL;
1756 }
1757
1758 /* alloc + fill struct bttv_buffer (if changed) */
1759 if (buf->vb.width != width || buf->vb.height != height ||
1760 buf->vb.field != field ||
Michael Schimeke5bd0262007-01-18 16:17:39 -03001761 buf->tvnorm != norm || buf->fmt != fmt ||
1762 buf->crop.top != c.rect.top ||
1763 buf->crop.left != c.rect.left ||
1764 buf->crop.width != c.rect.width ||
1765 buf->crop.height != c.rect.height) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 buf->vb.width = width;
1767 buf->vb.height = height;
1768 buf->vb.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001769 buf->tvnorm = norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 buf->fmt = fmt;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001771 buf->crop = c.rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 redo_dma_risc = 1;
1773 }
1774
1775 /* alloc risc memory */
1776 if (STATE_NEEDS_INIT == buf->vb.state) {
1777 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001778 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 goto fail;
1780 }
1781
1782 if (redo_dma_risc)
1783 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1784 goto fail;
1785
1786 buf->vb.state = STATE_PREPARED;
1787 return 0;
1788
1789 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001790 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 return rc;
1792}
1793
1794static int
1795buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1796{
1797 struct bttv_fh *fh = q->priv_data;
1798
1799 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1800 if (0 == *count)
1801 *count = gbuffers;
1802 while (*size * *count > gbuffers * gbufsize)
1803 (*count)--;
1804 return 0;
1805}
1806
1807static int
1808buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1809 enum v4l2_field field)
1810{
1811 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1812 struct bttv_fh *fh = q->priv_data;
1813
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001814 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 fh->width, fh->height, field);
1816}
1817
1818static void
1819buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1820{
1821 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1822 struct bttv_fh *fh = q->priv_data;
1823 struct bttv *btv = fh->btv;
1824
1825 buf->vb.state = STATE_QUEUED;
1826 list_add_tail(&buf->vb.queue,&btv->capture);
1827 if (!btv->curr.frame_irq) {
1828 btv->loop_irq |= 1;
1829 bttv_set_dma(btv, 0x03);
1830 }
1831}
1832
1833static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1834{
1835 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1836 struct bttv_fh *fh = q->priv_data;
1837
Michael Schimekfeaba7a2007-01-26 08:30:05 -03001838 bttv_dma_free(q,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839}
1840
1841static struct videobuf_queue_ops bttv_video_qops = {
1842 .buf_setup = buffer_setup,
1843 .buf_prepare = buffer_prepare,
1844 .buf_queue = buffer_queue,
1845 .buf_release = buffer_release,
1846};
1847
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1849{
1850 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 case VIDIOC_ENUMSTD:
1852 {
1853 struct v4l2_standard *e = arg;
1854 unsigned int index = e->index;
1855
1856 if (index >= BTTV_TVNORMS)
1857 return -EINVAL;
1858 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1859 bttv_tvnorms[e->index].name);
1860 e->index = index;
1861 return 0;
1862 }
1863 case VIDIOC_G_STD:
1864 {
1865 v4l2_std_id *id = arg;
1866 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1867 return 0;
1868 }
1869 case VIDIOC_S_STD:
1870 {
1871 v4l2_std_id *id = arg;
1872 unsigned int i;
1873
1874 for (i = 0; i < BTTV_TVNORMS; i++)
1875 if (*id & bttv_tvnorms[i].v4l2_id)
1876 break;
1877 if (i == BTTV_TVNORMS)
1878 return -EINVAL;
1879
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001880 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 set_tvnorm(btv,i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001882 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 return 0;
1884 }
1885 case VIDIOC_QUERYSTD:
1886 {
1887 v4l2_std_id *id = arg;
1888
1889 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1890 *id = V4L2_STD_625_50;
1891 else
1892 *id = V4L2_STD_525_60;
1893 return 0;
1894 }
1895
1896 case VIDIOC_ENUMINPUT:
1897 {
1898 struct v4l2_input *i = arg;
1899 unsigned int n;
1900
1901 n = i->index;
1902 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1903 return -EINVAL;
1904 memset(i,0,sizeof(*i));
1905 i->index = n;
1906 i->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab5d9d1712006-11-14 12:40:07 -03001907 i->audioset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1909 sprintf(i->name, "Television");
1910 i->type = V4L2_INPUT_TYPE_TUNER;
1911 i->tuner = 0;
1912 } else if (i->index == btv->svhs) {
1913 sprintf(i->name, "S-Video");
1914 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001915 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 }
1917 if (i->index == btv->input) {
1918 __u32 dstatus = btread(BT848_DSTATUS);
1919 if (0 == (dstatus & BT848_DSTATUS_PRES))
1920 i->status |= V4L2_IN_ST_NO_SIGNAL;
1921 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1922 i->status |= V4L2_IN_ST_NO_H_LOCK;
1923 }
1924 for (n = 0; n < BTTV_TVNORMS; n++)
1925 i->std |= bttv_tvnorms[n].v4l2_id;
1926 return 0;
1927 }
1928 case VIDIOC_G_INPUT:
1929 {
1930 int *i = arg;
1931 *i = btv->input;
1932 return 0;
1933 }
1934 case VIDIOC_S_INPUT:
1935 {
1936 unsigned int *i = arg;
1937
1938 if (*i > bttv_tvcards[btv->c.type].video_inputs)
1939 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001940 mutex_lock(&btv->lock);
Trent Piepho333408f2007-07-03 15:08:10 -03001941 set_input(btv, *i, btv->tvnorm);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001942 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 return 0;
1944 }
1945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 case VIDIOC_S_TUNER:
1947 {
1948 struct v4l2_tuner *t = arg;
1949
1950 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1951 return -EINVAL;
1952 if (0 != t->index)
1953 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001954 mutex_lock(&btv->lock);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001955 bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001956#ifdef CONFIG_VIDEO_V4L1
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001957 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 struct video_audio va;
1959 memset(&va, 0, sizeof(struct video_audio));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 if (t->audmode == V4L2_TUNER_MODE_MONO)
1961 va.mode = VIDEO_SOUND_MONO;
Hans Verkuil301e22d2006-03-18 17:15:00 -03001962 else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
1963 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 va.mode = VIDEO_SOUND_STEREO;
1965 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
1966 va.mode = VIDEO_SOUND_LANG1;
1967 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
1968 va.mode = VIDEO_SOUND_LANG2;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001969 btv->audio_hook(btv,&va,1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001971#endif
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001972 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 return 0;
1974 }
1975
1976 case VIDIOC_G_FREQUENCY:
1977 {
1978 struct v4l2_frequency *f = arg;
1979
1980 memset(f,0,sizeof(*f));
1981 f->type = V4L2_TUNER_ANALOG_TV;
1982 f->frequency = btv->freq;
1983 return 0;
1984 }
1985 case VIDIOC_S_FREQUENCY:
1986 {
1987 struct v4l2_frequency *f = arg;
1988
1989 if (unlikely(f->tuner != 0))
1990 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07001991 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001993 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 btv->freq = f->frequency;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001995 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 if (btv->has_matchbox && btv->radio_user)
1997 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001998 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return 0;
2000 }
Hans Verkuil299392b2005-11-08 21:37:42 -08002001 case VIDIOC_LOG_STATUS:
2002 {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002003 printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr);
Luiz Capitulino97cb4452005-12-01 00:51:24 -08002004 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002005 printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
Hans Verkuil299392b2005-11-08 21:37:42 -08002006 return 0;
2007 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002008 case VIDIOC_G_CTRL:
2009 return get_control(btv,arg);
2010 case VIDIOC_S_CTRL:
2011 return set_control(btv,arg);
Trent Piepho55c0d102007-06-29 00:17:36 -03002012#ifdef CONFIG_VIDEO_ADV_DEBUG
2013 case VIDIOC_DBG_G_REGISTER:
2014 case VIDIOC_DBG_S_REGISTER:
2015 {
2016 struct v4l2_register *reg = arg;
2017 if (!capable(CAP_SYS_ADMIN))
2018 return -EPERM;
2019 if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
2020 return -EINVAL;
2021 /* bt848 has a 12-bit register space */
2022 reg->reg &= 0xfff;
2023 if (cmd == VIDIOC_DBG_G_REGISTER)
2024 reg->val = btread(reg->reg);
2025 else
2026 btwrite(reg->val, reg->reg);
2027 return 0;
2028 }
2029#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
2031 default:
2032 return -ENOIOCTLCMD;
2033
2034 }
2035 return 0;
2036}
2037
Michael Schimeke5bd0262007-01-18 16:17:39 -03002038/* Given cropping boundaries b and the scaled width and height of a
2039 single field or frame, which must not exceed hardware limits, this
2040 function adjusts the cropping parameters c. */
2041static void
2042bttv_crop_adjust (struct bttv_crop * c,
2043 const struct v4l2_rect * b,
2044 __s32 width,
2045 __s32 height,
2046 enum v4l2_field field)
2047{
2048 __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
2049 __s32 max_left;
2050 __s32 max_top;
2051
2052 if (width < c->min_scaled_width) {
2053 /* Max. hor. scale factor 16:1. */
2054 c->rect.width = width * 16;
2055 } else if (width > c->max_scaled_width) {
2056 /* Min. hor. scale factor 1:1. */
2057 c->rect.width = width;
2058
2059 max_left = b->left + b->width - width;
2060 max_left = min(max_left, (__s32) MAX_HDELAY);
2061 if (c->rect.left > max_left)
2062 c->rect.left = max_left;
2063 }
2064
2065 if (height < c->min_scaled_height) {
2066 /* Max. vert. scale factor 16:1, single fields 8:1. */
2067 c->rect.height = height * 16;
2068 } else if (frame_height > c->max_scaled_height) {
2069 /* Min. vert. scale factor 1:1.
2070 Top and height count field lines times two. */
2071 c->rect.height = (frame_height + 1) & ~1;
2072
2073 max_top = b->top + b->height - c->rect.height;
2074 if (c->rect.top > max_top)
2075 c->rect.top = max_top;
2076 }
2077
2078 bttv_crop_calc_limits(c);
2079}
2080
2081/* Returns an error if scaling to a frame or single field with the given
2082 width and height is not possible with the current cropping parameters
2083 and width aligned according to width_mask. If adjust_size is TRUE the
2084 function may adjust the width and/or height instead, rounding width
2085 to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
2086 also adjust the current cropping parameters to get closer to the
2087 desired image size. */
2088static int
2089limit_scaled_size (struct bttv_fh * fh,
2090 __s32 * width,
2091 __s32 * height,
2092 enum v4l2_field field,
2093 unsigned int width_mask,
2094 unsigned int width_bias,
2095 int adjust_size,
2096 int adjust_crop)
2097{
2098 struct bttv *btv = fh->btv;
2099 const struct v4l2_rect *b;
2100 struct bttv_crop *c;
2101 __s32 min_width;
2102 __s32 min_height;
2103 __s32 max_width;
2104 __s32 max_height;
2105 int rc;
2106
2107 BUG_ON((int) width_mask >= 0 ||
2108 width_bias >= (unsigned int) -width_mask);
2109
2110 /* Make sure tvnorm, vbi_end and the current cropping parameters
2111 remain consistent until we're done. */
2112 mutex_lock(&btv->lock);
2113
2114 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
2115
2116 /* Do crop - use current, don't - use default parameters. */
2117 c = &btv->crop[!!fh->do_crop];
2118
2119 if (fh->do_crop
2120 && adjust_size
2121 && adjust_crop
2122 && !locked_btres(btv, VIDEO_RESOURCES)) {
2123 min_width = 48;
2124 min_height = 32;
2125
2126 /* We cannot scale up. When the scaled image is larger
2127 than crop.rect we adjust the crop.rect as required
2128 by the V4L2 spec, hence cropcap.bounds are our limit. */
2129 max_width = min(b->width, (__s32) MAX_HACTIVE);
2130 max_height = b->height;
2131
2132 /* We cannot capture the same line as video and VBI data.
2133 Note btv->vbi_end is really a minimum, see
2134 bttv_vbi_try_fmt(). */
2135 if (btv->vbi_end > b->top) {
2136 max_height -= btv->vbi_end - b->top;
2137 rc = -EBUSY;
2138 if (min_height > max_height)
2139 goto fail;
2140 }
2141 } else {
2142 rc = -EBUSY;
2143 if (btv->vbi_end > c->rect.top)
2144 goto fail;
2145
2146 min_width = c->min_scaled_width;
2147 min_height = c->min_scaled_height;
2148 max_width = c->max_scaled_width;
2149 max_height = c->max_scaled_height;
2150
2151 adjust_crop = 0;
2152 }
2153
2154 min_width = (min_width - width_mask - 1) & width_mask;
2155 max_width = max_width & width_mask;
2156
2157 /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
2158 min_height = min_height;
2159 /* Min. scale factor is 1:1. */
2160 max_height >>= !V4L2_FIELD_HAS_BOTH(field);
2161
2162 if (adjust_size) {
2163 *width = clamp(*width, min_width, max_width);
2164 *height = clamp(*height, min_height, max_height);
2165
2166 /* Round after clamping to avoid overflow. */
2167 *width = (*width + width_bias) & width_mask;
2168
2169 if (adjust_crop) {
2170 bttv_crop_adjust(c, b, *width, *height, field);
2171
2172 if (btv->vbi_end > c->rect.top) {
2173 /* Move the crop window out of the way. */
2174 c->rect.top = btv->vbi_end;
2175 }
2176 }
2177 } else {
2178 rc = -EINVAL;
2179 if (*width < min_width ||
2180 *height < min_height ||
2181 *width > max_width ||
2182 *height > max_height ||
2183 0 != (*width & ~width_mask))
2184 goto fail;
2185 }
2186
2187 rc = 0; /* success */
2188
2189 fail:
2190 mutex_unlock(&btv->lock);
2191
2192 return rc;
2193}
2194
2195/* Returns an error if the given overlay window dimensions are not
2196 possible with the current cropping parameters. If adjust_size is
2197 TRUE the function may adjust the window width and/or height
2198 instead, however it always rounds the horizontal position and
2199 width as btcx_align() does. If adjust_crop is TRUE the function
2200 may also adjust the current cropping parameters to get closer
2201 to the desired window size. */
2202static int
2203verify_window (struct bttv_fh * fh,
2204 struct v4l2_window * win,
2205 int adjust_size,
2206 int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207{
2208 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002209 unsigned int width_mask;
2210 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
2212 if (win->w.width < 48 || win->w.height < 32)
2213 return -EINVAL;
2214 if (win->clipcount > 2048)
2215 return -EINVAL;
2216
2217 field = win->field;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
2219 if (V4L2_FIELD_ANY == field) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03002220 __s32 height2;
2221
2222 height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
2223 field = (win->w.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 ? V4L2_FIELD_INTERLACED
2225 : V4L2_FIELD_TOP;
2226 }
2227 switch (field) {
2228 case V4L2_FIELD_TOP:
2229 case V4L2_FIELD_BOTTOM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 case V4L2_FIELD_INTERLACED:
2231 break;
2232 default:
2233 return -EINVAL;
2234 }
2235
Michael Schimeke5bd0262007-01-18 16:17:39 -03002236 /* 4-byte alignment. */
2237 if (NULL == fh->ovfmt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002239 width_mask = ~0;
2240 switch (fh->ovfmt->depth) {
2241 case 8:
2242 case 24:
2243 width_mask = ~3;
2244 break;
2245 case 16:
2246 width_mask = ~1;
2247 break;
2248 case 32:
2249 break;
2250 default:
2251 BUG();
2252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Michael Schimeke5bd0262007-01-18 16:17:39 -03002254 win->w.width -= win->w.left & ~width_mask;
2255 win->w.left = (win->w.left - width_mask - 1) & width_mask;
2256
2257 rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
2258 field, width_mask,
2259 /* width_bias: round down */ 0,
2260 adjust_size, adjust_crop);
2261 if (0 != rc)
2262 return rc;
2263
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 win->field = field;
2265 return 0;
2266}
2267
2268static int setup_window(struct bttv_fh *fh, struct bttv *btv,
2269 struct v4l2_window *win, int fixup)
2270{
2271 struct v4l2_clip *clips = NULL;
2272 int n,size,retval = 0;
2273
2274 if (NULL == fh->ovfmt)
2275 return -EINVAL;
2276 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
2277 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002278 retval = verify_window(fh, win,
2279 /* adjust_size */ fixup,
2280 /* adjust_crop */ fixup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 if (0 != retval)
2282 return retval;
2283
2284 /* copy clips -- luckily v4l1 + v4l2 are binary
2285 compatible here ...*/
2286 n = win->clipcount;
2287 size = sizeof(*clips)*(n+4);
2288 clips = kmalloc(size,GFP_KERNEL);
2289 if (NULL == clips)
2290 return -ENOMEM;
2291 if (n > 0) {
2292 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
2293 kfree(clips);
2294 return -EFAULT;
2295 }
2296 }
2297 /* clip against screen */
2298 if (NULL != btv->fbuf.base)
2299 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
2300 &win->w, clips, n);
2301 btcx_sort_clips(clips,n);
2302
2303 /* 4-byte alignments */
2304 switch (fh->ovfmt->depth) {
2305 case 8:
2306 case 24:
2307 btcx_align(&win->w, clips, n, 3);
2308 break;
2309 case 16:
2310 btcx_align(&win->w, clips, n, 1);
2311 break;
2312 case 32:
2313 /* no alignment fixups needed */
2314 break;
2315 default:
2316 BUG();
2317 }
2318
Ingo Molnar3593cab2006-02-07 06:49:14 -02002319 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002320 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 fh->ov.clips = clips;
2322 fh->ov.nclips = n;
2323
2324 fh->ov.w = win->w;
2325 fh->ov.field = win->field;
2326 fh->ov.setup_ok = 1;
2327 btv->init.ov.w.width = win->w.width;
2328 btv->init.ov.w.height = win->w.height;
2329 btv->init.ov.field = win->field;
2330
2331 /* update overlay if needed */
2332 retval = 0;
2333 if (check_btres(fh, RESOURCE_OVERLAY)) {
2334 struct bttv_buffer *new;
2335
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03002336 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03002337 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2339 retval = bttv_switch_overlay(btv,fh,new);
2340 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002341 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 return retval;
2343}
2344
2345/* ----------------------------------------------------------------------- */
2346
2347static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2348{
2349 struct videobuf_queue* q = NULL;
2350
2351 switch (fh->type) {
2352 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2353 q = &fh->cap;
2354 break;
2355 case V4L2_BUF_TYPE_VBI_CAPTURE:
2356 q = &fh->vbi;
2357 break;
2358 default:
2359 BUG();
2360 }
2361 return q;
2362}
2363
2364static int bttv_resource(struct bttv_fh *fh)
2365{
2366 int res = 0;
2367
2368 switch (fh->type) {
2369 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002370 res = RESOURCE_VIDEO_STREAM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 break;
2372 case V4L2_BUF_TYPE_VBI_CAPTURE:
2373 res = RESOURCE_VBI;
2374 break;
2375 default:
2376 BUG();
2377 }
2378 return res;
2379}
2380
2381static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2382{
2383 struct videobuf_queue *q = bttv_queue(fh);
2384 int res = bttv_resource(fh);
2385
2386 if (check_btres(fh,res))
2387 return -EBUSY;
2388 if (videobuf_queue_is_busy(q))
2389 return -EBUSY;
2390 fh->type = type;
2391 return 0;
2392}
2393
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002394static void
2395pix_format_set_size (struct v4l2_pix_format * f,
2396 const struct bttv_format * fmt,
2397 unsigned int width,
2398 unsigned int height)
2399{
2400 f->width = width;
2401 f->height = height;
2402
2403 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2404 f->bytesperline = width; /* Y plane */
2405 f->sizeimage = (width * height * fmt->depth) >> 3;
2406 } else {
2407 f->bytesperline = (width * fmt->depth) >> 3;
2408 f->sizeimage = height * f->bytesperline;
2409 }
2410}
2411
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2413{
2414 switch (f->type) {
2415 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2416 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002417 pix_format_set_size (&f->fmt.pix, fh->fmt,
2418 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 f->fmt.pix.field = fh->cap.field;
2420 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 return 0;
2422 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2423 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2424 f->fmt.win.w = fh->ov.w;
2425 f->fmt.win.field = fh->ov.field;
2426 return 0;
2427 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002428 bttv_vbi_get_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 return 0;
2430 default:
2431 return -EINVAL;
2432 }
2433}
2434
2435static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
Michael Schimeke5bd0262007-01-18 16:17:39 -03002436 struct v4l2_format *f, int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437{
2438 switch (f->type) {
2439 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2440 {
2441 const struct bttv_format *fmt;
2442 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002443 __s32 width, height;
2444 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
2446 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2447 if (NULL == fmt)
2448 return -EINVAL;
2449
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 field = f->fmt.pix.field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002451 if (V4L2_FIELD_ANY == field) {
2452 __s32 height2;
2453
2454 height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
2455 field = (f->fmt.pix.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 ? V4L2_FIELD_INTERLACED
2457 : V4L2_FIELD_BOTTOM;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 if (V4L2_FIELD_SEQ_BT == field)
2460 field = V4L2_FIELD_SEQ_TB;
2461 switch (field) {
2462 case V4L2_FIELD_TOP:
2463 case V4L2_FIELD_BOTTOM:
2464 case V4L2_FIELD_ALTERNATE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 case V4L2_FIELD_INTERLACED:
2466 break;
2467 case V4L2_FIELD_SEQ_TB:
2468 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2469 return -EINVAL;
2470 break;
2471 default:
2472 return -EINVAL;
2473 }
2474
Michael Schimeke5bd0262007-01-18 16:17:39 -03002475 width = f->fmt.pix.width;
2476 height = f->fmt.pix.height;
2477
2478 rc = limit_scaled_size(fh, &width, &height, field,
2479 /* width_mask: 4 pixels */ ~3,
2480 /* width_bias: nearest */ 2,
2481 /* adjust_size */ 1,
2482 adjust_crop);
2483 if (0 != rc)
2484 return rc;
2485
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 /* update data for the application */
2487 f->fmt.pix.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002488 pix_format_set_size(&f->fmt.pix, fmt, width, height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490 return 0;
2491 }
2492 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002493 return verify_window(fh, &f->fmt.win,
2494 /* adjust_size */ 1,
2495 /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002497 return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 default:
2499 return -EINVAL;
2500 }
2501}
2502
2503static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2504 struct v4l2_format *f)
2505{
2506 int retval;
2507
2508 switch (f->type) {
2509 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2510 {
2511 const struct bttv_format *fmt;
2512
2513 retval = bttv_switch_type(fh,f->type);
2514 if (0 != retval)
2515 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002516 retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 if (0 != retval)
2518 return retval;
2519 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2520
2521 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002522 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 fh->fmt = fmt;
2524 fh->cap.field = f->fmt.pix.field;
2525 fh->cap.last = V4L2_FIELD_NONE;
2526 fh->width = f->fmt.pix.width;
2527 fh->height = f->fmt.pix.height;
2528 btv->init.fmt = fmt;
2529 btv->init.width = f->fmt.pix.width;
2530 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002531 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532
2533 return 0;
2534 }
2535 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002536 if (no_overlay > 0) {
2537 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2538 return -EINVAL;
2539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 return setup_window(fh, btv, &f->fmt.win, 1);
2541 case V4L2_BUF_TYPE_VBI_CAPTURE:
2542 retval = bttv_switch_type(fh,f->type);
2543 if (0 != retval)
2544 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002545 return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 default:
2547 return -EINVAL;
2548 }
2549}
2550
2551static int bttv_do_ioctl(struct inode *inode, struct file *file,
2552 unsigned int cmd, void *arg)
2553{
2554 struct bttv_fh *fh = file->private_data;
2555 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 int retval = 0;
2557
Michael Krufky5e453dc2006-01-09 15:32:31 -02002558 if (bttv_debug > 1)
2559 v4l_print_ioctl(btv->c.name, cmd);
2560
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 if (btv->errors)
2562 bttv_reinit_bt848(btv);
2563
2564 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 case VIDIOC_S_CTRL:
2566 case VIDIOC_S_STD:
2567 case VIDIOC_S_INPUT:
2568 case VIDIOC_S_TUNER:
2569 case VIDIOC_S_FREQUENCY:
2570 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2571 if (0 != retval)
2572 return retval;
2573 };
2574
2575 switch (cmd) {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002576#ifdef CONFIG_VIDEO_V4L1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 case VIDIOCGMBUF:
2578 {
2579 struct video_mbuf *mbuf = arg;
2580 unsigned int i;
2581
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2583 V4L2_MEMORY_MMAP);
2584 if (retval < 0)
Gregor Jasnyd9030f52008-01-06 11:15:54 -03002585 return retval;
Brandon Philips49ee7182007-10-05 16:26:27 -03002586
2587 gbuffers = retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 memset(mbuf,0,sizeof(*mbuf));
2589 mbuf->frames = gbuffers;
2590 mbuf->size = gbuffers * gbufsize;
2591 for (i = 0; i < gbuffers; i++)
2592 mbuf->offsets[i] = i * gbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 return 0;
2594 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002595#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
2597 /* *** v4l2 *** ************************************************ */
2598 case VIDIOC_QUERYCAP:
2599 {
2600 struct v4l2_capability *cap = arg;
2601
2602 if (0 == v4l2)
2603 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002604 memset(cap, 0, sizeof (*cap));
2605 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
2606 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
2607 snprintf(cap->bus_info, sizeof (cap->bus_info),
2608 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 cap->version = BTTV_VERSION_CODE;
2610 cap->capabilities =
2611 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 V4L2_CAP_VBI_CAPTURE |
2613 V4L2_CAP_READWRITE |
2614 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002615 if (no_overlay <= 0)
2616 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2619 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2620 cap->capabilities |= V4L2_CAP_TUNER;
2621 return 0;
2622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 case VIDIOC_ENUM_FMT:
2624 {
2625 struct v4l2_fmtdesc *f = arg;
2626 enum v4l2_buf_type type;
2627 unsigned int i;
2628 int index;
2629
2630 type = f->type;
2631 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2632 /* vbi */
2633 index = f->index;
2634 if (0 != index)
2635 return -EINVAL;
2636 memset(f,0,sizeof(*f));
2637 f->index = index;
2638 f->type = type;
2639 f->pixelformat = V4L2_PIX_FMT_GREY;
2640 strcpy(f->description,"vbi data");
2641 return 0;
2642 }
2643
2644 /* video capture + overlay */
2645 index = -1;
2646 for (i = 0; i < BTTV_FORMATS; i++) {
2647 if (bttv_formats[i].fourcc != -1)
2648 index++;
2649 if ((unsigned int)index == f->index)
2650 break;
2651 }
2652 if (BTTV_FORMATS == i)
2653 return -EINVAL;
2654
2655 switch (f->type) {
2656 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2657 break;
2658 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2659 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2660 return -EINVAL;
2661 break;
2662 default:
2663 return -EINVAL;
2664 }
2665 memset(f,0,sizeof(*f));
2666 f->index = index;
2667 f->type = type;
2668 f->pixelformat = bttv_formats[i].fourcc;
2669 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2670 return 0;
2671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 case VIDIOC_TRY_FMT:
2673 {
2674 struct v4l2_format *f = arg;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002675 return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 }
2677 case VIDIOC_G_FMT:
2678 {
2679 struct v4l2_format *f = arg;
2680 return bttv_g_fmt(fh,f);
2681 }
2682 case VIDIOC_S_FMT:
2683 {
2684 struct v4l2_format *f = arg;
2685 return bttv_s_fmt(fh,btv,f);
2686 }
2687
2688 case VIDIOC_G_FBUF:
2689 {
2690 struct v4l2_framebuffer *fb = arg;
2691
2692 *fb = btv->fbuf;
2693 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2694 if (fh->ovfmt)
2695 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2696 return 0;
2697 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002698 case VIDIOC_OVERLAY:
2699 {
2700 struct bttv_buffer *new;
2701 int *on = arg;
2702
2703 if (*on) {
2704 /* verify args */
2705 if (NULL == btv->fbuf.base)
2706 return -EINVAL;
2707 if (!fh->ov.setup_ok) {
2708 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2709 return -EINVAL;
2710 }
2711 }
2712
2713 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2714 return -EBUSY;
2715
2716 mutex_lock(&fh->cap.lock);
2717 if (*on) {
2718 fh->ov.tvnorm = btv->tvnorm;
2719 new = videobuf_pci_alloc(sizeof(*new));
2720 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2721 } else {
2722 new = NULL;
2723 }
2724
2725 /* switch over */
2726 retval = bttv_switch_overlay(btv,fh,new);
2727 mutex_unlock(&fh->cap.lock);
2728 return retval;
2729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 case VIDIOC_S_FBUF:
2731 {
2732 struct v4l2_framebuffer *fb = arg;
2733 const struct bttv_format *fmt;
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
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 retval = -EINVAL;
2747 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03002748 __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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 }
2760
2761 /* ok, accept it */
Michael Schimeke5bd0262007-01-18 16:17:39 -03002762 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 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;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002781 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 fh->ov.clips = NULL;
2783 fh->ov.nclips = 0;
2784
2785 if (check_btres(fh, RESOURCE_OVERLAY)) {
2786 struct bttv_buffer *new;
2787
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03002788 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03002789 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2791 retval = bttv_switch_overlay(btv,fh,new);
2792 }
2793 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002794 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 return retval;
2796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 case VIDIOC_REQBUFS:
2798 return videobuf_reqbufs(bttv_queue(fh),arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 case VIDIOC_QUERYBUF:
2800 return videobuf_querybuf(bttv_queue(fh),arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 case VIDIOC_QBUF:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002802 {
2803 int res = bttv_resource(fh);
2804
2805 if (!check_alloc_btres(btv, fh, res))
2806 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 return videobuf_qbuf(bttv_queue(fh),arg);
Michael Schimeke5bd0262007-01-18 16:17:39 -03002808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 case VIDIOC_DQBUF:
2810 return videobuf_dqbuf(bttv_queue(fh),arg,
2811 file->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 case VIDIOC_STREAMON:
2813 {
2814 int res = bttv_resource(fh);
2815
2816 if (!check_alloc_btres(btv,fh,res))
2817 return -EBUSY;
2818 return videobuf_streamon(bttv_queue(fh));
2819 }
2820 case VIDIOC_STREAMOFF:
2821 {
2822 int res = bttv_resource(fh);
2823
2824 retval = videobuf_streamoff(bttv_queue(fh));
2825 if (retval < 0)
2826 return retval;
2827 free_btres(btv,fh,res);
2828 return 0;
2829 }
2830
2831 case VIDIOC_QUERYCTRL:
2832 {
2833 struct v4l2_queryctrl *c = arg;
2834 int i;
2835
2836 if ((c->id < V4L2_CID_BASE ||
2837 c->id >= V4L2_CID_LASTP1) &&
2838 (c->id < V4L2_CID_PRIVATE_BASE ||
2839 c->id >= V4L2_CID_PRIVATE_LASTP1))
2840 return -EINVAL;
2841 for (i = 0; i < BTTV_CTLS; i++)
2842 if (bttv_ctls[i].id == c->id)
2843 break;
2844 if (i == BTTV_CTLS) {
2845 *c = no_ctl;
2846 return 0;
2847 }
2848 *c = bttv_ctls[i];
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002849#ifdef CONFIG_VIDEO_V4L1
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002850 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 struct video_audio va;
2852 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002853 btv->audio_hook(btv,&va,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 switch (bttv_ctls[i].id) {
2855 case V4L2_CID_AUDIO_VOLUME:
2856 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2857 *c = no_ctl;
2858 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 }
2860 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002861#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 return 0;
2863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 case VIDIOC_G_PARM:
2865 {
2866 struct v4l2_streamparm *parm = arg;
2867 struct v4l2_standard s;
2868 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2869 return -EINVAL;
2870 memset(parm,0,sizeof(*parm));
2871 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2872 bttv_tvnorms[btv->tvnorm].name);
2873 parm->parm.capture.timeperframe = s.frameperiod;
2874 return 0;
2875 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002876 case VIDIOC_G_TUNER:
2877 {
2878 struct v4l2_tuner *t = arg;
2879
2880 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2881 return -EINVAL;
2882 if (0 != t->index)
2883 return -EINVAL;
2884 mutex_lock(&btv->lock);
2885 memset(t,0,sizeof(*t));
2886 t->rxsubchans = V4L2_TUNER_SUB_MONO;
2887 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
2888 strcpy(t->name, "Television");
2889 t->capability = V4L2_TUNER_CAP_NORM;
2890 t->type = V4L2_TUNER_ANALOG_TV;
2891 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
2892 t->signal = 0xffff;
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002893#ifdef CONFIG_VIDEO_V4L1
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002894 if (btv->audio_hook) {
2895 /* Hmmm ... */
2896 struct video_audio va;
2897 memset(&va, 0, sizeof(struct video_audio));
2898 btv->audio_hook(btv,&va,0);
2899 t->audmode = V4L2_TUNER_MODE_MONO;
2900 t->rxsubchans = V4L2_TUNER_SUB_MONO;
2901 if(va.mode & VIDEO_SOUND_STEREO) {
2902 t->audmode = V4L2_TUNER_MODE_STEREO;
2903 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
2904 }
2905 if(va.mode & VIDEO_SOUND_LANG2) {
2906 t->audmode = V4L2_TUNER_MODE_LANG1;
2907 t->rxsubchans = V4L2_TUNER_SUB_LANG1
2908 | V4L2_TUNER_SUB_LANG2;
2909 }
2910 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002911#endif
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002912 /* FIXME: fill capability+audmode */
2913 mutex_unlock(&btv->lock);
2914 return 0;
2915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
2917 case VIDIOC_G_PRIORITY:
2918 {
2919 enum v4l2_priority *p = arg;
2920
2921 *p = v4l2_prio_max(&btv->prio);
2922 return 0;
2923 }
2924 case VIDIOC_S_PRIORITY:
2925 {
2926 enum v4l2_priority *prio = arg;
2927
2928 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
2929 }
2930
Michael Schimeke5bd0262007-01-18 16:17:39 -03002931 case VIDIOC_CROPCAP:
2932 {
2933 struct v4l2_cropcap *cap = arg;
2934 enum v4l2_buf_type type;
2935
2936 type = cap->type;
2937
2938 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2939 type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
2940 return -EINVAL;
2941
2942 *cap = bttv_tvnorms[btv->tvnorm].cropcap;
2943 cap->type = type;
2944
2945 return 0;
2946 }
2947 case VIDIOC_G_CROP:
2948 {
2949 struct v4l2_crop * crop = arg;
2950
2951 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2952 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
2953 return -EINVAL;
2954
2955 /* No fh->do_crop = 1; because btv->crop[1] may be
2956 inconsistent with fh->width or fh->height and apps
2957 do not expect a change here. */
2958
2959 crop->c = btv->crop[!!fh->do_crop].rect;
2960
2961 return 0;
2962 }
2963 case VIDIOC_S_CROP:
2964 {
2965 struct v4l2_crop *crop = arg;
2966 const struct v4l2_rect *b;
2967 struct bttv_crop c;
2968 __s32 b_left;
2969 __s32 b_top;
2970 __s32 b_right;
2971 __s32 b_bottom;
2972
2973 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
2974 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
2975 return -EINVAL;
2976
2977 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2978 if (0 != retval)
2979 return retval;
2980
2981 /* Make sure tvnorm, vbi_end and the current cropping
2982 parameters remain consistent until we're done. Note
2983 read() may change vbi_end in check_alloc_btres(). */
2984 mutex_lock(&btv->lock);
2985
2986 retval = -EBUSY;
2987
2988 if (locked_btres(fh->btv, VIDEO_RESOURCES))
2989 goto btv_unlock_and_return;
2990
2991 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
2992
2993 b_left = b->left;
2994 b_right = b_left + b->width;
2995 b_bottom = b->top + b->height;
2996
2997 b_top = max(b->top, btv->vbi_end);
2998 if (b_top + 32 >= b_bottom)
2999 goto btv_unlock_and_return;
3000
3001 /* Min. scaled size 48 x 32. */
3002 c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
3003 c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
3004
3005 c.rect.width = clamp(crop->c.width,
3006 48, b_right - c.rect.left);
3007
3008 c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
3009 /* Top and height must be a multiple of two. */
3010 c.rect.top = (c.rect.top + 1) & ~1;
3011
3012 c.rect.height = clamp(crop->c.height,
3013 32, b_bottom - c.rect.top);
3014 c.rect.height = (c.rect.height + 1) & ~1;
3015
3016 bttv_crop_calc_limits(&c);
3017
3018 btv->crop[1] = c;
3019
3020 mutex_unlock(&btv->lock);
3021
3022 fh->do_crop = 1;
3023
3024 mutex_lock(&fh->cap.lock);
3025
3026 if (fh->width < c.min_scaled_width) {
3027 fh->width = c.min_scaled_width;
3028 btv->init.width = c.min_scaled_width;
3029 } else if (fh->width > c.max_scaled_width) {
3030 fh->width = c.max_scaled_width;
3031 btv->init.width = c.max_scaled_width;
3032 }
3033
3034 if (fh->height < c.min_scaled_height) {
3035 fh->height = c.min_scaled_height;
3036 btv->init.height = c.min_scaled_height;
3037 } else if (fh->height > c.max_scaled_height) {
3038 fh->height = c.max_scaled_height;
3039 btv->init.height = c.max_scaled_height;
3040 }
3041
3042 mutex_unlock(&fh->cap.lock);
3043
3044 return 0;
3045 }
3046
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 case VIDIOC_ENUMSTD:
3048 case VIDIOC_G_STD:
3049 case VIDIOC_S_STD:
3050 case VIDIOC_ENUMINPUT:
3051 case VIDIOC_G_INPUT:
3052 case VIDIOC_S_INPUT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 case VIDIOC_S_TUNER:
3054 case VIDIOC_G_FREQUENCY:
3055 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08003056 case VIDIOC_LOG_STATUS:
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003057 case VIDIOC_G_CTRL:
3058 case VIDIOC_S_CTRL:
Trent Piepho55c0d102007-06-29 00:17:36 -03003059 case VIDIOC_DBG_G_REGISTER:
3060 case VIDIOC_DBG_S_REGISTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 return bttv_common_ioctls(btv,cmd,arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 default:
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03003063 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
3064 bttv_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 }
3066 return 0;
3067
3068 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02003069 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003071
3072 btv_unlock_and_return:
3073 mutex_unlock(&btv->lock);
3074 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075}
3076
3077static int bttv_ioctl(struct inode *inode, struct file *file,
3078 unsigned int cmd, unsigned long arg)
3079{
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003080 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081}
3082
3083static ssize_t bttv_read(struct file *file, char __user *data,
3084 size_t count, loff_t *ppos)
3085{
3086 struct bttv_fh *fh = file->private_data;
3087 int retval = 0;
3088
3089 if (fh->btv->errors)
3090 bttv_reinit_bt848(fh->btv);
3091 dprintk("bttv%d: read count=%d type=%s\n",
3092 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
3093
3094 switch (fh->type) {
3095 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003096 if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
3097 /* VIDEO_READ in use by another fh,
3098 or VIDEO_STREAM by any fh. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 return -EBUSY;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 retval = videobuf_read_one(&fh->cap, data, count, ppos,
3102 file->f_flags & O_NONBLOCK);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003103 free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 break;
3105 case V4L2_BUF_TYPE_VBI_CAPTURE:
3106 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3107 return -EBUSY;
3108 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
3109 file->f_flags & O_NONBLOCK);
3110 break;
3111 default:
3112 BUG();
3113 }
3114 return retval;
3115}
3116
3117static unsigned int bttv_poll(struct file *file, poll_table *wait)
3118{
3119 struct bttv_fh *fh = file->private_data;
3120 struct bttv_buffer *buf;
3121 enum v4l2_field field;
3122
3123 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
3124 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3125 return POLLERR;
3126 return videobuf_poll_stream(file, &fh->vbi, wait);
3127 }
3128
Michael Schimeke5bd0262007-01-18 16:17:39 -03003129 if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 /* streaming capture */
3131 if (list_empty(&fh->cap.stream))
3132 return POLLERR;
3133 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
3134 } else {
3135 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02003136 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 if (NULL == fh->cap.read_buf) {
3138 /* need to capture a new frame */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003139 if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003140 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 return POLLERR;
3142 }
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003143 fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003145 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 return POLLERR;
3147 }
3148 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
3149 field = videobuf_next_field(&fh->cap);
3150 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08003151 kfree (fh->cap.read_buf);
3152 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003153 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 return POLLERR;
3155 }
3156 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3157 fh->cap.read_off = 0;
3158 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003159 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 buf = (struct bttv_buffer*)fh->cap.read_buf;
3161 }
3162
3163 poll_wait(file, &buf->vb.done, wait);
3164 if (buf->vb.state == STATE_DONE ||
3165 buf->vb.state == STATE_ERROR)
3166 return POLLIN|POLLRDNORM;
3167 return 0;
3168}
3169
3170static int bttv_open(struct inode *inode, struct file *file)
3171{
3172 int minor = iminor(inode);
3173 struct bttv *btv = NULL;
3174 struct bttv_fh *fh;
3175 enum v4l2_buf_type type = 0;
3176 unsigned int i;
3177
3178 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3179
3180 for (i = 0; i < bttv_num; i++) {
3181 if (bttvs[i].video_dev &&
3182 bttvs[i].video_dev->minor == minor) {
3183 btv = &bttvs[i];
3184 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3185 break;
3186 }
3187 if (bttvs[i].vbi_dev &&
3188 bttvs[i].vbi_dev->minor == minor) {
3189 btv = &bttvs[i];
3190 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3191 break;
3192 }
3193 }
3194 if (NULL == btv)
3195 return -ENODEV;
3196
3197 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3198 btv->c.nr,v4l2_type_names[type]);
3199
3200 /* allocate per filehandle data */
3201 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3202 if (NULL == fh)
3203 return -ENOMEM;
3204 file->private_data = fh;
3205 *fh = btv->init;
3206 fh->type = type;
3207 fh->ov.setup_ok = 0;
3208 v4l2_prio_open(&btv->prio,&fh->prio);
3209
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003210 videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 btv->c.pci, &btv->s_lock,
3212 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3213 V4L2_FIELD_INTERLACED,
3214 sizeof(struct bttv_buffer),
3215 fh);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003216 videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 btv->c.pci, &btv->s_lock,
3218 V4L2_BUF_TYPE_VBI_CAPTURE,
3219 V4L2_FIELD_SEQ_TB,
3220 sizeof(struct bttv_buffer),
3221 fh);
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03003222 set_tvnorm(btv,btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223
3224 btv->users++;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003225
3226 /* The V4L2 spec requires one global set of cropping parameters
3227 which only change on request. These are stored in btv->crop[1].
3228 However for compatibility with V4L apps and cropping unaware
3229 V4L2 apps we now reset the cropping parameters as seen through
3230 this fh, which is to say VIDIOC_G_CROP and scaling limit checks
3231 will use btv->crop[0], the default cropping parameters for the
3232 current video standard, and VIDIOC_S_FMT will not implicitely
3233 change the cropping parameters until VIDIOC_S_CROP has been
3234 called. */
3235 fh->do_crop = !reset_crop; /* module parameter */
3236
3237 /* Likewise there should be one global set of VBI capture
3238 parameters, but for compatibility with V4L apps and earlier
3239 driver versions each fh has its own parameters. */
3240 bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
3241
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 bttv_field_count(btv);
3243 return 0;
3244}
3245
3246static int bttv_release(struct inode *inode, struct file *file)
3247{
3248 struct bttv_fh *fh = file->private_data;
3249 struct bttv *btv = fh->btv;
3250
3251 /* turn off overlay */
3252 if (check_btres(fh, RESOURCE_OVERLAY))
3253 bttv_switch_overlay(btv,fh,NULL);
3254
3255 /* stop video capture */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003256 if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 videobuf_streamoff(&fh->cap);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003258 free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 }
3260 if (fh->cap.read_buf) {
3261 buffer_release(&fh->cap,fh->cap.read_buf);
3262 kfree(fh->cap.read_buf);
3263 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03003264 if (check_btres(fh, RESOURCE_VIDEO_READ)) {
3265 free_btres(btv, fh, RESOURCE_VIDEO_READ);
3266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267
3268 /* stop vbi capture */
3269 if (check_btres(fh, RESOURCE_VBI)) {
Brandon Philips053fcb62007-11-13 20:11:26 -03003270 videobuf_stop(&fh->vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 free_btres(btv,fh,RESOURCE_VBI);
3272 }
3273
3274 /* free stuff */
3275 videobuf_mmap_free(&fh->cap);
3276 videobuf_mmap_free(&fh->vbi);
3277 v4l2_prio_close(&btv->prio,&fh->prio);
3278 file->private_data = NULL;
3279 kfree(fh);
3280
3281 btv->users--;
3282 bttv_field_count(btv);
3283 return 0;
3284}
3285
3286static int
3287bttv_mmap(struct file *file, struct vm_area_struct *vma)
3288{
3289 struct bttv_fh *fh = file->private_data;
3290
3291 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3292 fh->btv->c.nr, v4l2_type_names[fh->type],
3293 vma->vm_start, vma->vm_end - vma->vm_start);
3294 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3295}
3296
Arjan van de Venfa027c22007-02-12 00:55:33 -08003297static const struct file_operations bttv_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298{
3299 .owner = THIS_MODULE,
3300 .open = bttv_open,
3301 .release = bttv_release,
3302 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003303 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 .llseek = no_llseek,
3305 .read = bttv_read,
3306 .mmap = bttv_mmap,
3307 .poll = bttv_poll,
3308};
3309
3310static struct video_device bttv_video_template =
3311{
3312 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003313 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003314 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 .fops = &bttv_fops,
3316 .minor = -1,
3317};
3318
3319static struct video_device bttv_vbi_template =
3320{
3321 .name = "bt848/878 vbi",
3322 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 .fops = &bttv_fops,
3324 .minor = -1,
3325};
3326
3327/* ----------------------------------------------------------------------- */
3328/* radio interface */
3329
3330static int radio_open(struct inode *inode, struct file *file)
3331{
3332 int minor = iminor(inode);
3333 struct bttv *btv = NULL;
3334 unsigned int i;
3335
3336 dprintk("bttv: open minor=%d\n",minor);
3337
3338 for (i = 0; i < bttv_num; i++) {
3339 if (bttvs[i].radio_dev->minor == minor) {
3340 btv = &bttvs[i];
3341 break;
3342 }
3343 }
3344 if (NULL == btv)
3345 return -ENODEV;
3346
3347 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003348 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003349
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003351
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 file->private_data = btv;
3353
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003354 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3355 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003357 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003358 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359}
3360
3361static int radio_release(struct inode *inode, struct file *file)
3362{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003363 struct bttv *btv = file->private_data;
3364 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
3366 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003367
3368 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3369
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 return 0;
3371}
3372
3373static int radio_do_ioctl(struct inode *inode, struct file *file,
3374 unsigned int cmd, void *arg)
3375{
3376 struct bttv *btv = file->private_data;
3377
3378 switch (cmd) {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003379 case VIDIOC_QUERYCAP:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003381 struct v4l2_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382
3383 memset(cap,0,sizeof(*cap));
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003384 strcpy(cap->driver, "bttv");
3385 strlcpy(cap->card, btv->radio_dev->name,sizeof(cap->card));
3386 sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci));
3387 cap->version = BTTV_VERSION_CODE;
3388 cap->capabilities = V4L2_CAP_TUNER;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003389 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003391 case VIDIOC_G_TUNER:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003392 {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003393 struct v4l2_tuner *t = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003395 if (UNSET == bttv_tvcards[btv->c.type].tuner)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003396 return -EINVAL;
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003397 if (0 != t->index)
3398 return -EINVAL;
3399 mutex_lock(&btv->lock);
3400 memset(t,0,sizeof(*t));
3401 strcpy(t->name, "Radio");
3402 t->type = V4L2_TUNER_RADIO;
3403
3404 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
3405
3406 mutex_unlock(&btv->lock);
3407
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003408 return 0;
3409 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003410 case VIDIOC_S_TUNER:
3411 case VIDIOC_G_FREQUENCY:
3412 case VIDIOC_S_FREQUENCY:
3413 case VIDIOC_G_CTRL:
3414 case VIDIOC_S_CTRL:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003415 case VIDIOC_LOG_STATUS:
Trent Piepho55c0d102007-06-29 00:17:36 -03003416 case VIDIOC_DBG_G_REGISTER:
3417 case VIDIOC_DBG_S_REGISTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 return bttv_common_ioctls(btv,cmd,arg);
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03003419 default:
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003420 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
3421 radio_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 }
3423 return 0;
3424}
3425
3426static int radio_ioctl(struct inode *inode, struct file *file,
3427 unsigned int cmd, unsigned long arg)
3428{
3429 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3430}
3431
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003432static ssize_t radio_read(struct file *file, char __user *data,
3433 size_t count, loff_t *ppos)
3434{
3435 struct bttv *btv = file->private_data;
3436 struct rds_command cmd;
3437 cmd.block_count = count/3;
3438 cmd.buffer = data;
3439 cmd.instance = file;
3440 cmd.result = -ENODEV;
3441
3442 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3443
3444 return cmd.result;
3445}
3446
3447static unsigned int radio_poll(struct file *file, poll_table *wait)
3448{
3449 struct bttv *btv = file->private_data;
3450 struct rds_command cmd;
3451 cmd.instance = file;
3452 cmd.event_list = wait;
3453 cmd.result = -ENODEV;
3454 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3455
3456 return cmd.result;
3457}
3458
Arjan van de Venfa027c22007-02-12 00:55:33 -08003459static const struct file_operations radio_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460{
3461 .owner = THIS_MODULE,
3462 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003463 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 .release = radio_release,
3465 .ioctl = radio_ioctl,
3466 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003467 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468};
3469
3470static struct video_device radio_template =
3471{
3472 .name = "bt848/878 radio",
3473 .type = VID_TYPE_TUNER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 .fops = &radio_fops,
3475 .minor = -1,
3476};
3477
3478/* ----------------------------------------------------------------------- */
3479/* some debug code */
3480
Adrian Bunk408b6642005-05-01 08:59:29 -07003481static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482{
3483 static char *instr[16] = {
3484 [ BT848_RISC_WRITE >> 28 ] = "write",
3485 [ BT848_RISC_SKIP >> 28 ] = "skip",
3486 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3487 [ BT848_RISC_JUMP >> 28 ] = "jump",
3488 [ BT848_RISC_SYNC >> 28 ] = "sync",
3489 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3490 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3491 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3492 };
3493 static int incr[16] = {
3494 [ BT848_RISC_WRITE >> 28 ] = 2,
3495 [ BT848_RISC_JUMP >> 28 ] = 2,
3496 [ BT848_RISC_SYNC >> 28 ] = 2,
3497 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3498 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3499 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3500 };
3501 static char *bits[] = {
3502 "be0", "be1", "be2", "be3/resync",
3503 "set0", "set1", "set2", "set3",
3504 "clr0", "clr1", "clr2", "clr3",
3505 "irq", "res", "eol", "sol",
3506 };
3507 int i;
3508
3509 printk("0x%08x [ %s", risc,
3510 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3511 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3512 if (risc & (1 << (i + 12)))
3513 printk(" %s",bits[i]);
3514 printk(" count=%d ]\n", risc & 0xfff);
3515 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3516}
3517
Adrian Bunk408b6642005-05-01 08:59:29 -07003518static void bttv_risc_disasm(struct bttv *btv,
3519 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520{
3521 unsigned int i,j,n;
3522
3523 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3524 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3525 for (i = 0; i < (risc->size >> 2); i += n) {
3526 printk("%s: 0x%lx: ", btv->c.name,
3527 (unsigned long)(risc->dma + (i<<2)));
3528 n = bttv_risc_decode(risc->cpu[i]);
3529 for (j = 1; j < n; j++)
3530 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3531 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3532 risc->cpu[i+j], j);
3533 if (0 == risc->cpu[i])
3534 break;
3535 }
3536}
3537
3538static void bttv_print_riscaddr(struct bttv *btv)
3539{
3540 printk(" main: %08Lx\n",
3541 (unsigned long long)btv->main.dma);
3542 printk(" vbi : o=%08Lx e=%08Lx\n",
3543 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3544 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3545 printk(" cap : o=%08Lx e=%08Lx\n",
3546 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3547 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3548 printk(" scr : o=%08Lx e=%08Lx\n",
3549 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3550 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3551 bttv_risc_disasm(btv, &btv->main);
3552}
3553
3554/* ----------------------------------------------------------------------- */
3555/* irq handler */
3556
3557static char *irq_name[] = {
3558 "FMTCHG", // format change detected (525 vs. 625)
3559 "VSYNC", // vertical sync (new field)
3560 "HSYNC", // horizontal sync
3561 "OFLOW", // chroma/luma AGC overflow
3562 "HLOCK", // horizontal lock changed
3563 "VPRES", // video presence changed
3564 "6", "7",
3565 "I2CDONE", // hw irc operation finished
3566 "GPINT", // gpio port triggered irq
3567 "10",
3568 "RISCI", // risc instruction triggered irq
3569 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3570 "FTRGT", // pixel data fifo overrun
3571 "FDSR", // fifo data stream resyncronisation
3572 "PPERR", // parity error (data transfer)
3573 "RIPERR", // parity error (read risc instructions)
3574 "PABORT", // pci abort
3575 "OCERR", // risc instruction error
3576 "SCERR", // syncronisation error
3577};
3578
3579static void bttv_print_irqbits(u32 print, u32 mark)
3580{
3581 unsigned int i;
3582
3583 printk("bits:");
3584 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3585 if (print & (1 << i))
3586 printk(" %s",irq_name[i]);
3587 if (mark & (1 << i))
3588 printk("*");
3589 }
3590}
3591
3592static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3593{
3594 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3595 btv->c.nr,
3596 (unsigned long)btv->main.dma,
3597 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3598 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3599 (unsigned long)rc);
3600
3601 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3602 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3603 "Ok, then this is harmless, don't worry ;)\n",
3604 btv->c.nr);
3605 return;
3606 }
3607 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3608 btv->c.nr);
3609 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3610 btv->c.nr);
3611 dump_stack();
3612}
3613
3614static int
3615bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3616{
3617 struct bttv_buffer *item;
3618
3619 memset(set,0,sizeof(*set));
3620
3621 /* capture request ? */
3622 if (!list_empty(&btv->capture)) {
3623 set->frame_irq = 1;
3624 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3625 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3626 set->top = item;
3627 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3628 set->bottom = item;
3629
3630 /* capture request for other field ? */
3631 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3632 (item->vb.queue.next != &btv->capture)) {
3633 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3634 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3635 if (NULL == set->top &&
3636 V4L2_FIELD_TOP == item->vb.field) {
3637 set->top = item;
3638 }
3639 if (NULL == set->bottom &&
3640 V4L2_FIELD_BOTTOM == item->vb.field) {
3641 set->bottom = item;
3642 }
3643 if (NULL != set->top && NULL != set->bottom)
3644 set->top_irq = 2;
3645 }
3646 }
3647 }
3648
3649 /* screen overlay ? */
3650 if (NULL != btv->screen) {
3651 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3652 if (NULL == set->top && NULL == set->bottom) {
3653 set->top = btv->screen;
3654 set->bottom = btv->screen;
3655 }
3656 } else {
3657 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3658 NULL == set->top) {
3659 set->top = btv->screen;
3660 }
3661 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3662 NULL == set->bottom) {
3663 set->bottom = btv->screen;
3664 }
3665 }
3666 }
3667
3668 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3669 btv->c.nr,set->top, set->bottom,
3670 btv->screen,set->frame_irq,set->top_irq);
3671 return 0;
3672}
3673
3674static void
3675bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3676 struct bttv_buffer_set *curr, unsigned int state)
3677{
3678 struct timeval ts;
3679
3680 do_gettimeofday(&ts);
3681
3682 if (wakeup->top == wakeup->bottom) {
3683 if (NULL != wakeup->top && curr->top != wakeup->top) {
3684 if (irq_debug > 1)
3685 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3686 wakeup->top->vb.ts = ts;
3687 wakeup->top->vb.field_count = btv->field_count;
3688 wakeup->top->vb.state = state;
3689 wake_up(&wakeup->top->vb.done);
3690 }
3691 } else {
3692 if (NULL != wakeup->top && curr->top != wakeup->top) {
3693 if (irq_debug > 1)
3694 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3695 wakeup->top->vb.ts = ts;
3696 wakeup->top->vb.field_count = btv->field_count;
3697 wakeup->top->vb.state = state;
3698 wake_up(&wakeup->top->vb.done);
3699 }
3700 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3701 if (irq_debug > 1)
3702 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3703 wakeup->bottom->vb.ts = ts;
3704 wakeup->bottom->vb.field_count = btv->field_count;
3705 wakeup->bottom->vb.state = state;
3706 wake_up(&wakeup->bottom->vb.done);
3707 }
3708 }
3709}
3710
3711static void
3712bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3713 unsigned int state)
3714{
3715 struct timeval ts;
3716
3717 if (NULL == wakeup)
3718 return;
3719
3720 do_gettimeofday(&ts);
3721 wakeup->vb.ts = ts;
3722 wakeup->vb.field_count = btv->field_count;
3723 wakeup->vb.state = state;
3724 wake_up(&wakeup->vb.done);
3725}
3726
3727static void bttv_irq_timeout(unsigned long data)
3728{
3729 struct bttv *btv = (struct bttv *)data;
3730 struct bttv_buffer_set old,new;
3731 struct bttv_buffer *ovbi;
3732 struct bttv_buffer *item;
3733 unsigned long flags;
3734
3735 if (bttv_verbose) {
3736 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3737 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3738 btread(BT848_RISC_COUNT));
3739 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3740 printk("\n");
3741 }
3742
3743 spin_lock_irqsave(&btv->s_lock,flags);
3744
3745 /* deactivate stuff */
3746 memset(&new,0,sizeof(new));
3747 old = btv->curr;
3748 ovbi = btv->cvbi;
3749 btv->curr = new;
3750 btv->cvbi = NULL;
3751 btv->loop_irq = 0;
3752 bttv_buffer_activate_video(btv, &new);
3753 bttv_buffer_activate_vbi(btv, NULL);
3754 bttv_set_dma(btv, 0);
3755
3756 /* wake up */
3757 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
3758 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
3759
3760 /* cancel all outstanding capture / vbi requests */
3761 while (!list_empty(&btv->capture)) {
3762 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3763 list_del(&item->vb.queue);
3764 item->vb.state = STATE_ERROR;
3765 wake_up(&item->vb.done);
3766 }
3767 while (!list_empty(&btv->vcapture)) {
3768 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3769 list_del(&item->vb.queue);
3770 item->vb.state = STATE_ERROR;
3771 wake_up(&item->vb.done);
3772 }
3773
3774 btv->errors++;
3775 spin_unlock_irqrestore(&btv->s_lock,flags);
3776}
3777
3778static void
3779bttv_irq_wakeup_top(struct bttv *btv)
3780{
3781 struct bttv_buffer *wakeup = btv->curr.top;
3782
3783 if (NULL == wakeup)
3784 return;
3785
3786 spin_lock(&btv->s_lock);
3787 btv->curr.top_irq = 0;
3788 btv->curr.top = NULL;
3789 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3790
3791 do_gettimeofday(&wakeup->vb.ts);
3792 wakeup->vb.field_count = btv->field_count;
3793 wakeup->vb.state = STATE_DONE;
3794 wake_up(&wakeup->vb.done);
3795 spin_unlock(&btv->s_lock);
3796}
3797
3798static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3799{
3800 if (rc < risc->dma)
3801 return 0;
3802 if (rc > risc->dma + risc->size)
3803 return 0;
3804 return 1;
3805}
3806
3807static void
3808bttv_irq_switch_video(struct bttv *btv)
3809{
3810 struct bttv_buffer_set new;
3811 struct bttv_buffer_set old;
3812 dma_addr_t rc;
3813
3814 spin_lock(&btv->s_lock);
3815
3816 /* new buffer set */
3817 bttv_irq_next_video(btv, &new);
3818 rc = btread(BT848_RISC_COUNT);
3819 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3820 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3821 btv->framedrop++;
3822 if (debug_latency)
3823 bttv_irq_debug_low_latency(btv, rc);
3824 spin_unlock(&btv->s_lock);
3825 return;
3826 }
3827
3828 /* switch over */
3829 old = btv->curr;
3830 btv->curr = new;
3831 btv->loop_irq &= ~1;
3832 bttv_buffer_activate_video(btv, &new);
3833 bttv_set_dma(btv, 0);
3834
3835 /* switch input */
3836 if (UNSET != btv->new_input) {
3837 video_mux(btv,btv->new_input);
3838 btv->new_input = UNSET;
3839 }
3840
3841 /* wake up finished buffers */
3842 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
3843 spin_unlock(&btv->s_lock);
3844}
3845
3846static void
3847bttv_irq_switch_vbi(struct bttv *btv)
3848{
3849 struct bttv_buffer *new = NULL;
3850 struct bttv_buffer *old;
3851 u32 rc;
3852
3853 spin_lock(&btv->s_lock);
3854
3855 if (!list_empty(&btv->vcapture))
3856 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3857 old = btv->cvbi;
3858
3859 rc = btread(BT848_RISC_COUNT);
3860 if (NULL != old && (is_active(&old->top, rc) ||
3861 is_active(&old->bottom, rc))) {
3862 btv->framedrop++;
3863 if (debug_latency)
3864 bttv_irq_debug_low_latency(btv, rc);
3865 spin_unlock(&btv->s_lock);
3866 return;
3867 }
3868
3869 /* switch */
3870 btv->cvbi = new;
3871 btv->loop_irq &= ~4;
3872 bttv_buffer_activate_vbi(btv, new);
3873 bttv_set_dma(btv, 0);
3874
3875 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
3876 spin_unlock(&btv->s_lock);
3877}
3878
David Howells7d12e782006-10-05 14:55:46 +01003879static irqreturn_t bttv_irq(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880{
3881 u32 stat,astat;
3882 u32 dstat;
3883 int count;
3884 struct bttv *btv;
3885 int handled = 0;
3886
3887 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003888
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003889 if (btv->custom_irq)
3890 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003891
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 count=0;
3893 while (1) {
3894 /* get/clear interrupt status bits */
3895 stat=btread(BT848_INT_STAT);
3896 astat=stat&btread(BT848_INT_MASK);
3897 if (!astat)
3898 break;
3899 handled = 1;
3900 btwrite(stat,BT848_INT_STAT);
3901
3902 /* get device status bits */
3903 dstat=btread(BT848_DSTATUS);
3904
3905 if (irq_debug) {
3906 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
3907 "riscs=%x, riscc=%08x, ",
3908 btv->c.nr, count, btv->field_count,
3909 stat>>28, btread(BT848_RISC_COUNT));
3910 bttv_print_irqbits(stat,astat);
3911 if (stat & BT848_INT_HLOCK)
3912 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
3913 ? "yes" : "no");
3914 if (stat & BT848_INT_VPRES)
3915 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
3916 ? "yes" : "no");
3917 if (stat & BT848_INT_FMTCHG)
3918 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
3919 ? "625" : "525");
3920 printk("\n");
3921 }
3922
3923 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003924 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003926 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003928 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 }
3930
3931 if (astat & BT848_INT_I2CDONE) {
3932 btv->i2c_done = stat;
3933 wake_up(&btv->i2c_queue);
3934 }
3935
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003936 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 bttv_irq_switch_vbi(btv);
3938
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003939 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 bttv_irq_wakeup_top(btv);
3941
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003942 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 bttv_irq_switch_video(btv);
3944
3945 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003946 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947
3948 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
3949 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
3950 (astat & BT848_INT_SCERR) ? "SCERR" : "",
3951 (astat & BT848_INT_OCERR) ? "OCERR" : "",
3952 btread(BT848_RISC_COUNT));
3953 bttv_print_irqbits(stat,astat);
3954 printk("\n");
3955 if (bttv_debug)
3956 bttv_print_riscaddr(btv);
3957 }
3958 if (fdsr && astat & BT848_INT_FDSR) {
3959 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
3960 btv->c.nr,btread(BT848_RISC_COUNT));
3961 if (bttv_debug)
3962 bttv_print_riscaddr(btv);
3963 }
3964
3965 count++;
3966 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003967
3968 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003969 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003970
3971 printk(KERN_ERR
3972 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
3973 } else {
3974 printk(KERN_ERR
3975 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
3976
3977 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
3978 BT848_INT_MASK);
3979 };
3980
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003982
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 printk("]\n");
3984 }
3985 }
3986 btv->irq_total++;
3987 if (handled)
3988 btv->irq_me++;
3989 return IRQ_RETVAL(handled);
3990}
3991
3992
3993/* ----------------------------------------------------------------------- */
3994/* initialitation */
3995
3996static struct video_device *vdev_init(struct bttv *btv,
3997 struct video_device *template,
3998 char *type)
3999{
4000 struct video_device *vfd;
4001
4002 vfd = video_device_alloc();
4003 if (NULL == vfd)
4004 return NULL;
4005 *vfd = *template;
4006 vfd->minor = -1;
4007 vfd->dev = &btv->c.pci->dev;
4008 vfd->release = video_device_release;
4009 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
4010 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
4011 type, bttv_tvcards[btv->c.type].name);
4012 return vfd;
4013}
4014
4015static void bttv_unregister_video(struct bttv *btv)
4016{
4017 if (btv->video_dev) {
4018 if (-1 != btv->video_dev->minor)
4019 video_unregister_device(btv->video_dev);
4020 else
4021 video_device_release(btv->video_dev);
4022 btv->video_dev = NULL;
4023 }
4024 if (btv->vbi_dev) {
4025 if (-1 != btv->vbi_dev->minor)
4026 video_unregister_device(btv->vbi_dev);
4027 else
4028 video_device_release(btv->vbi_dev);
4029 btv->vbi_dev = NULL;
4030 }
4031 if (btv->radio_dev) {
4032 if (-1 != btv->radio_dev->minor)
4033 video_unregister_device(btv->radio_dev);
4034 else
4035 video_device_release(btv->radio_dev);
4036 btv->radio_dev = NULL;
4037 }
4038}
4039
4040/* register video4linux devices */
4041static int __devinit bttv_register_video(struct bttv *btv)
4042{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07004043 if (no_overlay <= 0) {
4044 bttv_video_template.type |= VID_TYPE_OVERLAY;
4045 } else {
4046 printk("bttv: Overlay support disabled.\n");
4047 }
4048
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 /* video */
4050 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004051 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 goto err;
4053 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
4054 goto err;
4055 printk(KERN_INFO "bttv%d: registered device video%d\n",
4056 btv->c.nr,btv->video_dev->minor & 0x1f);
Kay Sievers54bd5b62007-10-08 16:26:13 -03004057 if (device_create_file(&btv->video_dev->class_dev,
4058 &dev_attr_card)<0) {
4059 printk(KERN_ERR "bttv%d: device_create_file 'card' "
Trent Piephod94fc9a2006-07-29 17:18:06 -03004060 "failed\n", btv->c.nr);
4061 goto err;
4062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
4064 /* vbi */
4065 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004066 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004068 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 goto err;
4070 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
4071 btv->c.nr,btv->vbi_dev->minor & 0x1f);
4072
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004073 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 return 0;
4075 /* radio */
4076 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004077 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 goto err;
4079 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
4080 goto err;
4081 printk(KERN_INFO "bttv%d: registered device radio%d\n",
4082 btv->c.nr,btv->radio_dev->minor & 0x1f);
4083
4084 /* all done */
4085 return 0;
4086
4087 err:
4088 bttv_unregister_video(btv);
4089 return -1;
4090}
4091
4092
4093/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
4094/* response on cards with no firmware is not enabled by OF */
4095static void pci_set_command(struct pci_dev *dev)
4096{
4097#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004098 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004100 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
4101 cmd = (cmd | PCI_COMMAND_MEMORY );
4102 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103#endif
4104}
4105
4106static int __devinit bttv_probe(struct pci_dev *dev,
4107 const struct pci_device_id *pci_id)
4108{
4109 int result;
4110 unsigned char lat;
4111 struct bttv *btv;
4112
4113 if (bttv_num == BTTV_MAX)
4114 return -ENOMEM;
4115 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004116 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 memset(btv,0,sizeof(*btv));
4118 btv->c.nr = bttv_num;
4119 sprintf(btv->c.name,"bttv%d",btv->c.nr);
4120
4121 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02004122 mutex_init(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004123 spin_lock_init(&btv->s_lock);
4124 spin_lock_init(&btv->gpio_lock);
4125 init_waitqueue_head(&btv->gpioq);
4126 init_waitqueue_head(&btv->i2c_queue);
4127 INIT_LIST_HEAD(&btv->c.subs);
4128 INIT_LIST_HEAD(&btv->capture);
4129 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 v4l2_prio_init(&btv->prio);
4131
4132 init_timer(&btv->timeout);
4133 btv->timeout.function = bttv_irq_timeout;
4134 btv->timeout.data = (unsigned long)btv;
4135
Michael Krufky7c08fb02005-11-08 21:36:21 -08004136 btv->i2c_rc = -1;
4137 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 btv->has_radio=radio[btv->c.nr];
4140
4141 /* pci stuff (init, get irq/mmio, ... */
4142 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08004143 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08004145 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 btv->c.nr);
4147 return -EIO;
4148 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004149 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
4150 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 btv->c.nr);
4152 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 if (!request_mem_region(pci_resource_start(dev,0),
4155 pci_resource_len(dev,0),
4156 btv->c.name)) {
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004157 printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
4158 btv->c.nr,
4159 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 return -EBUSY;
4161 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004162 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 pci_set_command(dev);
4164 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004166 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
4167 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
4168 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
4169 bttv_num,btv->id, btv->revision, pci_name(dev));
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004170 printk("irq: %d, latency: %d, mmio: 0x%llx\n",
4171 btv->c.pci->irq, lat,
4172 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 schedule();
4174
Akinobu Mita5f1693f2006-12-20 10:08:56 -03004175 btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
4176 if (NULL == btv->bt848_mmio) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4178 result = -EIO;
4179 goto fail1;
4180 }
4181
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004182 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 bttv_idcard(btv);
4184
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004185 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004187 result = request_irq(btv->c.pci->irq, bttv_irq,
Thomas Gleixner8076fe32006-07-01 19:29:37 -07004188 IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004189 if (result < 0) {
4190 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 bttv_num,btv->c.pci->irq);
4192 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
4195 if (0 != bttv_handle_chipset(btv)) {
4196 result = -EIO;
4197 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199
4200 /* init options from insmod args */
4201 btv->opt_combfilter = combfilter;
4202 btv->opt_lumafilter = lumafilter;
4203 btv->opt_automute = automute;
4204 btv->opt_chroma_agc = chroma_agc;
4205 btv->opt_adc_crush = adc_crush;
4206 btv->opt_vcr_hack = vcr_hack;
4207 btv->opt_whitecrush_upper = whitecrush_upper;
4208 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004209 btv->opt_uv_ratio = uv_ratio;
4210 btv->opt_full_luma_range = full_luma_range;
4211 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212
4213 /* fill struct bttv with some useful defaults */
4214 btv->init.btv = btv;
4215 btv->init.ov.w.width = 320;
4216 btv->init.ov.w.height = 240;
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03004217 btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 btv->init.width = 320;
4219 btv->init.height = 240;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 btv->input = 0;
4221
4222 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004223 if (bttv_gpio)
4224 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225
4226 bttv_risc_init_main(btv);
4227 init_bt848(btv);
4228
4229 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004230 btwrite(0x00, BT848_GPIO_REG_INP);
4231 btwrite(0x00, BT848_GPIO_OUT_EN);
4232 if (bttv_verbose)
4233 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004235 /* needs to be done before i2c is registered */
4236 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004238 /* register i2c + gpio */
4239 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004241 /* some card-specific stuff (needs working i2c) */
4242 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 init_irqreg(btv);
4244
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004245 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 if (!bttv_tvcards[btv->c.type].no_video) {
4247 bttv_register_video(btv);
4248 bt848_bright(btv,32768);
4249 bt848_contrast(btv,32768);
4250 bt848_hue(btv,32768);
4251 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004252 audio_mute(btv, 1);
Trent Piepho333408f2007-07-03 15:08:10 -03004253 set_input(btv, 0, btv->tvnorm);
Michael Schimeke5bd0262007-01-18 16:17:39 -03004254 bttv_crop_reset(&btv->crop[0], btv->tvnorm);
4255 btv->crop[1] = btv->crop[0]; /* current = default */
4256 disclaim_vbi_lines(btv);
4257 disclaim_video_lines(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 }
4259
Jarod Wilsonf992a492007-03-24 15:23:50 -03004260 /* add subdevices and autoload dvb-bt8xx if needed */
4261 if (bttv_tvcards[btv->c.type].has_dvb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 bttv_sub_add_device(&btv->c, "dvb");
Jarod Wilsonf992a492007-03-24 15:23:50 -03004263 request_modules(btv);
4264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004266 bttv_input_init(btv);
4267
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 /* everything is fine */
4269 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004270 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271
4272 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004273 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
4275 fail1:
4276 if (btv->bt848_mmio)
4277 iounmap(btv->bt848_mmio);
4278 release_mem_region(pci_resource_start(btv->c.pci,0),
4279 pci_resource_len(btv->c.pci,0));
4280 pci_set_drvdata(dev,NULL);
4281 return result;
4282}
4283
4284static void __devexit bttv_remove(struct pci_dev *pci_dev)
4285{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004286 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
4288 if (bttv_verbose)
4289 printk("bttv%d: unloading\n",btv->c.nr);
4290
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004291 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 btand(~15, BT848_GPIO_DMA_CTL);
4293 btwrite(0, BT848_INT_MASK);
4294 btwrite(~0x0, BT848_INT_STAT);
4295 btwrite(0x0, BT848_GPIO_OUT_EN);
4296 if (bttv_gpio)
4297 bttv_gpio_tracking(btv,"cleanup");
4298
4299 /* tell gpio modules we are leaving ... */
4300 btv->shutdown=1;
4301 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004302 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004303 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004305 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 fini_bttv_i2c(btv);
4307
4308 /* unregister video4linux */
4309 bttv_unregister_video(btv);
4310
4311 /* free allocated memory */
4312 btcx_riscmem_free(btv->c.pci,&btv->main);
4313
4314 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004315 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004317 release_mem_region(pci_resource_start(btv->c.pci,0),
4318 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319
4320 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004321 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322}
4323
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004324#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4326{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004327 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 struct bttv_buffer_set idle;
4329 unsigned long flags;
4330
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004331 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332
4333 /* stop dma + irqs */
4334 spin_lock_irqsave(&btv->s_lock,flags);
4335 memset(&idle, 0, sizeof(idle));
4336 btv->state.video = btv->curr;
4337 btv->state.vbi = btv->cvbi;
4338 btv->state.loop_irq = btv->loop_irq;
4339 btv->curr = idle;
4340 btv->loop_irq = 0;
4341 bttv_buffer_activate_video(btv, &idle);
4342 bttv_buffer_activate_vbi(btv, NULL);
4343 bttv_set_dma(btv, 0);
4344 btwrite(0, BT848_INT_MASK);
4345 spin_unlock_irqrestore(&btv->s_lock,flags);
4346
4347 /* save bt878 state */
4348 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4349 btv->state.gpio_data = gpio_read();
4350
4351 /* save pci state */
4352 pci_save_state(pci_dev);
4353 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4354 pci_disable_device(pci_dev);
4355 btv->state.disabled = 1;
4356 }
4357 return 0;
4358}
4359
4360static int bttv_resume(struct pci_dev *pci_dev)
4361{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004362 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004364 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365
4366 dprintk("bttv%d: resume\n", btv->c.nr);
4367
4368 /* restore pci state */
4369 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004370 err=pci_enable_device(pci_dev);
4371 if (err) {
4372 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4373 btv->c.nr);
4374 return err;
4375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 btv->state.disabled = 0;
4377 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004378 err=pci_set_power_state(pci_dev, PCI_D0);
4379 if (err) {
4380 pci_disable_device(pci_dev);
4381 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4382 btv->c.nr);
4383 btv->state.disabled = 1;
4384 return err;
4385 }
4386
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 pci_restore_state(pci_dev);
4388
4389 /* restore bt878 state */
4390 bttv_reinit_bt848(btv);
4391 gpio_inout(0xffffff, btv->state.gpio_enable);
4392 gpio_write(btv->state.gpio_data);
4393
4394 /* restart dma */
4395 spin_lock_irqsave(&btv->s_lock,flags);
4396 btv->curr = btv->state.video;
4397 btv->cvbi = btv->state.vbi;
4398 btv->loop_irq = btv->state.loop_irq;
4399 bttv_buffer_activate_video(btv, &btv->curr);
4400 bttv_buffer_activate_vbi(btv, btv->cvbi);
4401 bttv_set_dma(btv, 0);
4402 spin_unlock_irqrestore(&btv->s_lock,flags);
4403 return 0;
4404}
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004405#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406
4407static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004408 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4409 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004411 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004413 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004415 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4416 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417};
4418
4419MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4420
4421static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004422 .name = "bttv",
4423 .id_table = bttv_pci_tbl,
4424 .probe = bttv_probe,
4425 .remove = __devexit_p(bttv_remove),
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004426#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 .suspend = bttv_suspend,
4428 .resume = bttv_resume,
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004429#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430};
4431
Adrian Bunk7d44e892007-12-11 19:23:43 -03004432static int __init bttv_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433{
Randy Dunlapc526e222006-07-15 09:08:26 -03004434 int ret;
4435
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 bttv_num = 0;
4437
4438 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4439 (BTTV_VERSION_CODE >> 16) & 0xff,
4440 (BTTV_VERSION_CODE >> 8) & 0xff,
4441 BTTV_VERSION_CODE & 0xff);
4442#ifdef SNAPSHOT
4443 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4444 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4445#endif
4446 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4447 gbuffers = 2;
4448 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4449 gbufsize = BTTV_MAX_FBUF;
4450 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4451 if (bttv_verbose)
4452 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4453 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4454
4455 bttv_check_chipset();
4456
Randy Dunlapc526e222006-07-15 09:08:26 -03004457 ret = bus_register(&bttv_sub_bus_type);
4458 if (ret < 0) {
4459 printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
4460 return ret;
4461 }
Otavio Salvador23047592006-01-09 15:25:17 -02004462 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463}
4464
Adrian Bunk7d44e892007-12-11 19:23:43 -03004465static void __exit bttv_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466{
4467 pci_unregister_driver(&bttv_pci_driver);
4468 bus_unregister(&bttv_sub_bus_type);
4469 return;
4470}
4471
4472module_init(bttv_init_module);
4473module_exit(bttv_cleanup_module);
4474
4475/*
4476 * Local variables:
4477 * c-basic-offset: 8
4478 * End:
4479 */