blob: 7913e2ec7a5b57c6847ece711442892848f70460 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3 bttv - Bt848 frame grabber driver
4
5 Copyright (C) 1996,97,98 Ralph Metzler <rjkm@thp.uni-koeln.de>
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08006 & Marcus Metzler <mocm@thp.uni-koeln.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
8
9 some v4l2 code lines are taken from Justin's bttv2 driver which is
10 (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26
27#include <linux/init.h>
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/delay.h>
31#include <linux/errno.h>
32#include <linux/fs.h>
33#include <linux/kernel.h>
34#include <linux/sched.h>
35#include <linux/interrupt.h>
36#include <linux/kdev_t.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020037#include "bttvp.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020038#include <media/v4l2-common.h>
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -030039#include <media/tvaudio.h>
Hans Verkuil2474ed42006-03-19 12:35:57 -030040#include <media/msp3400.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020041
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -070042#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44#include <asm/io.h>
45#include <asm/byteorder.h>
46
Mauro Carvalho Chehabfa3fcce2006-03-23 21:45:24 -030047#include <media/rds.h>
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070048
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050unsigned int bttv_num; /* number of Bt848s in use */
51struct bttv bttvs[BTTV_MAX];
52
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020053unsigned int bttv_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054unsigned int bttv_verbose = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020055unsigned int bttv_gpio;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57/* config variables */
58#ifdef __BIG_ENDIAN
59static unsigned int bigendian=1;
60#else
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020061static unsigned int bigendian;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#endif
63static unsigned int radio[BTTV_MAX];
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020064static unsigned int irq_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065static unsigned int gbuffers = 8;
66static unsigned int gbufsize = 0x208000;
67
68static int video_nr = -1;
69static int radio_nr = -1;
70static int vbi_nr = -1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020071static int debug_latency;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020073static unsigned int fdsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75/* options */
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020076static unsigned int combfilter;
77static unsigned int lumafilter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static unsigned int automute = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020079static unsigned int chroma_agc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static unsigned int adc_crush = 1;
81static unsigned int whitecrush_upper = 0xCF;
82static unsigned int whitecrush_lower = 0x7F;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020083static unsigned int vcr_hack;
84static unsigned int irq_iswitch;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070085static unsigned int uv_ratio = 50;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020086static unsigned int full_luma_range;
87static unsigned int coring;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070088extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90/* API features (turn on/off stuff for testing) */
91static unsigned int v4l2 = 1;
92
Linus Torvalds1da177e2005-04-16 15:20:36 -070093/* insmod args */
94module_param(bttv_verbose, int, 0644);
95module_param(bttv_gpio, int, 0644);
96module_param(bttv_debug, int, 0644);
97module_param(irq_debug, int, 0644);
98module_param(debug_latency, int, 0644);
99
100module_param(fdsr, int, 0444);
101module_param(video_nr, int, 0444);
102module_param(radio_nr, int, 0444);
103module_param(vbi_nr, int, 0444);
104module_param(gbuffers, int, 0444);
105module_param(gbufsize, int, 0444);
106
107module_param(v4l2, int, 0644);
108module_param(bigendian, int, 0644);
109module_param(irq_iswitch, int, 0644);
110module_param(combfilter, int, 0444);
111module_param(lumafilter, int, 0444);
112module_param(automute, int, 0444);
113module_param(chroma_agc, int, 0444);
114module_param(adc_crush, int, 0444);
115module_param(whitecrush_upper, int, 0444);
116module_param(whitecrush_lower, int, 0444);
117module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700118module_param(uv_ratio, int, 0444);
119module_param(full_luma_range, int, 0444);
120module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122module_param_array(radio, int, NULL, 0444);
123
124MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
125MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
126MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
127MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
128MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
129MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
130MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
131MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
132MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
133MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
134MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
135MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
136MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
137MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
138MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700139MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
140MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
141MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
144MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
145MODULE_LICENSE("GPL");
146
147/* ----------------------------------------------------------------------- */
148/* sysfs */
149
150static ssize_t show_card(struct class_device *cd, char *buf)
151{
152 struct video_device *vfd = to_video_device(cd);
153 struct bttv *btv = dev_get_drvdata(vfd->dev);
154 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
155}
156static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
157
158/* ----------------------------------------------------------------------- */
159/* static data */
160
161/* special timing tables from conexant... */
162static u8 SRAM_Table[][60] =
163{
164 /* PAL digital input over GPIO[7:0] */
165 {
166 45, // 45 bytes following
167 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
168 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
169 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
170 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
171 0x37,0x00,0xAF,0x21,0x00
172 },
173 /* NTSC digital input over GPIO[7:0] */
174 {
175 51, // 51 bytes following
176 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
177 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
178 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
179 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
180 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
181 0x00,
182 },
183 // TGB_NTSC392 // quartzsight
184 // This table has been modified to be used for Fusion Rev D
185 {
186 0x2A, // size of table = 42
187 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
188 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
189 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
190 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
191 0x20, 0x00
192 }
193};
194
195const struct bttv_tvnorm bttv_tvnorms[] = {
196 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800197 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
198 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 {
200 .v4l2_id = V4L2_STD_PAL,
201 .name = "PAL",
202 .Fsc = 35468950,
203 .swidth = 924,
204 .sheight = 576,
205 .totalwidth = 1135,
206 .adelay = 0x7f,
207 .bdelay = 0x72,
208 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
209 .scaledtwidth = 1135,
210 .hdelayx1 = 186,
211 .hactivex1 = 924,
212 .vdelay = 0x20,
213 .vbipack = 255,
214 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200215 /* ITU-R frame line number of the first VBI line
216 we can capture, of the first and second field. */
217 .vbistart = { 7,320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 },{
Hans Verkuild97a11e2006-02-07 06:48:40 -0200219 .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 .name = "NTSC",
221 .Fsc = 28636363,
222 .swidth = 768,
223 .sheight = 480,
224 .totalwidth = 910,
225 .adelay = 0x68,
226 .bdelay = 0x5d,
227 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
228 .scaledtwidth = 910,
229 .hdelayx1 = 128,
230 .hactivex1 = 910,
231 .vdelay = 0x1a,
232 .vbipack = 144,
233 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200234 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 },{
236 .v4l2_id = V4L2_STD_SECAM,
237 .name = "SECAM",
238 .Fsc = 35468950,
239 .swidth = 924,
240 .sheight = 576,
241 .totalwidth = 1135,
242 .adelay = 0x7f,
243 .bdelay = 0xb0,
244 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
245 .scaledtwidth = 1135,
246 .hdelayx1 = 186,
247 .hactivex1 = 922,
248 .vdelay = 0x20,
249 .vbipack = 255,
250 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200251 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 },{
253 .v4l2_id = V4L2_STD_PAL_Nc,
254 .name = "PAL-Nc",
255 .Fsc = 28636363,
256 .swidth = 640,
257 .sheight = 576,
258 .totalwidth = 910,
259 .adelay = 0x68,
260 .bdelay = 0x5d,
261 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
262 .scaledtwidth = 780,
263 .hdelayx1 = 130,
264 .hactivex1 = 734,
265 .vdelay = 0x1a,
266 .vbipack = 144,
267 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200268 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 },{
270 .v4l2_id = V4L2_STD_PAL_M,
271 .name = "PAL-M",
272 .Fsc = 28636363,
273 .swidth = 640,
274 .sheight = 480,
275 .totalwidth = 910,
276 .adelay = 0x68,
277 .bdelay = 0x5d,
278 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
279 .scaledtwidth = 780,
280 .hdelayx1 = 135,
281 .hactivex1 = 754,
282 .vdelay = 0x1a,
283 .vbipack = 144,
284 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200285 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 },{
287 .v4l2_id = V4L2_STD_PAL_N,
288 .name = "PAL-N",
289 .Fsc = 35468950,
290 .swidth = 768,
291 .sheight = 576,
292 .totalwidth = 1135,
293 .adelay = 0x7f,
294 .bdelay = 0x72,
295 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
296 .scaledtwidth = 944,
297 .hdelayx1 = 186,
298 .hactivex1 = 922,
299 .vdelay = 0x20,
300 .vbipack = 144,
301 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200302 .vbistart = { 7, 320},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 },{
304 .v4l2_id = V4L2_STD_NTSC_M_JP,
305 .name = "NTSC-JP",
306 .Fsc = 28636363,
307 .swidth = 640,
308 .sheight = 480,
309 .totalwidth = 910,
310 .adelay = 0x68,
311 .bdelay = 0x5d,
312 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
313 .scaledtwidth = 780,
314 .hdelayx1 = 135,
315 .hactivex1 = 754,
316 .vdelay = 0x16,
317 .vbipack = 144,
318 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200319 .vbistart = {10, 273},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 },{
321 /* that one hopefully works with the strange timing
322 * which video recorders produce when playing a NTSC
323 * tape on a PAL TV ... */
324 .v4l2_id = V4L2_STD_PAL_60,
325 .name = "PAL-60",
326 .Fsc = 35468950,
327 .swidth = 924,
328 .sheight = 480,
329 .totalwidth = 1135,
330 .adelay = 0x7f,
331 .bdelay = 0x72,
332 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
333 .scaledtwidth = 1135,
334 .hdelayx1 = 186,
335 .hactivex1 = 924,
336 .vdelay = 0x1a,
337 .vbipack = 255,
338 .vtotal = 524,
339 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200340 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342};
343static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
344
345/* ----------------------------------------------------------------------- */
346/* bttv format list
347 packed pixel formats must come first */
348static const struct bttv_format bttv_formats[] = {
349 {
350 .name = "8 bpp, gray",
351 .palette = VIDEO_PALETTE_GREY,
352 .fourcc = V4L2_PIX_FMT_GREY,
353 .btformat = BT848_COLOR_FMT_Y8,
354 .depth = 8,
355 .flags = FORMAT_FLAGS_PACKED,
356 },{
357 .name = "8 bpp, dithered color",
358 .palette = VIDEO_PALETTE_HI240,
359 .fourcc = V4L2_PIX_FMT_HI240,
360 .btformat = BT848_COLOR_FMT_RGB8,
361 .depth = 8,
362 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
363 },{
364 .name = "15 bpp RGB, le",
365 .palette = VIDEO_PALETTE_RGB555,
366 .fourcc = V4L2_PIX_FMT_RGB555,
367 .btformat = BT848_COLOR_FMT_RGB15,
368 .depth = 16,
369 .flags = FORMAT_FLAGS_PACKED,
370 },{
371 .name = "15 bpp RGB, be",
372 .palette = -1,
373 .fourcc = V4L2_PIX_FMT_RGB555X,
374 .btformat = BT848_COLOR_FMT_RGB15,
375 .btswap = 0x03, /* byteswap */
376 .depth = 16,
377 .flags = FORMAT_FLAGS_PACKED,
378 },{
379 .name = "16 bpp RGB, le",
380 .palette = VIDEO_PALETTE_RGB565,
381 .fourcc = V4L2_PIX_FMT_RGB565,
382 .btformat = BT848_COLOR_FMT_RGB16,
383 .depth = 16,
384 .flags = FORMAT_FLAGS_PACKED,
385 },{
386 .name = "16 bpp RGB, be",
387 .palette = -1,
388 .fourcc = V4L2_PIX_FMT_RGB565X,
389 .btformat = BT848_COLOR_FMT_RGB16,
390 .btswap = 0x03, /* byteswap */
391 .depth = 16,
392 .flags = FORMAT_FLAGS_PACKED,
393 },{
394 .name = "24 bpp RGB, le",
395 .palette = VIDEO_PALETTE_RGB24,
396 .fourcc = V4L2_PIX_FMT_BGR24,
397 .btformat = BT848_COLOR_FMT_RGB24,
398 .depth = 24,
399 .flags = FORMAT_FLAGS_PACKED,
400 },{
401 .name = "32 bpp RGB, le",
402 .palette = VIDEO_PALETTE_RGB32,
403 .fourcc = V4L2_PIX_FMT_BGR32,
404 .btformat = BT848_COLOR_FMT_RGB32,
405 .depth = 32,
406 .flags = FORMAT_FLAGS_PACKED,
407 },{
408 .name = "32 bpp RGB, be",
409 .palette = -1,
410 .fourcc = V4L2_PIX_FMT_RGB32,
411 .btformat = BT848_COLOR_FMT_RGB32,
412 .btswap = 0x0f, /* byte+word swap */
413 .depth = 32,
414 .flags = FORMAT_FLAGS_PACKED,
415 },{
416 .name = "4:2:2, packed, YUYV",
417 .palette = VIDEO_PALETTE_YUV422,
418 .fourcc = V4L2_PIX_FMT_YUYV,
419 .btformat = BT848_COLOR_FMT_YUY2,
420 .depth = 16,
421 .flags = FORMAT_FLAGS_PACKED,
422 },{
423 .name = "4:2:2, packed, YUYV",
424 .palette = VIDEO_PALETTE_YUYV,
425 .fourcc = V4L2_PIX_FMT_YUYV,
426 .btformat = BT848_COLOR_FMT_YUY2,
427 .depth = 16,
428 .flags = FORMAT_FLAGS_PACKED,
429 },{
430 .name = "4:2:2, packed, UYVY",
431 .palette = VIDEO_PALETTE_UYVY,
432 .fourcc = V4L2_PIX_FMT_UYVY,
433 .btformat = BT848_COLOR_FMT_YUY2,
434 .btswap = 0x03, /* byteswap */
435 .depth = 16,
436 .flags = FORMAT_FLAGS_PACKED,
437 },{
438 .name = "4:2:2, planar, Y-Cb-Cr",
439 .palette = VIDEO_PALETTE_YUV422P,
440 .fourcc = V4L2_PIX_FMT_YUV422P,
441 .btformat = BT848_COLOR_FMT_YCrCb422,
442 .depth = 16,
443 .flags = FORMAT_FLAGS_PLANAR,
444 .hshift = 1,
445 .vshift = 0,
446 },{
447 .name = "4:2:0, planar, Y-Cb-Cr",
448 .palette = VIDEO_PALETTE_YUV420P,
449 .fourcc = V4L2_PIX_FMT_YUV420,
450 .btformat = BT848_COLOR_FMT_YCrCb422,
451 .depth = 12,
452 .flags = FORMAT_FLAGS_PLANAR,
453 .hshift = 1,
454 .vshift = 1,
455 },{
456 .name = "4:2:0, planar, Y-Cr-Cb",
457 .palette = -1,
458 .fourcc = V4L2_PIX_FMT_YVU420,
459 .btformat = BT848_COLOR_FMT_YCrCb422,
460 .depth = 12,
461 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
462 .hshift = 1,
463 .vshift = 1,
464 },{
465 .name = "4:1:1, planar, Y-Cb-Cr",
466 .palette = VIDEO_PALETTE_YUV411P,
467 .fourcc = V4L2_PIX_FMT_YUV411P,
468 .btformat = BT848_COLOR_FMT_YCrCb411,
469 .depth = 12,
470 .flags = FORMAT_FLAGS_PLANAR,
471 .hshift = 2,
472 .vshift = 0,
473 },{
474 .name = "4:1:0, planar, Y-Cb-Cr",
475 .palette = VIDEO_PALETTE_YUV410P,
476 .fourcc = V4L2_PIX_FMT_YUV410,
477 .btformat = BT848_COLOR_FMT_YCrCb411,
478 .depth = 9,
479 .flags = FORMAT_FLAGS_PLANAR,
480 .hshift = 2,
481 .vshift = 2,
482 },{
483 .name = "4:1:0, planar, Y-Cr-Cb",
484 .palette = -1,
485 .fourcc = V4L2_PIX_FMT_YVU410,
486 .btformat = BT848_COLOR_FMT_YCrCb411,
487 .depth = 9,
488 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
489 .hshift = 2,
490 .vshift = 2,
491 },{
492 .name = "raw scanlines",
493 .palette = VIDEO_PALETTE_RAW,
494 .fourcc = -1,
495 .btformat = BT848_COLOR_FMT_RAW,
496 .depth = 8,
497 .flags = FORMAT_FLAGS_RAW,
498 }
499};
500static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
501
502/* ----------------------------------------------------------------------- */
503
504#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
505#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
506#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
507#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
508#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
509#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
510#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
511#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700512#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
513#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
514#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
515#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517static const struct v4l2_queryctrl no_ctl = {
518 .name = "42",
519 .flags = V4L2_CTRL_FLAG_DISABLED,
520};
521static const struct v4l2_queryctrl bttv_ctls[] = {
522 /* --- video --- */
523 {
524 .id = V4L2_CID_BRIGHTNESS,
525 .name = "Brightness",
526 .minimum = 0,
527 .maximum = 65535,
528 .step = 256,
529 .default_value = 32768,
530 .type = V4L2_CTRL_TYPE_INTEGER,
531 },{
532 .id = V4L2_CID_CONTRAST,
533 .name = "Contrast",
534 .minimum = 0,
535 .maximum = 65535,
536 .step = 128,
537 .default_value = 32768,
538 .type = V4L2_CTRL_TYPE_INTEGER,
539 },{
540 .id = V4L2_CID_SATURATION,
541 .name = "Saturation",
542 .minimum = 0,
543 .maximum = 65535,
544 .step = 128,
545 .default_value = 32768,
546 .type = V4L2_CTRL_TYPE_INTEGER,
547 },{
548 .id = V4L2_CID_HUE,
549 .name = "Hue",
550 .minimum = 0,
551 .maximum = 65535,
552 .step = 256,
553 .default_value = 32768,
554 .type = V4L2_CTRL_TYPE_INTEGER,
555 },
556 /* --- audio --- */
557 {
558 .id = V4L2_CID_AUDIO_MUTE,
559 .name = "Mute",
560 .minimum = 0,
561 .maximum = 1,
562 .type = V4L2_CTRL_TYPE_BOOLEAN,
563 },{
564 .id = V4L2_CID_AUDIO_VOLUME,
565 .name = "Volume",
566 .minimum = 0,
567 .maximum = 65535,
568 .step = 65535/100,
569 .default_value = 65535,
570 .type = V4L2_CTRL_TYPE_INTEGER,
571 },{
572 .id = V4L2_CID_AUDIO_BALANCE,
573 .name = "Balance",
574 .minimum = 0,
575 .maximum = 65535,
576 .step = 65535/100,
577 .default_value = 32768,
578 .type = V4L2_CTRL_TYPE_INTEGER,
579 },{
580 .id = V4L2_CID_AUDIO_BASS,
581 .name = "Bass",
582 .minimum = 0,
583 .maximum = 65535,
584 .step = 65535/100,
585 .default_value = 32768,
586 .type = V4L2_CTRL_TYPE_INTEGER,
587 },{
588 .id = V4L2_CID_AUDIO_TREBLE,
589 .name = "Treble",
590 .minimum = 0,
591 .maximum = 65535,
592 .step = 65535/100,
593 .default_value = 32768,
594 .type = V4L2_CTRL_TYPE_INTEGER,
595 },
596 /* --- private --- */
597 {
598 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
599 .name = "chroma agc",
600 .minimum = 0,
601 .maximum = 1,
602 .type = V4L2_CTRL_TYPE_BOOLEAN,
603 },{
604 .id = V4L2_CID_PRIVATE_COMBFILTER,
605 .name = "combfilter",
606 .minimum = 0,
607 .maximum = 1,
608 .type = V4L2_CTRL_TYPE_BOOLEAN,
609 },{
610 .id = V4L2_CID_PRIVATE_AUTOMUTE,
611 .name = "automute",
612 .minimum = 0,
613 .maximum = 1,
614 .type = V4L2_CTRL_TYPE_BOOLEAN,
615 },{
616 .id = V4L2_CID_PRIVATE_LUMAFILTER,
617 .name = "luma decimation filter",
618 .minimum = 0,
619 .maximum = 1,
620 .type = V4L2_CTRL_TYPE_BOOLEAN,
621 },{
622 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
623 .name = "agc crush",
624 .minimum = 0,
625 .maximum = 1,
626 .type = V4L2_CTRL_TYPE_BOOLEAN,
627 },{
628 .id = V4L2_CID_PRIVATE_VCR_HACK,
629 .name = "vcr hack",
630 .minimum = 0,
631 .maximum = 1,
632 .type = V4L2_CTRL_TYPE_BOOLEAN,
633 },{
634 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
635 .name = "whitecrush upper",
636 .minimum = 0,
637 .maximum = 255,
638 .step = 1,
639 .default_value = 0xCF,
640 .type = V4L2_CTRL_TYPE_INTEGER,
641 },{
642 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
643 .name = "whitecrush lower",
644 .minimum = 0,
645 .maximum = 255,
646 .step = 1,
647 .default_value = 0x7F,
648 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700649 },{
650 .id = V4L2_CID_PRIVATE_UV_RATIO,
651 .name = "uv ratio",
652 .minimum = 0,
653 .maximum = 100,
654 .step = 1,
655 .default_value = 50,
656 .type = V4L2_CTRL_TYPE_INTEGER,
657 },{
658 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
659 .name = "full luma range",
660 .minimum = 0,
661 .maximum = 1,
662 .type = V4L2_CTRL_TYPE_BOOLEAN,
663 },{
664 .id = V4L2_CID_PRIVATE_CORING,
665 .name = "coring",
666 .minimum = 0,
667 .maximum = 3,
668 .step = 1,
669 .default_value = 0,
670 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
672
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700673
674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675};
676static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
677
678/* ----------------------------------------------------------------------- */
679/* resource management */
680
681static
682int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
683{
684 if (fh->resources & bit)
685 /* have it already allocated */
686 return 1;
687
688 /* is it free? */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200689 mutex_lock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if (btv->resources & bit) {
691 /* no, someone else uses it */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200692 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return 0;
694 }
695 /* it's free, grab it */
696 fh->resources |= bit;
697 btv->resources |= bit;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200698 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return 1;
700}
701
702static
703int check_btres(struct bttv_fh *fh, int bit)
704{
705 return (fh->resources & bit);
706}
707
708static
709int locked_btres(struct bttv *btv, int bit)
710{
711 return (btv->resources & bit);
712}
713
714static
715void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
716{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 if ((fh->resources & bits) != bits) {
718 /* trying to free ressources not allocated by us ... */
719 printk("bttv: BUG! (btres)\n");
720 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200721 mutex_lock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 fh->resources &= ~bits;
723 btv->resources &= ~bits;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200724 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725}
726
727/* ----------------------------------------------------------------------- */
728/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
729
730/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
731 PLL_X = Reference pre-divider (0=1, 1=2)
732 PLL_C = Post divider (0=6, 1=4)
733 PLL_I = Integer input
734 PLL_F = Fractional input
735
736 F_input = 28.636363 MHz:
737 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
738*/
739
740static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
741{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800742 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800744 /* prevent overflows */
745 fin/=4;
746 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800748 fout*=12;
749 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800751 fout=(fout%fin)*256;
752 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800754 fout=(fout%fin)*256;
755 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800757 btwrite(fl, BT848_PLL_F_LO);
758 btwrite(fh, BT848_PLL_F_HI);
759 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760}
761
762static void set_pll(struct bttv *btv)
763{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800764 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800766 if (!btv->pll.pll_crystal)
767 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
770 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800771 return;
772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800774 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
775 /* no PLL needed */
776 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800777 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700778 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800779 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800780 btwrite(0x00,BT848_TGCTRL);
781 btwrite(0x00,BT848_PLL_XCI);
782 btv->pll.pll_current = 0;
783 return;
784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700786 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800787 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
789
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800790 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700792 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 msleep(10);
794
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800795 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800797 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800798 btwrite(0x08,BT848_TGCTRL);
799 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700800 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800801 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800802 }
803 }
804 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700805 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800806 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807}
808
809/* used to switch between the bt848's analog/digital video capture modes */
810static void bt848A_set_timing(struct bttv *btv)
811{
812 int i, len;
813 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
814 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
815
816 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
817 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
818 btv->c.nr,table_idx);
819
820 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800821 btwrite(0x00, BT848_TGCTRL);
822 btwrite(0x02, BT848_TGCTRL);
823 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 len=SRAM_Table[table_idx][0];
826 for(i = 1; i <= len; i++)
827 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
828 btv->pll.pll_ofreq = 27000000;
829
830 set_pll(btv);
831 btwrite(0x11, BT848_TGCTRL);
832 btwrite(0x41, BT848_DVSIF);
833 } else {
834 btv->pll.pll_ofreq = fsc;
835 set_pll(btv);
836 btwrite(0x0, BT848_DVSIF);
837 }
838}
839
840/* ----------------------------------------------------------------------- */
841
842static void bt848_bright(struct bttv *btv, int bright)
843{
844 int value;
845
846 // printk("bttv: set bright: %d\n",bright); // DEBUG
847 btv->bright = bright;
848
849 /* We want -128 to 127 we get 0-65535 */
850 value = (bright >> 8) - 128;
851 btwrite(value & 0xff, BT848_BRIGHT);
852}
853
854static void bt848_hue(struct bttv *btv, int hue)
855{
856 int value;
857
858 btv->hue = hue;
859
860 /* -128 to 127 */
861 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800862 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
864
865static void bt848_contrast(struct bttv *btv, int cont)
866{
867 int value,hibit;
868
869 btv->contrast = cont;
870
871 /* 0-511 */
872 value = (cont >> 7);
873 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800874 btwrite(value & 0xff, BT848_CONTRAST_LO);
875 btaor(hibit, ~4, BT848_E_CONTROL);
876 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877}
878
879static void bt848_sat(struct bttv *btv, int color)
880{
881 int val_u,val_v,hibits;
882
883 btv->saturation = color;
884
885 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700886 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
887 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800888 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800890 btwrite(val_u & 0xff, BT848_SAT_U_LO);
891 btwrite(val_v & 0xff, BT848_SAT_V_LO);
892 btaor(hibits, ~3, BT848_E_CONTROL);
893 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894}
895
896/* ----------------------------------------------------------------------- */
897
898static int
899video_mux(struct bttv *btv, unsigned int input)
900{
901 int mux,mask2;
902
903 if (input >= bttv_tvcards[btv->c.type].video_inputs)
904 return -EINVAL;
905
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800906 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
908 if (mask2)
909 gpio_inout(mask2,mask2);
910
911 if (input == btv->svhs) {
912 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
913 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
914 } else {
915 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
916 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
917 }
918 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
919 btaor(mux<<5, ~(3<<5), BT848_IFORM);
920 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
921 btv->c.nr,input,mux);
922
923 /* card specific hook */
924 if(bttv_tvcards[btv->c.type].muxsel_hook)
925 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
926 return 0;
927}
928
929static char *audio_modes[] = {
930 "audio: tuner", "audio: radio", "audio: extern",
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300931 "audio: intern", "audio: mute"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932};
933
934static int
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300935audio_mux(struct bttv *btv, int input, int mute)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300937 int gpio_val, signal;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300938 struct v4l2_control ctrl;
939 struct i2c_client *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
942 bttv_tvcards[btv->c.type].gpiomask);
943 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
944
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300945 btv->mute = mute;
946 btv->audio = input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300948 /* automute */
949 mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
950
951 if (mute)
952 gpio_val = bttv_tvcards[btv->c.type].gpiomute;
953 else
954 gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300955
956 gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 if (bttv_gpio)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300958 bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
959 if (in_interrupt())
960 return 0;
961
962 ctrl.id = V4L2_CID_AUDIO_MUTE;
Hans Verkuil2474ed42006-03-19 12:35:57 -0300963 ctrl.value = btv->mute;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300964 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
965 c = btv->i2c_msp34xx_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -0300966 if (c) {
967 struct v4l2_routing route;
968
969 /* Note: the inputs tuner/radio/extern/intern are translated
970 to msp routings. This assumes common behavior for all msp3400
971 based TV cards. When this assumption fails, then the
972 specific MSP routing must be added to the card table.
973 For now this is sufficient. */
974 switch (input) {
975 case TVAUDIO_INPUT_RADIO:
976 route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1,
977 MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
978 break;
979 case TVAUDIO_INPUT_EXTERN:
980 route.input = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1,
981 MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
982 break;
983 case TVAUDIO_INPUT_INTERN:
984 /* Yes, this is the same input as for RADIO. I doubt
985 if this is ever used. The only board with an INTERN
986 input is the BTTV_BOARD_AVERMEDIA98. I wonder how
987 that was tested. My guess is that the whole INTERN
988 input does not work. */
989 route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1,
990 MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
991 break;
992 case TVAUDIO_INPUT_TUNER:
993 default:
994 route.input = MSP_INPUT_DEFAULT;
995 break;
996 }
997 route.output = MSP_OUTPUT_DEFAULT;
998 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
999 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001000 c = btv->i2c_tvaudio_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001001 if (c) {
1002 struct v4l2_routing route;
1003
1004 route.input = input;
1005 route.output = 0;
1006 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return 0;
1009}
1010
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001011static inline int
1012audio_mute(struct bttv *btv, int mute)
1013{
1014 return audio_mux(btv, btv->audio, mute);
1015}
1016
1017static inline int
1018audio_input(struct bttv *btv, int input)
1019{
1020 return audio_mux(btv, input, btv->mute);
1021}
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023static void
1024i2c_vidiocschan(struct bttv *btv)
1025{
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001026 v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001028 bttv_call_i2c_clients(btv, VIDIOC_S_INPUT, &btv->input);
1029 bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001030 if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001031 bttv_tda9880_setnorm(btv,btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032}
1033
1034static int
1035set_tvnorm(struct bttv *btv, unsigned int norm)
1036{
1037 const struct bttv_tvnorm *tvnorm;
1038
1039 if (norm < 0 || norm >= BTTV_TVNORMS)
1040 return -EINVAL;
1041
1042 btv->tvnorm = norm;
1043 tvnorm = &bttv_tvnorms[norm];
1044
1045 btwrite(tvnorm->adelay, BT848_ADELAY);
1046 btwrite(tvnorm->bdelay, BT848_BDELAY);
1047 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1048 BT848_IFORM);
1049 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1050 btwrite(1, BT848_VBI_PACK_DEL);
1051 bt848A_set_timing(btv);
1052
1053 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001054 case BTTV_BOARD_VOODOOTV_FM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 bttv_tda9880_setnorm(btv,norm);
1056 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
1058 return 0;
1059}
1060
1061static void
1062set_input(struct bttv *btv, unsigned int input)
1063{
1064 unsigned long flags;
1065
1066 btv->input = input;
1067 if (irq_iswitch) {
1068 spin_lock_irqsave(&btv->s_lock,flags);
1069 if (btv->curr.frame_irq) {
1070 /* active capture -> delayed input switch */
1071 btv->new_input = input;
1072 } else {
1073 video_mux(btv,input);
1074 }
1075 spin_unlock_irqrestore(&btv->s_lock,flags);
1076 } else {
1077 video_mux(btv,input);
1078 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001079 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1080 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 set_tvnorm(btv,btv->tvnorm);
1082 i2c_vidiocschan(btv);
1083}
1084
1085static void init_irqreg(struct bttv *btv)
1086{
1087 /* clear status */
1088 btwrite(0xfffffUL, BT848_INT_STAT);
1089
1090 if (bttv_tvcards[btv->c.type].no_video) {
1091 /* i2c only */
1092 btwrite(BT848_INT_I2CDONE,
1093 BT848_INT_MASK);
1094 } else {
1095 /* full video */
1096 btwrite((btv->triton1) |
1097 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1098 BT848_INT_SCERR |
1099 (fdsr ? BT848_INT_FDSR : 0) |
1100 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1101 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1102 BT848_INT_I2CDONE,
1103 BT848_INT_MASK);
1104 }
1105}
1106
1107static void init_bt848(struct bttv *btv)
1108{
1109 int val;
1110
1111 if (bttv_tvcards[btv->c.type].no_video) {
1112 /* very basic init only */
1113 init_irqreg(btv);
1114 return;
1115 }
1116
1117 btwrite(0x00, BT848_CAP_CTL);
1118 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1119 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1120
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001121 /* set planar and packed mode trigger points and */
1122 /* set rising edge of inverted GPINTR pin as irq trigger */
1123 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1124 BT848_GPIO_DMA_CTL_PLTP1_16|
1125 BT848_GPIO_DMA_CTL_PLTP23_16|
1126 BT848_GPIO_DMA_CTL_GPINTC|
1127 BT848_GPIO_DMA_CTL_GPINTI,
1128 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001131 btwrite(val, BT848_E_SCLOOP);
1132 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001134 btwrite(0x20, BT848_E_VSCALE_HI);
1135 btwrite(0x20, BT848_O_VSCALE_HI);
1136 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 BT848_ADC);
1138
1139 btwrite(whitecrush_upper, BT848_WC_UP);
1140 btwrite(whitecrush_lower, BT848_WC_DOWN);
1141
1142 if (btv->opt_lumafilter) {
1143 btwrite(0, BT848_E_CONTROL);
1144 btwrite(0, BT848_O_CONTROL);
1145 } else {
1146 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1147 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1148 }
1149
1150 bt848_bright(btv, btv->bright);
1151 bt848_hue(btv, btv->hue);
1152 bt848_contrast(btv, btv->contrast);
1153 bt848_sat(btv, btv->saturation);
1154
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001155 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 init_irqreg(btv);
1157}
1158
1159static void bttv_reinit_bt848(struct bttv *btv)
1160{
1161 unsigned long flags;
1162
1163 if (bttv_verbose)
1164 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1165 spin_lock_irqsave(&btv->s_lock,flags);
1166 btv->errors=0;
1167 bttv_set_dma(btv,0);
1168 spin_unlock_irqrestore(&btv->s_lock,flags);
1169
1170 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001171 btv->pll.pll_current = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 set_input(btv,btv->input);
1173}
1174
1175static int get_control(struct bttv *btv, struct v4l2_control *c)
1176{
1177 struct video_audio va;
1178 int i;
1179
1180 for (i = 0; i < BTTV_CTLS; i++)
1181 if (bttv_ctls[i].id == c->id)
1182 break;
1183 if (i == BTTV_CTLS)
1184 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001185 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001187 btv->audio_hook(btv,&va,0);
1188 switch (c->id) {
1189 case V4L2_CID_AUDIO_MUTE:
1190 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1191 break;
1192 case V4L2_CID_AUDIO_VOLUME:
1193 c->value = va.volume;
1194 break;
1195 case V4L2_CID_AUDIO_BALANCE:
1196 c->value = va.balance;
1197 break;
1198 case V4L2_CID_AUDIO_BASS:
1199 c->value = va.bass;
1200 break;
1201 case V4L2_CID_AUDIO_TREBLE:
1202 c->value = va.treble;
1203 break;
1204 }
1205 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 }
1207 switch (c->id) {
1208 case V4L2_CID_BRIGHTNESS:
1209 c->value = btv->bright;
1210 break;
1211 case V4L2_CID_HUE:
1212 c->value = btv->hue;
1213 break;
1214 case V4L2_CID_CONTRAST:
1215 c->value = btv->contrast;
1216 break;
1217 case V4L2_CID_SATURATION:
1218 c->value = btv->saturation;
1219 break;
1220
1221 case V4L2_CID_AUDIO_MUTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001226 bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 break;
1228
1229 case V4L2_CID_PRIVATE_CHROMA_AGC:
1230 c->value = btv->opt_chroma_agc;
1231 break;
1232 case V4L2_CID_PRIVATE_COMBFILTER:
1233 c->value = btv->opt_combfilter;
1234 break;
1235 case V4L2_CID_PRIVATE_LUMAFILTER:
1236 c->value = btv->opt_lumafilter;
1237 break;
1238 case V4L2_CID_PRIVATE_AUTOMUTE:
1239 c->value = btv->opt_automute;
1240 break;
1241 case V4L2_CID_PRIVATE_AGC_CRUSH:
1242 c->value = btv->opt_adc_crush;
1243 break;
1244 case V4L2_CID_PRIVATE_VCR_HACK:
1245 c->value = btv->opt_vcr_hack;
1246 break;
1247 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1248 c->value = btv->opt_whitecrush_upper;
1249 break;
1250 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1251 c->value = btv->opt_whitecrush_lower;
1252 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001253 case V4L2_CID_PRIVATE_UV_RATIO:
1254 c->value = btv->opt_uv_ratio;
1255 break;
1256 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1257 c->value = btv->opt_full_luma_range;
1258 break;
1259 case V4L2_CID_PRIVATE_CORING:
1260 c->value = btv->opt_coring;
1261 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 default:
1263 return -EINVAL;
1264 }
1265 return 0;
1266}
1267
1268static int set_control(struct bttv *btv, struct v4l2_control *c)
1269{
1270 struct video_audio va;
1271 int i,val;
1272
1273 for (i = 0; i < BTTV_CTLS; i++)
1274 if (bttv_ctls[i].id == c->id)
1275 break;
1276 if (i == BTTV_CTLS)
1277 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001278 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001280 btv->audio_hook(btv,&va,0);
1281 switch (c->id) {
1282 case V4L2_CID_AUDIO_MUTE:
1283 if (c->value) {
1284 va.flags |= VIDEO_AUDIO_MUTE;
1285 audio_mute(btv, 1);
1286 } else {
1287 va.flags &= ~VIDEO_AUDIO_MUTE;
1288 audio_mute(btv, 0);
1289 }
1290 break;
1291
1292 case V4L2_CID_AUDIO_VOLUME:
1293 va.volume = c->value;
1294 break;
1295 case V4L2_CID_AUDIO_BALANCE:
1296 va.balance = c->value;
1297 break;
1298 case V4L2_CID_AUDIO_BASS:
1299 va.bass = c->value;
1300 break;
1301 case V4L2_CID_AUDIO_TREBLE:
1302 va.treble = c->value;
1303 break;
1304 }
1305 btv->audio_hook(btv,&va,1);
1306 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 }
1308 switch (c->id) {
1309 case V4L2_CID_BRIGHTNESS:
1310 bt848_bright(btv,c->value);
1311 break;
1312 case V4L2_CID_HUE:
1313 bt848_hue(btv,c->value);
1314 break;
1315 case V4L2_CID_CONTRAST:
1316 bt848_contrast(btv,c->value);
1317 break;
1318 case V4L2_CID_SATURATION:
1319 bt848_sat(btv,c->value);
1320 break;
1321 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001322 audio_mute(btv, c->value);
1323 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001328 bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 break;
1330
1331 case V4L2_CID_PRIVATE_CHROMA_AGC:
1332 btv->opt_chroma_agc = c->value;
1333 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1334 btwrite(val, BT848_E_SCLOOP);
1335 btwrite(val, BT848_O_SCLOOP);
1336 break;
1337 case V4L2_CID_PRIVATE_COMBFILTER:
1338 btv->opt_combfilter = c->value;
1339 break;
1340 case V4L2_CID_PRIVATE_LUMAFILTER:
1341 btv->opt_lumafilter = c->value;
1342 if (btv->opt_lumafilter) {
1343 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1344 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1345 } else {
1346 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1347 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1348 }
1349 break;
1350 case V4L2_CID_PRIVATE_AUTOMUTE:
1351 btv->opt_automute = c->value;
1352 break;
1353 case V4L2_CID_PRIVATE_AGC_CRUSH:
1354 btv->opt_adc_crush = c->value;
1355 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1356 BT848_ADC);
1357 break;
1358 case V4L2_CID_PRIVATE_VCR_HACK:
1359 btv->opt_vcr_hack = c->value;
1360 break;
1361 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1362 btv->opt_whitecrush_upper = c->value;
1363 btwrite(c->value, BT848_WC_UP);
1364 break;
1365 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1366 btv->opt_whitecrush_lower = c->value;
1367 btwrite(c->value, BT848_WC_DOWN);
1368 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001369 case V4L2_CID_PRIVATE_UV_RATIO:
1370 btv->opt_uv_ratio = c->value;
1371 bt848_sat(btv, btv->saturation);
1372 break;
1373 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1374 btv->opt_full_luma_range = c->value;
1375 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1376 break;
1377 case V4L2_CID_PRIVATE_CORING:
1378 btv->opt_coring = c->value;
1379 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1380 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 default:
1382 return -EINVAL;
1383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 return 0;
1385}
1386
1387/* ----------------------------------------------------------------------- */
1388
1389void bttv_gpio_tracking(struct bttv *btv, char *comment)
1390{
1391 unsigned int outbits, data;
1392 outbits = btread(BT848_GPIO_OUT_EN);
1393 data = btread(BT848_GPIO_DATA);
1394 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1395 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1396}
1397
1398static void bttv_field_count(struct bttv *btv)
1399{
1400 int need_count = 0;
1401
1402 if (btv->users)
1403 need_count++;
1404
1405 if (need_count) {
1406 /* start field counter */
1407 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1408 } else {
1409 /* stop field counter */
1410 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1411 btv->field_count = 0;
1412 }
1413}
1414
1415static const struct bttv_format*
1416format_by_palette(int palette)
1417{
1418 unsigned int i;
1419
1420 for (i = 0; i < BTTV_FORMATS; i++) {
1421 if (-1 == bttv_formats[i].palette)
1422 continue;
1423 if (bttv_formats[i].palette == palette)
1424 return bttv_formats+i;
1425 }
1426 return NULL;
1427}
1428
1429static const struct bttv_format*
1430format_by_fourcc(int fourcc)
1431{
1432 unsigned int i;
1433
1434 for (i = 0; i < BTTV_FORMATS; i++) {
1435 if (-1 == bttv_formats[i].fourcc)
1436 continue;
1437 if (bttv_formats[i].fourcc == fourcc)
1438 return bttv_formats+i;
1439 }
1440 return NULL;
1441}
1442
1443/* ----------------------------------------------------------------------- */
1444/* misc helpers */
1445
1446static int
1447bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1448 struct bttv_buffer *new)
1449{
1450 struct bttv_buffer *old;
1451 unsigned long flags;
1452 int retval = 0;
1453
1454 dprintk("switch_overlay: enter [new=%p]\n",new);
1455 if (new)
1456 new->vb.state = STATE_DONE;
1457 spin_lock_irqsave(&btv->s_lock,flags);
1458 old = btv->screen;
1459 btv->screen = new;
1460 btv->loop_irq |= 1;
1461 bttv_set_dma(btv, 0x03);
1462 spin_unlock_irqrestore(&btv->s_lock,flags);
1463 if (NULL == new)
1464 free_btres(btv,fh,RESOURCE_OVERLAY);
1465 if (NULL != old) {
1466 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001467 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 kfree(old);
1469 }
1470 dprintk("switch_overlay: done\n");
1471 return retval;
1472}
1473
1474/* ----------------------------------------------------------------------- */
1475/* video4linux (1) interface */
1476
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001477static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1478 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001479 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 unsigned int width, unsigned int height,
1481 enum v4l2_field field)
1482{
1483 int redo_dma_risc = 0;
1484 int rc;
1485
1486 /* check settings */
1487 if (NULL == fmt)
1488 return -EINVAL;
1489 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1490 width = RAW_BPL;
1491 height = RAW_LINES*2;
1492 if (width*height > buf->vb.bsize)
1493 return -EINVAL;
1494 buf->vb.size = buf->vb.bsize;
1495 } else {
1496 if (width < 48 ||
1497 height < 32 ||
1498 width > bttv_tvnorms[btv->tvnorm].swidth ||
1499 height > bttv_tvnorms[btv->tvnorm].sheight)
1500 return -EINVAL;
1501 buf->vb.size = (width * height * fmt->depth) >> 3;
1502 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1503 return -EINVAL;
1504 }
1505
1506 /* alloc + fill struct bttv_buffer (if changed) */
1507 if (buf->vb.width != width || buf->vb.height != height ||
1508 buf->vb.field != field ||
1509 buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
1510 buf->vb.width = width;
1511 buf->vb.height = height;
1512 buf->vb.field = field;
1513 buf->tvnorm = btv->tvnorm;
1514 buf->fmt = fmt;
1515 redo_dma_risc = 1;
1516 }
1517
1518 /* alloc risc memory */
1519 if (STATE_NEEDS_INIT == buf->vb.state) {
1520 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001521 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 goto fail;
1523 }
1524
1525 if (redo_dma_risc)
1526 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1527 goto fail;
1528
1529 buf->vb.state = STATE_PREPARED;
1530 return 0;
1531
1532 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001533 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 return rc;
1535}
1536
1537static int
1538buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1539{
1540 struct bttv_fh *fh = q->priv_data;
1541
1542 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1543 if (0 == *count)
1544 *count = gbuffers;
1545 while (*size * *count > gbuffers * gbufsize)
1546 (*count)--;
1547 return 0;
1548}
1549
1550static int
1551buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1552 enum v4l2_field field)
1553{
1554 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1555 struct bttv_fh *fh = q->priv_data;
1556
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001557 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 fh->width, fh->height, field);
1559}
1560
1561static void
1562buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1563{
1564 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1565 struct bttv_fh *fh = q->priv_data;
1566 struct bttv *btv = fh->btv;
1567
1568 buf->vb.state = STATE_QUEUED;
1569 list_add_tail(&buf->vb.queue,&btv->capture);
1570 if (!btv->curr.frame_irq) {
1571 btv->loop_irq |= 1;
1572 bttv_set_dma(btv, 0x03);
1573 }
1574}
1575
1576static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1577{
1578 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1579 struct bttv_fh *fh = q->priv_data;
1580
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001581 bttv_dma_free(&fh->cap,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582}
1583
1584static struct videobuf_queue_ops bttv_video_qops = {
1585 .buf_setup = buffer_setup,
1586 .buf_prepare = buffer_prepare,
1587 .buf_queue = buffer_queue,
1588 .buf_release = buffer_release,
1589};
1590
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1592{
1593 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001594 case BTTV_VERSION:
1595 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
1597 /* *** v4l1 *** ************************************************ */
1598 case VIDIOCGFREQ:
1599 {
1600 unsigned long *freq = arg;
1601 *freq = btv->freq;
1602 return 0;
1603 }
1604 case VIDIOCSFREQ:
1605 {
1606 unsigned long *freq = arg;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001607 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 btv->freq=*freq;
1609 bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
1610 if (btv->has_matchbox && btv->radio_user)
1611 tea5757_set_freq(btv,*freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001612 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 return 0;
1614 }
1615
1616 case VIDIOCGTUNER:
1617 {
1618 struct video_tuner *v = arg;
1619
1620 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1621 return -EINVAL;
1622 if (v->tuner) /* Only tuner 0 */
1623 return -EINVAL;
1624 strcpy(v->name, "Television");
1625 v->rangelow = 0;
1626 v->rangehigh = 0x7FFFFFFF;
1627 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1628 v->mode = btv->tvnorm;
1629 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1630 bttv_call_i2c_clients(btv,cmd,v);
1631 return 0;
1632 }
1633 case VIDIOCSTUNER:
1634 {
1635 struct video_tuner *v = arg;
1636
1637 if (v->tuner) /* Only tuner 0 */
1638 return -EINVAL;
1639 if (v->mode >= BTTV_TVNORMS)
1640 return -EINVAL;
1641
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001642 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 set_tvnorm(btv,v->mode);
1644 bttv_call_i2c_clients(btv,cmd,v);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001645 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 return 0;
1647 }
1648
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001649 case VIDIOCGCHAN:
1650 {
1651 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 unsigned int channel = v->channel;
1653
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001654 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1655 return -EINVAL;
1656 v->tuners=0;
1657 v->flags = VIDEO_VC_AUDIO;
1658 v->type = VIDEO_TYPE_CAMERA;
1659 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001661 strcpy(v->name,"Television");
1662 v->flags|=VIDEO_VC_TUNER;
1663 v->type=VIDEO_TYPE_TV;
1664 v->tuners=1;
1665 } else if (channel == btv->svhs) {
1666 strcpy(v->name,"S-Video");
1667 } else {
1668 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 }
1670 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001671 }
1672 case VIDIOCSCHAN:
1673 {
1674 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 unsigned int channel = v->channel;
1676
1677 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1678 return -EINVAL;
1679 if (v->norm >= BTTV_TVNORMS)
1680 return -EINVAL;
1681
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001682 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 if (channel == btv->input &&
1684 v->norm == btv->tvnorm) {
1685 /* nothing to do */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001686 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 return 0;
1688 }
1689
1690 btv->tvnorm = v->norm;
1691 set_input(btv,v->channel);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001692 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 return 0;
1694 }
1695
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001696 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 {
1698 struct video_audio *v = arg;
1699
1700 memset(v,0,sizeof(*v));
1701 strcpy(v->name,"Television");
1702 v->flags |= VIDEO_AUDIO_MUTABLE;
1703 v->mode = VIDEO_SOUND_MONO;
1704
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001705 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 bttv_call_i2c_clients(btv,cmd,v);
1707
1708 /* card specific hooks */
1709 if (btv->audio_hook)
1710 btv->audio_hook(btv,v,0);
1711
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001712 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 return 0;
1714 }
1715 case VIDIOCSAUDIO:
1716 {
1717 struct video_audio *v = arg;
1718 unsigned int audio = v->audio;
1719
1720 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
1721 return -EINVAL;
1722
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001723 mutex_lock(&btv->lock);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001724 audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 bttv_call_i2c_clients(btv,cmd,v);
1726
1727 /* card specific hooks */
1728 if (btv->audio_hook)
1729 btv->audio_hook(btv,v,1);
1730
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001731 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 return 0;
1733 }
1734
1735 /* *** v4l2 *** ************************************************ */
1736 case VIDIOC_ENUMSTD:
1737 {
1738 struct v4l2_standard *e = arg;
1739 unsigned int index = e->index;
1740
1741 if (index >= BTTV_TVNORMS)
1742 return -EINVAL;
1743 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1744 bttv_tvnorms[e->index].name);
1745 e->index = index;
1746 return 0;
1747 }
1748 case VIDIOC_G_STD:
1749 {
1750 v4l2_std_id *id = arg;
1751 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1752 return 0;
1753 }
1754 case VIDIOC_S_STD:
1755 {
1756 v4l2_std_id *id = arg;
1757 unsigned int i;
1758
1759 for (i = 0; i < BTTV_TVNORMS; i++)
1760 if (*id & bttv_tvnorms[i].v4l2_id)
1761 break;
1762 if (i == BTTV_TVNORMS)
1763 return -EINVAL;
1764
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001765 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 set_tvnorm(btv,i);
1767 i2c_vidiocschan(btv);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001768 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 return 0;
1770 }
1771 case VIDIOC_QUERYSTD:
1772 {
1773 v4l2_std_id *id = arg;
1774
1775 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1776 *id = V4L2_STD_625_50;
1777 else
1778 *id = V4L2_STD_525_60;
1779 return 0;
1780 }
1781
1782 case VIDIOC_ENUMINPUT:
1783 {
1784 struct v4l2_input *i = arg;
1785 unsigned int n;
1786
1787 n = i->index;
1788 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1789 return -EINVAL;
1790 memset(i,0,sizeof(*i));
1791 i->index = n;
1792 i->type = V4L2_INPUT_TYPE_CAMERA;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001793 i->audioset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1795 sprintf(i->name, "Television");
1796 i->type = V4L2_INPUT_TYPE_TUNER;
1797 i->tuner = 0;
1798 } else if (i->index == btv->svhs) {
1799 sprintf(i->name, "S-Video");
1800 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001801 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 }
1803 if (i->index == btv->input) {
1804 __u32 dstatus = btread(BT848_DSTATUS);
1805 if (0 == (dstatus & BT848_DSTATUS_PRES))
1806 i->status |= V4L2_IN_ST_NO_SIGNAL;
1807 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1808 i->status |= V4L2_IN_ST_NO_H_LOCK;
1809 }
1810 for (n = 0; n < BTTV_TVNORMS; n++)
1811 i->std |= bttv_tvnorms[n].v4l2_id;
1812 return 0;
1813 }
1814 case VIDIOC_G_INPUT:
1815 {
1816 int *i = arg;
1817 *i = btv->input;
1818 return 0;
1819 }
1820 case VIDIOC_S_INPUT:
1821 {
1822 unsigned int *i = arg;
1823
1824 if (*i > bttv_tvcards[btv->c.type].video_inputs)
1825 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001826 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 set_input(btv,*i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001828 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 return 0;
1830 }
1831
1832 case VIDIOC_G_TUNER:
1833 {
1834 struct v4l2_tuner *t = arg;
1835
1836 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1837 return -EINVAL;
1838 if (0 != t->index)
1839 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001840 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 memset(t,0,sizeof(*t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001843 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
1844 strcpy(t->name, "Television");
1845 t->capability = V4L2_TUNER_CAP_NORM;
1846 t->type = V4L2_TUNER_ANALOG_TV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
1848 t->signal = 0xffff;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001849
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001850 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 /* Hmmm ... */
1852 struct video_audio va;
1853 memset(&va, 0, sizeof(struct video_audio));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001854 btv->audio_hook(btv,&va,0);
1855 t->audmode = V4L2_TUNER_MODE_MONO;
1856 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 if(va.mode & VIDEO_SOUND_STEREO) {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001858 t->audmode = V4L2_TUNER_MODE_STEREO;
1859 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 }
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001861 if(va.mode & VIDEO_SOUND_LANG2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 t->audmode = V4L2_TUNER_MODE_LANG1;
1863 t->rxsubchans = V4L2_TUNER_SUB_LANG1
1864 | V4L2_TUNER_SUB_LANG2;
1865 }
1866 }
1867 /* FIXME: fill capability+audmode */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001868 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 return 0;
1870 }
1871 case VIDIOC_S_TUNER:
1872 {
1873 struct v4l2_tuner *t = arg;
1874
1875 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1876 return -EINVAL;
1877 if (0 != t->index)
1878 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001879 mutex_lock(&btv->lock);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001880 bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
1881 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 struct video_audio va;
1883 memset(&va, 0, sizeof(struct video_audio));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (t->audmode == V4L2_TUNER_MODE_MONO)
1885 va.mode = VIDEO_SOUND_MONO;
Hans Verkuil301e22d2006-03-18 17:15:00 -03001886 else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
1887 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 va.mode = VIDEO_SOUND_STEREO;
1889 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
1890 va.mode = VIDEO_SOUND_LANG1;
1891 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
1892 va.mode = VIDEO_SOUND_LANG2;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001893 btv->audio_hook(btv,&va,1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001895 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 return 0;
1897 }
1898
1899 case VIDIOC_G_FREQUENCY:
1900 {
1901 struct v4l2_frequency *f = arg;
1902
1903 memset(f,0,sizeof(*f));
1904 f->type = V4L2_TUNER_ANALOG_TV;
1905 f->frequency = btv->freq;
1906 return 0;
1907 }
1908 case VIDIOC_S_FREQUENCY:
1909 {
1910 struct v4l2_frequency *f = arg;
1911
1912 if (unlikely(f->tuner != 0))
1913 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07001914 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001916 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 btv->freq = f->frequency;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001918 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 if (btv->has_matchbox && btv->radio_user)
1920 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001921 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 return 0;
1923 }
Hans Verkuil299392b2005-11-08 21:37:42 -08001924 case VIDIOC_LOG_STATUS:
1925 {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001926 printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr);
Luiz Capitulino97cb4452005-12-01 00:51:24 -08001927 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001928 printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
Hans Verkuil299392b2005-11-08 21:37:42 -08001929 return 0;
1930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
1932 default:
1933 return -ENOIOCTLCMD;
1934
1935 }
1936 return 0;
1937}
1938
1939static int verify_window(const struct bttv_tvnorm *tvn,
1940 struct v4l2_window *win, int fixup)
1941{
1942 enum v4l2_field field;
1943 int maxw, maxh;
1944
1945 if (win->w.width < 48 || win->w.height < 32)
1946 return -EINVAL;
1947 if (win->clipcount > 2048)
1948 return -EINVAL;
1949
1950 field = win->field;
1951 maxw = tvn->swidth;
1952 maxh = tvn->sheight;
1953
1954 if (V4L2_FIELD_ANY == field) {
1955 field = (win->w.height > maxh/2)
1956 ? V4L2_FIELD_INTERLACED
1957 : V4L2_FIELD_TOP;
1958 }
1959 switch (field) {
1960 case V4L2_FIELD_TOP:
1961 case V4L2_FIELD_BOTTOM:
1962 maxh = maxh / 2;
1963 break;
1964 case V4L2_FIELD_INTERLACED:
1965 break;
1966 default:
1967 return -EINVAL;
1968 }
1969
1970 if (!fixup && (win->w.width > maxw || win->w.height > maxh))
1971 return -EINVAL;
1972
1973 if (win->w.width > maxw)
1974 win->w.width = maxw;
1975 if (win->w.height > maxh)
1976 win->w.height = maxh;
1977 win->field = field;
1978 return 0;
1979}
1980
1981static int setup_window(struct bttv_fh *fh, struct bttv *btv,
1982 struct v4l2_window *win, int fixup)
1983{
1984 struct v4l2_clip *clips = NULL;
1985 int n,size,retval = 0;
1986
1987 if (NULL == fh->ovfmt)
1988 return -EINVAL;
1989 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
1990 return -EINVAL;
1991 retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
1992 if (0 != retval)
1993 return retval;
1994
1995 /* copy clips -- luckily v4l1 + v4l2 are binary
1996 compatible here ...*/
1997 n = win->clipcount;
1998 size = sizeof(*clips)*(n+4);
1999 clips = kmalloc(size,GFP_KERNEL);
2000 if (NULL == clips)
2001 return -ENOMEM;
2002 if (n > 0) {
2003 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
2004 kfree(clips);
2005 return -EFAULT;
2006 }
2007 }
2008 /* clip against screen */
2009 if (NULL != btv->fbuf.base)
2010 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
2011 &win->w, clips, n);
2012 btcx_sort_clips(clips,n);
2013
2014 /* 4-byte alignments */
2015 switch (fh->ovfmt->depth) {
2016 case 8:
2017 case 24:
2018 btcx_align(&win->w, clips, n, 3);
2019 break;
2020 case 16:
2021 btcx_align(&win->w, clips, n, 1);
2022 break;
2023 case 32:
2024 /* no alignment fixups needed */
2025 break;
2026 default:
2027 BUG();
2028 }
2029
Ingo Molnar3593cab2006-02-07 06:49:14 -02002030 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002031 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 fh->ov.clips = clips;
2033 fh->ov.nclips = n;
2034
2035 fh->ov.w = win->w;
2036 fh->ov.field = win->field;
2037 fh->ov.setup_ok = 1;
2038 btv->init.ov.w.width = win->w.width;
2039 btv->init.ov.w.height = win->w.height;
2040 btv->init.ov.field = win->field;
2041
2042 /* update overlay if needed */
2043 retval = 0;
2044 if (check_btres(fh, RESOURCE_OVERLAY)) {
2045 struct bttv_buffer *new;
2046
2047 new = videobuf_alloc(sizeof(*new));
2048 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2049 retval = bttv_switch_overlay(btv,fh,new);
2050 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002051 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 return retval;
2053}
2054
2055/* ----------------------------------------------------------------------- */
2056
2057static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2058{
2059 struct videobuf_queue* q = NULL;
2060
2061 switch (fh->type) {
2062 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2063 q = &fh->cap;
2064 break;
2065 case V4L2_BUF_TYPE_VBI_CAPTURE:
2066 q = &fh->vbi;
2067 break;
2068 default:
2069 BUG();
2070 }
2071 return q;
2072}
2073
2074static int bttv_resource(struct bttv_fh *fh)
2075{
2076 int res = 0;
2077
2078 switch (fh->type) {
2079 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2080 res = RESOURCE_VIDEO;
2081 break;
2082 case V4L2_BUF_TYPE_VBI_CAPTURE:
2083 res = RESOURCE_VBI;
2084 break;
2085 default:
2086 BUG();
2087 }
2088 return res;
2089}
2090
2091static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2092{
2093 struct videobuf_queue *q = bttv_queue(fh);
2094 int res = bttv_resource(fh);
2095
2096 if (check_btres(fh,res))
2097 return -EBUSY;
2098 if (videobuf_queue_is_busy(q))
2099 return -EBUSY;
2100 fh->type = type;
2101 return 0;
2102}
2103
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002104static void
2105pix_format_set_size (struct v4l2_pix_format * f,
2106 const struct bttv_format * fmt,
2107 unsigned int width,
2108 unsigned int height)
2109{
2110 f->width = width;
2111 f->height = height;
2112
2113 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2114 f->bytesperline = width; /* Y plane */
2115 f->sizeimage = (width * height * fmt->depth) >> 3;
2116 } else {
2117 f->bytesperline = (width * fmt->depth) >> 3;
2118 f->sizeimage = height * f->bytesperline;
2119 }
2120}
2121
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2123{
2124 switch (f->type) {
2125 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2126 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002127 pix_format_set_size (&f->fmt.pix, fh->fmt,
2128 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 f->fmt.pix.field = fh->cap.field;
2130 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 return 0;
2132 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2133 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2134 f->fmt.win.w = fh->ov.w;
2135 f->fmt.win.field = fh->ov.field;
2136 return 0;
2137 case V4L2_BUF_TYPE_VBI_CAPTURE:
2138 bttv_vbi_get_fmt(fh,f);
2139 return 0;
2140 default:
2141 return -EINVAL;
2142 }
2143}
2144
2145static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
2146 struct v4l2_format *f)
2147{
2148 switch (f->type) {
2149 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2150 {
2151 const struct bttv_format *fmt;
2152 enum v4l2_field field;
2153 unsigned int maxw,maxh;
2154
2155 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2156 if (NULL == fmt)
2157 return -EINVAL;
2158
2159 /* fixup format */
2160 maxw = bttv_tvnorms[btv->tvnorm].swidth;
2161 maxh = bttv_tvnorms[btv->tvnorm].sheight;
2162 field = f->fmt.pix.field;
2163 if (V4L2_FIELD_ANY == field)
2164 field = (f->fmt.pix.height > maxh/2)
2165 ? V4L2_FIELD_INTERLACED
2166 : V4L2_FIELD_BOTTOM;
2167 if (V4L2_FIELD_SEQ_BT == field)
2168 field = V4L2_FIELD_SEQ_TB;
2169 switch (field) {
2170 case V4L2_FIELD_TOP:
2171 case V4L2_FIELD_BOTTOM:
2172 case V4L2_FIELD_ALTERNATE:
2173 maxh = maxh/2;
2174 break;
2175 case V4L2_FIELD_INTERLACED:
2176 break;
2177 case V4L2_FIELD_SEQ_TB:
2178 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2179 return -EINVAL;
2180 break;
2181 default:
2182 return -EINVAL;
2183 }
2184
2185 /* update data for the application */
2186 f->fmt.pix.field = field;
2187 if (f->fmt.pix.width < 48)
2188 f->fmt.pix.width = 48;
2189 if (f->fmt.pix.height < 32)
2190 f->fmt.pix.height = 32;
2191 if (f->fmt.pix.width > maxw)
2192 f->fmt.pix.width = maxw;
2193 if (f->fmt.pix.height > maxh)
2194 f->fmt.pix.height = maxh;
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002195 pix_format_set_size (&f->fmt.pix, fmt,
2196 f->fmt.pix.width & ~3,
2197 f->fmt.pix.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
2199 return 0;
2200 }
2201 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2202 return verify_window(&bttv_tvnorms[btv->tvnorm],
2203 &f->fmt.win, 1);
2204 case V4L2_BUF_TYPE_VBI_CAPTURE:
2205 bttv_vbi_try_fmt(fh,f);
2206 return 0;
2207 default:
2208 return -EINVAL;
2209 }
2210}
2211
2212static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2213 struct v4l2_format *f)
2214{
2215 int retval;
2216
2217 switch (f->type) {
2218 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2219 {
2220 const struct bttv_format *fmt;
2221
2222 retval = bttv_switch_type(fh,f->type);
2223 if (0 != retval)
2224 return retval;
2225 retval = bttv_try_fmt(fh,btv,f);
2226 if (0 != retval)
2227 return retval;
2228 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2229
2230 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002231 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 fh->fmt = fmt;
2233 fh->cap.field = f->fmt.pix.field;
2234 fh->cap.last = V4L2_FIELD_NONE;
2235 fh->width = f->fmt.pix.width;
2236 fh->height = f->fmt.pix.height;
2237 btv->init.fmt = fmt;
2238 btv->init.width = f->fmt.pix.width;
2239 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002240 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
2242 return 0;
2243 }
2244 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002245 if (no_overlay > 0) {
2246 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2247 return -EINVAL;
2248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 return setup_window(fh, btv, &f->fmt.win, 1);
2250 case V4L2_BUF_TYPE_VBI_CAPTURE:
2251 retval = bttv_switch_type(fh,f->type);
2252 if (0 != retval)
2253 return retval;
2254 if (locked_btres(fh->btv, RESOURCE_VBI))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002255 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 bttv_vbi_try_fmt(fh,f);
2257 bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
2258 bttv_vbi_get_fmt(fh,f);
2259 return 0;
2260 default:
2261 return -EINVAL;
2262 }
2263}
2264
2265static int bttv_do_ioctl(struct inode *inode, struct file *file,
2266 unsigned int cmd, void *arg)
2267{
2268 struct bttv_fh *fh = file->private_data;
2269 struct bttv *btv = fh->btv;
2270 unsigned long flags;
2271 int retval = 0;
2272
Michael Krufky5e453dc2006-01-09 15:32:31 -02002273 if (bttv_debug > 1)
2274 v4l_print_ioctl(btv->c.name, cmd);
2275
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 if (btv->errors)
2277 bttv_reinit_bt848(btv);
2278
2279 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002280 case VIDIOCSFREQ:
2281 case VIDIOCSTUNER:
2282 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 case VIDIOC_S_CTRL:
2284 case VIDIOC_S_STD:
2285 case VIDIOC_S_INPUT:
2286 case VIDIOC_S_TUNER:
2287 case VIDIOC_S_FREQUENCY:
2288 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2289 if (0 != retval)
2290 return retval;
2291 };
2292
2293 switch (cmd) {
2294
2295 /* *** v4l1 *** ************************************************ */
2296 case VIDIOCGCAP:
2297 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002298 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299
2300 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002301 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2303 /* vbi */
2304 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2305 } else {
2306 /* others */
2307 cap->type = VID_TYPE_CAPTURE|
2308 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 VID_TYPE_CLIPPING|
2310 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002311 if (no_overlay <= 0)
2312 cap->type |= VID_TYPE_OVERLAY;
2313
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2315 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2316 cap->minwidth = 48;
2317 cap->minheight = 32;
2318 }
2319 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2320 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002321 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 }
2323
2324 case VIDIOCGPICT:
2325 {
2326 struct video_picture *pic = arg;
2327
2328 memset(pic,0,sizeof(*pic));
2329 pic->brightness = btv->bright;
2330 pic->contrast = btv->contrast;
2331 pic->hue = btv->hue;
2332 pic->colour = btv->saturation;
2333 if (fh->fmt) {
2334 pic->depth = fh->fmt->depth;
2335 pic->palette = fh->fmt->palette;
2336 }
2337 return 0;
2338 }
2339 case VIDIOCSPICT:
2340 {
2341 struct video_picture *pic = arg;
2342 const struct bttv_format *fmt;
2343
2344 fmt = format_by_palette(pic->palette);
2345 if (NULL == fmt)
2346 return -EINVAL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002347 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 if (fmt->depth != pic->depth) {
2349 retval = -EINVAL;
2350 goto fh_unlock_and_return;
2351 }
Michael H. Schimek13c72802005-12-01 00:51:37 -08002352 if (fmt->flags & FORMAT_FLAGS_RAW) {
2353 /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
2354 RAW_LINES * 2. F1 is stored at offset 0, F2
2355 at buffer size / 2. */
2356 fh->width = RAW_BPL;
2357 fh->height = gbufsize / RAW_BPL;
2358 btv->init.width = RAW_BPL;
2359 btv->init.height = gbufsize / RAW_BPL;
2360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 fh->ovfmt = fmt;
2362 fh->fmt = fmt;
2363 btv->init.ovfmt = fmt;
2364 btv->init.fmt = fmt;
2365 if (bigendian) {
2366 /* dirty hack time: swap bytes for overlay if the
2367 display adaptor is big endian (insmod option) */
2368 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2369 fmt->palette == VIDEO_PALETTE_RGB565 ||
2370 fmt->palette == VIDEO_PALETTE_RGB32) {
2371 fh->ovfmt = fmt+1;
2372 }
2373 }
2374 bt848_bright(btv,pic->brightness);
2375 bt848_contrast(btv,pic->contrast);
2376 bt848_hue(btv,pic->hue);
2377 bt848_sat(btv,pic->colour);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002378 mutex_unlock(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002379 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
2381
2382 case VIDIOCGWIN:
2383 {
2384 struct video_window *win = arg;
2385
2386 memset(win,0,sizeof(*win));
2387 win->x = fh->ov.w.left;
2388 win->y = fh->ov.w.top;
2389 win->width = fh->ov.w.width;
2390 win->height = fh->ov.w.height;
2391 return 0;
2392 }
2393 case VIDIOCSWIN:
2394 {
2395 struct video_window *win = arg;
2396 struct v4l2_window w2;
2397
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002398 if (no_overlay > 0) {
2399 printk ("VIDIOCSWIN: no_overlay\n");
2400 return -EINVAL;
2401 }
2402
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 w2.field = V4L2_FIELD_ANY;
2404 w2.w.left = win->x;
2405 w2.w.top = win->y;
2406 w2.w.width = win->width;
2407 w2.w.height = win->height;
2408 w2.clipcount = win->clipcount;
2409 w2.clips = (struct v4l2_clip __user *)win->clips;
2410 retval = setup_window(fh, btv, &w2, 0);
2411 if (0 == retval) {
2412 /* on v4l1 this ioctl affects the read() size too */
2413 fh->width = fh->ov.w.width;
2414 fh->height = fh->ov.w.height;
2415 btv->init.width = fh->ov.w.width;
2416 btv->init.height = fh->ov.w.height;
2417 }
2418 return retval;
2419 }
2420
2421 case VIDIOCGFBUF:
2422 {
2423 struct video_buffer *fbuf = arg;
2424
2425 fbuf->base = btv->fbuf.base;
2426 fbuf->width = btv->fbuf.fmt.width;
2427 fbuf->height = btv->fbuf.fmt.height;
2428 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2429 if (fh->ovfmt)
2430 fbuf->depth = fh->ovfmt->depth;
2431 return 0;
2432 }
2433 case VIDIOCSFBUF:
2434 {
2435 struct video_buffer *fbuf = arg;
2436 const struct bttv_format *fmt;
2437 unsigned long end;
2438
2439 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002440 !capable(CAP_SYS_RAWIO))
2441 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 end = (unsigned long)fbuf->base +
2443 fbuf->height * fbuf->bytesperline;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002444 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 retval = -EINVAL;
2446
2447 switch (fbuf->depth) {
2448 case 8:
2449 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2450 break;
2451 case 16:
2452 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2453 break;
2454 case 24:
2455 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2456 break;
2457 case 32:
2458 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2459 break;
2460 case 15:
2461 fbuf->depth = 16;
2462 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2463 break;
2464 default:
2465 fmt = NULL;
2466 break;
2467 }
2468 if (NULL == fmt)
2469 goto fh_unlock_and_return;
2470
2471 fh->ovfmt = fmt;
2472 fh->fmt = fmt;
2473 btv->init.ovfmt = fmt;
2474 btv->init.fmt = fmt;
2475 btv->fbuf.base = fbuf->base;
2476 btv->fbuf.fmt.width = fbuf->width;
2477 btv->fbuf.fmt.height = fbuf->height;
2478 if (fbuf->bytesperline)
2479 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
2480 else
2481 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002482 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 return 0;
2484 }
2485
2486 case VIDIOCCAPTURE:
2487 case VIDIOC_OVERLAY:
2488 {
2489 struct bttv_buffer *new;
2490 int *on = arg;
2491
2492 if (*on) {
2493 /* verify args */
2494 if (NULL == btv->fbuf.base)
2495 return -EINVAL;
2496 if (!fh->ov.setup_ok) {
2497 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2498 return -EINVAL;
2499 }
2500 }
2501
2502 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2503 return -EBUSY;
2504
Ingo Molnar3593cab2006-02-07 06:49:14 -02002505 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 if (*on) {
2507 fh->ov.tvnorm = btv->tvnorm;
2508 new = videobuf_alloc(sizeof(*new));
2509 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2510 } else {
2511 new = NULL;
2512 }
2513
2514 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002515 retval = bttv_switch_overlay(btv,fh,new);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002516 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 return retval;
2518 }
2519
2520 case VIDIOCGMBUF:
2521 {
2522 struct video_mbuf *mbuf = arg;
2523 unsigned int i;
2524
Ingo Molnar3593cab2006-02-07 06:49:14 -02002525 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2527 V4L2_MEMORY_MMAP);
2528 if (retval < 0)
2529 goto fh_unlock_and_return;
2530 memset(mbuf,0,sizeof(*mbuf));
2531 mbuf->frames = gbuffers;
2532 mbuf->size = gbuffers * gbufsize;
2533 for (i = 0; i < gbuffers; i++)
2534 mbuf->offsets[i] = i * gbufsize;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002535 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 return 0;
2537 }
2538 case VIDIOCMCAPTURE:
2539 {
2540 struct video_mmap *vm = arg;
2541 struct bttv_buffer *buf;
2542 enum v4l2_field field;
2543
2544 if (vm->frame >= VIDEO_MAX_FRAME)
2545 return -EINVAL;
2546
Ingo Molnar3593cab2006-02-07 06:49:14 -02002547 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 retval = -EINVAL;
2549 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
2550 if (NULL == buf)
2551 goto fh_unlock_and_return;
2552 if (0 == buf->vb.baddr)
2553 goto fh_unlock_and_return;
2554 if (buf->vb.state == STATE_QUEUED ||
2555 buf->vb.state == STATE_ACTIVE)
2556 goto fh_unlock_and_return;
2557
2558 field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
2559 ? V4L2_FIELD_INTERLACED
2560 : V4L2_FIELD_BOTTOM;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03002561 retval = bttv_prepare_buffer(&fh->cap,btv,buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 format_by_palette(vm->format),
2563 vm->width,vm->height,field);
2564 if (0 != retval)
2565 goto fh_unlock_and_return;
2566 spin_lock_irqsave(&btv->s_lock,flags);
2567 buffer_queue(&fh->cap,&buf->vb);
2568 spin_unlock_irqrestore(&btv->s_lock,flags);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002569 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 return 0;
2571 }
2572 case VIDIOCSYNC:
2573 {
2574 int *frame = arg;
2575 struct bttv_buffer *buf;
2576
2577 if (*frame >= VIDEO_MAX_FRAME)
2578 return -EINVAL;
2579
Ingo Molnar3593cab2006-02-07 06:49:14 -02002580 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 retval = -EINVAL;
2582 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
2583 if (NULL == buf)
2584 goto fh_unlock_and_return;
2585 retval = videobuf_waiton(&buf->vb,0,1);
2586 if (0 != retval)
2587 goto fh_unlock_and_return;
2588 switch (buf->vb.state) {
2589 case STATE_ERROR:
2590 retval = -EIO;
2591 /* fall through */
2592 case STATE_DONE:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03002593 videobuf_dma_sync(&fh->cap,&buf->vb.dma);
2594 bttv_dma_free(&fh->cap,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 break;
2596 default:
2597 retval = -EINVAL;
2598 break;
2599 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002600 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 return retval;
2602 }
2603
2604 case VIDIOCGVBIFMT:
2605 {
2606 struct vbi_format *fmt = (void *) arg;
2607 struct v4l2_format fmt2;
2608
2609 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
2610 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2611 if (0 != retval)
2612 return retval;
2613 }
2614 bttv_vbi_get_fmt(fh, &fmt2);
2615
2616 memset(fmt,0,sizeof(*fmt));
2617 fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
2618 fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
2619 fmt->sample_format = VIDEO_PALETTE_RAW;
2620 fmt->start[0] = fmt2.fmt.vbi.start[0];
2621 fmt->count[0] = fmt2.fmt.vbi.count[0];
2622 fmt->start[1] = fmt2.fmt.vbi.start[1];
2623 fmt->count[1] = fmt2.fmt.vbi.count[1];
Michael H. Schimek67f15702006-01-09 15:25:27 -02002624 if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
2625 fmt->flags |= VBI_UNSYNC;
2626 if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
2627 fmt->flags |= VBI_INTERLACED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 return 0;
2629 }
2630 case VIDIOCSVBIFMT:
2631 {
2632 struct vbi_format *fmt = (void *) arg;
2633 struct v4l2_format fmt2;
2634
2635 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2636 if (0 != retval)
2637 return retval;
2638 bttv_vbi_get_fmt(fh, &fmt2);
2639
2640 if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
2641 fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
2642 fmt->sample_format != VIDEO_PALETTE_RAW ||
2643 fmt->start[0] != fmt2.fmt.vbi.start[0] ||
2644 fmt->start[1] != fmt2.fmt.vbi.start[1] ||
2645 fmt->count[0] != fmt->count[1] ||
2646 fmt->count[0] < 1 ||
2647 fmt->count[0] > 32 /* VBI_MAXLINES */)
2648 return -EINVAL;
2649
2650 bttv_vbi_setlines(fh,btv,fmt->count[0]);
2651 return 0;
2652 }
2653
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002654 case BTTV_VERSION:
2655 case VIDIOCGFREQ:
2656 case VIDIOCSFREQ:
2657 case VIDIOCGTUNER:
2658 case VIDIOCSTUNER:
2659 case VIDIOCGCHAN:
2660 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 case VIDIOCGAUDIO:
2662 case VIDIOCSAUDIO:
2663 return bttv_common_ioctls(btv,cmd,arg);
2664
2665 /* *** v4l2 *** ************************************************ */
2666 case VIDIOC_QUERYCAP:
2667 {
2668 struct v4l2_capability *cap = arg;
2669
2670 if (0 == v4l2)
2671 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002672 memset(cap, 0, sizeof (*cap));
2673 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
2674 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
2675 snprintf(cap->bus_info, sizeof (cap->bus_info),
2676 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 cap->version = BTTV_VERSION_CODE;
2678 cap->capabilities =
2679 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 V4L2_CAP_VBI_CAPTURE |
2681 V4L2_CAP_READWRITE |
2682 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002683 if (no_overlay <= 0)
2684 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2685
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2687 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2688 cap->capabilities |= V4L2_CAP_TUNER;
2689 return 0;
2690 }
2691
2692 case VIDIOC_ENUM_FMT:
2693 {
2694 struct v4l2_fmtdesc *f = arg;
2695 enum v4l2_buf_type type;
2696 unsigned int i;
2697 int index;
2698
2699 type = f->type;
2700 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2701 /* vbi */
2702 index = f->index;
2703 if (0 != index)
2704 return -EINVAL;
2705 memset(f,0,sizeof(*f));
2706 f->index = index;
2707 f->type = type;
2708 f->pixelformat = V4L2_PIX_FMT_GREY;
2709 strcpy(f->description,"vbi data");
2710 return 0;
2711 }
2712
2713 /* video capture + overlay */
2714 index = -1;
2715 for (i = 0; i < BTTV_FORMATS; i++) {
2716 if (bttv_formats[i].fourcc != -1)
2717 index++;
2718 if ((unsigned int)index == f->index)
2719 break;
2720 }
2721 if (BTTV_FORMATS == i)
2722 return -EINVAL;
2723
2724 switch (f->type) {
2725 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2726 break;
2727 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2728 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2729 return -EINVAL;
2730 break;
2731 default:
2732 return -EINVAL;
2733 }
2734 memset(f,0,sizeof(*f));
2735 f->index = index;
2736 f->type = type;
2737 f->pixelformat = bttv_formats[i].fourcc;
2738 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2739 return 0;
2740 }
2741
2742 case VIDIOC_TRY_FMT:
2743 {
2744 struct v4l2_format *f = arg;
2745 return bttv_try_fmt(fh,btv,f);
2746 }
2747 case VIDIOC_G_FMT:
2748 {
2749 struct v4l2_format *f = arg;
2750 return bttv_g_fmt(fh,f);
2751 }
2752 case VIDIOC_S_FMT:
2753 {
2754 struct v4l2_format *f = arg;
2755 return bttv_s_fmt(fh,btv,f);
2756 }
2757
2758 case VIDIOC_G_FBUF:
2759 {
2760 struct v4l2_framebuffer *fb = arg;
2761
2762 *fb = btv->fbuf;
2763 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2764 if (fh->ovfmt)
2765 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2766 return 0;
2767 }
2768 case VIDIOC_S_FBUF:
2769 {
2770 struct v4l2_framebuffer *fb = arg;
2771 const struct bttv_format *fmt;
2772
2773 if(!capable(CAP_SYS_ADMIN) &&
2774 !capable(CAP_SYS_RAWIO))
2775 return -EPERM;
2776
2777 /* check args */
2778 fmt = format_by_fourcc(fb->fmt.pixelformat);
2779 if (NULL == fmt)
2780 return -EINVAL;
2781 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2782 return -EINVAL;
2783
Ingo Molnar3593cab2006-02-07 06:49:14 -02002784 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 retval = -EINVAL;
2786 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2787 if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
2788 goto fh_unlock_and_return;
2789 if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
2790 goto fh_unlock_and_return;
2791 }
2792
2793 /* ok, accept it */
2794 btv->fbuf.base = fb->base;
2795 btv->fbuf.fmt.width = fb->fmt.width;
2796 btv->fbuf.fmt.height = fb->fmt.height;
2797 if (0 != fb->fmt.bytesperline)
2798 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2799 else
2800 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2801
2802 retval = 0;
2803 fh->ovfmt = fmt;
2804 btv->init.ovfmt = fmt;
2805 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2806 fh->ov.w.left = 0;
2807 fh->ov.w.top = 0;
2808 fh->ov.w.width = fb->fmt.width;
2809 fh->ov.w.height = fb->fmt.height;
2810 btv->init.ov.w.width = fb->fmt.width;
2811 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002812 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 fh->ov.clips = NULL;
2814 fh->ov.nclips = 0;
2815
2816 if (check_btres(fh, RESOURCE_OVERLAY)) {
2817 struct bttv_buffer *new;
2818
2819 new = videobuf_alloc(sizeof(*new));
2820 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2821 retval = bttv_switch_overlay(btv,fh,new);
2822 }
2823 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002824 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 return retval;
2826 }
2827
2828 case VIDIOC_REQBUFS:
2829 return videobuf_reqbufs(bttv_queue(fh),arg);
2830
2831 case VIDIOC_QUERYBUF:
2832 return videobuf_querybuf(bttv_queue(fh),arg);
2833
2834 case VIDIOC_QBUF:
2835 return videobuf_qbuf(bttv_queue(fh),arg);
2836
2837 case VIDIOC_DQBUF:
2838 return videobuf_dqbuf(bttv_queue(fh),arg,
2839 file->f_flags & O_NONBLOCK);
2840
2841 case VIDIOC_STREAMON:
2842 {
2843 int res = bttv_resource(fh);
2844
2845 if (!check_alloc_btres(btv,fh,res))
2846 return -EBUSY;
2847 return videobuf_streamon(bttv_queue(fh));
2848 }
2849 case VIDIOC_STREAMOFF:
2850 {
2851 int res = bttv_resource(fh);
2852
2853 retval = videobuf_streamoff(bttv_queue(fh));
2854 if (retval < 0)
2855 return retval;
2856 free_btres(btv,fh,res);
2857 return 0;
2858 }
2859
2860 case VIDIOC_QUERYCTRL:
2861 {
2862 struct v4l2_queryctrl *c = arg;
2863 int i;
2864
2865 if ((c->id < V4L2_CID_BASE ||
2866 c->id >= V4L2_CID_LASTP1) &&
2867 (c->id < V4L2_CID_PRIVATE_BASE ||
2868 c->id >= V4L2_CID_PRIVATE_LASTP1))
2869 return -EINVAL;
2870 for (i = 0; i < BTTV_CTLS; i++)
2871 if (bttv_ctls[i].id == c->id)
2872 break;
2873 if (i == BTTV_CTLS) {
2874 *c = no_ctl;
2875 return 0;
2876 }
2877 *c = bttv_ctls[i];
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002878 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 struct video_audio va;
2880 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002881 btv->audio_hook(btv,&va,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 switch (bttv_ctls[i].id) {
2883 case V4L2_CID_AUDIO_VOLUME:
2884 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2885 *c = no_ctl;
2886 break;
2887 case V4L2_CID_AUDIO_BALANCE:
2888 if (!(va.flags & VIDEO_AUDIO_BALANCE))
2889 *c = no_ctl;
2890 break;
2891 case V4L2_CID_AUDIO_BASS:
2892 if (!(va.flags & VIDEO_AUDIO_BASS))
2893 *c = no_ctl;
2894 break;
2895 case V4L2_CID_AUDIO_TREBLE:
2896 if (!(va.flags & VIDEO_AUDIO_TREBLE))
2897 *c = no_ctl;
2898 break;
2899 }
2900 }
2901 return 0;
2902 }
2903 case VIDIOC_G_CTRL:
2904 return get_control(btv,arg);
2905 case VIDIOC_S_CTRL:
2906 return set_control(btv,arg);
2907 case VIDIOC_G_PARM:
2908 {
2909 struct v4l2_streamparm *parm = arg;
2910 struct v4l2_standard s;
2911 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2912 return -EINVAL;
2913 memset(parm,0,sizeof(*parm));
2914 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2915 bttv_tvnorms[btv->tvnorm].name);
2916 parm->parm.capture.timeperframe = s.frameperiod;
2917 return 0;
2918 }
2919
2920 case VIDIOC_G_PRIORITY:
2921 {
2922 enum v4l2_priority *p = arg;
2923
2924 *p = v4l2_prio_max(&btv->prio);
2925 return 0;
2926 }
2927 case VIDIOC_S_PRIORITY:
2928 {
2929 enum v4l2_priority *prio = arg;
2930
2931 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
2932 }
2933
2934 case VIDIOC_ENUMSTD:
2935 case VIDIOC_G_STD:
2936 case VIDIOC_S_STD:
2937 case VIDIOC_ENUMINPUT:
2938 case VIDIOC_G_INPUT:
2939 case VIDIOC_S_INPUT:
2940 case VIDIOC_G_TUNER:
2941 case VIDIOC_S_TUNER:
2942 case VIDIOC_G_FREQUENCY:
2943 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08002944 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 return bttv_common_ioctls(btv,cmd,arg);
2946
2947 default:
2948 return -ENOIOCTLCMD;
2949 }
2950 return 0;
2951
2952 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02002953 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 return retval;
2955}
2956
2957static int bttv_ioctl(struct inode *inode, struct file *file,
2958 unsigned int cmd, unsigned long arg)
2959{
2960 struct bttv_fh *fh = file->private_data;
2961
2962 switch (cmd) {
2963 case BTTV_VBISIZE:
2964 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2965 return fh->lines * 2 * 2048;
2966 default:
2967 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
2968 }
2969}
2970
2971static ssize_t bttv_read(struct file *file, char __user *data,
2972 size_t count, loff_t *ppos)
2973{
2974 struct bttv_fh *fh = file->private_data;
2975 int retval = 0;
2976
2977 if (fh->btv->errors)
2978 bttv_reinit_bt848(fh->btv);
2979 dprintk("bttv%d: read count=%d type=%s\n",
2980 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
2981
2982 switch (fh->type) {
2983 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2984 if (locked_btres(fh->btv,RESOURCE_VIDEO))
2985 return -EBUSY;
2986 retval = videobuf_read_one(&fh->cap, data, count, ppos,
2987 file->f_flags & O_NONBLOCK);
2988 break;
2989 case V4L2_BUF_TYPE_VBI_CAPTURE:
2990 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2991 return -EBUSY;
2992 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
2993 file->f_flags & O_NONBLOCK);
2994 break;
2995 default:
2996 BUG();
2997 }
2998 return retval;
2999}
3000
3001static unsigned int bttv_poll(struct file *file, poll_table *wait)
3002{
3003 struct bttv_fh *fh = file->private_data;
3004 struct bttv_buffer *buf;
3005 enum v4l2_field field;
3006
3007 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
3008 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3009 return POLLERR;
3010 return videobuf_poll_stream(file, &fh->vbi, wait);
3011 }
3012
3013 if (check_btres(fh,RESOURCE_VIDEO)) {
3014 /* streaming capture */
3015 if (list_empty(&fh->cap.stream))
3016 return POLLERR;
3017 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
3018 } else {
3019 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02003020 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 if (NULL == fh->cap.read_buf) {
3022 /* need to capture a new frame */
3023 if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003024 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 return POLLERR;
3026 }
3027 fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
3028 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003029 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 return POLLERR;
3031 }
3032 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
3033 field = videobuf_next_field(&fh->cap);
3034 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08003035 kfree (fh->cap.read_buf);
3036 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003037 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 return POLLERR;
3039 }
3040 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3041 fh->cap.read_off = 0;
3042 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003043 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 buf = (struct bttv_buffer*)fh->cap.read_buf;
3045 }
3046
3047 poll_wait(file, &buf->vb.done, wait);
3048 if (buf->vb.state == STATE_DONE ||
3049 buf->vb.state == STATE_ERROR)
3050 return POLLIN|POLLRDNORM;
3051 return 0;
3052}
3053
3054static int bttv_open(struct inode *inode, struct file *file)
3055{
3056 int minor = iminor(inode);
3057 struct bttv *btv = NULL;
3058 struct bttv_fh *fh;
3059 enum v4l2_buf_type type = 0;
3060 unsigned int i;
3061
3062 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3063
3064 for (i = 0; i < bttv_num; i++) {
3065 if (bttvs[i].video_dev &&
3066 bttvs[i].video_dev->minor == minor) {
3067 btv = &bttvs[i];
3068 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3069 break;
3070 }
3071 if (bttvs[i].vbi_dev &&
3072 bttvs[i].vbi_dev->minor == minor) {
3073 btv = &bttvs[i];
3074 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3075 break;
3076 }
3077 }
3078 if (NULL == btv)
3079 return -ENODEV;
3080
3081 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3082 btv->c.nr,v4l2_type_names[type]);
3083
3084 /* allocate per filehandle data */
3085 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3086 if (NULL == fh)
3087 return -ENOMEM;
3088 file->private_data = fh;
3089 *fh = btv->init;
3090 fh->type = type;
3091 fh->ov.setup_ok = 0;
3092 v4l2_prio_open(&btv->prio,&fh->prio);
3093
3094 videobuf_queue_init(&fh->cap, &bttv_video_qops,
3095 btv->c.pci, &btv->s_lock,
3096 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3097 V4L2_FIELD_INTERLACED,
3098 sizeof(struct bttv_buffer),
3099 fh);
3100 videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
3101 btv->c.pci, &btv->s_lock,
3102 V4L2_BUF_TYPE_VBI_CAPTURE,
3103 V4L2_FIELD_SEQ_TB,
3104 sizeof(struct bttv_buffer),
3105 fh);
3106 i2c_vidiocschan(btv);
3107
3108 btv->users++;
3109 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
3110 bttv_vbi_setlines(fh,btv,16);
3111 bttv_field_count(btv);
3112 return 0;
3113}
3114
3115static int bttv_release(struct inode *inode, struct file *file)
3116{
3117 struct bttv_fh *fh = file->private_data;
3118 struct bttv *btv = fh->btv;
3119
3120 /* turn off overlay */
3121 if (check_btres(fh, RESOURCE_OVERLAY))
3122 bttv_switch_overlay(btv,fh,NULL);
3123
3124 /* stop video capture */
3125 if (check_btres(fh, RESOURCE_VIDEO)) {
3126 videobuf_streamoff(&fh->cap);
3127 free_btres(btv,fh,RESOURCE_VIDEO);
3128 }
3129 if (fh->cap.read_buf) {
3130 buffer_release(&fh->cap,fh->cap.read_buf);
3131 kfree(fh->cap.read_buf);
3132 }
3133
3134 /* stop vbi capture */
3135 if (check_btres(fh, RESOURCE_VBI)) {
3136 if (fh->vbi.streaming)
3137 videobuf_streamoff(&fh->vbi);
3138 if (fh->vbi.reading)
3139 videobuf_read_stop(&fh->vbi);
3140 free_btres(btv,fh,RESOURCE_VBI);
3141 }
3142
3143 /* free stuff */
3144 videobuf_mmap_free(&fh->cap);
3145 videobuf_mmap_free(&fh->vbi);
3146 v4l2_prio_close(&btv->prio,&fh->prio);
3147 file->private_data = NULL;
3148 kfree(fh);
3149
3150 btv->users--;
3151 bttv_field_count(btv);
3152 return 0;
3153}
3154
3155static int
3156bttv_mmap(struct file *file, struct vm_area_struct *vma)
3157{
3158 struct bttv_fh *fh = file->private_data;
3159
3160 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3161 fh->btv->c.nr, v4l2_type_names[fh->type],
3162 vma->vm_start, vma->vm_end - vma->vm_start);
3163 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3164}
3165
3166static struct file_operations bttv_fops =
3167{
3168 .owner = THIS_MODULE,
3169 .open = bttv_open,
3170 .release = bttv_release,
3171 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003172 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 .llseek = no_llseek,
3174 .read = bttv_read,
3175 .mmap = bttv_mmap,
3176 .poll = bttv_poll,
3177};
3178
3179static struct video_device bttv_video_template =
3180{
3181 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003182 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003183 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 .hardware = VID_HARDWARE_BT848,
3185 .fops = &bttv_fops,
3186 .minor = -1,
3187};
3188
3189static struct video_device bttv_vbi_template =
3190{
3191 .name = "bt848/878 vbi",
3192 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
3193 .hardware = VID_HARDWARE_BT848,
3194 .fops = &bttv_fops,
3195 .minor = -1,
3196};
3197
3198/* ----------------------------------------------------------------------- */
3199/* radio interface */
3200
3201static int radio_open(struct inode *inode, struct file *file)
3202{
3203 int minor = iminor(inode);
3204 struct bttv *btv = NULL;
3205 unsigned int i;
3206
3207 dprintk("bttv: open minor=%d\n",minor);
3208
3209 for (i = 0; i < bttv_num; i++) {
3210 if (bttvs[i].radio_dev->minor == minor) {
3211 btv = &bttvs[i];
3212 break;
3213 }
3214 }
3215 if (NULL == btv)
3216 return -ENODEV;
3217
3218 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003219 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003220
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003222
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 file->private_data = btv;
3224
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003225 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3226 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003228 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003229 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230}
3231
3232static int radio_release(struct inode *inode, struct file *file)
3233{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003234 struct bttv *btv = file->private_data;
3235 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236
3237 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003238
3239 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3240
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 return 0;
3242}
3243
3244static int radio_do_ioctl(struct inode *inode, struct file *file,
3245 unsigned int cmd, void *arg)
3246{
3247 struct bttv *btv = file->private_data;
3248
3249 switch (cmd) {
3250 case VIDIOCGCAP:
3251 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003252 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253
3254 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003255 strcpy(cap->name,btv->radio_dev->name);
3256 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 cap->channels = 1;
3258 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003259 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 }
3261
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003262 case VIDIOCGTUNER:
3263 {
3264 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003266 if(v->tuner)
3267 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003269 strcpy(v->name, "Radio");
3270 bttv_call_i2c_clients(btv,cmd,v);
3271 return 0;
3272 }
3273 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 /* nothing to do */
3275 return 0;
3276
3277 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003278 case VIDIOCGFREQ:
3279 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 case VIDIOCGAUDIO:
3281 case VIDIOCSAUDIO:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003282 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 return bttv_common_ioctls(btv,cmd,arg);
3284
3285 default:
3286 return -ENOIOCTLCMD;
3287 }
3288 return 0;
3289}
3290
3291static int radio_ioctl(struct inode *inode, struct file *file,
3292 unsigned int cmd, unsigned long arg)
3293{
3294 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3295}
3296
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003297static ssize_t radio_read(struct file *file, char __user *data,
3298 size_t count, loff_t *ppos)
3299{
3300 struct bttv *btv = file->private_data;
3301 struct rds_command cmd;
3302 cmd.block_count = count/3;
3303 cmd.buffer = data;
3304 cmd.instance = file;
3305 cmd.result = -ENODEV;
3306
3307 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3308
3309 return cmd.result;
3310}
3311
3312static unsigned int radio_poll(struct file *file, poll_table *wait)
3313{
3314 struct bttv *btv = file->private_data;
3315 struct rds_command cmd;
3316 cmd.instance = file;
3317 cmd.event_list = wait;
3318 cmd.result = -ENODEV;
3319 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3320
3321 return cmd.result;
3322}
3323
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324static struct file_operations radio_fops =
3325{
3326 .owner = THIS_MODULE,
3327 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003328 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 .release = radio_release,
3330 .ioctl = radio_ioctl,
3331 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003332 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333};
3334
3335static struct video_device radio_template =
3336{
3337 .name = "bt848/878 radio",
3338 .type = VID_TYPE_TUNER,
3339 .hardware = VID_HARDWARE_BT848,
3340 .fops = &radio_fops,
3341 .minor = -1,
3342};
3343
3344/* ----------------------------------------------------------------------- */
3345/* some debug code */
3346
Adrian Bunk408b6642005-05-01 08:59:29 -07003347static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348{
3349 static char *instr[16] = {
3350 [ BT848_RISC_WRITE >> 28 ] = "write",
3351 [ BT848_RISC_SKIP >> 28 ] = "skip",
3352 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3353 [ BT848_RISC_JUMP >> 28 ] = "jump",
3354 [ BT848_RISC_SYNC >> 28 ] = "sync",
3355 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3356 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3357 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3358 };
3359 static int incr[16] = {
3360 [ BT848_RISC_WRITE >> 28 ] = 2,
3361 [ BT848_RISC_JUMP >> 28 ] = 2,
3362 [ BT848_RISC_SYNC >> 28 ] = 2,
3363 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3364 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3365 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3366 };
3367 static char *bits[] = {
3368 "be0", "be1", "be2", "be3/resync",
3369 "set0", "set1", "set2", "set3",
3370 "clr0", "clr1", "clr2", "clr3",
3371 "irq", "res", "eol", "sol",
3372 };
3373 int i;
3374
3375 printk("0x%08x [ %s", risc,
3376 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3377 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3378 if (risc & (1 << (i + 12)))
3379 printk(" %s",bits[i]);
3380 printk(" count=%d ]\n", risc & 0xfff);
3381 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3382}
3383
Adrian Bunk408b6642005-05-01 08:59:29 -07003384static void bttv_risc_disasm(struct bttv *btv,
3385 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386{
3387 unsigned int i,j,n;
3388
3389 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3390 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3391 for (i = 0; i < (risc->size >> 2); i += n) {
3392 printk("%s: 0x%lx: ", btv->c.name,
3393 (unsigned long)(risc->dma + (i<<2)));
3394 n = bttv_risc_decode(risc->cpu[i]);
3395 for (j = 1; j < n; j++)
3396 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3397 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3398 risc->cpu[i+j], j);
3399 if (0 == risc->cpu[i])
3400 break;
3401 }
3402}
3403
3404static void bttv_print_riscaddr(struct bttv *btv)
3405{
3406 printk(" main: %08Lx\n",
3407 (unsigned long long)btv->main.dma);
3408 printk(" vbi : o=%08Lx e=%08Lx\n",
3409 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3410 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3411 printk(" cap : o=%08Lx e=%08Lx\n",
3412 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3413 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3414 printk(" scr : o=%08Lx e=%08Lx\n",
3415 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3416 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3417 bttv_risc_disasm(btv, &btv->main);
3418}
3419
3420/* ----------------------------------------------------------------------- */
3421/* irq handler */
3422
3423static char *irq_name[] = {
3424 "FMTCHG", // format change detected (525 vs. 625)
3425 "VSYNC", // vertical sync (new field)
3426 "HSYNC", // horizontal sync
3427 "OFLOW", // chroma/luma AGC overflow
3428 "HLOCK", // horizontal lock changed
3429 "VPRES", // video presence changed
3430 "6", "7",
3431 "I2CDONE", // hw irc operation finished
3432 "GPINT", // gpio port triggered irq
3433 "10",
3434 "RISCI", // risc instruction triggered irq
3435 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3436 "FTRGT", // pixel data fifo overrun
3437 "FDSR", // fifo data stream resyncronisation
3438 "PPERR", // parity error (data transfer)
3439 "RIPERR", // parity error (read risc instructions)
3440 "PABORT", // pci abort
3441 "OCERR", // risc instruction error
3442 "SCERR", // syncronisation error
3443};
3444
3445static void bttv_print_irqbits(u32 print, u32 mark)
3446{
3447 unsigned int i;
3448
3449 printk("bits:");
3450 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3451 if (print & (1 << i))
3452 printk(" %s",irq_name[i]);
3453 if (mark & (1 << i))
3454 printk("*");
3455 }
3456}
3457
3458static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3459{
3460 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3461 btv->c.nr,
3462 (unsigned long)btv->main.dma,
3463 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3464 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3465 (unsigned long)rc);
3466
3467 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3468 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3469 "Ok, then this is harmless, don't worry ;)\n",
3470 btv->c.nr);
3471 return;
3472 }
3473 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3474 btv->c.nr);
3475 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3476 btv->c.nr);
3477 dump_stack();
3478}
3479
3480static int
3481bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3482{
3483 struct bttv_buffer *item;
3484
3485 memset(set,0,sizeof(*set));
3486
3487 /* capture request ? */
3488 if (!list_empty(&btv->capture)) {
3489 set->frame_irq = 1;
3490 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3491 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3492 set->top = item;
3493 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3494 set->bottom = item;
3495
3496 /* capture request for other field ? */
3497 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3498 (item->vb.queue.next != &btv->capture)) {
3499 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3500 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3501 if (NULL == set->top &&
3502 V4L2_FIELD_TOP == item->vb.field) {
3503 set->top = item;
3504 }
3505 if (NULL == set->bottom &&
3506 V4L2_FIELD_BOTTOM == item->vb.field) {
3507 set->bottom = item;
3508 }
3509 if (NULL != set->top && NULL != set->bottom)
3510 set->top_irq = 2;
3511 }
3512 }
3513 }
3514
3515 /* screen overlay ? */
3516 if (NULL != btv->screen) {
3517 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3518 if (NULL == set->top && NULL == set->bottom) {
3519 set->top = btv->screen;
3520 set->bottom = btv->screen;
3521 }
3522 } else {
3523 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3524 NULL == set->top) {
3525 set->top = btv->screen;
3526 }
3527 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3528 NULL == set->bottom) {
3529 set->bottom = btv->screen;
3530 }
3531 }
3532 }
3533
3534 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3535 btv->c.nr,set->top, set->bottom,
3536 btv->screen,set->frame_irq,set->top_irq);
3537 return 0;
3538}
3539
3540static void
3541bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3542 struct bttv_buffer_set *curr, unsigned int state)
3543{
3544 struct timeval ts;
3545
3546 do_gettimeofday(&ts);
3547
3548 if (wakeup->top == wakeup->bottom) {
3549 if (NULL != wakeup->top && curr->top != wakeup->top) {
3550 if (irq_debug > 1)
3551 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3552 wakeup->top->vb.ts = ts;
3553 wakeup->top->vb.field_count = btv->field_count;
3554 wakeup->top->vb.state = state;
3555 wake_up(&wakeup->top->vb.done);
3556 }
3557 } else {
3558 if (NULL != wakeup->top && curr->top != wakeup->top) {
3559 if (irq_debug > 1)
3560 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3561 wakeup->top->vb.ts = ts;
3562 wakeup->top->vb.field_count = btv->field_count;
3563 wakeup->top->vb.state = state;
3564 wake_up(&wakeup->top->vb.done);
3565 }
3566 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3567 if (irq_debug > 1)
3568 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3569 wakeup->bottom->vb.ts = ts;
3570 wakeup->bottom->vb.field_count = btv->field_count;
3571 wakeup->bottom->vb.state = state;
3572 wake_up(&wakeup->bottom->vb.done);
3573 }
3574 }
3575}
3576
3577static void
3578bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3579 unsigned int state)
3580{
3581 struct timeval ts;
3582
3583 if (NULL == wakeup)
3584 return;
3585
3586 do_gettimeofday(&ts);
3587 wakeup->vb.ts = ts;
3588 wakeup->vb.field_count = btv->field_count;
3589 wakeup->vb.state = state;
3590 wake_up(&wakeup->vb.done);
3591}
3592
3593static void bttv_irq_timeout(unsigned long data)
3594{
3595 struct bttv *btv = (struct bttv *)data;
3596 struct bttv_buffer_set old,new;
3597 struct bttv_buffer *ovbi;
3598 struct bttv_buffer *item;
3599 unsigned long flags;
3600
3601 if (bttv_verbose) {
3602 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3603 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3604 btread(BT848_RISC_COUNT));
3605 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3606 printk("\n");
3607 }
3608
3609 spin_lock_irqsave(&btv->s_lock,flags);
3610
3611 /* deactivate stuff */
3612 memset(&new,0,sizeof(new));
3613 old = btv->curr;
3614 ovbi = btv->cvbi;
3615 btv->curr = new;
3616 btv->cvbi = NULL;
3617 btv->loop_irq = 0;
3618 bttv_buffer_activate_video(btv, &new);
3619 bttv_buffer_activate_vbi(btv, NULL);
3620 bttv_set_dma(btv, 0);
3621
3622 /* wake up */
3623 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
3624 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
3625
3626 /* cancel all outstanding capture / vbi requests */
3627 while (!list_empty(&btv->capture)) {
3628 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3629 list_del(&item->vb.queue);
3630 item->vb.state = STATE_ERROR;
3631 wake_up(&item->vb.done);
3632 }
3633 while (!list_empty(&btv->vcapture)) {
3634 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3635 list_del(&item->vb.queue);
3636 item->vb.state = STATE_ERROR;
3637 wake_up(&item->vb.done);
3638 }
3639
3640 btv->errors++;
3641 spin_unlock_irqrestore(&btv->s_lock,flags);
3642}
3643
3644static void
3645bttv_irq_wakeup_top(struct bttv *btv)
3646{
3647 struct bttv_buffer *wakeup = btv->curr.top;
3648
3649 if (NULL == wakeup)
3650 return;
3651
3652 spin_lock(&btv->s_lock);
3653 btv->curr.top_irq = 0;
3654 btv->curr.top = NULL;
3655 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3656
3657 do_gettimeofday(&wakeup->vb.ts);
3658 wakeup->vb.field_count = btv->field_count;
3659 wakeup->vb.state = STATE_DONE;
3660 wake_up(&wakeup->vb.done);
3661 spin_unlock(&btv->s_lock);
3662}
3663
3664static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3665{
3666 if (rc < risc->dma)
3667 return 0;
3668 if (rc > risc->dma + risc->size)
3669 return 0;
3670 return 1;
3671}
3672
3673static void
3674bttv_irq_switch_video(struct bttv *btv)
3675{
3676 struct bttv_buffer_set new;
3677 struct bttv_buffer_set old;
3678 dma_addr_t rc;
3679
3680 spin_lock(&btv->s_lock);
3681
3682 /* new buffer set */
3683 bttv_irq_next_video(btv, &new);
3684 rc = btread(BT848_RISC_COUNT);
3685 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3686 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3687 btv->framedrop++;
3688 if (debug_latency)
3689 bttv_irq_debug_low_latency(btv, rc);
3690 spin_unlock(&btv->s_lock);
3691 return;
3692 }
3693
3694 /* switch over */
3695 old = btv->curr;
3696 btv->curr = new;
3697 btv->loop_irq &= ~1;
3698 bttv_buffer_activate_video(btv, &new);
3699 bttv_set_dma(btv, 0);
3700
3701 /* switch input */
3702 if (UNSET != btv->new_input) {
3703 video_mux(btv,btv->new_input);
3704 btv->new_input = UNSET;
3705 }
3706
3707 /* wake up finished buffers */
3708 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
3709 spin_unlock(&btv->s_lock);
3710}
3711
3712static void
3713bttv_irq_switch_vbi(struct bttv *btv)
3714{
3715 struct bttv_buffer *new = NULL;
3716 struct bttv_buffer *old;
3717 u32 rc;
3718
3719 spin_lock(&btv->s_lock);
3720
3721 if (!list_empty(&btv->vcapture))
3722 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3723 old = btv->cvbi;
3724
3725 rc = btread(BT848_RISC_COUNT);
3726 if (NULL != old && (is_active(&old->top, rc) ||
3727 is_active(&old->bottom, rc))) {
3728 btv->framedrop++;
3729 if (debug_latency)
3730 bttv_irq_debug_low_latency(btv, rc);
3731 spin_unlock(&btv->s_lock);
3732 return;
3733 }
3734
3735 /* switch */
3736 btv->cvbi = new;
3737 btv->loop_irq &= ~4;
3738 bttv_buffer_activate_vbi(btv, new);
3739 bttv_set_dma(btv, 0);
3740
3741 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
3742 spin_unlock(&btv->s_lock);
3743}
3744
3745static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
3746{
3747 u32 stat,astat;
3748 u32 dstat;
3749 int count;
3750 struct bttv *btv;
3751 int handled = 0;
3752
3753 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003754
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003755 if (btv->custom_irq)
3756 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003757
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 count=0;
3759 while (1) {
3760 /* get/clear interrupt status bits */
3761 stat=btread(BT848_INT_STAT);
3762 astat=stat&btread(BT848_INT_MASK);
3763 if (!astat)
3764 break;
3765 handled = 1;
3766 btwrite(stat,BT848_INT_STAT);
3767
3768 /* get device status bits */
3769 dstat=btread(BT848_DSTATUS);
3770
3771 if (irq_debug) {
3772 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
3773 "riscs=%x, riscc=%08x, ",
3774 btv->c.nr, count, btv->field_count,
3775 stat>>28, btread(BT848_RISC_COUNT));
3776 bttv_print_irqbits(stat,astat);
3777 if (stat & BT848_INT_HLOCK)
3778 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
3779 ? "yes" : "no");
3780 if (stat & BT848_INT_VPRES)
3781 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
3782 ? "yes" : "no");
3783 if (stat & BT848_INT_FMTCHG)
3784 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
3785 ? "625" : "525");
3786 printk("\n");
3787 }
3788
3789 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003790 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003792 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003794 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 }
3796
3797 if (astat & BT848_INT_I2CDONE) {
3798 btv->i2c_done = stat;
3799 wake_up(&btv->i2c_queue);
3800 }
3801
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003802 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 bttv_irq_switch_vbi(btv);
3804
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003805 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 bttv_irq_wakeup_top(btv);
3807
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003808 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 bttv_irq_switch_video(btv);
3810
3811 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003812 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813
3814 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
3815 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
3816 (astat & BT848_INT_SCERR) ? "SCERR" : "",
3817 (astat & BT848_INT_OCERR) ? "OCERR" : "",
3818 btread(BT848_RISC_COUNT));
3819 bttv_print_irqbits(stat,astat);
3820 printk("\n");
3821 if (bttv_debug)
3822 bttv_print_riscaddr(btv);
3823 }
3824 if (fdsr && astat & BT848_INT_FDSR) {
3825 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
3826 btv->c.nr,btread(BT848_RISC_COUNT));
3827 if (bttv_debug)
3828 bttv_print_riscaddr(btv);
3829 }
3830
3831 count++;
3832 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003833
3834 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003835 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003836
3837 printk(KERN_ERR
3838 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
3839 } else {
3840 printk(KERN_ERR
3841 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
3842
3843 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
3844 BT848_INT_MASK);
3845 };
3846
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003848
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 printk("]\n");
3850 }
3851 }
3852 btv->irq_total++;
3853 if (handled)
3854 btv->irq_me++;
3855 return IRQ_RETVAL(handled);
3856}
3857
3858
3859/* ----------------------------------------------------------------------- */
3860/* initialitation */
3861
3862static struct video_device *vdev_init(struct bttv *btv,
3863 struct video_device *template,
3864 char *type)
3865{
3866 struct video_device *vfd;
3867
3868 vfd = video_device_alloc();
3869 if (NULL == vfd)
3870 return NULL;
3871 *vfd = *template;
3872 vfd->minor = -1;
3873 vfd->dev = &btv->c.pci->dev;
3874 vfd->release = video_device_release;
3875 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
3876 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
3877 type, bttv_tvcards[btv->c.type].name);
3878 return vfd;
3879}
3880
3881static void bttv_unregister_video(struct bttv *btv)
3882{
3883 if (btv->video_dev) {
3884 if (-1 != btv->video_dev->minor)
3885 video_unregister_device(btv->video_dev);
3886 else
3887 video_device_release(btv->video_dev);
3888 btv->video_dev = NULL;
3889 }
3890 if (btv->vbi_dev) {
3891 if (-1 != btv->vbi_dev->minor)
3892 video_unregister_device(btv->vbi_dev);
3893 else
3894 video_device_release(btv->vbi_dev);
3895 btv->vbi_dev = NULL;
3896 }
3897 if (btv->radio_dev) {
3898 if (-1 != btv->radio_dev->minor)
3899 video_unregister_device(btv->radio_dev);
3900 else
3901 video_device_release(btv->radio_dev);
3902 btv->radio_dev = NULL;
3903 }
3904}
3905
3906/* register video4linux devices */
3907static int __devinit bttv_register_video(struct bttv *btv)
3908{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003909 if (no_overlay <= 0) {
3910 bttv_video_template.type |= VID_TYPE_OVERLAY;
3911 } else {
3912 printk("bttv: Overlay support disabled.\n");
3913 }
3914
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 /* video */
3916 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003917 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 goto err;
3919 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
3920 goto err;
3921 printk(KERN_INFO "bttv%d: registered device video%d\n",
3922 btv->c.nr,btv->video_dev->minor & 0x1f);
3923 video_device_create_file(btv->video_dev, &class_device_attr_card);
3924
3925 /* vbi */
3926 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003927 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003929 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 goto err;
3931 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
3932 btv->c.nr,btv->vbi_dev->minor & 0x1f);
3933
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003934 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 return 0;
3936 /* radio */
3937 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003938 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 goto err;
3940 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
3941 goto err;
3942 printk(KERN_INFO "bttv%d: registered device radio%d\n",
3943 btv->c.nr,btv->radio_dev->minor & 0x1f);
3944
3945 /* all done */
3946 return 0;
3947
3948 err:
3949 bttv_unregister_video(btv);
3950 return -1;
3951}
3952
3953
3954/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
3955/* response on cards with no firmware is not enabled by OF */
3956static void pci_set_command(struct pci_dev *dev)
3957{
3958#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003959 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003961 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
3962 cmd = (cmd | PCI_COMMAND_MEMORY );
3963 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964#endif
3965}
3966
3967static int __devinit bttv_probe(struct pci_dev *dev,
3968 const struct pci_device_id *pci_id)
3969{
3970 int result;
3971 unsigned char lat;
3972 struct bttv *btv;
3973
3974 if (bttv_num == BTTV_MAX)
3975 return -ENOMEM;
3976 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003977 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 memset(btv,0,sizeof(*btv));
3979 btv->c.nr = bttv_num;
3980 sprintf(btv->c.name,"bttv%d",btv->c.nr);
3981
3982 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003983 mutex_init(&btv->lock);
3984 mutex_init(&btv->reslock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003985 spin_lock_init(&btv->s_lock);
3986 spin_lock_init(&btv->gpio_lock);
3987 init_waitqueue_head(&btv->gpioq);
3988 init_waitqueue_head(&btv->i2c_queue);
3989 INIT_LIST_HEAD(&btv->c.subs);
3990 INIT_LIST_HEAD(&btv->capture);
3991 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 v4l2_prio_init(&btv->prio);
3993
3994 init_timer(&btv->timeout);
3995 btv->timeout.function = bttv_irq_timeout;
3996 btv->timeout.data = (unsigned long)btv;
3997
Michael Krufky7c08fb02005-11-08 21:36:21 -08003998 btv->i2c_rc = -1;
3999 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 btv->has_radio=radio[btv->c.nr];
4002
4003 /* pci stuff (init, get irq/mmio, ... */
4004 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08004005 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08004007 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 btv->c.nr);
4009 return -EIO;
4010 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004011 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
4012 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 btv->c.nr);
4014 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 if (!request_mem_region(pci_resource_start(dev,0),
4017 pci_resource_len(dev,0),
4018 btv->c.name)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004019 printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 btv->c.nr, pci_resource_start(dev,0));
4021 return -EBUSY;
4022 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004023 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 pci_set_command(dev);
4025 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004027 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
4028 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
4029 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
4030 bttv_num,btv->id, btv->revision, pci_name(dev));
4031 printk("irq: %d, latency: %d, mmio: 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 btv->c.pci->irq, lat, pci_resource_start(dev,0));
4033 schedule();
4034
4035 btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
4036 if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
4037 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4038 result = -EIO;
4039 goto fail1;
4040 }
4041
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004042 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 bttv_idcard(btv);
4044
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004045 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004047 result = request_irq(btv->c.pci->irq, bttv_irq,
4048 SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
4049 if (result < 0) {
4050 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 bttv_num,btv->c.pci->irq);
4052 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
4055 if (0 != bttv_handle_chipset(btv)) {
4056 result = -EIO;
4057 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059
4060 /* init options from insmod args */
4061 btv->opt_combfilter = combfilter;
4062 btv->opt_lumafilter = lumafilter;
4063 btv->opt_automute = automute;
4064 btv->opt_chroma_agc = chroma_agc;
4065 btv->opt_adc_crush = adc_crush;
4066 btv->opt_vcr_hack = vcr_hack;
4067 btv->opt_whitecrush_upper = whitecrush_upper;
4068 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004069 btv->opt_uv_ratio = uv_ratio;
4070 btv->opt_full_luma_range = full_luma_range;
4071 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072
4073 /* fill struct bttv with some useful defaults */
4074 btv->init.btv = btv;
4075 btv->init.ov.w.width = 320;
4076 btv->init.ov.w.height = 240;
4077 btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
4078 btv->init.width = 320;
4079 btv->init.height = 240;
4080 btv->init.lines = 16;
4081 btv->input = 0;
4082
4083 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004084 if (bttv_gpio)
4085 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
4087 bttv_risc_init_main(btv);
4088 init_bt848(btv);
4089
4090 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004091 btwrite(0x00, BT848_GPIO_REG_INP);
4092 btwrite(0x00, BT848_GPIO_OUT_EN);
4093 if (bttv_verbose)
4094 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004096 /* needs to be done before i2c is registered */
4097 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004099 /* register i2c + gpio */
4100 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004102 /* some card-specific stuff (needs working i2c) */
4103 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 init_irqreg(btv);
4105
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004106 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 if (!bttv_tvcards[btv->c.type].no_video) {
4108 bttv_register_video(btv);
4109 bt848_bright(btv,32768);
4110 bt848_contrast(btv,32768);
4111 bt848_hue(btv,32768);
4112 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004113 audio_mute(btv, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 set_input(btv,0);
4115 }
4116
4117 /* add subdevices */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 if (bttv_tvcards[btv->c.type].has_dvb)
4119 bttv_sub_add_device(&btv->c, "dvb");
4120
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004121 bttv_input_init(btv);
4122
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 /* everything is fine */
4124 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004125 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
4127 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004128 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129
4130 fail1:
4131 if (btv->bt848_mmio)
4132 iounmap(btv->bt848_mmio);
4133 release_mem_region(pci_resource_start(btv->c.pci,0),
4134 pci_resource_len(btv->c.pci,0));
4135 pci_set_drvdata(dev,NULL);
4136 return result;
4137}
4138
4139static void __devexit bttv_remove(struct pci_dev *pci_dev)
4140{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004141 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143 if (bttv_verbose)
4144 printk("bttv%d: unloading\n",btv->c.nr);
4145
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004146 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 btand(~15, BT848_GPIO_DMA_CTL);
4148 btwrite(0, BT848_INT_MASK);
4149 btwrite(~0x0, BT848_INT_STAT);
4150 btwrite(0x0, BT848_GPIO_OUT_EN);
4151 if (bttv_gpio)
4152 bttv_gpio_tracking(btv,"cleanup");
4153
4154 /* tell gpio modules we are leaving ... */
4155 btv->shutdown=1;
4156 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004157 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004158 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004160 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 fini_bttv_i2c(btv);
4162
4163 /* unregister video4linux */
4164 bttv_unregister_video(btv);
4165
4166 /* free allocated memory */
4167 btcx_riscmem_free(btv->c.pci,&btv->main);
4168
4169 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004170 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004172 release_mem_region(pci_resource_start(btv->c.pci,0),
4173 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
4175 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004176 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177}
4178
4179static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4180{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004181 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 struct bttv_buffer_set idle;
4183 unsigned long flags;
4184
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004185 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
4187 /* stop dma + irqs */
4188 spin_lock_irqsave(&btv->s_lock,flags);
4189 memset(&idle, 0, sizeof(idle));
4190 btv->state.video = btv->curr;
4191 btv->state.vbi = btv->cvbi;
4192 btv->state.loop_irq = btv->loop_irq;
4193 btv->curr = idle;
4194 btv->loop_irq = 0;
4195 bttv_buffer_activate_video(btv, &idle);
4196 bttv_buffer_activate_vbi(btv, NULL);
4197 bttv_set_dma(btv, 0);
4198 btwrite(0, BT848_INT_MASK);
4199 spin_unlock_irqrestore(&btv->s_lock,flags);
4200
4201 /* save bt878 state */
4202 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4203 btv->state.gpio_data = gpio_read();
4204
4205 /* save pci state */
4206 pci_save_state(pci_dev);
4207 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4208 pci_disable_device(pci_dev);
4209 btv->state.disabled = 1;
4210 }
4211 return 0;
4212}
4213
4214static int bttv_resume(struct pci_dev *pci_dev)
4215{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004216 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004218 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219
4220 dprintk("bttv%d: resume\n", btv->c.nr);
4221
4222 /* restore pci state */
4223 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004224 err=pci_enable_device(pci_dev);
4225 if (err) {
4226 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4227 btv->c.nr);
4228 return err;
4229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 btv->state.disabled = 0;
4231 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004232 err=pci_set_power_state(pci_dev, PCI_D0);
4233 if (err) {
4234 pci_disable_device(pci_dev);
4235 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4236 btv->c.nr);
4237 btv->state.disabled = 1;
4238 return err;
4239 }
4240
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 pci_restore_state(pci_dev);
4242
4243 /* restore bt878 state */
4244 bttv_reinit_bt848(btv);
4245 gpio_inout(0xffffff, btv->state.gpio_enable);
4246 gpio_write(btv->state.gpio_data);
4247
4248 /* restart dma */
4249 spin_lock_irqsave(&btv->s_lock,flags);
4250 btv->curr = btv->state.video;
4251 btv->cvbi = btv->state.vbi;
4252 btv->loop_irq = btv->state.loop_irq;
4253 bttv_buffer_activate_video(btv, &btv->curr);
4254 bttv_buffer_activate_vbi(btv, btv->cvbi);
4255 bttv_set_dma(btv, 0);
4256 spin_unlock_irqrestore(&btv->s_lock,flags);
4257 return 0;
4258}
4259
4260static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004261 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4262 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004264 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004266 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004268 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4269 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270};
4271
4272MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4273
4274static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004275 .name = "bttv",
4276 .id_table = bttv_pci_tbl,
4277 .probe = bttv_probe,
4278 .remove = __devexit_p(bttv_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 .suspend = bttv_suspend,
4280 .resume = bttv_resume,
4281};
4282
4283static int bttv_init_module(void)
4284{
4285 bttv_num = 0;
4286
4287 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4288 (BTTV_VERSION_CODE >> 16) & 0xff,
4289 (BTTV_VERSION_CODE >> 8) & 0xff,
4290 BTTV_VERSION_CODE & 0xff);
4291#ifdef SNAPSHOT
4292 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4293 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4294#endif
4295 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4296 gbuffers = 2;
4297 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4298 gbufsize = BTTV_MAX_FBUF;
4299 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4300 if (bttv_verbose)
4301 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4302 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4303
4304 bttv_check_chipset();
4305
4306 bus_register(&bttv_sub_bus_type);
Otavio Salvador23047592006-01-09 15:25:17 -02004307 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308}
4309
4310static void bttv_cleanup_module(void)
4311{
4312 pci_unregister_driver(&bttv_pci_driver);
4313 bus_unregister(&bttv_sub_bus_type);
4314 return;
4315}
4316
4317module_init(bttv_init_module);
4318module_exit(bttv_cleanup_module);
4319
4320/*
4321 * Local variables:
4322 * c-basic-offset: 8
4323 * End:
4324 */