blob: f9d581cd31dbc02c58cb8754719d2db9cebf210e [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 Chehabfa9846a2005-07-12 13:58:42 -070037#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39#include <asm/io.h>
40#include <asm/byteorder.h>
41
42#include "bttvp.h"
43
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070044#include "rds.h"
45
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047unsigned int bttv_num; /* number of Bt848s in use */
48struct bttv bttvs[BTTV_MAX];
49
50unsigned int bttv_debug = 0;
51unsigned int bttv_verbose = 1;
52unsigned int bttv_gpio = 0;
53
54/* config variables */
55#ifdef __BIG_ENDIAN
56static unsigned int bigendian=1;
57#else
58static unsigned int bigendian=0;
59#endif
60static unsigned int radio[BTTV_MAX];
61static unsigned int irq_debug = 0;
62static unsigned int gbuffers = 8;
63static unsigned int gbufsize = 0x208000;
64
65static int video_nr = -1;
66static int radio_nr = -1;
67static int vbi_nr = -1;
68static int debug_latency = 0;
69
70static unsigned int fdsr = 0;
71
72/* options */
73static unsigned int combfilter = 0;
74static unsigned int lumafilter = 0;
75static unsigned int automute = 1;
76static unsigned int chroma_agc = 0;
77static unsigned int adc_crush = 1;
78static unsigned int whitecrush_upper = 0xCF;
79static unsigned int whitecrush_lower = 0x7F;
80static unsigned int vcr_hack = 0;
81static unsigned int irq_iswitch = 0;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070082static unsigned int uv_ratio = 50;
83static unsigned int full_luma_range = 0;
84static unsigned int coring = 0;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070085extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
87/* API features (turn on/off stuff for testing) */
88static unsigned int v4l2 = 1;
89
90
91/* 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,
213 },{
214 .v4l2_id = V4L2_STD_NTSC_M,
215 .name = "NTSC",
216 .Fsc = 28636363,
217 .swidth = 768,
218 .sheight = 480,
219 .totalwidth = 910,
220 .adelay = 0x68,
221 .bdelay = 0x5d,
222 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
223 .scaledtwidth = 910,
224 .hdelayx1 = 128,
225 .hactivex1 = 910,
226 .vdelay = 0x1a,
227 .vbipack = 144,
228 .sram = 1,
229 },{
230 .v4l2_id = V4L2_STD_SECAM,
231 .name = "SECAM",
232 .Fsc = 35468950,
233 .swidth = 924,
234 .sheight = 576,
235 .totalwidth = 1135,
236 .adelay = 0x7f,
237 .bdelay = 0xb0,
238 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
239 .scaledtwidth = 1135,
240 .hdelayx1 = 186,
241 .hactivex1 = 922,
242 .vdelay = 0x20,
243 .vbipack = 255,
244 .sram = 0, /* like PAL, correct? */
245 },{
246 .v4l2_id = V4L2_STD_PAL_Nc,
247 .name = "PAL-Nc",
248 .Fsc = 28636363,
249 .swidth = 640,
250 .sheight = 576,
251 .totalwidth = 910,
252 .adelay = 0x68,
253 .bdelay = 0x5d,
254 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
255 .scaledtwidth = 780,
256 .hdelayx1 = 130,
257 .hactivex1 = 734,
258 .vdelay = 0x1a,
259 .vbipack = 144,
260 .sram = -1,
261 },{
262 .v4l2_id = V4L2_STD_PAL_M,
263 .name = "PAL-M",
264 .Fsc = 28636363,
265 .swidth = 640,
266 .sheight = 480,
267 .totalwidth = 910,
268 .adelay = 0x68,
269 .bdelay = 0x5d,
270 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
271 .scaledtwidth = 780,
272 .hdelayx1 = 135,
273 .hactivex1 = 754,
274 .vdelay = 0x1a,
275 .vbipack = 144,
276 .sram = -1,
277 },{
278 .v4l2_id = V4L2_STD_PAL_N,
279 .name = "PAL-N",
280 .Fsc = 35468950,
281 .swidth = 768,
282 .sheight = 576,
283 .totalwidth = 1135,
284 .adelay = 0x7f,
285 .bdelay = 0x72,
286 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
287 .scaledtwidth = 944,
288 .hdelayx1 = 186,
289 .hactivex1 = 922,
290 .vdelay = 0x20,
291 .vbipack = 144,
292 .sram = -1,
293 },{
294 .v4l2_id = V4L2_STD_NTSC_M_JP,
295 .name = "NTSC-JP",
296 .Fsc = 28636363,
297 .swidth = 640,
298 .sheight = 480,
299 .totalwidth = 910,
300 .adelay = 0x68,
301 .bdelay = 0x5d,
302 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
303 .scaledtwidth = 780,
304 .hdelayx1 = 135,
305 .hactivex1 = 754,
306 .vdelay = 0x16,
307 .vbipack = 144,
308 .sram = -1,
309 },{
310 /* that one hopefully works with the strange timing
311 * which video recorders produce when playing a NTSC
312 * tape on a PAL TV ... */
313 .v4l2_id = V4L2_STD_PAL_60,
314 .name = "PAL-60",
315 .Fsc = 35468950,
316 .swidth = 924,
317 .sheight = 480,
318 .totalwidth = 1135,
319 .adelay = 0x7f,
320 .bdelay = 0x72,
321 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
322 .scaledtwidth = 1135,
323 .hdelayx1 = 186,
324 .hactivex1 = 924,
325 .vdelay = 0x1a,
326 .vbipack = 255,
327 .vtotal = 524,
328 .sram = -1,
329 }
330};
331static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
332
333/* ----------------------------------------------------------------------- */
334/* bttv format list
335 packed pixel formats must come first */
336static const struct bttv_format bttv_formats[] = {
337 {
338 .name = "8 bpp, gray",
339 .palette = VIDEO_PALETTE_GREY,
340 .fourcc = V4L2_PIX_FMT_GREY,
341 .btformat = BT848_COLOR_FMT_Y8,
342 .depth = 8,
343 .flags = FORMAT_FLAGS_PACKED,
344 },{
345 .name = "8 bpp, dithered color",
346 .palette = VIDEO_PALETTE_HI240,
347 .fourcc = V4L2_PIX_FMT_HI240,
348 .btformat = BT848_COLOR_FMT_RGB8,
349 .depth = 8,
350 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
351 },{
352 .name = "15 bpp RGB, le",
353 .palette = VIDEO_PALETTE_RGB555,
354 .fourcc = V4L2_PIX_FMT_RGB555,
355 .btformat = BT848_COLOR_FMT_RGB15,
356 .depth = 16,
357 .flags = FORMAT_FLAGS_PACKED,
358 },{
359 .name = "15 bpp RGB, be",
360 .palette = -1,
361 .fourcc = V4L2_PIX_FMT_RGB555X,
362 .btformat = BT848_COLOR_FMT_RGB15,
363 .btswap = 0x03, /* byteswap */
364 .depth = 16,
365 .flags = FORMAT_FLAGS_PACKED,
366 },{
367 .name = "16 bpp RGB, le",
368 .palette = VIDEO_PALETTE_RGB565,
369 .fourcc = V4L2_PIX_FMT_RGB565,
370 .btformat = BT848_COLOR_FMT_RGB16,
371 .depth = 16,
372 .flags = FORMAT_FLAGS_PACKED,
373 },{
374 .name = "16 bpp RGB, be",
375 .palette = -1,
376 .fourcc = V4L2_PIX_FMT_RGB565X,
377 .btformat = BT848_COLOR_FMT_RGB16,
378 .btswap = 0x03, /* byteswap */
379 .depth = 16,
380 .flags = FORMAT_FLAGS_PACKED,
381 },{
382 .name = "24 bpp RGB, le",
383 .palette = VIDEO_PALETTE_RGB24,
384 .fourcc = V4L2_PIX_FMT_BGR24,
385 .btformat = BT848_COLOR_FMT_RGB24,
386 .depth = 24,
387 .flags = FORMAT_FLAGS_PACKED,
388 },{
389 .name = "32 bpp RGB, le",
390 .palette = VIDEO_PALETTE_RGB32,
391 .fourcc = V4L2_PIX_FMT_BGR32,
392 .btformat = BT848_COLOR_FMT_RGB32,
393 .depth = 32,
394 .flags = FORMAT_FLAGS_PACKED,
395 },{
396 .name = "32 bpp RGB, be",
397 .palette = -1,
398 .fourcc = V4L2_PIX_FMT_RGB32,
399 .btformat = BT848_COLOR_FMT_RGB32,
400 .btswap = 0x0f, /* byte+word swap */
401 .depth = 32,
402 .flags = FORMAT_FLAGS_PACKED,
403 },{
404 .name = "4:2:2, packed, YUYV",
405 .palette = VIDEO_PALETTE_YUV422,
406 .fourcc = V4L2_PIX_FMT_YUYV,
407 .btformat = BT848_COLOR_FMT_YUY2,
408 .depth = 16,
409 .flags = FORMAT_FLAGS_PACKED,
410 },{
411 .name = "4:2:2, packed, YUYV",
412 .palette = VIDEO_PALETTE_YUYV,
413 .fourcc = V4L2_PIX_FMT_YUYV,
414 .btformat = BT848_COLOR_FMT_YUY2,
415 .depth = 16,
416 .flags = FORMAT_FLAGS_PACKED,
417 },{
418 .name = "4:2:2, packed, UYVY",
419 .palette = VIDEO_PALETTE_UYVY,
420 .fourcc = V4L2_PIX_FMT_UYVY,
421 .btformat = BT848_COLOR_FMT_YUY2,
422 .btswap = 0x03, /* byteswap */
423 .depth = 16,
424 .flags = FORMAT_FLAGS_PACKED,
425 },{
426 .name = "4:2:2, planar, Y-Cb-Cr",
427 .palette = VIDEO_PALETTE_YUV422P,
428 .fourcc = V4L2_PIX_FMT_YUV422P,
429 .btformat = BT848_COLOR_FMT_YCrCb422,
430 .depth = 16,
431 .flags = FORMAT_FLAGS_PLANAR,
432 .hshift = 1,
433 .vshift = 0,
434 },{
435 .name = "4:2:0, planar, Y-Cb-Cr",
436 .palette = VIDEO_PALETTE_YUV420P,
437 .fourcc = V4L2_PIX_FMT_YUV420,
438 .btformat = BT848_COLOR_FMT_YCrCb422,
439 .depth = 12,
440 .flags = FORMAT_FLAGS_PLANAR,
441 .hshift = 1,
442 .vshift = 1,
443 },{
444 .name = "4:2:0, planar, Y-Cr-Cb",
445 .palette = -1,
446 .fourcc = V4L2_PIX_FMT_YVU420,
447 .btformat = BT848_COLOR_FMT_YCrCb422,
448 .depth = 12,
449 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
450 .hshift = 1,
451 .vshift = 1,
452 },{
453 .name = "4:1:1, planar, Y-Cb-Cr",
454 .palette = VIDEO_PALETTE_YUV411P,
455 .fourcc = V4L2_PIX_FMT_YUV411P,
456 .btformat = BT848_COLOR_FMT_YCrCb411,
457 .depth = 12,
458 .flags = FORMAT_FLAGS_PLANAR,
459 .hshift = 2,
460 .vshift = 0,
461 },{
462 .name = "4:1:0, planar, Y-Cb-Cr",
463 .palette = VIDEO_PALETTE_YUV410P,
464 .fourcc = V4L2_PIX_FMT_YUV410,
465 .btformat = BT848_COLOR_FMT_YCrCb411,
466 .depth = 9,
467 .flags = FORMAT_FLAGS_PLANAR,
468 .hshift = 2,
469 .vshift = 2,
470 },{
471 .name = "4:1:0, planar, Y-Cr-Cb",
472 .palette = -1,
473 .fourcc = V4L2_PIX_FMT_YVU410,
474 .btformat = BT848_COLOR_FMT_YCrCb411,
475 .depth = 9,
476 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
477 .hshift = 2,
478 .vshift = 2,
479 },{
480 .name = "raw scanlines",
481 .palette = VIDEO_PALETTE_RAW,
482 .fourcc = -1,
483 .btformat = BT848_COLOR_FMT_RAW,
484 .depth = 8,
485 .flags = FORMAT_FLAGS_RAW,
486 }
487};
488static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
489
490/* ----------------------------------------------------------------------- */
491
492#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
493#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
494#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
495#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
496#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
497#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
498#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
499#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700500#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
501#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
502#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
503#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505static const struct v4l2_queryctrl no_ctl = {
506 .name = "42",
507 .flags = V4L2_CTRL_FLAG_DISABLED,
508};
509static const struct v4l2_queryctrl bttv_ctls[] = {
510 /* --- video --- */
511 {
512 .id = V4L2_CID_BRIGHTNESS,
513 .name = "Brightness",
514 .minimum = 0,
515 .maximum = 65535,
516 .step = 256,
517 .default_value = 32768,
518 .type = V4L2_CTRL_TYPE_INTEGER,
519 },{
520 .id = V4L2_CID_CONTRAST,
521 .name = "Contrast",
522 .minimum = 0,
523 .maximum = 65535,
524 .step = 128,
525 .default_value = 32768,
526 .type = V4L2_CTRL_TYPE_INTEGER,
527 },{
528 .id = V4L2_CID_SATURATION,
529 .name = "Saturation",
530 .minimum = 0,
531 .maximum = 65535,
532 .step = 128,
533 .default_value = 32768,
534 .type = V4L2_CTRL_TYPE_INTEGER,
535 },{
536 .id = V4L2_CID_HUE,
537 .name = "Hue",
538 .minimum = 0,
539 .maximum = 65535,
540 .step = 256,
541 .default_value = 32768,
542 .type = V4L2_CTRL_TYPE_INTEGER,
543 },
544 /* --- audio --- */
545 {
546 .id = V4L2_CID_AUDIO_MUTE,
547 .name = "Mute",
548 .minimum = 0,
549 .maximum = 1,
550 .type = V4L2_CTRL_TYPE_BOOLEAN,
551 },{
552 .id = V4L2_CID_AUDIO_VOLUME,
553 .name = "Volume",
554 .minimum = 0,
555 .maximum = 65535,
556 .step = 65535/100,
557 .default_value = 65535,
558 .type = V4L2_CTRL_TYPE_INTEGER,
559 },{
560 .id = V4L2_CID_AUDIO_BALANCE,
561 .name = "Balance",
562 .minimum = 0,
563 .maximum = 65535,
564 .step = 65535/100,
565 .default_value = 32768,
566 .type = V4L2_CTRL_TYPE_INTEGER,
567 },{
568 .id = V4L2_CID_AUDIO_BASS,
569 .name = "Bass",
570 .minimum = 0,
571 .maximum = 65535,
572 .step = 65535/100,
573 .default_value = 32768,
574 .type = V4L2_CTRL_TYPE_INTEGER,
575 },{
576 .id = V4L2_CID_AUDIO_TREBLE,
577 .name = "Treble",
578 .minimum = 0,
579 .maximum = 65535,
580 .step = 65535/100,
581 .default_value = 32768,
582 .type = V4L2_CTRL_TYPE_INTEGER,
583 },
584 /* --- private --- */
585 {
586 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
587 .name = "chroma agc",
588 .minimum = 0,
589 .maximum = 1,
590 .type = V4L2_CTRL_TYPE_BOOLEAN,
591 },{
592 .id = V4L2_CID_PRIVATE_COMBFILTER,
593 .name = "combfilter",
594 .minimum = 0,
595 .maximum = 1,
596 .type = V4L2_CTRL_TYPE_BOOLEAN,
597 },{
598 .id = V4L2_CID_PRIVATE_AUTOMUTE,
599 .name = "automute",
600 .minimum = 0,
601 .maximum = 1,
602 .type = V4L2_CTRL_TYPE_BOOLEAN,
603 },{
604 .id = V4L2_CID_PRIVATE_LUMAFILTER,
605 .name = "luma decimation filter",
606 .minimum = 0,
607 .maximum = 1,
608 .type = V4L2_CTRL_TYPE_BOOLEAN,
609 },{
610 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
611 .name = "agc crush",
612 .minimum = 0,
613 .maximum = 1,
614 .type = V4L2_CTRL_TYPE_BOOLEAN,
615 },{
616 .id = V4L2_CID_PRIVATE_VCR_HACK,
617 .name = "vcr hack",
618 .minimum = 0,
619 .maximum = 1,
620 .type = V4L2_CTRL_TYPE_BOOLEAN,
621 },{
622 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
623 .name = "whitecrush upper",
624 .minimum = 0,
625 .maximum = 255,
626 .step = 1,
627 .default_value = 0xCF,
628 .type = V4L2_CTRL_TYPE_INTEGER,
629 },{
630 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
631 .name = "whitecrush lower",
632 .minimum = 0,
633 .maximum = 255,
634 .step = 1,
635 .default_value = 0x7F,
636 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700637 },{
638 .id = V4L2_CID_PRIVATE_UV_RATIO,
639 .name = "uv ratio",
640 .minimum = 0,
641 .maximum = 100,
642 .step = 1,
643 .default_value = 50,
644 .type = V4L2_CTRL_TYPE_INTEGER,
645 },{
646 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
647 .name = "full luma range",
648 .minimum = 0,
649 .maximum = 1,
650 .type = V4L2_CTRL_TYPE_BOOLEAN,
651 },{
652 .id = V4L2_CID_PRIVATE_CORING,
653 .name = "coring",
654 .minimum = 0,
655 .maximum = 3,
656 .step = 1,
657 .default_value = 0,
658 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 }
660
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700661
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663};
664static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
665
666/* ----------------------------------------------------------------------- */
667/* resource management */
668
669static
670int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
671{
672 if (fh->resources & bit)
673 /* have it already allocated */
674 return 1;
675
676 /* is it free? */
677 down(&btv->reslock);
678 if (btv->resources & bit) {
679 /* no, someone else uses it */
680 up(&btv->reslock);
681 return 0;
682 }
683 /* it's free, grab it */
684 fh->resources |= bit;
685 btv->resources |= bit;
686 up(&btv->reslock);
687 return 1;
688}
689
690static
691int check_btres(struct bttv_fh *fh, int bit)
692{
693 return (fh->resources & bit);
694}
695
696static
697int locked_btres(struct bttv *btv, int bit)
698{
699 return (btv->resources & bit);
700}
701
702static
703void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
704{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 if ((fh->resources & bits) != bits) {
706 /* trying to free ressources not allocated by us ... */
707 printk("bttv: BUG! (btres)\n");
708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 down(&btv->reslock);
710 fh->resources &= ~bits;
711 btv->resources &= ~bits;
712 up(&btv->reslock);
713}
714
715/* ----------------------------------------------------------------------- */
716/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
717
718/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
719 PLL_X = Reference pre-divider (0=1, 1=2)
720 PLL_C = Post divider (0=6, 1=4)
721 PLL_I = Integer input
722 PLL_F = Fractional input
723
724 F_input = 28.636363 MHz:
725 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
726*/
727
728static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
729{
730 unsigned char fl, fh, fi;
731
732 /* prevent overflows */
733 fin/=4;
734 fout/=4;
735
736 fout*=12;
737 fi=fout/fin;
738
739 fout=(fout%fin)*256;
740 fh=fout/fin;
741
742 fout=(fout%fin)*256;
743 fl=fout/fin;
744
745 btwrite(fl, BT848_PLL_F_LO);
746 btwrite(fh, BT848_PLL_F_HI);
747 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
748}
749
750static void set_pll(struct bttv *btv)
751{
752 int i;
753
754 if (!btv->pll.pll_crystal)
755 return;
756
757 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
758 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
759 return;
760 }
761
762 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
763 /* no PLL needed */
764 if (btv->pll.pll_current == 0)
765 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700766 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
767 btv->c.nr,btv->pll.pll_ifreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 btwrite(0x00,BT848_TGCTRL);
769 btwrite(0x00,BT848_PLL_XCI);
770 btv->pll.pll_current = 0;
771 return;
772 }
773
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700774 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
775 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
777
778 for (i=0; i<10; i++) {
779 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700780 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 msleep(10);
782
783 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
784 btwrite(0,BT848_DSTATUS);
785 } else {
786 btwrite(0x08,BT848_TGCTRL);
787 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700788 bttv_printk(" ok\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return;
790 }
791 }
792 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700793 bttv_printk("failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return;
795}
796
797/* used to switch between the bt848's analog/digital video capture modes */
798static void bt848A_set_timing(struct bttv *btv)
799{
800 int i, len;
801 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
802 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
803
804 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
805 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
806 btv->c.nr,table_idx);
807
808 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800809 btwrite(0x00, BT848_TGCTRL);
810 btwrite(0x02, BT848_TGCTRL);
811 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 len=SRAM_Table[table_idx][0];
814 for(i = 1; i <= len; i++)
815 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
816 btv->pll.pll_ofreq = 27000000;
817
818 set_pll(btv);
819 btwrite(0x11, BT848_TGCTRL);
820 btwrite(0x41, BT848_DVSIF);
821 } else {
822 btv->pll.pll_ofreq = fsc;
823 set_pll(btv);
824 btwrite(0x0, BT848_DVSIF);
825 }
826}
827
828/* ----------------------------------------------------------------------- */
829
830static void bt848_bright(struct bttv *btv, int bright)
831{
832 int value;
833
834 // printk("bttv: set bright: %d\n",bright); // DEBUG
835 btv->bright = bright;
836
837 /* We want -128 to 127 we get 0-65535 */
838 value = (bright >> 8) - 128;
839 btwrite(value & 0xff, BT848_BRIGHT);
840}
841
842static void bt848_hue(struct bttv *btv, int hue)
843{
844 int value;
845
846 btv->hue = hue;
847
848 /* -128 to 127 */
849 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800850 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851}
852
853static void bt848_contrast(struct bttv *btv, int cont)
854{
855 int value,hibit;
856
857 btv->contrast = cont;
858
859 /* 0-511 */
860 value = (cont >> 7);
861 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800862 btwrite(value & 0xff, BT848_CONTRAST_LO);
863 btaor(hibit, ~4, BT848_E_CONTROL);
864 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
867static void bt848_sat(struct bttv *btv, int color)
868{
869 int val_u,val_v,hibits;
870
871 btv->saturation = color;
872
873 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700874 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
875 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800876 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800878 btwrite(val_u & 0xff, BT848_SAT_U_LO);
879 btwrite(val_v & 0xff, BT848_SAT_V_LO);
880 btaor(hibits, ~3, BT848_E_CONTROL);
881 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882}
883
884/* ----------------------------------------------------------------------- */
885
886static int
887video_mux(struct bttv *btv, unsigned int input)
888{
889 int mux,mask2;
890
891 if (input >= bttv_tvcards[btv->c.type].video_inputs)
892 return -EINVAL;
893
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800894 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
896 if (mask2)
897 gpio_inout(mask2,mask2);
898
899 if (input == btv->svhs) {
900 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
901 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
902 } else {
903 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
904 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
905 }
906 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
907 btaor(mux<<5, ~(3<<5), BT848_IFORM);
908 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
909 btv->c.nr,input,mux);
910
911 /* card specific hook */
912 if(bttv_tvcards[btv->c.type].muxsel_hook)
913 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
914 return 0;
915}
916
917static char *audio_modes[] = {
918 "audio: tuner", "audio: radio", "audio: extern",
919 "audio: intern", "audio: off"
920};
921
922static int
923audio_mux(struct bttv *btv, int mode)
924{
925 int val,mux,i2c_mux,signal;
926
927 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
928 bttv_tvcards[btv->c.type].gpiomask);
929 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
930
931 switch (mode) {
932 case AUDIO_MUTE:
933 btv->audio |= AUDIO_MUTE;
934 break;
935 case AUDIO_UNMUTE:
936 btv->audio &= ~AUDIO_MUTE;
937 break;
938 case AUDIO_TUNER:
939 case AUDIO_RADIO:
940 case AUDIO_EXTERN:
941 case AUDIO_INTERN:
942 btv->audio &= AUDIO_MUTE;
943 btv->audio |= mode;
944 }
945 i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
946 if (btv->opt_automute && !signal && !btv->radio_user)
947 mux = AUDIO_OFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 val = bttv_tvcards[btv->c.type].audiomux[mux];
950 gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val);
951 if (bttv_gpio)
952 bttv_gpio_tracking(btv,audio_modes[mux]);
953 if (!in_interrupt())
954 bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(i2c_mux));
955 return 0;
956}
957
958static void
959i2c_vidiocschan(struct bttv *btv)
960{
961 struct video_channel c;
962
963 memset(&c,0,sizeof(c));
964 c.norm = btv->tvnorm;
965 c.channel = btv->input;
966 bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -0800967 if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 bttv_tda9880_setnorm(btv,c.norm);
969}
970
971static int
972set_tvnorm(struct bttv *btv, unsigned int norm)
973{
974 const struct bttv_tvnorm *tvnorm;
975
976 if (norm < 0 || norm >= BTTV_TVNORMS)
977 return -EINVAL;
978
979 btv->tvnorm = norm;
980 tvnorm = &bttv_tvnorms[norm];
981
982 btwrite(tvnorm->adelay, BT848_ADELAY);
983 btwrite(tvnorm->bdelay, BT848_BDELAY);
984 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
985 BT848_IFORM);
986 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
987 btwrite(1, BT848_VBI_PACK_DEL);
988 bt848A_set_timing(btv);
989
990 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -0800991 case BTTV_BOARD_VOODOOTV_FM:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 bttv_tda9880_setnorm(btv,norm);
993 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 }
995 return 0;
996}
997
998static void
999set_input(struct bttv *btv, unsigned int input)
1000{
1001 unsigned long flags;
1002
1003 btv->input = input;
1004 if (irq_iswitch) {
1005 spin_lock_irqsave(&btv->s_lock,flags);
1006 if (btv->curr.frame_irq) {
1007 /* active capture -> delayed input switch */
1008 btv->new_input = input;
1009 } else {
1010 video_mux(btv,input);
1011 }
1012 spin_unlock_irqrestore(&btv->s_lock,flags);
1013 } else {
1014 video_mux(btv,input);
1015 }
1016 audio_mux(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1017 AUDIO_TUNER : AUDIO_EXTERN));
1018 set_tvnorm(btv,btv->tvnorm);
1019 i2c_vidiocschan(btv);
1020}
1021
1022static void init_irqreg(struct bttv *btv)
1023{
1024 /* clear status */
1025 btwrite(0xfffffUL, BT848_INT_STAT);
1026
1027 if (bttv_tvcards[btv->c.type].no_video) {
1028 /* i2c only */
1029 btwrite(BT848_INT_I2CDONE,
1030 BT848_INT_MASK);
1031 } else {
1032 /* full video */
1033 btwrite((btv->triton1) |
1034 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1035 BT848_INT_SCERR |
1036 (fdsr ? BT848_INT_FDSR : 0) |
1037 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1038 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1039 BT848_INT_I2CDONE,
1040 BT848_INT_MASK);
1041 }
1042}
1043
1044static void init_bt848(struct bttv *btv)
1045{
1046 int val;
1047
1048 if (bttv_tvcards[btv->c.type].no_video) {
1049 /* very basic init only */
1050 init_irqreg(btv);
1051 return;
1052 }
1053
1054 btwrite(0x00, BT848_CAP_CTL);
1055 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1056 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1057
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001058 /* set planar and packed mode trigger points and */
1059 /* set rising edge of inverted GPINTR pin as irq trigger */
1060 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1061 BT848_GPIO_DMA_CTL_PLTP1_16|
1062 BT848_GPIO_DMA_CTL_PLTP23_16|
1063 BT848_GPIO_DMA_CTL_GPINTC|
1064 BT848_GPIO_DMA_CTL_GPINTI,
1065 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001068 btwrite(val, BT848_E_SCLOOP);
1069 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001071 btwrite(0x20, BT848_E_VSCALE_HI);
1072 btwrite(0x20, BT848_O_VSCALE_HI);
1073 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 BT848_ADC);
1075
1076 btwrite(whitecrush_upper, BT848_WC_UP);
1077 btwrite(whitecrush_lower, BT848_WC_DOWN);
1078
1079 if (btv->opt_lumafilter) {
1080 btwrite(0, BT848_E_CONTROL);
1081 btwrite(0, BT848_O_CONTROL);
1082 } else {
1083 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1084 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1085 }
1086
1087 bt848_bright(btv, btv->bright);
1088 bt848_hue(btv, btv->hue);
1089 bt848_contrast(btv, btv->contrast);
1090 bt848_sat(btv, btv->saturation);
1091
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001092 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 init_irqreg(btv);
1094}
1095
1096static void bttv_reinit_bt848(struct bttv *btv)
1097{
1098 unsigned long flags;
1099
1100 if (bttv_verbose)
1101 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1102 spin_lock_irqsave(&btv->s_lock,flags);
1103 btv->errors=0;
1104 bttv_set_dma(btv,0);
1105 spin_unlock_irqrestore(&btv->s_lock,flags);
1106
1107 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001108 btv->pll.pll_current = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 set_input(btv,btv->input);
1110}
1111
1112static int get_control(struct bttv *btv, struct v4l2_control *c)
1113{
1114 struct video_audio va;
1115 int i;
1116
1117 for (i = 0; i < BTTV_CTLS; i++)
1118 if (bttv_ctls[i].id == c->id)
1119 break;
1120 if (i == BTTV_CTLS)
1121 return -EINVAL;
1122 if (i >= 4 && i <= 8) {
1123 memset(&va,0,sizeof(va));
1124 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1125 if (btv->audio_hook)
1126 btv->audio_hook(btv,&va,0);
1127 }
1128 switch (c->id) {
1129 case V4L2_CID_BRIGHTNESS:
1130 c->value = btv->bright;
1131 break;
1132 case V4L2_CID_HUE:
1133 c->value = btv->hue;
1134 break;
1135 case V4L2_CID_CONTRAST:
1136 c->value = btv->contrast;
1137 break;
1138 case V4L2_CID_SATURATION:
1139 c->value = btv->saturation;
1140 break;
1141
1142 case V4L2_CID_AUDIO_MUTE:
1143 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1144 break;
1145 case V4L2_CID_AUDIO_VOLUME:
1146 c->value = va.volume;
1147 break;
1148 case V4L2_CID_AUDIO_BALANCE:
1149 c->value = va.balance;
1150 break;
1151 case V4L2_CID_AUDIO_BASS:
1152 c->value = va.bass;
1153 break;
1154 case V4L2_CID_AUDIO_TREBLE:
1155 c->value = va.treble;
1156 break;
1157
1158 case V4L2_CID_PRIVATE_CHROMA_AGC:
1159 c->value = btv->opt_chroma_agc;
1160 break;
1161 case V4L2_CID_PRIVATE_COMBFILTER:
1162 c->value = btv->opt_combfilter;
1163 break;
1164 case V4L2_CID_PRIVATE_LUMAFILTER:
1165 c->value = btv->opt_lumafilter;
1166 break;
1167 case V4L2_CID_PRIVATE_AUTOMUTE:
1168 c->value = btv->opt_automute;
1169 break;
1170 case V4L2_CID_PRIVATE_AGC_CRUSH:
1171 c->value = btv->opt_adc_crush;
1172 break;
1173 case V4L2_CID_PRIVATE_VCR_HACK:
1174 c->value = btv->opt_vcr_hack;
1175 break;
1176 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1177 c->value = btv->opt_whitecrush_upper;
1178 break;
1179 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1180 c->value = btv->opt_whitecrush_lower;
1181 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001182 case V4L2_CID_PRIVATE_UV_RATIO:
1183 c->value = btv->opt_uv_ratio;
1184 break;
1185 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1186 c->value = btv->opt_full_luma_range;
1187 break;
1188 case V4L2_CID_PRIVATE_CORING:
1189 c->value = btv->opt_coring;
1190 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 default:
1192 return -EINVAL;
1193 }
1194 return 0;
1195}
1196
1197static int set_control(struct bttv *btv, struct v4l2_control *c)
1198{
1199 struct video_audio va;
1200 int i,val;
1201
1202 for (i = 0; i < BTTV_CTLS; i++)
1203 if (bttv_ctls[i].id == c->id)
1204 break;
1205 if (i == BTTV_CTLS)
1206 return -EINVAL;
1207 if (i >= 4 && i <= 8) {
1208 memset(&va,0,sizeof(va));
1209 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1210 if (btv->audio_hook)
1211 btv->audio_hook(btv,&va,0);
1212 }
1213 switch (c->id) {
1214 case V4L2_CID_BRIGHTNESS:
1215 bt848_bright(btv,c->value);
1216 break;
1217 case V4L2_CID_HUE:
1218 bt848_hue(btv,c->value);
1219 break;
1220 case V4L2_CID_CONTRAST:
1221 bt848_contrast(btv,c->value);
1222 break;
1223 case V4L2_CID_SATURATION:
1224 bt848_sat(btv,c->value);
1225 break;
1226 case V4L2_CID_AUDIO_MUTE:
1227 if (c->value) {
1228 va.flags |= VIDEO_AUDIO_MUTE;
1229 audio_mux(btv, AUDIO_MUTE);
1230 } else {
1231 va.flags &= ~VIDEO_AUDIO_MUTE;
1232 audio_mux(btv, AUDIO_UNMUTE);
1233 }
1234 break;
1235
1236 case V4L2_CID_AUDIO_VOLUME:
1237 va.volume = c->value;
1238 break;
1239 case V4L2_CID_AUDIO_BALANCE:
1240 va.balance = c->value;
1241 break;
1242 case V4L2_CID_AUDIO_BASS:
1243 va.bass = c->value;
1244 break;
1245 case V4L2_CID_AUDIO_TREBLE:
1246 va.treble = c->value;
1247 break;
1248
1249 case V4L2_CID_PRIVATE_CHROMA_AGC:
1250 btv->opt_chroma_agc = c->value;
1251 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1252 btwrite(val, BT848_E_SCLOOP);
1253 btwrite(val, BT848_O_SCLOOP);
1254 break;
1255 case V4L2_CID_PRIVATE_COMBFILTER:
1256 btv->opt_combfilter = c->value;
1257 break;
1258 case V4L2_CID_PRIVATE_LUMAFILTER:
1259 btv->opt_lumafilter = c->value;
1260 if (btv->opt_lumafilter) {
1261 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1262 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1263 } else {
1264 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1265 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1266 }
1267 break;
1268 case V4L2_CID_PRIVATE_AUTOMUTE:
1269 btv->opt_automute = c->value;
1270 break;
1271 case V4L2_CID_PRIVATE_AGC_CRUSH:
1272 btv->opt_adc_crush = c->value;
1273 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1274 BT848_ADC);
1275 break;
1276 case V4L2_CID_PRIVATE_VCR_HACK:
1277 btv->opt_vcr_hack = c->value;
1278 break;
1279 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1280 btv->opt_whitecrush_upper = c->value;
1281 btwrite(c->value, BT848_WC_UP);
1282 break;
1283 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1284 btv->opt_whitecrush_lower = c->value;
1285 btwrite(c->value, BT848_WC_DOWN);
1286 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001287 case V4L2_CID_PRIVATE_UV_RATIO:
1288 btv->opt_uv_ratio = c->value;
1289 bt848_sat(btv, btv->saturation);
1290 break;
1291 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1292 btv->opt_full_luma_range = c->value;
1293 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1294 break;
1295 case V4L2_CID_PRIVATE_CORING:
1296 btv->opt_coring = c->value;
1297 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1298 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 default:
1300 return -EINVAL;
1301 }
1302 if (i >= 4 && i <= 8) {
1303 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1304 if (btv->audio_hook)
1305 btv->audio_hook(btv,&va,1);
1306 }
1307 return 0;
1308}
1309
1310/* ----------------------------------------------------------------------- */
1311
1312void bttv_gpio_tracking(struct bttv *btv, char *comment)
1313{
1314 unsigned int outbits, data;
1315 outbits = btread(BT848_GPIO_OUT_EN);
1316 data = btread(BT848_GPIO_DATA);
1317 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1318 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1319}
1320
1321static void bttv_field_count(struct bttv *btv)
1322{
1323 int need_count = 0;
1324
1325 if (btv->users)
1326 need_count++;
1327
1328 if (need_count) {
1329 /* start field counter */
1330 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1331 } else {
1332 /* stop field counter */
1333 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1334 btv->field_count = 0;
1335 }
1336}
1337
1338static const struct bttv_format*
1339format_by_palette(int palette)
1340{
1341 unsigned int i;
1342
1343 for (i = 0; i < BTTV_FORMATS; i++) {
1344 if (-1 == bttv_formats[i].palette)
1345 continue;
1346 if (bttv_formats[i].palette == palette)
1347 return bttv_formats+i;
1348 }
1349 return NULL;
1350}
1351
1352static const struct bttv_format*
1353format_by_fourcc(int fourcc)
1354{
1355 unsigned int i;
1356
1357 for (i = 0; i < BTTV_FORMATS; i++) {
1358 if (-1 == bttv_formats[i].fourcc)
1359 continue;
1360 if (bttv_formats[i].fourcc == fourcc)
1361 return bttv_formats+i;
1362 }
1363 return NULL;
1364}
1365
1366/* ----------------------------------------------------------------------- */
1367/* misc helpers */
1368
1369static int
1370bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1371 struct bttv_buffer *new)
1372{
1373 struct bttv_buffer *old;
1374 unsigned long flags;
1375 int retval = 0;
1376
1377 dprintk("switch_overlay: enter [new=%p]\n",new);
1378 if (new)
1379 new->vb.state = STATE_DONE;
1380 spin_lock_irqsave(&btv->s_lock,flags);
1381 old = btv->screen;
1382 btv->screen = new;
1383 btv->loop_irq |= 1;
1384 bttv_set_dma(btv, 0x03);
1385 spin_unlock_irqrestore(&btv->s_lock,flags);
1386 if (NULL == new)
1387 free_btres(btv,fh,RESOURCE_OVERLAY);
1388 if (NULL != old) {
1389 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
1390 bttv_dma_free(btv, old);
1391 kfree(old);
1392 }
1393 dprintk("switch_overlay: done\n");
1394 return retval;
1395}
1396
1397/* ----------------------------------------------------------------------- */
1398/* video4linux (1) interface */
1399
1400static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001401 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 unsigned int width, unsigned int height,
1403 enum v4l2_field field)
1404{
1405 int redo_dma_risc = 0;
1406 int rc;
1407
1408 /* check settings */
1409 if (NULL == fmt)
1410 return -EINVAL;
1411 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1412 width = RAW_BPL;
1413 height = RAW_LINES*2;
1414 if (width*height > buf->vb.bsize)
1415 return -EINVAL;
1416 buf->vb.size = buf->vb.bsize;
1417 } else {
1418 if (width < 48 ||
1419 height < 32 ||
1420 width > bttv_tvnorms[btv->tvnorm].swidth ||
1421 height > bttv_tvnorms[btv->tvnorm].sheight)
1422 return -EINVAL;
1423 buf->vb.size = (width * height * fmt->depth) >> 3;
1424 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1425 return -EINVAL;
1426 }
1427
1428 /* alloc + fill struct bttv_buffer (if changed) */
1429 if (buf->vb.width != width || buf->vb.height != height ||
1430 buf->vb.field != field ||
1431 buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
1432 buf->vb.width = width;
1433 buf->vb.height = height;
1434 buf->vb.field = field;
1435 buf->tvnorm = btv->tvnorm;
1436 buf->fmt = fmt;
1437 redo_dma_risc = 1;
1438 }
1439
1440 /* alloc risc memory */
1441 if (STATE_NEEDS_INIT == buf->vb.state) {
1442 redo_dma_risc = 1;
1443 if (0 != (rc = videobuf_iolock(btv->c.pci,&buf->vb,&btv->fbuf)))
1444 goto fail;
1445 }
1446
1447 if (redo_dma_risc)
1448 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1449 goto fail;
1450
1451 buf->vb.state = STATE_PREPARED;
1452 return 0;
1453
1454 fail:
1455 bttv_dma_free(btv,buf);
1456 return rc;
1457}
1458
1459static int
1460buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1461{
1462 struct bttv_fh *fh = q->priv_data;
1463
1464 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1465 if (0 == *count)
1466 *count = gbuffers;
1467 while (*size * *count > gbuffers * gbufsize)
1468 (*count)--;
1469 return 0;
1470}
1471
1472static int
1473buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1474 enum v4l2_field field)
1475{
1476 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1477 struct bttv_fh *fh = q->priv_data;
1478
1479 return bttv_prepare_buffer(fh->btv, buf, fh->fmt,
1480 fh->width, fh->height, field);
1481}
1482
1483static void
1484buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1485{
1486 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1487 struct bttv_fh *fh = q->priv_data;
1488 struct bttv *btv = fh->btv;
1489
1490 buf->vb.state = STATE_QUEUED;
1491 list_add_tail(&buf->vb.queue,&btv->capture);
1492 if (!btv->curr.frame_irq) {
1493 btv->loop_irq |= 1;
1494 bttv_set_dma(btv, 0x03);
1495 }
1496}
1497
1498static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1499{
1500 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1501 struct bttv_fh *fh = q->priv_data;
1502
1503 bttv_dma_free(fh->btv,buf);
1504}
1505
1506static struct videobuf_queue_ops bttv_video_qops = {
1507 .buf_setup = buffer_setup,
1508 .buf_prepare = buffer_prepare,
1509 .buf_queue = buffer_queue,
1510 .buf_release = buffer_release,
1511};
1512
1513static const char *v4l1_ioctls[] = {
1514 "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT",
1515 "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ",
1516 "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
1517 "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
1518 "SMICROCODE", "GVBIFMT", "SVBIFMT" };
1519#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
1520
1521static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1522{
1523 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001524 case BTTV_VERSION:
1525 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 /* *** v4l1 *** ************************************************ */
1528 case VIDIOCGFREQ:
1529 {
1530 unsigned long *freq = arg;
1531 *freq = btv->freq;
1532 return 0;
1533 }
1534 case VIDIOCSFREQ:
1535 {
1536 unsigned long *freq = arg;
1537 down(&btv->lock);
1538 btv->freq=*freq;
1539 bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
1540 if (btv->has_matchbox && btv->radio_user)
1541 tea5757_set_freq(btv,*freq);
1542 up(&btv->lock);
1543 return 0;
1544 }
1545
1546 case VIDIOCGTUNER:
1547 {
1548 struct video_tuner *v = arg;
1549
1550 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1551 return -EINVAL;
1552 if (v->tuner) /* Only tuner 0 */
1553 return -EINVAL;
1554 strcpy(v->name, "Television");
1555 v->rangelow = 0;
1556 v->rangehigh = 0x7FFFFFFF;
1557 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1558 v->mode = btv->tvnorm;
1559 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1560 bttv_call_i2c_clients(btv,cmd,v);
1561 return 0;
1562 }
1563 case VIDIOCSTUNER:
1564 {
1565 struct video_tuner *v = arg;
1566
1567 if (v->tuner) /* Only tuner 0 */
1568 return -EINVAL;
1569 if (v->mode >= BTTV_TVNORMS)
1570 return -EINVAL;
1571
1572 down(&btv->lock);
1573 set_tvnorm(btv,v->mode);
1574 bttv_call_i2c_clients(btv,cmd,v);
1575 up(&btv->lock);
1576 return 0;
1577 }
1578
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001579 case VIDIOCGCHAN:
1580 {
1581 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 unsigned int channel = v->channel;
1583
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001584 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1585 return -EINVAL;
1586 v->tuners=0;
1587 v->flags = VIDEO_VC_AUDIO;
1588 v->type = VIDEO_TYPE_CAMERA;
1589 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001591 strcpy(v->name,"Television");
1592 v->flags|=VIDEO_VC_TUNER;
1593 v->type=VIDEO_TYPE_TV;
1594 v->tuners=1;
1595 } else if (channel == btv->svhs) {
1596 strcpy(v->name,"S-Video");
1597 } else {
1598 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 }
1600 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001601 }
1602 case VIDIOCSCHAN:
1603 {
1604 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 unsigned int channel = v->channel;
1606
1607 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1608 return -EINVAL;
1609 if (v->norm >= BTTV_TVNORMS)
1610 return -EINVAL;
1611
1612 down(&btv->lock);
1613 if (channel == btv->input &&
1614 v->norm == btv->tvnorm) {
1615 /* nothing to do */
1616 up(&btv->lock);
1617 return 0;
1618 }
1619
1620 btv->tvnorm = v->norm;
1621 set_input(btv,v->channel);
1622 up(&btv->lock);
1623 return 0;
1624 }
1625
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001626 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 {
1628 struct video_audio *v = arg;
1629
1630 memset(v,0,sizeof(*v));
1631 strcpy(v->name,"Television");
1632 v->flags |= VIDEO_AUDIO_MUTABLE;
1633 v->mode = VIDEO_SOUND_MONO;
1634
1635 down(&btv->lock);
1636 bttv_call_i2c_clients(btv,cmd,v);
1637
1638 /* card specific hooks */
1639 if (btv->audio_hook)
1640 btv->audio_hook(btv,v,0);
1641
1642 up(&btv->lock);
1643 return 0;
1644 }
1645 case VIDIOCSAUDIO:
1646 {
1647 struct video_audio *v = arg;
1648 unsigned int audio = v->audio;
1649
1650 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
1651 return -EINVAL;
1652
1653 down(&btv->lock);
1654 audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE);
1655 bttv_call_i2c_clients(btv,cmd,v);
1656
1657 /* card specific hooks */
1658 if (btv->audio_hook)
1659 btv->audio_hook(btv,v,1);
1660
1661 up(&btv->lock);
1662 return 0;
1663 }
1664
1665 /* *** v4l2 *** ************************************************ */
1666 case VIDIOC_ENUMSTD:
1667 {
1668 struct v4l2_standard *e = arg;
1669 unsigned int index = e->index;
1670
1671 if (index >= BTTV_TVNORMS)
1672 return -EINVAL;
1673 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1674 bttv_tvnorms[e->index].name);
1675 e->index = index;
1676 return 0;
1677 }
1678 case VIDIOC_G_STD:
1679 {
1680 v4l2_std_id *id = arg;
1681 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1682 return 0;
1683 }
1684 case VIDIOC_S_STD:
1685 {
1686 v4l2_std_id *id = arg;
1687 unsigned int i;
1688
1689 for (i = 0; i < BTTV_TVNORMS; i++)
1690 if (*id & bttv_tvnorms[i].v4l2_id)
1691 break;
1692 if (i == BTTV_TVNORMS)
1693 return -EINVAL;
1694
1695 down(&btv->lock);
1696 set_tvnorm(btv,i);
1697 i2c_vidiocschan(btv);
1698 up(&btv->lock);
1699 return 0;
1700 }
1701 case VIDIOC_QUERYSTD:
1702 {
1703 v4l2_std_id *id = arg;
1704
1705 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1706 *id = V4L2_STD_625_50;
1707 else
1708 *id = V4L2_STD_525_60;
1709 return 0;
1710 }
1711
1712 case VIDIOC_ENUMINPUT:
1713 {
1714 struct v4l2_input *i = arg;
1715 unsigned int n;
1716
1717 n = i->index;
1718 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1719 return -EINVAL;
1720 memset(i,0,sizeof(*i));
1721 i->index = n;
1722 i->type = V4L2_INPUT_TYPE_CAMERA;
1723 i->audioset = 1;
1724 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1725 sprintf(i->name, "Television");
1726 i->type = V4L2_INPUT_TYPE_TUNER;
1727 i->tuner = 0;
1728 } else if (i->index == btv->svhs) {
1729 sprintf(i->name, "S-Video");
1730 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001731 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 }
1733 if (i->index == btv->input) {
1734 __u32 dstatus = btread(BT848_DSTATUS);
1735 if (0 == (dstatus & BT848_DSTATUS_PRES))
1736 i->status |= V4L2_IN_ST_NO_SIGNAL;
1737 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1738 i->status |= V4L2_IN_ST_NO_H_LOCK;
1739 }
1740 for (n = 0; n < BTTV_TVNORMS; n++)
1741 i->std |= bttv_tvnorms[n].v4l2_id;
1742 return 0;
1743 }
1744 case VIDIOC_G_INPUT:
1745 {
1746 int *i = arg;
1747 *i = btv->input;
1748 return 0;
1749 }
1750 case VIDIOC_S_INPUT:
1751 {
1752 unsigned int *i = arg;
1753
1754 if (*i > bttv_tvcards[btv->c.type].video_inputs)
1755 return -EINVAL;
1756 down(&btv->lock);
1757 set_input(btv,*i);
1758 up(&btv->lock);
1759 return 0;
1760 }
1761
1762 case VIDIOC_G_TUNER:
1763 {
1764 struct v4l2_tuner *t = arg;
1765
1766 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1767 return -EINVAL;
1768 if (0 != t->index)
1769 return -EINVAL;
1770 down(&btv->lock);
1771 memset(t,0,sizeof(*t));
1772 strcpy(t->name, "Television");
1773 t->type = V4L2_TUNER_ANALOG_TV;
1774 t->rangehigh = 0xffffffffUL;
1775 t->capability = V4L2_TUNER_CAP_NORM;
1776 t->rxsubchans = V4L2_TUNER_SUB_MONO;
1777 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
1778 t->signal = 0xffff;
1779 {
1780 /* Hmmm ... */
1781 struct video_audio va;
1782 memset(&va, 0, sizeof(struct video_audio));
1783 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1784 if (btv->audio_hook)
1785 btv->audio_hook(btv,&va,0);
1786 if(va.mode & VIDEO_SOUND_STEREO) {
1787 t->audmode = V4L2_TUNER_MODE_STEREO;
1788 t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
1789 }
1790 if(va.mode & VIDEO_SOUND_LANG1) {
1791 t->audmode = V4L2_TUNER_MODE_LANG1;
1792 t->rxsubchans = V4L2_TUNER_SUB_LANG1
1793 | V4L2_TUNER_SUB_LANG2;
1794 }
1795 }
1796 /* FIXME: fill capability+audmode */
1797 up(&btv->lock);
1798 return 0;
1799 }
1800 case VIDIOC_S_TUNER:
1801 {
1802 struct v4l2_tuner *t = arg;
1803
1804 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1805 return -EINVAL;
1806 if (0 != t->index)
1807 return -EINVAL;
1808 down(&btv->lock);
1809 {
1810 struct video_audio va;
1811 memset(&va, 0, sizeof(struct video_audio));
1812 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1813 if (t->audmode == V4L2_TUNER_MODE_MONO)
1814 va.mode = VIDEO_SOUND_MONO;
1815 else if (t->audmode == V4L2_TUNER_MODE_STEREO)
1816 va.mode = VIDEO_SOUND_STEREO;
1817 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
1818 va.mode = VIDEO_SOUND_LANG1;
1819 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
1820 va.mode = VIDEO_SOUND_LANG2;
1821 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1822 if (btv->audio_hook)
1823 btv->audio_hook(btv,&va,1);
1824 }
1825 up(&btv->lock);
1826 return 0;
1827 }
1828
1829 case VIDIOC_G_FREQUENCY:
1830 {
1831 struct v4l2_frequency *f = arg;
1832
1833 memset(f,0,sizeof(*f));
1834 f->type = V4L2_TUNER_ANALOG_TV;
1835 f->frequency = btv->freq;
1836 return 0;
1837 }
1838 case VIDIOC_S_FREQUENCY:
1839 {
1840 struct v4l2_frequency *f = arg;
1841
1842 if (unlikely(f->tuner != 0))
1843 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07001844 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 return -EINVAL;
1846 down(&btv->lock);
1847 btv->freq = f->frequency;
1848 bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
1849 if (btv->has_matchbox && btv->radio_user)
1850 tea5757_set_freq(btv,btv->freq);
1851 up(&btv->lock);
1852 return 0;
1853 }
Hans Verkuil299392b2005-11-08 21:37:42 -08001854 case VIDIOC_LOG_STATUS:
1855 {
Luiz Capitulino97cb4452005-12-01 00:51:24 -08001856 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil299392b2005-11-08 21:37:42 -08001857 return 0;
1858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
1860 default:
1861 return -ENOIOCTLCMD;
1862
1863 }
1864 return 0;
1865}
1866
1867static int verify_window(const struct bttv_tvnorm *tvn,
1868 struct v4l2_window *win, int fixup)
1869{
1870 enum v4l2_field field;
1871 int maxw, maxh;
1872
1873 if (win->w.width < 48 || win->w.height < 32)
1874 return -EINVAL;
1875 if (win->clipcount > 2048)
1876 return -EINVAL;
1877
1878 field = win->field;
1879 maxw = tvn->swidth;
1880 maxh = tvn->sheight;
1881
1882 if (V4L2_FIELD_ANY == field) {
1883 field = (win->w.height > maxh/2)
1884 ? V4L2_FIELD_INTERLACED
1885 : V4L2_FIELD_TOP;
1886 }
1887 switch (field) {
1888 case V4L2_FIELD_TOP:
1889 case V4L2_FIELD_BOTTOM:
1890 maxh = maxh / 2;
1891 break;
1892 case V4L2_FIELD_INTERLACED:
1893 break;
1894 default:
1895 return -EINVAL;
1896 }
1897
1898 if (!fixup && (win->w.width > maxw || win->w.height > maxh))
1899 return -EINVAL;
1900
1901 if (win->w.width > maxw)
1902 win->w.width = maxw;
1903 if (win->w.height > maxh)
1904 win->w.height = maxh;
1905 win->field = field;
1906 return 0;
1907}
1908
1909static int setup_window(struct bttv_fh *fh, struct bttv *btv,
1910 struct v4l2_window *win, int fixup)
1911{
1912 struct v4l2_clip *clips = NULL;
1913 int n,size,retval = 0;
1914
1915 if (NULL == fh->ovfmt)
1916 return -EINVAL;
1917 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
1918 return -EINVAL;
1919 retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
1920 if (0 != retval)
1921 return retval;
1922
1923 /* copy clips -- luckily v4l1 + v4l2 are binary
1924 compatible here ...*/
1925 n = win->clipcount;
1926 size = sizeof(*clips)*(n+4);
1927 clips = kmalloc(size,GFP_KERNEL);
1928 if (NULL == clips)
1929 return -ENOMEM;
1930 if (n > 0) {
1931 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
1932 kfree(clips);
1933 return -EFAULT;
1934 }
1935 }
1936 /* clip against screen */
1937 if (NULL != btv->fbuf.base)
1938 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
1939 &win->w, clips, n);
1940 btcx_sort_clips(clips,n);
1941
1942 /* 4-byte alignments */
1943 switch (fh->ovfmt->depth) {
1944 case 8:
1945 case 24:
1946 btcx_align(&win->w, clips, n, 3);
1947 break;
1948 case 16:
1949 btcx_align(&win->w, clips, n, 1);
1950 break;
1951 case 32:
1952 /* no alignment fixups needed */
1953 break;
1954 default:
1955 BUG();
1956 }
1957
1958 down(&fh->cap.lock);
Jesper Juhl2ea75332005-11-07 01:01:31 -08001959 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 fh->ov.clips = clips;
1961 fh->ov.nclips = n;
1962
1963 fh->ov.w = win->w;
1964 fh->ov.field = win->field;
1965 fh->ov.setup_ok = 1;
1966 btv->init.ov.w.width = win->w.width;
1967 btv->init.ov.w.height = win->w.height;
1968 btv->init.ov.field = win->field;
1969
1970 /* update overlay if needed */
1971 retval = 0;
1972 if (check_btres(fh, RESOURCE_OVERLAY)) {
1973 struct bttv_buffer *new;
1974
1975 new = videobuf_alloc(sizeof(*new));
1976 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
1977 retval = bttv_switch_overlay(btv,fh,new);
1978 }
1979 up(&fh->cap.lock);
1980 return retval;
1981}
1982
1983/* ----------------------------------------------------------------------- */
1984
1985static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
1986{
1987 struct videobuf_queue* q = NULL;
1988
1989 switch (fh->type) {
1990 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1991 q = &fh->cap;
1992 break;
1993 case V4L2_BUF_TYPE_VBI_CAPTURE:
1994 q = &fh->vbi;
1995 break;
1996 default:
1997 BUG();
1998 }
1999 return q;
2000}
2001
2002static int bttv_resource(struct bttv_fh *fh)
2003{
2004 int res = 0;
2005
2006 switch (fh->type) {
2007 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2008 res = RESOURCE_VIDEO;
2009 break;
2010 case V4L2_BUF_TYPE_VBI_CAPTURE:
2011 res = RESOURCE_VBI;
2012 break;
2013 default:
2014 BUG();
2015 }
2016 return res;
2017}
2018
2019static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2020{
2021 struct videobuf_queue *q = bttv_queue(fh);
2022 int res = bttv_resource(fh);
2023
2024 if (check_btres(fh,res))
2025 return -EBUSY;
2026 if (videobuf_queue_is_busy(q))
2027 return -EBUSY;
2028 fh->type = type;
2029 return 0;
2030}
2031
2032static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2033{
2034 switch (f->type) {
2035 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2036 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
2037 f->fmt.pix.width = fh->width;
2038 f->fmt.pix.height = fh->height;
2039 f->fmt.pix.field = fh->cap.field;
2040 f->fmt.pix.pixelformat = fh->fmt->fourcc;
2041 f->fmt.pix.bytesperline =
2042 (f->fmt.pix.width * fh->fmt->depth) >> 3;
2043 f->fmt.pix.sizeimage =
2044 f->fmt.pix.height * f->fmt.pix.bytesperline;
2045 return 0;
2046 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2047 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2048 f->fmt.win.w = fh->ov.w;
2049 f->fmt.win.field = fh->ov.field;
2050 return 0;
2051 case V4L2_BUF_TYPE_VBI_CAPTURE:
2052 bttv_vbi_get_fmt(fh,f);
2053 return 0;
2054 default:
2055 return -EINVAL;
2056 }
2057}
2058
2059static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
2060 struct v4l2_format *f)
2061{
2062 switch (f->type) {
2063 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2064 {
2065 const struct bttv_format *fmt;
2066 enum v4l2_field field;
2067 unsigned int maxw,maxh;
2068
2069 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2070 if (NULL == fmt)
2071 return -EINVAL;
2072
2073 /* fixup format */
2074 maxw = bttv_tvnorms[btv->tvnorm].swidth;
2075 maxh = bttv_tvnorms[btv->tvnorm].sheight;
2076 field = f->fmt.pix.field;
2077 if (V4L2_FIELD_ANY == field)
2078 field = (f->fmt.pix.height > maxh/2)
2079 ? V4L2_FIELD_INTERLACED
2080 : V4L2_FIELD_BOTTOM;
2081 if (V4L2_FIELD_SEQ_BT == field)
2082 field = V4L2_FIELD_SEQ_TB;
2083 switch (field) {
2084 case V4L2_FIELD_TOP:
2085 case V4L2_FIELD_BOTTOM:
2086 case V4L2_FIELD_ALTERNATE:
2087 maxh = maxh/2;
2088 break;
2089 case V4L2_FIELD_INTERLACED:
2090 break;
2091 case V4L2_FIELD_SEQ_TB:
2092 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2093 return -EINVAL;
2094 break;
2095 default:
2096 return -EINVAL;
2097 }
2098
2099 /* update data for the application */
2100 f->fmt.pix.field = field;
2101 if (f->fmt.pix.width < 48)
2102 f->fmt.pix.width = 48;
2103 if (f->fmt.pix.height < 32)
2104 f->fmt.pix.height = 32;
2105 if (f->fmt.pix.width > maxw)
2106 f->fmt.pix.width = maxw;
2107 if (f->fmt.pix.height > maxh)
2108 f->fmt.pix.height = maxh;
2109 f->fmt.pix.width &= ~0x03;
2110 f->fmt.pix.bytesperline =
2111 (f->fmt.pix.width * fmt->depth) >> 3;
2112 f->fmt.pix.sizeimage =
2113 f->fmt.pix.height * f->fmt.pix.bytesperline;
2114
2115 return 0;
2116 }
2117 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2118 return verify_window(&bttv_tvnorms[btv->tvnorm],
2119 &f->fmt.win, 1);
2120 case V4L2_BUF_TYPE_VBI_CAPTURE:
2121 bttv_vbi_try_fmt(fh,f);
2122 return 0;
2123 default:
2124 return -EINVAL;
2125 }
2126}
2127
2128static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2129 struct v4l2_format *f)
2130{
2131 int retval;
2132
2133 switch (f->type) {
2134 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2135 {
2136 const struct bttv_format *fmt;
2137
2138 retval = bttv_switch_type(fh,f->type);
2139 if (0 != retval)
2140 return retval;
2141 retval = bttv_try_fmt(fh,btv,f);
2142 if (0 != retval)
2143 return retval;
2144 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2145
2146 /* update our state informations */
2147 down(&fh->cap.lock);
2148 fh->fmt = fmt;
2149 fh->cap.field = f->fmt.pix.field;
2150 fh->cap.last = V4L2_FIELD_NONE;
2151 fh->width = f->fmt.pix.width;
2152 fh->height = f->fmt.pix.height;
2153 btv->init.fmt = fmt;
2154 btv->init.width = f->fmt.pix.width;
2155 btv->init.height = f->fmt.pix.height;
2156 up(&fh->cap.lock);
2157
2158 return 0;
2159 }
2160 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002161 if (no_overlay > 0) {
2162 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2163 return -EINVAL;
2164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 return setup_window(fh, btv, &f->fmt.win, 1);
2166 case V4L2_BUF_TYPE_VBI_CAPTURE:
2167 retval = bttv_switch_type(fh,f->type);
2168 if (0 != retval)
2169 return retval;
2170 if (locked_btres(fh->btv, RESOURCE_VBI))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002171 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 bttv_vbi_try_fmt(fh,f);
2173 bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
2174 bttv_vbi_get_fmt(fh,f);
2175 return 0;
2176 default:
2177 return -EINVAL;
2178 }
2179}
2180
2181static int bttv_do_ioctl(struct inode *inode, struct file *file,
2182 unsigned int cmd, void *arg)
2183{
2184 struct bttv_fh *fh = file->private_data;
2185 struct bttv *btv = fh->btv;
2186 unsigned long flags;
2187 int retval = 0;
2188
2189 if (bttv_debug > 1) {
2190 switch (_IOC_TYPE(cmd)) {
2191 case 'v':
2192 printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n",
2193 btv->c.nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ?
2194 v4l1_ioctls[_IOC_NR(cmd)] : "???");
2195 break;
2196 case 'V':
2197 printk("bttv%d: ioctl 0x%x (v4l2, %s)\n",
2198 btv->c.nr, cmd, v4l2_ioctl_names[_IOC_NR(cmd)]);
2199 break;
2200 default:
2201 printk("bttv%d: ioctl 0x%x (???)\n",
2202 btv->c.nr, cmd);
2203 }
2204 }
2205 if (btv->errors)
2206 bttv_reinit_bt848(btv);
2207
2208 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002209 case VIDIOCSFREQ:
2210 case VIDIOCSTUNER:
2211 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 case VIDIOC_S_CTRL:
2213 case VIDIOC_S_STD:
2214 case VIDIOC_S_INPUT:
2215 case VIDIOC_S_TUNER:
2216 case VIDIOC_S_FREQUENCY:
2217 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2218 if (0 != retval)
2219 return retval;
2220 };
2221
2222 switch (cmd) {
2223
2224 /* *** v4l1 *** ************************************************ */
2225 case VIDIOCGCAP:
2226 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002227 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
2229 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002230 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2232 /* vbi */
2233 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2234 } else {
2235 /* others */
2236 cap->type = VID_TYPE_CAPTURE|
2237 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 VID_TYPE_CLIPPING|
2239 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002240 if (no_overlay <= 0)
2241 cap->type |= VID_TYPE_OVERLAY;
2242
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2244 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2245 cap->minwidth = 48;
2246 cap->minheight = 32;
2247 }
2248 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2249 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002250 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 }
2252
2253 case VIDIOCGPICT:
2254 {
2255 struct video_picture *pic = arg;
2256
2257 memset(pic,0,sizeof(*pic));
2258 pic->brightness = btv->bright;
2259 pic->contrast = btv->contrast;
2260 pic->hue = btv->hue;
2261 pic->colour = btv->saturation;
2262 if (fh->fmt) {
2263 pic->depth = fh->fmt->depth;
2264 pic->palette = fh->fmt->palette;
2265 }
2266 return 0;
2267 }
2268 case VIDIOCSPICT:
2269 {
2270 struct video_picture *pic = arg;
2271 const struct bttv_format *fmt;
2272
2273 fmt = format_by_palette(pic->palette);
2274 if (NULL == fmt)
2275 return -EINVAL;
2276 down(&fh->cap.lock);
2277 if (fmt->depth != pic->depth) {
2278 retval = -EINVAL;
2279 goto fh_unlock_and_return;
2280 }
2281 fh->ovfmt = fmt;
2282 fh->fmt = fmt;
2283 btv->init.ovfmt = fmt;
2284 btv->init.fmt = fmt;
2285 if (bigendian) {
2286 /* dirty hack time: swap bytes for overlay if the
2287 display adaptor is big endian (insmod option) */
2288 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2289 fmt->palette == VIDEO_PALETTE_RGB565 ||
2290 fmt->palette == VIDEO_PALETTE_RGB32) {
2291 fh->ovfmt = fmt+1;
2292 }
2293 }
2294 bt848_bright(btv,pic->brightness);
2295 bt848_contrast(btv,pic->contrast);
2296 bt848_hue(btv,pic->hue);
2297 bt848_sat(btv,pic->colour);
2298 up(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002299 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 }
2301
2302 case VIDIOCGWIN:
2303 {
2304 struct video_window *win = arg;
2305
2306 memset(win,0,sizeof(*win));
2307 win->x = fh->ov.w.left;
2308 win->y = fh->ov.w.top;
2309 win->width = fh->ov.w.width;
2310 win->height = fh->ov.w.height;
2311 return 0;
2312 }
2313 case VIDIOCSWIN:
2314 {
2315 struct video_window *win = arg;
2316 struct v4l2_window w2;
2317
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002318 if (no_overlay > 0) {
2319 printk ("VIDIOCSWIN: no_overlay\n");
2320 return -EINVAL;
2321 }
2322
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 w2.field = V4L2_FIELD_ANY;
2324 w2.w.left = win->x;
2325 w2.w.top = win->y;
2326 w2.w.width = win->width;
2327 w2.w.height = win->height;
2328 w2.clipcount = win->clipcount;
2329 w2.clips = (struct v4l2_clip __user *)win->clips;
2330 retval = setup_window(fh, btv, &w2, 0);
2331 if (0 == retval) {
2332 /* on v4l1 this ioctl affects the read() size too */
2333 fh->width = fh->ov.w.width;
2334 fh->height = fh->ov.w.height;
2335 btv->init.width = fh->ov.w.width;
2336 btv->init.height = fh->ov.w.height;
2337 }
2338 return retval;
2339 }
2340
2341 case VIDIOCGFBUF:
2342 {
2343 struct video_buffer *fbuf = arg;
2344
2345 fbuf->base = btv->fbuf.base;
2346 fbuf->width = btv->fbuf.fmt.width;
2347 fbuf->height = btv->fbuf.fmt.height;
2348 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2349 if (fh->ovfmt)
2350 fbuf->depth = fh->ovfmt->depth;
2351 return 0;
2352 }
2353 case VIDIOCSFBUF:
2354 {
2355 struct video_buffer *fbuf = arg;
2356 const struct bttv_format *fmt;
2357 unsigned long end;
2358
2359 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002360 !capable(CAP_SYS_RAWIO))
2361 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 end = (unsigned long)fbuf->base +
2363 fbuf->height * fbuf->bytesperline;
2364 down(&fh->cap.lock);
2365 retval = -EINVAL;
2366
2367 switch (fbuf->depth) {
2368 case 8:
2369 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2370 break;
2371 case 16:
2372 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2373 break;
2374 case 24:
2375 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2376 break;
2377 case 32:
2378 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2379 break;
2380 case 15:
2381 fbuf->depth = 16;
2382 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2383 break;
2384 default:
2385 fmt = NULL;
2386 break;
2387 }
2388 if (NULL == fmt)
2389 goto fh_unlock_and_return;
2390
2391 fh->ovfmt = fmt;
2392 fh->fmt = fmt;
2393 btv->init.ovfmt = fmt;
2394 btv->init.fmt = fmt;
2395 btv->fbuf.base = fbuf->base;
2396 btv->fbuf.fmt.width = fbuf->width;
2397 btv->fbuf.fmt.height = fbuf->height;
2398 if (fbuf->bytesperline)
2399 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
2400 else
2401 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
2402 up(&fh->cap.lock);
2403 return 0;
2404 }
2405
2406 case VIDIOCCAPTURE:
2407 case VIDIOC_OVERLAY:
2408 {
2409 struct bttv_buffer *new;
2410 int *on = arg;
2411
2412 if (*on) {
2413 /* verify args */
2414 if (NULL == btv->fbuf.base)
2415 return -EINVAL;
2416 if (!fh->ov.setup_ok) {
2417 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2418 return -EINVAL;
2419 }
2420 }
2421
2422 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2423 return -EBUSY;
2424
2425 down(&fh->cap.lock);
2426 if (*on) {
2427 fh->ov.tvnorm = btv->tvnorm;
2428 new = videobuf_alloc(sizeof(*new));
2429 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2430 } else {
2431 new = NULL;
2432 }
2433
2434 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002435 retval = bttv_switch_overlay(btv,fh,new);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 up(&fh->cap.lock);
2437 return retval;
2438 }
2439
2440 case VIDIOCGMBUF:
2441 {
2442 struct video_mbuf *mbuf = arg;
2443 unsigned int i;
2444
2445 down(&fh->cap.lock);
2446 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2447 V4L2_MEMORY_MMAP);
2448 if (retval < 0)
2449 goto fh_unlock_and_return;
2450 memset(mbuf,0,sizeof(*mbuf));
2451 mbuf->frames = gbuffers;
2452 mbuf->size = gbuffers * gbufsize;
2453 for (i = 0; i < gbuffers; i++)
2454 mbuf->offsets[i] = i * gbufsize;
2455 up(&fh->cap.lock);
2456 return 0;
2457 }
2458 case VIDIOCMCAPTURE:
2459 {
2460 struct video_mmap *vm = arg;
2461 struct bttv_buffer *buf;
2462 enum v4l2_field field;
2463
2464 if (vm->frame >= VIDEO_MAX_FRAME)
2465 return -EINVAL;
2466
2467 down(&fh->cap.lock);
2468 retval = -EINVAL;
2469 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
2470 if (NULL == buf)
2471 goto fh_unlock_and_return;
2472 if (0 == buf->vb.baddr)
2473 goto fh_unlock_and_return;
2474 if (buf->vb.state == STATE_QUEUED ||
2475 buf->vb.state == STATE_ACTIVE)
2476 goto fh_unlock_and_return;
2477
2478 field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
2479 ? V4L2_FIELD_INTERLACED
2480 : V4L2_FIELD_BOTTOM;
2481 retval = bttv_prepare_buffer(btv,buf,
2482 format_by_palette(vm->format),
2483 vm->width,vm->height,field);
2484 if (0 != retval)
2485 goto fh_unlock_and_return;
2486 spin_lock_irqsave(&btv->s_lock,flags);
2487 buffer_queue(&fh->cap,&buf->vb);
2488 spin_unlock_irqrestore(&btv->s_lock,flags);
2489 up(&fh->cap.lock);
2490 return 0;
2491 }
2492 case VIDIOCSYNC:
2493 {
2494 int *frame = arg;
2495 struct bttv_buffer *buf;
2496
2497 if (*frame >= VIDEO_MAX_FRAME)
2498 return -EINVAL;
2499
2500 down(&fh->cap.lock);
2501 retval = -EINVAL;
2502 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
2503 if (NULL == buf)
2504 goto fh_unlock_and_return;
2505 retval = videobuf_waiton(&buf->vb,0,1);
2506 if (0 != retval)
2507 goto fh_unlock_and_return;
2508 switch (buf->vb.state) {
2509 case STATE_ERROR:
2510 retval = -EIO;
2511 /* fall through */
2512 case STATE_DONE:
2513 videobuf_dma_pci_sync(btv->c.pci,&buf->vb.dma);
2514 bttv_dma_free(btv,buf);
2515 break;
2516 default:
2517 retval = -EINVAL;
2518 break;
2519 }
2520 up(&fh->cap.lock);
2521 return retval;
2522 }
2523
2524 case VIDIOCGVBIFMT:
2525 {
2526 struct vbi_format *fmt = (void *) arg;
2527 struct v4l2_format fmt2;
2528
2529 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
2530 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2531 if (0 != retval)
2532 return retval;
2533 }
2534 bttv_vbi_get_fmt(fh, &fmt2);
2535
2536 memset(fmt,0,sizeof(*fmt));
2537 fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
2538 fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
2539 fmt->sample_format = VIDEO_PALETTE_RAW;
2540 fmt->start[0] = fmt2.fmt.vbi.start[0];
2541 fmt->count[0] = fmt2.fmt.vbi.count[0];
2542 fmt->start[1] = fmt2.fmt.vbi.start[1];
2543 fmt->count[1] = fmt2.fmt.vbi.count[1];
2544 if (fmt2.fmt.vbi.flags & VBI_UNSYNC)
2545 fmt->flags |= V4L2_VBI_UNSYNC;
2546 if (fmt2.fmt.vbi.flags & VBI_INTERLACED)
2547 fmt->flags |= V4L2_VBI_INTERLACED;
2548 return 0;
2549 }
2550 case VIDIOCSVBIFMT:
2551 {
2552 struct vbi_format *fmt = (void *) arg;
2553 struct v4l2_format fmt2;
2554
2555 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2556 if (0 != retval)
2557 return retval;
2558 bttv_vbi_get_fmt(fh, &fmt2);
2559
2560 if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
2561 fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
2562 fmt->sample_format != VIDEO_PALETTE_RAW ||
2563 fmt->start[0] != fmt2.fmt.vbi.start[0] ||
2564 fmt->start[1] != fmt2.fmt.vbi.start[1] ||
2565 fmt->count[0] != fmt->count[1] ||
2566 fmt->count[0] < 1 ||
2567 fmt->count[0] > 32 /* VBI_MAXLINES */)
2568 return -EINVAL;
2569
2570 bttv_vbi_setlines(fh,btv,fmt->count[0]);
2571 return 0;
2572 }
2573
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002574 case BTTV_VERSION:
2575 case VIDIOCGFREQ:
2576 case VIDIOCSFREQ:
2577 case VIDIOCGTUNER:
2578 case VIDIOCSTUNER:
2579 case VIDIOCGCHAN:
2580 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 case VIDIOCGAUDIO:
2582 case VIDIOCSAUDIO:
2583 return bttv_common_ioctls(btv,cmd,arg);
2584
2585 /* *** v4l2 *** ************************************************ */
2586 case VIDIOC_QUERYCAP:
2587 {
2588 struct v4l2_capability *cap = arg;
2589
2590 if (0 == v4l2)
2591 return -EINVAL;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002592 strcpy(cap->driver,"bttv");
2593 strlcpy(cap->card,btv->video_dev->name,sizeof(cap->card));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci));
2595 cap->version = BTTV_VERSION_CODE;
2596 cap->capabilities =
2597 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 V4L2_CAP_VBI_CAPTURE |
2599 V4L2_CAP_READWRITE |
2600 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002601 if (no_overlay <= 0)
2602 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2605 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2606 cap->capabilities |= V4L2_CAP_TUNER;
2607 return 0;
2608 }
2609
2610 case VIDIOC_ENUM_FMT:
2611 {
2612 struct v4l2_fmtdesc *f = arg;
2613 enum v4l2_buf_type type;
2614 unsigned int i;
2615 int index;
2616
2617 type = f->type;
2618 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2619 /* vbi */
2620 index = f->index;
2621 if (0 != index)
2622 return -EINVAL;
2623 memset(f,0,sizeof(*f));
2624 f->index = index;
2625 f->type = type;
2626 f->pixelformat = V4L2_PIX_FMT_GREY;
2627 strcpy(f->description,"vbi data");
2628 return 0;
2629 }
2630
2631 /* video capture + overlay */
2632 index = -1;
2633 for (i = 0; i < BTTV_FORMATS; i++) {
2634 if (bttv_formats[i].fourcc != -1)
2635 index++;
2636 if ((unsigned int)index == f->index)
2637 break;
2638 }
2639 if (BTTV_FORMATS == i)
2640 return -EINVAL;
2641
2642 switch (f->type) {
2643 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2644 break;
2645 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2646 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2647 return -EINVAL;
2648 break;
2649 default:
2650 return -EINVAL;
2651 }
2652 memset(f,0,sizeof(*f));
2653 f->index = index;
2654 f->type = type;
2655 f->pixelformat = bttv_formats[i].fourcc;
2656 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2657 return 0;
2658 }
2659
2660 case VIDIOC_TRY_FMT:
2661 {
2662 struct v4l2_format *f = arg;
2663 return bttv_try_fmt(fh,btv,f);
2664 }
2665 case VIDIOC_G_FMT:
2666 {
2667 struct v4l2_format *f = arg;
2668 return bttv_g_fmt(fh,f);
2669 }
2670 case VIDIOC_S_FMT:
2671 {
2672 struct v4l2_format *f = arg;
2673 return bttv_s_fmt(fh,btv,f);
2674 }
2675
2676 case VIDIOC_G_FBUF:
2677 {
2678 struct v4l2_framebuffer *fb = arg;
2679
2680 *fb = btv->fbuf;
2681 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2682 if (fh->ovfmt)
2683 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2684 return 0;
2685 }
2686 case VIDIOC_S_FBUF:
2687 {
2688 struct v4l2_framebuffer *fb = arg;
2689 const struct bttv_format *fmt;
2690
2691 if(!capable(CAP_SYS_ADMIN) &&
2692 !capable(CAP_SYS_RAWIO))
2693 return -EPERM;
2694
2695 /* check args */
2696 fmt = format_by_fourcc(fb->fmt.pixelformat);
2697 if (NULL == fmt)
2698 return -EINVAL;
2699 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2700 return -EINVAL;
2701
2702 down(&fh->cap.lock);
2703 retval = -EINVAL;
2704 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2705 if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
2706 goto fh_unlock_and_return;
2707 if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
2708 goto fh_unlock_and_return;
2709 }
2710
2711 /* ok, accept it */
2712 btv->fbuf.base = fb->base;
2713 btv->fbuf.fmt.width = fb->fmt.width;
2714 btv->fbuf.fmt.height = fb->fmt.height;
2715 if (0 != fb->fmt.bytesperline)
2716 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2717 else
2718 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2719
2720 retval = 0;
2721 fh->ovfmt = fmt;
2722 btv->init.ovfmt = fmt;
2723 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2724 fh->ov.w.left = 0;
2725 fh->ov.w.top = 0;
2726 fh->ov.w.width = fb->fmt.width;
2727 fh->ov.w.height = fb->fmt.height;
2728 btv->init.ov.w.width = fb->fmt.width;
2729 btv->init.ov.w.height = fb->fmt.height;
Jesper Juhl2ea75332005-11-07 01:01:31 -08002730 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 fh->ov.clips = NULL;
2732 fh->ov.nclips = 0;
2733
2734 if (check_btres(fh, RESOURCE_OVERLAY)) {
2735 struct bttv_buffer *new;
2736
2737 new = videobuf_alloc(sizeof(*new));
2738 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2739 retval = bttv_switch_overlay(btv,fh,new);
2740 }
2741 }
2742 up(&fh->cap.lock);
2743 return retval;
2744 }
2745
2746 case VIDIOC_REQBUFS:
2747 return videobuf_reqbufs(bttv_queue(fh),arg);
2748
2749 case VIDIOC_QUERYBUF:
2750 return videobuf_querybuf(bttv_queue(fh),arg);
2751
2752 case VIDIOC_QBUF:
2753 return videobuf_qbuf(bttv_queue(fh),arg);
2754
2755 case VIDIOC_DQBUF:
2756 return videobuf_dqbuf(bttv_queue(fh),arg,
2757 file->f_flags & O_NONBLOCK);
2758
2759 case VIDIOC_STREAMON:
2760 {
2761 int res = bttv_resource(fh);
2762
2763 if (!check_alloc_btres(btv,fh,res))
2764 return -EBUSY;
2765 return videobuf_streamon(bttv_queue(fh));
2766 }
2767 case VIDIOC_STREAMOFF:
2768 {
2769 int res = bttv_resource(fh);
2770
2771 retval = videobuf_streamoff(bttv_queue(fh));
2772 if (retval < 0)
2773 return retval;
2774 free_btres(btv,fh,res);
2775 return 0;
2776 }
2777
2778 case VIDIOC_QUERYCTRL:
2779 {
2780 struct v4l2_queryctrl *c = arg;
2781 int i;
2782
2783 if ((c->id < V4L2_CID_BASE ||
2784 c->id >= V4L2_CID_LASTP1) &&
2785 (c->id < V4L2_CID_PRIVATE_BASE ||
2786 c->id >= V4L2_CID_PRIVATE_LASTP1))
2787 return -EINVAL;
2788 for (i = 0; i < BTTV_CTLS; i++)
2789 if (bttv_ctls[i].id == c->id)
2790 break;
2791 if (i == BTTV_CTLS) {
2792 *c = no_ctl;
2793 return 0;
2794 }
2795 *c = bttv_ctls[i];
2796 if (i >= 4 && i <= 8) {
2797 struct video_audio va;
2798 memset(&va,0,sizeof(va));
2799 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
2800 if (btv->audio_hook)
2801 btv->audio_hook(btv,&va,0);
2802 switch (bttv_ctls[i].id) {
2803 case V4L2_CID_AUDIO_VOLUME:
2804 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2805 *c = no_ctl;
2806 break;
2807 case V4L2_CID_AUDIO_BALANCE:
2808 if (!(va.flags & VIDEO_AUDIO_BALANCE))
2809 *c = no_ctl;
2810 break;
2811 case V4L2_CID_AUDIO_BASS:
2812 if (!(va.flags & VIDEO_AUDIO_BASS))
2813 *c = no_ctl;
2814 break;
2815 case V4L2_CID_AUDIO_TREBLE:
2816 if (!(va.flags & VIDEO_AUDIO_TREBLE))
2817 *c = no_ctl;
2818 break;
2819 }
2820 }
2821 return 0;
2822 }
2823 case VIDIOC_G_CTRL:
2824 return get_control(btv,arg);
2825 case VIDIOC_S_CTRL:
2826 return set_control(btv,arg);
2827 case VIDIOC_G_PARM:
2828 {
2829 struct v4l2_streamparm *parm = arg;
2830 struct v4l2_standard s;
2831 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2832 return -EINVAL;
2833 memset(parm,0,sizeof(*parm));
2834 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2835 bttv_tvnorms[btv->tvnorm].name);
2836 parm->parm.capture.timeperframe = s.frameperiod;
2837 return 0;
2838 }
2839
2840 case VIDIOC_G_PRIORITY:
2841 {
2842 enum v4l2_priority *p = arg;
2843
2844 *p = v4l2_prio_max(&btv->prio);
2845 return 0;
2846 }
2847 case VIDIOC_S_PRIORITY:
2848 {
2849 enum v4l2_priority *prio = arg;
2850
2851 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
2852 }
2853
2854 case VIDIOC_ENUMSTD:
2855 case VIDIOC_G_STD:
2856 case VIDIOC_S_STD:
2857 case VIDIOC_ENUMINPUT:
2858 case VIDIOC_G_INPUT:
2859 case VIDIOC_S_INPUT:
2860 case VIDIOC_G_TUNER:
2861 case VIDIOC_S_TUNER:
2862 case VIDIOC_G_FREQUENCY:
2863 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08002864 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 return bttv_common_ioctls(btv,cmd,arg);
2866
2867 default:
2868 return -ENOIOCTLCMD;
2869 }
2870 return 0;
2871
2872 fh_unlock_and_return:
2873 up(&fh->cap.lock);
2874 return retval;
2875}
2876
2877static int bttv_ioctl(struct inode *inode, struct file *file,
2878 unsigned int cmd, unsigned long arg)
2879{
2880 struct bttv_fh *fh = file->private_data;
2881
2882 switch (cmd) {
2883 case BTTV_VBISIZE:
2884 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2885 return fh->lines * 2 * 2048;
2886 default:
2887 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
2888 }
2889}
2890
2891static ssize_t bttv_read(struct file *file, char __user *data,
2892 size_t count, loff_t *ppos)
2893{
2894 struct bttv_fh *fh = file->private_data;
2895 int retval = 0;
2896
2897 if (fh->btv->errors)
2898 bttv_reinit_bt848(fh->btv);
2899 dprintk("bttv%d: read count=%d type=%s\n",
2900 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
2901
2902 switch (fh->type) {
2903 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2904 if (locked_btres(fh->btv,RESOURCE_VIDEO))
2905 return -EBUSY;
2906 retval = videobuf_read_one(&fh->cap, data, count, ppos,
2907 file->f_flags & O_NONBLOCK);
2908 break;
2909 case V4L2_BUF_TYPE_VBI_CAPTURE:
2910 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2911 return -EBUSY;
2912 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
2913 file->f_flags & O_NONBLOCK);
2914 break;
2915 default:
2916 BUG();
2917 }
2918 return retval;
2919}
2920
2921static unsigned int bttv_poll(struct file *file, poll_table *wait)
2922{
2923 struct bttv_fh *fh = file->private_data;
2924 struct bttv_buffer *buf;
2925 enum v4l2_field field;
2926
2927 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2928 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2929 return POLLERR;
2930 return videobuf_poll_stream(file, &fh->vbi, wait);
2931 }
2932
2933 if (check_btres(fh,RESOURCE_VIDEO)) {
2934 /* streaming capture */
2935 if (list_empty(&fh->cap.stream))
2936 return POLLERR;
2937 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
2938 } else {
2939 /* read() capture */
2940 down(&fh->cap.lock);
2941 if (NULL == fh->cap.read_buf) {
2942 /* need to capture a new frame */
2943 if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
2944 up(&fh->cap.lock);
2945 return POLLERR;
2946 }
2947 fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
2948 if (NULL == fh->cap.read_buf) {
2949 up(&fh->cap.lock);
2950 return POLLERR;
2951 }
2952 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
2953 field = videobuf_next_field(&fh->cap);
2954 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08002955 kfree (fh->cap.read_buf);
2956 fh->cap.read_buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 up(&fh->cap.lock);
2958 return POLLERR;
2959 }
2960 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
2961 fh->cap.read_off = 0;
2962 }
2963 up(&fh->cap.lock);
2964 buf = (struct bttv_buffer*)fh->cap.read_buf;
2965 }
2966
2967 poll_wait(file, &buf->vb.done, wait);
2968 if (buf->vb.state == STATE_DONE ||
2969 buf->vb.state == STATE_ERROR)
2970 return POLLIN|POLLRDNORM;
2971 return 0;
2972}
2973
2974static int bttv_open(struct inode *inode, struct file *file)
2975{
2976 int minor = iminor(inode);
2977 struct bttv *btv = NULL;
2978 struct bttv_fh *fh;
2979 enum v4l2_buf_type type = 0;
2980 unsigned int i;
2981
2982 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
2983
2984 for (i = 0; i < bttv_num; i++) {
2985 if (bttvs[i].video_dev &&
2986 bttvs[i].video_dev->minor == minor) {
2987 btv = &bttvs[i];
2988 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2989 break;
2990 }
2991 if (bttvs[i].vbi_dev &&
2992 bttvs[i].vbi_dev->minor == minor) {
2993 btv = &bttvs[i];
2994 type = V4L2_BUF_TYPE_VBI_CAPTURE;
2995 break;
2996 }
2997 }
2998 if (NULL == btv)
2999 return -ENODEV;
3000
3001 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3002 btv->c.nr,v4l2_type_names[type]);
3003
3004 /* allocate per filehandle data */
3005 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3006 if (NULL == fh)
3007 return -ENOMEM;
3008 file->private_data = fh;
3009 *fh = btv->init;
3010 fh->type = type;
3011 fh->ov.setup_ok = 0;
3012 v4l2_prio_open(&btv->prio,&fh->prio);
3013
3014 videobuf_queue_init(&fh->cap, &bttv_video_qops,
3015 btv->c.pci, &btv->s_lock,
3016 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3017 V4L2_FIELD_INTERLACED,
3018 sizeof(struct bttv_buffer),
3019 fh);
3020 videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
3021 btv->c.pci, &btv->s_lock,
3022 V4L2_BUF_TYPE_VBI_CAPTURE,
3023 V4L2_FIELD_SEQ_TB,
3024 sizeof(struct bttv_buffer),
3025 fh);
3026 i2c_vidiocschan(btv);
3027
3028 btv->users++;
3029 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
3030 bttv_vbi_setlines(fh,btv,16);
3031 bttv_field_count(btv);
3032 return 0;
3033}
3034
3035static int bttv_release(struct inode *inode, struct file *file)
3036{
3037 struct bttv_fh *fh = file->private_data;
3038 struct bttv *btv = fh->btv;
3039
3040 /* turn off overlay */
3041 if (check_btres(fh, RESOURCE_OVERLAY))
3042 bttv_switch_overlay(btv,fh,NULL);
3043
3044 /* stop video capture */
3045 if (check_btres(fh, RESOURCE_VIDEO)) {
3046 videobuf_streamoff(&fh->cap);
3047 free_btres(btv,fh,RESOURCE_VIDEO);
3048 }
3049 if (fh->cap.read_buf) {
3050 buffer_release(&fh->cap,fh->cap.read_buf);
3051 kfree(fh->cap.read_buf);
3052 }
3053
3054 /* stop vbi capture */
3055 if (check_btres(fh, RESOURCE_VBI)) {
3056 if (fh->vbi.streaming)
3057 videobuf_streamoff(&fh->vbi);
3058 if (fh->vbi.reading)
3059 videobuf_read_stop(&fh->vbi);
3060 free_btres(btv,fh,RESOURCE_VBI);
3061 }
3062
3063 /* free stuff */
3064 videobuf_mmap_free(&fh->cap);
3065 videobuf_mmap_free(&fh->vbi);
3066 v4l2_prio_close(&btv->prio,&fh->prio);
3067 file->private_data = NULL;
3068 kfree(fh);
3069
3070 btv->users--;
3071 bttv_field_count(btv);
3072 return 0;
3073}
3074
3075static int
3076bttv_mmap(struct file *file, struct vm_area_struct *vma)
3077{
3078 struct bttv_fh *fh = file->private_data;
3079
3080 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3081 fh->btv->c.nr, v4l2_type_names[fh->type],
3082 vma->vm_start, vma->vm_end - vma->vm_start);
3083 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3084}
3085
3086static struct file_operations bttv_fops =
3087{
3088 .owner = THIS_MODULE,
3089 .open = bttv_open,
3090 .release = bttv_release,
3091 .ioctl = bttv_ioctl,
3092 .llseek = no_llseek,
3093 .read = bttv_read,
3094 .mmap = bttv_mmap,
3095 .poll = bttv_poll,
3096};
3097
3098static struct video_device bttv_video_template =
3099{
3100 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003101 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003102 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 .hardware = VID_HARDWARE_BT848,
3104 .fops = &bttv_fops,
3105 .minor = -1,
3106};
3107
3108static struct video_device bttv_vbi_template =
3109{
3110 .name = "bt848/878 vbi",
3111 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
3112 .hardware = VID_HARDWARE_BT848,
3113 .fops = &bttv_fops,
3114 .minor = -1,
3115};
3116
3117/* ----------------------------------------------------------------------- */
3118/* radio interface */
3119
3120static int radio_open(struct inode *inode, struct file *file)
3121{
3122 int minor = iminor(inode);
3123 struct bttv *btv = NULL;
3124 unsigned int i;
3125
3126 dprintk("bttv: open minor=%d\n",minor);
3127
3128 for (i = 0; i < bttv_num; i++) {
3129 if (bttvs[i].radio_dev->minor == minor) {
3130 btv = &bttvs[i];
3131 break;
3132 }
3133 }
3134 if (NULL == btv)
3135 return -ENODEV;
3136
3137 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
3138 down(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003139
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003141
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 file->private_data = btv;
3143
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003144 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 audio_mux(btv,AUDIO_RADIO);
3146
3147 up(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003148 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149}
3150
3151static int radio_release(struct inode *inode, struct file *file)
3152{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003153 struct bttv *btv = file->private_data;
3154 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
3156 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003157
3158 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3159
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 return 0;
3161}
3162
3163static int radio_do_ioctl(struct inode *inode, struct file *file,
3164 unsigned int cmd, void *arg)
3165{
3166 struct bttv *btv = file->private_data;
3167
3168 switch (cmd) {
3169 case VIDIOCGCAP:
3170 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003171 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
3173 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003174 strcpy(cap->name,btv->radio_dev->name);
3175 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 cap->channels = 1;
3177 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003178 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 }
3180
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003181 case VIDIOCGTUNER:
3182 {
3183 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003185 if(v->tuner)
3186 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003188 strcpy(v->name, "Radio");
3189 bttv_call_i2c_clients(btv,cmd,v);
3190 return 0;
3191 }
3192 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 /* nothing to do */
3194 return 0;
3195
3196 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003197 case VIDIOCGFREQ:
3198 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 case VIDIOCGAUDIO:
3200 case VIDIOCSAUDIO:
3201 return bttv_common_ioctls(btv,cmd,arg);
3202
3203 default:
3204 return -ENOIOCTLCMD;
3205 }
3206 return 0;
3207}
3208
3209static int radio_ioctl(struct inode *inode, struct file *file,
3210 unsigned int cmd, unsigned long arg)
3211{
3212 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3213}
3214
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003215static ssize_t radio_read(struct file *file, char __user *data,
3216 size_t count, loff_t *ppos)
3217{
3218 struct bttv *btv = file->private_data;
3219 struct rds_command cmd;
3220 cmd.block_count = count/3;
3221 cmd.buffer = data;
3222 cmd.instance = file;
3223 cmd.result = -ENODEV;
3224
3225 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3226
3227 return cmd.result;
3228}
3229
3230static unsigned int radio_poll(struct file *file, poll_table *wait)
3231{
3232 struct bttv *btv = file->private_data;
3233 struct rds_command cmd;
3234 cmd.instance = file;
3235 cmd.event_list = wait;
3236 cmd.result = -ENODEV;
3237 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3238
3239 return cmd.result;
3240}
3241
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242static struct file_operations radio_fops =
3243{
3244 .owner = THIS_MODULE,
3245 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003246 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247 .release = radio_release,
3248 .ioctl = radio_ioctl,
3249 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003250 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251};
3252
3253static struct video_device radio_template =
3254{
3255 .name = "bt848/878 radio",
3256 .type = VID_TYPE_TUNER,
3257 .hardware = VID_HARDWARE_BT848,
3258 .fops = &radio_fops,
3259 .minor = -1,
3260};
3261
3262/* ----------------------------------------------------------------------- */
3263/* some debug code */
3264
Adrian Bunk408b6642005-05-01 08:59:29 -07003265static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266{
3267 static char *instr[16] = {
3268 [ BT848_RISC_WRITE >> 28 ] = "write",
3269 [ BT848_RISC_SKIP >> 28 ] = "skip",
3270 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3271 [ BT848_RISC_JUMP >> 28 ] = "jump",
3272 [ BT848_RISC_SYNC >> 28 ] = "sync",
3273 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3274 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3275 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3276 };
3277 static int incr[16] = {
3278 [ BT848_RISC_WRITE >> 28 ] = 2,
3279 [ BT848_RISC_JUMP >> 28 ] = 2,
3280 [ BT848_RISC_SYNC >> 28 ] = 2,
3281 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3282 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3283 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3284 };
3285 static char *bits[] = {
3286 "be0", "be1", "be2", "be3/resync",
3287 "set0", "set1", "set2", "set3",
3288 "clr0", "clr1", "clr2", "clr3",
3289 "irq", "res", "eol", "sol",
3290 };
3291 int i;
3292
3293 printk("0x%08x [ %s", risc,
3294 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3295 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3296 if (risc & (1 << (i + 12)))
3297 printk(" %s",bits[i]);
3298 printk(" count=%d ]\n", risc & 0xfff);
3299 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3300}
3301
Adrian Bunk408b6642005-05-01 08:59:29 -07003302static void bttv_risc_disasm(struct bttv *btv,
3303 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304{
3305 unsigned int i,j,n;
3306
3307 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3308 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3309 for (i = 0; i < (risc->size >> 2); i += n) {
3310 printk("%s: 0x%lx: ", btv->c.name,
3311 (unsigned long)(risc->dma + (i<<2)));
3312 n = bttv_risc_decode(risc->cpu[i]);
3313 for (j = 1; j < n; j++)
3314 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3315 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3316 risc->cpu[i+j], j);
3317 if (0 == risc->cpu[i])
3318 break;
3319 }
3320}
3321
3322static void bttv_print_riscaddr(struct bttv *btv)
3323{
3324 printk(" main: %08Lx\n",
3325 (unsigned long long)btv->main.dma);
3326 printk(" vbi : o=%08Lx e=%08Lx\n",
3327 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3328 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3329 printk(" cap : o=%08Lx e=%08Lx\n",
3330 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3331 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3332 printk(" scr : o=%08Lx e=%08Lx\n",
3333 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3334 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3335 bttv_risc_disasm(btv, &btv->main);
3336}
3337
3338/* ----------------------------------------------------------------------- */
3339/* irq handler */
3340
3341static char *irq_name[] = {
3342 "FMTCHG", // format change detected (525 vs. 625)
3343 "VSYNC", // vertical sync (new field)
3344 "HSYNC", // horizontal sync
3345 "OFLOW", // chroma/luma AGC overflow
3346 "HLOCK", // horizontal lock changed
3347 "VPRES", // video presence changed
3348 "6", "7",
3349 "I2CDONE", // hw irc operation finished
3350 "GPINT", // gpio port triggered irq
3351 "10",
3352 "RISCI", // risc instruction triggered irq
3353 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3354 "FTRGT", // pixel data fifo overrun
3355 "FDSR", // fifo data stream resyncronisation
3356 "PPERR", // parity error (data transfer)
3357 "RIPERR", // parity error (read risc instructions)
3358 "PABORT", // pci abort
3359 "OCERR", // risc instruction error
3360 "SCERR", // syncronisation error
3361};
3362
3363static void bttv_print_irqbits(u32 print, u32 mark)
3364{
3365 unsigned int i;
3366
3367 printk("bits:");
3368 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3369 if (print & (1 << i))
3370 printk(" %s",irq_name[i]);
3371 if (mark & (1 << i))
3372 printk("*");
3373 }
3374}
3375
3376static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3377{
3378 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3379 btv->c.nr,
3380 (unsigned long)btv->main.dma,
3381 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3382 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3383 (unsigned long)rc);
3384
3385 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3386 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3387 "Ok, then this is harmless, don't worry ;)\n",
3388 btv->c.nr);
3389 return;
3390 }
3391 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3392 btv->c.nr);
3393 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3394 btv->c.nr);
3395 dump_stack();
3396}
3397
3398static int
3399bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3400{
3401 struct bttv_buffer *item;
3402
3403 memset(set,0,sizeof(*set));
3404
3405 /* capture request ? */
3406 if (!list_empty(&btv->capture)) {
3407 set->frame_irq = 1;
3408 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3409 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3410 set->top = item;
3411 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3412 set->bottom = item;
3413
3414 /* capture request for other field ? */
3415 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3416 (item->vb.queue.next != &btv->capture)) {
3417 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3418 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3419 if (NULL == set->top &&
3420 V4L2_FIELD_TOP == item->vb.field) {
3421 set->top = item;
3422 }
3423 if (NULL == set->bottom &&
3424 V4L2_FIELD_BOTTOM == item->vb.field) {
3425 set->bottom = item;
3426 }
3427 if (NULL != set->top && NULL != set->bottom)
3428 set->top_irq = 2;
3429 }
3430 }
3431 }
3432
3433 /* screen overlay ? */
3434 if (NULL != btv->screen) {
3435 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3436 if (NULL == set->top && NULL == set->bottom) {
3437 set->top = btv->screen;
3438 set->bottom = btv->screen;
3439 }
3440 } else {
3441 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3442 NULL == set->top) {
3443 set->top = btv->screen;
3444 }
3445 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3446 NULL == set->bottom) {
3447 set->bottom = btv->screen;
3448 }
3449 }
3450 }
3451
3452 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3453 btv->c.nr,set->top, set->bottom,
3454 btv->screen,set->frame_irq,set->top_irq);
3455 return 0;
3456}
3457
3458static void
3459bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3460 struct bttv_buffer_set *curr, unsigned int state)
3461{
3462 struct timeval ts;
3463
3464 do_gettimeofday(&ts);
3465
3466 if (wakeup->top == wakeup->bottom) {
3467 if (NULL != wakeup->top && curr->top != wakeup->top) {
3468 if (irq_debug > 1)
3469 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3470 wakeup->top->vb.ts = ts;
3471 wakeup->top->vb.field_count = btv->field_count;
3472 wakeup->top->vb.state = state;
3473 wake_up(&wakeup->top->vb.done);
3474 }
3475 } else {
3476 if (NULL != wakeup->top && curr->top != wakeup->top) {
3477 if (irq_debug > 1)
3478 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3479 wakeup->top->vb.ts = ts;
3480 wakeup->top->vb.field_count = btv->field_count;
3481 wakeup->top->vb.state = state;
3482 wake_up(&wakeup->top->vb.done);
3483 }
3484 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3485 if (irq_debug > 1)
3486 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3487 wakeup->bottom->vb.ts = ts;
3488 wakeup->bottom->vb.field_count = btv->field_count;
3489 wakeup->bottom->vb.state = state;
3490 wake_up(&wakeup->bottom->vb.done);
3491 }
3492 }
3493}
3494
3495static void
3496bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3497 unsigned int state)
3498{
3499 struct timeval ts;
3500
3501 if (NULL == wakeup)
3502 return;
3503
3504 do_gettimeofday(&ts);
3505 wakeup->vb.ts = ts;
3506 wakeup->vb.field_count = btv->field_count;
3507 wakeup->vb.state = state;
3508 wake_up(&wakeup->vb.done);
3509}
3510
3511static void bttv_irq_timeout(unsigned long data)
3512{
3513 struct bttv *btv = (struct bttv *)data;
3514 struct bttv_buffer_set old,new;
3515 struct bttv_buffer *ovbi;
3516 struct bttv_buffer *item;
3517 unsigned long flags;
3518
3519 if (bttv_verbose) {
3520 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3521 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3522 btread(BT848_RISC_COUNT));
3523 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3524 printk("\n");
3525 }
3526
3527 spin_lock_irqsave(&btv->s_lock,flags);
3528
3529 /* deactivate stuff */
3530 memset(&new,0,sizeof(new));
3531 old = btv->curr;
3532 ovbi = btv->cvbi;
3533 btv->curr = new;
3534 btv->cvbi = NULL;
3535 btv->loop_irq = 0;
3536 bttv_buffer_activate_video(btv, &new);
3537 bttv_buffer_activate_vbi(btv, NULL);
3538 bttv_set_dma(btv, 0);
3539
3540 /* wake up */
3541 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
3542 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
3543
3544 /* cancel all outstanding capture / vbi requests */
3545 while (!list_empty(&btv->capture)) {
3546 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3547 list_del(&item->vb.queue);
3548 item->vb.state = STATE_ERROR;
3549 wake_up(&item->vb.done);
3550 }
3551 while (!list_empty(&btv->vcapture)) {
3552 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3553 list_del(&item->vb.queue);
3554 item->vb.state = STATE_ERROR;
3555 wake_up(&item->vb.done);
3556 }
3557
3558 btv->errors++;
3559 spin_unlock_irqrestore(&btv->s_lock,flags);
3560}
3561
3562static void
3563bttv_irq_wakeup_top(struct bttv *btv)
3564{
3565 struct bttv_buffer *wakeup = btv->curr.top;
3566
3567 if (NULL == wakeup)
3568 return;
3569
3570 spin_lock(&btv->s_lock);
3571 btv->curr.top_irq = 0;
3572 btv->curr.top = NULL;
3573 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3574
3575 do_gettimeofday(&wakeup->vb.ts);
3576 wakeup->vb.field_count = btv->field_count;
3577 wakeup->vb.state = STATE_DONE;
3578 wake_up(&wakeup->vb.done);
3579 spin_unlock(&btv->s_lock);
3580}
3581
3582static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3583{
3584 if (rc < risc->dma)
3585 return 0;
3586 if (rc > risc->dma + risc->size)
3587 return 0;
3588 return 1;
3589}
3590
3591static void
3592bttv_irq_switch_video(struct bttv *btv)
3593{
3594 struct bttv_buffer_set new;
3595 struct bttv_buffer_set old;
3596 dma_addr_t rc;
3597
3598 spin_lock(&btv->s_lock);
3599
3600 /* new buffer set */
3601 bttv_irq_next_video(btv, &new);
3602 rc = btread(BT848_RISC_COUNT);
3603 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3604 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3605 btv->framedrop++;
3606 if (debug_latency)
3607 bttv_irq_debug_low_latency(btv, rc);
3608 spin_unlock(&btv->s_lock);
3609 return;
3610 }
3611
3612 /* switch over */
3613 old = btv->curr;
3614 btv->curr = new;
3615 btv->loop_irq &= ~1;
3616 bttv_buffer_activate_video(btv, &new);
3617 bttv_set_dma(btv, 0);
3618
3619 /* switch input */
3620 if (UNSET != btv->new_input) {
3621 video_mux(btv,btv->new_input);
3622 btv->new_input = UNSET;
3623 }
3624
3625 /* wake up finished buffers */
3626 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
3627 spin_unlock(&btv->s_lock);
3628}
3629
3630static void
3631bttv_irq_switch_vbi(struct bttv *btv)
3632{
3633 struct bttv_buffer *new = NULL;
3634 struct bttv_buffer *old;
3635 u32 rc;
3636
3637 spin_lock(&btv->s_lock);
3638
3639 if (!list_empty(&btv->vcapture))
3640 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3641 old = btv->cvbi;
3642
3643 rc = btread(BT848_RISC_COUNT);
3644 if (NULL != old && (is_active(&old->top, rc) ||
3645 is_active(&old->bottom, rc))) {
3646 btv->framedrop++;
3647 if (debug_latency)
3648 bttv_irq_debug_low_latency(btv, rc);
3649 spin_unlock(&btv->s_lock);
3650 return;
3651 }
3652
3653 /* switch */
3654 btv->cvbi = new;
3655 btv->loop_irq &= ~4;
3656 bttv_buffer_activate_vbi(btv, new);
3657 bttv_set_dma(btv, 0);
3658
3659 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
3660 spin_unlock(&btv->s_lock);
3661}
3662
3663static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
3664{
3665 u32 stat,astat;
3666 u32 dstat;
3667 int count;
3668 struct bttv *btv;
3669 int handled = 0;
3670
3671 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003672
3673 if (btv->any_irq)
3674 handled = bttv_any_irq(&btv->c);
3675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 count=0;
3677 while (1) {
3678 /* get/clear interrupt status bits */
3679 stat=btread(BT848_INT_STAT);
3680 astat=stat&btread(BT848_INT_MASK);
3681 if (!astat)
3682 break;
3683 handled = 1;
3684 btwrite(stat,BT848_INT_STAT);
3685
3686 /* get device status bits */
3687 dstat=btread(BT848_DSTATUS);
3688
3689 if (irq_debug) {
3690 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
3691 "riscs=%x, riscc=%08x, ",
3692 btv->c.nr, count, btv->field_count,
3693 stat>>28, btread(BT848_RISC_COUNT));
3694 bttv_print_irqbits(stat,astat);
3695 if (stat & BT848_INT_HLOCK)
3696 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
3697 ? "yes" : "no");
3698 if (stat & BT848_INT_VPRES)
3699 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
3700 ? "yes" : "no");
3701 if (stat & BT848_INT_FMTCHG)
3702 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
3703 ? "625" : "525");
3704 printk("\n");
3705 }
3706
3707 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003708 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
3710 if (astat & BT848_INT_GPINT) {
3711 wake_up(&btv->gpioq);
3712 bttv_gpio_irq(&btv->c);
3713 }
3714
3715 if (astat & BT848_INT_I2CDONE) {
3716 btv->i2c_done = stat;
3717 wake_up(&btv->i2c_queue);
3718 }
3719
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003720 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 bttv_irq_switch_vbi(btv);
3722
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003723 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 bttv_irq_wakeup_top(btv);
3725
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003726 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 bttv_irq_switch_video(btv);
3728
3729 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
3730 audio_mux(btv, -1);
3731
3732 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
3733 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
3734 (astat & BT848_INT_SCERR) ? "SCERR" : "",
3735 (astat & BT848_INT_OCERR) ? "OCERR" : "",
3736 btread(BT848_RISC_COUNT));
3737 bttv_print_irqbits(stat,astat);
3738 printk("\n");
3739 if (bttv_debug)
3740 bttv_print_riscaddr(btv);
3741 }
3742 if (fdsr && astat & BT848_INT_FDSR) {
3743 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
3744 btv->c.nr,btread(BT848_RISC_COUNT));
3745 if (bttv_debug)
3746 bttv_print_riscaddr(btv);
3747 }
3748
3749 count++;
3750 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003751
3752 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003753 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003754
3755 printk(KERN_ERR
3756 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
3757 } else {
3758 printk(KERN_ERR
3759 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
3760
3761 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
3762 BT848_INT_MASK);
3763 };
3764
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003766
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 printk("]\n");
3768 }
3769 }
3770 btv->irq_total++;
3771 if (handled)
3772 btv->irq_me++;
3773 return IRQ_RETVAL(handled);
3774}
3775
3776
3777/* ----------------------------------------------------------------------- */
3778/* initialitation */
3779
3780static struct video_device *vdev_init(struct bttv *btv,
3781 struct video_device *template,
3782 char *type)
3783{
3784 struct video_device *vfd;
3785
3786 vfd = video_device_alloc();
3787 if (NULL == vfd)
3788 return NULL;
3789 *vfd = *template;
3790 vfd->minor = -1;
3791 vfd->dev = &btv->c.pci->dev;
3792 vfd->release = video_device_release;
3793 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
3794 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
3795 type, bttv_tvcards[btv->c.type].name);
3796 return vfd;
3797}
3798
3799static void bttv_unregister_video(struct bttv *btv)
3800{
3801 if (btv->video_dev) {
3802 if (-1 != btv->video_dev->minor)
3803 video_unregister_device(btv->video_dev);
3804 else
3805 video_device_release(btv->video_dev);
3806 btv->video_dev = NULL;
3807 }
3808 if (btv->vbi_dev) {
3809 if (-1 != btv->vbi_dev->minor)
3810 video_unregister_device(btv->vbi_dev);
3811 else
3812 video_device_release(btv->vbi_dev);
3813 btv->vbi_dev = NULL;
3814 }
3815 if (btv->radio_dev) {
3816 if (-1 != btv->radio_dev->minor)
3817 video_unregister_device(btv->radio_dev);
3818 else
3819 video_device_release(btv->radio_dev);
3820 btv->radio_dev = NULL;
3821 }
3822}
3823
3824/* register video4linux devices */
3825static int __devinit bttv_register_video(struct bttv *btv)
3826{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003827 if (no_overlay <= 0) {
3828 bttv_video_template.type |= VID_TYPE_OVERLAY;
3829 } else {
3830 printk("bttv: Overlay support disabled.\n");
3831 }
3832
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 /* video */
3834 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003835 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 goto err;
3837 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
3838 goto err;
3839 printk(KERN_INFO "bttv%d: registered device video%d\n",
3840 btv->c.nr,btv->video_dev->minor & 0x1f);
3841 video_device_create_file(btv->video_dev, &class_device_attr_card);
3842
3843 /* vbi */
3844 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003845 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003847 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 goto err;
3849 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
3850 btv->c.nr,btv->vbi_dev->minor & 0x1f);
3851
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003852 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 return 0;
3854 /* radio */
3855 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003856 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 goto err;
3858 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
3859 goto err;
3860 printk(KERN_INFO "bttv%d: registered device radio%d\n",
3861 btv->c.nr,btv->radio_dev->minor & 0x1f);
3862
3863 /* all done */
3864 return 0;
3865
3866 err:
3867 bttv_unregister_video(btv);
3868 return -1;
3869}
3870
3871
3872/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
3873/* response on cards with no firmware is not enabled by OF */
3874static void pci_set_command(struct pci_dev *dev)
3875{
3876#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003877 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003879 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
3880 cmd = (cmd | PCI_COMMAND_MEMORY );
3881 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882#endif
3883}
3884
3885static int __devinit bttv_probe(struct pci_dev *dev,
3886 const struct pci_device_id *pci_id)
3887{
3888 int result;
3889 unsigned char lat;
3890 struct bttv *btv;
3891
3892 if (bttv_num == BTTV_MAX)
3893 return -ENOMEM;
3894 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003895 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 memset(btv,0,sizeof(*btv));
3897 btv->c.nr = bttv_num;
3898 sprintf(btv->c.name,"bttv%d",btv->c.nr);
3899
3900 /* initialize structs / fill in defaults */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003901 init_MUTEX(&btv->lock);
3902 init_MUTEX(&btv->reslock);
3903 spin_lock_init(&btv->s_lock);
3904 spin_lock_init(&btv->gpio_lock);
3905 init_waitqueue_head(&btv->gpioq);
3906 init_waitqueue_head(&btv->i2c_queue);
3907 INIT_LIST_HEAD(&btv->c.subs);
3908 INIT_LIST_HEAD(&btv->capture);
3909 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 v4l2_prio_init(&btv->prio);
3911
3912 init_timer(&btv->timeout);
3913 btv->timeout.function = bttv_irq_timeout;
3914 btv->timeout.data = (unsigned long)btv;
3915
Michael Krufky7c08fb02005-11-08 21:36:21 -08003916 btv->i2c_rc = -1;
3917 btv->tuner_type = UNSET;
3918 btv->pinnacle_id = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 btv->has_radio=radio[btv->c.nr];
3921
3922 /* pci stuff (init, get irq/mmio, ... */
3923 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08003924 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08003926 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 btv->c.nr);
3928 return -EIO;
3929 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003930 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
3931 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 btv->c.nr);
3933 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 if (!request_mem_region(pci_resource_start(dev,0),
3936 pci_resource_len(dev,0),
3937 btv->c.name)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003938 printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 btv->c.nr, pci_resource_start(dev,0));
3940 return -EBUSY;
3941 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003942 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 pci_set_command(dev);
3944 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003946 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
3947 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
3948 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
3949 bttv_num,btv->id, btv->revision, pci_name(dev));
3950 printk("irq: %d, latency: %d, mmio: 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 btv->c.pci->irq, lat, pci_resource_start(dev,0));
3952 schedule();
3953
3954 btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
3955 if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
3956 printk("bttv%d: ioremap() failed\n", btv->c.nr);
3957 result = -EIO;
3958 goto fail1;
3959 }
3960
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003961 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 bttv_idcard(btv);
3963
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003964 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003966 result = request_irq(btv->c.pci->irq, bttv_irq,
3967 SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
3968 if (result < 0) {
3969 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 bttv_num,btv->c.pci->irq);
3971 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003972 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973
3974 if (0 != bttv_handle_chipset(btv)) {
3975 result = -EIO;
3976 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978
3979 /* init options from insmod args */
3980 btv->opt_combfilter = combfilter;
3981 btv->opt_lumafilter = lumafilter;
3982 btv->opt_automute = automute;
3983 btv->opt_chroma_agc = chroma_agc;
3984 btv->opt_adc_crush = adc_crush;
3985 btv->opt_vcr_hack = vcr_hack;
3986 btv->opt_whitecrush_upper = whitecrush_upper;
3987 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07003988 btv->opt_uv_ratio = uv_ratio;
3989 btv->opt_full_luma_range = full_luma_range;
3990 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
3992 /* fill struct bttv with some useful defaults */
3993 btv->init.btv = btv;
3994 btv->init.ov.w.width = 320;
3995 btv->init.ov.w.height = 240;
3996 btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
3997 btv->init.width = 320;
3998 btv->init.height = 240;
3999 btv->init.lines = 16;
4000 btv->input = 0;
4001
4002 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004003 if (bttv_gpio)
4004 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005
4006 bttv_risc_init_main(btv);
4007 init_bt848(btv);
4008
4009 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004010 btwrite(0x00, BT848_GPIO_REG_INP);
4011 btwrite(0x00, BT848_GPIO_OUT_EN);
4012 if (bttv_verbose)
4013 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004015 /* needs to be done before i2c is registered */
4016 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004018 /* register i2c + gpio */
4019 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004021 /* some card-specific stuff (needs working i2c) */
4022 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 init_irqreg(btv);
4024
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004025 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 if (!bttv_tvcards[btv->c.type].no_video) {
4027 bttv_register_video(btv);
4028 bt848_bright(btv,32768);
4029 bt848_contrast(btv,32768);
4030 bt848_hue(btv,32768);
4031 bt848_sat(btv,32768);
4032 audio_mux(btv,AUDIO_MUTE);
4033 set_input(btv,0);
4034 }
4035
4036 /* add subdevices */
4037 if (btv->has_remote)
4038 bttv_sub_add_device(&btv->c, "remote");
4039 if (bttv_tvcards[btv->c.type].has_dvb)
4040 bttv_sub_add_device(&btv->c, "dvb");
4041
4042 /* everything is fine */
4043 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004044 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045
4046 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004047 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048
4049 fail1:
4050 if (btv->bt848_mmio)
4051 iounmap(btv->bt848_mmio);
4052 release_mem_region(pci_resource_start(btv->c.pci,0),
4053 pci_resource_len(btv->c.pci,0));
4054 pci_set_drvdata(dev,NULL);
4055 return result;
4056}
4057
4058static void __devexit bttv_remove(struct pci_dev *pci_dev)
4059{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004060 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061
4062 if (bttv_verbose)
4063 printk("bttv%d: unloading\n",btv->c.nr);
4064
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004065 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 btand(~15, BT848_GPIO_DMA_CTL);
4067 btwrite(0, BT848_INT_MASK);
4068 btwrite(~0x0, BT848_INT_STAT);
4069 btwrite(0x0, BT848_GPIO_OUT_EN);
4070 if (bttv_gpio)
4071 bttv_gpio_tracking(btv,"cleanup");
4072
4073 /* tell gpio modules we are leaving ... */
4074 btv->shutdown=1;
4075 wake_up(&btv->gpioq);
4076 bttv_sub_del_devices(&btv->c);
4077
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004078 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 fini_bttv_i2c(btv);
4080
4081 /* unregister video4linux */
4082 bttv_unregister_video(btv);
4083
4084 /* free allocated memory */
4085 btcx_riscmem_free(btv->c.pci,&btv->main);
4086
4087 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004088 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004090 release_mem_region(pci_resource_start(btv->c.pci,0),
4091 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092
4093 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004094 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095}
4096
4097static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4098{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004099 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 struct bttv_buffer_set idle;
4101 unsigned long flags;
4102
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004103 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
4105 /* stop dma + irqs */
4106 spin_lock_irqsave(&btv->s_lock,flags);
4107 memset(&idle, 0, sizeof(idle));
4108 btv->state.video = btv->curr;
4109 btv->state.vbi = btv->cvbi;
4110 btv->state.loop_irq = btv->loop_irq;
4111 btv->curr = idle;
4112 btv->loop_irq = 0;
4113 bttv_buffer_activate_video(btv, &idle);
4114 bttv_buffer_activate_vbi(btv, NULL);
4115 bttv_set_dma(btv, 0);
4116 btwrite(0, BT848_INT_MASK);
4117 spin_unlock_irqrestore(&btv->s_lock,flags);
4118
4119 /* save bt878 state */
4120 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4121 btv->state.gpio_data = gpio_read();
4122
4123 /* save pci state */
4124 pci_save_state(pci_dev);
4125 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4126 pci_disable_device(pci_dev);
4127 btv->state.disabled = 1;
4128 }
4129 return 0;
4130}
4131
4132static int bttv_resume(struct pci_dev *pci_dev)
4133{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004134 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004136 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138 dprintk("bttv%d: resume\n", btv->c.nr);
4139
4140 /* restore pci state */
4141 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004142 err=pci_enable_device(pci_dev);
4143 if (err) {
4144 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4145 btv->c.nr);
4146 return err;
4147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 btv->state.disabled = 0;
4149 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004150 err=pci_set_power_state(pci_dev, PCI_D0);
4151 if (err) {
4152 pci_disable_device(pci_dev);
4153 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4154 btv->c.nr);
4155 btv->state.disabled = 1;
4156 return err;
4157 }
4158
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 pci_restore_state(pci_dev);
4160
4161 /* restore bt878 state */
4162 bttv_reinit_bt848(btv);
4163 gpio_inout(0xffffff, btv->state.gpio_enable);
4164 gpio_write(btv->state.gpio_data);
4165
4166 /* restart dma */
4167 spin_lock_irqsave(&btv->s_lock,flags);
4168 btv->curr = btv->state.video;
4169 btv->cvbi = btv->state.vbi;
4170 btv->loop_irq = btv->state.loop_irq;
4171 bttv_buffer_activate_video(btv, &btv->curr);
4172 bttv_buffer_activate_vbi(btv, btv->cvbi);
4173 bttv_set_dma(btv, 0);
4174 spin_unlock_irqrestore(&btv->s_lock,flags);
4175 return 0;
4176}
4177
4178static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004179 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4180 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004182 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004184 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004186 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4187 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188};
4189
4190MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4191
4192static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004193 .name = "bttv",
4194 .id_table = bttv_pci_tbl,
4195 .probe = bttv_probe,
4196 .remove = __devexit_p(bttv_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 .suspend = bttv_suspend,
4198 .resume = bttv_resume,
4199};
4200
4201static int bttv_init_module(void)
4202{
4203 bttv_num = 0;
4204
4205 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4206 (BTTV_VERSION_CODE >> 16) & 0xff,
4207 (BTTV_VERSION_CODE >> 8) & 0xff,
4208 BTTV_VERSION_CODE & 0xff);
4209#ifdef SNAPSHOT
4210 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4211 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4212#endif
4213 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4214 gbuffers = 2;
4215 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4216 gbufsize = BTTV_MAX_FBUF;
4217 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4218 if (bttv_verbose)
4219 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4220 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4221
4222 bttv_check_chipset();
4223
4224 bus_register(&bttv_sub_bus_type);
4225 return pci_module_init(&bttv_pci_driver);
4226}
4227
4228static void bttv_cleanup_module(void)
4229{
4230 pci_unregister_driver(&bttv_pci_driver);
4231 bus_unregister(&bttv_sub_bus_type);
4232 return;
4233}
4234
4235module_init(bttv_init_module);
4236module_exit(bttv_cleanup_module);
4237
4238/*
4239 * Local variables:
4240 * c-basic-offset: 8
4241 * End:
4242 */