blob: c0415d6e7fee2164bda6731e15fccea8ff58a259 [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
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020051unsigned int bttv_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052unsigned int bttv_verbose = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020053unsigned int bttv_gpio;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55/* config variables */
56#ifdef __BIG_ENDIAN
57static unsigned int bigendian=1;
58#else
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020059static unsigned int bigendian;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#endif
61static unsigned int radio[BTTV_MAX];
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020062static unsigned int irq_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063static 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;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020069static int debug_latency;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020071static unsigned int fdsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73/* options */
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020074static unsigned int combfilter;
75static unsigned int lumafilter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076static unsigned int automute = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020077static unsigned int chroma_agc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static unsigned int adc_crush = 1;
79static unsigned int whitecrush_upper = 0xCF;
80static unsigned int whitecrush_lower = 0x7F;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020081static unsigned int vcr_hack;
82static unsigned int irq_iswitch;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070083static unsigned int uv_ratio = 50;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020084static unsigned int full_luma_range;
85static unsigned int coring;
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070091/* insmod args */
92module_param(bttv_verbose, int, 0644);
93module_param(bttv_gpio, int, 0644);
94module_param(bttv_debug, int, 0644);
95module_param(irq_debug, int, 0644);
96module_param(debug_latency, int, 0644);
97
98module_param(fdsr, int, 0444);
99module_param(video_nr, int, 0444);
100module_param(radio_nr, int, 0444);
101module_param(vbi_nr, int, 0444);
102module_param(gbuffers, int, 0444);
103module_param(gbufsize, int, 0444);
104
105module_param(v4l2, int, 0644);
106module_param(bigendian, int, 0644);
107module_param(irq_iswitch, int, 0644);
108module_param(combfilter, int, 0444);
109module_param(lumafilter, int, 0444);
110module_param(automute, int, 0444);
111module_param(chroma_agc, int, 0444);
112module_param(adc_crush, int, 0444);
113module_param(whitecrush_upper, int, 0444);
114module_param(whitecrush_lower, int, 0444);
115module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700116module_param(uv_ratio, int, 0444);
117module_param(full_luma_range, int, 0444);
118module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
120module_param_array(radio, int, NULL, 0444);
121
122MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
123MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
124MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
125MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
126MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
127MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
128MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
129MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
130MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
131MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
132MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
133MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
134MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
135MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
136MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700137MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
138MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
139MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
142MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
143MODULE_LICENSE("GPL");
144
145/* ----------------------------------------------------------------------- */
146/* sysfs */
147
148static ssize_t show_card(struct class_device *cd, char *buf)
149{
150 struct video_device *vfd = to_video_device(cd);
151 struct bttv *btv = dev_get_drvdata(vfd->dev);
152 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
153}
154static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
155
156/* ----------------------------------------------------------------------- */
157/* static data */
158
159/* special timing tables from conexant... */
160static u8 SRAM_Table[][60] =
161{
162 /* PAL digital input over GPIO[7:0] */
163 {
164 45, // 45 bytes following
165 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
166 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
167 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
168 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
169 0x37,0x00,0xAF,0x21,0x00
170 },
171 /* NTSC digital input over GPIO[7:0] */
172 {
173 51, // 51 bytes following
174 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
175 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
176 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
177 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
178 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
179 0x00,
180 },
181 // TGB_NTSC392 // quartzsight
182 // This table has been modified to be used for Fusion Rev D
183 {
184 0x2A, // size of table = 42
185 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
186 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
187 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
188 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
189 0x20, 0x00
190 }
191};
192
193const struct bttv_tvnorm bttv_tvnorms[] = {
194 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800195 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
196 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 {
198 .v4l2_id = V4L2_STD_PAL,
199 .name = "PAL",
200 .Fsc = 35468950,
201 .swidth = 924,
202 .sheight = 576,
203 .totalwidth = 1135,
204 .adelay = 0x7f,
205 .bdelay = 0x72,
206 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
207 .scaledtwidth = 1135,
208 .hdelayx1 = 186,
209 .hactivex1 = 924,
210 .vdelay = 0x20,
211 .vbipack = 255,
212 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200213 /* ITU-R frame line number of the first VBI line
214 we can capture, of the first and second field. */
215 .vbistart = { 7,320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 },{
Hans Verkuild97a11e2006-02-07 06:48:40 -0200217 .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 .name = "NTSC",
219 .Fsc = 28636363,
220 .swidth = 768,
221 .sheight = 480,
222 .totalwidth = 910,
223 .adelay = 0x68,
224 .bdelay = 0x5d,
225 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
226 .scaledtwidth = 910,
227 .hdelayx1 = 128,
228 .hactivex1 = 910,
229 .vdelay = 0x1a,
230 .vbipack = 144,
231 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200232 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 },{
234 .v4l2_id = V4L2_STD_SECAM,
235 .name = "SECAM",
236 .Fsc = 35468950,
237 .swidth = 924,
238 .sheight = 576,
239 .totalwidth = 1135,
240 .adelay = 0x7f,
241 .bdelay = 0xb0,
242 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
243 .scaledtwidth = 1135,
244 .hdelayx1 = 186,
245 .hactivex1 = 922,
246 .vdelay = 0x20,
247 .vbipack = 255,
248 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200249 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 },{
251 .v4l2_id = V4L2_STD_PAL_Nc,
252 .name = "PAL-Nc",
253 .Fsc = 28636363,
254 .swidth = 640,
255 .sheight = 576,
256 .totalwidth = 910,
257 .adelay = 0x68,
258 .bdelay = 0x5d,
259 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
260 .scaledtwidth = 780,
261 .hdelayx1 = 130,
262 .hactivex1 = 734,
263 .vdelay = 0x1a,
264 .vbipack = 144,
265 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200266 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 },{
268 .v4l2_id = V4L2_STD_PAL_M,
269 .name = "PAL-M",
270 .Fsc = 28636363,
271 .swidth = 640,
272 .sheight = 480,
273 .totalwidth = 910,
274 .adelay = 0x68,
275 .bdelay = 0x5d,
276 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
277 .scaledtwidth = 780,
278 .hdelayx1 = 135,
279 .hactivex1 = 754,
280 .vdelay = 0x1a,
281 .vbipack = 144,
282 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200283 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 },{
285 .v4l2_id = V4L2_STD_PAL_N,
286 .name = "PAL-N",
287 .Fsc = 35468950,
288 .swidth = 768,
289 .sheight = 576,
290 .totalwidth = 1135,
291 .adelay = 0x7f,
292 .bdelay = 0x72,
293 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
294 .scaledtwidth = 944,
295 .hdelayx1 = 186,
296 .hactivex1 = 922,
297 .vdelay = 0x20,
298 .vbipack = 144,
299 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200300 .vbistart = { 7, 320},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 },{
302 .v4l2_id = V4L2_STD_NTSC_M_JP,
303 .name = "NTSC-JP",
304 .Fsc = 28636363,
305 .swidth = 640,
306 .sheight = 480,
307 .totalwidth = 910,
308 .adelay = 0x68,
309 .bdelay = 0x5d,
310 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
311 .scaledtwidth = 780,
312 .hdelayx1 = 135,
313 .hactivex1 = 754,
314 .vdelay = 0x16,
315 .vbipack = 144,
316 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200317 .vbistart = {10, 273},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 },{
319 /* that one hopefully works with the strange timing
320 * which video recorders produce when playing a NTSC
321 * tape on a PAL TV ... */
322 .v4l2_id = V4L2_STD_PAL_60,
323 .name = "PAL-60",
324 .Fsc = 35468950,
325 .swidth = 924,
326 .sheight = 480,
327 .totalwidth = 1135,
328 .adelay = 0x7f,
329 .bdelay = 0x72,
330 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
331 .scaledtwidth = 1135,
332 .hdelayx1 = 186,
333 .hactivex1 = 924,
334 .vdelay = 0x1a,
335 .vbipack = 255,
336 .vtotal = 524,
337 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200338 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 }
340};
341static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
342
343/* ----------------------------------------------------------------------- */
344/* bttv format list
345 packed pixel formats must come first */
346static const struct bttv_format bttv_formats[] = {
347 {
348 .name = "8 bpp, gray",
349 .palette = VIDEO_PALETTE_GREY,
350 .fourcc = V4L2_PIX_FMT_GREY,
351 .btformat = BT848_COLOR_FMT_Y8,
352 .depth = 8,
353 .flags = FORMAT_FLAGS_PACKED,
354 },{
355 .name = "8 bpp, dithered color",
356 .palette = VIDEO_PALETTE_HI240,
357 .fourcc = V4L2_PIX_FMT_HI240,
358 .btformat = BT848_COLOR_FMT_RGB8,
359 .depth = 8,
360 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
361 },{
362 .name = "15 bpp RGB, le",
363 .palette = VIDEO_PALETTE_RGB555,
364 .fourcc = V4L2_PIX_FMT_RGB555,
365 .btformat = BT848_COLOR_FMT_RGB15,
366 .depth = 16,
367 .flags = FORMAT_FLAGS_PACKED,
368 },{
369 .name = "15 bpp RGB, be",
370 .palette = -1,
371 .fourcc = V4L2_PIX_FMT_RGB555X,
372 .btformat = BT848_COLOR_FMT_RGB15,
373 .btswap = 0x03, /* byteswap */
374 .depth = 16,
375 .flags = FORMAT_FLAGS_PACKED,
376 },{
377 .name = "16 bpp RGB, le",
378 .palette = VIDEO_PALETTE_RGB565,
379 .fourcc = V4L2_PIX_FMT_RGB565,
380 .btformat = BT848_COLOR_FMT_RGB16,
381 .depth = 16,
382 .flags = FORMAT_FLAGS_PACKED,
383 },{
384 .name = "16 bpp RGB, be",
385 .palette = -1,
386 .fourcc = V4L2_PIX_FMT_RGB565X,
387 .btformat = BT848_COLOR_FMT_RGB16,
388 .btswap = 0x03, /* byteswap */
389 .depth = 16,
390 .flags = FORMAT_FLAGS_PACKED,
391 },{
392 .name = "24 bpp RGB, le",
393 .palette = VIDEO_PALETTE_RGB24,
394 .fourcc = V4L2_PIX_FMT_BGR24,
395 .btformat = BT848_COLOR_FMT_RGB24,
396 .depth = 24,
397 .flags = FORMAT_FLAGS_PACKED,
398 },{
399 .name = "32 bpp RGB, le",
400 .palette = VIDEO_PALETTE_RGB32,
401 .fourcc = V4L2_PIX_FMT_BGR32,
402 .btformat = BT848_COLOR_FMT_RGB32,
403 .depth = 32,
404 .flags = FORMAT_FLAGS_PACKED,
405 },{
406 .name = "32 bpp RGB, be",
407 .palette = -1,
408 .fourcc = V4L2_PIX_FMT_RGB32,
409 .btformat = BT848_COLOR_FMT_RGB32,
410 .btswap = 0x0f, /* byte+word swap */
411 .depth = 32,
412 .flags = FORMAT_FLAGS_PACKED,
413 },{
414 .name = "4:2:2, packed, YUYV",
415 .palette = VIDEO_PALETTE_YUV422,
416 .fourcc = V4L2_PIX_FMT_YUYV,
417 .btformat = BT848_COLOR_FMT_YUY2,
418 .depth = 16,
419 .flags = FORMAT_FLAGS_PACKED,
420 },{
421 .name = "4:2:2, packed, YUYV",
422 .palette = VIDEO_PALETTE_YUYV,
423 .fourcc = V4L2_PIX_FMT_YUYV,
424 .btformat = BT848_COLOR_FMT_YUY2,
425 .depth = 16,
426 .flags = FORMAT_FLAGS_PACKED,
427 },{
428 .name = "4:2:2, packed, UYVY",
429 .palette = VIDEO_PALETTE_UYVY,
430 .fourcc = V4L2_PIX_FMT_UYVY,
431 .btformat = BT848_COLOR_FMT_YUY2,
432 .btswap = 0x03, /* byteswap */
433 .depth = 16,
434 .flags = FORMAT_FLAGS_PACKED,
435 },{
436 .name = "4:2:2, planar, Y-Cb-Cr",
437 .palette = VIDEO_PALETTE_YUV422P,
438 .fourcc = V4L2_PIX_FMT_YUV422P,
439 .btformat = BT848_COLOR_FMT_YCrCb422,
440 .depth = 16,
441 .flags = FORMAT_FLAGS_PLANAR,
442 .hshift = 1,
443 .vshift = 0,
444 },{
445 .name = "4:2:0, planar, Y-Cb-Cr",
446 .palette = VIDEO_PALETTE_YUV420P,
447 .fourcc = V4L2_PIX_FMT_YUV420,
448 .btformat = BT848_COLOR_FMT_YCrCb422,
449 .depth = 12,
450 .flags = FORMAT_FLAGS_PLANAR,
451 .hshift = 1,
452 .vshift = 1,
453 },{
454 .name = "4:2:0, planar, Y-Cr-Cb",
455 .palette = -1,
456 .fourcc = V4L2_PIX_FMT_YVU420,
457 .btformat = BT848_COLOR_FMT_YCrCb422,
458 .depth = 12,
459 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
460 .hshift = 1,
461 .vshift = 1,
462 },{
463 .name = "4:1:1, planar, Y-Cb-Cr",
464 .palette = VIDEO_PALETTE_YUV411P,
465 .fourcc = V4L2_PIX_FMT_YUV411P,
466 .btformat = BT848_COLOR_FMT_YCrCb411,
467 .depth = 12,
468 .flags = FORMAT_FLAGS_PLANAR,
469 .hshift = 2,
470 .vshift = 0,
471 },{
472 .name = "4:1:0, planar, Y-Cb-Cr",
473 .palette = VIDEO_PALETTE_YUV410P,
474 .fourcc = V4L2_PIX_FMT_YUV410,
475 .btformat = BT848_COLOR_FMT_YCrCb411,
476 .depth = 9,
477 .flags = FORMAT_FLAGS_PLANAR,
478 .hshift = 2,
479 .vshift = 2,
480 },{
481 .name = "4:1:0, planar, Y-Cr-Cb",
482 .palette = -1,
483 .fourcc = V4L2_PIX_FMT_YVU410,
484 .btformat = BT848_COLOR_FMT_YCrCb411,
485 .depth = 9,
486 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
487 .hshift = 2,
488 .vshift = 2,
489 },{
490 .name = "raw scanlines",
491 .palette = VIDEO_PALETTE_RAW,
492 .fourcc = -1,
493 .btformat = BT848_COLOR_FMT_RAW,
494 .depth = 8,
495 .flags = FORMAT_FLAGS_RAW,
496 }
497};
498static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
499
500/* ----------------------------------------------------------------------- */
501
502#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
503#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
504#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
505#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
506#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
507#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
508#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
509#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700510#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
511#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
512#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
513#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515static const struct v4l2_queryctrl no_ctl = {
516 .name = "42",
517 .flags = V4L2_CTRL_FLAG_DISABLED,
518};
519static const struct v4l2_queryctrl bttv_ctls[] = {
520 /* --- video --- */
521 {
522 .id = V4L2_CID_BRIGHTNESS,
523 .name = "Brightness",
524 .minimum = 0,
525 .maximum = 65535,
526 .step = 256,
527 .default_value = 32768,
528 .type = V4L2_CTRL_TYPE_INTEGER,
529 },{
530 .id = V4L2_CID_CONTRAST,
531 .name = "Contrast",
532 .minimum = 0,
533 .maximum = 65535,
534 .step = 128,
535 .default_value = 32768,
536 .type = V4L2_CTRL_TYPE_INTEGER,
537 },{
538 .id = V4L2_CID_SATURATION,
539 .name = "Saturation",
540 .minimum = 0,
541 .maximum = 65535,
542 .step = 128,
543 .default_value = 32768,
544 .type = V4L2_CTRL_TYPE_INTEGER,
545 },{
546 .id = V4L2_CID_HUE,
547 .name = "Hue",
548 .minimum = 0,
549 .maximum = 65535,
550 .step = 256,
551 .default_value = 32768,
552 .type = V4L2_CTRL_TYPE_INTEGER,
553 },
554 /* --- audio --- */
555 {
556 .id = V4L2_CID_AUDIO_MUTE,
557 .name = "Mute",
558 .minimum = 0,
559 .maximum = 1,
560 .type = V4L2_CTRL_TYPE_BOOLEAN,
561 },{
562 .id = V4L2_CID_AUDIO_VOLUME,
563 .name = "Volume",
564 .minimum = 0,
565 .maximum = 65535,
566 .step = 65535/100,
567 .default_value = 65535,
568 .type = V4L2_CTRL_TYPE_INTEGER,
569 },{
570 .id = V4L2_CID_AUDIO_BALANCE,
571 .name = "Balance",
572 .minimum = 0,
573 .maximum = 65535,
574 .step = 65535/100,
575 .default_value = 32768,
576 .type = V4L2_CTRL_TYPE_INTEGER,
577 },{
578 .id = V4L2_CID_AUDIO_BASS,
579 .name = "Bass",
580 .minimum = 0,
581 .maximum = 65535,
582 .step = 65535/100,
583 .default_value = 32768,
584 .type = V4L2_CTRL_TYPE_INTEGER,
585 },{
586 .id = V4L2_CID_AUDIO_TREBLE,
587 .name = "Treble",
588 .minimum = 0,
589 .maximum = 65535,
590 .step = 65535/100,
591 .default_value = 32768,
592 .type = V4L2_CTRL_TYPE_INTEGER,
593 },
594 /* --- private --- */
595 {
596 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
597 .name = "chroma agc",
598 .minimum = 0,
599 .maximum = 1,
600 .type = V4L2_CTRL_TYPE_BOOLEAN,
601 },{
602 .id = V4L2_CID_PRIVATE_COMBFILTER,
603 .name = "combfilter",
604 .minimum = 0,
605 .maximum = 1,
606 .type = V4L2_CTRL_TYPE_BOOLEAN,
607 },{
608 .id = V4L2_CID_PRIVATE_AUTOMUTE,
609 .name = "automute",
610 .minimum = 0,
611 .maximum = 1,
612 .type = V4L2_CTRL_TYPE_BOOLEAN,
613 },{
614 .id = V4L2_CID_PRIVATE_LUMAFILTER,
615 .name = "luma decimation filter",
616 .minimum = 0,
617 .maximum = 1,
618 .type = V4L2_CTRL_TYPE_BOOLEAN,
619 },{
620 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
621 .name = "agc crush",
622 .minimum = 0,
623 .maximum = 1,
624 .type = V4L2_CTRL_TYPE_BOOLEAN,
625 },{
626 .id = V4L2_CID_PRIVATE_VCR_HACK,
627 .name = "vcr hack",
628 .minimum = 0,
629 .maximum = 1,
630 .type = V4L2_CTRL_TYPE_BOOLEAN,
631 },{
632 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
633 .name = "whitecrush upper",
634 .minimum = 0,
635 .maximum = 255,
636 .step = 1,
637 .default_value = 0xCF,
638 .type = V4L2_CTRL_TYPE_INTEGER,
639 },{
640 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
641 .name = "whitecrush lower",
642 .minimum = 0,
643 .maximum = 255,
644 .step = 1,
645 .default_value = 0x7F,
646 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700647 },{
648 .id = V4L2_CID_PRIVATE_UV_RATIO,
649 .name = "uv ratio",
650 .minimum = 0,
651 .maximum = 100,
652 .step = 1,
653 .default_value = 50,
654 .type = V4L2_CTRL_TYPE_INTEGER,
655 },{
656 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
657 .name = "full luma range",
658 .minimum = 0,
659 .maximum = 1,
660 .type = V4L2_CTRL_TYPE_BOOLEAN,
661 },{
662 .id = V4L2_CID_PRIVATE_CORING,
663 .name = "coring",
664 .minimum = 0,
665 .maximum = 3,
666 .step = 1,
667 .default_value = 0,
668 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
670
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700671
672
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673};
674static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
675
676/* ----------------------------------------------------------------------- */
677/* resource management */
678
679static
680int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
681{
682 if (fh->resources & bit)
683 /* have it already allocated */
684 return 1;
685
686 /* is it free? */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200687 mutex_lock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 if (btv->resources & bit) {
689 /* no, someone else uses it */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200690 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return 0;
692 }
693 /* it's free, grab it */
694 fh->resources |= bit;
695 btv->resources |= bit;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200696 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return 1;
698}
699
700static
701int check_btres(struct bttv_fh *fh, int bit)
702{
703 return (fh->resources & bit);
704}
705
706static
707int locked_btres(struct bttv *btv, int bit)
708{
709 return (btv->resources & bit);
710}
711
712static
713void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
714{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 if ((fh->resources & bits) != bits) {
716 /* trying to free ressources not allocated by us ... */
717 printk("bttv: BUG! (btres)\n");
718 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200719 mutex_lock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 fh->resources &= ~bits;
721 btv->resources &= ~bits;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200722 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723}
724
725/* ----------------------------------------------------------------------- */
726/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
727
728/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
729 PLL_X = Reference pre-divider (0=1, 1=2)
730 PLL_C = Post divider (0=6, 1=4)
731 PLL_I = Integer input
732 PLL_F = Fractional input
733
734 F_input = 28.636363 MHz:
735 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
736*/
737
738static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
739{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800740 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800742 /* prevent overflows */
743 fin/=4;
744 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800746 fout*=12;
747 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800749 fout=(fout%fin)*256;
750 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800752 fout=(fout%fin)*256;
753 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800755 btwrite(fl, BT848_PLL_F_LO);
756 btwrite(fh, BT848_PLL_F_HI);
757 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
760static void set_pll(struct bttv *btv)
761{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800762 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800764 if (!btv->pll.pll_crystal)
765 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
768 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800769 return;
770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800772 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
773 /* no PLL needed */
774 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800775 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700776 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800777 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800778 btwrite(0x00,BT848_TGCTRL);
779 btwrite(0x00,BT848_PLL_XCI);
780 btv->pll.pll_current = 0;
781 return;
782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700784 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800785 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
787
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800788 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700790 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 msleep(10);
792
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800793 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800795 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800796 btwrite(0x08,BT848_TGCTRL);
797 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700798 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800799 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800800 }
801 }
802 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700803 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800804 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805}
806
807/* used to switch between the bt848's analog/digital video capture modes */
808static void bt848A_set_timing(struct bttv *btv)
809{
810 int i, len;
811 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
812 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
813
814 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
815 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
816 btv->c.nr,table_idx);
817
818 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800819 btwrite(0x00, BT848_TGCTRL);
820 btwrite(0x02, BT848_TGCTRL);
821 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 len=SRAM_Table[table_idx][0];
824 for(i = 1; i <= len; i++)
825 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
826 btv->pll.pll_ofreq = 27000000;
827
828 set_pll(btv);
829 btwrite(0x11, BT848_TGCTRL);
830 btwrite(0x41, BT848_DVSIF);
831 } else {
832 btv->pll.pll_ofreq = fsc;
833 set_pll(btv);
834 btwrite(0x0, BT848_DVSIF);
835 }
836}
837
838/* ----------------------------------------------------------------------- */
839
840static void bt848_bright(struct bttv *btv, int bright)
841{
842 int value;
843
844 // printk("bttv: set bright: %d\n",bright); // DEBUG
845 btv->bright = bright;
846
847 /* We want -128 to 127 we get 0-65535 */
848 value = (bright >> 8) - 128;
849 btwrite(value & 0xff, BT848_BRIGHT);
850}
851
852static void bt848_hue(struct bttv *btv, int hue)
853{
854 int value;
855
856 btv->hue = hue;
857
858 /* -128 to 127 */
859 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800860 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
862
863static void bt848_contrast(struct bttv *btv, int cont)
864{
865 int value,hibit;
866
867 btv->contrast = cont;
868
869 /* 0-511 */
870 value = (cont >> 7);
871 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800872 btwrite(value & 0xff, BT848_CONTRAST_LO);
873 btaor(hibit, ~4, BT848_E_CONTROL);
874 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875}
876
877static void bt848_sat(struct bttv *btv, int color)
878{
879 int val_u,val_v,hibits;
880
881 btv->saturation = color;
882
883 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700884 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
885 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800886 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800888 btwrite(val_u & 0xff, BT848_SAT_U_LO);
889 btwrite(val_v & 0xff, BT848_SAT_V_LO);
890 btaor(hibits, ~3, BT848_E_CONTROL);
891 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
894/* ----------------------------------------------------------------------- */
895
896static int
897video_mux(struct bttv *btv, unsigned int input)
898{
899 int mux,mask2;
900
901 if (input >= bttv_tvcards[btv->c.type].video_inputs)
902 return -EINVAL;
903
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800904 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
906 if (mask2)
907 gpio_inout(mask2,mask2);
908
909 if (input == btv->svhs) {
910 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
911 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
912 } else {
913 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
914 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
915 }
916 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
917 btaor(mux<<5, ~(3<<5), BT848_IFORM);
918 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
919 btv->c.nr,input,mux);
920
921 /* card specific hook */
922 if(bttv_tvcards[btv->c.type].muxsel_hook)
923 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
924 return 0;
925}
926
927static char *audio_modes[] = {
928 "audio: tuner", "audio: radio", "audio: extern",
929 "audio: intern", "audio: off"
930};
931
932static int
933audio_mux(struct bttv *btv, int mode)
934{
935 int val,mux,i2c_mux,signal;
936
937 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
938 bttv_tvcards[btv->c.type].gpiomask);
939 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
940
941 switch (mode) {
942 case AUDIO_MUTE:
943 btv->audio |= AUDIO_MUTE;
944 break;
945 case AUDIO_UNMUTE:
946 btv->audio &= ~AUDIO_MUTE;
947 break;
948 case AUDIO_TUNER:
949 case AUDIO_RADIO:
950 case AUDIO_EXTERN:
951 case AUDIO_INTERN:
952 btv->audio &= AUDIO_MUTE;
953 btv->audio |= mode;
954 }
955 i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
956 if (btv->opt_automute && !signal && !btv->radio_user)
957 mux = AUDIO_OFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 val = bttv_tvcards[btv->c.type].audiomux[mux];
960 gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val);
961 if (bttv_gpio)
962 bttv_gpio_tracking(btv,audio_modes[mux]);
963 if (!in_interrupt())
964 bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));
965 return 0;
966}
967
968static void
969i2c_vidiocschan(struct bttv *btv)
970{
971 struct video_channel c;
972
973 memset(&c,0,sizeof(c));
974 c.norm = btv->tvnorm;
975 c.channel = btv->input;
976 bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -0800977 if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 bttv_tda9880_setnorm(btv,c.norm);
979}
980
981static int
982set_tvnorm(struct bttv *btv, unsigned int norm)
983{
984 const struct bttv_tvnorm *tvnorm;
985
986 if (norm < 0 || norm >= BTTV_TVNORMS)
987 return -EINVAL;
988
989 btv->tvnorm = norm;
990 tvnorm = &bttv_tvnorms[norm];
991
992 btwrite(tvnorm->adelay, BT848_ADELAY);
993 btwrite(tvnorm->bdelay, BT848_BDELAY);
994 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
995 BT848_IFORM);
996 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
997 btwrite(1, BT848_VBI_PACK_DEL);
998 bt848A_set_timing(btv);
999
1000 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001001 case BTTV_BOARD_VOODOOTV_FM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 bttv_tda9880_setnorm(btv,norm);
1003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 }
1005 return 0;
1006}
1007
1008static void
1009set_input(struct bttv *btv, unsigned int input)
1010{
1011 unsigned long flags;
1012
1013 btv->input = input;
1014 if (irq_iswitch) {
1015 spin_lock_irqsave(&btv->s_lock,flags);
1016 if (btv->curr.frame_irq) {
1017 /* active capture -> delayed input switch */
1018 btv->new_input = input;
1019 } else {
1020 video_mux(btv,input);
1021 }
1022 spin_unlock_irqrestore(&btv->s_lock,flags);
1023 } else {
1024 video_mux(btv,input);
1025 }
1026 audio_mux(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1027 AUDIO_TUNER : AUDIO_EXTERN));
1028 set_tvnorm(btv,btv->tvnorm);
1029 i2c_vidiocschan(btv);
1030}
1031
1032static void init_irqreg(struct bttv *btv)
1033{
1034 /* clear status */
1035 btwrite(0xfffffUL, BT848_INT_STAT);
1036
1037 if (bttv_tvcards[btv->c.type].no_video) {
1038 /* i2c only */
1039 btwrite(BT848_INT_I2CDONE,
1040 BT848_INT_MASK);
1041 } else {
1042 /* full video */
1043 btwrite((btv->triton1) |
1044 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1045 BT848_INT_SCERR |
1046 (fdsr ? BT848_INT_FDSR : 0) |
1047 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1048 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1049 BT848_INT_I2CDONE,
1050 BT848_INT_MASK);
1051 }
1052}
1053
1054static void init_bt848(struct bttv *btv)
1055{
1056 int val;
1057
1058 if (bttv_tvcards[btv->c.type].no_video) {
1059 /* very basic init only */
1060 init_irqreg(btv);
1061 return;
1062 }
1063
1064 btwrite(0x00, BT848_CAP_CTL);
1065 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1066 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1067
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001068 /* set planar and packed mode trigger points and */
1069 /* set rising edge of inverted GPINTR pin as irq trigger */
1070 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1071 BT848_GPIO_DMA_CTL_PLTP1_16|
1072 BT848_GPIO_DMA_CTL_PLTP23_16|
1073 BT848_GPIO_DMA_CTL_GPINTC|
1074 BT848_GPIO_DMA_CTL_GPINTI,
1075 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
1077 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001078 btwrite(val, BT848_E_SCLOOP);
1079 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001081 btwrite(0x20, BT848_E_VSCALE_HI);
1082 btwrite(0x20, BT848_O_VSCALE_HI);
1083 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 BT848_ADC);
1085
1086 btwrite(whitecrush_upper, BT848_WC_UP);
1087 btwrite(whitecrush_lower, BT848_WC_DOWN);
1088
1089 if (btv->opt_lumafilter) {
1090 btwrite(0, BT848_E_CONTROL);
1091 btwrite(0, BT848_O_CONTROL);
1092 } else {
1093 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1094 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1095 }
1096
1097 bt848_bright(btv, btv->bright);
1098 bt848_hue(btv, btv->hue);
1099 bt848_contrast(btv, btv->contrast);
1100 bt848_sat(btv, btv->saturation);
1101
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001102 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 init_irqreg(btv);
1104}
1105
1106static void bttv_reinit_bt848(struct bttv *btv)
1107{
1108 unsigned long flags;
1109
1110 if (bttv_verbose)
1111 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1112 spin_lock_irqsave(&btv->s_lock,flags);
1113 btv->errors=0;
1114 bttv_set_dma(btv,0);
1115 spin_unlock_irqrestore(&btv->s_lock,flags);
1116
1117 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001118 btv->pll.pll_current = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 set_input(btv,btv->input);
1120}
1121
1122static int get_control(struct bttv *btv, struct v4l2_control *c)
1123{
1124 struct video_audio va;
1125 int i;
1126
1127 for (i = 0; i < BTTV_CTLS; i++)
1128 if (bttv_ctls[i].id == c->id)
1129 break;
1130 if (i == BTTV_CTLS)
1131 return -EINVAL;
1132 if (i >= 4 && i <= 8) {
1133 memset(&va,0,sizeof(va));
1134 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1135 if (btv->audio_hook)
1136 btv->audio_hook(btv,&va,0);
1137 }
1138 switch (c->id) {
1139 case V4L2_CID_BRIGHTNESS:
1140 c->value = btv->bright;
1141 break;
1142 case V4L2_CID_HUE:
1143 c->value = btv->hue;
1144 break;
1145 case V4L2_CID_CONTRAST:
1146 c->value = btv->contrast;
1147 break;
1148 case V4L2_CID_SATURATION:
1149 c->value = btv->saturation;
1150 break;
1151
1152 case V4L2_CID_AUDIO_MUTE:
1153 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1154 break;
1155 case V4L2_CID_AUDIO_VOLUME:
1156 c->value = va.volume;
1157 break;
1158 case V4L2_CID_AUDIO_BALANCE:
1159 c->value = va.balance;
1160 break;
1161 case V4L2_CID_AUDIO_BASS:
1162 c->value = va.bass;
1163 break;
1164 case V4L2_CID_AUDIO_TREBLE:
1165 c->value = va.treble;
1166 break;
1167
1168 case V4L2_CID_PRIVATE_CHROMA_AGC:
1169 c->value = btv->opt_chroma_agc;
1170 break;
1171 case V4L2_CID_PRIVATE_COMBFILTER:
1172 c->value = btv->opt_combfilter;
1173 break;
1174 case V4L2_CID_PRIVATE_LUMAFILTER:
1175 c->value = btv->opt_lumafilter;
1176 break;
1177 case V4L2_CID_PRIVATE_AUTOMUTE:
1178 c->value = btv->opt_automute;
1179 break;
1180 case V4L2_CID_PRIVATE_AGC_CRUSH:
1181 c->value = btv->opt_adc_crush;
1182 break;
1183 case V4L2_CID_PRIVATE_VCR_HACK:
1184 c->value = btv->opt_vcr_hack;
1185 break;
1186 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1187 c->value = btv->opt_whitecrush_upper;
1188 break;
1189 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1190 c->value = btv->opt_whitecrush_lower;
1191 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001192 case V4L2_CID_PRIVATE_UV_RATIO:
1193 c->value = btv->opt_uv_ratio;
1194 break;
1195 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1196 c->value = btv->opt_full_luma_range;
1197 break;
1198 case V4L2_CID_PRIVATE_CORING:
1199 c->value = btv->opt_coring;
1200 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 default:
1202 return -EINVAL;
1203 }
1204 return 0;
1205}
1206
1207static int set_control(struct bttv *btv, struct v4l2_control *c)
1208{
1209 struct video_audio va;
1210 int i,val;
1211
1212 for (i = 0; i < BTTV_CTLS; i++)
1213 if (bttv_ctls[i].id == c->id)
1214 break;
1215 if (i == BTTV_CTLS)
1216 return -EINVAL;
1217 if (i >= 4 && i <= 8) {
1218 memset(&va,0,sizeof(va));
1219 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1220 if (btv->audio_hook)
1221 btv->audio_hook(btv,&va,0);
1222 }
1223 switch (c->id) {
1224 case V4L2_CID_BRIGHTNESS:
1225 bt848_bright(btv,c->value);
1226 break;
1227 case V4L2_CID_HUE:
1228 bt848_hue(btv,c->value);
1229 break;
1230 case V4L2_CID_CONTRAST:
1231 bt848_contrast(btv,c->value);
1232 break;
1233 case V4L2_CID_SATURATION:
1234 bt848_sat(btv,c->value);
1235 break;
1236 case V4L2_CID_AUDIO_MUTE:
1237 if (c->value) {
1238 va.flags |= VIDEO_AUDIO_MUTE;
1239 audio_mux(btv, AUDIO_MUTE);
1240 } else {
1241 va.flags &= ~VIDEO_AUDIO_MUTE;
1242 audio_mux(btv, AUDIO_UNMUTE);
1243 }
1244 break;
1245
1246 case V4L2_CID_AUDIO_VOLUME:
1247 va.volume = c->value;
1248 break;
1249 case V4L2_CID_AUDIO_BALANCE:
1250 va.balance = c->value;
1251 break;
1252 case V4L2_CID_AUDIO_BASS:
1253 va.bass = c->value;
1254 break;
1255 case V4L2_CID_AUDIO_TREBLE:
1256 va.treble = c->value;
1257 break;
1258
1259 case V4L2_CID_PRIVATE_CHROMA_AGC:
1260 btv->opt_chroma_agc = c->value;
1261 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1262 btwrite(val, BT848_E_SCLOOP);
1263 btwrite(val, BT848_O_SCLOOP);
1264 break;
1265 case V4L2_CID_PRIVATE_COMBFILTER:
1266 btv->opt_combfilter = c->value;
1267 break;
1268 case V4L2_CID_PRIVATE_LUMAFILTER:
1269 btv->opt_lumafilter = c->value;
1270 if (btv->opt_lumafilter) {
1271 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1272 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1273 } else {
1274 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1275 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1276 }
1277 break;
1278 case V4L2_CID_PRIVATE_AUTOMUTE:
1279 btv->opt_automute = c->value;
1280 break;
1281 case V4L2_CID_PRIVATE_AGC_CRUSH:
1282 btv->opt_adc_crush = c->value;
1283 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1284 BT848_ADC);
1285 break;
1286 case V4L2_CID_PRIVATE_VCR_HACK:
1287 btv->opt_vcr_hack = c->value;
1288 break;
1289 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1290 btv->opt_whitecrush_upper = c->value;
1291 btwrite(c->value, BT848_WC_UP);
1292 break;
1293 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1294 btv->opt_whitecrush_lower = c->value;
1295 btwrite(c->value, BT848_WC_DOWN);
1296 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001297 case V4L2_CID_PRIVATE_UV_RATIO:
1298 btv->opt_uv_ratio = c->value;
1299 bt848_sat(btv, btv->saturation);
1300 break;
1301 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1302 btv->opt_full_luma_range = c->value;
1303 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1304 break;
1305 case V4L2_CID_PRIVATE_CORING:
1306 btv->opt_coring = c->value;
1307 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1308 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 default:
1310 return -EINVAL;
1311 }
1312 if (i >= 4 && i <= 8) {
1313 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1314 if (btv->audio_hook)
1315 btv->audio_hook(btv,&va,1);
1316 }
1317 return 0;
1318}
1319
1320/* ----------------------------------------------------------------------- */
1321
1322void bttv_gpio_tracking(struct bttv *btv, char *comment)
1323{
1324 unsigned int outbits, data;
1325 outbits = btread(BT848_GPIO_OUT_EN);
1326 data = btread(BT848_GPIO_DATA);
1327 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1328 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1329}
1330
1331static void bttv_field_count(struct bttv *btv)
1332{
1333 int need_count = 0;
1334
1335 if (btv->users)
1336 need_count++;
1337
1338 if (need_count) {
1339 /* start field counter */
1340 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1341 } else {
1342 /* stop field counter */
1343 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1344 btv->field_count = 0;
1345 }
1346}
1347
1348static const struct bttv_format*
1349format_by_palette(int palette)
1350{
1351 unsigned int i;
1352
1353 for (i = 0; i < BTTV_FORMATS; i++) {
1354 if (-1 == bttv_formats[i].palette)
1355 continue;
1356 if (bttv_formats[i].palette == palette)
1357 return bttv_formats+i;
1358 }
1359 return NULL;
1360}
1361
1362static const struct bttv_format*
1363format_by_fourcc(int fourcc)
1364{
1365 unsigned int i;
1366
1367 for (i = 0; i < BTTV_FORMATS; i++) {
1368 if (-1 == bttv_formats[i].fourcc)
1369 continue;
1370 if (bttv_formats[i].fourcc == fourcc)
1371 return bttv_formats+i;
1372 }
1373 return NULL;
1374}
1375
1376/* ----------------------------------------------------------------------- */
1377/* misc helpers */
1378
1379static int
1380bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1381 struct bttv_buffer *new)
1382{
1383 struct bttv_buffer *old;
1384 unsigned long flags;
1385 int retval = 0;
1386
1387 dprintk("switch_overlay: enter [new=%p]\n",new);
1388 if (new)
1389 new->vb.state = STATE_DONE;
1390 spin_lock_irqsave(&btv->s_lock,flags);
1391 old = btv->screen;
1392 btv->screen = new;
1393 btv->loop_irq |= 1;
1394 bttv_set_dma(btv, 0x03);
1395 spin_unlock_irqrestore(&btv->s_lock,flags);
1396 if (NULL == new)
1397 free_btres(btv,fh,RESOURCE_OVERLAY);
1398 if (NULL != old) {
1399 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
1400 bttv_dma_free(btv, old);
1401 kfree(old);
1402 }
1403 dprintk("switch_overlay: done\n");
1404 return retval;
1405}
1406
1407/* ----------------------------------------------------------------------- */
1408/* video4linux (1) interface */
1409
1410static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001411 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 unsigned int width, unsigned int height,
1413 enum v4l2_field field)
1414{
1415 int redo_dma_risc = 0;
1416 int rc;
1417
1418 /* check settings */
1419 if (NULL == fmt)
1420 return -EINVAL;
1421 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1422 width = RAW_BPL;
1423 height = RAW_LINES*2;
1424 if (width*height > buf->vb.bsize)
1425 return -EINVAL;
1426 buf->vb.size = buf->vb.bsize;
1427 } else {
1428 if (width < 48 ||
1429 height < 32 ||
1430 width > bttv_tvnorms[btv->tvnorm].swidth ||
1431 height > bttv_tvnorms[btv->tvnorm].sheight)
1432 return -EINVAL;
1433 buf->vb.size = (width * height * fmt->depth) >> 3;
1434 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1435 return -EINVAL;
1436 }
1437
1438 /* alloc + fill struct bttv_buffer (if changed) */
1439 if (buf->vb.width != width || buf->vb.height != height ||
1440 buf->vb.field != field ||
1441 buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
1442 buf->vb.width = width;
1443 buf->vb.height = height;
1444 buf->vb.field = field;
1445 buf->tvnorm = btv->tvnorm;
1446 buf->fmt = fmt;
1447 redo_dma_risc = 1;
1448 }
1449
1450 /* alloc risc memory */
1451 if (STATE_NEEDS_INIT == buf->vb.state) {
1452 redo_dma_risc = 1;
1453 if (0 != (rc = videobuf_iolock(btv->c.pci,&buf->vb,&btv->fbuf)))
1454 goto fail;
1455 }
1456
1457 if (redo_dma_risc)
1458 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1459 goto fail;
1460
1461 buf->vb.state = STATE_PREPARED;
1462 return 0;
1463
1464 fail:
1465 bttv_dma_free(btv,buf);
1466 return rc;
1467}
1468
1469static int
1470buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1471{
1472 struct bttv_fh *fh = q->priv_data;
1473
1474 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1475 if (0 == *count)
1476 *count = gbuffers;
1477 while (*size * *count > gbuffers * gbufsize)
1478 (*count)--;
1479 return 0;
1480}
1481
1482static int
1483buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1484 enum v4l2_field field)
1485{
1486 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1487 struct bttv_fh *fh = q->priv_data;
1488
1489 return bttv_prepare_buffer(fh->btv, buf, fh->fmt,
1490 fh->width, fh->height, field);
1491}
1492
1493static void
1494buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1495{
1496 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1497 struct bttv_fh *fh = q->priv_data;
1498 struct bttv *btv = fh->btv;
1499
1500 buf->vb.state = STATE_QUEUED;
1501 list_add_tail(&buf->vb.queue,&btv->capture);
1502 if (!btv->curr.frame_irq) {
1503 btv->loop_irq |= 1;
1504 bttv_set_dma(btv, 0x03);
1505 }
1506}
1507
1508static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1509{
1510 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1511 struct bttv_fh *fh = q->priv_data;
1512
1513 bttv_dma_free(fh->btv,buf);
1514}
1515
1516static struct videobuf_queue_ops bttv_video_qops = {
1517 .buf_setup = buffer_setup,
1518 .buf_prepare = buffer_prepare,
1519 .buf_queue = buffer_queue,
1520 .buf_release = buffer_release,
1521};
1522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1524{
1525 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001526 case BTTV_VERSION:
1527 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
1529 /* *** v4l1 *** ************************************************ */
1530 case VIDIOCGFREQ:
1531 {
1532 unsigned long *freq = arg;
1533 *freq = btv->freq;
1534 return 0;
1535 }
1536 case VIDIOCSFREQ:
1537 {
1538 unsigned long *freq = arg;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001539 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 btv->freq=*freq;
1541 bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
1542 if (btv->has_matchbox && btv->radio_user)
1543 tea5757_set_freq(btv,*freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001544 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 return 0;
1546 }
1547
1548 case VIDIOCGTUNER:
1549 {
1550 struct video_tuner *v = arg;
1551
1552 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1553 return -EINVAL;
1554 if (v->tuner) /* Only tuner 0 */
1555 return -EINVAL;
1556 strcpy(v->name, "Television");
1557 v->rangelow = 0;
1558 v->rangehigh = 0x7FFFFFFF;
1559 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1560 v->mode = btv->tvnorm;
1561 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1562 bttv_call_i2c_clients(btv,cmd,v);
1563 return 0;
1564 }
1565 case VIDIOCSTUNER:
1566 {
1567 struct video_tuner *v = arg;
1568
1569 if (v->tuner) /* Only tuner 0 */
1570 return -EINVAL;
1571 if (v->mode >= BTTV_TVNORMS)
1572 return -EINVAL;
1573
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001574 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 set_tvnorm(btv,v->mode);
1576 bttv_call_i2c_clients(btv,cmd,v);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001577 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 return 0;
1579 }
1580
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001581 case VIDIOCGCHAN:
1582 {
1583 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 unsigned int channel = v->channel;
1585
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001586 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1587 return -EINVAL;
1588 v->tuners=0;
1589 v->flags = VIDEO_VC_AUDIO;
1590 v->type = VIDEO_TYPE_CAMERA;
1591 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001593 strcpy(v->name,"Television");
1594 v->flags|=VIDEO_VC_TUNER;
1595 v->type=VIDEO_TYPE_TV;
1596 v->tuners=1;
1597 } else if (channel == btv->svhs) {
1598 strcpy(v->name,"S-Video");
1599 } else {
1600 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 }
1602 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001603 }
1604 case VIDIOCSCHAN:
1605 {
1606 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 unsigned int channel = v->channel;
1608
1609 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1610 return -EINVAL;
1611 if (v->norm >= BTTV_TVNORMS)
1612 return -EINVAL;
1613
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001614 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 if (channel == btv->input &&
1616 v->norm == btv->tvnorm) {
1617 /* nothing to do */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001618 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 return 0;
1620 }
1621
1622 btv->tvnorm = v->norm;
1623 set_input(btv,v->channel);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001624 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 return 0;
1626 }
1627
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001628 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 {
1630 struct video_audio *v = arg;
1631
1632 memset(v,0,sizeof(*v));
1633 strcpy(v->name,"Television");
1634 v->flags |= VIDEO_AUDIO_MUTABLE;
1635 v->mode = VIDEO_SOUND_MONO;
1636
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001637 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 bttv_call_i2c_clients(btv,cmd,v);
1639
1640 /* card specific hooks */
1641 if (btv->audio_hook)
1642 btv->audio_hook(btv,v,0);
1643
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001644 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 return 0;
1646 }
1647 case VIDIOCSAUDIO:
1648 {
1649 struct video_audio *v = arg;
1650 unsigned int audio = v->audio;
1651
1652 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
1653 return -EINVAL;
1654
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001655 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE);
1657 bttv_call_i2c_clients(btv,cmd,v);
1658
1659 /* card specific hooks */
1660 if (btv->audio_hook)
1661 btv->audio_hook(btv,v,1);
1662
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001663 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 return 0;
1665 }
1666
1667 /* *** v4l2 *** ************************************************ */
1668 case VIDIOC_ENUMSTD:
1669 {
1670 struct v4l2_standard *e = arg;
1671 unsigned int index = e->index;
1672
1673 if (index >= BTTV_TVNORMS)
1674 return -EINVAL;
1675 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1676 bttv_tvnorms[e->index].name);
1677 e->index = index;
1678 return 0;
1679 }
1680 case VIDIOC_G_STD:
1681 {
1682 v4l2_std_id *id = arg;
1683 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1684 return 0;
1685 }
1686 case VIDIOC_S_STD:
1687 {
1688 v4l2_std_id *id = arg;
1689 unsigned int i;
1690
1691 for (i = 0; i < BTTV_TVNORMS; i++)
1692 if (*id & bttv_tvnorms[i].v4l2_id)
1693 break;
1694 if (i == BTTV_TVNORMS)
1695 return -EINVAL;
1696
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001697 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 set_tvnorm(btv,i);
1699 i2c_vidiocschan(btv);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001700 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 return 0;
1702 }
1703 case VIDIOC_QUERYSTD:
1704 {
1705 v4l2_std_id *id = arg;
1706
1707 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1708 *id = V4L2_STD_625_50;
1709 else
1710 *id = V4L2_STD_525_60;
1711 return 0;
1712 }
1713
1714 case VIDIOC_ENUMINPUT:
1715 {
1716 struct v4l2_input *i = arg;
1717 unsigned int n;
1718
1719 n = i->index;
1720 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1721 return -EINVAL;
1722 memset(i,0,sizeof(*i));
1723 i->index = n;
1724 i->type = V4L2_INPUT_TYPE_CAMERA;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001725 i->audioset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1727 sprintf(i->name, "Television");
1728 i->type = V4L2_INPUT_TYPE_TUNER;
1729 i->tuner = 0;
1730 } else if (i->index == btv->svhs) {
1731 sprintf(i->name, "S-Video");
1732 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001733 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 }
1735 if (i->index == btv->input) {
1736 __u32 dstatus = btread(BT848_DSTATUS);
1737 if (0 == (dstatus & BT848_DSTATUS_PRES))
1738 i->status |= V4L2_IN_ST_NO_SIGNAL;
1739 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1740 i->status |= V4L2_IN_ST_NO_H_LOCK;
1741 }
1742 for (n = 0; n < BTTV_TVNORMS; n++)
1743 i->std |= bttv_tvnorms[n].v4l2_id;
1744 return 0;
1745 }
1746 case VIDIOC_G_INPUT:
1747 {
1748 int *i = arg;
1749 *i = btv->input;
1750 return 0;
1751 }
1752 case VIDIOC_S_INPUT:
1753 {
1754 unsigned int *i = arg;
1755
1756 if (*i > bttv_tvcards[btv->c.type].video_inputs)
1757 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001758 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 set_input(btv,*i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001760 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 return 0;
1762 }
1763
1764 case VIDIOC_G_TUNER:
1765 {
1766 struct v4l2_tuner *t = arg;
1767
1768 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1769 return -EINVAL;
1770 if (0 != t->index)
1771 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001772 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 memset(t,0,sizeof(*t));
1774 strcpy(t->name, "Television");
1775 t->type = V4L2_TUNER_ANALOG_TV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 t->capability = V4L2_TUNER_CAP_NORM;
1777 t->rxsubchans = V4L2_TUNER_SUB_MONO;
1778 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
1779 t->signal = 0xffff;
1780 {
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001781 struct video_tuner tuner;
1782
1783 memset(&tuner, 0, sizeof (tuner));
1784 tuner.rangehigh = 0xffffffffUL;
1785 bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);
1786 t->rangelow = tuner.rangelow;
1787 t->rangehigh = tuner.rangehigh;
1788 }
1789 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 /* Hmmm ... */
1791 struct video_audio va;
1792 memset(&va, 0, sizeof(struct video_audio));
1793 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1794 if (btv->audio_hook)
1795 btv->audio_hook(btv,&va,0);
1796 if(va.mode & VIDEO_SOUND_STEREO) {
1797 t->audmode = V4L2_TUNER_MODE_STEREO;
1798 t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
1799 }
1800 if(va.mode & VIDEO_SOUND_LANG1) {
1801 t->audmode = V4L2_TUNER_MODE_LANG1;
1802 t->rxsubchans = V4L2_TUNER_SUB_LANG1
1803 | V4L2_TUNER_SUB_LANG2;
1804 }
1805 }
1806 /* FIXME: fill capability+audmode */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001807 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 return 0;
1809 }
1810 case VIDIOC_S_TUNER:
1811 {
1812 struct v4l2_tuner *t = arg;
1813
1814 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1815 return -EINVAL;
1816 if (0 != t->index)
1817 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001818 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 {
1820 struct video_audio va;
1821 memset(&va, 0, sizeof(struct video_audio));
1822 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1823 if (t->audmode == V4L2_TUNER_MODE_MONO)
1824 va.mode = VIDEO_SOUND_MONO;
1825 else if (t->audmode == V4L2_TUNER_MODE_STEREO)
1826 va.mode = VIDEO_SOUND_STEREO;
1827 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
1828 va.mode = VIDEO_SOUND_LANG1;
1829 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
1830 va.mode = VIDEO_SOUND_LANG2;
1831 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1832 if (btv->audio_hook)
1833 btv->audio_hook(btv,&va,1);
1834 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001835 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 return 0;
1837 }
1838
1839 case VIDIOC_G_FREQUENCY:
1840 {
1841 struct v4l2_frequency *f = arg;
1842
1843 memset(f,0,sizeof(*f));
1844 f->type = V4L2_TUNER_ANALOG_TV;
1845 f->frequency = btv->freq;
1846 return 0;
1847 }
1848 case VIDIOC_S_FREQUENCY:
1849 {
1850 struct v4l2_frequency *f = arg;
1851
1852 if (unlikely(f->tuner != 0))
1853 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07001854 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001856 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 btv->freq = f->frequency;
1858 bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
1859 if (btv->has_matchbox && btv->radio_user)
1860 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001861 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 return 0;
1863 }
Hans Verkuil299392b2005-11-08 21:37:42 -08001864 case VIDIOC_LOG_STATUS:
1865 {
Luiz Capitulino97cb4452005-12-01 00:51:24 -08001866 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil299392b2005-11-08 21:37:42 -08001867 return 0;
1868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
1870 default:
1871 return -ENOIOCTLCMD;
1872
1873 }
1874 return 0;
1875}
1876
1877static int verify_window(const struct bttv_tvnorm *tvn,
1878 struct v4l2_window *win, int fixup)
1879{
1880 enum v4l2_field field;
1881 int maxw, maxh;
1882
1883 if (win->w.width < 48 || win->w.height < 32)
1884 return -EINVAL;
1885 if (win->clipcount > 2048)
1886 return -EINVAL;
1887
1888 field = win->field;
1889 maxw = tvn->swidth;
1890 maxh = tvn->sheight;
1891
1892 if (V4L2_FIELD_ANY == field) {
1893 field = (win->w.height > maxh/2)
1894 ? V4L2_FIELD_INTERLACED
1895 : V4L2_FIELD_TOP;
1896 }
1897 switch (field) {
1898 case V4L2_FIELD_TOP:
1899 case V4L2_FIELD_BOTTOM:
1900 maxh = maxh / 2;
1901 break;
1902 case V4L2_FIELD_INTERLACED:
1903 break;
1904 default:
1905 return -EINVAL;
1906 }
1907
1908 if (!fixup && (win->w.width > maxw || win->w.height > maxh))
1909 return -EINVAL;
1910
1911 if (win->w.width > maxw)
1912 win->w.width = maxw;
1913 if (win->w.height > maxh)
1914 win->w.height = maxh;
1915 win->field = field;
1916 return 0;
1917}
1918
1919static int setup_window(struct bttv_fh *fh, struct bttv *btv,
1920 struct v4l2_window *win, int fixup)
1921{
1922 struct v4l2_clip *clips = NULL;
1923 int n,size,retval = 0;
1924
1925 if (NULL == fh->ovfmt)
1926 return -EINVAL;
1927 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
1928 return -EINVAL;
1929 retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
1930 if (0 != retval)
1931 return retval;
1932
1933 /* copy clips -- luckily v4l1 + v4l2 are binary
1934 compatible here ...*/
1935 n = win->clipcount;
1936 size = sizeof(*clips)*(n+4);
1937 clips = kmalloc(size,GFP_KERNEL);
1938 if (NULL == clips)
1939 return -ENOMEM;
1940 if (n > 0) {
1941 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
1942 kfree(clips);
1943 return -EFAULT;
1944 }
1945 }
1946 /* clip against screen */
1947 if (NULL != btv->fbuf.base)
1948 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
1949 &win->w, clips, n);
1950 btcx_sort_clips(clips,n);
1951
1952 /* 4-byte alignments */
1953 switch (fh->ovfmt->depth) {
1954 case 8:
1955 case 24:
1956 btcx_align(&win->w, clips, n, 3);
1957 break;
1958 case 16:
1959 btcx_align(&win->w, clips, n, 1);
1960 break;
1961 case 32:
1962 /* no alignment fixups needed */
1963 break;
1964 default:
1965 BUG();
1966 }
1967
Ingo Molnar3593cab2006-02-07 06:49:14 -02001968 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001969 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 fh->ov.clips = clips;
1971 fh->ov.nclips = n;
1972
1973 fh->ov.w = win->w;
1974 fh->ov.field = win->field;
1975 fh->ov.setup_ok = 1;
1976 btv->init.ov.w.width = win->w.width;
1977 btv->init.ov.w.height = win->w.height;
1978 btv->init.ov.field = win->field;
1979
1980 /* update overlay if needed */
1981 retval = 0;
1982 if (check_btres(fh, RESOURCE_OVERLAY)) {
1983 struct bttv_buffer *new;
1984
1985 new = videobuf_alloc(sizeof(*new));
1986 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
1987 retval = bttv_switch_overlay(btv,fh,new);
1988 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02001989 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 return retval;
1991}
1992
1993/* ----------------------------------------------------------------------- */
1994
1995static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
1996{
1997 struct videobuf_queue* q = NULL;
1998
1999 switch (fh->type) {
2000 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2001 q = &fh->cap;
2002 break;
2003 case V4L2_BUF_TYPE_VBI_CAPTURE:
2004 q = &fh->vbi;
2005 break;
2006 default:
2007 BUG();
2008 }
2009 return q;
2010}
2011
2012static int bttv_resource(struct bttv_fh *fh)
2013{
2014 int res = 0;
2015
2016 switch (fh->type) {
2017 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2018 res = RESOURCE_VIDEO;
2019 break;
2020 case V4L2_BUF_TYPE_VBI_CAPTURE:
2021 res = RESOURCE_VBI;
2022 break;
2023 default:
2024 BUG();
2025 }
2026 return res;
2027}
2028
2029static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2030{
2031 struct videobuf_queue *q = bttv_queue(fh);
2032 int res = bttv_resource(fh);
2033
2034 if (check_btres(fh,res))
2035 return -EBUSY;
2036 if (videobuf_queue_is_busy(q))
2037 return -EBUSY;
2038 fh->type = type;
2039 return 0;
2040}
2041
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002042static void
2043pix_format_set_size (struct v4l2_pix_format * f,
2044 const struct bttv_format * fmt,
2045 unsigned int width,
2046 unsigned int height)
2047{
2048 f->width = width;
2049 f->height = height;
2050
2051 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2052 f->bytesperline = width; /* Y plane */
2053 f->sizeimage = (width * height * fmt->depth) >> 3;
2054 } else {
2055 f->bytesperline = (width * fmt->depth) >> 3;
2056 f->sizeimage = height * f->bytesperline;
2057 }
2058}
2059
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2061{
2062 switch (f->type) {
2063 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2064 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002065 pix_format_set_size (&f->fmt.pix, fh->fmt,
2066 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 f->fmt.pix.field = fh->cap.field;
2068 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 return 0;
2070 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2071 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2072 f->fmt.win.w = fh->ov.w;
2073 f->fmt.win.field = fh->ov.field;
2074 return 0;
2075 case V4L2_BUF_TYPE_VBI_CAPTURE:
2076 bttv_vbi_get_fmt(fh,f);
2077 return 0;
2078 default:
2079 return -EINVAL;
2080 }
2081}
2082
2083static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
2084 struct v4l2_format *f)
2085{
2086 switch (f->type) {
2087 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2088 {
2089 const struct bttv_format *fmt;
2090 enum v4l2_field field;
2091 unsigned int maxw,maxh;
2092
2093 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2094 if (NULL == fmt)
2095 return -EINVAL;
2096
2097 /* fixup format */
2098 maxw = bttv_tvnorms[btv->tvnorm].swidth;
2099 maxh = bttv_tvnorms[btv->tvnorm].sheight;
2100 field = f->fmt.pix.field;
2101 if (V4L2_FIELD_ANY == field)
2102 field = (f->fmt.pix.height > maxh/2)
2103 ? V4L2_FIELD_INTERLACED
2104 : V4L2_FIELD_BOTTOM;
2105 if (V4L2_FIELD_SEQ_BT == field)
2106 field = V4L2_FIELD_SEQ_TB;
2107 switch (field) {
2108 case V4L2_FIELD_TOP:
2109 case V4L2_FIELD_BOTTOM:
2110 case V4L2_FIELD_ALTERNATE:
2111 maxh = maxh/2;
2112 break;
2113 case V4L2_FIELD_INTERLACED:
2114 break;
2115 case V4L2_FIELD_SEQ_TB:
2116 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2117 return -EINVAL;
2118 break;
2119 default:
2120 return -EINVAL;
2121 }
2122
2123 /* update data for the application */
2124 f->fmt.pix.field = field;
2125 if (f->fmt.pix.width < 48)
2126 f->fmt.pix.width = 48;
2127 if (f->fmt.pix.height < 32)
2128 f->fmt.pix.height = 32;
2129 if (f->fmt.pix.width > maxw)
2130 f->fmt.pix.width = maxw;
2131 if (f->fmt.pix.height > maxh)
2132 f->fmt.pix.height = maxh;
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002133 pix_format_set_size (&f->fmt.pix, fmt,
2134 f->fmt.pix.width & ~3,
2135 f->fmt.pix.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
2137 return 0;
2138 }
2139 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2140 return verify_window(&bttv_tvnorms[btv->tvnorm],
2141 &f->fmt.win, 1);
2142 case V4L2_BUF_TYPE_VBI_CAPTURE:
2143 bttv_vbi_try_fmt(fh,f);
2144 return 0;
2145 default:
2146 return -EINVAL;
2147 }
2148}
2149
2150static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2151 struct v4l2_format *f)
2152{
2153 int retval;
2154
2155 switch (f->type) {
2156 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2157 {
2158 const struct bttv_format *fmt;
2159
2160 retval = bttv_switch_type(fh,f->type);
2161 if (0 != retval)
2162 return retval;
2163 retval = bttv_try_fmt(fh,btv,f);
2164 if (0 != retval)
2165 return retval;
2166 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2167
2168 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002169 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 fh->fmt = fmt;
2171 fh->cap.field = f->fmt.pix.field;
2172 fh->cap.last = V4L2_FIELD_NONE;
2173 fh->width = f->fmt.pix.width;
2174 fh->height = f->fmt.pix.height;
2175 btv->init.fmt = fmt;
2176 btv->init.width = f->fmt.pix.width;
2177 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002178 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
2180 return 0;
2181 }
2182 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002183 if (no_overlay > 0) {
2184 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2185 return -EINVAL;
2186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 return setup_window(fh, btv, &f->fmt.win, 1);
2188 case V4L2_BUF_TYPE_VBI_CAPTURE:
2189 retval = bttv_switch_type(fh,f->type);
2190 if (0 != retval)
2191 return retval;
2192 if (locked_btres(fh->btv, RESOURCE_VBI))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002193 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 bttv_vbi_try_fmt(fh,f);
2195 bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
2196 bttv_vbi_get_fmt(fh,f);
2197 return 0;
2198 default:
2199 return -EINVAL;
2200 }
2201}
2202
2203static int bttv_do_ioctl(struct inode *inode, struct file *file,
2204 unsigned int cmd, void *arg)
2205{
2206 struct bttv_fh *fh = file->private_data;
2207 struct bttv *btv = fh->btv;
2208 unsigned long flags;
2209 int retval = 0;
2210
Michael Krufky5e453dc2006-01-09 15:32:31 -02002211 if (bttv_debug > 1)
2212 v4l_print_ioctl(btv->c.name, cmd);
2213
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 if (btv->errors)
2215 bttv_reinit_bt848(btv);
2216
2217 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002218 case VIDIOCSFREQ:
2219 case VIDIOCSTUNER:
2220 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 case VIDIOC_S_CTRL:
2222 case VIDIOC_S_STD:
2223 case VIDIOC_S_INPUT:
2224 case VIDIOC_S_TUNER:
2225 case VIDIOC_S_FREQUENCY:
2226 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2227 if (0 != retval)
2228 return retval;
2229 };
2230
2231 switch (cmd) {
2232
2233 /* *** v4l1 *** ************************************************ */
2234 case VIDIOCGCAP:
2235 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002236 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002239 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2241 /* vbi */
2242 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2243 } else {
2244 /* others */
2245 cap->type = VID_TYPE_CAPTURE|
2246 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 VID_TYPE_CLIPPING|
2248 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002249 if (no_overlay <= 0)
2250 cap->type |= VID_TYPE_OVERLAY;
2251
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2253 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2254 cap->minwidth = 48;
2255 cap->minheight = 32;
2256 }
2257 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2258 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002259 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 }
2261
2262 case VIDIOCGPICT:
2263 {
2264 struct video_picture *pic = arg;
2265
2266 memset(pic,0,sizeof(*pic));
2267 pic->brightness = btv->bright;
2268 pic->contrast = btv->contrast;
2269 pic->hue = btv->hue;
2270 pic->colour = btv->saturation;
2271 if (fh->fmt) {
2272 pic->depth = fh->fmt->depth;
2273 pic->palette = fh->fmt->palette;
2274 }
2275 return 0;
2276 }
2277 case VIDIOCSPICT:
2278 {
2279 struct video_picture *pic = arg;
2280 const struct bttv_format *fmt;
2281
2282 fmt = format_by_palette(pic->palette);
2283 if (NULL == fmt)
2284 return -EINVAL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002285 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 if (fmt->depth != pic->depth) {
2287 retval = -EINVAL;
2288 goto fh_unlock_and_return;
2289 }
Michael H. Schimek13c72802005-12-01 00:51:37 -08002290 if (fmt->flags & FORMAT_FLAGS_RAW) {
2291 /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
2292 RAW_LINES * 2. F1 is stored at offset 0, F2
2293 at buffer size / 2. */
2294 fh->width = RAW_BPL;
2295 fh->height = gbufsize / RAW_BPL;
2296 btv->init.width = RAW_BPL;
2297 btv->init.height = gbufsize / RAW_BPL;
2298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 fh->ovfmt = fmt;
2300 fh->fmt = fmt;
2301 btv->init.ovfmt = fmt;
2302 btv->init.fmt = fmt;
2303 if (bigendian) {
2304 /* dirty hack time: swap bytes for overlay if the
2305 display adaptor is big endian (insmod option) */
2306 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2307 fmt->palette == VIDEO_PALETTE_RGB565 ||
2308 fmt->palette == VIDEO_PALETTE_RGB32) {
2309 fh->ovfmt = fmt+1;
2310 }
2311 }
2312 bt848_bright(btv,pic->brightness);
2313 bt848_contrast(btv,pic->contrast);
2314 bt848_hue(btv,pic->hue);
2315 bt848_sat(btv,pic->colour);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002316 mutex_unlock(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002317 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 }
2319
2320 case VIDIOCGWIN:
2321 {
2322 struct video_window *win = arg;
2323
2324 memset(win,0,sizeof(*win));
2325 win->x = fh->ov.w.left;
2326 win->y = fh->ov.w.top;
2327 win->width = fh->ov.w.width;
2328 win->height = fh->ov.w.height;
2329 return 0;
2330 }
2331 case VIDIOCSWIN:
2332 {
2333 struct video_window *win = arg;
2334 struct v4l2_window w2;
2335
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002336 if (no_overlay > 0) {
2337 printk ("VIDIOCSWIN: no_overlay\n");
2338 return -EINVAL;
2339 }
2340
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 w2.field = V4L2_FIELD_ANY;
2342 w2.w.left = win->x;
2343 w2.w.top = win->y;
2344 w2.w.width = win->width;
2345 w2.w.height = win->height;
2346 w2.clipcount = win->clipcount;
2347 w2.clips = (struct v4l2_clip __user *)win->clips;
2348 retval = setup_window(fh, btv, &w2, 0);
2349 if (0 == retval) {
2350 /* on v4l1 this ioctl affects the read() size too */
2351 fh->width = fh->ov.w.width;
2352 fh->height = fh->ov.w.height;
2353 btv->init.width = fh->ov.w.width;
2354 btv->init.height = fh->ov.w.height;
2355 }
2356 return retval;
2357 }
2358
2359 case VIDIOCGFBUF:
2360 {
2361 struct video_buffer *fbuf = arg;
2362
2363 fbuf->base = btv->fbuf.base;
2364 fbuf->width = btv->fbuf.fmt.width;
2365 fbuf->height = btv->fbuf.fmt.height;
2366 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2367 if (fh->ovfmt)
2368 fbuf->depth = fh->ovfmt->depth;
2369 return 0;
2370 }
2371 case VIDIOCSFBUF:
2372 {
2373 struct video_buffer *fbuf = arg;
2374 const struct bttv_format *fmt;
2375 unsigned long end;
2376
2377 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002378 !capable(CAP_SYS_RAWIO))
2379 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 end = (unsigned long)fbuf->base +
2381 fbuf->height * fbuf->bytesperline;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002382 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 retval = -EINVAL;
2384
2385 switch (fbuf->depth) {
2386 case 8:
2387 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2388 break;
2389 case 16:
2390 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2391 break;
2392 case 24:
2393 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2394 break;
2395 case 32:
2396 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2397 break;
2398 case 15:
2399 fbuf->depth = 16;
2400 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2401 break;
2402 default:
2403 fmt = NULL;
2404 break;
2405 }
2406 if (NULL == fmt)
2407 goto fh_unlock_and_return;
2408
2409 fh->ovfmt = fmt;
2410 fh->fmt = fmt;
2411 btv->init.ovfmt = fmt;
2412 btv->init.fmt = fmt;
2413 btv->fbuf.base = fbuf->base;
2414 btv->fbuf.fmt.width = fbuf->width;
2415 btv->fbuf.fmt.height = fbuf->height;
2416 if (fbuf->bytesperline)
2417 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
2418 else
2419 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002420 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 return 0;
2422 }
2423
2424 case VIDIOCCAPTURE:
2425 case VIDIOC_OVERLAY:
2426 {
2427 struct bttv_buffer *new;
2428 int *on = arg;
2429
2430 if (*on) {
2431 /* verify args */
2432 if (NULL == btv->fbuf.base)
2433 return -EINVAL;
2434 if (!fh->ov.setup_ok) {
2435 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2436 return -EINVAL;
2437 }
2438 }
2439
2440 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2441 return -EBUSY;
2442
Ingo Molnar3593cab2006-02-07 06:49:14 -02002443 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 if (*on) {
2445 fh->ov.tvnorm = btv->tvnorm;
2446 new = videobuf_alloc(sizeof(*new));
2447 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2448 } else {
2449 new = NULL;
2450 }
2451
2452 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002453 retval = bttv_switch_overlay(btv,fh,new);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002454 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 return retval;
2456 }
2457
2458 case VIDIOCGMBUF:
2459 {
2460 struct video_mbuf *mbuf = arg;
2461 unsigned int i;
2462
Ingo Molnar3593cab2006-02-07 06:49:14 -02002463 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2465 V4L2_MEMORY_MMAP);
2466 if (retval < 0)
2467 goto fh_unlock_and_return;
2468 memset(mbuf,0,sizeof(*mbuf));
2469 mbuf->frames = gbuffers;
2470 mbuf->size = gbuffers * gbufsize;
2471 for (i = 0; i < gbuffers; i++)
2472 mbuf->offsets[i] = i * gbufsize;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002473 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 return 0;
2475 }
2476 case VIDIOCMCAPTURE:
2477 {
2478 struct video_mmap *vm = arg;
2479 struct bttv_buffer *buf;
2480 enum v4l2_field field;
2481
2482 if (vm->frame >= VIDEO_MAX_FRAME)
2483 return -EINVAL;
2484
Ingo Molnar3593cab2006-02-07 06:49:14 -02002485 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 retval = -EINVAL;
2487 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
2488 if (NULL == buf)
2489 goto fh_unlock_and_return;
2490 if (0 == buf->vb.baddr)
2491 goto fh_unlock_and_return;
2492 if (buf->vb.state == STATE_QUEUED ||
2493 buf->vb.state == STATE_ACTIVE)
2494 goto fh_unlock_and_return;
2495
2496 field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
2497 ? V4L2_FIELD_INTERLACED
2498 : V4L2_FIELD_BOTTOM;
2499 retval = bttv_prepare_buffer(btv,buf,
2500 format_by_palette(vm->format),
2501 vm->width,vm->height,field);
2502 if (0 != retval)
2503 goto fh_unlock_and_return;
2504 spin_lock_irqsave(&btv->s_lock,flags);
2505 buffer_queue(&fh->cap,&buf->vb);
2506 spin_unlock_irqrestore(&btv->s_lock,flags);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002507 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 return 0;
2509 }
2510 case VIDIOCSYNC:
2511 {
2512 int *frame = arg;
2513 struct bttv_buffer *buf;
2514
2515 if (*frame >= VIDEO_MAX_FRAME)
2516 return -EINVAL;
2517
Ingo Molnar3593cab2006-02-07 06:49:14 -02002518 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 retval = -EINVAL;
2520 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
2521 if (NULL == buf)
2522 goto fh_unlock_and_return;
2523 retval = videobuf_waiton(&buf->vb,0,1);
2524 if (0 != retval)
2525 goto fh_unlock_and_return;
2526 switch (buf->vb.state) {
2527 case STATE_ERROR:
2528 retval = -EIO;
2529 /* fall through */
2530 case STATE_DONE:
2531 videobuf_dma_pci_sync(btv->c.pci,&buf->vb.dma);
2532 bttv_dma_free(btv,buf);
2533 break;
2534 default:
2535 retval = -EINVAL;
2536 break;
2537 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002538 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 return retval;
2540 }
2541
2542 case VIDIOCGVBIFMT:
2543 {
2544 struct vbi_format *fmt = (void *) arg;
2545 struct v4l2_format fmt2;
2546
2547 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
2548 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2549 if (0 != retval)
2550 return retval;
2551 }
2552 bttv_vbi_get_fmt(fh, &fmt2);
2553
2554 memset(fmt,0,sizeof(*fmt));
2555 fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
2556 fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
2557 fmt->sample_format = VIDEO_PALETTE_RAW;
2558 fmt->start[0] = fmt2.fmt.vbi.start[0];
2559 fmt->count[0] = fmt2.fmt.vbi.count[0];
2560 fmt->start[1] = fmt2.fmt.vbi.start[1];
2561 fmt->count[1] = fmt2.fmt.vbi.count[1];
Michael H. Schimek67f15702006-01-09 15:25:27 -02002562 if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
2563 fmt->flags |= VBI_UNSYNC;
2564 if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
2565 fmt->flags |= VBI_INTERLACED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 return 0;
2567 }
2568 case VIDIOCSVBIFMT:
2569 {
2570 struct vbi_format *fmt = (void *) arg;
2571 struct v4l2_format fmt2;
2572
2573 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2574 if (0 != retval)
2575 return retval;
2576 bttv_vbi_get_fmt(fh, &fmt2);
2577
2578 if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
2579 fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
2580 fmt->sample_format != VIDEO_PALETTE_RAW ||
2581 fmt->start[0] != fmt2.fmt.vbi.start[0] ||
2582 fmt->start[1] != fmt2.fmt.vbi.start[1] ||
2583 fmt->count[0] != fmt->count[1] ||
2584 fmt->count[0] < 1 ||
2585 fmt->count[0] > 32 /* VBI_MAXLINES */)
2586 return -EINVAL;
2587
2588 bttv_vbi_setlines(fh,btv,fmt->count[0]);
2589 return 0;
2590 }
2591
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002592 case BTTV_VERSION:
2593 case VIDIOCGFREQ:
2594 case VIDIOCSFREQ:
2595 case VIDIOCGTUNER:
2596 case VIDIOCSTUNER:
2597 case VIDIOCGCHAN:
2598 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 case VIDIOCGAUDIO:
2600 case VIDIOCSAUDIO:
2601 return bttv_common_ioctls(btv,cmd,arg);
2602
2603 /* *** v4l2 *** ************************************************ */
2604 case VIDIOC_QUERYCAP:
2605 {
2606 struct v4l2_capability *cap = arg;
2607
2608 if (0 == v4l2)
2609 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002610 memset(cap, 0, sizeof (*cap));
2611 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
2612 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
2613 snprintf(cap->bus_info, sizeof (cap->bus_info),
2614 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 cap->version = BTTV_VERSION_CODE;
2616 cap->capabilities =
2617 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 V4L2_CAP_VBI_CAPTURE |
2619 V4L2_CAP_READWRITE |
2620 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002621 if (no_overlay <= 0)
2622 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2623
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2625 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2626 cap->capabilities |= V4L2_CAP_TUNER;
2627 return 0;
2628 }
2629
2630 case VIDIOC_ENUM_FMT:
2631 {
2632 struct v4l2_fmtdesc *f = arg;
2633 enum v4l2_buf_type type;
2634 unsigned int i;
2635 int index;
2636
2637 type = f->type;
2638 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2639 /* vbi */
2640 index = f->index;
2641 if (0 != index)
2642 return -EINVAL;
2643 memset(f,0,sizeof(*f));
2644 f->index = index;
2645 f->type = type;
2646 f->pixelformat = V4L2_PIX_FMT_GREY;
2647 strcpy(f->description,"vbi data");
2648 return 0;
2649 }
2650
2651 /* video capture + overlay */
2652 index = -1;
2653 for (i = 0; i < BTTV_FORMATS; i++) {
2654 if (bttv_formats[i].fourcc != -1)
2655 index++;
2656 if ((unsigned int)index == f->index)
2657 break;
2658 }
2659 if (BTTV_FORMATS == i)
2660 return -EINVAL;
2661
2662 switch (f->type) {
2663 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2664 break;
2665 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2666 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2667 return -EINVAL;
2668 break;
2669 default:
2670 return -EINVAL;
2671 }
2672 memset(f,0,sizeof(*f));
2673 f->index = index;
2674 f->type = type;
2675 f->pixelformat = bttv_formats[i].fourcc;
2676 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2677 return 0;
2678 }
2679
2680 case VIDIOC_TRY_FMT:
2681 {
2682 struct v4l2_format *f = arg;
2683 return bttv_try_fmt(fh,btv,f);
2684 }
2685 case VIDIOC_G_FMT:
2686 {
2687 struct v4l2_format *f = arg;
2688 return bttv_g_fmt(fh,f);
2689 }
2690 case VIDIOC_S_FMT:
2691 {
2692 struct v4l2_format *f = arg;
2693 return bttv_s_fmt(fh,btv,f);
2694 }
2695
2696 case VIDIOC_G_FBUF:
2697 {
2698 struct v4l2_framebuffer *fb = arg;
2699
2700 *fb = btv->fbuf;
2701 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2702 if (fh->ovfmt)
2703 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2704 return 0;
2705 }
2706 case VIDIOC_S_FBUF:
2707 {
2708 struct v4l2_framebuffer *fb = arg;
2709 const struct bttv_format *fmt;
2710
2711 if(!capable(CAP_SYS_ADMIN) &&
2712 !capable(CAP_SYS_RAWIO))
2713 return -EPERM;
2714
2715 /* check args */
2716 fmt = format_by_fourcc(fb->fmt.pixelformat);
2717 if (NULL == fmt)
2718 return -EINVAL;
2719 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2720 return -EINVAL;
2721
Ingo Molnar3593cab2006-02-07 06:49:14 -02002722 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 retval = -EINVAL;
2724 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2725 if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
2726 goto fh_unlock_and_return;
2727 if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
2728 goto fh_unlock_and_return;
2729 }
2730
2731 /* ok, accept it */
2732 btv->fbuf.base = fb->base;
2733 btv->fbuf.fmt.width = fb->fmt.width;
2734 btv->fbuf.fmt.height = fb->fmt.height;
2735 if (0 != fb->fmt.bytesperline)
2736 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2737 else
2738 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2739
2740 retval = 0;
2741 fh->ovfmt = fmt;
2742 btv->init.ovfmt = fmt;
2743 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2744 fh->ov.w.left = 0;
2745 fh->ov.w.top = 0;
2746 fh->ov.w.width = fb->fmt.width;
2747 fh->ov.w.height = fb->fmt.height;
2748 btv->init.ov.w.width = fb->fmt.width;
2749 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002750 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 fh->ov.clips = NULL;
2752 fh->ov.nclips = 0;
2753
2754 if (check_btres(fh, RESOURCE_OVERLAY)) {
2755 struct bttv_buffer *new;
2756
2757 new = videobuf_alloc(sizeof(*new));
2758 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2759 retval = bttv_switch_overlay(btv,fh,new);
2760 }
2761 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002762 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 return retval;
2764 }
2765
2766 case VIDIOC_REQBUFS:
2767 return videobuf_reqbufs(bttv_queue(fh),arg);
2768
2769 case VIDIOC_QUERYBUF:
2770 return videobuf_querybuf(bttv_queue(fh),arg);
2771
2772 case VIDIOC_QBUF:
2773 return videobuf_qbuf(bttv_queue(fh),arg);
2774
2775 case VIDIOC_DQBUF:
2776 return videobuf_dqbuf(bttv_queue(fh),arg,
2777 file->f_flags & O_NONBLOCK);
2778
2779 case VIDIOC_STREAMON:
2780 {
2781 int res = bttv_resource(fh);
2782
2783 if (!check_alloc_btres(btv,fh,res))
2784 return -EBUSY;
2785 return videobuf_streamon(bttv_queue(fh));
2786 }
2787 case VIDIOC_STREAMOFF:
2788 {
2789 int res = bttv_resource(fh);
2790
2791 retval = videobuf_streamoff(bttv_queue(fh));
2792 if (retval < 0)
2793 return retval;
2794 free_btres(btv,fh,res);
2795 return 0;
2796 }
2797
2798 case VIDIOC_QUERYCTRL:
2799 {
2800 struct v4l2_queryctrl *c = arg;
2801 int i;
2802
2803 if ((c->id < V4L2_CID_BASE ||
2804 c->id >= V4L2_CID_LASTP1) &&
2805 (c->id < V4L2_CID_PRIVATE_BASE ||
2806 c->id >= V4L2_CID_PRIVATE_LASTP1))
2807 return -EINVAL;
2808 for (i = 0; i < BTTV_CTLS; i++)
2809 if (bttv_ctls[i].id == c->id)
2810 break;
2811 if (i == BTTV_CTLS) {
2812 *c = no_ctl;
2813 return 0;
2814 }
2815 *c = bttv_ctls[i];
2816 if (i >= 4 && i <= 8) {
2817 struct video_audio va;
2818 memset(&va,0,sizeof(va));
2819 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
2820 if (btv->audio_hook)
2821 btv->audio_hook(btv,&va,0);
2822 switch (bttv_ctls[i].id) {
2823 case V4L2_CID_AUDIO_VOLUME:
2824 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2825 *c = no_ctl;
2826 break;
2827 case V4L2_CID_AUDIO_BALANCE:
2828 if (!(va.flags & VIDEO_AUDIO_BALANCE))
2829 *c = no_ctl;
2830 break;
2831 case V4L2_CID_AUDIO_BASS:
2832 if (!(va.flags & VIDEO_AUDIO_BASS))
2833 *c = no_ctl;
2834 break;
2835 case V4L2_CID_AUDIO_TREBLE:
2836 if (!(va.flags & VIDEO_AUDIO_TREBLE))
2837 *c = no_ctl;
2838 break;
2839 }
2840 }
2841 return 0;
2842 }
2843 case VIDIOC_G_CTRL:
2844 return get_control(btv,arg);
2845 case VIDIOC_S_CTRL:
2846 return set_control(btv,arg);
2847 case VIDIOC_G_PARM:
2848 {
2849 struct v4l2_streamparm *parm = arg;
2850 struct v4l2_standard s;
2851 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2852 return -EINVAL;
2853 memset(parm,0,sizeof(*parm));
2854 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2855 bttv_tvnorms[btv->tvnorm].name);
2856 parm->parm.capture.timeperframe = s.frameperiod;
2857 return 0;
2858 }
2859
2860 case VIDIOC_G_PRIORITY:
2861 {
2862 enum v4l2_priority *p = arg;
2863
2864 *p = v4l2_prio_max(&btv->prio);
2865 return 0;
2866 }
2867 case VIDIOC_S_PRIORITY:
2868 {
2869 enum v4l2_priority *prio = arg;
2870
2871 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
2872 }
2873
2874 case VIDIOC_ENUMSTD:
2875 case VIDIOC_G_STD:
2876 case VIDIOC_S_STD:
2877 case VIDIOC_ENUMINPUT:
2878 case VIDIOC_G_INPUT:
2879 case VIDIOC_S_INPUT:
2880 case VIDIOC_G_TUNER:
2881 case VIDIOC_S_TUNER:
2882 case VIDIOC_G_FREQUENCY:
2883 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08002884 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 return bttv_common_ioctls(btv,cmd,arg);
2886
2887 default:
2888 return -ENOIOCTLCMD;
2889 }
2890 return 0;
2891
2892 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02002893 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 return retval;
2895}
2896
2897static int bttv_ioctl(struct inode *inode, struct file *file,
2898 unsigned int cmd, unsigned long arg)
2899{
2900 struct bttv_fh *fh = file->private_data;
2901
2902 switch (cmd) {
2903 case BTTV_VBISIZE:
2904 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2905 return fh->lines * 2 * 2048;
2906 default:
2907 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
2908 }
2909}
2910
2911static ssize_t bttv_read(struct file *file, char __user *data,
2912 size_t count, loff_t *ppos)
2913{
2914 struct bttv_fh *fh = file->private_data;
2915 int retval = 0;
2916
2917 if (fh->btv->errors)
2918 bttv_reinit_bt848(fh->btv);
2919 dprintk("bttv%d: read count=%d type=%s\n",
2920 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
2921
2922 switch (fh->type) {
2923 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2924 if (locked_btres(fh->btv,RESOURCE_VIDEO))
2925 return -EBUSY;
2926 retval = videobuf_read_one(&fh->cap, data, count, ppos,
2927 file->f_flags & O_NONBLOCK);
2928 break;
2929 case V4L2_BUF_TYPE_VBI_CAPTURE:
2930 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2931 return -EBUSY;
2932 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
2933 file->f_flags & O_NONBLOCK);
2934 break;
2935 default:
2936 BUG();
2937 }
2938 return retval;
2939}
2940
2941static unsigned int bttv_poll(struct file *file, poll_table *wait)
2942{
2943 struct bttv_fh *fh = file->private_data;
2944 struct bttv_buffer *buf;
2945 enum v4l2_field field;
2946
2947 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2948 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2949 return POLLERR;
2950 return videobuf_poll_stream(file, &fh->vbi, wait);
2951 }
2952
2953 if (check_btres(fh,RESOURCE_VIDEO)) {
2954 /* streaming capture */
2955 if (list_empty(&fh->cap.stream))
2956 return POLLERR;
2957 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
2958 } else {
2959 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002960 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 if (NULL == fh->cap.read_buf) {
2962 /* need to capture a new frame */
2963 if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02002964 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 return POLLERR;
2966 }
2967 fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
2968 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02002969 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 return POLLERR;
2971 }
2972 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
2973 field = videobuf_next_field(&fh->cap);
2974 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08002975 kfree (fh->cap.read_buf);
2976 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002977 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 return POLLERR;
2979 }
2980 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
2981 fh->cap.read_off = 0;
2982 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002983 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 buf = (struct bttv_buffer*)fh->cap.read_buf;
2985 }
2986
2987 poll_wait(file, &buf->vb.done, wait);
2988 if (buf->vb.state == STATE_DONE ||
2989 buf->vb.state == STATE_ERROR)
2990 return POLLIN|POLLRDNORM;
2991 return 0;
2992}
2993
2994static int bttv_open(struct inode *inode, struct file *file)
2995{
2996 int minor = iminor(inode);
2997 struct bttv *btv = NULL;
2998 struct bttv_fh *fh;
2999 enum v4l2_buf_type type = 0;
3000 unsigned int i;
3001
3002 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3003
3004 for (i = 0; i < bttv_num; i++) {
3005 if (bttvs[i].video_dev &&
3006 bttvs[i].video_dev->minor == minor) {
3007 btv = &bttvs[i];
3008 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3009 break;
3010 }
3011 if (bttvs[i].vbi_dev &&
3012 bttvs[i].vbi_dev->minor == minor) {
3013 btv = &bttvs[i];
3014 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3015 break;
3016 }
3017 }
3018 if (NULL == btv)
3019 return -ENODEV;
3020
3021 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3022 btv->c.nr,v4l2_type_names[type]);
3023
3024 /* allocate per filehandle data */
3025 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3026 if (NULL == fh)
3027 return -ENOMEM;
3028 file->private_data = fh;
3029 *fh = btv->init;
3030 fh->type = type;
3031 fh->ov.setup_ok = 0;
3032 v4l2_prio_open(&btv->prio,&fh->prio);
3033
3034 videobuf_queue_init(&fh->cap, &bttv_video_qops,
3035 btv->c.pci, &btv->s_lock,
3036 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3037 V4L2_FIELD_INTERLACED,
3038 sizeof(struct bttv_buffer),
3039 fh);
3040 videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
3041 btv->c.pci, &btv->s_lock,
3042 V4L2_BUF_TYPE_VBI_CAPTURE,
3043 V4L2_FIELD_SEQ_TB,
3044 sizeof(struct bttv_buffer),
3045 fh);
3046 i2c_vidiocschan(btv);
3047
3048 btv->users++;
3049 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
3050 bttv_vbi_setlines(fh,btv,16);
3051 bttv_field_count(btv);
3052 return 0;
3053}
3054
3055static int bttv_release(struct inode *inode, struct file *file)
3056{
3057 struct bttv_fh *fh = file->private_data;
3058 struct bttv *btv = fh->btv;
3059
3060 /* turn off overlay */
3061 if (check_btres(fh, RESOURCE_OVERLAY))
3062 bttv_switch_overlay(btv,fh,NULL);
3063
3064 /* stop video capture */
3065 if (check_btres(fh, RESOURCE_VIDEO)) {
3066 videobuf_streamoff(&fh->cap);
3067 free_btres(btv,fh,RESOURCE_VIDEO);
3068 }
3069 if (fh->cap.read_buf) {
3070 buffer_release(&fh->cap,fh->cap.read_buf);
3071 kfree(fh->cap.read_buf);
3072 }
3073
3074 /* stop vbi capture */
3075 if (check_btres(fh, RESOURCE_VBI)) {
3076 if (fh->vbi.streaming)
3077 videobuf_streamoff(&fh->vbi);
3078 if (fh->vbi.reading)
3079 videobuf_read_stop(&fh->vbi);
3080 free_btres(btv,fh,RESOURCE_VBI);
3081 }
3082
3083 /* free stuff */
3084 videobuf_mmap_free(&fh->cap);
3085 videobuf_mmap_free(&fh->vbi);
3086 v4l2_prio_close(&btv->prio,&fh->prio);
3087 file->private_data = NULL;
3088 kfree(fh);
3089
3090 btv->users--;
3091 bttv_field_count(btv);
3092 return 0;
3093}
3094
3095static int
3096bttv_mmap(struct file *file, struct vm_area_struct *vma)
3097{
3098 struct bttv_fh *fh = file->private_data;
3099
3100 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3101 fh->btv->c.nr, v4l2_type_names[fh->type],
3102 vma->vm_start, vma->vm_end - vma->vm_start);
3103 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3104}
3105
3106static struct file_operations bttv_fops =
3107{
3108 .owner = THIS_MODULE,
3109 .open = bttv_open,
3110 .release = bttv_release,
3111 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003112 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 .llseek = no_llseek,
3114 .read = bttv_read,
3115 .mmap = bttv_mmap,
3116 .poll = bttv_poll,
3117};
3118
3119static struct video_device bttv_video_template =
3120{
3121 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003122 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003123 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 .hardware = VID_HARDWARE_BT848,
3125 .fops = &bttv_fops,
3126 .minor = -1,
3127};
3128
3129static struct video_device bttv_vbi_template =
3130{
3131 .name = "bt848/878 vbi",
3132 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
3133 .hardware = VID_HARDWARE_BT848,
3134 .fops = &bttv_fops,
3135 .minor = -1,
3136};
3137
3138/* ----------------------------------------------------------------------- */
3139/* radio interface */
3140
3141static int radio_open(struct inode *inode, struct file *file)
3142{
3143 int minor = iminor(inode);
3144 struct bttv *btv = NULL;
3145 unsigned int i;
3146
3147 dprintk("bttv: open minor=%d\n",minor);
3148
3149 for (i = 0; i < bttv_num; i++) {
3150 if (bttvs[i].radio_dev->minor == minor) {
3151 btv = &bttvs[i];
3152 break;
3153 }
3154 }
3155 if (NULL == btv)
3156 return -ENODEV;
3157
3158 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003159 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003160
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003162
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 file->private_data = btv;
3164
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003165 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 audio_mux(btv,AUDIO_RADIO);
3167
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003168 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003169 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170}
3171
3172static int radio_release(struct inode *inode, struct file *file)
3173{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003174 struct bttv *btv = file->private_data;
3175 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
3177 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003178
3179 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3180
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 return 0;
3182}
3183
3184static int radio_do_ioctl(struct inode *inode, struct file *file,
3185 unsigned int cmd, void *arg)
3186{
3187 struct bttv *btv = file->private_data;
3188
3189 switch (cmd) {
3190 case VIDIOCGCAP:
3191 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003192 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
3194 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003195 strcpy(cap->name,btv->radio_dev->name);
3196 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 cap->channels = 1;
3198 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003199 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 }
3201
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003202 case VIDIOCGTUNER:
3203 {
3204 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003206 if(v->tuner)
3207 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003209 strcpy(v->name, "Radio");
3210 bttv_call_i2c_clients(btv,cmd,v);
3211 return 0;
3212 }
3213 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 /* nothing to do */
3215 return 0;
3216
3217 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003218 case VIDIOCGFREQ:
3219 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 case VIDIOCGAUDIO:
3221 case VIDIOCSAUDIO:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003222 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 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 */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003923 mutex_init(&btv->lock);
3924 mutex_init(&btv->reslock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003925 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 */