blob: 423e954948beb01153b17aafadaf694100996749 [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:
Hans Verkuil07151722006-04-01 18:03:23 -0300976 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
977 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -0300978 break;
979 case TVAUDIO_INPUT_EXTERN:
Hans Verkuil07151722006-04-01 18:03:23 -0300980 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
981 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -0300982 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. */
Hans Verkuil07151722006-04-01 18:03:23 -0300989 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
990 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -0300991 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_STD, &std);
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001029 if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001030 bttv_tda9880_setnorm(btv,btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031}
1032
1033static int
1034set_tvnorm(struct bttv *btv, unsigned int norm)
1035{
1036 const struct bttv_tvnorm *tvnorm;
1037
1038 if (norm < 0 || norm >= BTTV_TVNORMS)
1039 return -EINVAL;
1040
1041 btv->tvnorm = norm;
1042 tvnorm = &bttv_tvnorms[norm];
1043
1044 btwrite(tvnorm->adelay, BT848_ADELAY);
1045 btwrite(tvnorm->bdelay, BT848_BDELAY);
1046 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1047 BT848_IFORM);
1048 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1049 btwrite(1, BT848_VBI_PACK_DEL);
1050 bt848A_set_timing(btv);
1051
1052 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001053 case BTTV_BOARD_VOODOOTV_FM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 bttv_tda9880_setnorm(btv,norm);
1055 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057 return 0;
1058}
1059
1060static void
1061set_input(struct bttv *btv, unsigned int input)
1062{
1063 unsigned long flags;
1064
1065 btv->input = input;
1066 if (irq_iswitch) {
1067 spin_lock_irqsave(&btv->s_lock,flags);
1068 if (btv->curr.frame_irq) {
1069 /* active capture -> delayed input switch */
1070 btv->new_input = input;
1071 } else {
1072 video_mux(btv,input);
1073 }
1074 spin_unlock_irqrestore(&btv->s_lock,flags);
1075 } else {
1076 video_mux(btv,input);
1077 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001078 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1079 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 set_tvnorm(btv,btv->tvnorm);
1081 i2c_vidiocschan(btv);
1082}
1083
1084static void init_irqreg(struct bttv *btv)
1085{
1086 /* clear status */
1087 btwrite(0xfffffUL, BT848_INT_STAT);
1088
1089 if (bttv_tvcards[btv->c.type].no_video) {
1090 /* i2c only */
1091 btwrite(BT848_INT_I2CDONE,
1092 BT848_INT_MASK);
1093 } else {
1094 /* full video */
1095 btwrite((btv->triton1) |
1096 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1097 BT848_INT_SCERR |
1098 (fdsr ? BT848_INT_FDSR : 0) |
1099 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1100 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1101 BT848_INT_I2CDONE,
1102 BT848_INT_MASK);
1103 }
1104}
1105
1106static void init_bt848(struct bttv *btv)
1107{
1108 int val;
1109
1110 if (bttv_tvcards[btv->c.type].no_video) {
1111 /* very basic init only */
1112 init_irqreg(btv);
1113 return;
1114 }
1115
1116 btwrite(0x00, BT848_CAP_CTL);
1117 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1118 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1119
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001120 /* set planar and packed mode trigger points and */
1121 /* set rising edge of inverted GPINTR pin as irq trigger */
1122 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1123 BT848_GPIO_DMA_CTL_PLTP1_16|
1124 BT848_GPIO_DMA_CTL_PLTP23_16|
1125 BT848_GPIO_DMA_CTL_GPINTC|
1126 BT848_GPIO_DMA_CTL_GPINTI,
1127 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001130 btwrite(val, BT848_E_SCLOOP);
1131 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001133 btwrite(0x20, BT848_E_VSCALE_HI);
1134 btwrite(0x20, BT848_O_VSCALE_HI);
1135 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 BT848_ADC);
1137
1138 btwrite(whitecrush_upper, BT848_WC_UP);
1139 btwrite(whitecrush_lower, BT848_WC_DOWN);
1140
1141 if (btv->opt_lumafilter) {
1142 btwrite(0, BT848_E_CONTROL);
1143 btwrite(0, BT848_O_CONTROL);
1144 } else {
1145 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1146 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1147 }
1148
1149 bt848_bright(btv, btv->bright);
1150 bt848_hue(btv, btv->hue);
1151 bt848_contrast(btv, btv->contrast);
1152 bt848_sat(btv, btv->saturation);
1153
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001154 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 init_irqreg(btv);
1156}
1157
1158static void bttv_reinit_bt848(struct bttv *btv)
1159{
1160 unsigned long flags;
1161
1162 if (bttv_verbose)
1163 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1164 spin_lock_irqsave(&btv->s_lock,flags);
1165 btv->errors=0;
1166 bttv_set_dma(btv,0);
1167 spin_unlock_irqrestore(&btv->s_lock,flags);
1168
1169 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001170 btv->pll.pll_current = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 set_input(btv,btv->input);
1172}
1173
1174static int get_control(struct bttv *btv, struct v4l2_control *c)
1175{
1176 struct video_audio va;
1177 int i;
1178
1179 for (i = 0; i < BTTV_CTLS; i++)
1180 if (bttv_ctls[i].id == c->id)
1181 break;
1182 if (i == BTTV_CTLS)
1183 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001184 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001186 btv->audio_hook(btv,&va,0);
1187 switch (c->id) {
1188 case V4L2_CID_AUDIO_MUTE:
1189 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1190 break;
1191 case V4L2_CID_AUDIO_VOLUME:
1192 c->value = va.volume;
1193 break;
1194 case V4L2_CID_AUDIO_BALANCE:
1195 c->value = va.balance;
1196 break;
1197 case V4L2_CID_AUDIO_BASS:
1198 c->value = va.bass;
1199 break;
1200 case V4L2_CID_AUDIO_TREBLE:
1201 c->value = va.treble;
1202 break;
1203 }
1204 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 }
1206 switch (c->id) {
1207 case V4L2_CID_BRIGHTNESS:
1208 c->value = btv->bright;
1209 break;
1210 case V4L2_CID_HUE:
1211 c->value = btv->hue;
1212 break;
1213 case V4L2_CID_CONTRAST:
1214 c->value = btv->contrast;
1215 break;
1216 case V4L2_CID_SATURATION:
1217 c->value = btv->saturation;
1218 break;
1219
1220 case V4L2_CID_AUDIO_MUTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001225 bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 break;
1227
1228 case V4L2_CID_PRIVATE_CHROMA_AGC:
1229 c->value = btv->opt_chroma_agc;
1230 break;
1231 case V4L2_CID_PRIVATE_COMBFILTER:
1232 c->value = btv->opt_combfilter;
1233 break;
1234 case V4L2_CID_PRIVATE_LUMAFILTER:
1235 c->value = btv->opt_lumafilter;
1236 break;
1237 case V4L2_CID_PRIVATE_AUTOMUTE:
1238 c->value = btv->opt_automute;
1239 break;
1240 case V4L2_CID_PRIVATE_AGC_CRUSH:
1241 c->value = btv->opt_adc_crush;
1242 break;
1243 case V4L2_CID_PRIVATE_VCR_HACK:
1244 c->value = btv->opt_vcr_hack;
1245 break;
1246 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1247 c->value = btv->opt_whitecrush_upper;
1248 break;
1249 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1250 c->value = btv->opt_whitecrush_lower;
1251 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001252 case V4L2_CID_PRIVATE_UV_RATIO:
1253 c->value = btv->opt_uv_ratio;
1254 break;
1255 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1256 c->value = btv->opt_full_luma_range;
1257 break;
1258 case V4L2_CID_PRIVATE_CORING:
1259 c->value = btv->opt_coring;
1260 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 default:
1262 return -EINVAL;
1263 }
1264 return 0;
1265}
1266
1267static int set_control(struct bttv *btv, struct v4l2_control *c)
1268{
1269 struct video_audio va;
1270 int i,val;
1271
1272 for (i = 0; i < BTTV_CTLS; i++)
1273 if (bttv_ctls[i].id == c->id)
1274 break;
1275 if (i == BTTV_CTLS)
1276 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001277 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001279 btv->audio_hook(btv,&va,0);
1280 switch (c->id) {
1281 case V4L2_CID_AUDIO_MUTE:
1282 if (c->value) {
1283 va.flags |= VIDEO_AUDIO_MUTE;
1284 audio_mute(btv, 1);
1285 } else {
1286 va.flags &= ~VIDEO_AUDIO_MUTE;
1287 audio_mute(btv, 0);
1288 }
1289 break;
1290
1291 case V4L2_CID_AUDIO_VOLUME:
1292 va.volume = c->value;
1293 break;
1294 case V4L2_CID_AUDIO_BALANCE:
1295 va.balance = c->value;
1296 break;
1297 case V4L2_CID_AUDIO_BASS:
1298 va.bass = c->value;
1299 break;
1300 case V4L2_CID_AUDIO_TREBLE:
1301 va.treble = c->value;
1302 break;
1303 }
1304 btv->audio_hook(btv,&va,1);
1305 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
1307 switch (c->id) {
1308 case V4L2_CID_BRIGHTNESS:
1309 bt848_bright(btv,c->value);
1310 break;
1311 case V4L2_CID_HUE:
1312 bt848_hue(btv,c->value);
1313 break;
1314 case V4L2_CID_CONTRAST:
1315 bt848_contrast(btv,c->value);
1316 break;
1317 case V4L2_CID_SATURATION:
1318 bt848_sat(btv,c->value);
1319 break;
1320 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001321 audio_mute(btv, c->value);
1322 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001327 bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 break;
1329
1330 case V4L2_CID_PRIVATE_CHROMA_AGC:
1331 btv->opt_chroma_agc = c->value;
1332 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1333 btwrite(val, BT848_E_SCLOOP);
1334 btwrite(val, BT848_O_SCLOOP);
1335 break;
1336 case V4L2_CID_PRIVATE_COMBFILTER:
1337 btv->opt_combfilter = c->value;
1338 break;
1339 case V4L2_CID_PRIVATE_LUMAFILTER:
1340 btv->opt_lumafilter = c->value;
1341 if (btv->opt_lumafilter) {
1342 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1343 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1344 } else {
1345 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1346 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1347 }
1348 break;
1349 case V4L2_CID_PRIVATE_AUTOMUTE:
1350 btv->opt_automute = c->value;
1351 break;
1352 case V4L2_CID_PRIVATE_AGC_CRUSH:
1353 btv->opt_adc_crush = c->value;
1354 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1355 BT848_ADC);
1356 break;
1357 case V4L2_CID_PRIVATE_VCR_HACK:
1358 btv->opt_vcr_hack = c->value;
1359 break;
1360 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1361 btv->opt_whitecrush_upper = c->value;
1362 btwrite(c->value, BT848_WC_UP);
1363 break;
1364 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1365 btv->opt_whitecrush_lower = c->value;
1366 btwrite(c->value, BT848_WC_DOWN);
1367 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001368 case V4L2_CID_PRIVATE_UV_RATIO:
1369 btv->opt_uv_ratio = c->value;
1370 bt848_sat(btv, btv->saturation);
1371 break;
1372 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1373 btv->opt_full_luma_range = c->value;
1374 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1375 break;
1376 case V4L2_CID_PRIVATE_CORING:
1377 btv->opt_coring = c->value;
1378 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1379 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 default:
1381 return -EINVAL;
1382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 return 0;
1384}
1385
1386/* ----------------------------------------------------------------------- */
1387
1388void bttv_gpio_tracking(struct bttv *btv, char *comment)
1389{
1390 unsigned int outbits, data;
1391 outbits = btread(BT848_GPIO_OUT_EN);
1392 data = btread(BT848_GPIO_DATA);
1393 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1394 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1395}
1396
1397static void bttv_field_count(struct bttv *btv)
1398{
1399 int need_count = 0;
1400
1401 if (btv->users)
1402 need_count++;
1403
1404 if (need_count) {
1405 /* start field counter */
1406 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1407 } else {
1408 /* stop field counter */
1409 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1410 btv->field_count = 0;
1411 }
1412}
1413
1414static const struct bttv_format*
1415format_by_palette(int palette)
1416{
1417 unsigned int i;
1418
1419 for (i = 0; i < BTTV_FORMATS; i++) {
1420 if (-1 == bttv_formats[i].palette)
1421 continue;
1422 if (bttv_formats[i].palette == palette)
1423 return bttv_formats+i;
1424 }
1425 return NULL;
1426}
1427
1428static const struct bttv_format*
1429format_by_fourcc(int fourcc)
1430{
1431 unsigned int i;
1432
1433 for (i = 0; i < BTTV_FORMATS; i++) {
1434 if (-1 == bttv_formats[i].fourcc)
1435 continue;
1436 if (bttv_formats[i].fourcc == fourcc)
1437 return bttv_formats+i;
1438 }
1439 return NULL;
1440}
1441
1442/* ----------------------------------------------------------------------- */
1443/* misc helpers */
1444
1445static int
1446bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1447 struct bttv_buffer *new)
1448{
1449 struct bttv_buffer *old;
1450 unsigned long flags;
1451 int retval = 0;
1452
1453 dprintk("switch_overlay: enter [new=%p]\n",new);
1454 if (new)
1455 new->vb.state = STATE_DONE;
1456 spin_lock_irqsave(&btv->s_lock,flags);
1457 old = btv->screen;
1458 btv->screen = new;
1459 btv->loop_irq |= 1;
1460 bttv_set_dma(btv, 0x03);
1461 spin_unlock_irqrestore(&btv->s_lock,flags);
1462 if (NULL == new)
1463 free_btres(btv,fh,RESOURCE_OVERLAY);
1464 if (NULL != old) {
1465 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001466 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 kfree(old);
1468 }
1469 dprintk("switch_overlay: done\n");
1470 return retval;
1471}
1472
1473/* ----------------------------------------------------------------------- */
1474/* video4linux (1) interface */
1475
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001476static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1477 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001478 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 unsigned int width, unsigned int height,
1480 enum v4l2_field field)
1481{
1482 int redo_dma_risc = 0;
1483 int rc;
1484
1485 /* check settings */
1486 if (NULL == fmt)
1487 return -EINVAL;
1488 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1489 width = RAW_BPL;
1490 height = RAW_LINES*2;
1491 if (width*height > buf->vb.bsize)
1492 return -EINVAL;
1493 buf->vb.size = buf->vb.bsize;
1494 } else {
1495 if (width < 48 ||
1496 height < 32 ||
1497 width > bttv_tvnorms[btv->tvnorm].swidth ||
1498 height > bttv_tvnorms[btv->tvnorm].sheight)
1499 return -EINVAL;
1500 buf->vb.size = (width * height * fmt->depth) >> 3;
1501 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1502 return -EINVAL;
1503 }
1504
1505 /* alloc + fill struct bttv_buffer (if changed) */
1506 if (buf->vb.width != width || buf->vb.height != height ||
1507 buf->vb.field != field ||
1508 buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
1509 buf->vb.width = width;
1510 buf->vb.height = height;
1511 buf->vb.field = field;
1512 buf->tvnorm = btv->tvnorm;
1513 buf->fmt = fmt;
1514 redo_dma_risc = 1;
1515 }
1516
1517 /* alloc risc memory */
1518 if (STATE_NEEDS_INIT == buf->vb.state) {
1519 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001520 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 goto fail;
1522 }
1523
1524 if (redo_dma_risc)
1525 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1526 goto fail;
1527
1528 buf->vb.state = STATE_PREPARED;
1529 return 0;
1530
1531 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001532 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 return rc;
1534}
1535
1536static int
1537buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1538{
1539 struct bttv_fh *fh = q->priv_data;
1540
1541 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1542 if (0 == *count)
1543 *count = gbuffers;
1544 while (*size * *count > gbuffers * gbufsize)
1545 (*count)--;
1546 return 0;
1547}
1548
1549static int
1550buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1551 enum v4l2_field field)
1552{
1553 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1554 struct bttv_fh *fh = q->priv_data;
1555
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001556 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 fh->width, fh->height, field);
1558}
1559
1560static void
1561buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1562{
1563 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1564 struct bttv_fh *fh = q->priv_data;
1565 struct bttv *btv = fh->btv;
1566
1567 buf->vb.state = STATE_QUEUED;
1568 list_add_tail(&buf->vb.queue,&btv->capture);
1569 if (!btv->curr.frame_irq) {
1570 btv->loop_irq |= 1;
1571 bttv_set_dma(btv, 0x03);
1572 }
1573}
1574
1575static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1576{
1577 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1578 struct bttv_fh *fh = q->priv_data;
1579
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001580 bttv_dma_free(&fh->cap,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581}
1582
1583static struct videobuf_queue_ops bttv_video_qops = {
1584 .buf_setup = buffer_setup,
1585 .buf_prepare = buffer_prepare,
1586 .buf_queue = buffer_queue,
1587 .buf_release = buffer_release,
1588};
1589
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1591{
1592 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001593 case BTTV_VERSION:
1594 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 /* *** v4l1 *** ************************************************ */
1597 case VIDIOCGFREQ:
1598 {
1599 unsigned long *freq = arg;
1600 *freq = btv->freq;
1601 return 0;
1602 }
1603 case VIDIOCSFREQ:
1604 {
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001605 struct v4l2_frequency freq;
1606
1607 memset(&freq, 0, sizeof(freq));
1608 freq.frequency = *(unsigned long *)arg;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001609 mutex_lock(&btv->lock);
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001610 freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
1611 btv->freq = *(unsigned long *)arg;
1612 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 if (btv->has_matchbox && btv->radio_user)
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001614 tea5757_set_freq(btv,*(unsigned long *)arg);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001615 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 return 0;
1617 }
1618
1619 case VIDIOCGTUNER:
1620 {
1621 struct video_tuner *v = arg;
1622
1623 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1624 return -EINVAL;
1625 if (v->tuner) /* Only tuner 0 */
1626 return -EINVAL;
1627 strcpy(v->name, "Television");
1628 v->rangelow = 0;
1629 v->rangehigh = 0x7FFFFFFF;
1630 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1631 v->mode = btv->tvnorm;
1632 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1633 bttv_call_i2c_clients(btv,cmd,v);
1634 return 0;
1635 }
1636 case VIDIOCSTUNER:
1637 {
1638 struct video_tuner *v = arg;
1639
1640 if (v->tuner) /* Only tuner 0 */
1641 return -EINVAL;
1642 if (v->mode >= BTTV_TVNORMS)
1643 return -EINVAL;
1644
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001645 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 set_tvnorm(btv,v->mode);
1647 bttv_call_i2c_clients(btv,cmd,v);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001648 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 return 0;
1650 }
1651
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001652 case VIDIOCGCHAN:
1653 {
1654 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 unsigned int channel = v->channel;
1656
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001657 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1658 return -EINVAL;
1659 v->tuners=0;
1660 v->flags = VIDEO_VC_AUDIO;
1661 v->type = VIDEO_TYPE_CAMERA;
1662 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001664 strcpy(v->name,"Television");
1665 v->flags|=VIDEO_VC_TUNER;
1666 v->type=VIDEO_TYPE_TV;
1667 v->tuners=1;
1668 } else if (channel == btv->svhs) {
1669 strcpy(v->name,"S-Video");
1670 } else {
1671 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 }
1673 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001674 }
1675 case VIDIOCSCHAN:
1676 {
1677 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 unsigned int channel = v->channel;
1679
1680 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1681 return -EINVAL;
1682 if (v->norm >= BTTV_TVNORMS)
1683 return -EINVAL;
1684
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001685 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (channel == btv->input &&
1687 v->norm == btv->tvnorm) {
1688 /* nothing to do */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001689 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 return 0;
1691 }
1692
1693 btv->tvnorm = v->norm;
1694 set_input(btv,v->channel);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001695 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 return 0;
1697 }
1698
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001699 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 {
1701 struct video_audio *v = arg;
1702
1703 memset(v,0,sizeof(*v));
1704 strcpy(v->name,"Television");
1705 v->flags |= VIDEO_AUDIO_MUTABLE;
1706 v->mode = VIDEO_SOUND_MONO;
1707
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001708 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 bttv_call_i2c_clients(btv,cmd,v);
1710
1711 /* card specific hooks */
1712 if (btv->audio_hook)
1713 btv->audio_hook(btv,v,0);
1714
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001715 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 return 0;
1717 }
1718 case VIDIOCSAUDIO:
1719 {
1720 struct video_audio *v = arg;
1721 unsigned int audio = v->audio;
1722
1723 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
1724 return -EINVAL;
1725
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001726 mutex_lock(&btv->lock);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001727 audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 bttv_call_i2c_clients(btv,cmd,v);
1729
1730 /* card specific hooks */
1731 if (btv->audio_hook)
1732 btv->audio_hook(btv,v,1);
1733
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001734 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 return 0;
1736 }
1737
1738 /* *** v4l2 *** ************************************************ */
1739 case VIDIOC_ENUMSTD:
1740 {
1741 struct v4l2_standard *e = arg;
1742 unsigned int index = e->index;
1743
1744 if (index >= BTTV_TVNORMS)
1745 return -EINVAL;
1746 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1747 bttv_tvnorms[e->index].name);
1748 e->index = index;
1749 return 0;
1750 }
1751 case VIDIOC_G_STD:
1752 {
1753 v4l2_std_id *id = arg;
1754 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1755 return 0;
1756 }
1757 case VIDIOC_S_STD:
1758 {
1759 v4l2_std_id *id = arg;
1760 unsigned int i;
1761
1762 for (i = 0; i < BTTV_TVNORMS; i++)
1763 if (*id & bttv_tvnorms[i].v4l2_id)
1764 break;
1765 if (i == BTTV_TVNORMS)
1766 return -EINVAL;
1767
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001768 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 set_tvnorm(btv,i);
1770 i2c_vidiocschan(btv);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001771 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return 0;
1773 }
1774 case VIDIOC_QUERYSTD:
1775 {
1776 v4l2_std_id *id = arg;
1777
1778 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1779 *id = V4L2_STD_625_50;
1780 else
1781 *id = V4L2_STD_525_60;
1782 return 0;
1783 }
1784
1785 case VIDIOC_ENUMINPUT:
1786 {
1787 struct v4l2_input *i = arg;
1788 unsigned int n;
1789
1790 n = i->index;
1791 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1792 return -EINVAL;
1793 memset(i,0,sizeof(*i));
1794 i->index = n;
1795 i->type = V4L2_INPUT_TYPE_CAMERA;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001796 i->audioset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1798 sprintf(i->name, "Television");
1799 i->type = V4L2_INPUT_TYPE_TUNER;
1800 i->tuner = 0;
1801 } else if (i->index == btv->svhs) {
1802 sprintf(i->name, "S-Video");
1803 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001804 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 }
1806 if (i->index == btv->input) {
1807 __u32 dstatus = btread(BT848_DSTATUS);
1808 if (0 == (dstatus & BT848_DSTATUS_PRES))
1809 i->status |= V4L2_IN_ST_NO_SIGNAL;
1810 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1811 i->status |= V4L2_IN_ST_NO_H_LOCK;
1812 }
1813 for (n = 0; n < BTTV_TVNORMS; n++)
1814 i->std |= bttv_tvnorms[n].v4l2_id;
1815 return 0;
1816 }
1817 case VIDIOC_G_INPUT:
1818 {
1819 int *i = arg;
1820 *i = btv->input;
1821 return 0;
1822 }
1823 case VIDIOC_S_INPUT:
1824 {
1825 unsigned int *i = arg;
1826
1827 if (*i > bttv_tvcards[btv->c.type].video_inputs)
1828 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001829 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 set_input(btv,*i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001831 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 return 0;
1833 }
1834
1835 case VIDIOC_G_TUNER:
1836 {
1837 struct v4l2_tuner *t = arg;
1838
1839 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1840 return -EINVAL;
1841 if (0 != t->index)
1842 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001843 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 memset(t,0,sizeof(*t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001846 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
1847 strcpy(t->name, "Television");
1848 t->capability = V4L2_TUNER_CAP_NORM;
1849 t->type = V4L2_TUNER_ANALOG_TV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
1851 t->signal = 0xffff;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001852
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001853 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 /* Hmmm ... */
1855 struct video_audio va;
1856 memset(&va, 0, sizeof(struct video_audio));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001857 btv->audio_hook(btv,&va,0);
1858 t->audmode = V4L2_TUNER_MODE_MONO;
1859 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 if(va.mode & VIDEO_SOUND_STEREO) {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001861 t->audmode = V4L2_TUNER_MODE_STEREO;
1862 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 }
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001864 if(va.mode & VIDEO_SOUND_LANG2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 t->audmode = V4L2_TUNER_MODE_LANG1;
1866 t->rxsubchans = V4L2_TUNER_SUB_LANG1
1867 | V4L2_TUNER_SUB_LANG2;
1868 }
1869 }
1870 /* FIXME: fill capability+audmode */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001871 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 return 0;
1873 }
1874 case VIDIOC_S_TUNER:
1875 {
1876 struct v4l2_tuner *t = arg;
1877
1878 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1879 return -EINVAL;
1880 if (0 != t->index)
1881 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001882 mutex_lock(&btv->lock);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001883 bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
1884 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 struct video_audio va;
1886 memset(&va, 0, sizeof(struct video_audio));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 if (t->audmode == V4L2_TUNER_MODE_MONO)
1888 va.mode = VIDEO_SOUND_MONO;
Hans Verkuil301e22d2006-03-18 17:15:00 -03001889 else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
1890 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 va.mode = VIDEO_SOUND_STEREO;
1892 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
1893 va.mode = VIDEO_SOUND_LANG1;
1894 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
1895 va.mode = VIDEO_SOUND_LANG2;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001896 btv->audio_hook(btv,&va,1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001898 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 return 0;
1900 }
1901
1902 case VIDIOC_G_FREQUENCY:
1903 {
1904 struct v4l2_frequency *f = arg;
1905
1906 memset(f,0,sizeof(*f));
1907 f->type = V4L2_TUNER_ANALOG_TV;
1908 f->frequency = btv->freq;
1909 return 0;
1910 }
1911 case VIDIOC_S_FREQUENCY:
1912 {
1913 struct v4l2_frequency *f = arg;
1914
1915 if (unlikely(f->tuner != 0))
1916 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07001917 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001919 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 btv->freq = f->frequency;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001921 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (btv->has_matchbox && btv->radio_user)
1923 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001924 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 return 0;
1926 }
Hans Verkuil299392b2005-11-08 21:37:42 -08001927 case VIDIOC_LOG_STATUS:
1928 {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001929 printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr);
Luiz Capitulino97cb4452005-12-01 00:51:24 -08001930 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001931 printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
Hans Verkuil299392b2005-11-08 21:37:42 -08001932 return 0;
1933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
1935 default:
1936 return -ENOIOCTLCMD;
1937
1938 }
1939 return 0;
1940}
1941
1942static int verify_window(const struct bttv_tvnorm *tvn,
1943 struct v4l2_window *win, int fixup)
1944{
1945 enum v4l2_field field;
1946 int maxw, maxh;
1947
1948 if (win->w.width < 48 || win->w.height < 32)
1949 return -EINVAL;
1950 if (win->clipcount > 2048)
1951 return -EINVAL;
1952
1953 field = win->field;
1954 maxw = tvn->swidth;
1955 maxh = tvn->sheight;
1956
1957 if (V4L2_FIELD_ANY == field) {
1958 field = (win->w.height > maxh/2)
1959 ? V4L2_FIELD_INTERLACED
1960 : V4L2_FIELD_TOP;
1961 }
1962 switch (field) {
1963 case V4L2_FIELD_TOP:
1964 case V4L2_FIELD_BOTTOM:
1965 maxh = maxh / 2;
1966 break;
1967 case V4L2_FIELD_INTERLACED:
1968 break;
1969 default:
1970 return -EINVAL;
1971 }
1972
1973 if (!fixup && (win->w.width > maxw || win->w.height > maxh))
1974 return -EINVAL;
1975
1976 if (win->w.width > maxw)
1977 win->w.width = maxw;
1978 if (win->w.height > maxh)
1979 win->w.height = maxh;
1980 win->field = field;
1981 return 0;
1982}
1983
1984static int setup_window(struct bttv_fh *fh, struct bttv *btv,
1985 struct v4l2_window *win, int fixup)
1986{
1987 struct v4l2_clip *clips = NULL;
1988 int n,size,retval = 0;
1989
1990 if (NULL == fh->ovfmt)
1991 return -EINVAL;
1992 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
1993 return -EINVAL;
1994 retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
1995 if (0 != retval)
1996 return retval;
1997
1998 /* copy clips -- luckily v4l1 + v4l2 are binary
1999 compatible here ...*/
2000 n = win->clipcount;
2001 size = sizeof(*clips)*(n+4);
2002 clips = kmalloc(size,GFP_KERNEL);
2003 if (NULL == clips)
2004 return -ENOMEM;
2005 if (n > 0) {
2006 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
2007 kfree(clips);
2008 return -EFAULT;
2009 }
2010 }
2011 /* clip against screen */
2012 if (NULL != btv->fbuf.base)
2013 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
2014 &win->w, clips, n);
2015 btcx_sort_clips(clips,n);
2016
2017 /* 4-byte alignments */
2018 switch (fh->ovfmt->depth) {
2019 case 8:
2020 case 24:
2021 btcx_align(&win->w, clips, n, 3);
2022 break;
2023 case 16:
2024 btcx_align(&win->w, clips, n, 1);
2025 break;
2026 case 32:
2027 /* no alignment fixups needed */
2028 break;
2029 default:
2030 BUG();
2031 }
2032
Ingo Molnar3593cab2006-02-07 06:49:14 -02002033 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002034 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 fh->ov.clips = clips;
2036 fh->ov.nclips = n;
2037
2038 fh->ov.w = win->w;
2039 fh->ov.field = win->field;
2040 fh->ov.setup_ok = 1;
2041 btv->init.ov.w.width = win->w.width;
2042 btv->init.ov.w.height = win->w.height;
2043 btv->init.ov.field = win->field;
2044
2045 /* update overlay if needed */
2046 retval = 0;
2047 if (check_btres(fh, RESOURCE_OVERLAY)) {
2048 struct bttv_buffer *new;
2049
2050 new = videobuf_alloc(sizeof(*new));
2051 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2052 retval = bttv_switch_overlay(btv,fh,new);
2053 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002054 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 return retval;
2056}
2057
2058/* ----------------------------------------------------------------------- */
2059
2060static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2061{
2062 struct videobuf_queue* q = NULL;
2063
2064 switch (fh->type) {
2065 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2066 q = &fh->cap;
2067 break;
2068 case V4L2_BUF_TYPE_VBI_CAPTURE:
2069 q = &fh->vbi;
2070 break;
2071 default:
2072 BUG();
2073 }
2074 return q;
2075}
2076
2077static int bttv_resource(struct bttv_fh *fh)
2078{
2079 int res = 0;
2080
2081 switch (fh->type) {
2082 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2083 res = RESOURCE_VIDEO;
2084 break;
2085 case V4L2_BUF_TYPE_VBI_CAPTURE:
2086 res = RESOURCE_VBI;
2087 break;
2088 default:
2089 BUG();
2090 }
2091 return res;
2092}
2093
2094static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2095{
2096 struct videobuf_queue *q = bttv_queue(fh);
2097 int res = bttv_resource(fh);
2098
2099 if (check_btres(fh,res))
2100 return -EBUSY;
2101 if (videobuf_queue_is_busy(q))
2102 return -EBUSY;
2103 fh->type = type;
2104 return 0;
2105}
2106
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002107static void
2108pix_format_set_size (struct v4l2_pix_format * f,
2109 const struct bttv_format * fmt,
2110 unsigned int width,
2111 unsigned int height)
2112{
2113 f->width = width;
2114 f->height = height;
2115
2116 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2117 f->bytesperline = width; /* Y plane */
2118 f->sizeimage = (width * height * fmt->depth) >> 3;
2119 } else {
2120 f->bytesperline = (width * fmt->depth) >> 3;
2121 f->sizeimage = height * f->bytesperline;
2122 }
2123}
2124
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2126{
2127 switch (f->type) {
2128 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2129 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002130 pix_format_set_size (&f->fmt.pix, fh->fmt,
2131 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 f->fmt.pix.field = fh->cap.field;
2133 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 return 0;
2135 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2136 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2137 f->fmt.win.w = fh->ov.w;
2138 f->fmt.win.field = fh->ov.field;
2139 return 0;
2140 case V4L2_BUF_TYPE_VBI_CAPTURE:
2141 bttv_vbi_get_fmt(fh,f);
2142 return 0;
2143 default:
2144 return -EINVAL;
2145 }
2146}
2147
2148static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
2149 struct v4l2_format *f)
2150{
2151 switch (f->type) {
2152 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2153 {
2154 const struct bttv_format *fmt;
2155 enum v4l2_field field;
2156 unsigned int maxw,maxh;
2157
2158 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2159 if (NULL == fmt)
2160 return -EINVAL;
2161
2162 /* fixup format */
2163 maxw = bttv_tvnorms[btv->tvnorm].swidth;
2164 maxh = bttv_tvnorms[btv->tvnorm].sheight;
2165 field = f->fmt.pix.field;
2166 if (V4L2_FIELD_ANY == field)
2167 field = (f->fmt.pix.height > maxh/2)
2168 ? V4L2_FIELD_INTERLACED
2169 : V4L2_FIELD_BOTTOM;
2170 if (V4L2_FIELD_SEQ_BT == field)
2171 field = V4L2_FIELD_SEQ_TB;
2172 switch (field) {
2173 case V4L2_FIELD_TOP:
2174 case V4L2_FIELD_BOTTOM:
2175 case V4L2_FIELD_ALTERNATE:
2176 maxh = maxh/2;
2177 break;
2178 case V4L2_FIELD_INTERLACED:
2179 break;
2180 case V4L2_FIELD_SEQ_TB:
2181 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2182 return -EINVAL;
2183 break;
2184 default:
2185 return -EINVAL;
2186 }
2187
2188 /* update data for the application */
2189 f->fmt.pix.field = field;
2190 if (f->fmt.pix.width < 48)
2191 f->fmt.pix.width = 48;
2192 if (f->fmt.pix.height < 32)
2193 f->fmt.pix.height = 32;
2194 if (f->fmt.pix.width > maxw)
2195 f->fmt.pix.width = maxw;
2196 if (f->fmt.pix.height > maxh)
2197 f->fmt.pix.height = maxh;
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002198 pix_format_set_size (&f->fmt.pix, fmt,
2199 f->fmt.pix.width & ~3,
2200 f->fmt.pix.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
2202 return 0;
2203 }
2204 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2205 return verify_window(&bttv_tvnorms[btv->tvnorm],
2206 &f->fmt.win, 1);
2207 case V4L2_BUF_TYPE_VBI_CAPTURE:
2208 bttv_vbi_try_fmt(fh,f);
2209 return 0;
2210 default:
2211 return -EINVAL;
2212 }
2213}
2214
2215static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2216 struct v4l2_format *f)
2217{
2218 int retval;
2219
2220 switch (f->type) {
2221 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2222 {
2223 const struct bttv_format *fmt;
2224
2225 retval = bttv_switch_type(fh,f->type);
2226 if (0 != retval)
2227 return retval;
2228 retval = bttv_try_fmt(fh,btv,f);
2229 if (0 != retval)
2230 return retval;
2231 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2232
2233 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002234 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 fh->fmt = fmt;
2236 fh->cap.field = f->fmt.pix.field;
2237 fh->cap.last = V4L2_FIELD_NONE;
2238 fh->width = f->fmt.pix.width;
2239 fh->height = f->fmt.pix.height;
2240 btv->init.fmt = fmt;
2241 btv->init.width = f->fmt.pix.width;
2242 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002243 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
2245 return 0;
2246 }
2247 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002248 if (no_overlay > 0) {
2249 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2250 return -EINVAL;
2251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 return setup_window(fh, btv, &f->fmt.win, 1);
2253 case V4L2_BUF_TYPE_VBI_CAPTURE:
2254 retval = bttv_switch_type(fh,f->type);
2255 if (0 != retval)
2256 return retval;
2257 if (locked_btres(fh->btv, RESOURCE_VBI))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002258 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 bttv_vbi_try_fmt(fh,f);
2260 bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
2261 bttv_vbi_get_fmt(fh,f);
2262 return 0;
2263 default:
2264 return -EINVAL;
2265 }
2266}
2267
2268static int bttv_do_ioctl(struct inode *inode, struct file *file,
2269 unsigned int cmd, void *arg)
2270{
2271 struct bttv_fh *fh = file->private_data;
2272 struct bttv *btv = fh->btv;
2273 unsigned long flags;
2274 int retval = 0;
2275
Michael Krufky5e453dc2006-01-09 15:32:31 -02002276 if (bttv_debug > 1)
2277 v4l_print_ioctl(btv->c.name, cmd);
2278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 if (btv->errors)
2280 bttv_reinit_bt848(btv);
2281
2282 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002283 case VIDIOCSFREQ:
2284 case VIDIOCSTUNER:
2285 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 case VIDIOC_S_CTRL:
2287 case VIDIOC_S_STD:
2288 case VIDIOC_S_INPUT:
2289 case VIDIOC_S_TUNER:
2290 case VIDIOC_S_FREQUENCY:
2291 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2292 if (0 != retval)
2293 return retval;
2294 };
2295
2296 switch (cmd) {
2297
2298 /* *** v4l1 *** ************************************************ */
2299 case VIDIOCGCAP:
2300 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002301 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
2303 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002304 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2306 /* vbi */
2307 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2308 } else {
2309 /* others */
2310 cap->type = VID_TYPE_CAPTURE|
2311 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 VID_TYPE_CLIPPING|
2313 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002314 if (no_overlay <= 0)
2315 cap->type |= VID_TYPE_OVERLAY;
2316
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2318 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2319 cap->minwidth = 48;
2320 cap->minheight = 32;
2321 }
2322 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2323 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002324 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 }
2326
2327 case VIDIOCGPICT:
2328 {
2329 struct video_picture *pic = arg;
2330
2331 memset(pic,0,sizeof(*pic));
2332 pic->brightness = btv->bright;
2333 pic->contrast = btv->contrast;
2334 pic->hue = btv->hue;
2335 pic->colour = btv->saturation;
2336 if (fh->fmt) {
2337 pic->depth = fh->fmt->depth;
2338 pic->palette = fh->fmt->palette;
2339 }
2340 return 0;
2341 }
2342 case VIDIOCSPICT:
2343 {
2344 struct video_picture *pic = arg;
2345 const struct bttv_format *fmt;
2346
2347 fmt = format_by_palette(pic->palette);
2348 if (NULL == fmt)
2349 return -EINVAL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002350 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 if (fmt->depth != pic->depth) {
2352 retval = -EINVAL;
2353 goto fh_unlock_and_return;
2354 }
Michael H. Schimek13c72802005-12-01 00:51:37 -08002355 if (fmt->flags & FORMAT_FLAGS_RAW) {
2356 /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
2357 RAW_LINES * 2. F1 is stored at offset 0, F2
2358 at buffer size / 2. */
2359 fh->width = RAW_BPL;
2360 fh->height = gbufsize / RAW_BPL;
2361 btv->init.width = RAW_BPL;
2362 btv->init.height = gbufsize / RAW_BPL;
2363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 fh->ovfmt = fmt;
2365 fh->fmt = fmt;
2366 btv->init.ovfmt = fmt;
2367 btv->init.fmt = fmt;
2368 if (bigendian) {
2369 /* dirty hack time: swap bytes for overlay if the
2370 display adaptor is big endian (insmod option) */
2371 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2372 fmt->palette == VIDEO_PALETTE_RGB565 ||
2373 fmt->palette == VIDEO_PALETTE_RGB32) {
2374 fh->ovfmt = fmt+1;
2375 }
2376 }
2377 bt848_bright(btv,pic->brightness);
2378 bt848_contrast(btv,pic->contrast);
2379 bt848_hue(btv,pic->hue);
2380 bt848_sat(btv,pic->colour);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002381 mutex_unlock(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002382 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 }
2384
2385 case VIDIOCGWIN:
2386 {
2387 struct video_window *win = arg;
2388
2389 memset(win,0,sizeof(*win));
2390 win->x = fh->ov.w.left;
2391 win->y = fh->ov.w.top;
2392 win->width = fh->ov.w.width;
2393 win->height = fh->ov.w.height;
2394 return 0;
2395 }
2396 case VIDIOCSWIN:
2397 {
2398 struct video_window *win = arg;
2399 struct v4l2_window w2;
2400
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002401 if (no_overlay > 0) {
2402 printk ("VIDIOCSWIN: no_overlay\n");
2403 return -EINVAL;
2404 }
2405
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 w2.field = V4L2_FIELD_ANY;
2407 w2.w.left = win->x;
2408 w2.w.top = win->y;
2409 w2.w.width = win->width;
2410 w2.w.height = win->height;
2411 w2.clipcount = win->clipcount;
2412 w2.clips = (struct v4l2_clip __user *)win->clips;
2413 retval = setup_window(fh, btv, &w2, 0);
2414 if (0 == retval) {
2415 /* on v4l1 this ioctl affects the read() size too */
2416 fh->width = fh->ov.w.width;
2417 fh->height = fh->ov.w.height;
2418 btv->init.width = fh->ov.w.width;
2419 btv->init.height = fh->ov.w.height;
2420 }
2421 return retval;
2422 }
2423
2424 case VIDIOCGFBUF:
2425 {
2426 struct video_buffer *fbuf = arg;
2427
2428 fbuf->base = btv->fbuf.base;
2429 fbuf->width = btv->fbuf.fmt.width;
2430 fbuf->height = btv->fbuf.fmt.height;
2431 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2432 if (fh->ovfmt)
2433 fbuf->depth = fh->ovfmt->depth;
2434 return 0;
2435 }
2436 case VIDIOCSFBUF:
2437 {
2438 struct video_buffer *fbuf = arg;
2439 const struct bttv_format *fmt;
2440 unsigned long end;
2441
2442 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002443 !capable(CAP_SYS_RAWIO))
2444 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 end = (unsigned long)fbuf->base +
2446 fbuf->height * fbuf->bytesperline;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002447 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 retval = -EINVAL;
2449
2450 switch (fbuf->depth) {
2451 case 8:
2452 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2453 break;
2454 case 16:
2455 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2456 break;
2457 case 24:
2458 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2459 break;
2460 case 32:
2461 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2462 break;
2463 case 15:
2464 fbuf->depth = 16;
2465 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2466 break;
2467 default:
2468 fmt = NULL;
2469 break;
2470 }
2471 if (NULL == fmt)
2472 goto fh_unlock_and_return;
2473
2474 fh->ovfmt = fmt;
2475 fh->fmt = fmt;
2476 btv->init.ovfmt = fmt;
2477 btv->init.fmt = fmt;
2478 btv->fbuf.base = fbuf->base;
2479 btv->fbuf.fmt.width = fbuf->width;
2480 btv->fbuf.fmt.height = fbuf->height;
2481 if (fbuf->bytesperline)
2482 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
2483 else
2484 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002485 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 return 0;
2487 }
2488
2489 case VIDIOCCAPTURE:
2490 case VIDIOC_OVERLAY:
2491 {
2492 struct bttv_buffer *new;
2493 int *on = arg;
2494
2495 if (*on) {
2496 /* verify args */
2497 if (NULL == btv->fbuf.base)
2498 return -EINVAL;
2499 if (!fh->ov.setup_ok) {
2500 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2501 return -EINVAL;
2502 }
2503 }
2504
2505 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2506 return -EBUSY;
2507
Ingo Molnar3593cab2006-02-07 06:49:14 -02002508 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 if (*on) {
2510 fh->ov.tvnorm = btv->tvnorm;
2511 new = videobuf_alloc(sizeof(*new));
2512 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2513 } else {
2514 new = NULL;
2515 }
2516
2517 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002518 retval = bttv_switch_overlay(btv,fh,new);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002519 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 return retval;
2521 }
2522
2523 case VIDIOCGMBUF:
2524 {
2525 struct video_mbuf *mbuf = arg;
2526 unsigned int i;
2527
Ingo Molnar3593cab2006-02-07 06:49:14 -02002528 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2530 V4L2_MEMORY_MMAP);
2531 if (retval < 0)
2532 goto fh_unlock_and_return;
2533 memset(mbuf,0,sizeof(*mbuf));
2534 mbuf->frames = gbuffers;
2535 mbuf->size = gbuffers * gbufsize;
2536 for (i = 0; i < gbuffers; i++)
2537 mbuf->offsets[i] = i * gbufsize;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002538 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 return 0;
2540 }
2541 case VIDIOCMCAPTURE:
2542 {
2543 struct video_mmap *vm = arg;
2544 struct bttv_buffer *buf;
2545 enum v4l2_field field;
2546
2547 if (vm->frame >= VIDEO_MAX_FRAME)
2548 return -EINVAL;
2549
Ingo Molnar3593cab2006-02-07 06:49:14 -02002550 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 retval = -EINVAL;
2552 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
2553 if (NULL == buf)
2554 goto fh_unlock_and_return;
2555 if (0 == buf->vb.baddr)
2556 goto fh_unlock_and_return;
2557 if (buf->vb.state == STATE_QUEUED ||
2558 buf->vb.state == STATE_ACTIVE)
2559 goto fh_unlock_and_return;
2560
2561 field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
2562 ? V4L2_FIELD_INTERLACED
2563 : V4L2_FIELD_BOTTOM;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03002564 retval = bttv_prepare_buffer(&fh->cap,btv,buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 format_by_palette(vm->format),
2566 vm->width,vm->height,field);
2567 if (0 != retval)
2568 goto fh_unlock_and_return;
2569 spin_lock_irqsave(&btv->s_lock,flags);
2570 buffer_queue(&fh->cap,&buf->vb);
2571 spin_unlock_irqrestore(&btv->s_lock,flags);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002572 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 return 0;
2574 }
2575 case VIDIOCSYNC:
2576 {
2577 int *frame = arg;
2578 struct bttv_buffer *buf;
2579
2580 if (*frame >= VIDEO_MAX_FRAME)
2581 return -EINVAL;
2582
Ingo Molnar3593cab2006-02-07 06:49:14 -02002583 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 retval = -EINVAL;
2585 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
2586 if (NULL == buf)
2587 goto fh_unlock_and_return;
2588 retval = videobuf_waiton(&buf->vb,0,1);
2589 if (0 != retval)
2590 goto fh_unlock_and_return;
2591 switch (buf->vb.state) {
2592 case STATE_ERROR:
2593 retval = -EIO;
2594 /* fall through */
2595 case STATE_DONE:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03002596 videobuf_dma_sync(&fh->cap,&buf->vb.dma);
2597 bttv_dma_free(&fh->cap,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 break;
2599 default:
2600 retval = -EINVAL;
2601 break;
2602 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002603 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 return retval;
2605 }
2606
2607 case VIDIOCGVBIFMT:
2608 {
2609 struct vbi_format *fmt = (void *) arg;
2610 struct v4l2_format fmt2;
2611
2612 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
2613 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2614 if (0 != retval)
2615 return retval;
2616 }
2617 bttv_vbi_get_fmt(fh, &fmt2);
2618
2619 memset(fmt,0,sizeof(*fmt));
2620 fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
2621 fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
2622 fmt->sample_format = VIDEO_PALETTE_RAW;
2623 fmt->start[0] = fmt2.fmt.vbi.start[0];
2624 fmt->count[0] = fmt2.fmt.vbi.count[0];
2625 fmt->start[1] = fmt2.fmt.vbi.start[1];
2626 fmt->count[1] = fmt2.fmt.vbi.count[1];
Michael H. Schimek67f15702006-01-09 15:25:27 -02002627 if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
2628 fmt->flags |= VBI_UNSYNC;
2629 if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
2630 fmt->flags |= VBI_INTERLACED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 return 0;
2632 }
2633 case VIDIOCSVBIFMT:
2634 {
2635 struct vbi_format *fmt = (void *) arg;
2636 struct v4l2_format fmt2;
2637
2638 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2639 if (0 != retval)
2640 return retval;
2641 bttv_vbi_get_fmt(fh, &fmt2);
2642
2643 if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
2644 fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
2645 fmt->sample_format != VIDEO_PALETTE_RAW ||
2646 fmt->start[0] != fmt2.fmt.vbi.start[0] ||
2647 fmt->start[1] != fmt2.fmt.vbi.start[1] ||
2648 fmt->count[0] != fmt->count[1] ||
2649 fmt->count[0] < 1 ||
2650 fmt->count[0] > 32 /* VBI_MAXLINES */)
2651 return -EINVAL;
2652
2653 bttv_vbi_setlines(fh,btv,fmt->count[0]);
2654 return 0;
2655 }
2656
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002657 case BTTV_VERSION:
2658 case VIDIOCGFREQ:
2659 case VIDIOCSFREQ:
2660 case VIDIOCGTUNER:
2661 case VIDIOCSTUNER:
2662 case VIDIOCGCHAN:
2663 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 case VIDIOCGAUDIO:
2665 case VIDIOCSAUDIO:
2666 return bttv_common_ioctls(btv,cmd,arg);
2667
2668 /* *** v4l2 *** ************************************************ */
2669 case VIDIOC_QUERYCAP:
2670 {
2671 struct v4l2_capability *cap = arg;
2672
2673 if (0 == v4l2)
2674 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002675 memset(cap, 0, sizeof (*cap));
2676 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
2677 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
2678 snprintf(cap->bus_info, sizeof (cap->bus_info),
2679 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 cap->version = BTTV_VERSION_CODE;
2681 cap->capabilities =
2682 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 V4L2_CAP_VBI_CAPTURE |
2684 V4L2_CAP_READWRITE |
2685 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002686 if (no_overlay <= 0)
2687 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2688
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2690 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2691 cap->capabilities |= V4L2_CAP_TUNER;
2692 return 0;
2693 }
2694
2695 case VIDIOC_ENUM_FMT:
2696 {
2697 struct v4l2_fmtdesc *f = arg;
2698 enum v4l2_buf_type type;
2699 unsigned int i;
2700 int index;
2701
2702 type = f->type;
2703 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2704 /* vbi */
2705 index = f->index;
2706 if (0 != index)
2707 return -EINVAL;
2708 memset(f,0,sizeof(*f));
2709 f->index = index;
2710 f->type = type;
2711 f->pixelformat = V4L2_PIX_FMT_GREY;
2712 strcpy(f->description,"vbi data");
2713 return 0;
2714 }
2715
2716 /* video capture + overlay */
2717 index = -1;
2718 for (i = 0; i < BTTV_FORMATS; i++) {
2719 if (bttv_formats[i].fourcc != -1)
2720 index++;
2721 if ((unsigned int)index == f->index)
2722 break;
2723 }
2724 if (BTTV_FORMATS == i)
2725 return -EINVAL;
2726
2727 switch (f->type) {
2728 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2729 break;
2730 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2731 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2732 return -EINVAL;
2733 break;
2734 default:
2735 return -EINVAL;
2736 }
2737 memset(f,0,sizeof(*f));
2738 f->index = index;
2739 f->type = type;
2740 f->pixelformat = bttv_formats[i].fourcc;
2741 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2742 return 0;
2743 }
2744
2745 case VIDIOC_TRY_FMT:
2746 {
2747 struct v4l2_format *f = arg;
2748 return bttv_try_fmt(fh,btv,f);
2749 }
2750 case VIDIOC_G_FMT:
2751 {
2752 struct v4l2_format *f = arg;
2753 return bttv_g_fmt(fh,f);
2754 }
2755 case VIDIOC_S_FMT:
2756 {
2757 struct v4l2_format *f = arg;
2758 return bttv_s_fmt(fh,btv,f);
2759 }
2760
2761 case VIDIOC_G_FBUF:
2762 {
2763 struct v4l2_framebuffer *fb = arg;
2764
2765 *fb = btv->fbuf;
2766 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2767 if (fh->ovfmt)
2768 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2769 return 0;
2770 }
2771 case VIDIOC_S_FBUF:
2772 {
2773 struct v4l2_framebuffer *fb = arg;
2774 const struct bttv_format *fmt;
2775
2776 if(!capable(CAP_SYS_ADMIN) &&
2777 !capable(CAP_SYS_RAWIO))
2778 return -EPERM;
2779
2780 /* check args */
2781 fmt = format_by_fourcc(fb->fmt.pixelformat);
2782 if (NULL == fmt)
2783 return -EINVAL;
2784 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2785 return -EINVAL;
2786
Ingo Molnar3593cab2006-02-07 06:49:14 -02002787 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 retval = -EINVAL;
2789 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2790 if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
2791 goto fh_unlock_and_return;
2792 if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
2793 goto fh_unlock_and_return;
2794 }
2795
2796 /* ok, accept it */
2797 btv->fbuf.base = fb->base;
2798 btv->fbuf.fmt.width = fb->fmt.width;
2799 btv->fbuf.fmt.height = fb->fmt.height;
2800 if (0 != fb->fmt.bytesperline)
2801 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2802 else
2803 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2804
2805 retval = 0;
2806 fh->ovfmt = fmt;
2807 btv->init.ovfmt = fmt;
2808 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2809 fh->ov.w.left = 0;
2810 fh->ov.w.top = 0;
2811 fh->ov.w.width = fb->fmt.width;
2812 fh->ov.w.height = fb->fmt.height;
2813 btv->init.ov.w.width = fb->fmt.width;
2814 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002815 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 fh->ov.clips = NULL;
2817 fh->ov.nclips = 0;
2818
2819 if (check_btres(fh, RESOURCE_OVERLAY)) {
2820 struct bttv_buffer *new;
2821
2822 new = videobuf_alloc(sizeof(*new));
2823 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2824 retval = bttv_switch_overlay(btv,fh,new);
2825 }
2826 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002827 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 return retval;
2829 }
2830
2831 case VIDIOC_REQBUFS:
2832 return videobuf_reqbufs(bttv_queue(fh),arg);
2833
2834 case VIDIOC_QUERYBUF:
2835 return videobuf_querybuf(bttv_queue(fh),arg);
2836
2837 case VIDIOC_QBUF:
2838 return videobuf_qbuf(bttv_queue(fh),arg);
2839
2840 case VIDIOC_DQBUF:
2841 return videobuf_dqbuf(bttv_queue(fh),arg,
2842 file->f_flags & O_NONBLOCK);
2843
2844 case VIDIOC_STREAMON:
2845 {
2846 int res = bttv_resource(fh);
2847
2848 if (!check_alloc_btres(btv,fh,res))
2849 return -EBUSY;
2850 return videobuf_streamon(bttv_queue(fh));
2851 }
2852 case VIDIOC_STREAMOFF:
2853 {
2854 int res = bttv_resource(fh);
2855
2856 retval = videobuf_streamoff(bttv_queue(fh));
2857 if (retval < 0)
2858 return retval;
2859 free_btres(btv,fh,res);
2860 return 0;
2861 }
2862
2863 case VIDIOC_QUERYCTRL:
2864 {
2865 struct v4l2_queryctrl *c = arg;
2866 int i;
2867
2868 if ((c->id < V4L2_CID_BASE ||
2869 c->id >= V4L2_CID_LASTP1) &&
2870 (c->id < V4L2_CID_PRIVATE_BASE ||
2871 c->id >= V4L2_CID_PRIVATE_LASTP1))
2872 return -EINVAL;
2873 for (i = 0; i < BTTV_CTLS; i++)
2874 if (bttv_ctls[i].id == c->id)
2875 break;
2876 if (i == BTTV_CTLS) {
2877 *c = no_ctl;
2878 return 0;
2879 }
2880 *c = bttv_ctls[i];
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002881 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 struct video_audio va;
2883 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002884 btv->audio_hook(btv,&va,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 switch (bttv_ctls[i].id) {
2886 case V4L2_CID_AUDIO_VOLUME:
2887 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2888 *c = no_ctl;
2889 break;
2890 case V4L2_CID_AUDIO_BALANCE:
2891 if (!(va.flags & VIDEO_AUDIO_BALANCE))
2892 *c = no_ctl;
2893 break;
2894 case V4L2_CID_AUDIO_BASS:
2895 if (!(va.flags & VIDEO_AUDIO_BASS))
2896 *c = no_ctl;
2897 break;
2898 case V4L2_CID_AUDIO_TREBLE:
2899 if (!(va.flags & VIDEO_AUDIO_TREBLE))
2900 *c = no_ctl;
2901 break;
2902 }
2903 }
2904 return 0;
2905 }
2906 case VIDIOC_G_CTRL:
2907 return get_control(btv,arg);
2908 case VIDIOC_S_CTRL:
2909 return set_control(btv,arg);
2910 case VIDIOC_G_PARM:
2911 {
2912 struct v4l2_streamparm *parm = arg;
2913 struct v4l2_standard s;
2914 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2915 return -EINVAL;
2916 memset(parm,0,sizeof(*parm));
2917 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2918 bttv_tvnorms[btv->tvnorm].name);
2919 parm->parm.capture.timeperframe = s.frameperiod;
2920 return 0;
2921 }
2922
2923 case VIDIOC_G_PRIORITY:
2924 {
2925 enum v4l2_priority *p = arg;
2926
2927 *p = v4l2_prio_max(&btv->prio);
2928 return 0;
2929 }
2930 case VIDIOC_S_PRIORITY:
2931 {
2932 enum v4l2_priority *prio = arg;
2933
2934 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
2935 }
2936
2937 case VIDIOC_ENUMSTD:
2938 case VIDIOC_G_STD:
2939 case VIDIOC_S_STD:
2940 case VIDIOC_ENUMINPUT:
2941 case VIDIOC_G_INPUT:
2942 case VIDIOC_S_INPUT:
2943 case VIDIOC_G_TUNER:
2944 case VIDIOC_S_TUNER:
2945 case VIDIOC_G_FREQUENCY:
2946 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08002947 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 return bttv_common_ioctls(btv,cmd,arg);
2949
2950 default:
2951 return -ENOIOCTLCMD;
2952 }
2953 return 0;
2954
2955 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02002956 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 return retval;
2958}
2959
2960static int bttv_ioctl(struct inode *inode, struct file *file,
2961 unsigned int cmd, unsigned long arg)
2962{
2963 struct bttv_fh *fh = file->private_data;
2964
2965 switch (cmd) {
2966 case BTTV_VBISIZE:
2967 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2968 return fh->lines * 2 * 2048;
2969 default:
2970 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
2971 }
2972}
2973
2974static ssize_t bttv_read(struct file *file, char __user *data,
2975 size_t count, loff_t *ppos)
2976{
2977 struct bttv_fh *fh = file->private_data;
2978 int retval = 0;
2979
2980 if (fh->btv->errors)
2981 bttv_reinit_bt848(fh->btv);
2982 dprintk("bttv%d: read count=%d type=%s\n",
2983 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
2984
2985 switch (fh->type) {
2986 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2987 if (locked_btres(fh->btv,RESOURCE_VIDEO))
2988 return -EBUSY;
2989 retval = videobuf_read_one(&fh->cap, data, count, ppos,
2990 file->f_flags & O_NONBLOCK);
2991 break;
2992 case V4L2_BUF_TYPE_VBI_CAPTURE:
2993 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2994 return -EBUSY;
2995 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
2996 file->f_flags & O_NONBLOCK);
2997 break;
2998 default:
2999 BUG();
3000 }
3001 return retval;
3002}
3003
3004static unsigned int bttv_poll(struct file *file, poll_table *wait)
3005{
3006 struct bttv_fh *fh = file->private_data;
3007 struct bttv_buffer *buf;
3008 enum v4l2_field field;
3009
3010 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
3011 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3012 return POLLERR;
3013 return videobuf_poll_stream(file, &fh->vbi, wait);
3014 }
3015
3016 if (check_btres(fh,RESOURCE_VIDEO)) {
3017 /* streaming capture */
3018 if (list_empty(&fh->cap.stream))
3019 return POLLERR;
3020 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
3021 } else {
3022 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02003023 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 if (NULL == fh->cap.read_buf) {
3025 /* need to capture a new frame */
3026 if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003027 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 return POLLERR;
3029 }
3030 fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
3031 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003032 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 return POLLERR;
3034 }
3035 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
3036 field = videobuf_next_field(&fh->cap);
3037 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08003038 kfree (fh->cap.read_buf);
3039 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003040 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 return POLLERR;
3042 }
3043 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3044 fh->cap.read_off = 0;
3045 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003046 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 buf = (struct bttv_buffer*)fh->cap.read_buf;
3048 }
3049
3050 poll_wait(file, &buf->vb.done, wait);
3051 if (buf->vb.state == STATE_DONE ||
3052 buf->vb.state == STATE_ERROR)
3053 return POLLIN|POLLRDNORM;
3054 return 0;
3055}
3056
3057static int bttv_open(struct inode *inode, struct file *file)
3058{
3059 int minor = iminor(inode);
3060 struct bttv *btv = NULL;
3061 struct bttv_fh *fh;
3062 enum v4l2_buf_type type = 0;
3063 unsigned int i;
3064
3065 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3066
3067 for (i = 0; i < bttv_num; i++) {
3068 if (bttvs[i].video_dev &&
3069 bttvs[i].video_dev->minor == minor) {
3070 btv = &bttvs[i];
3071 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3072 break;
3073 }
3074 if (bttvs[i].vbi_dev &&
3075 bttvs[i].vbi_dev->minor == minor) {
3076 btv = &bttvs[i];
3077 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3078 break;
3079 }
3080 }
3081 if (NULL == btv)
3082 return -ENODEV;
3083
3084 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3085 btv->c.nr,v4l2_type_names[type]);
3086
3087 /* allocate per filehandle data */
3088 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3089 if (NULL == fh)
3090 return -ENOMEM;
3091 file->private_data = fh;
3092 *fh = btv->init;
3093 fh->type = type;
3094 fh->ov.setup_ok = 0;
3095 v4l2_prio_open(&btv->prio,&fh->prio);
3096
3097 videobuf_queue_init(&fh->cap, &bttv_video_qops,
3098 btv->c.pci, &btv->s_lock,
3099 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3100 V4L2_FIELD_INTERLACED,
3101 sizeof(struct bttv_buffer),
3102 fh);
3103 videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
3104 btv->c.pci, &btv->s_lock,
3105 V4L2_BUF_TYPE_VBI_CAPTURE,
3106 V4L2_FIELD_SEQ_TB,
3107 sizeof(struct bttv_buffer),
3108 fh);
3109 i2c_vidiocschan(btv);
3110
3111 btv->users++;
3112 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
3113 bttv_vbi_setlines(fh,btv,16);
3114 bttv_field_count(btv);
3115 return 0;
3116}
3117
3118static int bttv_release(struct inode *inode, struct file *file)
3119{
3120 struct bttv_fh *fh = file->private_data;
3121 struct bttv *btv = fh->btv;
3122
3123 /* turn off overlay */
3124 if (check_btres(fh, RESOURCE_OVERLAY))
3125 bttv_switch_overlay(btv,fh,NULL);
3126
3127 /* stop video capture */
3128 if (check_btres(fh, RESOURCE_VIDEO)) {
3129 videobuf_streamoff(&fh->cap);
3130 free_btres(btv,fh,RESOURCE_VIDEO);
3131 }
3132 if (fh->cap.read_buf) {
3133 buffer_release(&fh->cap,fh->cap.read_buf);
3134 kfree(fh->cap.read_buf);
3135 }
3136
3137 /* stop vbi capture */
3138 if (check_btres(fh, RESOURCE_VBI)) {
3139 if (fh->vbi.streaming)
3140 videobuf_streamoff(&fh->vbi);
3141 if (fh->vbi.reading)
3142 videobuf_read_stop(&fh->vbi);
3143 free_btres(btv,fh,RESOURCE_VBI);
3144 }
3145
3146 /* free stuff */
3147 videobuf_mmap_free(&fh->cap);
3148 videobuf_mmap_free(&fh->vbi);
3149 v4l2_prio_close(&btv->prio,&fh->prio);
3150 file->private_data = NULL;
3151 kfree(fh);
3152
3153 btv->users--;
3154 bttv_field_count(btv);
3155 return 0;
3156}
3157
3158static int
3159bttv_mmap(struct file *file, struct vm_area_struct *vma)
3160{
3161 struct bttv_fh *fh = file->private_data;
3162
3163 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3164 fh->btv->c.nr, v4l2_type_names[fh->type],
3165 vma->vm_start, vma->vm_end - vma->vm_start);
3166 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3167}
3168
3169static struct file_operations bttv_fops =
3170{
3171 .owner = THIS_MODULE,
3172 .open = bttv_open,
3173 .release = bttv_release,
3174 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003175 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 .llseek = no_llseek,
3177 .read = bttv_read,
3178 .mmap = bttv_mmap,
3179 .poll = bttv_poll,
3180};
3181
3182static struct video_device bttv_video_template =
3183{
3184 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003185 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003186 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 .hardware = VID_HARDWARE_BT848,
3188 .fops = &bttv_fops,
3189 .minor = -1,
3190};
3191
3192static struct video_device bttv_vbi_template =
3193{
3194 .name = "bt848/878 vbi",
3195 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
3196 .hardware = VID_HARDWARE_BT848,
3197 .fops = &bttv_fops,
3198 .minor = -1,
3199};
3200
3201/* ----------------------------------------------------------------------- */
3202/* radio interface */
3203
3204static int radio_open(struct inode *inode, struct file *file)
3205{
3206 int minor = iminor(inode);
3207 struct bttv *btv = NULL;
3208 unsigned int i;
3209
3210 dprintk("bttv: open minor=%d\n",minor);
3211
3212 for (i = 0; i < bttv_num; i++) {
3213 if (bttvs[i].radio_dev->minor == minor) {
3214 btv = &bttvs[i];
3215 break;
3216 }
3217 }
3218 if (NULL == btv)
3219 return -ENODEV;
3220
3221 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003222 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003223
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003225
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 file->private_data = btv;
3227
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003228 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3229 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003231 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003232 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233}
3234
3235static int radio_release(struct inode *inode, struct file *file)
3236{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003237 struct bttv *btv = file->private_data;
3238 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
3240 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003241
3242 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3243
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 return 0;
3245}
3246
3247static int radio_do_ioctl(struct inode *inode, struct file *file,
3248 unsigned int cmd, void *arg)
3249{
3250 struct bttv *btv = file->private_data;
3251
3252 switch (cmd) {
3253 case VIDIOCGCAP:
3254 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003255 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256
3257 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003258 strcpy(cap->name,btv->radio_dev->name);
3259 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 cap->channels = 1;
3261 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003262 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 }
3264
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003265 case VIDIOCGTUNER:
3266 {
3267 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003269 if(v->tuner)
3270 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003272 strcpy(v->name, "Radio");
3273 bttv_call_i2c_clients(btv,cmd,v);
3274 return 0;
3275 }
3276 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 /* nothing to do */
3278 return 0;
3279
3280 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003281 case VIDIOCGFREQ:
3282 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 case VIDIOCGAUDIO:
3284 case VIDIOCSAUDIO:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003285 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 return bttv_common_ioctls(btv,cmd,arg);
3287
3288 default:
3289 return -ENOIOCTLCMD;
3290 }
3291 return 0;
3292}
3293
3294static int radio_ioctl(struct inode *inode, struct file *file,
3295 unsigned int cmd, unsigned long arg)
3296{
3297 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3298}
3299
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003300static ssize_t radio_read(struct file *file, char __user *data,
3301 size_t count, loff_t *ppos)
3302{
3303 struct bttv *btv = file->private_data;
3304 struct rds_command cmd;
3305 cmd.block_count = count/3;
3306 cmd.buffer = data;
3307 cmd.instance = file;
3308 cmd.result = -ENODEV;
3309
3310 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3311
3312 return cmd.result;
3313}
3314
3315static unsigned int radio_poll(struct file *file, poll_table *wait)
3316{
3317 struct bttv *btv = file->private_data;
3318 struct rds_command cmd;
3319 cmd.instance = file;
3320 cmd.event_list = wait;
3321 cmd.result = -ENODEV;
3322 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3323
3324 return cmd.result;
3325}
3326
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327static struct file_operations radio_fops =
3328{
3329 .owner = THIS_MODULE,
3330 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003331 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 .release = radio_release,
3333 .ioctl = radio_ioctl,
3334 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003335 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336};
3337
3338static struct video_device radio_template =
3339{
3340 .name = "bt848/878 radio",
3341 .type = VID_TYPE_TUNER,
3342 .hardware = VID_HARDWARE_BT848,
3343 .fops = &radio_fops,
3344 .minor = -1,
3345};
3346
3347/* ----------------------------------------------------------------------- */
3348/* some debug code */
3349
Adrian Bunk408b6642005-05-01 08:59:29 -07003350static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351{
3352 static char *instr[16] = {
3353 [ BT848_RISC_WRITE >> 28 ] = "write",
3354 [ BT848_RISC_SKIP >> 28 ] = "skip",
3355 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3356 [ BT848_RISC_JUMP >> 28 ] = "jump",
3357 [ BT848_RISC_SYNC >> 28 ] = "sync",
3358 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3359 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3360 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3361 };
3362 static int incr[16] = {
3363 [ BT848_RISC_WRITE >> 28 ] = 2,
3364 [ BT848_RISC_JUMP >> 28 ] = 2,
3365 [ BT848_RISC_SYNC >> 28 ] = 2,
3366 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3367 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3368 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3369 };
3370 static char *bits[] = {
3371 "be0", "be1", "be2", "be3/resync",
3372 "set0", "set1", "set2", "set3",
3373 "clr0", "clr1", "clr2", "clr3",
3374 "irq", "res", "eol", "sol",
3375 };
3376 int i;
3377
3378 printk("0x%08x [ %s", risc,
3379 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3380 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3381 if (risc & (1 << (i + 12)))
3382 printk(" %s",bits[i]);
3383 printk(" count=%d ]\n", risc & 0xfff);
3384 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3385}
3386
Adrian Bunk408b6642005-05-01 08:59:29 -07003387static void bttv_risc_disasm(struct bttv *btv,
3388 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389{
3390 unsigned int i,j,n;
3391
3392 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3393 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3394 for (i = 0; i < (risc->size >> 2); i += n) {
3395 printk("%s: 0x%lx: ", btv->c.name,
3396 (unsigned long)(risc->dma + (i<<2)));
3397 n = bttv_risc_decode(risc->cpu[i]);
3398 for (j = 1; j < n; j++)
3399 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3400 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3401 risc->cpu[i+j], j);
3402 if (0 == risc->cpu[i])
3403 break;
3404 }
3405}
3406
3407static void bttv_print_riscaddr(struct bttv *btv)
3408{
3409 printk(" main: %08Lx\n",
3410 (unsigned long long)btv->main.dma);
3411 printk(" vbi : o=%08Lx e=%08Lx\n",
3412 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3413 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3414 printk(" cap : o=%08Lx e=%08Lx\n",
3415 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3416 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3417 printk(" scr : o=%08Lx e=%08Lx\n",
3418 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3419 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3420 bttv_risc_disasm(btv, &btv->main);
3421}
3422
3423/* ----------------------------------------------------------------------- */
3424/* irq handler */
3425
3426static char *irq_name[] = {
3427 "FMTCHG", // format change detected (525 vs. 625)
3428 "VSYNC", // vertical sync (new field)
3429 "HSYNC", // horizontal sync
3430 "OFLOW", // chroma/luma AGC overflow
3431 "HLOCK", // horizontal lock changed
3432 "VPRES", // video presence changed
3433 "6", "7",
3434 "I2CDONE", // hw irc operation finished
3435 "GPINT", // gpio port triggered irq
3436 "10",
3437 "RISCI", // risc instruction triggered irq
3438 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3439 "FTRGT", // pixel data fifo overrun
3440 "FDSR", // fifo data stream resyncronisation
3441 "PPERR", // parity error (data transfer)
3442 "RIPERR", // parity error (read risc instructions)
3443 "PABORT", // pci abort
3444 "OCERR", // risc instruction error
3445 "SCERR", // syncronisation error
3446};
3447
3448static void bttv_print_irqbits(u32 print, u32 mark)
3449{
3450 unsigned int i;
3451
3452 printk("bits:");
3453 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3454 if (print & (1 << i))
3455 printk(" %s",irq_name[i]);
3456 if (mark & (1 << i))
3457 printk("*");
3458 }
3459}
3460
3461static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3462{
3463 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3464 btv->c.nr,
3465 (unsigned long)btv->main.dma,
3466 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3467 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3468 (unsigned long)rc);
3469
3470 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3471 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3472 "Ok, then this is harmless, don't worry ;)\n",
3473 btv->c.nr);
3474 return;
3475 }
3476 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3477 btv->c.nr);
3478 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3479 btv->c.nr);
3480 dump_stack();
3481}
3482
3483static int
3484bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3485{
3486 struct bttv_buffer *item;
3487
3488 memset(set,0,sizeof(*set));
3489
3490 /* capture request ? */
3491 if (!list_empty(&btv->capture)) {
3492 set->frame_irq = 1;
3493 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3494 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3495 set->top = item;
3496 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3497 set->bottom = item;
3498
3499 /* capture request for other field ? */
3500 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3501 (item->vb.queue.next != &btv->capture)) {
3502 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3503 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3504 if (NULL == set->top &&
3505 V4L2_FIELD_TOP == item->vb.field) {
3506 set->top = item;
3507 }
3508 if (NULL == set->bottom &&
3509 V4L2_FIELD_BOTTOM == item->vb.field) {
3510 set->bottom = item;
3511 }
3512 if (NULL != set->top && NULL != set->bottom)
3513 set->top_irq = 2;
3514 }
3515 }
3516 }
3517
3518 /* screen overlay ? */
3519 if (NULL != btv->screen) {
3520 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3521 if (NULL == set->top && NULL == set->bottom) {
3522 set->top = btv->screen;
3523 set->bottom = btv->screen;
3524 }
3525 } else {
3526 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3527 NULL == set->top) {
3528 set->top = btv->screen;
3529 }
3530 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3531 NULL == set->bottom) {
3532 set->bottom = btv->screen;
3533 }
3534 }
3535 }
3536
3537 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3538 btv->c.nr,set->top, set->bottom,
3539 btv->screen,set->frame_irq,set->top_irq);
3540 return 0;
3541}
3542
3543static void
3544bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3545 struct bttv_buffer_set *curr, unsigned int state)
3546{
3547 struct timeval ts;
3548
3549 do_gettimeofday(&ts);
3550
3551 if (wakeup->top == wakeup->bottom) {
3552 if (NULL != wakeup->top && curr->top != wakeup->top) {
3553 if (irq_debug > 1)
3554 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3555 wakeup->top->vb.ts = ts;
3556 wakeup->top->vb.field_count = btv->field_count;
3557 wakeup->top->vb.state = state;
3558 wake_up(&wakeup->top->vb.done);
3559 }
3560 } else {
3561 if (NULL != wakeup->top && curr->top != wakeup->top) {
3562 if (irq_debug > 1)
3563 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3564 wakeup->top->vb.ts = ts;
3565 wakeup->top->vb.field_count = btv->field_count;
3566 wakeup->top->vb.state = state;
3567 wake_up(&wakeup->top->vb.done);
3568 }
3569 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3570 if (irq_debug > 1)
3571 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3572 wakeup->bottom->vb.ts = ts;
3573 wakeup->bottom->vb.field_count = btv->field_count;
3574 wakeup->bottom->vb.state = state;
3575 wake_up(&wakeup->bottom->vb.done);
3576 }
3577 }
3578}
3579
3580static void
3581bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3582 unsigned int state)
3583{
3584 struct timeval ts;
3585
3586 if (NULL == wakeup)
3587 return;
3588
3589 do_gettimeofday(&ts);
3590 wakeup->vb.ts = ts;
3591 wakeup->vb.field_count = btv->field_count;
3592 wakeup->vb.state = state;
3593 wake_up(&wakeup->vb.done);
3594}
3595
3596static void bttv_irq_timeout(unsigned long data)
3597{
3598 struct bttv *btv = (struct bttv *)data;
3599 struct bttv_buffer_set old,new;
3600 struct bttv_buffer *ovbi;
3601 struct bttv_buffer *item;
3602 unsigned long flags;
3603
3604 if (bttv_verbose) {
3605 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3606 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3607 btread(BT848_RISC_COUNT));
3608 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3609 printk("\n");
3610 }
3611
3612 spin_lock_irqsave(&btv->s_lock,flags);
3613
3614 /* deactivate stuff */
3615 memset(&new,0,sizeof(new));
3616 old = btv->curr;
3617 ovbi = btv->cvbi;
3618 btv->curr = new;
3619 btv->cvbi = NULL;
3620 btv->loop_irq = 0;
3621 bttv_buffer_activate_video(btv, &new);
3622 bttv_buffer_activate_vbi(btv, NULL);
3623 bttv_set_dma(btv, 0);
3624
3625 /* wake up */
3626 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
3627 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
3628
3629 /* cancel all outstanding capture / vbi requests */
3630 while (!list_empty(&btv->capture)) {
3631 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3632 list_del(&item->vb.queue);
3633 item->vb.state = STATE_ERROR;
3634 wake_up(&item->vb.done);
3635 }
3636 while (!list_empty(&btv->vcapture)) {
3637 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3638 list_del(&item->vb.queue);
3639 item->vb.state = STATE_ERROR;
3640 wake_up(&item->vb.done);
3641 }
3642
3643 btv->errors++;
3644 spin_unlock_irqrestore(&btv->s_lock,flags);
3645}
3646
3647static void
3648bttv_irq_wakeup_top(struct bttv *btv)
3649{
3650 struct bttv_buffer *wakeup = btv->curr.top;
3651
3652 if (NULL == wakeup)
3653 return;
3654
3655 spin_lock(&btv->s_lock);
3656 btv->curr.top_irq = 0;
3657 btv->curr.top = NULL;
3658 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3659
3660 do_gettimeofday(&wakeup->vb.ts);
3661 wakeup->vb.field_count = btv->field_count;
3662 wakeup->vb.state = STATE_DONE;
3663 wake_up(&wakeup->vb.done);
3664 spin_unlock(&btv->s_lock);
3665}
3666
3667static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3668{
3669 if (rc < risc->dma)
3670 return 0;
3671 if (rc > risc->dma + risc->size)
3672 return 0;
3673 return 1;
3674}
3675
3676static void
3677bttv_irq_switch_video(struct bttv *btv)
3678{
3679 struct bttv_buffer_set new;
3680 struct bttv_buffer_set old;
3681 dma_addr_t rc;
3682
3683 spin_lock(&btv->s_lock);
3684
3685 /* new buffer set */
3686 bttv_irq_next_video(btv, &new);
3687 rc = btread(BT848_RISC_COUNT);
3688 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3689 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3690 btv->framedrop++;
3691 if (debug_latency)
3692 bttv_irq_debug_low_latency(btv, rc);
3693 spin_unlock(&btv->s_lock);
3694 return;
3695 }
3696
3697 /* switch over */
3698 old = btv->curr;
3699 btv->curr = new;
3700 btv->loop_irq &= ~1;
3701 bttv_buffer_activate_video(btv, &new);
3702 bttv_set_dma(btv, 0);
3703
3704 /* switch input */
3705 if (UNSET != btv->new_input) {
3706 video_mux(btv,btv->new_input);
3707 btv->new_input = UNSET;
3708 }
3709
3710 /* wake up finished buffers */
3711 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
3712 spin_unlock(&btv->s_lock);
3713}
3714
3715static void
3716bttv_irq_switch_vbi(struct bttv *btv)
3717{
3718 struct bttv_buffer *new = NULL;
3719 struct bttv_buffer *old;
3720 u32 rc;
3721
3722 spin_lock(&btv->s_lock);
3723
3724 if (!list_empty(&btv->vcapture))
3725 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3726 old = btv->cvbi;
3727
3728 rc = btread(BT848_RISC_COUNT);
3729 if (NULL != old && (is_active(&old->top, rc) ||
3730 is_active(&old->bottom, rc))) {
3731 btv->framedrop++;
3732 if (debug_latency)
3733 bttv_irq_debug_low_latency(btv, rc);
3734 spin_unlock(&btv->s_lock);
3735 return;
3736 }
3737
3738 /* switch */
3739 btv->cvbi = new;
3740 btv->loop_irq &= ~4;
3741 bttv_buffer_activate_vbi(btv, new);
3742 bttv_set_dma(btv, 0);
3743
3744 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
3745 spin_unlock(&btv->s_lock);
3746}
3747
3748static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
3749{
3750 u32 stat,astat;
3751 u32 dstat;
3752 int count;
3753 struct bttv *btv;
3754 int handled = 0;
3755
3756 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003757
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003758 if (btv->custom_irq)
3759 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003760
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 count=0;
3762 while (1) {
3763 /* get/clear interrupt status bits */
3764 stat=btread(BT848_INT_STAT);
3765 astat=stat&btread(BT848_INT_MASK);
3766 if (!astat)
3767 break;
3768 handled = 1;
3769 btwrite(stat,BT848_INT_STAT);
3770
3771 /* get device status bits */
3772 dstat=btread(BT848_DSTATUS);
3773
3774 if (irq_debug) {
3775 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
3776 "riscs=%x, riscc=%08x, ",
3777 btv->c.nr, count, btv->field_count,
3778 stat>>28, btread(BT848_RISC_COUNT));
3779 bttv_print_irqbits(stat,astat);
3780 if (stat & BT848_INT_HLOCK)
3781 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
3782 ? "yes" : "no");
3783 if (stat & BT848_INT_VPRES)
3784 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
3785 ? "yes" : "no");
3786 if (stat & BT848_INT_FMTCHG)
3787 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
3788 ? "625" : "525");
3789 printk("\n");
3790 }
3791
3792 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003793 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003795 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003797 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 }
3799
3800 if (astat & BT848_INT_I2CDONE) {
3801 btv->i2c_done = stat;
3802 wake_up(&btv->i2c_queue);
3803 }
3804
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003805 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806 bttv_irq_switch_vbi(btv);
3807
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003808 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 bttv_irq_wakeup_top(btv);
3810
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003811 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 bttv_irq_switch_video(btv);
3813
3814 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003815 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816
3817 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
3818 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
3819 (astat & BT848_INT_SCERR) ? "SCERR" : "",
3820 (astat & BT848_INT_OCERR) ? "OCERR" : "",
3821 btread(BT848_RISC_COUNT));
3822 bttv_print_irqbits(stat,astat);
3823 printk("\n");
3824 if (bttv_debug)
3825 bttv_print_riscaddr(btv);
3826 }
3827 if (fdsr && astat & BT848_INT_FDSR) {
3828 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
3829 btv->c.nr,btread(BT848_RISC_COUNT));
3830 if (bttv_debug)
3831 bttv_print_riscaddr(btv);
3832 }
3833
3834 count++;
3835 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003836
3837 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003838 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003839
3840 printk(KERN_ERR
3841 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
3842 } else {
3843 printk(KERN_ERR
3844 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
3845
3846 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
3847 BT848_INT_MASK);
3848 };
3849
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003851
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 printk("]\n");
3853 }
3854 }
3855 btv->irq_total++;
3856 if (handled)
3857 btv->irq_me++;
3858 return IRQ_RETVAL(handled);
3859}
3860
3861
3862/* ----------------------------------------------------------------------- */
3863/* initialitation */
3864
3865static struct video_device *vdev_init(struct bttv *btv,
3866 struct video_device *template,
3867 char *type)
3868{
3869 struct video_device *vfd;
3870
3871 vfd = video_device_alloc();
3872 if (NULL == vfd)
3873 return NULL;
3874 *vfd = *template;
3875 vfd->minor = -1;
3876 vfd->dev = &btv->c.pci->dev;
3877 vfd->release = video_device_release;
3878 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
3879 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
3880 type, bttv_tvcards[btv->c.type].name);
3881 return vfd;
3882}
3883
3884static void bttv_unregister_video(struct bttv *btv)
3885{
3886 if (btv->video_dev) {
3887 if (-1 != btv->video_dev->minor)
3888 video_unregister_device(btv->video_dev);
3889 else
3890 video_device_release(btv->video_dev);
3891 btv->video_dev = NULL;
3892 }
3893 if (btv->vbi_dev) {
3894 if (-1 != btv->vbi_dev->minor)
3895 video_unregister_device(btv->vbi_dev);
3896 else
3897 video_device_release(btv->vbi_dev);
3898 btv->vbi_dev = NULL;
3899 }
3900 if (btv->radio_dev) {
3901 if (-1 != btv->radio_dev->minor)
3902 video_unregister_device(btv->radio_dev);
3903 else
3904 video_device_release(btv->radio_dev);
3905 btv->radio_dev = NULL;
3906 }
3907}
3908
3909/* register video4linux devices */
3910static int __devinit bttv_register_video(struct bttv *btv)
3911{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003912 if (no_overlay <= 0) {
3913 bttv_video_template.type |= VID_TYPE_OVERLAY;
3914 } else {
3915 printk("bttv: Overlay support disabled.\n");
3916 }
3917
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 /* video */
3919 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003920 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 goto err;
3922 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
3923 goto err;
3924 printk(KERN_INFO "bttv%d: registered device video%d\n",
3925 btv->c.nr,btv->video_dev->minor & 0x1f);
3926 video_device_create_file(btv->video_dev, &class_device_attr_card);
3927
3928 /* vbi */
3929 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003930 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003932 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 goto err;
3934 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
3935 btv->c.nr,btv->vbi_dev->minor & 0x1f);
3936
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003937 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 return 0;
3939 /* radio */
3940 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003941 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 goto err;
3943 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
3944 goto err;
3945 printk(KERN_INFO "bttv%d: registered device radio%d\n",
3946 btv->c.nr,btv->radio_dev->minor & 0x1f);
3947
3948 /* all done */
3949 return 0;
3950
3951 err:
3952 bttv_unregister_video(btv);
3953 return -1;
3954}
3955
3956
3957/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
3958/* response on cards with no firmware is not enabled by OF */
3959static void pci_set_command(struct pci_dev *dev)
3960{
3961#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003962 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003964 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
3965 cmd = (cmd | PCI_COMMAND_MEMORY );
3966 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967#endif
3968}
3969
3970static int __devinit bttv_probe(struct pci_dev *dev,
3971 const struct pci_device_id *pci_id)
3972{
3973 int result;
3974 unsigned char lat;
3975 struct bttv *btv;
3976
3977 if (bttv_num == BTTV_MAX)
3978 return -ENOMEM;
3979 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003980 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 memset(btv,0,sizeof(*btv));
3982 btv->c.nr = bttv_num;
3983 sprintf(btv->c.name,"bttv%d",btv->c.nr);
3984
3985 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003986 mutex_init(&btv->lock);
3987 mutex_init(&btv->reslock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003988 spin_lock_init(&btv->s_lock);
3989 spin_lock_init(&btv->gpio_lock);
3990 init_waitqueue_head(&btv->gpioq);
3991 init_waitqueue_head(&btv->i2c_queue);
3992 INIT_LIST_HEAD(&btv->c.subs);
3993 INIT_LIST_HEAD(&btv->capture);
3994 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 v4l2_prio_init(&btv->prio);
3996
3997 init_timer(&btv->timeout);
3998 btv->timeout.function = bttv_irq_timeout;
3999 btv->timeout.data = (unsigned long)btv;
4000
Michael Krufky7c08fb02005-11-08 21:36:21 -08004001 btv->i2c_rc = -1;
4002 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 btv->has_radio=radio[btv->c.nr];
4005
4006 /* pci stuff (init, get irq/mmio, ... */
4007 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08004008 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08004010 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 btv->c.nr);
4012 return -EIO;
4013 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004014 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
4015 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 btv->c.nr);
4017 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 if (!request_mem_region(pci_resource_start(dev,0),
4020 pci_resource_len(dev,0),
4021 btv->c.name)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004022 printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 btv->c.nr, pci_resource_start(dev,0));
4024 return -EBUSY;
4025 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004026 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 pci_set_command(dev);
4028 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004030 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
4031 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
4032 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
4033 bttv_num,btv->id, btv->revision, pci_name(dev));
4034 printk("irq: %d, latency: %d, mmio: 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 btv->c.pci->irq, lat, pci_resource_start(dev,0));
4036 schedule();
4037
4038 btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
4039 if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
4040 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4041 result = -EIO;
4042 goto fail1;
4043 }
4044
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004045 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 bttv_idcard(btv);
4047
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004048 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004050 result = request_irq(btv->c.pci->irq, bttv_irq,
4051 SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
4052 if (result < 0) {
4053 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 bttv_num,btv->c.pci->irq);
4055 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057
4058 if (0 != bttv_handle_chipset(btv)) {
4059 result = -EIO;
4060 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062
4063 /* init options from insmod args */
4064 btv->opt_combfilter = combfilter;
4065 btv->opt_lumafilter = lumafilter;
4066 btv->opt_automute = automute;
4067 btv->opt_chroma_agc = chroma_agc;
4068 btv->opt_adc_crush = adc_crush;
4069 btv->opt_vcr_hack = vcr_hack;
4070 btv->opt_whitecrush_upper = whitecrush_upper;
4071 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004072 btv->opt_uv_ratio = uv_ratio;
4073 btv->opt_full_luma_range = full_luma_range;
4074 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075
4076 /* fill struct bttv with some useful defaults */
4077 btv->init.btv = btv;
4078 btv->init.ov.w.width = 320;
4079 btv->init.ov.w.height = 240;
4080 btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
4081 btv->init.width = 320;
4082 btv->init.height = 240;
4083 btv->init.lines = 16;
4084 btv->input = 0;
4085
4086 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004087 if (bttv_gpio)
4088 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089
4090 bttv_risc_init_main(btv);
4091 init_bt848(btv);
4092
4093 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004094 btwrite(0x00, BT848_GPIO_REG_INP);
4095 btwrite(0x00, BT848_GPIO_OUT_EN);
4096 if (bttv_verbose)
4097 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004099 /* needs to be done before i2c is registered */
4100 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004102 /* register i2c + gpio */
4103 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004105 /* some card-specific stuff (needs working i2c) */
4106 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 init_irqreg(btv);
4108
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004109 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 if (!bttv_tvcards[btv->c.type].no_video) {
4111 bttv_register_video(btv);
4112 bt848_bright(btv,32768);
4113 bt848_contrast(btv,32768);
4114 bt848_hue(btv,32768);
4115 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004116 audio_mute(btv, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 set_input(btv,0);
4118 }
4119
4120 /* add subdevices */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 if (bttv_tvcards[btv->c.type].has_dvb)
4122 bttv_sub_add_device(&btv->c, "dvb");
4123
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004124 bttv_input_init(btv);
4125
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 /* everything is fine */
4127 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004128 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129
4130 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004131 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
4133 fail1:
4134 if (btv->bt848_mmio)
4135 iounmap(btv->bt848_mmio);
4136 release_mem_region(pci_resource_start(btv->c.pci,0),
4137 pci_resource_len(btv->c.pci,0));
4138 pci_set_drvdata(dev,NULL);
4139 return result;
4140}
4141
4142static void __devexit bttv_remove(struct pci_dev *pci_dev)
4143{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004144 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145
4146 if (bttv_verbose)
4147 printk("bttv%d: unloading\n",btv->c.nr);
4148
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004149 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 btand(~15, BT848_GPIO_DMA_CTL);
4151 btwrite(0, BT848_INT_MASK);
4152 btwrite(~0x0, BT848_INT_STAT);
4153 btwrite(0x0, BT848_GPIO_OUT_EN);
4154 if (bttv_gpio)
4155 bttv_gpio_tracking(btv,"cleanup");
4156
4157 /* tell gpio modules we are leaving ... */
4158 btv->shutdown=1;
4159 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004160 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004161 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004163 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 fini_bttv_i2c(btv);
4165
4166 /* unregister video4linux */
4167 bttv_unregister_video(btv);
4168
4169 /* free allocated memory */
4170 btcx_riscmem_free(btv->c.pci,&btv->main);
4171
4172 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004173 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004175 release_mem_region(pci_resource_start(btv->c.pci,0),
4176 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177
4178 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004179 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180}
4181
4182static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4183{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004184 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 struct bttv_buffer_set idle;
4186 unsigned long flags;
4187
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004188 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189
4190 /* stop dma + irqs */
4191 spin_lock_irqsave(&btv->s_lock,flags);
4192 memset(&idle, 0, sizeof(idle));
4193 btv->state.video = btv->curr;
4194 btv->state.vbi = btv->cvbi;
4195 btv->state.loop_irq = btv->loop_irq;
4196 btv->curr = idle;
4197 btv->loop_irq = 0;
4198 bttv_buffer_activate_video(btv, &idle);
4199 bttv_buffer_activate_vbi(btv, NULL);
4200 bttv_set_dma(btv, 0);
4201 btwrite(0, BT848_INT_MASK);
4202 spin_unlock_irqrestore(&btv->s_lock,flags);
4203
4204 /* save bt878 state */
4205 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4206 btv->state.gpio_data = gpio_read();
4207
4208 /* save pci state */
4209 pci_save_state(pci_dev);
4210 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4211 pci_disable_device(pci_dev);
4212 btv->state.disabled = 1;
4213 }
4214 return 0;
4215}
4216
4217static int bttv_resume(struct pci_dev *pci_dev)
4218{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004219 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004221 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
4223 dprintk("bttv%d: resume\n", btv->c.nr);
4224
4225 /* restore pci state */
4226 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004227 err=pci_enable_device(pci_dev);
4228 if (err) {
4229 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4230 btv->c.nr);
4231 return err;
4232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 btv->state.disabled = 0;
4234 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004235 err=pci_set_power_state(pci_dev, PCI_D0);
4236 if (err) {
4237 pci_disable_device(pci_dev);
4238 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4239 btv->c.nr);
4240 btv->state.disabled = 1;
4241 return err;
4242 }
4243
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 pci_restore_state(pci_dev);
4245
4246 /* restore bt878 state */
4247 bttv_reinit_bt848(btv);
4248 gpio_inout(0xffffff, btv->state.gpio_enable);
4249 gpio_write(btv->state.gpio_data);
4250
4251 /* restart dma */
4252 spin_lock_irqsave(&btv->s_lock,flags);
4253 btv->curr = btv->state.video;
4254 btv->cvbi = btv->state.vbi;
4255 btv->loop_irq = btv->state.loop_irq;
4256 bttv_buffer_activate_video(btv, &btv->curr);
4257 bttv_buffer_activate_vbi(btv, btv->cvbi);
4258 bttv_set_dma(btv, 0);
4259 spin_unlock_irqrestore(&btv->s_lock,flags);
4260 return 0;
4261}
4262
4263static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004264 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4265 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004267 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004269 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004271 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4272 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273};
4274
4275MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4276
4277static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004278 .name = "bttv",
4279 .id_table = bttv_pci_tbl,
4280 .probe = bttv_probe,
4281 .remove = __devexit_p(bttv_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 .suspend = bttv_suspend,
4283 .resume = bttv_resume,
4284};
4285
4286static int bttv_init_module(void)
4287{
4288 bttv_num = 0;
4289
4290 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4291 (BTTV_VERSION_CODE >> 16) & 0xff,
4292 (BTTV_VERSION_CODE >> 8) & 0xff,
4293 BTTV_VERSION_CODE & 0xff);
4294#ifdef SNAPSHOT
4295 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4296 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4297#endif
4298 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4299 gbuffers = 2;
4300 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4301 gbufsize = BTTV_MAX_FBUF;
4302 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4303 if (bttv_verbose)
4304 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4305 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4306
4307 bttv_check_chipset();
4308
4309 bus_register(&bttv_sub_bus_type);
Otavio Salvador23047592006-01-09 15:25:17 -02004310 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311}
4312
4313static void bttv_cleanup_module(void)
4314{
4315 pci_unregister_driver(&bttv_pci_driver);
4316 bus_unregister(&bttv_sub_bus_type);
4317 return;
4318}
4319
4320module_init(bttv_init_module);
4321module_exit(bttv_cleanup_module);
4322
4323/*
4324 * Local variables:
4325 * c-basic-offset: 8
4326 * End:
4327 */