blob: f3de852517191d093cf86bbb94a99d736a9ca823 [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
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26
27#include <linux/init.h>
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/delay.h>
31#include <linux/errno.h>
32#include <linux/fs.h>
33#include <linux/kernel.h>
34#include <linux/sched.h>
35#include <linux/interrupt.h>
36#include <linux/kdev_t.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020037#include "bttvp.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020038#include <media/v4l2-common.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020039
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -070040#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include <asm/io.h>
43#include <asm/byteorder.h>
44
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070045#include "rds.h"
46
47
Linus Torvalds1da177e2005-04-16 15:20:36 -070048unsigned int bttv_num; /* number of Bt848s in use */
49struct bttv bttvs[BTTV_MAX];
50
51unsigned int bttv_debug = 0;
52unsigned int bttv_verbose = 1;
53unsigned int bttv_gpio = 0;
54
55/* config variables */
56#ifdef __BIG_ENDIAN
57static unsigned int bigendian=1;
58#else
59static unsigned int bigendian=0;
60#endif
61static unsigned int radio[BTTV_MAX];
62static unsigned int irq_debug = 0;
63static unsigned int gbuffers = 8;
64static unsigned int gbufsize = 0x208000;
65
66static int video_nr = -1;
67static int radio_nr = -1;
68static int vbi_nr = -1;
69static int debug_latency = 0;
70
71static unsigned int fdsr = 0;
72
73/* options */
74static unsigned int combfilter = 0;
75static unsigned int lumafilter = 0;
76static unsigned int automute = 1;
77static unsigned int chroma_agc = 0;
78static unsigned int adc_crush = 1;
79static unsigned int whitecrush_upper = 0xCF;
80static unsigned int whitecrush_lower = 0x7F;
81static unsigned int vcr_hack = 0;
82static unsigned int irq_iswitch = 0;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070083static unsigned int uv_ratio = 50;
84static unsigned int full_luma_range = 0;
85static unsigned int coring = 0;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070086extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
88/* API features (turn on/off stuff for testing) */
89static unsigned int v4l2 = 1;
90
91
92/* insmod args */
93module_param(bttv_verbose, int, 0644);
94module_param(bttv_gpio, int, 0644);
95module_param(bttv_debug, int, 0644);
96module_param(irq_debug, int, 0644);
97module_param(debug_latency, int, 0644);
98
99module_param(fdsr, int, 0444);
100module_param(video_nr, int, 0444);
101module_param(radio_nr, int, 0444);
102module_param(vbi_nr, int, 0444);
103module_param(gbuffers, int, 0444);
104module_param(gbufsize, int, 0444);
105
106module_param(v4l2, int, 0644);
107module_param(bigendian, int, 0644);
108module_param(irq_iswitch, int, 0644);
109module_param(combfilter, int, 0444);
110module_param(lumafilter, int, 0444);
111module_param(automute, int, 0444);
112module_param(chroma_agc, int, 0444);
113module_param(adc_crush, int, 0444);
114module_param(whitecrush_upper, int, 0444);
115module_param(whitecrush_lower, int, 0444);
116module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700117module_param(uv_ratio, int, 0444);
118module_param(full_luma_range, int, 0444);
119module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121module_param_array(radio, int, NULL, 0444);
122
123MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
124MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
125MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
126MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
127MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
128MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
129MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
130MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
131MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
132MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
133MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
134MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
135MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
136MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
137MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700138MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
139MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
140MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
143MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
144MODULE_LICENSE("GPL");
145
146/* ----------------------------------------------------------------------- */
147/* sysfs */
148
149static ssize_t show_card(struct class_device *cd, char *buf)
150{
151 struct video_device *vfd = to_video_device(cd);
152 struct bttv *btv = dev_get_drvdata(vfd->dev);
153 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
154}
155static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
156
157/* ----------------------------------------------------------------------- */
158/* static data */
159
160/* special timing tables from conexant... */
161static u8 SRAM_Table[][60] =
162{
163 /* PAL digital input over GPIO[7:0] */
164 {
165 45, // 45 bytes following
166 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
167 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
168 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
169 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
170 0x37,0x00,0xAF,0x21,0x00
171 },
172 /* NTSC digital input over GPIO[7:0] */
173 {
174 51, // 51 bytes following
175 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
176 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
177 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
178 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
179 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
180 0x00,
181 },
182 // TGB_NTSC392 // quartzsight
183 // This table has been modified to be used for Fusion Rev D
184 {
185 0x2A, // size of table = 42
186 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
187 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
188 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
189 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
190 0x20, 0x00
191 }
192};
193
194const struct bttv_tvnorm bttv_tvnorms[] = {
195 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800196 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
197 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 {
199 .v4l2_id = V4L2_STD_PAL,
200 .name = "PAL",
201 .Fsc = 35468950,
202 .swidth = 924,
203 .sheight = 576,
204 .totalwidth = 1135,
205 .adelay = 0x7f,
206 .bdelay = 0x72,
207 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
208 .scaledtwidth = 1135,
209 .hdelayx1 = 186,
210 .hactivex1 = 924,
211 .vdelay = 0x20,
212 .vbipack = 255,
213 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200214 /* ITU-R frame line number of the first VBI line
215 we can capture, of the first and second field. */
216 .vbistart = { 7,320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 },{
218 .v4l2_id = V4L2_STD_NTSC_M,
219 .name = "NTSC",
220 .Fsc = 28636363,
221 .swidth = 768,
222 .sheight = 480,
223 .totalwidth = 910,
224 .adelay = 0x68,
225 .bdelay = 0x5d,
226 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
227 .scaledtwidth = 910,
228 .hdelayx1 = 128,
229 .hactivex1 = 910,
230 .vdelay = 0x1a,
231 .vbipack = 144,
232 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200233 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 },{
235 .v4l2_id = V4L2_STD_SECAM,
236 .name = "SECAM",
237 .Fsc = 35468950,
238 .swidth = 924,
239 .sheight = 576,
240 .totalwidth = 1135,
241 .adelay = 0x7f,
242 .bdelay = 0xb0,
243 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
244 .scaledtwidth = 1135,
245 .hdelayx1 = 186,
246 .hactivex1 = 922,
247 .vdelay = 0x20,
248 .vbipack = 255,
249 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200250 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 },{
252 .v4l2_id = V4L2_STD_PAL_Nc,
253 .name = "PAL-Nc",
254 .Fsc = 28636363,
255 .swidth = 640,
256 .sheight = 576,
257 .totalwidth = 910,
258 .adelay = 0x68,
259 .bdelay = 0x5d,
260 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
261 .scaledtwidth = 780,
262 .hdelayx1 = 130,
263 .hactivex1 = 734,
264 .vdelay = 0x1a,
265 .vbipack = 144,
266 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200267 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 },{
269 .v4l2_id = V4L2_STD_PAL_M,
270 .name = "PAL-M",
271 .Fsc = 28636363,
272 .swidth = 640,
273 .sheight = 480,
274 .totalwidth = 910,
275 .adelay = 0x68,
276 .bdelay = 0x5d,
277 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
278 .scaledtwidth = 780,
279 .hdelayx1 = 135,
280 .hactivex1 = 754,
281 .vdelay = 0x1a,
282 .vbipack = 144,
283 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200284 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 },{
286 .v4l2_id = V4L2_STD_PAL_N,
287 .name = "PAL-N",
288 .Fsc = 35468950,
289 .swidth = 768,
290 .sheight = 576,
291 .totalwidth = 1135,
292 .adelay = 0x7f,
293 .bdelay = 0x72,
294 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
295 .scaledtwidth = 944,
296 .hdelayx1 = 186,
297 .hactivex1 = 922,
298 .vdelay = 0x20,
299 .vbipack = 144,
300 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200301 .vbistart = { 7, 320},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 },{
303 .v4l2_id = V4L2_STD_NTSC_M_JP,
304 .name = "NTSC-JP",
305 .Fsc = 28636363,
306 .swidth = 640,
307 .sheight = 480,
308 .totalwidth = 910,
309 .adelay = 0x68,
310 .bdelay = 0x5d,
311 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
312 .scaledtwidth = 780,
313 .hdelayx1 = 135,
314 .hactivex1 = 754,
315 .vdelay = 0x16,
316 .vbipack = 144,
317 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200318 .vbistart = {10, 273},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 },{
320 /* that one hopefully works with the strange timing
321 * which video recorders produce when playing a NTSC
322 * tape on a PAL TV ... */
323 .v4l2_id = V4L2_STD_PAL_60,
324 .name = "PAL-60",
325 .Fsc = 35468950,
326 .swidth = 924,
327 .sheight = 480,
328 .totalwidth = 1135,
329 .adelay = 0x7f,
330 .bdelay = 0x72,
331 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
332 .scaledtwidth = 1135,
333 .hdelayx1 = 186,
334 .hactivex1 = 924,
335 .vdelay = 0x1a,
336 .vbipack = 255,
337 .vtotal = 524,
338 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200339 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 }
341};
342static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
343
344/* ----------------------------------------------------------------------- */
345/* bttv format list
346 packed pixel formats must come first */
347static const struct bttv_format bttv_formats[] = {
348 {
349 .name = "8 bpp, gray",
350 .palette = VIDEO_PALETTE_GREY,
351 .fourcc = V4L2_PIX_FMT_GREY,
352 .btformat = BT848_COLOR_FMT_Y8,
353 .depth = 8,
354 .flags = FORMAT_FLAGS_PACKED,
355 },{
356 .name = "8 bpp, dithered color",
357 .palette = VIDEO_PALETTE_HI240,
358 .fourcc = V4L2_PIX_FMT_HI240,
359 .btformat = BT848_COLOR_FMT_RGB8,
360 .depth = 8,
361 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
362 },{
363 .name = "15 bpp RGB, le",
364 .palette = VIDEO_PALETTE_RGB555,
365 .fourcc = V4L2_PIX_FMT_RGB555,
366 .btformat = BT848_COLOR_FMT_RGB15,
367 .depth = 16,
368 .flags = FORMAT_FLAGS_PACKED,
369 },{
370 .name = "15 bpp RGB, be",
371 .palette = -1,
372 .fourcc = V4L2_PIX_FMT_RGB555X,
373 .btformat = BT848_COLOR_FMT_RGB15,
374 .btswap = 0x03, /* byteswap */
375 .depth = 16,
376 .flags = FORMAT_FLAGS_PACKED,
377 },{
378 .name = "16 bpp RGB, le",
379 .palette = VIDEO_PALETTE_RGB565,
380 .fourcc = V4L2_PIX_FMT_RGB565,
381 .btformat = BT848_COLOR_FMT_RGB16,
382 .depth = 16,
383 .flags = FORMAT_FLAGS_PACKED,
384 },{
385 .name = "16 bpp RGB, be",
386 .palette = -1,
387 .fourcc = V4L2_PIX_FMT_RGB565X,
388 .btformat = BT848_COLOR_FMT_RGB16,
389 .btswap = 0x03, /* byteswap */
390 .depth = 16,
391 .flags = FORMAT_FLAGS_PACKED,
392 },{
393 .name = "24 bpp RGB, le",
394 .palette = VIDEO_PALETTE_RGB24,
395 .fourcc = V4L2_PIX_FMT_BGR24,
396 .btformat = BT848_COLOR_FMT_RGB24,
397 .depth = 24,
398 .flags = FORMAT_FLAGS_PACKED,
399 },{
400 .name = "32 bpp RGB, le",
401 .palette = VIDEO_PALETTE_RGB32,
402 .fourcc = V4L2_PIX_FMT_BGR32,
403 .btformat = BT848_COLOR_FMT_RGB32,
404 .depth = 32,
405 .flags = FORMAT_FLAGS_PACKED,
406 },{
407 .name = "32 bpp RGB, be",
408 .palette = -1,
409 .fourcc = V4L2_PIX_FMT_RGB32,
410 .btformat = BT848_COLOR_FMT_RGB32,
411 .btswap = 0x0f, /* byte+word swap */
412 .depth = 32,
413 .flags = FORMAT_FLAGS_PACKED,
414 },{
415 .name = "4:2:2, packed, YUYV",
416 .palette = VIDEO_PALETTE_YUV422,
417 .fourcc = V4L2_PIX_FMT_YUYV,
418 .btformat = BT848_COLOR_FMT_YUY2,
419 .depth = 16,
420 .flags = FORMAT_FLAGS_PACKED,
421 },{
422 .name = "4:2:2, packed, YUYV",
423 .palette = VIDEO_PALETTE_YUYV,
424 .fourcc = V4L2_PIX_FMT_YUYV,
425 .btformat = BT848_COLOR_FMT_YUY2,
426 .depth = 16,
427 .flags = FORMAT_FLAGS_PACKED,
428 },{
429 .name = "4:2:2, packed, UYVY",
430 .palette = VIDEO_PALETTE_UYVY,
431 .fourcc = V4L2_PIX_FMT_UYVY,
432 .btformat = BT848_COLOR_FMT_YUY2,
433 .btswap = 0x03, /* byteswap */
434 .depth = 16,
435 .flags = FORMAT_FLAGS_PACKED,
436 },{
437 .name = "4:2:2, planar, Y-Cb-Cr",
438 .palette = VIDEO_PALETTE_YUV422P,
439 .fourcc = V4L2_PIX_FMT_YUV422P,
440 .btformat = BT848_COLOR_FMT_YCrCb422,
441 .depth = 16,
442 .flags = FORMAT_FLAGS_PLANAR,
443 .hshift = 1,
444 .vshift = 0,
445 },{
446 .name = "4:2:0, planar, Y-Cb-Cr",
447 .palette = VIDEO_PALETTE_YUV420P,
448 .fourcc = V4L2_PIX_FMT_YUV420,
449 .btformat = BT848_COLOR_FMT_YCrCb422,
450 .depth = 12,
451 .flags = FORMAT_FLAGS_PLANAR,
452 .hshift = 1,
453 .vshift = 1,
454 },{
455 .name = "4:2:0, planar, Y-Cr-Cb",
456 .palette = -1,
457 .fourcc = V4L2_PIX_FMT_YVU420,
458 .btformat = BT848_COLOR_FMT_YCrCb422,
459 .depth = 12,
460 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
461 .hshift = 1,
462 .vshift = 1,
463 },{
464 .name = "4:1:1, planar, Y-Cb-Cr",
465 .palette = VIDEO_PALETTE_YUV411P,
466 .fourcc = V4L2_PIX_FMT_YUV411P,
467 .btformat = BT848_COLOR_FMT_YCrCb411,
468 .depth = 12,
469 .flags = FORMAT_FLAGS_PLANAR,
470 .hshift = 2,
471 .vshift = 0,
472 },{
473 .name = "4:1:0, planar, Y-Cb-Cr",
474 .palette = VIDEO_PALETTE_YUV410P,
475 .fourcc = V4L2_PIX_FMT_YUV410,
476 .btformat = BT848_COLOR_FMT_YCrCb411,
477 .depth = 9,
478 .flags = FORMAT_FLAGS_PLANAR,
479 .hshift = 2,
480 .vshift = 2,
481 },{
482 .name = "4:1:0, planar, Y-Cr-Cb",
483 .palette = -1,
484 .fourcc = V4L2_PIX_FMT_YVU410,
485 .btformat = BT848_COLOR_FMT_YCrCb411,
486 .depth = 9,
487 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
488 .hshift = 2,
489 .vshift = 2,
490 },{
491 .name = "raw scanlines",
492 .palette = VIDEO_PALETTE_RAW,
493 .fourcc = -1,
494 .btformat = BT848_COLOR_FMT_RAW,
495 .depth = 8,
496 .flags = FORMAT_FLAGS_RAW,
497 }
498};
499static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
500
501/* ----------------------------------------------------------------------- */
502
503#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
504#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
505#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
506#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
507#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
508#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
509#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
510#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700511#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
512#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
513#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
514#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516static const struct v4l2_queryctrl no_ctl = {
517 .name = "42",
518 .flags = V4L2_CTRL_FLAG_DISABLED,
519};
520static const struct v4l2_queryctrl bttv_ctls[] = {
521 /* --- video --- */
522 {
523 .id = V4L2_CID_BRIGHTNESS,
524 .name = "Brightness",
525 .minimum = 0,
526 .maximum = 65535,
527 .step = 256,
528 .default_value = 32768,
529 .type = V4L2_CTRL_TYPE_INTEGER,
530 },{
531 .id = V4L2_CID_CONTRAST,
532 .name = "Contrast",
533 .minimum = 0,
534 .maximum = 65535,
535 .step = 128,
536 .default_value = 32768,
537 .type = V4L2_CTRL_TYPE_INTEGER,
538 },{
539 .id = V4L2_CID_SATURATION,
540 .name = "Saturation",
541 .minimum = 0,
542 .maximum = 65535,
543 .step = 128,
544 .default_value = 32768,
545 .type = V4L2_CTRL_TYPE_INTEGER,
546 },{
547 .id = V4L2_CID_HUE,
548 .name = "Hue",
549 .minimum = 0,
550 .maximum = 65535,
551 .step = 256,
552 .default_value = 32768,
553 .type = V4L2_CTRL_TYPE_INTEGER,
554 },
555 /* --- audio --- */
556 {
557 .id = V4L2_CID_AUDIO_MUTE,
558 .name = "Mute",
559 .minimum = 0,
560 .maximum = 1,
561 .type = V4L2_CTRL_TYPE_BOOLEAN,
562 },{
563 .id = V4L2_CID_AUDIO_VOLUME,
564 .name = "Volume",
565 .minimum = 0,
566 .maximum = 65535,
567 .step = 65535/100,
568 .default_value = 65535,
569 .type = V4L2_CTRL_TYPE_INTEGER,
570 },{
571 .id = V4L2_CID_AUDIO_BALANCE,
572 .name = "Balance",
573 .minimum = 0,
574 .maximum = 65535,
575 .step = 65535/100,
576 .default_value = 32768,
577 .type = V4L2_CTRL_TYPE_INTEGER,
578 },{
579 .id = V4L2_CID_AUDIO_BASS,
580 .name = "Bass",
581 .minimum = 0,
582 .maximum = 65535,
583 .step = 65535/100,
584 .default_value = 32768,
585 .type = V4L2_CTRL_TYPE_INTEGER,
586 },{
587 .id = V4L2_CID_AUDIO_TREBLE,
588 .name = "Treble",
589 .minimum = 0,
590 .maximum = 65535,
591 .step = 65535/100,
592 .default_value = 32768,
593 .type = V4L2_CTRL_TYPE_INTEGER,
594 },
595 /* --- private --- */
596 {
597 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
598 .name = "chroma agc",
599 .minimum = 0,
600 .maximum = 1,
601 .type = V4L2_CTRL_TYPE_BOOLEAN,
602 },{
603 .id = V4L2_CID_PRIVATE_COMBFILTER,
604 .name = "combfilter",
605 .minimum = 0,
606 .maximum = 1,
607 .type = V4L2_CTRL_TYPE_BOOLEAN,
608 },{
609 .id = V4L2_CID_PRIVATE_AUTOMUTE,
610 .name = "automute",
611 .minimum = 0,
612 .maximum = 1,
613 .type = V4L2_CTRL_TYPE_BOOLEAN,
614 },{
615 .id = V4L2_CID_PRIVATE_LUMAFILTER,
616 .name = "luma decimation filter",
617 .minimum = 0,
618 .maximum = 1,
619 .type = V4L2_CTRL_TYPE_BOOLEAN,
620 },{
621 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
622 .name = "agc crush",
623 .minimum = 0,
624 .maximum = 1,
625 .type = V4L2_CTRL_TYPE_BOOLEAN,
626 },{
627 .id = V4L2_CID_PRIVATE_VCR_HACK,
628 .name = "vcr hack",
629 .minimum = 0,
630 .maximum = 1,
631 .type = V4L2_CTRL_TYPE_BOOLEAN,
632 },{
633 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
634 .name = "whitecrush upper",
635 .minimum = 0,
636 .maximum = 255,
637 .step = 1,
638 .default_value = 0xCF,
639 .type = V4L2_CTRL_TYPE_INTEGER,
640 },{
641 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
642 .name = "whitecrush lower",
643 .minimum = 0,
644 .maximum = 255,
645 .step = 1,
646 .default_value = 0x7F,
647 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700648 },{
649 .id = V4L2_CID_PRIVATE_UV_RATIO,
650 .name = "uv ratio",
651 .minimum = 0,
652 .maximum = 100,
653 .step = 1,
654 .default_value = 50,
655 .type = V4L2_CTRL_TYPE_INTEGER,
656 },{
657 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
658 .name = "full luma range",
659 .minimum = 0,
660 .maximum = 1,
661 .type = V4L2_CTRL_TYPE_BOOLEAN,
662 },{
663 .id = V4L2_CID_PRIVATE_CORING,
664 .name = "coring",
665 .minimum = 0,
666 .maximum = 3,
667 .step = 1,
668 .default_value = 0,
669 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 }
671
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700672
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674};
675static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
676
677/* ----------------------------------------------------------------------- */
678/* resource management */
679
680static
681int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
682{
683 if (fh->resources & bit)
684 /* have it already allocated */
685 return 1;
686
687 /* is it free? */
688 down(&btv->reslock);
689 if (btv->resources & bit) {
690 /* no, someone else uses it */
691 up(&btv->reslock);
692 return 0;
693 }
694 /* it's free, grab it */
695 fh->resources |= bit;
696 btv->resources |= bit;
697 up(&btv->reslock);
698 return 1;
699}
700
701static
702int check_btres(struct bttv_fh *fh, int bit)
703{
704 return (fh->resources & bit);
705}
706
707static
708int locked_btres(struct bttv *btv, int bit)
709{
710 return (btv->resources & bit);
711}
712
713static
714void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
715{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if ((fh->resources & bits) != bits) {
717 /* trying to free ressources not allocated by us ... */
718 printk("bttv: BUG! (btres)\n");
719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 down(&btv->reslock);
721 fh->resources &= ~bits;
722 btv->resources &= ~bits;
723 up(&btv->reslock);
724}
725
726/* ----------------------------------------------------------------------- */
727/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
728
729/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
730 PLL_X = Reference pre-divider (0=1, 1=2)
731 PLL_C = Post divider (0=6, 1=4)
732 PLL_I = Integer input
733 PLL_F = Fractional input
734
735 F_input = 28.636363 MHz:
736 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
737*/
738
739static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
740{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800741 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800743 /* prevent overflows */
744 fin/=4;
745 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800747 fout*=12;
748 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800750 fout=(fout%fin)*256;
751 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800753 fout=(fout%fin)*256;
754 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800756 btwrite(fl, BT848_PLL_F_LO);
757 btwrite(fh, BT848_PLL_F_HI);
758 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759}
760
761static void set_pll(struct bttv *btv)
762{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800763 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800765 if (!btv->pll.pll_crystal)
766 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
769 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800770 return;
771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800773 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
774 /* no PLL needed */
775 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800776 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700777 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800778 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800779 btwrite(0x00,BT848_TGCTRL);
780 btwrite(0x00,BT848_PLL_XCI);
781 btv->pll.pll_current = 0;
782 return;
783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700785 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800786 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
788
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800789 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700791 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 msleep(10);
793
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800794 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800796 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800797 btwrite(0x08,BT848_TGCTRL);
798 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700799 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800800 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800801 }
802 }
803 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700804 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800805 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806}
807
808/* used to switch between the bt848's analog/digital video capture modes */
809static void bt848A_set_timing(struct bttv *btv)
810{
811 int i, len;
812 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
813 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
814
815 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
816 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
817 btv->c.nr,table_idx);
818
819 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800820 btwrite(0x00, BT848_TGCTRL);
821 btwrite(0x02, BT848_TGCTRL);
822 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 len=SRAM_Table[table_idx][0];
825 for(i = 1; i <= len; i++)
826 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
827 btv->pll.pll_ofreq = 27000000;
828
829 set_pll(btv);
830 btwrite(0x11, BT848_TGCTRL);
831 btwrite(0x41, BT848_DVSIF);
832 } else {
833 btv->pll.pll_ofreq = fsc;
834 set_pll(btv);
835 btwrite(0x0, BT848_DVSIF);
836 }
837}
838
839/* ----------------------------------------------------------------------- */
840
841static void bt848_bright(struct bttv *btv, int bright)
842{
843 int value;
844
845 // printk("bttv: set bright: %d\n",bright); // DEBUG
846 btv->bright = bright;
847
848 /* We want -128 to 127 we get 0-65535 */
849 value = (bright >> 8) - 128;
850 btwrite(value & 0xff, BT848_BRIGHT);
851}
852
853static void bt848_hue(struct bttv *btv, int hue)
854{
855 int value;
856
857 btv->hue = hue;
858
859 /* -128 to 127 */
860 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800861 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862}
863
864static void bt848_contrast(struct bttv *btv, int cont)
865{
866 int value,hibit;
867
868 btv->contrast = cont;
869
870 /* 0-511 */
871 value = (cont >> 7);
872 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800873 btwrite(value & 0xff, BT848_CONTRAST_LO);
874 btaor(hibit, ~4, BT848_E_CONTROL);
875 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878static void bt848_sat(struct bttv *btv, int color)
879{
880 int val_u,val_v,hibits;
881
882 btv->saturation = color;
883
884 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700885 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
886 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800887 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800889 btwrite(val_u & 0xff, BT848_SAT_U_LO);
890 btwrite(val_v & 0xff, BT848_SAT_V_LO);
891 btaor(hibits, ~3, BT848_E_CONTROL);
892 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
895/* ----------------------------------------------------------------------- */
896
897static int
898video_mux(struct bttv *btv, unsigned int input)
899{
900 int mux,mask2;
901
902 if (input >= bttv_tvcards[btv->c.type].video_inputs)
903 return -EINVAL;
904
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800905 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
907 if (mask2)
908 gpio_inout(mask2,mask2);
909
910 if (input == btv->svhs) {
911 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
912 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
913 } else {
914 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
915 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
916 }
917 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
918 btaor(mux<<5, ~(3<<5), BT848_IFORM);
919 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
920 btv->c.nr,input,mux);
921
922 /* card specific hook */
923 if(bttv_tvcards[btv->c.type].muxsel_hook)
924 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
925 return 0;
926}
927
928static char *audio_modes[] = {
929 "audio: tuner", "audio: radio", "audio: extern",
930 "audio: intern", "audio: off"
931};
932
933static int
934audio_mux(struct bttv *btv, int mode)
935{
936 int val,mux,i2c_mux,signal;
937
938 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
939 bttv_tvcards[btv->c.type].gpiomask);
940 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
941
942 switch (mode) {
943 case AUDIO_MUTE:
944 btv->audio |= AUDIO_MUTE;
945 break;
946 case AUDIO_UNMUTE:
947 btv->audio &= ~AUDIO_MUTE;
948 break;
949 case AUDIO_TUNER:
950 case AUDIO_RADIO:
951 case AUDIO_EXTERN:
952 case AUDIO_INTERN:
953 btv->audio &= AUDIO_MUTE;
954 btv->audio |= mode;
955 }
956 i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
957 if (btv->opt_automute && !signal && !btv->radio_user)
958 mux = AUDIO_OFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 val = bttv_tvcards[btv->c.type].audiomux[mux];
961 gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val);
962 if (bttv_gpio)
963 bttv_gpio_tracking(btv,audio_modes[mux]);
964 if (!in_interrupt())
965 bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));
966 return 0;
967}
968
969static void
970i2c_vidiocschan(struct bttv *btv)
971{
972 struct video_channel c;
973
974 memset(&c,0,sizeof(c));
975 c.norm = btv->tvnorm;
976 c.channel = btv->input;
977 bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -0800978 if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 bttv_tda9880_setnorm(btv,c.norm);
980}
981
982static int
983set_tvnorm(struct bttv *btv, unsigned int norm)
984{
985 const struct bttv_tvnorm *tvnorm;
986
987 if (norm < 0 || norm >= BTTV_TVNORMS)
988 return -EINVAL;
989
990 btv->tvnorm = norm;
991 tvnorm = &bttv_tvnorms[norm];
992
993 btwrite(tvnorm->adelay, BT848_ADELAY);
994 btwrite(tvnorm->bdelay, BT848_BDELAY);
995 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
996 BT848_IFORM);
997 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
998 btwrite(1, BT848_VBI_PACK_DEL);
999 bt848A_set_timing(btv);
1000
1001 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001002 case BTTV_BOARD_VOODOOTV_FM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 bttv_tda9880_setnorm(btv,norm);
1004 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 }
1006 return 0;
1007}
1008
1009static void
1010set_input(struct bttv *btv, unsigned int input)
1011{
1012 unsigned long flags;
1013
1014 btv->input = input;
1015 if (irq_iswitch) {
1016 spin_lock_irqsave(&btv->s_lock,flags);
1017 if (btv->curr.frame_irq) {
1018 /* active capture -> delayed input switch */
1019 btv->new_input = input;
1020 } else {
1021 video_mux(btv,input);
1022 }
1023 spin_unlock_irqrestore(&btv->s_lock,flags);
1024 } else {
1025 video_mux(btv,input);
1026 }
1027 audio_mux(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1028 AUDIO_TUNER : AUDIO_EXTERN));
1029 set_tvnorm(btv,btv->tvnorm);
1030 i2c_vidiocschan(btv);
1031}
1032
1033static void init_irqreg(struct bttv *btv)
1034{
1035 /* clear status */
1036 btwrite(0xfffffUL, BT848_INT_STAT);
1037
1038 if (bttv_tvcards[btv->c.type].no_video) {
1039 /* i2c only */
1040 btwrite(BT848_INT_I2CDONE,
1041 BT848_INT_MASK);
1042 } else {
1043 /* full video */
1044 btwrite((btv->triton1) |
1045 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1046 BT848_INT_SCERR |
1047 (fdsr ? BT848_INT_FDSR : 0) |
1048 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1049 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1050 BT848_INT_I2CDONE,
1051 BT848_INT_MASK);
1052 }
1053}
1054
1055static void init_bt848(struct bttv *btv)
1056{
1057 int val;
1058
1059 if (bttv_tvcards[btv->c.type].no_video) {
1060 /* very basic init only */
1061 init_irqreg(btv);
1062 return;
1063 }
1064
1065 btwrite(0x00, BT848_CAP_CTL);
1066 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1067 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1068
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001069 /* set planar and packed mode trigger points and */
1070 /* set rising edge of inverted GPINTR pin as irq trigger */
1071 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1072 BT848_GPIO_DMA_CTL_PLTP1_16|
1073 BT848_GPIO_DMA_CTL_PLTP23_16|
1074 BT848_GPIO_DMA_CTL_GPINTC|
1075 BT848_GPIO_DMA_CTL_GPINTI,
1076 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001079 btwrite(val, BT848_E_SCLOOP);
1080 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001082 btwrite(0x20, BT848_E_VSCALE_HI);
1083 btwrite(0x20, BT848_O_VSCALE_HI);
1084 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 BT848_ADC);
1086
1087 btwrite(whitecrush_upper, BT848_WC_UP);
1088 btwrite(whitecrush_lower, BT848_WC_DOWN);
1089
1090 if (btv->opt_lumafilter) {
1091 btwrite(0, BT848_E_CONTROL);
1092 btwrite(0, BT848_O_CONTROL);
1093 } else {
1094 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1095 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1096 }
1097
1098 bt848_bright(btv, btv->bright);
1099 bt848_hue(btv, btv->hue);
1100 bt848_contrast(btv, btv->contrast);
1101 bt848_sat(btv, btv->saturation);
1102
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001103 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 init_irqreg(btv);
1105}
1106
1107static void bttv_reinit_bt848(struct bttv *btv)
1108{
1109 unsigned long flags;
1110
1111 if (bttv_verbose)
1112 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1113 spin_lock_irqsave(&btv->s_lock,flags);
1114 btv->errors=0;
1115 bttv_set_dma(btv,0);
1116 spin_unlock_irqrestore(&btv->s_lock,flags);
1117
1118 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001119 btv->pll.pll_current = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 set_input(btv,btv->input);
1121}
1122
1123static int get_control(struct bttv *btv, struct v4l2_control *c)
1124{
1125 struct video_audio va;
1126 int i;
1127
1128 for (i = 0; i < BTTV_CTLS; i++)
1129 if (bttv_ctls[i].id == c->id)
1130 break;
1131 if (i == BTTV_CTLS)
1132 return -EINVAL;
1133 if (i >= 4 && i <= 8) {
1134 memset(&va,0,sizeof(va));
1135 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1136 if (btv->audio_hook)
1137 btv->audio_hook(btv,&va,0);
1138 }
1139 switch (c->id) {
1140 case V4L2_CID_BRIGHTNESS:
1141 c->value = btv->bright;
1142 break;
1143 case V4L2_CID_HUE:
1144 c->value = btv->hue;
1145 break;
1146 case V4L2_CID_CONTRAST:
1147 c->value = btv->contrast;
1148 break;
1149 case V4L2_CID_SATURATION:
1150 c->value = btv->saturation;
1151 break;
1152
1153 case V4L2_CID_AUDIO_MUTE:
1154 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1155 break;
1156 case V4L2_CID_AUDIO_VOLUME:
1157 c->value = va.volume;
1158 break;
1159 case V4L2_CID_AUDIO_BALANCE:
1160 c->value = va.balance;
1161 break;
1162 case V4L2_CID_AUDIO_BASS:
1163 c->value = va.bass;
1164 break;
1165 case V4L2_CID_AUDIO_TREBLE:
1166 c->value = va.treble;
1167 break;
1168
1169 case V4L2_CID_PRIVATE_CHROMA_AGC:
1170 c->value = btv->opt_chroma_agc;
1171 break;
1172 case V4L2_CID_PRIVATE_COMBFILTER:
1173 c->value = btv->opt_combfilter;
1174 break;
1175 case V4L2_CID_PRIVATE_LUMAFILTER:
1176 c->value = btv->opt_lumafilter;
1177 break;
1178 case V4L2_CID_PRIVATE_AUTOMUTE:
1179 c->value = btv->opt_automute;
1180 break;
1181 case V4L2_CID_PRIVATE_AGC_CRUSH:
1182 c->value = btv->opt_adc_crush;
1183 break;
1184 case V4L2_CID_PRIVATE_VCR_HACK:
1185 c->value = btv->opt_vcr_hack;
1186 break;
1187 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1188 c->value = btv->opt_whitecrush_upper;
1189 break;
1190 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1191 c->value = btv->opt_whitecrush_lower;
1192 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001193 case V4L2_CID_PRIVATE_UV_RATIO:
1194 c->value = btv->opt_uv_ratio;
1195 break;
1196 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1197 c->value = btv->opt_full_luma_range;
1198 break;
1199 case V4L2_CID_PRIVATE_CORING:
1200 c->value = btv->opt_coring;
1201 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 default:
1203 return -EINVAL;
1204 }
1205 return 0;
1206}
1207
1208static int set_control(struct bttv *btv, struct v4l2_control *c)
1209{
1210 struct video_audio va;
1211 int i,val;
1212
1213 for (i = 0; i < BTTV_CTLS; i++)
1214 if (bttv_ctls[i].id == c->id)
1215 break;
1216 if (i == BTTV_CTLS)
1217 return -EINVAL;
1218 if (i >= 4 && i <= 8) {
1219 memset(&va,0,sizeof(va));
1220 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1221 if (btv->audio_hook)
1222 btv->audio_hook(btv,&va,0);
1223 }
1224 switch (c->id) {
1225 case V4L2_CID_BRIGHTNESS:
1226 bt848_bright(btv,c->value);
1227 break;
1228 case V4L2_CID_HUE:
1229 bt848_hue(btv,c->value);
1230 break;
1231 case V4L2_CID_CONTRAST:
1232 bt848_contrast(btv,c->value);
1233 break;
1234 case V4L2_CID_SATURATION:
1235 bt848_sat(btv,c->value);
1236 break;
1237 case V4L2_CID_AUDIO_MUTE:
1238 if (c->value) {
1239 va.flags |= VIDEO_AUDIO_MUTE;
1240 audio_mux(btv, AUDIO_MUTE);
1241 } else {
1242 va.flags &= ~VIDEO_AUDIO_MUTE;
1243 audio_mux(btv, AUDIO_UNMUTE);
1244 }
1245 break;
1246
1247 case V4L2_CID_AUDIO_VOLUME:
1248 va.volume = c->value;
1249 break;
1250 case V4L2_CID_AUDIO_BALANCE:
1251 va.balance = c->value;
1252 break;
1253 case V4L2_CID_AUDIO_BASS:
1254 va.bass = c->value;
1255 break;
1256 case V4L2_CID_AUDIO_TREBLE:
1257 va.treble = c->value;
1258 break;
1259
1260 case V4L2_CID_PRIVATE_CHROMA_AGC:
1261 btv->opt_chroma_agc = c->value;
1262 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1263 btwrite(val, BT848_E_SCLOOP);
1264 btwrite(val, BT848_O_SCLOOP);
1265 break;
1266 case V4L2_CID_PRIVATE_COMBFILTER:
1267 btv->opt_combfilter = c->value;
1268 break;
1269 case V4L2_CID_PRIVATE_LUMAFILTER:
1270 btv->opt_lumafilter = c->value;
1271 if (btv->opt_lumafilter) {
1272 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1273 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1274 } else {
1275 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1276 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1277 }
1278 break;
1279 case V4L2_CID_PRIVATE_AUTOMUTE:
1280 btv->opt_automute = c->value;
1281 break;
1282 case V4L2_CID_PRIVATE_AGC_CRUSH:
1283 btv->opt_adc_crush = c->value;
1284 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1285 BT848_ADC);
1286 break;
1287 case V4L2_CID_PRIVATE_VCR_HACK:
1288 btv->opt_vcr_hack = c->value;
1289 break;
1290 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1291 btv->opt_whitecrush_upper = c->value;
1292 btwrite(c->value, BT848_WC_UP);
1293 break;
1294 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1295 btv->opt_whitecrush_lower = c->value;
1296 btwrite(c->value, BT848_WC_DOWN);
1297 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001298 case V4L2_CID_PRIVATE_UV_RATIO:
1299 btv->opt_uv_ratio = c->value;
1300 bt848_sat(btv, btv->saturation);
1301 break;
1302 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1303 btv->opt_full_luma_range = c->value;
1304 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1305 break;
1306 case V4L2_CID_PRIVATE_CORING:
1307 btv->opt_coring = c->value;
1308 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1309 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 default:
1311 return -EINVAL;
1312 }
1313 if (i >= 4 && i <= 8) {
1314 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1315 if (btv->audio_hook)
1316 btv->audio_hook(btv,&va,1);
1317 }
1318 return 0;
1319}
1320
1321/* ----------------------------------------------------------------------- */
1322
1323void bttv_gpio_tracking(struct bttv *btv, char *comment)
1324{
1325 unsigned int outbits, data;
1326 outbits = btread(BT848_GPIO_OUT_EN);
1327 data = btread(BT848_GPIO_DATA);
1328 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1329 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1330}
1331
1332static void bttv_field_count(struct bttv *btv)
1333{
1334 int need_count = 0;
1335
1336 if (btv->users)
1337 need_count++;
1338
1339 if (need_count) {
1340 /* start field counter */
1341 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1342 } else {
1343 /* stop field counter */
1344 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1345 btv->field_count = 0;
1346 }
1347}
1348
1349static const struct bttv_format*
1350format_by_palette(int palette)
1351{
1352 unsigned int i;
1353
1354 for (i = 0; i < BTTV_FORMATS; i++) {
1355 if (-1 == bttv_formats[i].palette)
1356 continue;
1357 if (bttv_formats[i].palette == palette)
1358 return bttv_formats+i;
1359 }
1360 return NULL;
1361}
1362
1363static const struct bttv_format*
1364format_by_fourcc(int fourcc)
1365{
1366 unsigned int i;
1367
1368 for (i = 0; i < BTTV_FORMATS; i++) {
1369 if (-1 == bttv_formats[i].fourcc)
1370 continue;
1371 if (bttv_formats[i].fourcc == fourcc)
1372 return bttv_formats+i;
1373 }
1374 return NULL;
1375}
1376
1377/* ----------------------------------------------------------------------- */
1378/* misc helpers */
1379
1380static int
1381bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1382 struct bttv_buffer *new)
1383{
1384 struct bttv_buffer *old;
1385 unsigned long flags;
1386 int retval = 0;
1387
1388 dprintk("switch_overlay: enter [new=%p]\n",new);
1389 if (new)
1390 new->vb.state = STATE_DONE;
1391 spin_lock_irqsave(&btv->s_lock,flags);
1392 old = btv->screen;
1393 btv->screen = new;
1394 btv->loop_irq |= 1;
1395 bttv_set_dma(btv, 0x03);
1396 spin_unlock_irqrestore(&btv->s_lock,flags);
1397 if (NULL == new)
1398 free_btres(btv,fh,RESOURCE_OVERLAY);
1399 if (NULL != old) {
1400 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
1401 bttv_dma_free(btv, old);
1402 kfree(old);
1403 }
1404 dprintk("switch_overlay: done\n");
1405 return retval;
1406}
1407
1408/* ----------------------------------------------------------------------- */
1409/* video4linux (1) interface */
1410
1411static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001412 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 unsigned int width, unsigned int height,
1414 enum v4l2_field field)
1415{
1416 int redo_dma_risc = 0;
1417 int rc;
1418
1419 /* check settings */
1420 if (NULL == fmt)
1421 return -EINVAL;
1422 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1423 width = RAW_BPL;
1424 height = RAW_LINES*2;
1425 if (width*height > buf->vb.bsize)
1426 return -EINVAL;
1427 buf->vb.size = buf->vb.bsize;
1428 } else {
1429 if (width < 48 ||
1430 height < 32 ||
1431 width > bttv_tvnorms[btv->tvnorm].swidth ||
1432 height > bttv_tvnorms[btv->tvnorm].sheight)
1433 return -EINVAL;
1434 buf->vb.size = (width * height * fmt->depth) >> 3;
1435 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1436 return -EINVAL;
1437 }
1438
1439 /* alloc + fill struct bttv_buffer (if changed) */
1440 if (buf->vb.width != width || buf->vb.height != height ||
1441 buf->vb.field != field ||
1442 buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
1443 buf->vb.width = width;
1444 buf->vb.height = height;
1445 buf->vb.field = field;
1446 buf->tvnorm = btv->tvnorm;
1447 buf->fmt = fmt;
1448 redo_dma_risc = 1;
1449 }
1450
1451 /* alloc risc memory */
1452 if (STATE_NEEDS_INIT == buf->vb.state) {
1453 redo_dma_risc = 1;
1454 if (0 != (rc = videobuf_iolock(btv->c.pci,&buf->vb,&btv->fbuf)))
1455 goto fail;
1456 }
1457
1458 if (redo_dma_risc)
1459 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1460 goto fail;
1461
1462 buf->vb.state = STATE_PREPARED;
1463 return 0;
1464
1465 fail:
1466 bttv_dma_free(btv,buf);
1467 return rc;
1468}
1469
1470static int
1471buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1472{
1473 struct bttv_fh *fh = q->priv_data;
1474
1475 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1476 if (0 == *count)
1477 *count = gbuffers;
1478 while (*size * *count > gbuffers * gbufsize)
1479 (*count)--;
1480 return 0;
1481}
1482
1483static int
1484buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1485 enum v4l2_field field)
1486{
1487 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1488 struct bttv_fh *fh = q->priv_data;
1489
1490 return bttv_prepare_buffer(fh->btv, buf, fh->fmt,
1491 fh->width, fh->height, field);
1492}
1493
1494static void
1495buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1496{
1497 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1498 struct bttv_fh *fh = q->priv_data;
1499 struct bttv *btv = fh->btv;
1500
1501 buf->vb.state = STATE_QUEUED;
1502 list_add_tail(&buf->vb.queue,&btv->capture);
1503 if (!btv->curr.frame_irq) {
1504 btv->loop_irq |= 1;
1505 bttv_set_dma(btv, 0x03);
1506 }
1507}
1508
1509static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1510{
1511 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1512 struct bttv_fh *fh = q->priv_data;
1513
1514 bttv_dma_free(fh->btv,buf);
1515}
1516
1517static struct videobuf_queue_ops bttv_video_qops = {
1518 .buf_setup = buffer_setup,
1519 .buf_prepare = buffer_prepare,
1520 .buf_queue = buffer_queue,
1521 .buf_release = buffer_release,
1522};
1523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1525{
1526 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001527 case BTTV_VERSION:
1528 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 /* *** v4l1 *** ************************************************ */
1531 case VIDIOCGFREQ:
1532 {
1533 unsigned long *freq = arg;
1534 *freq = btv->freq;
1535 return 0;
1536 }
1537 case VIDIOCSFREQ:
1538 {
1539 unsigned long *freq = arg;
1540 down(&btv->lock);
1541 btv->freq=*freq;
1542 bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
1543 if (btv->has_matchbox && btv->radio_user)
1544 tea5757_set_freq(btv,*freq);
1545 up(&btv->lock);
1546 return 0;
1547 }
1548
1549 case VIDIOCGTUNER:
1550 {
1551 struct video_tuner *v = arg;
1552
1553 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1554 return -EINVAL;
1555 if (v->tuner) /* Only tuner 0 */
1556 return -EINVAL;
1557 strcpy(v->name, "Television");
1558 v->rangelow = 0;
1559 v->rangehigh = 0x7FFFFFFF;
1560 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1561 v->mode = btv->tvnorm;
1562 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1563 bttv_call_i2c_clients(btv,cmd,v);
1564 return 0;
1565 }
1566 case VIDIOCSTUNER:
1567 {
1568 struct video_tuner *v = arg;
1569
1570 if (v->tuner) /* Only tuner 0 */
1571 return -EINVAL;
1572 if (v->mode >= BTTV_TVNORMS)
1573 return -EINVAL;
1574
1575 down(&btv->lock);
1576 set_tvnorm(btv,v->mode);
1577 bttv_call_i2c_clients(btv,cmd,v);
1578 up(&btv->lock);
1579 return 0;
1580 }
1581
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001582 case VIDIOCGCHAN:
1583 {
1584 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 unsigned int channel = v->channel;
1586
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001587 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1588 return -EINVAL;
1589 v->tuners=0;
1590 v->flags = VIDEO_VC_AUDIO;
1591 v->type = VIDEO_TYPE_CAMERA;
1592 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001594 strcpy(v->name,"Television");
1595 v->flags|=VIDEO_VC_TUNER;
1596 v->type=VIDEO_TYPE_TV;
1597 v->tuners=1;
1598 } else if (channel == btv->svhs) {
1599 strcpy(v->name,"S-Video");
1600 } else {
1601 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 }
1603 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001604 }
1605 case VIDIOCSCHAN:
1606 {
1607 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 unsigned int channel = v->channel;
1609
1610 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1611 return -EINVAL;
1612 if (v->norm >= BTTV_TVNORMS)
1613 return -EINVAL;
1614
1615 down(&btv->lock);
1616 if (channel == btv->input &&
1617 v->norm == btv->tvnorm) {
1618 /* nothing to do */
1619 up(&btv->lock);
1620 return 0;
1621 }
1622
1623 btv->tvnorm = v->norm;
1624 set_input(btv,v->channel);
1625 up(&btv->lock);
1626 return 0;
1627 }
1628
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001629 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 {
1631 struct video_audio *v = arg;
1632
1633 memset(v,0,sizeof(*v));
1634 strcpy(v->name,"Television");
1635 v->flags |= VIDEO_AUDIO_MUTABLE;
1636 v->mode = VIDEO_SOUND_MONO;
1637
1638 down(&btv->lock);
1639 bttv_call_i2c_clients(btv,cmd,v);
1640
1641 /* card specific hooks */
1642 if (btv->audio_hook)
1643 btv->audio_hook(btv,v,0);
1644
1645 up(&btv->lock);
1646 return 0;
1647 }
1648 case VIDIOCSAUDIO:
1649 {
1650 struct video_audio *v = arg;
1651 unsigned int audio = v->audio;
1652
1653 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
1654 return -EINVAL;
1655
1656 down(&btv->lock);
1657 audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE);
1658 bttv_call_i2c_clients(btv,cmd,v);
1659
1660 /* card specific hooks */
1661 if (btv->audio_hook)
1662 btv->audio_hook(btv,v,1);
1663
1664 up(&btv->lock);
1665 return 0;
1666 }
1667
1668 /* *** v4l2 *** ************************************************ */
1669 case VIDIOC_ENUMSTD:
1670 {
1671 struct v4l2_standard *e = arg;
1672 unsigned int index = e->index;
1673
1674 if (index >= BTTV_TVNORMS)
1675 return -EINVAL;
1676 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1677 bttv_tvnorms[e->index].name);
1678 e->index = index;
1679 return 0;
1680 }
1681 case VIDIOC_G_STD:
1682 {
1683 v4l2_std_id *id = arg;
1684 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1685 return 0;
1686 }
1687 case VIDIOC_S_STD:
1688 {
1689 v4l2_std_id *id = arg;
1690 unsigned int i;
1691
1692 for (i = 0; i < BTTV_TVNORMS; i++)
1693 if (*id & bttv_tvnorms[i].v4l2_id)
1694 break;
1695 if (i == BTTV_TVNORMS)
1696 return -EINVAL;
1697
1698 down(&btv->lock);
1699 set_tvnorm(btv,i);
1700 i2c_vidiocschan(btv);
1701 up(&btv->lock);
1702 return 0;
1703 }
1704 case VIDIOC_QUERYSTD:
1705 {
1706 v4l2_std_id *id = arg;
1707
1708 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1709 *id = V4L2_STD_625_50;
1710 else
1711 *id = V4L2_STD_525_60;
1712 return 0;
1713 }
1714
1715 case VIDIOC_ENUMINPUT:
1716 {
1717 struct v4l2_input *i = arg;
1718 unsigned int n;
1719
1720 n = i->index;
1721 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1722 return -EINVAL;
1723 memset(i,0,sizeof(*i));
1724 i->index = n;
1725 i->type = V4L2_INPUT_TYPE_CAMERA;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001726 i->audioset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1728 sprintf(i->name, "Television");
1729 i->type = V4L2_INPUT_TYPE_TUNER;
1730 i->tuner = 0;
1731 } else if (i->index == btv->svhs) {
1732 sprintf(i->name, "S-Video");
1733 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001734 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
1736 if (i->index == btv->input) {
1737 __u32 dstatus = btread(BT848_DSTATUS);
1738 if (0 == (dstatus & BT848_DSTATUS_PRES))
1739 i->status |= V4L2_IN_ST_NO_SIGNAL;
1740 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1741 i->status |= V4L2_IN_ST_NO_H_LOCK;
1742 }
1743 for (n = 0; n < BTTV_TVNORMS; n++)
1744 i->std |= bttv_tvnorms[n].v4l2_id;
1745 return 0;
1746 }
1747 case VIDIOC_G_INPUT:
1748 {
1749 int *i = arg;
1750 *i = btv->input;
1751 return 0;
1752 }
1753 case VIDIOC_S_INPUT:
1754 {
1755 unsigned int *i = arg;
1756
1757 if (*i > bttv_tvcards[btv->c.type].video_inputs)
1758 return -EINVAL;
1759 down(&btv->lock);
1760 set_input(btv,*i);
1761 up(&btv->lock);
1762 return 0;
1763 }
1764
1765 case VIDIOC_G_TUNER:
1766 {
1767 struct v4l2_tuner *t = arg;
1768
1769 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1770 return -EINVAL;
1771 if (0 != t->index)
1772 return -EINVAL;
1773 down(&btv->lock);
1774 memset(t,0,sizeof(*t));
1775 strcpy(t->name, "Television");
1776 t->type = V4L2_TUNER_ANALOG_TV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 t->capability = V4L2_TUNER_CAP_NORM;
1778 t->rxsubchans = V4L2_TUNER_SUB_MONO;
1779 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
1780 t->signal = 0xffff;
1781 {
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001782 struct video_tuner tuner;
1783
1784 memset(&tuner, 0, sizeof (tuner));
1785 tuner.rangehigh = 0xffffffffUL;
1786 bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);
1787 t->rangelow = tuner.rangelow;
1788 t->rangehigh = tuner.rangehigh;
1789 }
1790 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 /* Hmmm ... */
1792 struct video_audio va;
1793 memset(&va, 0, sizeof(struct video_audio));
1794 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1795 if (btv->audio_hook)
1796 btv->audio_hook(btv,&va,0);
1797 if(va.mode & VIDEO_SOUND_STEREO) {
1798 t->audmode = V4L2_TUNER_MODE_STEREO;
1799 t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
1800 }
1801 if(va.mode & VIDEO_SOUND_LANG1) {
1802 t->audmode = V4L2_TUNER_MODE_LANG1;
1803 t->rxsubchans = V4L2_TUNER_SUB_LANG1
1804 | V4L2_TUNER_SUB_LANG2;
1805 }
1806 }
1807 /* FIXME: fill capability+audmode */
1808 up(&btv->lock);
1809 return 0;
1810 }
1811 case VIDIOC_S_TUNER:
1812 {
1813 struct v4l2_tuner *t = arg;
1814
1815 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1816 return -EINVAL;
1817 if (0 != t->index)
1818 return -EINVAL;
1819 down(&btv->lock);
1820 {
1821 struct video_audio va;
1822 memset(&va, 0, sizeof(struct video_audio));
1823 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1824 if (t->audmode == V4L2_TUNER_MODE_MONO)
1825 va.mode = VIDEO_SOUND_MONO;
1826 else if (t->audmode == V4L2_TUNER_MODE_STEREO)
1827 va.mode = VIDEO_SOUND_STEREO;
1828 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
1829 va.mode = VIDEO_SOUND_LANG1;
1830 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
1831 va.mode = VIDEO_SOUND_LANG2;
1832 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1833 if (btv->audio_hook)
1834 btv->audio_hook(btv,&va,1);
1835 }
1836 up(&btv->lock);
1837 return 0;
1838 }
1839
1840 case VIDIOC_G_FREQUENCY:
1841 {
1842 struct v4l2_frequency *f = arg;
1843
1844 memset(f,0,sizeof(*f));
1845 f->type = V4L2_TUNER_ANALOG_TV;
1846 f->frequency = btv->freq;
1847 return 0;
1848 }
1849 case VIDIOC_S_FREQUENCY:
1850 {
1851 struct v4l2_frequency *f = arg;
1852
1853 if (unlikely(f->tuner != 0))
1854 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07001855 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 return -EINVAL;
1857 down(&btv->lock);
1858 btv->freq = f->frequency;
1859 bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
1860 if (btv->has_matchbox && btv->radio_user)
1861 tea5757_set_freq(btv,btv->freq);
1862 up(&btv->lock);
1863 return 0;
1864 }
Hans Verkuil299392b2005-11-08 21:37:42 -08001865 case VIDIOC_LOG_STATUS:
1866 {
Luiz Capitulino97cb4452005-12-01 00:51:24 -08001867 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil299392b2005-11-08 21:37:42 -08001868 return 0;
1869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 default:
1872 return -ENOIOCTLCMD;
1873
1874 }
1875 return 0;
1876}
1877
1878static int verify_window(const struct bttv_tvnorm *tvn,
1879 struct v4l2_window *win, int fixup)
1880{
1881 enum v4l2_field field;
1882 int maxw, maxh;
1883
1884 if (win->w.width < 48 || win->w.height < 32)
1885 return -EINVAL;
1886 if (win->clipcount > 2048)
1887 return -EINVAL;
1888
1889 field = win->field;
1890 maxw = tvn->swidth;
1891 maxh = tvn->sheight;
1892
1893 if (V4L2_FIELD_ANY == field) {
1894 field = (win->w.height > maxh/2)
1895 ? V4L2_FIELD_INTERLACED
1896 : V4L2_FIELD_TOP;
1897 }
1898 switch (field) {
1899 case V4L2_FIELD_TOP:
1900 case V4L2_FIELD_BOTTOM:
1901 maxh = maxh / 2;
1902 break;
1903 case V4L2_FIELD_INTERLACED:
1904 break;
1905 default:
1906 return -EINVAL;
1907 }
1908
1909 if (!fixup && (win->w.width > maxw || win->w.height > maxh))
1910 return -EINVAL;
1911
1912 if (win->w.width > maxw)
1913 win->w.width = maxw;
1914 if (win->w.height > maxh)
1915 win->w.height = maxh;
1916 win->field = field;
1917 return 0;
1918}
1919
1920static int setup_window(struct bttv_fh *fh, struct bttv *btv,
1921 struct v4l2_window *win, int fixup)
1922{
1923 struct v4l2_clip *clips = NULL;
1924 int n,size,retval = 0;
1925
1926 if (NULL == fh->ovfmt)
1927 return -EINVAL;
1928 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
1929 return -EINVAL;
1930 retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
1931 if (0 != retval)
1932 return retval;
1933
1934 /* copy clips -- luckily v4l1 + v4l2 are binary
1935 compatible here ...*/
1936 n = win->clipcount;
1937 size = sizeof(*clips)*(n+4);
1938 clips = kmalloc(size,GFP_KERNEL);
1939 if (NULL == clips)
1940 return -ENOMEM;
1941 if (n > 0) {
1942 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
1943 kfree(clips);
1944 return -EFAULT;
1945 }
1946 }
1947 /* clip against screen */
1948 if (NULL != btv->fbuf.base)
1949 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
1950 &win->w, clips, n);
1951 btcx_sort_clips(clips,n);
1952
1953 /* 4-byte alignments */
1954 switch (fh->ovfmt->depth) {
1955 case 8:
1956 case 24:
1957 btcx_align(&win->w, clips, n, 3);
1958 break;
1959 case 16:
1960 btcx_align(&win->w, clips, n, 1);
1961 break;
1962 case 32:
1963 /* no alignment fixups needed */
1964 break;
1965 default:
1966 BUG();
1967 }
1968
1969 down(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001970 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 fh->ov.clips = clips;
1972 fh->ov.nclips = n;
1973
1974 fh->ov.w = win->w;
1975 fh->ov.field = win->field;
1976 fh->ov.setup_ok = 1;
1977 btv->init.ov.w.width = win->w.width;
1978 btv->init.ov.w.height = win->w.height;
1979 btv->init.ov.field = win->field;
1980
1981 /* update overlay if needed */
1982 retval = 0;
1983 if (check_btres(fh, RESOURCE_OVERLAY)) {
1984 struct bttv_buffer *new;
1985
1986 new = videobuf_alloc(sizeof(*new));
1987 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
1988 retval = bttv_switch_overlay(btv,fh,new);
1989 }
1990 up(&fh->cap.lock);
1991 return retval;
1992}
1993
1994/* ----------------------------------------------------------------------- */
1995
1996static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
1997{
1998 struct videobuf_queue* q = NULL;
1999
2000 switch (fh->type) {
2001 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2002 q = &fh->cap;
2003 break;
2004 case V4L2_BUF_TYPE_VBI_CAPTURE:
2005 q = &fh->vbi;
2006 break;
2007 default:
2008 BUG();
2009 }
2010 return q;
2011}
2012
2013static int bttv_resource(struct bttv_fh *fh)
2014{
2015 int res = 0;
2016
2017 switch (fh->type) {
2018 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2019 res = RESOURCE_VIDEO;
2020 break;
2021 case V4L2_BUF_TYPE_VBI_CAPTURE:
2022 res = RESOURCE_VBI;
2023 break;
2024 default:
2025 BUG();
2026 }
2027 return res;
2028}
2029
2030static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2031{
2032 struct videobuf_queue *q = bttv_queue(fh);
2033 int res = bttv_resource(fh);
2034
2035 if (check_btres(fh,res))
2036 return -EBUSY;
2037 if (videobuf_queue_is_busy(q))
2038 return -EBUSY;
2039 fh->type = type;
2040 return 0;
2041}
2042
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002043static void
2044pix_format_set_size (struct v4l2_pix_format * f,
2045 const struct bttv_format * fmt,
2046 unsigned int width,
2047 unsigned int height)
2048{
2049 f->width = width;
2050 f->height = height;
2051
2052 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2053 f->bytesperline = width; /* Y plane */
2054 f->sizeimage = (width * height * fmt->depth) >> 3;
2055 } else {
2056 f->bytesperline = (width * fmt->depth) >> 3;
2057 f->sizeimage = height * f->bytesperline;
2058 }
2059}
2060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2062{
2063 switch (f->type) {
2064 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2065 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002066 pix_format_set_size (&f->fmt.pix, fh->fmt,
2067 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 f->fmt.pix.field = fh->cap.field;
2069 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 return 0;
2071 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2072 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2073 f->fmt.win.w = fh->ov.w;
2074 f->fmt.win.field = fh->ov.field;
2075 return 0;
2076 case V4L2_BUF_TYPE_VBI_CAPTURE:
2077 bttv_vbi_get_fmt(fh,f);
2078 return 0;
2079 default:
2080 return -EINVAL;
2081 }
2082}
2083
2084static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
2085 struct v4l2_format *f)
2086{
2087 switch (f->type) {
2088 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2089 {
2090 const struct bttv_format *fmt;
2091 enum v4l2_field field;
2092 unsigned int maxw,maxh;
2093
2094 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2095 if (NULL == fmt)
2096 return -EINVAL;
2097
2098 /* fixup format */
2099 maxw = bttv_tvnorms[btv->tvnorm].swidth;
2100 maxh = bttv_tvnorms[btv->tvnorm].sheight;
2101 field = f->fmt.pix.field;
2102 if (V4L2_FIELD_ANY == field)
2103 field = (f->fmt.pix.height > maxh/2)
2104 ? V4L2_FIELD_INTERLACED
2105 : V4L2_FIELD_BOTTOM;
2106 if (V4L2_FIELD_SEQ_BT == field)
2107 field = V4L2_FIELD_SEQ_TB;
2108 switch (field) {
2109 case V4L2_FIELD_TOP:
2110 case V4L2_FIELD_BOTTOM:
2111 case V4L2_FIELD_ALTERNATE:
2112 maxh = maxh/2;
2113 break;
2114 case V4L2_FIELD_INTERLACED:
2115 break;
2116 case V4L2_FIELD_SEQ_TB:
2117 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2118 return -EINVAL;
2119 break;
2120 default:
2121 return -EINVAL;
2122 }
2123
2124 /* update data for the application */
2125 f->fmt.pix.field = field;
2126 if (f->fmt.pix.width < 48)
2127 f->fmt.pix.width = 48;
2128 if (f->fmt.pix.height < 32)
2129 f->fmt.pix.height = 32;
2130 if (f->fmt.pix.width > maxw)
2131 f->fmt.pix.width = maxw;
2132 if (f->fmt.pix.height > maxh)
2133 f->fmt.pix.height = maxh;
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002134 pix_format_set_size (&f->fmt.pix, fmt,
2135 f->fmt.pix.width & ~3,
2136 f->fmt.pix.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
2138 return 0;
2139 }
2140 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2141 return verify_window(&bttv_tvnorms[btv->tvnorm],
2142 &f->fmt.win, 1);
2143 case V4L2_BUF_TYPE_VBI_CAPTURE:
2144 bttv_vbi_try_fmt(fh,f);
2145 return 0;
2146 default:
2147 return -EINVAL;
2148 }
2149}
2150
2151static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2152 struct v4l2_format *f)
2153{
2154 int retval;
2155
2156 switch (f->type) {
2157 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2158 {
2159 const struct bttv_format *fmt;
2160
2161 retval = bttv_switch_type(fh,f->type);
2162 if (0 != retval)
2163 return retval;
2164 retval = bttv_try_fmt(fh,btv,f);
2165 if (0 != retval)
2166 return retval;
2167 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2168
2169 /* update our state informations */
2170 down(&fh->cap.lock);
2171 fh->fmt = fmt;
2172 fh->cap.field = f->fmt.pix.field;
2173 fh->cap.last = V4L2_FIELD_NONE;
2174 fh->width = f->fmt.pix.width;
2175 fh->height = f->fmt.pix.height;
2176 btv->init.fmt = fmt;
2177 btv->init.width = f->fmt.pix.width;
2178 btv->init.height = f->fmt.pix.height;
2179 up(&fh->cap.lock);
2180
2181 return 0;
2182 }
2183 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002184 if (no_overlay > 0) {
2185 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2186 return -EINVAL;
2187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 return setup_window(fh, btv, &f->fmt.win, 1);
2189 case V4L2_BUF_TYPE_VBI_CAPTURE:
2190 retval = bttv_switch_type(fh,f->type);
2191 if (0 != retval)
2192 return retval;
2193 if (locked_btres(fh->btv, RESOURCE_VBI))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002194 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 bttv_vbi_try_fmt(fh,f);
2196 bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
2197 bttv_vbi_get_fmt(fh,f);
2198 return 0;
2199 default:
2200 return -EINVAL;
2201 }
2202}
2203
2204static int bttv_do_ioctl(struct inode *inode, struct file *file,
2205 unsigned int cmd, void *arg)
2206{
2207 struct bttv_fh *fh = file->private_data;
2208 struct bttv *btv = fh->btv;
2209 unsigned long flags;
2210 int retval = 0;
2211
Michael Krufky5e453dc2006-01-09 15:32:31 -02002212 if (bttv_debug > 1)
2213 v4l_print_ioctl(btv->c.name, cmd);
2214
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 if (btv->errors)
2216 bttv_reinit_bt848(btv);
2217
2218 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002219 case VIDIOCSFREQ:
2220 case VIDIOCSTUNER:
2221 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 case VIDIOC_S_CTRL:
2223 case VIDIOC_S_STD:
2224 case VIDIOC_S_INPUT:
2225 case VIDIOC_S_TUNER:
2226 case VIDIOC_S_FREQUENCY:
2227 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2228 if (0 != retval)
2229 return retval;
2230 };
2231
2232 switch (cmd) {
2233
2234 /* *** v4l1 *** ************************************************ */
2235 case VIDIOCGCAP:
2236 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002237 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002240 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2242 /* vbi */
2243 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2244 } else {
2245 /* others */
2246 cap->type = VID_TYPE_CAPTURE|
2247 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 VID_TYPE_CLIPPING|
2249 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002250 if (no_overlay <= 0)
2251 cap->type |= VID_TYPE_OVERLAY;
2252
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2254 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2255 cap->minwidth = 48;
2256 cap->minheight = 32;
2257 }
2258 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2259 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002260 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 }
2262
2263 case VIDIOCGPICT:
2264 {
2265 struct video_picture *pic = arg;
2266
2267 memset(pic,0,sizeof(*pic));
2268 pic->brightness = btv->bright;
2269 pic->contrast = btv->contrast;
2270 pic->hue = btv->hue;
2271 pic->colour = btv->saturation;
2272 if (fh->fmt) {
2273 pic->depth = fh->fmt->depth;
2274 pic->palette = fh->fmt->palette;
2275 }
2276 return 0;
2277 }
2278 case VIDIOCSPICT:
2279 {
2280 struct video_picture *pic = arg;
2281 const struct bttv_format *fmt;
2282
2283 fmt = format_by_palette(pic->palette);
2284 if (NULL == fmt)
2285 return -EINVAL;
2286 down(&fh->cap.lock);
2287 if (fmt->depth != pic->depth) {
2288 retval = -EINVAL;
2289 goto fh_unlock_and_return;
2290 }
Michael H. Schimek13c72802005-12-01 00:51:37 -08002291 if (fmt->flags & FORMAT_FLAGS_RAW) {
2292 /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
2293 RAW_LINES * 2. F1 is stored at offset 0, F2
2294 at buffer size / 2. */
2295 fh->width = RAW_BPL;
2296 fh->height = gbufsize / RAW_BPL;
2297 btv->init.width = RAW_BPL;
2298 btv->init.height = gbufsize / RAW_BPL;
2299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 fh->ovfmt = fmt;
2301 fh->fmt = fmt;
2302 btv->init.ovfmt = fmt;
2303 btv->init.fmt = fmt;
2304 if (bigendian) {
2305 /* dirty hack time: swap bytes for overlay if the
2306 display adaptor is big endian (insmod option) */
2307 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2308 fmt->palette == VIDEO_PALETTE_RGB565 ||
2309 fmt->palette == VIDEO_PALETTE_RGB32) {
2310 fh->ovfmt = fmt+1;
2311 }
2312 }
2313 bt848_bright(btv,pic->brightness);
2314 bt848_contrast(btv,pic->contrast);
2315 bt848_hue(btv,pic->hue);
2316 bt848_sat(btv,pic->colour);
2317 up(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002318 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 }
2320
2321 case VIDIOCGWIN:
2322 {
2323 struct video_window *win = arg;
2324
2325 memset(win,0,sizeof(*win));
2326 win->x = fh->ov.w.left;
2327 win->y = fh->ov.w.top;
2328 win->width = fh->ov.w.width;
2329 win->height = fh->ov.w.height;
2330 return 0;
2331 }
2332 case VIDIOCSWIN:
2333 {
2334 struct video_window *win = arg;
2335 struct v4l2_window w2;
2336
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002337 if (no_overlay > 0) {
2338 printk ("VIDIOCSWIN: no_overlay\n");
2339 return -EINVAL;
2340 }
2341
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 w2.field = V4L2_FIELD_ANY;
2343 w2.w.left = win->x;
2344 w2.w.top = win->y;
2345 w2.w.width = win->width;
2346 w2.w.height = win->height;
2347 w2.clipcount = win->clipcount;
2348 w2.clips = (struct v4l2_clip __user *)win->clips;
2349 retval = setup_window(fh, btv, &w2, 0);
2350 if (0 == retval) {
2351 /* on v4l1 this ioctl affects the read() size too */
2352 fh->width = fh->ov.w.width;
2353 fh->height = fh->ov.w.height;
2354 btv->init.width = fh->ov.w.width;
2355 btv->init.height = fh->ov.w.height;
2356 }
2357 return retval;
2358 }
2359
2360 case VIDIOCGFBUF:
2361 {
2362 struct video_buffer *fbuf = arg;
2363
2364 fbuf->base = btv->fbuf.base;
2365 fbuf->width = btv->fbuf.fmt.width;
2366 fbuf->height = btv->fbuf.fmt.height;
2367 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2368 if (fh->ovfmt)
2369 fbuf->depth = fh->ovfmt->depth;
2370 return 0;
2371 }
2372 case VIDIOCSFBUF:
2373 {
2374 struct video_buffer *fbuf = arg;
2375 const struct bttv_format *fmt;
2376 unsigned long end;
2377
2378 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002379 !capable(CAP_SYS_RAWIO))
2380 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 end = (unsigned long)fbuf->base +
2382 fbuf->height * fbuf->bytesperline;
2383 down(&fh->cap.lock);
2384 retval = -EINVAL;
2385
2386 switch (fbuf->depth) {
2387 case 8:
2388 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2389 break;
2390 case 16:
2391 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2392 break;
2393 case 24:
2394 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2395 break;
2396 case 32:
2397 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2398 break;
2399 case 15:
2400 fbuf->depth = 16;
2401 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2402 break;
2403 default:
2404 fmt = NULL;
2405 break;
2406 }
2407 if (NULL == fmt)
2408 goto fh_unlock_and_return;
2409
2410 fh->ovfmt = fmt;
2411 fh->fmt = fmt;
2412 btv->init.ovfmt = fmt;
2413 btv->init.fmt = fmt;
2414 btv->fbuf.base = fbuf->base;
2415 btv->fbuf.fmt.width = fbuf->width;
2416 btv->fbuf.fmt.height = fbuf->height;
2417 if (fbuf->bytesperline)
2418 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
2419 else
2420 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
2421 up(&fh->cap.lock);
2422 return 0;
2423 }
2424
2425 case VIDIOCCAPTURE:
2426 case VIDIOC_OVERLAY:
2427 {
2428 struct bttv_buffer *new;
2429 int *on = arg;
2430
2431 if (*on) {
2432 /* verify args */
2433 if (NULL == btv->fbuf.base)
2434 return -EINVAL;
2435 if (!fh->ov.setup_ok) {
2436 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2437 return -EINVAL;
2438 }
2439 }
2440
2441 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2442 return -EBUSY;
2443
2444 down(&fh->cap.lock);
2445 if (*on) {
2446 fh->ov.tvnorm = btv->tvnorm;
2447 new = videobuf_alloc(sizeof(*new));
2448 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2449 } else {
2450 new = NULL;
2451 }
2452
2453 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002454 retval = bttv_switch_overlay(btv,fh,new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 up(&fh->cap.lock);
2456 return retval;
2457 }
2458
2459 case VIDIOCGMBUF:
2460 {
2461 struct video_mbuf *mbuf = arg;
2462 unsigned int i;
2463
2464 down(&fh->cap.lock);
2465 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2466 V4L2_MEMORY_MMAP);
2467 if (retval < 0)
2468 goto fh_unlock_and_return;
2469 memset(mbuf,0,sizeof(*mbuf));
2470 mbuf->frames = gbuffers;
2471 mbuf->size = gbuffers * gbufsize;
2472 for (i = 0; i < gbuffers; i++)
2473 mbuf->offsets[i] = i * gbufsize;
2474 up(&fh->cap.lock);
2475 return 0;
2476 }
2477 case VIDIOCMCAPTURE:
2478 {
2479 struct video_mmap *vm = arg;
2480 struct bttv_buffer *buf;
2481 enum v4l2_field field;
2482
2483 if (vm->frame >= VIDEO_MAX_FRAME)
2484 return -EINVAL;
2485
2486 down(&fh->cap.lock);
2487 retval = -EINVAL;
2488 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
2489 if (NULL == buf)
2490 goto fh_unlock_and_return;
2491 if (0 == buf->vb.baddr)
2492 goto fh_unlock_and_return;
2493 if (buf->vb.state == STATE_QUEUED ||
2494 buf->vb.state == STATE_ACTIVE)
2495 goto fh_unlock_and_return;
2496
2497 field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
2498 ? V4L2_FIELD_INTERLACED
2499 : V4L2_FIELD_BOTTOM;
2500 retval = bttv_prepare_buffer(btv,buf,
2501 format_by_palette(vm->format),
2502 vm->width,vm->height,field);
2503 if (0 != retval)
2504 goto fh_unlock_and_return;
2505 spin_lock_irqsave(&btv->s_lock,flags);
2506 buffer_queue(&fh->cap,&buf->vb);
2507 spin_unlock_irqrestore(&btv->s_lock,flags);
2508 up(&fh->cap.lock);
2509 return 0;
2510 }
2511 case VIDIOCSYNC:
2512 {
2513 int *frame = arg;
2514 struct bttv_buffer *buf;
2515
2516 if (*frame >= VIDEO_MAX_FRAME)
2517 return -EINVAL;
2518
2519 down(&fh->cap.lock);
2520 retval = -EINVAL;
2521 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
2522 if (NULL == buf)
2523 goto fh_unlock_and_return;
2524 retval = videobuf_waiton(&buf->vb,0,1);
2525 if (0 != retval)
2526 goto fh_unlock_and_return;
2527 switch (buf->vb.state) {
2528 case STATE_ERROR:
2529 retval = -EIO;
2530 /* fall through */
2531 case STATE_DONE:
2532 videobuf_dma_pci_sync(btv->c.pci,&buf->vb.dma);
2533 bttv_dma_free(btv,buf);
2534 break;
2535 default:
2536 retval = -EINVAL;
2537 break;
2538 }
2539 up(&fh->cap.lock);
2540 return retval;
2541 }
2542
2543 case VIDIOCGVBIFMT:
2544 {
2545 struct vbi_format *fmt = (void *) arg;
2546 struct v4l2_format fmt2;
2547
2548 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
2549 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2550 if (0 != retval)
2551 return retval;
2552 }
2553 bttv_vbi_get_fmt(fh, &fmt2);
2554
2555 memset(fmt,0,sizeof(*fmt));
2556 fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
2557 fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
2558 fmt->sample_format = VIDEO_PALETTE_RAW;
2559 fmt->start[0] = fmt2.fmt.vbi.start[0];
2560 fmt->count[0] = fmt2.fmt.vbi.count[0];
2561 fmt->start[1] = fmt2.fmt.vbi.start[1];
2562 fmt->count[1] = fmt2.fmt.vbi.count[1];
Michael H. Schimek67f15702006-01-09 15:25:27 -02002563 if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
2564 fmt->flags |= VBI_UNSYNC;
2565 if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
2566 fmt->flags |= VBI_INTERLACED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 return 0;
2568 }
2569 case VIDIOCSVBIFMT:
2570 {
2571 struct vbi_format *fmt = (void *) arg;
2572 struct v4l2_format fmt2;
2573
2574 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2575 if (0 != retval)
2576 return retval;
2577 bttv_vbi_get_fmt(fh, &fmt2);
2578
2579 if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
2580 fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
2581 fmt->sample_format != VIDEO_PALETTE_RAW ||
2582 fmt->start[0] != fmt2.fmt.vbi.start[0] ||
2583 fmt->start[1] != fmt2.fmt.vbi.start[1] ||
2584 fmt->count[0] != fmt->count[1] ||
2585 fmt->count[0] < 1 ||
2586 fmt->count[0] > 32 /* VBI_MAXLINES */)
2587 return -EINVAL;
2588
2589 bttv_vbi_setlines(fh,btv,fmt->count[0]);
2590 return 0;
2591 }
2592
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002593 case BTTV_VERSION:
2594 case VIDIOCGFREQ:
2595 case VIDIOCSFREQ:
2596 case VIDIOCGTUNER:
2597 case VIDIOCSTUNER:
2598 case VIDIOCGCHAN:
2599 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 case VIDIOCGAUDIO:
2601 case VIDIOCSAUDIO:
2602 return bttv_common_ioctls(btv,cmd,arg);
2603
2604 /* *** v4l2 *** ************************************************ */
2605 case VIDIOC_QUERYCAP:
2606 {
2607 struct v4l2_capability *cap = arg;
2608
2609 if (0 == v4l2)
2610 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002611 memset(cap, 0, sizeof (*cap));
2612 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
2613 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
2614 snprintf(cap->bus_info, sizeof (cap->bus_info),
2615 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 cap->version = BTTV_VERSION_CODE;
2617 cap->capabilities =
2618 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 V4L2_CAP_VBI_CAPTURE |
2620 V4L2_CAP_READWRITE |
2621 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002622 if (no_overlay <= 0)
2623 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2626 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2627 cap->capabilities |= V4L2_CAP_TUNER;
2628 return 0;
2629 }
2630
2631 case VIDIOC_ENUM_FMT:
2632 {
2633 struct v4l2_fmtdesc *f = arg;
2634 enum v4l2_buf_type type;
2635 unsigned int i;
2636 int index;
2637
2638 type = f->type;
2639 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2640 /* vbi */
2641 index = f->index;
2642 if (0 != index)
2643 return -EINVAL;
2644 memset(f,0,sizeof(*f));
2645 f->index = index;
2646 f->type = type;
2647 f->pixelformat = V4L2_PIX_FMT_GREY;
2648 strcpy(f->description,"vbi data");
2649 return 0;
2650 }
2651
2652 /* video capture + overlay */
2653 index = -1;
2654 for (i = 0; i < BTTV_FORMATS; i++) {
2655 if (bttv_formats[i].fourcc != -1)
2656 index++;
2657 if ((unsigned int)index == f->index)
2658 break;
2659 }
2660 if (BTTV_FORMATS == i)
2661 return -EINVAL;
2662
2663 switch (f->type) {
2664 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2665 break;
2666 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2667 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2668 return -EINVAL;
2669 break;
2670 default:
2671 return -EINVAL;
2672 }
2673 memset(f,0,sizeof(*f));
2674 f->index = index;
2675 f->type = type;
2676 f->pixelformat = bttv_formats[i].fourcc;
2677 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2678 return 0;
2679 }
2680
2681 case VIDIOC_TRY_FMT:
2682 {
2683 struct v4l2_format *f = arg;
2684 return bttv_try_fmt(fh,btv,f);
2685 }
2686 case VIDIOC_G_FMT:
2687 {
2688 struct v4l2_format *f = arg;
2689 return bttv_g_fmt(fh,f);
2690 }
2691 case VIDIOC_S_FMT:
2692 {
2693 struct v4l2_format *f = arg;
2694 return bttv_s_fmt(fh,btv,f);
2695 }
2696
2697 case VIDIOC_G_FBUF:
2698 {
2699 struct v4l2_framebuffer *fb = arg;
2700
2701 *fb = btv->fbuf;
2702 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2703 if (fh->ovfmt)
2704 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2705 return 0;
2706 }
2707 case VIDIOC_S_FBUF:
2708 {
2709 struct v4l2_framebuffer *fb = arg;
2710 const struct bttv_format *fmt;
2711
2712 if(!capable(CAP_SYS_ADMIN) &&
2713 !capable(CAP_SYS_RAWIO))
2714 return -EPERM;
2715
2716 /* check args */
2717 fmt = format_by_fourcc(fb->fmt.pixelformat);
2718 if (NULL == fmt)
2719 return -EINVAL;
2720 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2721 return -EINVAL;
2722
2723 down(&fh->cap.lock);
2724 retval = -EINVAL;
2725 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2726 if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
2727 goto fh_unlock_and_return;
2728 if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
2729 goto fh_unlock_and_return;
2730 }
2731
2732 /* ok, accept it */
2733 btv->fbuf.base = fb->base;
2734 btv->fbuf.fmt.width = fb->fmt.width;
2735 btv->fbuf.fmt.height = fb->fmt.height;
2736 if (0 != fb->fmt.bytesperline)
2737 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2738 else
2739 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2740
2741 retval = 0;
2742 fh->ovfmt = fmt;
2743 btv->init.ovfmt = fmt;
2744 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2745 fh->ov.w.left = 0;
2746 fh->ov.w.top = 0;
2747 fh->ov.w.width = fb->fmt.width;
2748 fh->ov.w.height = fb->fmt.height;
2749 btv->init.ov.w.width = fb->fmt.width;
2750 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002751 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 fh->ov.clips = NULL;
2753 fh->ov.nclips = 0;
2754
2755 if (check_btres(fh, RESOURCE_OVERLAY)) {
2756 struct bttv_buffer *new;
2757
2758 new = videobuf_alloc(sizeof(*new));
2759 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2760 retval = bttv_switch_overlay(btv,fh,new);
2761 }
2762 }
2763 up(&fh->cap.lock);
2764 return retval;
2765 }
2766
2767 case VIDIOC_REQBUFS:
2768 return videobuf_reqbufs(bttv_queue(fh),arg);
2769
2770 case VIDIOC_QUERYBUF:
2771 return videobuf_querybuf(bttv_queue(fh),arg);
2772
2773 case VIDIOC_QBUF:
2774 return videobuf_qbuf(bttv_queue(fh),arg);
2775
2776 case VIDIOC_DQBUF:
2777 return videobuf_dqbuf(bttv_queue(fh),arg,
2778 file->f_flags & O_NONBLOCK);
2779
2780 case VIDIOC_STREAMON:
2781 {
2782 int res = bttv_resource(fh);
2783
2784 if (!check_alloc_btres(btv,fh,res))
2785 return -EBUSY;
2786 return videobuf_streamon(bttv_queue(fh));
2787 }
2788 case VIDIOC_STREAMOFF:
2789 {
2790 int res = bttv_resource(fh);
2791
2792 retval = videobuf_streamoff(bttv_queue(fh));
2793 if (retval < 0)
2794 return retval;
2795 free_btres(btv,fh,res);
2796 return 0;
2797 }
2798
2799 case VIDIOC_QUERYCTRL:
2800 {
2801 struct v4l2_queryctrl *c = arg;
2802 int i;
2803
2804 if ((c->id < V4L2_CID_BASE ||
2805 c->id >= V4L2_CID_LASTP1) &&
2806 (c->id < V4L2_CID_PRIVATE_BASE ||
2807 c->id >= V4L2_CID_PRIVATE_LASTP1))
2808 return -EINVAL;
2809 for (i = 0; i < BTTV_CTLS; i++)
2810 if (bttv_ctls[i].id == c->id)
2811 break;
2812 if (i == BTTV_CTLS) {
2813 *c = no_ctl;
2814 return 0;
2815 }
2816 *c = bttv_ctls[i];
2817 if (i >= 4 && i <= 8) {
2818 struct video_audio va;
2819 memset(&va,0,sizeof(va));
2820 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
2821 if (btv->audio_hook)
2822 btv->audio_hook(btv,&va,0);
2823 switch (bttv_ctls[i].id) {
2824 case V4L2_CID_AUDIO_VOLUME:
2825 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2826 *c = no_ctl;
2827 break;
2828 case V4L2_CID_AUDIO_BALANCE:
2829 if (!(va.flags & VIDEO_AUDIO_BALANCE))
2830 *c = no_ctl;
2831 break;
2832 case V4L2_CID_AUDIO_BASS:
2833 if (!(va.flags & VIDEO_AUDIO_BASS))
2834 *c = no_ctl;
2835 break;
2836 case V4L2_CID_AUDIO_TREBLE:
2837 if (!(va.flags & VIDEO_AUDIO_TREBLE))
2838 *c = no_ctl;
2839 break;
2840 }
2841 }
2842 return 0;
2843 }
2844 case VIDIOC_G_CTRL:
2845 return get_control(btv,arg);
2846 case VIDIOC_S_CTRL:
2847 return set_control(btv,arg);
2848 case VIDIOC_G_PARM:
2849 {
2850 struct v4l2_streamparm *parm = arg;
2851 struct v4l2_standard s;
2852 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2853 return -EINVAL;
2854 memset(parm,0,sizeof(*parm));
2855 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2856 bttv_tvnorms[btv->tvnorm].name);
2857 parm->parm.capture.timeperframe = s.frameperiod;
2858 return 0;
2859 }
2860
2861 case VIDIOC_G_PRIORITY:
2862 {
2863 enum v4l2_priority *p = arg;
2864
2865 *p = v4l2_prio_max(&btv->prio);
2866 return 0;
2867 }
2868 case VIDIOC_S_PRIORITY:
2869 {
2870 enum v4l2_priority *prio = arg;
2871
2872 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
2873 }
2874
2875 case VIDIOC_ENUMSTD:
2876 case VIDIOC_G_STD:
2877 case VIDIOC_S_STD:
2878 case VIDIOC_ENUMINPUT:
2879 case VIDIOC_G_INPUT:
2880 case VIDIOC_S_INPUT:
2881 case VIDIOC_G_TUNER:
2882 case VIDIOC_S_TUNER:
2883 case VIDIOC_G_FREQUENCY:
2884 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08002885 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 return bttv_common_ioctls(btv,cmd,arg);
2887
2888 default:
2889 return -ENOIOCTLCMD;
2890 }
2891 return 0;
2892
2893 fh_unlock_and_return:
2894 up(&fh->cap.lock);
2895 return retval;
2896}
2897
2898static int bttv_ioctl(struct inode *inode, struct file *file,
2899 unsigned int cmd, unsigned long arg)
2900{
2901 struct bttv_fh *fh = file->private_data;
2902
2903 switch (cmd) {
2904 case BTTV_VBISIZE:
2905 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2906 return fh->lines * 2 * 2048;
2907 default:
2908 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
2909 }
2910}
2911
2912static ssize_t bttv_read(struct file *file, char __user *data,
2913 size_t count, loff_t *ppos)
2914{
2915 struct bttv_fh *fh = file->private_data;
2916 int retval = 0;
2917
2918 if (fh->btv->errors)
2919 bttv_reinit_bt848(fh->btv);
2920 dprintk("bttv%d: read count=%d type=%s\n",
2921 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
2922
2923 switch (fh->type) {
2924 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2925 if (locked_btres(fh->btv,RESOURCE_VIDEO))
2926 return -EBUSY;
2927 retval = videobuf_read_one(&fh->cap, data, count, ppos,
2928 file->f_flags & O_NONBLOCK);
2929 break;
2930 case V4L2_BUF_TYPE_VBI_CAPTURE:
2931 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2932 return -EBUSY;
2933 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
2934 file->f_flags & O_NONBLOCK);
2935 break;
2936 default:
2937 BUG();
2938 }
2939 return retval;
2940}
2941
2942static unsigned int bttv_poll(struct file *file, poll_table *wait)
2943{
2944 struct bttv_fh *fh = file->private_data;
2945 struct bttv_buffer *buf;
2946 enum v4l2_field field;
2947
2948 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2949 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2950 return POLLERR;
2951 return videobuf_poll_stream(file, &fh->vbi, wait);
2952 }
2953
2954 if (check_btres(fh,RESOURCE_VIDEO)) {
2955 /* streaming capture */
2956 if (list_empty(&fh->cap.stream))
2957 return POLLERR;
2958 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
2959 } else {
2960 /* read() capture */
2961 down(&fh->cap.lock);
2962 if (NULL == fh->cap.read_buf) {
2963 /* need to capture a new frame */
2964 if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
2965 up(&fh->cap.lock);
2966 return POLLERR;
2967 }
2968 fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
2969 if (NULL == fh->cap.read_buf) {
2970 up(&fh->cap.lock);
2971 return POLLERR;
2972 }
2973 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
2974 field = videobuf_next_field(&fh->cap);
2975 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08002976 kfree (fh->cap.read_buf);
2977 fh->cap.read_buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 up(&fh->cap.lock);
2979 return POLLERR;
2980 }
2981 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
2982 fh->cap.read_off = 0;
2983 }
2984 up(&fh->cap.lock);
2985 buf = (struct bttv_buffer*)fh->cap.read_buf;
2986 }
2987
2988 poll_wait(file, &buf->vb.done, wait);
2989 if (buf->vb.state == STATE_DONE ||
2990 buf->vb.state == STATE_ERROR)
2991 return POLLIN|POLLRDNORM;
2992 return 0;
2993}
2994
2995static int bttv_open(struct inode *inode, struct file *file)
2996{
2997 int minor = iminor(inode);
2998 struct bttv *btv = NULL;
2999 struct bttv_fh *fh;
3000 enum v4l2_buf_type type = 0;
3001 unsigned int i;
3002
3003 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3004
3005 for (i = 0; i < bttv_num; i++) {
3006 if (bttvs[i].video_dev &&
3007 bttvs[i].video_dev->minor == minor) {
3008 btv = &bttvs[i];
3009 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3010 break;
3011 }
3012 if (bttvs[i].vbi_dev &&
3013 bttvs[i].vbi_dev->minor == minor) {
3014 btv = &bttvs[i];
3015 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3016 break;
3017 }
3018 }
3019 if (NULL == btv)
3020 return -ENODEV;
3021
3022 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3023 btv->c.nr,v4l2_type_names[type]);
3024
3025 /* allocate per filehandle data */
3026 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3027 if (NULL == fh)
3028 return -ENOMEM;
3029 file->private_data = fh;
3030 *fh = btv->init;
3031 fh->type = type;
3032 fh->ov.setup_ok = 0;
3033 v4l2_prio_open(&btv->prio,&fh->prio);
3034
3035 videobuf_queue_init(&fh->cap, &bttv_video_qops,
3036 btv->c.pci, &btv->s_lock,
3037 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3038 V4L2_FIELD_INTERLACED,
3039 sizeof(struct bttv_buffer),
3040 fh);
3041 videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
3042 btv->c.pci, &btv->s_lock,
3043 V4L2_BUF_TYPE_VBI_CAPTURE,
3044 V4L2_FIELD_SEQ_TB,
3045 sizeof(struct bttv_buffer),
3046 fh);
3047 i2c_vidiocschan(btv);
3048
3049 btv->users++;
3050 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
3051 bttv_vbi_setlines(fh,btv,16);
3052 bttv_field_count(btv);
3053 return 0;
3054}
3055
3056static int bttv_release(struct inode *inode, struct file *file)
3057{
3058 struct bttv_fh *fh = file->private_data;
3059 struct bttv *btv = fh->btv;
3060
3061 /* turn off overlay */
3062 if (check_btres(fh, RESOURCE_OVERLAY))
3063 bttv_switch_overlay(btv,fh,NULL);
3064
3065 /* stop video capture */
3066 if (check_btres(fh, RESOURCE_VIDEO)) {
3067 videobuf_streamoff(&fh->cap);
3068 free_btres(btv,fh,RESOURCE_VIDEO);
3069 }
3070 if (fh->cap.read_buf) {
3071 buffer_release(&fh->cap,fh->cap.read_buf);
3072 kfree(fh->cap.read_buf);
3073 }
3074
3075 /* stop vbi capture */
3076 if (check_btres(fh, RESOURCE_VBI)) {
3077 if (fh->vbi.streaming)
3078 videobuf_streamoff(&fh->vbi);
3079 if (fh->vbi.reading)
3080 videobuf_read_stop(&fh->vbi);
3081 free_btres(btv,fh,RESOURCE_VBI);
3082 }
3083
3084 /* free stuff */
3085 videobuf_mmap_free(&fh->cap);
3086 videobuf_mmap_free(&fh->vbi);
3087 v4l2_prio_close(&btv->prio,&fh->prio);
3088 file->private_data = NULL;
3089 kfree(fh);
3090
3091 btv->users--;
3092 bttv_field_count(btv);
3093 return 0;
3094}
3095
3096static int
3097bttv_mmap(struct file *file, struct vm_area_struct *vma)
3098{
3099 struct bttv_fh *fh = file->private_data;
3100
3101 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3102 fh->btv->c.nr, v4l2_type_names[fh->type],
3103 vma->vm_start, vma->vm_end - vma->vm_start);
3104 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3105}
3106
3107static struct file_operations bttv_fops =
3108{
3109 .owner = THIS_MODULE,
3110 .open = bttv_open,
3111 .release = bttv_release,
3112 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003113 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 .llseek = no_llseek,
3115 .read = bttv_read,
3116 .mmap = bttv_mmap,
3117 .poll = bttv_poll,
3118};
3119
3120static struct video_device bttv_video_template =
3121{
3122 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003123 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003124 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 .hardware = VID_HARDWARE_BT848,
3126 .fops = &bttv_fops,
3127 .minor = -1,
3128};
3129
3130static struct video_device bttv_vbi_template =
3131{
3132 .name = "bt848/878 vbi",
3133 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
3134 .hardware = VID_HARDWARE_BT848,
3135 .fops = &bttv_fops,
3136 .minor = -1,
3137};
3138
3139/* ----------------------------------------------------------------------- */
3140/* radio interface */
3141
3142static int radio_open(struct inode *inode, struct file *file)
3143{
3144 int minor = iminor(inode);
3145 struct bttv *btv = NULL;
3146 unsigned int i;
3147
3148 dprintk("bttv: open minor=%d\n",minor);
3149
3150 for (i = 0; i < bttv_num; i++) {
3151 if (bttvs[i].radio_dev->minor == minor) {
3152 btv = &bttvs[i];
3153 break;
3154 }
3155 }
3156 if (NULL == btv)
3157 return -ENODEV;
3158
3159 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
3160 down(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003161
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003163
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 file->private_data = btv;
3165
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003166 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 audio_mux(btv,AUDIO_RADIO);
3168
3169 up(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003170 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171}
3172
3173static int radio_release(struct inode *inode, struct file *file)
3174{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003175 struct bttv *btv = file->private_data;
3176 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
3178 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003179
3180 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 return 0;
3183}
3184
3185static int radio_do_ioctl(struct inode *inode, struct file *file,
3186 unsigned int cmd, void *arg)
3187{
3188 struct bttv *btv = file->private_data;
3189
3190 switch (cmd) {
3191 case VIDIOCGCAP:
3192 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003193 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
3195 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003196 strcpy(cap->name,btv->radio_dev->name);
3197 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 cap->channels = 1;
3199 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003200 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
3202
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003203 case VIDIOCGTUNER:
3204 {
3205 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003207 if(v->tuner)
3208 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003210 strcpy(v->name, "Radio");
3211 bttv_call_i2c_clients(btv,cmd,v);
3212 return 0;
3213 }
3214 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 /* nothing to do */
3216 return 0;
3217
3218 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003219 case VIDIOCGFREQ:
3220 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 case VIDIOCGAUDIO:
3222 case VIDIOCSAUDIO:
3223 return bttv_common_ioctls(btv,cmd,arg);
3224
3225 default:
3226 return -ENOIOCTLCMD;
3227 }
3228 return 0;
3229}
3230
3231static int radio_ioctl(struct inode *inode, struct file *file,
3232 unsigned int cmd, unsigned long arg)
3233{
3234 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3235}
3236
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003237static ssize_t radio_read(struct file *file, char __user *data,
3238 size_t count, loff_t *ppos)
3239{
3240 struct bttv *btv = file->private_data;
3241 struct rds_command cmd;
3242 cmd.block_count = count/3;
3243 cmd.buffer = data;
3244 cmd.instance = file;
3245 cmd.result = -ENODEV;
3246
3247 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3248
3249 return cmd.result;
3250}
3251
3252static unsigned int radio_poll(struct file *file, poll_table *wait)
3253{
3254 struct bttv *btv = file->private_data;
3255 struct rds_command cmd;
3256 cmd.instance = file;
3257 cmd.event_list = wait;
3258 cmd.result = -ENODEV;
3259 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3260
3261 return cmd.result;
3262}
3263
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264static struct file_operations radio_fops =
3265{
3266 .owner = THIS_MODULE,
3267 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003268 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 .release = radio_release,
3270 .ioctl = radio_ioctl,
3271 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003272 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273};
3274
3275static struct video_device radio_template =
3276{
3277 .name = "bt848/878 radio",
3278 .type = VID_TYPE_TUNER,
3279 .hardware = VID_HARDWARE_BT848,
3280 .fops = &radio_fops,
3281 .minor = -1,
3282};
3283
3284/* ----------------------------------------------------------------------- */
3285/* some debug code */
3286
Adrian Bunk408b6642005-05-01 08:59:29 -07003287static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288{
3289 static char *instr[16] = {
3290 [ BT848_RISC_WRITE >> 28 ] = "write",
3291 [ BT848_RISC_SKIP >> 28 ] = "skip",
3292 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3293 [ BT848_RISC_JUMP >> 28 ] = "jump",
3294 [ BT848_RISC_SYNC >> 28 ] = "sync",
3295 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3296 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3297 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3298 };
3299 static int incr[16] = {
3300 [ BT848_RISC_WRITE >> 28 ] = 2,
3301 [ BT848_RISC_JUMP >> 28 ] = 2,
3302 [ BT848_RISC_SYNC >> 28 ] = 2,
3303 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3304 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3305 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3306 };
3307 static char *bits[] = {
3308 "be0", "be1", "be2", "be3/resync",
3309 "set0", "set1", "set2", "set3",
3310 "clr0", "clr1", "clr2", "clr3",
3311 "irq", "res", "eol", "sol",
3312 };
3313 int i;
3314
3315 printk("0x%08x [ %s", risc,
3316 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3317 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3318 if (risc & (1 << (i + 12)))
3319 printk(" %s",bits[i]);
3320 printk(" count=%d ]\n", risc & 0xfff);
3321 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3322}
3323
Adrian Bunk408b6642005-05-01 08:59:29 -07003324static void bttv_risc_disasm(struct bttv *btv,
3325 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326{
3327 unsigned int i,j,n;
3328
3329 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3330 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3331 for (i = 0; i < (risc->size >> 2); i += n) {
3332 printk("%s: 0x%lx: ", btv->c.name,
3333 (unsigned long)(risc->dma + (i<<2)));
3334 n = bttv_risc_decode(risc->cpu[i]);
3335 for (j = 1; j < n; j++)
3336 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3337 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3338 risc->cpu[i+j], j);
3339 if (0 == risc->cpu[i])
3340 break;
3341 }
3342}
3343
3344static void bttv_print_riscaddr(struct bttv *btv)
3345{
3346 printk(" main: %08Lx\n",
3347 (unsigned long long)btv->main.dma);
3348 printk(" vbi : o=%08Lx e=%08Lx\n",
3349 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3350 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3351 printk(" cap : o=%08Lx e=%08Lx\n",
3352 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3353 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3354 printk(" scr : o=%08Lx e=%08Lx\n",
3355 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3356 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3357 bttv_risc_disasm(btv, &btv->main);
3358}
3359
3360/* ----------------------------------------------------------------------- */
3361/* irq handler */
3362
3363static char *irq_name[] = {
3364 "FMTCHG", // format change detected (525 vs. 625)
3365 "VSYNC", // vertical sync (new field)
3366 "HSYNC", // horizontal sync
3367 "OFLOW", // chroma/luma AGC overflow
3368 "HLOCK", // horizontal lock changed
3369 "VPRES", // video presence changed
3370 "6", "7",
3371 "I2CDONE", // hw irc operation finished
3372 "GPINT", // gpio port triggered irq
3373 "10",
3374 "RISCI", // risc instruction triggered irq
3375 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3376 "FTRGT", // pixel data fifo overrun
3377 "FDSR", // fifo data stream resyncronisation
3378 "PPERR", // parity error (data transfer)
3379 "RIPERR", // parity error (read risc instructions)
3380 "PABORT", // pci abort
3381 "OCERR", // risc instruction error
3382 "SCERR", // syncronisation error
3383};
3384
3385static void bttv_print_irqbits(u32 print, u32 mark)
3386{
3387 unsigned int i;
3388
3389 printk("bits:");
3390 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3391 if (print & (1 << i))
3392 printk(" %s",irq_name[i]);
3393 if (mark & (1 << i))
3394 printk("*");
3395 }
3396}
3397
3398static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3399{
3400 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3401 btv->c.nr,
3402 (unsigned long)btv->main.dma,
3403 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3404 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3405 (unsigned long)rc);
3406
3407 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3408 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3409 "Ok, then this is harmless, don't worry ;)\n",
3410 btv->c.nr);
3411 return;
3412 }
3413 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3414 btv->c.nr);
3415 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3416 btv->c.nr);
3417 dump_stack();
3418}
3419
3420static int
3421bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3422{
3423 struct bttv_buffer *item;
3424
3425 memset(set,0,sizeof(*set));
3426
3427 /* capture request ? */
3428 if (!list_empty(&btv->capture)) {
3429 set->frame_irq = 1;
3430 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3431 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3432 set->top = item;
3433 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3434 set->bottom = item;
3435
3436 /* capture request for other field ? */
3437 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3438 (item->vb.queue.next != &btv->capture)) {
3439 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3440 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3441 if (NULL == set->top &&
3442 V4L2_FIELD_TOP == item->vb.field) {
3443 set->top = item;
3444 }
3445 if (NULL == set->bottom &&
3446 V4L2_FIELD_BOTTOM == item->vb.field) {
3447 set->bottom = item;
3448 }
3449 if (NULL != set->top && NULL != set->bottom)
3450 set->top_irq = 2;
3451 }
3452 }
3453 }
3454
3455 /* screen overlay ? */
3456 if (NULL != btv->screen) {
3457 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3458 if (NULL == set->top && NULL == set->bottom) {
3459 set->top = btv->screen;
3460 set->bottom = btv->screen;
3461 }
3462 } else {
3463 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3464 NULL == set->top) {
3465 set->top = btv->screen;
3466 }
3467 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3468 NULL == set->bottom) {
3469 set->bottom = btv->screen;
3470 }
3471 }
3472 }
3473
3474 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3475 btv->c.nr,set->top, set->bottom,
3476 btv->screen,set->frame_irq,set->top_irq);
3477 return 0;
3478}
3479
3480static void
3481bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3482 struct bttv_buffer_set *curr, unsigned int state)
3483{
3484 struct timeval ts;
3485
3486 do_gettimeofday(&ts);
3487
3488 if (wakeup->top == wakeup->bottom) {
3489 if (NULL != wakeup->top && curr->top != wakeup->top) {
3490 if (irq_debug > 1)
3491 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3492 wakeup->top->vb.ts = ts;
3493 wakeup->top->vb.field_count = btv->field_count;
3494 wakeup->top->vb.state = state;
3495 wake_up(&wakeup->top->vb.done);
3496 }
3497 } else {
3498 if (NULL != wakeup->top && curr->top != wakeup->top) {
3499 if (irq_debug > 1)
3500 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3501 wakeup->top->vb.ts = ts;
3502 wakeup->top->vb.field_count = btv->field_count;
3503 wakeup->top->vb.state = state;
3504 wake_up(&wakeup->top->vb.done);
3505 }
3506 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3507 if (irq_debug > 1)
3508 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3509 wakeup->bottom->vb.ts = ts;
3510 wakeup->bottom->vb.field_count = btv->field_count;
3511 wakeup->bottom->vb.state = state;
3512 wake_up(&wakeup->bottom->vb.done);
3513 }
3514 }
3515}
3516
3517static void
3518bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3519 unsigned int state)
3520{
3521 struct timeval ts;
3522
3523 if (NULL == wakeup)
3524 return;
3525
3526 do_gettimeofday(&ts);
3527 wakeup->vb.ts = ts;
3528 wakeup->vb.field_count = btv->field_count;
3529 wakeup->vb.state = state;
3530 wake_up(&wakeup->vb.done);
3531}
3532
3533static void bttv_irq_timeout(unsigned long data)
3534{
3535 struct bttv *btv = (struct bttv *)data;
3536 struct bttv_buffer_set old,new;
3537 struct bttv_buffer *ovbi;
3538 struct bttv_buffer *item;
3539 unsigned long flags;
3540
3541 if (bttv_verbose) {
3542 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3543 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3544 btread(BT848_RISC_COUNT));
3545 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3546 printk("\n");
3547 }
3548
3549 spin_lock_irqsave(&btv->s_lock,flags);
3550
3551 /* deactivate stuff */
3552 memset(&new,0,sizeof(new));
3553 old = btv->curr;
3554 ovbi = btv->cvbi;
3555 btv->curr = new;
3556 btv->cvbi = NULL;
3557 btv->loop_irq = 0;
3558 bttv_buffer_activate_video(btv, &new);
3559 bttv_buffer_activate_vbi(btv, NULL);
3560 bttv_set_dma(btv, 0);
3561
3562 /* wake up */
3563 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
3564 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
3565
3566 /* cancel all outstanding capture / vbi requests */
3567 while (!list_empty(&btv->capture)) {
3568 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3569 list_del(&item->vb.queue);
3570 item->vb.state = STATE_ERROR;
3571 wake_up(&item->vb.done);
3572 }
3573 while (!list_empty(&btv->vcapture)) {
3574 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3575 list_del(&item->vb.queue);
3576 item->vb.state = STATE_ERROR;
3577 wake_up(&item->vb.done);
3578 }
3579
3580 btv->errors++;
3581 spin_unlock_irqrestore(&btv->s_lock,flags);
3582}
3583
3584static void
3585bttv_irq_wakeup_top(struct bttv *btv)
3586{
3587 struct bttv_buffer *wakeup = btv->curr.top;
3588
3589 if (NULL == wakeup)
3590 return;
3591
3592 spin_lock(&btv->s_lock);
3593 btv->curr.top_irq = 0;
3594 btv->curr.top = NULL;
3595 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3596
3597 do_gettimeofday(&wakeup->vb.ts);
3598 wakeup->vb.field_count = btv->field_count;
3599 wakeup->vb.state = STATE_DONE;
3600 wake_up(&wakeup->vb.done);
3601 spin_unlock(&btv->s_lock);
3602}
3603
3604static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3605{
3606 if (rc < risc->dma)
3607 return 0;
3608 if (rc > risc->dma + risc->size)
3609 return 0;
3610 return 1;
3611}
3612
3613static void
3614bttv_irq_switch_video(struct bttv *btv)
3615{
3616 struct bttv_buffer_set new;
3617 struct bttv_buffer_set old;
3618 dma_addr_t rc;
3619
3620 spin_lock(&btv->s_lock);
3621
3622 /* new buffer set */
3623 bttv_irq_next_video(btv, &new);
3624 rc = btread(BT848_RISC_COUNT);
3625 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3626 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3627 btv->framedrop++;
3628 if (debug_latency)
3629 bttv_irq_debug_low_latency(btv, rc);
3630 spin_unlock(&btv->s_lock);
3631 return;
3632 }
3633
3634 /* switch over */
3635 old = btv->curr;
3636 btv->curr = new;
3637 btv->loop_irq &= ~1;
3638 bttv_buffer_activate_video(btv, &new);
3639 bttv_set_dma(btv, 0);
3640
3641 /* switch input */
3642 if (UNSET != btv->new_input) {
3643 video_mux(btv,btv->new_input);
3644 btv->new_input = UNSET;
3645 }
3646
3647 /* wake up finished buffers */
3648 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
3649 spin_unlock(&btv->s_lock);
3650}
3651
3652static void
3653bttv_irq_switch_vbi(struct bttv *btv)
3654{
3655 struct bttv_buffer *new = NULL;
3656 struct bttv_buffer *old;
3657 u32 rc;
3658
3659 spin_lock(&btv->s_lock);
3660
3661 if (!list_empty(&btv->vcapture))
3662 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3663 old = btv->cvbi;
3664
3665 rc = btread(BT848_RISC_COUNT);
3666 if (NULL != old && (is_active(&old->top, rc) ||
3667 is_active(&old->bottom, rc))) {
3668 btv->framedrop++;
3669 if (debug_latency)
3670 bttv_irq_debug_low_latency(btv, rc);
3671 spin_unlock(&btv->s_lock);
3672 return;
3673 }
3674
3675 /* switch */
3676 btv->cvbi = new;
3677 btv->loop_irq &= ~4;
3678 bttv_buffer_activate_vbi(btv, new);
3679 bttv_set_dma(btv, 0);
3680
3681 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
3682 spin_unlock(&btv->s_lock);
3683}
3684
3685static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
3686{
3687 u32 stat,astat;
3688 u32 dstat;
3689 int count;
3690 struct bttv *btv;
3691 int handled = 0;
3692
3693 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003694
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003695 if (btv->custom_irq)
3696 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003697
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 count=0;
3699 while (1) {
3700 /* get/clear interrupt status bits */
3701 stat=btread(BT848_INT_STAT);
3702 astat=stat&btread(BT848_INT_MASK);
3703 if (!astat)
3704 break;
3705 handled = 1;
3706 btwrite(stat,BT848_INT_STAT);
3707
3708 /* get device status bits */
3709 dstat=btread(BT848_DSTATUS);
3710
3711 if (irq_debug) {
3712 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
3713 "riscs=%x, riscc=%08x, ",
3714 btv->c.nr, count, btv->field_count,
3715 stat>>28, btread(BT848_RISC_COUNT));
3716 bttv_print_irqbits(stat,astat);
3717 if (stat & BT848_INT_HLOCK)
3718 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
3719 ? "yes" : "no");
3720 if (stat & BT848_INT_VPRES)
3721 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
3722 ? "yes" : "no");
3723 if (stat & BT848_INT_FMTCHG)
3724 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
3725 ? "625" : "525");
3726 printk("\n");
3727 }
3728
3729 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003730 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003732 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003734 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 }
3736
3737 if (astat & BT848_INT_I2CDONE) {
3738 btv->i2c_done = stat;
3739 wake_up(&btv->i2c_queue);
3740 }
3741
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003742 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 bttv_irq_switch_vbi(btv);
3744
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003745 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 bttv_irq_wakeup_top(btv);
3747
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003748 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 bttv_irq_switch_video(btv);
3750
3751 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
3752 audio_mux(btv, -1);
3753
3754 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
3755 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
3756 (astat & BT848_INT_SCERR) ? "SCERR" : "",
3757 (astat & BT848_INT_OCERR) ? "OCERR" : "",
3758 btread(BT848_RISC_COUNT));
3759 bttv_print_irqbits(stat,astat);
3760 printk("\n");
3761 if (bttv_debug)
3762 bttv_print_riscaddr(btv);
3763 }
3764 if (fdsr && astat & BT848_INT_FDSR) {
3765 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
3766 btv->c.nr,btread(BT848_RISC_COUNT));
3767 if (bttv_debug)
3768 bttv_print_riscaddr(btv);
3769 }
3770
3771 count++;
3772 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003773
3774 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003775 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003776
3777 printk(KERN_ERR
3778 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
3779 } else {
3780 printk(KERN_ERR
3781 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
3782
3783 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
3784 BT848_INT_MASK);
3785 };
3786
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003788
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 printk("]\n");
3790 }
3791 }
3792 btv->irq_total++;
3793 if (handled)
3794 btv->irq_me++;
3795 return IRQ_RETVAL(handled);
3796}
3797
3798
3799/* ----------------------------------------------------------------------- */
3800/* initialitation */
3801
3802static struct video_device *vdev_init(struct bttv *btv,
3803 struct video_device *template,
3804 char *type)
3805{
3806 struct video_device *vfd;
3807
3808 vfd = video_device_alloc();
3809 if (NULL == vfd)
3810 return NULL;
3811 *vfd = *template;
3812 vfd->minor = -1;
3813 vfd->dev = &btv->c.pci->dev;
3814 vfd->release = video_device_release;
3815 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
3816 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
3817 type, bttv_tvcards[btv->c.type].name);
3818 return vfd;
3819}
3820
3821static void bttv_unregister_video(struct bttv *btv)
3822{
3823 if (btv->video_dev) {
3824 if (-1 != btv->video_dev->minor)
3825 video_unregister_device(btv->video_dev);
3826 else
3827 video_device_release(btv->video_dev);
3828 btv->video_dev = NULL;
3829 }
3830 if (btv->vbi_dev) {
3831 if (-1 != btv->vbi_dev->minor)
3832 video_unregister_device(btv->vbi_dev);
3833 else
3834 video_device_release(btv->vbi_dev);
3835 btv->vbi_dev = NULL;
3836 }
3837 if (btv->radio_dev) {
3838 if (-1 != btv->radio_dev->minor)
3839 video_unregister_device(btv->radio_dev);
3840 else
3841 video_device_release(btv->radio_dev);
3842 btv->radio_dev = NULL;
3843 }
3844}
3845
3846/* register video4linux devices */
3847static int __devinit bttv_register_video(struct bttv *btv)
3848{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003849 if (no_overlay <= 0) {
3850 bttv_video_template.type |= VID_TYPE_OVERLAY;
3851 } else {
3852 printk("bttv: Overlay support disabled.\n");
3853 }
3854
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 /* video */
3856 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003857 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 goto err;
3859 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
3860 goto err;
3861 printk(KERN_INFO "bttv%d: registered device video%d\n",
3862 btv->c.nr,btv->video_dev->minor & 0x1f);
3863 video_device_create_file(btv->video_dev, &class_device_attr_card);
3864
3865 /* vbi */
3866 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003867 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003869 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 goto err;
3871 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
3872 btv->c.nr,btv->vbi_dev->minor & 0x1f);
3873
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003874 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 return 0;
3876 /* radio */
3877 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003878 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 goto err;
3880 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
3881 goto err;
3882 printk(KERN_INFO "bttv%d: registered device radio%d\n",
3883 btv->c.nr,btv->radio_dev->minor & 0x1f);
3884
3885 /* all done */
3886 return 0;
3887
3888 err:
3889 bttv_unregister_video(btv);
3890 return -1;
3891}
3892
3893
3894/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
3895/* response on cards with no firmware is not enabled by OF */
3896static void pci_set_command(struct pci_dev *dev)
3897{
3898#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003899 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003901 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
3902 cmd = (cmd | PCI_COMMAND_MEMORY );
3903 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904#endif
3905}
3906
3907static int __devinit bttv_probe(struct pci_dev *dev,
3908 const struct pci_device_id *pci_id)
3909{
3910 int result;
3911 unsigned char lat;
3912 struct bttv *btv;
3913
3914 if (bttv_num == BTTV_MAX)
3915 return -ENOMEM;
3916 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003917 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 memset(btv,0,sizeof(*btv));
3919 btv->c.nr = bttv_num;
3920 sprintf(btv->c.name,"bttv%d",btv->c.nr);
3921
3922 /* initialize structs / fill in defaults */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003923 init_MUTEX(&btv->lock);
3924 init_MUTEX(&btv->reslock);
3925 spin_lock_init(&btv->s_lock);
3926 spin_lock_init(&btv->gpio_lock);
3927 init_waitqueue_head(&btv->gpioq);
3928 init_waitqueue_head(&btv->i2c_queue);
3929 INIT_LIST_HEAD(&btv->c.subs);
3930 INIT_LIST_HEAD(&btv->capture);
3931 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 v4l2_prio_init(&btv->prio);
3933
3934 init_timer(&btv->timeout);
3935 btv->timeout.function = bttv_irq_timeout;
3936 btv->timeout.data = (unsigned long)btv;
3937
Michael Krufky7c08fb02005-11-08 21:36:21 -08003938 btv->i2c_rc = -1;
3939 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 btv->has_radio=radio[btv->c.nr];
3942
3943 /* pci stuff (init, get irq/mmio, ... */
3944 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08003945 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08003947 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 btv->c.nr);
3949 return -EIO;
3950 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003951 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
3952 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 btv->c.nr);
3954 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 if (!request_mem_region(pci_resource_start(dev,0),
3957 pci_resource_len(dev,0),
3958 btv->c.name)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003959 printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 btv->c.nr, pci_resource_start(dev,0));
3961 return -EBUSY;
3962 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003963 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 pci_set_command(dev);
3965 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003967 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
3968 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
3969 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
3970 bttv_num,btv->id, btv->revision, pci_name(dev));
3971 printk("irq: %d, latency: %d, mmio: 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 btv->c.pci->irq, lat, pci_resource_start(dev,0));
3973 schedule();
3974
3975 btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
3976 if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
3977 printk("bttv%d: ioremap() failed\n", btv->c.nr);
3978 result = -EIO;
3979 goto fail1;
3980 }
3981
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003982 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 bttv_idcard(btv);
3984
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003985 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003987 result = request_irq(btv->c.pci->irq, bttv_irq,
3988 SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
3989 if (result < 0) {
3990 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 bttv_num,btv->c.pci->irq);
3992 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994
3995 if (0 != bttv_handle_chipset(btv)) {
3996 result = -EIO;
3997 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999
4000 /* init options from insmod args */
4001 btv->opt_combfilter = combfilter;
4002 btv->opt_lumafilter = lumafilter;
4003 btv->opt_automute = automute;
4004 btv->opt_chroma_agc = chroma_agc;
4005 btv->opt_adc_crush = adc_crush;
4006 btv->opt_vcr_hack = vcr_hack;
4007 btv->opt_whitecrush_upper = whitecrush_upper;
4008 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004009 btv->opt_uv_ratio = uv_ratio;
4010 btv->opt_full_luma_range = full_luma_range;
4011 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012
4013 /* fill struct bttv with some useful defaults */
4014 btv->init.btv = btv;
4015 btv->init.ov.w.width = 320;
4016 btv->init.ov.w.height = 240;
4017 btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
4018 btv->init.width = 320;
4019 btv->init.height = 240;
4020 btv->init.lines = 16;
4021 btv->input = 0;
4022
4023 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004024 if (bttv_gpio)
4025 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
4027 bttv_risc_init_main(btv);
4028 init_bt848(btv);
4029
4030 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004031 btwrite(0x00, BT848_GPIO_REG_INP);
4032 btwrite(0x00, BT848_GPIO_OUT_EN);
4033 if (bttv_verbose)
4034 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004036 /* needs to be done before i2c is registered */
4037 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004039 /* register i2c + gpio */
4040 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004042 /* some card-specific stuff (needs working i2c) */
4043 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 init_irqreg(btv);
4045
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004046 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 if (!bttv_tvcards[btv->c.type].no_video) {
4048 bttv_register_video(btv);
4049 bt848_bright(btv,32768);
4050 bt848_contrast(btv,32768);
4051 bt848_hue(btv,32768);
4052 bt848_sat(btv,32768);
4053 audio_mux(btv,AUDIO_MUTE);
4054 set_input(btv,0);
4055 }
4056
4057 /* add subdevices */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 if (bttv_tvcards[btv->c.type].has_dvb)
4059 bttv_sub_add_device(&btv->c, "dvb");
4060
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004061 bttv_input_init(btv);
4062
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 /* everything is fine */
4064 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004065 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066
4067 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004068 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069
4070 fail1:
4071 if (btv->bt848_mmio)
4072 iounmap(btv->bt848_mmio);
4073 release_mem_region(pci_resource_start(btv->c.pci,0),
4074 pci_resource_len(btv->c.pci,0));
4075 pci_set_drvdata(dev,NULL);
4076 return result;
4077}
4078
4079static void __devexit bttv_remove(struct pci_dev *pci_dev)
4080{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004081 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082
4083 if (bttv_verbose)
4084 printk("bttv%d: unloading\n",btv->c.nr);
4085
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004086 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 btand(~15, BT848_GPIO_DMA_CTL);
4088 btwrite(0, BT848_INT_MASK);
4089 btwrite(~0x0, BT848_INT_STAT);
4090 btwrite(0x0, BT848_GPIO_OUT_EN);
4091 if (bttv_gpio)
4092 bttv_gpio_tracking(btv,"cleanup");
4093
4094 /* tell gpio modules we are leaving ... */
4095 btv->shutdown=1;
4096 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004097 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004098 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004100 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 fini_bttv_i2c(btv);
4102
4103 /* unregister video4linux */
4104 bttv_unregister_video(btv);
4105
4106 /* free allocated memory */
4107 btcx_riscmem_free(btv->c.pci,&btv->main);
4108
4109 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004110 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004112 release_mem_region(pci_resource_start(btv->c.pci,0),
4113 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114
4115 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004116 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117}
4118
4119static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4120{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004121 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 struct bttv_buffer_set idle;
4123 unsigned long flags;
4124
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004125 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
4127 /* stop dma + irqs */
4128 spin_lock_irqsave(&btv->s_lock,flags);
4129 memset(&idle, 0, sizeof(idle));
4130 btv->state.video = btv->curr;
4131 btv->state.vbi = btv->cvbi;
4132 btv->state.loop_irq = btv->loop_irq;
4133 btv->curr = idle;
4134 btv->loop_irq = 0;
4135 bttv_buffer_activate_video(btv, &idle);
4136 bttv_buffer_activate_vbi(btv, NULL);
4137 bttv_set_dma(btv, 0);
4138 btwrite(0, BT848_INT_MASK);
4139 spin_unlock_irqrestore(&btv->s_lock,flags);
4140
4141 /* save bt878 state */
4142 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4143 btv->state.gpio_data = gpio_read();
4144
4145 /* save pci state */
4146 pci_save_state(pci_dev);
4147 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4148 pci_disable_device(pci_dev);
4149 btv->state.disabled = 1;
4150 }
4151 return 0;
4152}
4153
4154static int bttv_resume(struct pci_dev *pci_dev)
4155{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004156 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004158 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
4160 dprintk("bttv%d: resume\n", btv->c.nr);
4161
4162 /* restore pci state */
4163 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004164 err=pci_enable_device(pci_dev);
4165 if (err) {
4166 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4167 btv->c.nr);
4168 return err;
4169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 btv->state.disabled = 0;
4171 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004172 err=pci_set_power_state(pci_dev, PCI_D0);
4173 if (err) {
4174 pci_disable_device(pci_dev);
4175 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4176 btv->c.nr);
4177 btv->state.disabled = 1;
4178 return err;
4179 }
4180
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 pci_restore_state(pci_dev);
4182
4183 /* restore bt878 state */
4184 bttv_reinit_bt848(btv);
4185 gpio_inout(0xffffff, btv->state.gpio_enable);
4186 gpio_write(btv->state.gpio_data);
4187
4188 /* restart dma */
4189 spin_lock_irqsave(&btv->s_lock,flags);
4190 btv->curr = btv->state.video;
4191 btv->cvbi = btv->state.vbi;
4192 btv->loop_irq = btv->state.loop_irq;
4193 bttv_buffer_activate_video(btv, &btv->curr);
4194 bttv_buffer_activate_vbi(btv, btv->cvbi);
4195 bttv_set_dma(btv, 0);
4196 spin_unlock_irqrestore(&btv->s_lock,flags);
4197 return 0;
4198}
4199
4200static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004201 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4202 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004204 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004206 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004208 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4209 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210};
4211
4212MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4213
4214static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004215 .name = "bttv",
4216 .id_table = bttv_pci_tbl,
4217 .probe = bttv_probe,
4218 .remove = __devexit_p(bttv_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 .suspend = bttv_suspend,
4220 .resume = bttv_resume,
4221};
4222
4223static int bttv_init_module(void)
4224{
4225 bttv_num = 0;
4226
4227 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4228 (BTTV_VERSION_CODE >> 16) & 0xff,
4229 (BTTV_VERSION_CODE >> 8) & 0xff,
4230 BTTV_VERSION_CODE & 0xff);
4231#ifdef SNAPSHOT
4232 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4233 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4234#endif
4235 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4236 gbuffers = 2;
4237 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4238 gbufsize = BTTV_MAX_FBUF;
4239 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4240 if (bttv_verbose)
4241 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4242 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4243
4244 bttv_check_chipset();
4245
4246 bus_register(&bttv_sub_bus_type);
Otavio Salvador23047592006-01-09 15:25:17 -02004247 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248}
4249
4250static void bttv_cleanup_module(void)
4251{
4252 pci_unregister_driver(&bttv_pci_driver);
4253 bus_unregister(&bttv_sub_bus_type);
4254 return;
4255}
4256
4257module_init(bttv_init_module);
4258module_exit(bttv_cleanup_module);
4259
4260/*
4261 * Local variables:
4262 * c-basic-offset: 8
4263 * End:
4264 */