blob: be567ec9e1450fb20a42d1254872a0ed2c7a57a8 [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>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020040
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -070041#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <asm/io.h>
44#include <asm/byteorder.h>
45
Mauro Carvalho Chehabfa3fcce2006-03-23 21:45:24 -030046#include <media/rds.h>
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070047
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049unsigned int bttv_num; /* number of Bt848s in use */
50struct bttv bttvs[BTTV_MAX];
51
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020052unsigned int bttv_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053unsigned int bttv_verbose = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020054unsigned int bttv_gpio;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56/* config variables */
57#ifdef __BIG_ENDIAN
58static unsigned int bigendian=1;
59#else
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020060static unsigned int bigendian;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#endif
62static unsigned int radio[BTTV_MAX];
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020063static unsigned int irq_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static unsigned int gbuffers = 8;
65static unsigned int gbufsize = 0x208000;
66
67static int video_nr = -1;
68static int radio_nr = -1;
69static int vbi_nr = -1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020070static int debug_latency;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020072static unsigned int fdsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/* options */
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020075static unsigned int combfilter;
76static unsigned int lumafilter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077static unsigned int automute = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020078static unsigned int chroma_agc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static unsigned int adc_crush = 1;
80static unsigned int whitecrush_upper = 0xCF;
81static unsigned int whitecrush_lower = 0x7F;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020082static unsigned int vcr_hack;
83static unsigned int irq_iswitch;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070084static unsigned int uv_ratio = 50;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020085static unsigned int full_luma_range;
86static unsigned int coring;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070087extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89/* API features (turn on/off stuff for testing) */
90static unsigned int v4l2 = 1;
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092/* insmod args */
93module_param(bttv_verbose, int, 0644);
94module_param(bttv_gpio, int, 0644);
95module_param(bttv_debug, int, 0644);
96module_param(irq_debug, int, 0644);
97module_param(debug_latency, int, 0644);
98
99module_param(fdsr, int, 0444);
100module_param(video_nr, int, 0444);
101module_param(radio_nr, int, 0444);
102module_param(vbi_nr, int, 0444);
103module_param(gbuffers, int, 0444);
104module_param(gbufsize, int, 0444);
105
106module_param(v4l2, int, 0644);
107module_param(bigendian, int, 0644);
108module_param(irq_iswitch, int, 0644);
109module_param(combfilter, int, 0444);
110module_param(lumafilter, int, 0444);
111module_param(automute, int, 0444);
112module_param(chroma_agc, int, 0444);
113module_param(adc_crush, int, 0444);
114module_param(whitecrush_upper, int, 0444);
115module_param(whitecrush_lower, int, 0444);
116module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700117module_param(uv_ratio, int, 0444);
118module_param(full_luma_range, int, 0444);
119module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121module_param_array(radio, int, NULL, 0444);
122
123MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
124MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
125MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
126MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
127MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
128MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
129MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
130MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
131MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
132MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
133MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
134MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
135MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
136MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
137MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700138MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
139MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
140MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
143MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
144MODULE_LICENSE("GPL");
145
146/* ----------------------------------------------------------------------- */
147/* sysfs */
148
149static ssize_t show_card(struct class_device *cd, char *buf)
150{
151 struct video_device *vfd = to_video_device(cd);
152 struct bttv *btv = dev_get_drvdata(vfd->dev);
153 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
154}
155static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
156
157/* ----------------------------------------------------------------------- */
158/* static data */
159
160/* special timing tables from conexant... */
161static u8 SRAM_Table[][60] =
162{
163 /* PAL digital input over GPIO[7:0] */
164 {
165 45, // 45 bytes following
166 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
167 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
168 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
169 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
170 0x37,0x00,0xAF,0x21,0x00
171 },
172 /* NTSC digital input over GPIO[7:0] */
173 {
174 51, // 51 bytes following
175 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
176 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
177 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
178 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
179 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
180 0x00,
181 },
182 // TGB_NTSC392 // quartzsight
183 // This table has been modified to be used for Fusion Rev D
184 {
185 0x2A, // size of table = 42
186 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
187 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
188 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
189 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
190 0x20, 0x00
191 }
192};
193
194const struct bttv_tvnorm bttv_tvnorms[] = {
195 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800196 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
197 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 {
199 .v4l2_id = V4L2_STD_PAL,
200 .name = "PAL",
201 .Fsc = 35468950,
202 .swidth = 924,
203 .sheight = 576,
204 .totalwidth = 1135,
205 .adelay = 0x7f,
206 .bdelay = 0x72,
207 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
208 .scaledtwidth = 1135,
209 .hdelayx1 = 186,
210 .hactivex1 = 924,
211 .vdelay = 0x20,
212 .vbipack = 255,
213 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200214 /* ITU-R frame line number of the first VBI line
215 we can capture, of the first and second field. */
216 .vbistart = { 7,320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 },{
Hans Verkuild97a11e2006-02-07 06:48:40 -0200218 .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 .name = "NTSC",
220 .Fsc = 28636363,
221 .swidth = 768,
222 .sheight = 480,
223 .totalwidth = 910,
224 .adelay = 0x68,
225 .bdelay = 0x5d,
226 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
227 .scaledtwidth = 910,
228 .hdelayx1 = 128,
229 .hactivex1 = 910,
230 .vdelay = 0x1a,
231 .vbipack = 144,
232 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200233 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 },{
235 .v4l2_id = V4L2_STD_SECAM,
236 .name = "SECAM",
237 .Fsc = 35468950,
238 .swidth = 924,
239 .sheight = 576,
240 .totalwidth = 1135,
241 .adelay = 0x7f,
242 .bdelay = 0xb0,
243 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
244 .scaledtwidth = 1135,
245 .hdelayx1 = 186,
246 .hactivex1 = 922,
247 .vdelay = 0x20,
248 .vbipack = 255,
249 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200250 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 },{
252 .v4l2_id = V4L2_STD_PAL_Nc,
253 .name = "PAL-Nc",
254 .Fsc = 28636363,
255 .swidth = 640,
256 .sheight = 576,
257 .totalwidth = 910,
258 .adelay = 0x68,
259 .bdelay = 0x5d,
260 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
261 .scaledtwidth = 780,
262 .hdelayx1 = 130,
263 .hactivex1 = 734,
264 .vdelay = 0x1a,
265 .vbipack = 144,
266 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200267 .vbistart = { 7, 320 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 },{
269 .v4l2_id = V4L2_STD_PAL_M,
270 .name = "PAL-M",
271 .Fsc = 28636363,
272 .swidth = 640,
273 .sheight = 480,
274 .totalwidth = 910,
275 .adelay = 0x68,
276 .bdelay = 0x5d,
277 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
278 .scaledtwidth = 780,
279 .hdelayx1 = 135,
280 .hactivex1 = 754,
281 .vdelay = 0x1a,
282 .vbipack = 144,
283 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200284 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 },{
286 .v4l2_id = V4L2_STD_PAL_N,
287 .name = "PAL-N",
288 .Fsc = 35468950,
289 .swidth = 768,
290 .sheight = 576,
291 .totalwidth = 1135,
292 .adelay = 0x7f,
293 .bdelay = 0x72,
294 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
295 .scaledtwidth = 944,
296 .hdelayx1 = 186,
297 .hactivex1 = 922,
298 .vdelay = 0x20,
299 .vbipack = 144,
300 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200301 .vbistart = { 7, 320},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 },{
303 .v4l2_id = V4L2_STD_NTSC_M_JP,
304 .name = "NTSC-JP",
305 .Fsc = 28636363,
306 .swidth = 640,
307 .sheight = 480,
308 .totalwidth = 910,
309 .adelay = 0x68,
310 .bdelay = 0x5d,
311 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
312 .scaledtwidth = 780,
313 .hdelayx1 = 135,
314 .hactivex1 = 754,
315 .vdelay = 0x16,
316 .vbipack = 144,
317 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200318 .vbistart = {10, 273},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 },{
320 /* that one hopefully works with the strange timing
321 * which video recorders produce when playing a NTSC
322 * tape on a PAL TV ... */
323 .v4l2_id = V4L2_STD_PAL_60,
324 .name = "PAL-60",
325 .Fsc = 35468950,
326 .swidth = 924,
327 .sheight = 480,
328 .totalwidth = 1135,
329 .adelay = 0x7f,
330 .bdelay = 0x72,
331 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
332 .scaledtwidth = 1135,
333 .hdelayx1 = 186,
334 .hactivex1 = 924,
335 .vdelay = 0x1a,
336 .vbipack = 255,
337 .vtotal = 524,
338 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200339 .vbistart = { 10, 273 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 }
341};
342static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
343
344/* ----------------------------------------------------------------------- */
345/* bttv format list
346 packed pixel formats must come first */
347static const struct bttv_format bttv_formats[] = {
348 {
349 .name = "8 bpp, gray",
350 .palette = VIDEO_PALETTE_GREY,
351 .fourcc = V4L2_PIX_FMT_GREY,
352 .btformat = BT848_COLOR_FMT_Y8,
353 .depth = 8,
354 .flags = FORMAT_FLAGS_PACKED,
355 },{
356 .name = "8 bpp, dithered color",
357 .palette = VIDEO_PALETTE_HI240,
358 .fourcc = V4L2_PIX_FMT_HI240,
359 .btformat = BT848_COLOR_FMT_RGB8,
360 .depth = 8,
361 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
362 },{
363 .name = "15 bpp RGB, le",
364 .palette = VIDEO_PALETTE_RGB555,
365 .fourcc = V4L2_PIX_FMT_RGB555,
366 .btformat = BT848_COLOR_FMT_RGB15,
367 .depth = 16,
368 .flags = FORMAT_FLAGS_PACKED,
369 },{
370 .name = "15 bpp RGB, be",
371 .palette = -1,
372 .fourcc = V4L2_PIX_FMT_RGB555X,
373 .btformat = BT848_COLOR_FMT_RGB15,
374 .btswap = 0x03, /* byteswap */
375 .depth = 16,
376 .flags = FORMAT_FLAGS_PACKED,
377 },{
378 .name = "16 bpp RGB, le",
379 .palette = VIDEO_PALETTE_RGB565,
380 .fourcc = V4L2_PIX_FMT_RGB565,
381 .btformat = BT848_COLOR_FMT_RGB16,
382 .depth = 16,
383 .flags = FORMAT_FLAGS_PACKED,
384 },{
385 .name = "16 bpp RGB, be",
386 .palette = -1,
387 .fourcc = V4L2_PIX_FMT_RGB565X,
388 .btformat = BT848_COLOR_FMT_RGB16,
389 .btswap = 0x03, /* byteswap */
390 .depth = 16,
391 .flags = FORMAT_FLAGS_PACKED,
392 },{
393 .name = "24 bpp RGB, le",
394 .palette = VIDEO_PALETTE_RGB24,
395 .fourcc = V4L2_PIX_FMT_BGR24,
396 .btformat = BT848_COLOR_FMT_RGB24,
397 .depth = 24,
398 .flags = FORMAT_FLAGS_PACKED,
399 },{
400 .name = "32 bpp RGB, le",
401 .palette = VIDEO_PALETTE_RGB32,
402 .fourcc = V4L2_PIX_FMT_BGR32,
403 .btformat = BT848_COLOR_FMT_RGB32,
404 .depth = 32,
405 .flags = FORMAT_FLAGS_PACKED,
406 },{
407 .name = "32 bpp RGB, be",
408 .palette = -1,
409 .fourcc = V4L2_PIX_FMT_RGB32,
410 .btformat = BT848_COLOR_FMT_RGB32,
411 .btswap = 0x0f, /* byte+word swap */
412 .depth = 32,
413 .flags = FORMAT_FLAGS_PACKED,
414 },{
415 .name = "4:2:2, packed, YUYV",
416 .palette = VIDEO_PALETTE_YUV422,
417 .fourcc = V4L2_PIX_FMT_YUYV,
418 .btformat = BT848_COLOR_FMT_YUY2,
419 .depth = 16,
420 .flags = FORMAT_FLAGS_PACKED,
421 },{
422 .name = "4:2:2, packed, YUYV",
423 .palette = VIDEO_PALETTE_YUYV,
424 .fourcc = V4L2_PIX_FMT_YUYV,
425 .btformat = BT848_COLOR_FMT_YUY2,
426 .depth = 16,
427 .flags = FORMAT_FLAGS_PACKED,
428 },{
429 .name = "4:2:2, packed, UYVY",
430 .palette = VIDEO_PALETTE_UYVY,
431 .fourcc = V4L2_PIX_FMT_UYVY,
432 .btformat = BT848_COLOR_FMT_YUY2,
433 .btswap = 0x03, /* byteswap */
434 .depth = 16,
435 .flags = FORMAT_FLAGS_PACKED,
436 },{
437 .name = "4:2:2, planar, Y-Cb-Cr",
438 .palette = VIDEO_PALETTE_YUV422P,
439 .fourcc = V4L2_PIX_FMT_YUV422P,
440 .btformat = BT848_COLOR_FMT_YCrCb422,
441 .depth = 16,
442 .flags = FORMAT_FLAGS_PLANAR,
443 .hshift = 1,
444 .vshift = 0,
445 },{
446 .name = "4:2:0, planar, Y-Cb-Cr",
447 .palette = VIDEO_PALETTE_YUV420P,
448 .fourcc = V4L2_PIX_FMT_YUV420,
449 .btformat = BT848_COLOR_FMT_YCrCb422,
450 .depth = 12,
451 .flags = FORMAT_FLAGS_PLANAR,
452 .hshift = 1,
453 .vshift = 1,
454 },{
455 .name = "4:2:0, planar, Y-Cr-Cb",
456 .palette = -1,
457 .fourcc = V4L2_PIX_FMT_YVU420,
458 .btformat = BT848_COLOR_FMT_YCrCb422,
459 .depth = 12,
460 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
461 .hshift = 1,
462 .vshift = 1,
463 },{
464 .name = "4:1:1, planar, Y-Cb-Cr",
465 .palette = VIDEO_PALETTE_YUV411P,
466 .fourcc = V4L2_PIX_FMT_YUV411P,
467 .btformat = BT848_COLOR_FMT_YCrCb411,
468 .depth = 12,
469 .flags = FORMAT_FLAGS_PLANAR,
470 .hshift = 2,
471 .vshift = 0,
472 },{
473 .name = "4:1:0, planar, Y-Cb-Cr",
474 .palette = VIDEO_PALETTE_YUV410P,
475 .fourcc = V4L2_PIX_FMT_YUV410,
476 .btformat = BT848_COLOR_FMT_YCrCb411,
477 .depth = 9,
478 .flags = FORMAT_FLAGS_PLANAR,
479 .hshift = 2,
480 .vshift = 2,
481 },{
482 .name = "4:1:0, planar, Y-Cr-Cb",
483 .palette = -1,
484 .fourcc = V4L2_PIX_FMT_YVU410,
485 .btformat = BT848_COLOR_FMT_YCrCb411,
486 .depth = 9,
487 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
488 .hshift = 2,
489 .vshift = 2,
490 },{
491 .name = "raw scanlines",
492 .palette = VIDEO_PALETTE_RAW,
493 .fourcc = -1,
494 .btformat = BT848_COLOR_FMT_RAW,
495 .depth = 8,
496 .flags = FORMAT_FLAGS_RAW,
497 }
498};
499static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
500
501/* ----------------------------------------------------------------------- */
502
503#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
504#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
505#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
506#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
507#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
508#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
509#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
510#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700511#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
512#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
513#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
514#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516static const struct v4l2_queryctrl no_ctl = {
517 .name = "42",
518 .flags = V4L2_CTRL_FLAG_DISABLED,
519};
520static const struct v4l2_queryctrl bttv_ctls[] = {
521 /* --- video --- */
522 {
523 .id = V4L2_CID_BRIGHTNESS,
524 .name = "Brightness",
525 .minimum = 0,
526 .maximum = 65535,
527 .step = 256,
528 .default_value = 32768,
529 .type = V4L2_CTRL_TYPE_INTEGER,
530 },{
531 .id = V4L2_CID_CONTRAST,
532 .name = "Contrast",
533 .minimum = 0,
534 .maximum = 65535,
535 .step = 128,
536 .default_value = 32768,
537 .type = V4L2_CTRL_TYPE_INTEGER,
538 },{
539 .id = V4L2_CID_SATURATION,
540 .name = "Saturation",
541 .minimum = 0,
542 .maximum = 65535,
543 .step = 128,
544 .default_value = 32768,
545 .type = V4L2_CTRL_TYPE_INTEGER,
546 },{
547 .id = V4L2_CID_HUE,
548 .name = "Hue",
549 .minimum = 0,
550 .maximum = 65535,
551 .step = 256,
552 .default_value = 32768,
553 .type = V4L2_CTRL_TYPE_INTEGER,
554 },
555 /* --- audio --- */
556 {
557 .id = V4L2_CID_AUDIO_MUTE,
558 .name = "Mute",
559 .minimum = 0,
560 .maximum = 1,
561 .type = V4L2_CTRL_TYPE_BOOLEAN,
562 },{
563 .id = V4L2_CID_AUDIO_VOLUME,
564 .name = "Volume",
565 .minimum = 0,
566 .maximum = 65535,
567 .step = 65535/100,
568 .default_value = 65535,
569 .type = V4L2_CTRL_TYPE_INTEGER,
570 },{
571 .id = V4L2_CID_AUDIO_BALANCE,
572 .name = "Balance",
573 .minimum = 0,
574 .maximum = 65535,
575 .step = 65535/100,
576 .default_value = 32768,
577 .type = V4L2_CTRL_TYPE_INTEGER,
578 },{
579 .id = V4L2_CID_AUDIO_BASS,
580 .name = "Bass",
581 .minimum = 0,
582 .maximum = 65535,
583 .step = 65535/100,
584 .default_value = 32768,
585 .type = V4L2_CTRL_TYPE_INTEGER,
586 },{
587 .id = V4L2_CID_AUDIO_TREBLE,
588 .name = "Treble",
589 .minimum = 0,
590 .maximum = 65535,
591 .step = 65535/100,
592 .default_value = 32768,
593 .type = V4L2_CTRL_TYPE_INTEGER,
594 },
595 /* --- private --- */
596 {
597 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
598 .name = "chroma agc",
599 .minimum = 0,
600 .maximum = 1,
601 .type = V4L2_CTRL_TYPE_BOOLEAN,
602 },{
603 .id = V4L2_CID_PRIVATE_COMBFILTER,
604 .name = "combfilter",
605 .minimum = 0,
606 .maximum = 1,
607 .type = V4L2_CTRL_TYPE_BOOLEAN,
608 },{
609 .id = V4L2_CID_PRIVATE_AUTOMUTE,
610 .name = "automute",
611 .minimum = 0,
612 .maximum = 1,
613 .type = V4L2_CTRL_TYPE_BOOLEAN,
614 },{
615 .id = V4L2_CID_PRIVATE_LUMAFILTER,
616 .name = "luma decimation filter",
617 .minimum = 0,
618 .maximum = 1,
619 .type = V4L2_CTRL_TYPE_BOOLEAN,
620 },{
621 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
622 .name = "agc crush",
623 .minimum = 0,
624 .maximum = 1,
625 .type = V4L2_CTRL_TYPE_BOOLEAN,
626 },{
627 .id = V4L2_CID_PRIVATE_VCR_HACK,
628 .name = "vcr hack",
629 .minimum = 0,
630 .maximum = 1,
631 .type = V4L2_CTRL_TYPE_BOOLEAN,
632 },{
633 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
634 .name = "whitecrush upper",
635 .minimum = 0,
636 .maximum = 255,
637 .step = 1,
638 .default_value = 0xCF,
639 .type = V4L2_CTRL_TYPE_INTEGER,
640 },{
641 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
642 .name = "whitecrush lower",
643 .minimum = 0,
644 .maximum = 255,
645 .step = 1,
646 .default_value = 0x7F,
647 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700648 },{
649 .id = V4L2_CID_PRIVATE_UV_RATIO,
650 .name = "uv ratio",
651 .minimum = 0,
652 .maximum = 100,
653 .step = 1,
654 .default_value = 50,
655 .type = V4L2_CTRL_TYPE_INTEGER,
656 },{
657 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
658 .name = "full luma range",
659 .minimum = 0,
660 .maximum = 1,
661 .type = V4L2_CTRL_TYPE_BOOLEAN,
662 },{
663 .id = V4L2_CID_PRIVATE_CORING,
664 .name = "coring",
665 .minimum = 0,
666 .maximum = 3,
667 .step = 1,
668 .default_value = 0,
669 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 }
671
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700672
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674};
675static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
676
677/* ----------------------------------------------------------------------- */
678/* resource management */
679
680static
681int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
682{
683 if (fh->resources & bit)
684 /* have it already allocated */
685 return 1;
686
687 /* is it free? */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200688 mutex_lock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (btv->resources & bit) {
690 /* no, someone else uses it */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200691 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 return 0;
693 }
694 /* it's free, grab it */
695 fh->resources |= bit;
696 btv->resources |= bit;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200697 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 return 1;
699}
700
701static
702int check_btres(struct bttv_fh *fh, int bit)
703{
704 return (fh->resources & bit);
705}
706
707static
708int locked_btres(struct bttv *btv, int bit)
709{
710 return (btv->resources & bit);
711}
712
713static
714void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
715{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if ((fh->resources & bits) != bits) {
717 /* trying to free ressources not allocated by us ... */
718 printk("bttv: BUG! (btres)\n");
719 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200720 mutex_lock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 fh->resources &= ~bits;
722 btv->resources &= ~bits;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -0200723 mutex_unlock(&btv->reslock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724}
725
726/* ----------------------------------------------------------------------- */
727/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
728
729/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
730 PLL_X = Reference pre-divider (0=1, 1=2)
731 PLL_C = Post divider (0=6, 1=4)
732 PLL_I = Integer input
733 PLL_F = Fractional input
734
735 F_input = 28.636363 MHz:
736 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
737*/
738
739static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
740{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800741 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800743 /* prevent overflows */
744 fin/=4;
745 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800747 fout*=12;
748 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800750 fout=(fout%fin)*256;
751 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800753 fout=(fout%fin)*256;
754 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800756 btwrite(fl, BT848_PLL_F_LO);
757 btwrite(fh, BT848_PLL_F_HI);
758 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759}
760
761static void set_pll(struct bttv *btv)
762{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800763 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800765 if (!btv->pll.pll_crystal)
766 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
769 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800770 return;
771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800773 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
774 /* no PLL needed */
775 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800776 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700777 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800778 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800779 btwrite(0x00,BT848_TGCTRL);
780 btwrite(0x00,BT848_PLL_XCI);
781 btv->pll.pll_current = 0;
782 return;
783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700785 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800786 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
788
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800789 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700791 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 msleep(10);
793
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800794 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800796 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800797 btwrite(0x08,BT848_TGCTRL);
798 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700799 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800800 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800801 }
802 }
803 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700804 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800805 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806}
807
808/* used to switch between the bt848's analog/digital video capture modes */
809static void bt848A_set_timing(struct bttv *btv)
810{
811 int i, len;
812 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
813 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
814
815 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
816 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
817 btv->c.nr,table_idx);
818
819 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800820 btwrite(0x00, BT848_TGCTRL);
821 btwrite(0x02, BT848_TGCTRL);
822 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823
824 len=SRAM_Table[table_idx][0];
825 for(i = 1; i <= len; i++)
826 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
827 btv->pll.pll_ofreq = 27000000;
828
829 set_pll(btv);
830 btwrite(0x11, BT848_TGCTRL);
831 btwrite(0x41, BT848_DVSIF);
832 } else {
833 btv->pll.pll_ofreq = fsc;
834 set_pll(btv);
835 btwrite(0x0, BT848_DVSIF);
836 }
837}
838
839/* ----------------------------------------------------------------------- */
840
841static void bt848_bright(struct bttv *btv, int bright)
842{
843 int value;
844
845 // printk("bttv: set bright: %d\n",bright); // DEBUG
846 btv->bright = bright;
847
848 /* We want -128 to 127 we get 0-65535 */
849 value = (bright >> 8) - 128;
850 btwrite(value & 0xff, BT848_BRIGHT);
851}
852
853static void bt848_hue(struct bttv *btv, int hue)
854{
855 int value;
856
857 btv->hue = hue;
858
859 /* -128 to 127 */
860 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800861 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862}
863
864static void bt848_contrast(struct bttv *btv, int cont)
865{
866 int value,hibit;
867
868 btv->contrast = cont;
869
870 /* 0-511 */
871 value = (cont >> 7);
872 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800873 btwrite(value & 0xff, BT848_CONTRAST_LO);
874 btaor(hibit, ~4, BT848_E_CONTROL);
875 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878static void bt848_sat(struct bttv *btv, int color)
879{
880 int val_u,val_v,hibits;
881
882 btv->saturation = color;
883
884 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700885 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
886 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800887 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800889 btwrite(val_u & 0xff, BT848_SAT_U_LO);
890 btwrite(val_v & 0xff, BT848_SAT_V_LO);
891 btaor(hibits, ~3, BT848_E_CONTROL);
892 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
895/* ----------------------------------------------------------------------- */
896
897static int
898video_mux(struct bttv *btv, unsigned int input)
899{
900 int mux,mask2;
901
902 if (input >= bttv_tvcards[btv->c.type].video_inputs)
903 return -EINVAL;
904
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800905 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
907 if (mask2)
908 gpio_inout(mask2,mask2);
909
910 if (input == btv->svhs) {
911 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
912 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
913 } else {
914 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
915 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
916 }
917 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
918 btaor(mux<<5, ~(3<<5), BT848_IFORM);
919 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
920 btv->c.nr,input,mux);
921
922 /* card specific hook */
923 if(bttv_tvcards[btv->c.type].muxsel_hook)
924 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
925 return 0;
926}
927
928static char *audio_modes[] = {
929 "audio: tuner", "audio: radio", "audio: extern",
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300930 "audio: intern", "audio: mute"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931};
932
933static int
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300934audio_mux(struct bttv *btv, int input, int mute)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300936 int gpio_val, signal;
937 struct v4l2_audio aud_input;
938 struct v4l2_control ctrl;
939 struct i2c_client *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300941 memset(&aud_input, 0, sizeof(aud_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
943 bttv_tvcards[btv->c.type].gpiomask);
944 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
945
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300946 btv->mute = mute;
947 btv->audio = input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300949 /* automute */
950 mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
951
952 if (mute)
953 gpio_val = bttv_tvcards[btv->c.type].gpiomute;
954 else
955 gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
956 aud_input.index = btv->audio;
957
958 gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 if (bttv_gpio)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300960 bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
961 if (in_interrupt())
962 return 0;
963
964 ctrl.id = V4L2_CID_AUDIO_MUTE;
965 /* take automute into account, just btv->mute is not enough */
966 ctrl.value = mute;
967 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
968 c = btv->i2c_msp34xx_client;
969 if (c)
970 c->driver->command(c, VIDIOC_S_AUDIO, &aud_input);
971 c = btv->i2c_tvaudio_client;
972 if (c)
973 c->driver->command(c, VIDIOC_S_AUDIO, &aud_input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return 0;
975}
976
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -0300977static inline int
978audio_mute(struct bttv *btv, int mute)
979{
980 return audio_mux(btv, btv->audio, mute);
981}
982
983static inline int
984audio_input(struct bttv *btv, int input)
985{
986 return audio_mux(btv, input, btv->mute);
987}
988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989static void
990i2c_vidiocschan(struct bttv *btv)
991{
992 struct video_channel c;
993
994 memset(&c,0,sizeof(c));
995 c.norm = btv->tvnorm;
996 c.channel = btv->input;
997 bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c);
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -0800998 if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 bttv_tda9880_setnorm(btv,c.norm);
1000}
1001
1002static int
1003set_tvnorm(struct bttv *btv, unsigned int norm)
1004{
1005 const struct bttv_tvnorm *tvnorm;
1006
1007 if (norm < 0 || norm >= BTTV_TVNORMS)
1008 return -EINVAL;
1009
1010 btv->tvnorm = norm;
1011 tvnorm = &bttv_tvnorms[norm];
1012
1013 btwrite(tvnorm->adelay, BT848_ADELAY);
1014 btwrite(tvnorm->bdelay, BT848_BDELAY);
1015 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1016 BT848_IFORM);
1017 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1018 btwrite(1, BT848_VBI_PACK_DEL);
1019 bt848A_set_timing(btv);
1020
1021 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001022 case BTTV_BOARD_VOODOOTV_FM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 bttv_tda9880_setnorm(btv,norm);
1024 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 }
1026 return 0;
1027}
1028
1029static void
1030set_input(struct bttv *btv, unsigned int input)
1031{
1032 unsigned long flags;
1033
1034 btv->input = input;
1035 if (irq_iswitch) {
1036 spin_lock_irqsave(&btv->s_lock,flags);
1037 if (btv->curr.frame_irq) {
1038 /* active capture -> delayed input switch */
1039 btv->new_input = input;
1040 } else {
1041 video_mux(btv,input);
1042 }
1043 spin_unlock_irqrestore(&btv->s_lock,flags);
1044 } else {
1045 video_mux(btv,input);
1046 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001047 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1048 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 set_tvnorm(btv,btv->tvnorm);
1050 i2c_vidiocschan(btv);
1051}
1052
1053static void init_irqreg(struct bttv *btv)
1054{
1055 /* clear status */
1056 btwrite(0xfffffUL, BT848_INT_STAT);
1057
1058 if (bttv_tvcards[btv->c.type].no_video) {
1059 /* i2c only */
1060 btwrite(BT848_INT_I2CDONE,
1061 BT848_INT_MASK);
1062 } else {
1063 /* full video */
1064 btwrite((btv->triton1) |
1065 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1066 BT848_INT_SCERR |
1067 (fdsr ? BT848_INT_FDSR : 0) |
1068 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1069 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1070 BT848_INT_I2CDONE,
1071 BT848_INT_MASK);
1072 }
1073}
1074
1075static void init_bt848(struct bttv *btv)
1076{
1077 int val;
1078
1079 if (bttv_tvcards[btv->c.type].no_video) {
1080 /* very basic init only */
1081 init_irqreg(btv);
1082 return;
1083 }
1084
1085 btwrite(0x00, BT848_CAP_CTL);
1086 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1087 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1088
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001089 /* set planar and packed mode trigger points and */
1090 /* set rising edge of inverted GPINTR pin as irq trigger */
1091 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1092 BT848_GPIO_DMA_CTL_PLTP1_16|
1093 BT848_GPIO_DMA_CTL_PLTP23_16|
1094 BT848_GPIO_DMA_CTL_GPINTC|
1095 BT848_GPIO_DMA_CTL_GPINTI,
1096 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001099 btwrite(val, BT848_E_SCLOOP);
1100 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001102 btwrite(0x20, BT848_E_VSCALE_HI);
1103 btwrite(0x20, BT848_O_VSCALE_HI);
1104 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 BT848_ADC);
1106
1107 btwrite(whitecrush_upper, BT848_WC_UP);
1108 btwrite(whitecrush_lower, BT848_WC_DOWN);
1109
1110 if (btv->opt_lumafilter) {
1111 btwrite(0, BT848_E_CONTROL);
1112 btwrite(0, BT848_O_CONTROL);
1113 } else {
1114 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1115 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1116 }
1117
1118 bt848_bright(btv, btv->bright);
1119 bt848_hue(btv, btv->hue);
1120 bt848_contrast(btv, btv->contrast);
1121 bt848_sat(btv, btv->saturation);
1122
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001123 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 init_irqreg(btv);
1125}
1126
1127static void bttv_reinit_bt848(struct bttv *btv)
1128{
1129 unsigned long flags;
1130
1131 if (bttv_verbose)
1132 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1133 spin_lock_irqsave(&btv->s_lock,flags);
1134 btv->errors=0;
1135 bttv_set_dma(btv,0);
1136 spin_unlock_irqrestore(&btv->s_lock,flags);
1137
1138 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001139 btv->pll.pll_current = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 set_input(btv,btv->input);
1141}
1142
1143static int get_control(struct bttv *btv, struct v4l2_control *c)
1144{
1145 struct video_audio va;
1146 int i;
1147
1148 for (i = 0; i < BTTV_CTLS; i++)
1149 if (bttv_ctls[i].id == c->id)
1150 break;
1151 if (i == BTTV_CTLS)
1152 return -EINVAL;
1153 if (i >= 4 && i <= 8) {
1154 memset(&va,0,sizeof(va));
1155 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1156 if (btv->audio_hook)
1157 btv->audio_hook(btv,&va,0);
1158 }
1159 switch (c->id) {
1160 case V4L2_CID_BRIGHTNESS:
1161 c->value = btv->bright;
1162 break;
1163 case V4L2_CID_HUE:
1164 c->value = btv->hue;
1165 break;
1166 case V4L2_CID_CONTRAST:
1167 c->value = btv->contrast;
1168 break;
1169 case V4L2_CID_SATURATION:
1170 c->value = btv->saturation;
1171 break;
1172
1173 case V4L2_CID_AUDIO_MUTE:
1174 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1175 break;
1176 case V4L2_CID_AUDIO_VOLUME:
1177 c->value = va.volume;
1178 break;
1179 case V4L2_CID_AUDIO_BALANCE:
1180 c->value = va.balance;
1181 break;
1182 case V4L2_CID_AUDIO_BASS:
1183 c->value = va.bass;
1184 break;
1185 case V4L2_CID_AUDIO_TREBLE:
1186 c->value = va.treble;
1187 break;
1188
1189 case V4L2_CID_PRIVATE_CHROMA_AGC:
1190 c->value = btv->opt_chroma_agc;
1191 break;
1192 case V4L2_CID_PRIVATE_COMBFILTER:
1193 c->value = btv->opt_combfilter;
1194 break;
1195 case V4L2_CID_PRIVATE_LUMAFILTER:
1196 c->value = btv->opt_lumafilter;
1197 break;
1198 case V4L2_CID_PRIVATE_AUTOMUTE:
1199 c->value = btv->opt_automute;
1200 break;
1201 case V4L2_CID_PRIVATE_AGC_CRUSH:
1202 c->value = btv->opt_adc_crush;
1203 break;
1204 case V4L2_CID_PRIVATE_VCR_HACK:
1205 c->value = btv->opt_vcr_hack;
1206 break;
1207 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1208 c->value = btv->opt_whitecrush_upper;
1209 break;
1210 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1211 c->value = btv->opt_whitecrush_lower;
1212 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001213 case V4L2_CID_PRIVATE_UV_RATIO:
1214 c->value = btv->opt_uv_ratio;
1215 break;
1216 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1217 c->value = btv->opt_full_luma_range;
1218 break;
1219 case V4L2_CID_PRIVATE_CORING:
1220 c->value = btv->opt_coring;
1221 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 default:
1223 return -EINVAL;
1224 }
1225 return 0;
1226}
1227
1228static int set_control(struct bttv *btv, struct v4l2_control *c)
1229{
1230 struct video_audio va;
1231 int i,val;
1232
1233 for (i = 0; i < BTTV_CTLS; i++)
1234 if (bttv_ctls[i].id == c->id)
1235 break;
1236 if (i == BTTV_CTLS)
1237 return -EINVAL;
1238 if (i >= 4 && i <= 8) {
1239 memset(&va,0,sizeof(va));
1240 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1241 if (btv->audio_hook)
1242 btv->audio_hook(btv,&va,0);
1243 }
1244 switch (c->id) {
1245 case V4L2_CID_BRIGHTNESS:
1246 bt848_bright(btv,c->value);
1247 break;
1248 case V4L2_CID_HUE:
1249 bt848_hue(btv,c->value);
1250 break;
1251 case V4L2_CID_CONTRAST:
1252 bt848_contrast(btv,c->value);
1253 break;
1254 case V4L2_CID_SATURATION:
1255 bt848_sat(btv,c->value);
1256 break;
1257 case V4L2_CID_AUDIO_MUTE:
1258 if (c->value) {
1259 va.flags |= VIDEO_AUDIO_MUTE;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001260 audio_mute(btv, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 } else {
1262 va.flags &= ~VIDEO_AUDIO_MUTE;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001263 audio_mute(btv, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 }
1265 break;
1266
1267 case V4L2_CID_AUDIO_VOLUME:
1268 va.volume = c->value;
1269 break;
1270 case V4L2_CID_AUDIO_BALANCE:
1271 va.balance = c->value;
1272 break;
1273 case V4L2_CID_AUDIO_BASS:
1274 va.bass = c->value;
1275 break;
1276 case V4L2_CID_AUDIO_TREBLE:
1277 va.treble = c->value;
1278 break;
1279
1280 case V4L2_CID_PRIVATE_CHROMA_AGC:
1281 btv->opt_chroma_agc = c->value;
1282 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1283 btwrite(val, BT848_E_SCLOOP);
1284 btwrite(val, BT848_O_SCLOOP);
1285 break;
1286 case V4L2_CID_PRIVATE_COMBFILTER:
1287 btv->opt_combfilter = c->value;
1288 break;
1289 case V4L2_CID_PRIVATE_LUMAFILTER:
1290 btv->opt_lumafilter = c->value;
1291 if (btv->opt_lumafilter) {
1292 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1293 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1294 } else {
1295 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1296 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1297 }
1298 break;
1299 case V4L2_CID_PRIVATE_AUTOMUTE:
1300 btv->opt_automute = c->value;
1301 break;
1302 case V4L2_CID_PRIVATE_AGC_CRUSH:
1303 btv->opt_adc_crush = c->value;
1304 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1305 BT848_ADC);
1306 break;
1307 case V4L2_CID_PRIVATE_VCR_HACK:
1308 btv->opt_vcr_hack = c->value;
1309 break;
1310 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1311 btv->opt_whitecrush_upper = c->value;
1312 btwrite(c->value, BT848_WC_UP);
1313 break;
1314 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1315 btv->opt_whitecrush_lower = c->value;
1316 btwrite(c->value, BT848_WC_DOWN);
1317 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001318 case V4L2_CID_PRIVATE_UV_RATIO:
1319 btv->opt_uv_ratio = c->value;
1320 bt848_sat(btv, btv->saturation);
1321 break;
1322 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1323 btv->opt_full_luma_range = c->value;
1324 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1325 break;
1326 case V4L2_CID_PRIVATE_CORING:
1327 btv->opt_coring = c->value;
1328 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1329 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 default:
1331 return -EINVAL;
1332 }
1333 if (i >= 4 && i <= 8) {
1334 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1335 if (btv->audio_hook)
1336 btv->audio_hook(btv,&va,1);
1337 }
1338 return 0;
1339}
1340
1341/* ----------------------------------------------------------------------- */
1342
1343void bttv_gpio_tracking(struct bttv *btv, char *comment)
1344{
1345 unsigned int outbits, data;
1346 outbits = btread(BT848_GPIO_OUT_EN);
1347 data = btread(BT848_GPIO_DATA);
1348 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1349 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1350}
1351
1352static void bttv_field_count(struct bttv *btv)
1353{
1354 int need_count = 0;
1355
1356 if (btv->users)
1357 need_count++;
1358
1359 if (need_count) {
1360 /* start field counter */
1361 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1362 } else {
1363 /* stop field counter */
1364 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1365 btv->field_count = 0;
1366 }
1367}
1368
1369static const struct bttv_format*
1370format_by_palette(int palette)
1371{
1372 unsigned int i;
1373
1374 for (i = 0; i < BTTV_FORMATS; i++) {
1375 if (-1 == bttv_formats[i].palette)
1376 continue;
1377 if (bttv_formats[i].palette == palette)
1378 return bttv_formats+i;
1379 }
1380 return NULL;
1381}
1382
1383static const struct bttv_format*
1384format_by_fourcc(int fourcc)
1385{
1386 unsigned int i;
1387
1388 for (i = 0; i < BTTV_FORMATS; i++) {
1389 if (-1 == bttv_formats[i].fourcc)
1390 continue;
1391 if (bttv_formats[i].fourcc == fourcc)
1392 return bttv_formats+i;
1393 }
1394 return NULL;
1395}
1396
1397/* ----------------------------------------------------------------------- */
1398/* misc helpers */
1399
1400static int
1401bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1402 struct bttv_buffer *new)
1403{
1404 struct bttv_buffer *old;
1405 unsigned long flags;
1406 int retval = 0;
1407
1408 dprintk("switch_overlay: enter [new=%p]\n",new);
1409 if (new)
1410 new->vb.state = STATE_DONE;
1411 spin_lock_irqsave(&btv->s_lock,flags);
1412 old = btv->screen;
1413 btv->screen = new;
1414 btv->loop_irq |= 1;
1415 bttv_set_dma(btv, 0x03);
1416 spin_unlock_irqrestore(&btv->s_lock,flags);
1417 if (NULL == new)
1418 free_btres(btv,fh,RESOURCE_OVERLAY);
1419 if (NULL != old) {
1420 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001421 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 kfree(old);
1423 }
1424 dprintk("switch_overlay: done\n");
1425 return retval;
1426}
1427
1428/* ----------------------------------------------------------------------- */
1429/* video4linux (1) interface */
1430
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001431static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1432 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001433 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 unsigned int width, unsigned int height,
1435 enum v4l2_field field)
1436{
1437 int redo_dma_risc = 0;
1438 int rc;
1439
1440 /* check settings */
1441 if (NULL == fmt)
1442 return -EINVAL;
1443 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1444 width = RAW_BPL;
1445 height = RAW_LINES*2;
1446 if (width*height > buf->vb.bsize)
1447 return -EINVAL;
1448 buf->vb.size = buf->vb.bsize;
1449 } else {
1450 if (width < 48 ||
1451 height < 32 ||
1452 width > bttv_tvnorms[btv->tvnorm].swidth ||
1453 height > bttv_tvnorms[btv->tvnorm].sheight)
1454 return -EINVAL;
1455 buf->vb.size = (width * height * fmt->depth) >> 3;
1456 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1457 return -EINVAL;
1458 }
1459
1460 /* alloc + fill struct bttv_buffer (if changed) */
1461 if (buf->vb.width != width || buf->vb.height != height ||
1462 buf->vb.field != field ||
1463 buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
1464 buf->vb.width = width;
1465 buf->vb.height = height;
1466 buf->vb.field = field;
1467 buf->tvnorm = btv->tvnorm;
1468 buf->fmt = fmt;
1469 redo_dma_risc = 1;
1470 }
1471
1472 /* alloc risc memory */
1473 if (STATE_NEEDS_INIT == buf->vb.state) {
1474 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001475 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 goto fail;
1477 }
1478
1479 if (redo_dma_risc)
1480 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1481 goto fail;
1482
1483 buf->vb.state = STATE_PREPARED;
1484 return 0;
1485
1486 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001487 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 return rc;
1489}
1490
1491static int
1492buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1493{
1494 struct bttv_fh *fh = q->priv_data;
1495
1496 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1497 if (0 == *count)
1498 *count = gbuffers;
1499 while (*size * *count > gbuffers * gbufsize)
1500 (*count)--;
1501 return 0;
1502}
1503
1504static int
1505buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1506 enum v4l2_field field)
1507{
1508 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1509 struct bttv_fh *fh = q->priv_data;
1510
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001511 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 fh->width, fh->height, field);
1513}
1514
1515static void
1516buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1517{
1518 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1519 struct bttv_fh *fh = q->priv_data;
1520 struct bttv *btv = fh->btv;
1521
1522 buf->vb.state = STATE_QUEUED;
1523 list_add_tail(&buf->vb.queue,&btv->capture);
1524 if (!btv->curr.frame_irq) {
1525 btv->loop_irq |= 1;
1526 bttv_set_dma(btv, 0x03);
1527 }
1528}
1529
1530static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1531{
1532 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1533 struct bttv_fh *fh = q->priv_data;
1534
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001535 bttv_dma_free(&fh->cap,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536}
1537
1538static struct videobuf_queue_ops bttv_video_qops = {
1539 .buf_setup = buffer_setup,
1540 .buf_prepare = buffer_prepare,
1541 .buf_queue = buffer_queue,
1542 .buf_release = buffer_release,
1543};
1544
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1546{
1547 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001548 case BTTV_VERSION:
1549 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
1551 /* *** v4l1 *** ************************************************ */
1552 case VIDIOCGFREQ:
1553 {
1554 unsigned long *freq = arg;
1555 *freq = btv->freq;
1556 return 0;
1557 }
1558 case VIDIOCSFREQ:
1559 {
1560 unsigned long *freq = arg;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001561 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 btv->freq=*freq;
1563 bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq);
1564 if (btv->has_matchbox && btv->radio_user)
1565 tea5757_set_freq(btv,*freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001566 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 return 0;
1568 }
1569
1570 case VIDIOCGTUNER:
1571 {
1572 struct video_tuner *v = arg;
1573
1574 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1575 return -EINVAL;
1576 if (v->tuner) /* Only tuner 0 */
1577 return -EINVAL;
1578 strcpy(v->name, "Television");
1579 v->rangelow = 0;
1580 v->rangehigh = 0x7FFFFFFF;
1581 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1582 v->mode = btv->tvnorm;
1583 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1584 bttv_call_i2c_clients(btv,cmd,v);
1585 return 0;
1586 }
1587 case VIDIOCSTUNER:
1588 {
1589 struct video_tuner *v = arg;
1590
1591 if (v->tuner) /* Only tuner 0 */
1592 return -EINVAL;
1593 if (v->mode >= BTTV_TVNORMS)
1594 return -EINVAL;
1595
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001596 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 set_tvnorm(btv,v->mode);
1598 bttv_call_i2c_clients(btv,cmd,v);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001599 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 return 0;
1601 }
1602
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001603 case VIDIOCGCHAN:
1604 {
1605 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 unsigned int channel = v->channel;
1607
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001608 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1609 return -EINVAL;
1610 v->tuners=0;
1611 v->flags = VIDEO_VC_AUDIO;
1612 v->type = VIDEO_TYPE_CAMERA;
1613 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001615 strcpy(v->name,"Television");
1616 v->flags|=VIDEO_VC_TUNER;
1617 v->type=VIDEO_TYPE_TV;
1618 v->tuners=1;
1619 } else if (channel == btv->svhs) {
1620 strcpy(v->name,"S-Video");
1621 } else {
1622 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 }
1624 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001625 }
1626 case VIDIOCSCHAN:
1627 {
1628 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 unsigned int channel = v->channel;
1630
1631 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1632 return -EINVAL;
1633 if (v->norm >= BTTV_TVNORMS)
1634 return -EINVAL;
1635
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001636 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 if (channel == btv->input &&
1638 v->norm == btv->tvnorm) {
1639 /* nothing to do */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001640 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 return 0;
1642 }
1643
1644 btv->tvnorm = v->norm;
1645 set_input(btv,v->channel);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001646 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 return 0;
1648 }
1649
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001650 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 {
1652 struct video_audio *v = arg;
1653
1654 memset(v,0,sizeof(*v));
1655 strcpy(v->name,"Television");
1656 v->flags |= VIDEO_AUDIO_MUTABLE;
1657 v->mode = VIDEO_SOUND_MONO;
1658
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001659 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 bttv_call_i2c_clients(btv,cmd,v);
1661
1662 /* card specific hooks */
1663 if (btv->audio_hook)
1664 btv->audio_hook(btv,v,0);
1665
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001666 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 return 0;
1668 }
1669 case VIDIOCSAUDIO:
1670 {
1671 struct video_audio *v = arg;
1672 unsigned int audio = v->audio;
1673
1674 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
1675 return -EINVAL;
1676
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001677 mutex_lock(&btv->lock);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001678 audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 bttv_call_i2c_clients(btv,cmd,v);
1680
1681 /* card specific hooks */
1682 if (btv->audio_hook)
1683 btv->audio_hook(btv,v,1);
1684
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001685 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 return 0;
1687 }
1688
1689 /* *** v4l2 *** ************************************************ */
1690 case VIDIOC_ENUMSTD:
1691 {
1692 struct v4l2_standard *e = arg;
1693 unsigned int index = e->index;
1694
1695 if (index >= BTTV_TVNORMS)
1696 return -EINVAL;
1697 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1698 bttv_tvnorms[e->index].name);
1699 e->index = index;
1700 return 0;
1701 }
1702 case VIDIOC_G_STD:
1703 {
1704 v4l2_std_id *id = arg;
1705 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1706 return 0;
1707 }
1708 case VIDIOC_S_STD:
1709 {
1710 v4l2_std_id *id = arg;
1711 unsigned int i;
1712
1713 for (i = 0; i < BTTV_TVNORMS; i++)
1714 if (*id & bttv_tvnorms[i].v4l2_id)
1715 break;
1716 if (i == BTTV_TVNORMS)
1717 return -EINVAL;
1718
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001719 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 set_tvnorm(btv,i);
1721 i2c_vidiocschan(btv);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001722 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 return 0;
1724 }
1725 case VIDIOC_QUERYSTD:
1726 {
1727 v4l2_std_id *id = arg;
1728
1729 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1730 *id = V4L2_STD_625_50;
1731 else
1732 *id = V4L2_STD_525_60;
1733 return 0;
1734 }
1735
1736 case VIDIOC_ENUMINPUT:
1737 {
1738 struct v4l2_input *i = arg;
1739 unsigned int n;
1740
1741 n = i->index;
1742 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1743 return -EINVAL;
1744 memset(i,0,sizeof(*i));
1745 i->index = n;
1746 i->type = V4L2_INPUT_TYPE_CAMERA;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001747 i->audioset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1749 sprintf(i->name, "Television");
1750 i->type = V4L2_INPUT_TYPE_TUNER;
1751 i->tuner = 0;
1752 } else if (i->index == btv->svhs) {
1753 sprintf(i->name, "S-Video");
1754 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001755 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 }
1757 if (i->index == btv->input) {
1758 __u32 dstatus = btread(BT848_DSTATUS);
1759 if (0 == (dstatus & BT848_DSTATUS_PRES))
1760 i->status |= V4L2_IN_ST_NO_SIGNAL;
1761 if (0 == (dstatus & BT848_DSTATUS_HLOC))
1762 i->status |= V4L2_IN_ST_NO_H_LOCK;
1763 }
1764 for (n = 0; n < BTTV_TVNORMS; n++)
1765 i->std |= bttv_tvnorms[n].v4l2_id;
1766 return 0;
1767 }
1768 case VIDIOC_G_INPUT:
1769 {
1770 int *i = arg;
1771 *i = btv->input;
1772 return 0;
1773 }
1774 case VIDIOC_S_INPUT:
1775 {
1776 unsigned int *i = arg;
1777
1778 if (*i > bttv_tvcards[btv->c.type].video_inputs)
1779 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001780 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 set_input(btv,*i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001782 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 return 0;
1784 }
1785
1786 case VIDIOC_G_TUNER:
1787 {
1788 struct v4l2_tuner *t = arg;
1789
1790 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1791 return -EINVAL;
1792 if (0 != t->index)
1793 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001794 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 memset(t,0,sizeof(*t));
1796 strcpy(t->name, "Television");
1797 t->type = V4L2_TUNER_ANALOG_TV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 t->capability = V4L2_TUNER_CAP_NORM;
1799 t->rxsubchans = V4L2_TUNER_SUB_MONO;
1800 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
1801 t->signal = 0xffff;
1802 {
Michael H. Schimekbbf78712005-12-01 00:51:40 -08001803 struct video_tuner tuner;
1804
1805 memset(&tuner, 0, sizeof (tuner));
1806 tuner.rangehigh = 0xffffffffUL;
1807 bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner);
1808 t->rangelow = tuner.rangelow;
1809 t->rangehigh = tuner.rangehigh;
1810 }
1811 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 /* Hmmm ... */
1813 struct video_audio va;
1814 memset(&va, 0, sizeof(struct video_audio));
1815 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1816 if (btv->audio_hook)
1817 btv->audio_hook(btv,&va,0);
1818 if(va.mode & VIDEO_SOUND_STEREO) {
1819 t->audmode = V4L2_TUNER_MODE_STEREO;
1820 t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
1821 }
1822 if(va.mode & VIDEO_SOUND_LANG1) {
1823 t->audmode = V4L2_TUNER_MODE_LANG1;
1824 t->rxsubchans = V4L2_TUNER_SUB_LANG1
1825 | V4L2_TUNER_SUB_LANG2;
1826 }
1827 }
1828 /* FIXME: fill capability+audmode */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001829 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 return 0;
1831 }
1832 case VIDIOC_S_TUNER:
1833 {
1834 struct v4l2_tuner *t = arg;
1835
1836 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1837 return -EINVAL;
1838 if (0 != t->index)
1839 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001840 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 {
1842 struct video_audio va;
1843 memset(&va, 0, sizeof(struct video_audio));
1844 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
1845 if (t->audmode == V4L2_TUNER_MODE_MONO)
1846 va.mode = VIDEO_SOUND_MONO;
1847 else if (t->audmode == V4L2_TUNER_MODE_STEREO)
1848 va.mode = VIDEO_SOUND_STEREO;
1849 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
1850 va.mode = VIDEO_SOUND_LANG1;
1851 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
1852 va.mode = VIDEO_SOUND_LANG2;
1853 bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);
1854 if (btv->audio_hook)
1855 btv->audio_hook(btv,&va,1);
1856 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001857 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 return 0;
1859 }
1860
1861 case VIDIOC_G_FREQUENCY:
1862 {
1863 struct v4l2_frequency *f = arg;
1864
1865 memset(f,0,sizeof(*f));
1866 f->type = V4L2_TUNER_ANALOG_TV;
1867 f->frequency = btv->freq;
1868 return 0;
1869 }
1870 case VIDIOC_S_FREQUENCY:
1871 {
1872 struct v4l2_frequency *f = arg;
1873
1874 if (unlikely(f->tuner != 0))
1875 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07001876 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001878 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 btv->freq = f->frequency;
1880 bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq);
1881 if (btv->has_matchbox && btv->radio_user)
1882 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001883 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 return 0;
1885 }
Hans Verkuil299392b2005-11-08 21:37:42 -08001886 case VIDIOC_LOG_STATUS:
1887 {
Luiz Capitulino97cb4452005-12-01 00:51:24 -08001888 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil299392b2005-11-08 21:37:42 -08001889 return 0;
1890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
1892 default:
1893 return -ENOIOCTLCMD;
1894
1895 }
1896 return 0;
1897}
1898
1899static int verify_window(const struct bttv_tvnorm *tvn,
1900 struct v4l2_window *win, int fixup)
1901{
1902 enum v4l2_field field;
1903 int maxw, maxh;
1904
1905 if (win->w.width < 48 || win->w.height < 32)
1906 return -EINVAL;
1907 if (win->clipcount > 2048)
1908 return -EINVAL;
1909
1910 field = win->field;
1911 maxw = tvn->swidth;
1912 maxh = tvn->sheight;
1913
1914 if (V4L2_FIELD_ANY == field) {
1915 field = (win->w.height > maxh/2)
1916 ? V4L2_FIELD_INTERLACED
1917 : V4L2_FIELD_TOP;
1918 }
1919 switch (field) {
1920 case V4L2_FIELD_TOP:
1921 case V4L2_FIELD_BOTTOM:
1922 maxh = maxh / 2;
1923 break;
1924 case V4L2_FIELD_INTERLACED:
1925 break;
1926 default:
1927 return -EINVAL;
1928 }
1929
1930 if (!fixup && (win->w.width > maxw || win->w.height > maxh))
1931 return -EINVAL;
1932
1933 if (win->w.width > maxw)
1934 win->w.width = maxw;
1935 if (win->w.height > maxh)
1936 win->w.height = maxh;
1937 win->field = field;
1938 return 0;
1939}
1940
1941static int setup_window(struct bttv_fh *fh, struct bttv *btv,
1942 struct v4l2_window *win, int fixup)
1943{
1944 struct v4l2_clip *clips = NULL;
1945 int n,size,retval = 0;
1946
1947 if (NULL == fh->ovfmt)
1948 return -EINVAL;
1949 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
1950 return -EINVAL;
1951 retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
1952 if (0 != retval)
1953 return retval;
1954
1955 /* copy clips -- luckily v4l1 + v4l2 are binary
1956 compatible here ...*/
1957 n = win->clipcount;
1958 size = sizeof(*clips)*(n+4);
1959 clips = kmalloc(size,GFP_KERNEL);
1960 if (NULL == clips)
1961 return -ENOMEM;
1962 if (n > 0) {
1963 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
1964 kfree(clips);
1965 return -EFAULT;
1966 }
1967 }
1968 /* clip against screen */
1969 if (NULL != btv->fbuf.base)
1970 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
1971 &win->w, clips, n);
1972 btcx_sort_clips(clips,n);
1973
1974 /* 4-byte alignments */
1975 switch (fh->ovfmt->depth) {
1976 case 8:
1977 case 24:
1978 btcx_align(&win->w, clips, n, 3);
1979 break;
1980 case 16:
1981 btcx_align(&win->w, clips, n, 1);
1982 break;
1983 case 32:
1984 /* no alignment fixups needed */
1985 break;
1986 default:
1987 BUG();
1988 }
1989
Ingo Molnar3593cab2006-02-07 06:49:14 -02001990 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001991 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 fh->ov.clips = clips;
1993 fh->ov.nclips = n;
1994
1995 fh->ov.w = win->w;
1996 fh->ov.field = win->field;
1997 fh->ov.setup_ok = 1;
1998 btv->init.ov.w.width = win->w.width;
1999 btv->init.ov.w.height = win->w.height;
2000 btv->init.ov.field = win->field;
2001
2002 /* update overlay if needed */
2003 retval = 0;
2004 if (check_btres(fh, RESOURCE_OVERLAY)) {
2005 struct bttv_buffer *new;
2006
2007 new = videobuf_alloc(sizeof(*new));
2008 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2009 retval = bttv_switch_overlay(btv,fh,new);
2010 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002011 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 return retval;
2013}
2014
2015/* ----------------------------------------------------------------------- */
2016
2017static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2018{
2019 struct videobuf_queue* q = NULL;
2020
2021 switch (fh->type) {
2022 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2023 q = &fh->cap;
2024 break;
2025 case V4L2_BUF_TYPE_VBI_CAPTURE:
2026 q = &fh->vbi;
2027 break;
2028 default:
2029 BUG();
2030 }
2031 return q;
2032}
2033
2034static int bttv_resource(struct bttv_fh *fh)
2035{
2036 int res = 0;
2037
2038 switch (fh->type) {
2039 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2040 res = RESOURCE_VIDEO;
2041 break;
2042 case V4L2_BUF_TYPE_VBI_CAPTURE:
2043 res = RESOURCE_VBI;
2044 break;
2045 default:
2046 BUG();
2047 }
2048 return res;
2049}
2050
2051static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2052{
2053 struct videobuf_queue *q = bttv_queue(fh);
2054 int res = bttv_resource(fh);
2055
2056 if (check_btres(fh,res))
2057 return -EBUSY;
2058 if (videobuf_queue_is_busy(q))
2059 return -EBUSY;
2060 fh->type = type;
2061 return 0;
2062}
2063
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002064static void
2065pix_format_set_size (struct v4l2_pix_format * f,
2066 const struct bttv_format * fmt,
2067 unsigned int width,
2068 unsigned int height)
2069{
2070 f->width = width;
2071 f->height = height;
2072
2073 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2074 f->bytesperline = width; /* Y plane */
2075 f->sizeimage = (width * height * fmt->depth) >> 3;
2076 } else {
2077 f->bytesperline = (width * fmt->depth) >> 3;
2078 f->sizeimage = height * f->bytesperline;
2079 }
2080}
2081
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2083{
2084 switch (f->type) {
2085 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2086 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002087 pix_format_set_size (&f->fmt.pix, fh->fmt,
2088 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 f->fmt.pix.field = fh->cap.field;
2090 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 return 0;
2092 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2093 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2094 f->fmt.win.w = fh->ov.w;
2095 f->fmt.win.field = fh->ov.field;
2096 return 0;
2097 case V4L2_BUF_TYPE_VBI_CAPTURE:
2098 bttv_vbi_get_fmt(fh,f);
2099 return 0;
2100 default:
2101 return -EINVAL;
2102 }
2103}
2104
2105static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
2106 struct v4l2_format *f)
2107{
2108 switch (f->type) {
2109 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2110 {
2111 const struct bttv_format *fmt;
2112 enum v4l2_field field;
2113 unsigned int maxw,maxh;
2114
2115 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2116 if (NULL == fmt)
2117 return -EINVAL;
2118
2119 /* fixup format */
2120 maxw = bttv_tvnorms[btv->tvnorm].swidth;
2121 maxh = bttv_tvnorms[btv->tvnorm].sheight;
2122 field = f->fmt.pix.field;
2123 if (V4L2_FIELD_ANY == field)
2124 field = (f->fmt.pix.height > maxh/2)
2125 ? V4L2_FIELD_INTERLACED
2126 : V4L2_FIELD_BOTTOM;
2127 if (V4L2_FIELD_SEQ_BT == field)
2128 field = V4L2_FIELD_SEQ_TB;
2129 switch (field) {
2130 case V4L2_FIELD_TOP:
2131 case V4L2_FIELD_BOTTOM:
2132 case V4L2_FIELD_ALTERNATE:
2133 maxh = maxh/2;
2134 break;
2135 case V4L2_FIELD_INTERLACED:
2136 break;
2137 case V4L2_FIELD_SEQ_TB:
2138 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2139 return -EINVAL;
2140 break;
2141 default:
2142 return -EINVAL;
2143 }
2144
2145 /* update data for the application */
2146 f->fmt.pix.field = field;
2147 if (f->fmt.pix.width < 48)
2148 f->fmt.pix.width = 48;
2149 if (f->fmt.pix.height < 32)
2150 f->fmt.pix.height = 32;
2151 if (f->fmt.pix.width > maxw)
2152 f->fmt.pix.width = maxw;
2153 if (f->fmt.pix.height > maxh)
2154 f->fmt.pix.height = maxh;
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002155 pix_format_set_size (&f->fmt.pix, fmt,
2156 f->fmt.pix.width & ~3,
2157 f->fmt.pix.height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
2159 return 0;
2160 }
2161 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2162 return verify_window(&bttv_tvnorms[btv->tvnorm],
2163 &f->fmt.win, 1);
2164 case V4L2_BUF_TYPE_VBI_CAPTURE:
2165 bttv_vbi_try_fmt(fh,f);
2166 return 0;
2167 default:
2168 return -EINVAL;
2169 }
2170}
2171
2172static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2173 struct v4l2_format *f)
2174{
2175 int retval;
2176
2177 switch (f->type) {
2178 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2179 {
2180 const struct bttv_format *fmt;
2181
2182 retval = bttv_switch_type(fh,f->type);
2183 if (0 != retval)
2184 return retval;
2185 retval = bttv_try_fmt(fh,btv,f);
2186 if (0 != retval)
2187 return retval;
2188 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2189
2190 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002191 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 fh->fmt = fmt;
2193 fh->cap.field = f->fmt.pix.field;
2194 fh->cap.last = V4L2_FIELD_NONE;
2195 fh->width = f->fmt.pix.width;
2196 fh->height = f->fmt.pix.height;
2197 btv->init.fmt = fmt;
2198 btv->init.width = f->fmt.pix.width;
2199 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002200 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
2202 return 0;
2203 }
2204 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002205 if (no_overlay > 0) {
2206 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2207 return -EINVAL;
2208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 return setup_window(fh, btv, &f->fmt.win, 1);
2210 case V4L2_BUF_TYPE_VBI_CAPTURE:
2211 retval = bttv_switch_type(fh,f->type);
2212 if (0 != retval)
2213 return retval;
2214 if (locked_btres(fh->btv, RESOURCE_VBI))
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002215 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 bttv_vbi_try_fmt(fh,f);
2217 bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
2218 bttv_vbi_get_fmt(fh,f);
2219 return 0;
2220 default:
2221 return -EINVAL;
2222 }
2223}
2224
2225static int bttv_do_ioctl(struct inode *inode, struct file *file,
2226 unsigned int cmd, void *arg)
2227{
2228 struct bttv_fh *fh = file->private_data;
2229 struct bttv *btv = fh->btv;
2230 unsigned long flags;
2231 int retval = 0;
2232
Michael Krufky5e453dc2006-01-09 15:32:31 -02002233 if (bttv_debug > 1)
2234 v4l_print_ioctl(btv->c.name, cmd);
2235
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 if (btv->errors)
2237 bttv_reinit_bt848(btv);
2238
2239 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002240 case VIDIOCSFREQ:
2241 case VIDIOCSTUNER:
2242 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 case VIDIOC_S_CTRL:
2244 case VIDIOC_S_STD:
2245 case VIDIOC_S_INPUT:
2246 case VIDIOC_S_TUNER:
2247 case VIDIOC_S_FREQUENCY:
2248 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2249 if (0 != retval)
2250 return retval;
2251 };
2252
2253 switch (cmd) {
2254
2255 /* *** v4l1 *** ************************************************ */
2256 case VIDIOCGCAP:
2257 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002258 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
2260 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002261 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2263 /* vbi */
2264 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2265 } else {
2266 /* others */
2267 cap->type = VID_TYPE_CAPTURE|
2268 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 VID_TYPE_CLIPPING|
2270 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002271 if (no_overlay <= 0)
2272 cap->type |= VID_TYPE_OVERLAY;
2273
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2275 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2276 cap->minwidth = 48;
2277 cap->minheight = 32;
2278 }
2279 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2280 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002281 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 }
2283
2284 case VIDIOCGPICT:
2285 {
2286 struct video_picture *pic = arg;
2287
2288 memset(pic,0,sizeof(*pic));
2289 pic->brightness = btv->bright;
2290 pic->contrast = btv->contrast;
2291 pic->hue = btv->hue;
2292 pic->colour = btv->saturation;
2293 if (fh->fmt) {
2294 pic->depth = fh->fmt->depth;
2295 pic->palette = fh->fmt->palette;
2296 }
2297 return 0;
2298 }
2299 case VIDIOCSPICT:
2300 {
2301 struct video_picture *pic = arg;
2302 const struct bttv_format *fmt;
2303
2304 fmt = format_by_palette(pic->palette);
2305 if (NULL == fmt)
2306 return -EINVAL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002307 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 if (fmt->depth != pic->depth) {
2309 retval = -EINVAL;
2310 goto fh_unlock_and_return;
2311 }
Michael H. Schimek13c72802005-12-01 00:51:37 -08002312 if (fmt->flags & FORMAT_FLAGS_RAW) {
2313 /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
2314 RAW_LINES * 2. F1 is stored at offset 0, F2
2315 at buffer size / 2. */
2316 fh->width = RAW_BPL;
2317 fh->height = gbufsize / RAW_BPL;
2318 btv->init.width = RAW_BPL;
2319 btv->init.height = gbufsize / RAW_BPL;
2320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 fh->ovfmt = fmt;
2322 fh->fmt = fmt;
2323 btv->init.ovfmt = fmt;
2324 btv->init.fmt = fmt;
2325 if (bigendian) {
2326 /* dirty hack time: swap bytes for overlay if the
2327 display adaptor is big endian (insmod option) */
2328 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2329 fmt->palette == VIDEO_PALETTE_RGB565 ||
2330 fmt->palette == VIDEO_PALETTE_RGB32) {
2331 fh->ovfmt = fmt+1;
2332 }
2333 }
2334 bt848_bright(btv,pic->brightness);
2335 bt848_contrast(btv,pic->contrast);
2336 bt848_hue(btv,pic->hue);
2337 bt848_sat(btv,pic->colour);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002338 mutex_unlock(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002339 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 }
2341
2342 case VIDIOCGWIN:
2343 {
2344 struct video_window *win = arg;
2345
2346 memset(win,0,sizeof(*win));
2347 win->x = fh->ov.w.left;
2348 win->y = fh->ov.w.top;
2349 win->width = fh->ov.w.width;
2350 win->height = fh->ov.w.height;
2351 return 0;
2352 }
2353 case VIDIOCSWIN:
2354 {
2355 struct video_window *win = arg;
2356 struct v4l2_window w2;
2357
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002358 if (no_overlay > 0) {
2359 printk ("VIDIOCSWIN: no_overlay\n");
2360 return -EINVAL;
2361 }
2362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 w2.field = V4L2_FIELD_ANY;
2364 w2.w.left = win->x;
2365 w2.w.top = win->y;
2366 w2.w.width = win->width;
2367 w2.w.height = win->height;
2368 w2.clipcount = win->clipcount;
2369 w2.clips = (struct v4l2_clip __user *)win->clips;
2370 retval = setup_window(fh, btv, &w2, 0);
2371 if (0 == retval) {
2372 /* on v4l1 this ioctl affects the read() size too */
2373 fh->width = fh->ov.w.width;
2374 fh->height = fh->ov.w.height;
2375 btv->init.width = fh->ov.w.width;
2376 btv->init.height = fh->ov.w.height;
2377 }
2378 return retval;
2379 }
2380
2381 case VIDIOCGFBUF:
2382 {
2383 struct video_buffer *fbuf = arg;
2384
2385 fbuf->base = btv->fbuf.base;
2386 fbuf->width = btv->fbuf.fmt.width;
2387 fbuf->height = btv->fbuf.fmt.height;
2388 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2389 if (fh->ovfmt)
2390 fbuf->depth = fh->ovfmt->depth;
2391 return 0;
2392 }
2393 case VIDIOCSFBUF:
2394 {
2395 struct video_buffer *fbuf = arg;
2396 const struct bttv_format *fmt;
2397 unsigned long end;
2398
2399 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002400 !capable(CAP_SYS_RAWIO))
2401 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 end = (unsigned long)fbuf->base +
2403 fbuf->height * fbuf->bytesperline;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002404 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 retval = -EINVAL;
2406
2407 switch (fbuf->depth) {
2408 case 8:
2409 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2410 break;
2411 case 16:
2412 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2413 break;
2414 case 24:
2415 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2416 break;
2417 case 32:
2418 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2419 break;
2420 case 15:
2421 fbuf->depth = 16;
2422 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2423 break;
2424 default:
2425 fmt = NULL;
2426 break;
2427 }
2428 if (NULL == fmt)
2429 goto fh_unlock_and_return;
2430
2431 fh->ovfmt = fmt;
2432 fh->fmt = fmt;
2433 btv->init.ovfmt = fmt;
2434 btv->init.fmt = fmt;
2435 btv->fbuf.base = fbuf->base;
2436 btv->fbuf.fmt.width = fbuf->width;
2437 btv->fbuf.fmt.height = fbuf->height;
2438 if (fbuf->bytesperline)
2439 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
2440 else
2441 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002442 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 return 0;
2444 }
2445
2446 case VIDIOCCAPTURE:
2447 case VIDIOC_OVERLAY:
2448 {
2449 struct bttv_buffer *new;
2450 int *on = arg;
2451
2452 if (*on) {
2453 /* verify args */
2454 if (NULL == btv->fbuf.base)
2455 return -EINVAL;
2456 if (!fh->ov.setup_ok) {
2457 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2458 return -EINVAL;
2459 }
2460 }
2461
2462 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2463 return -EBUSY;
2464
Ingo Molnar3593cab2006-02-07 06:49:14 -02002465 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 if (*on) {
2467 fh->ov.tvnorm = btv->tvnorm;
2468 new = videobuf_alloc(sizeof(*new));
2469 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2470 } else {
2471 new = NULL;
2472 }
2473
2474 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002475 retval = bttv_switch_overlay(btv,fh,new);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002476 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 return retval;
2478 }
2479
2480 case VIDIOCGMBUF:
2481 {
2482 struct video_mbuf *mbuf = arg;
2483 unsigned int i;
2484
Ingo Molnar3593cab2006-02-07 06:49:14 -02002485 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2487 V4L2_MEMORY_MMAP);
2488 if (retval < 0)
2489 goto fh_unlock_and_return;
2490 memset(mbuf,0,sizeof(*mbuf));
2491 mbuf->frames = gbuffers;
2492 mbuf->size = gbuffers * gbufsize;
2493 for (i = 0; i < gbuffers; i++)
2494 mbuf->offsets[i] = i * gbufsize;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002495 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 return 0;
2497 }
2498 case VIDIOCMCAPTURE:
2499 {
2500 struct video_mmap *vm = arg;
2501 struct bttv_buffer *buf;
2502 enum v4l2_field field;
2503
2504 if (vm->frame >= VIDEO_MAX_FRAME)
2505 return -EINVAL;
2506
Ingo Molnar3593cab2006-02-07 06:49:14 -02002507 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 retval = -EINVAL;
2509 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
2510 if (NULL == buf)
2511 goto fh_unlock_and_return;
2512 if (0 == buf->vb.baddr)
2513 goto fh_unlock_and_return;
2514 if (buf->vb.state == STATE_QUEUED ||
2515 buf->vb.state == STATE_ACTIVE)
2516 goto fh_unlock_and_return;
2517
2518 field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
2519 ? V4L2_FIELD_INTERLACED
2520 : V4L2_FIELD_BOTTOM;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03002521 retval = bttv_prepare_buffer(&fh->cap,btv,buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 format_by_palette(vm->format),
2523 vm->width,vm->height,field);
2524 if (0 != retval)
2525 goto fh_unlock_and_return;
2526 spin_lock_irqsave(&btv->s_lock,flags);
2527 buffer_queue(&fh->cap,&buf->vb);
2528 spin_unlock_irqrestore(&btv->s_lock,flags);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002529 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 return 0;
2531 }
2532 case VIDIOCSYNC:
2533 {
2534 int *frame = arg;
2535 struct bttv_buffer *buf;
2536
2537 if (*frame >= VIDEO_MAX_FRAME)
2538 return -EINVAL;
2539
Ingo Molnar3593cab2006-02-07 06:49:14 -02002540 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 retval = -EINVAL;
2542 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
2543 if (NULL == buf)
2544 goto fh_unlock_and_return;
2545 retval = videobuf_waiton(&buf->vb,0,1);
2546 if (0 != retval)
2547 goto fh_unlock_and_return;
2548 switch (buf->vb.state) {
2549 case STATE_ERROR:
2550 retval = -EIO;
2551 /* fall through */
2552 case STATE_DONE:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03002553 videobuf_dma_sync(&fh->cap,&buf->vb.dma);
2554 bttv_dma_free(&fh->cap,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 break;
2556 default:
2557 retval = -EINVAL;
2558 break;
2559 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002560 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 return retval;
2562 }
2563
2564 case VIDIOCGVBIFMT:
2565 {
2566 struct vbi_format *fmt = (void *) arg;
2567 struct v4l2_format fmt2;
2568
2569 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
2570 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2571 if (0 != retval)
2572 return retval;
2573 }
2574 bttv_vbi_get_fmt(fh, &fmt2);
2575
2576 memset(fmt,0,sizeof(*fmt));
2577 fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
2578 fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
2579 fmt->sample_format = VIDEO_PALETTE_RAW;
2580 fmt->start[0] = fmt2.fmt.vbi.start[0];
2581 fmt->count[0] = fmt2.fmt.vbi.count[0];
2582 fmt->start[1] = fmt2.fmt.vbi.start[1];
2583 fmt->count[1] = fmt2.fmt.vbi.count[1];
Michael H. Schimek67f15702006-01-09 15:25:27 -02002584 if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
2585 fmt->flags |= VBI_UNSYNC;
2586 if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
2587 fmt->flags |= VBI_INTERLACED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 return 0;
2589 }
2590 case VIDIOCSVBIFMT:
2591 {
2592 struct vbi_format *fmt = (void *) arg;
2593 struct v4l2_format fmt2;
2594
2595 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2596 if (0 != retval)
2597 return retval;
2598 bttv_vbi_get_fmt(fh, &fmt2);
2599
2600 if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
2601 fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
2602 fmt->sample_format != VIDEO_PALETTE_RAW ||
2603 fmt->start[0] != fmt2.fmt.vbi.start[0] ||
2604 fmt->start[1] != fmt2.fmt.vbi.start[1] ||
2605 fmt->count[0] != fmt->count[1] ||
2606 fmt->count[0] < 1 ||
2607 fmt->count[0] > 32 /* VBI_MAXLINES */)
2608 return -EINVAL;
2609
2610 bttv_vbi_setlines(fh,btv,fmt->count[0]);
2611 return 0;
2612 }
2613
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002614 case BTTV_VERSION:
2615 case VIDIOCGFREQ:
2616 case VIDIOCSFREQ:
2617 case VIDIOCGTUNER:
2618 case VIDIOCSTUNER:
2619 case VIDIOCGCHAN:
2620 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 case VIDIOCGAUDIO:
2622 case VIDIOCSAUDIO:
2623 return bttv_common_ioctls(btv,cmd,arg);
2624
2625 /* *** v4l2 *** ************************************************ */
2626 case VIDIOC_QUERYCAP:
2627 {
2628 struct v4l2_capability *cap = arg;
2629
2630 if (0 == v4l2)
2631 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002632 memset(cap, 0, sizeof (*cap));
2633 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
2634 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
2635 snprintf(cap->bus_info, sizeof (cap->bus_info),
2636 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 cap->version = BTTV_VERSION_CODE;
2638 cap->capabilities =
2639 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 V4L2_CAP_VBI_CAPTURE |
2641 V4L2_CAP_READWRITE |
2642 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002643 if (no_overlay <= 0)
2644 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2647 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2648 cap->capabilities |= V4L2_CAP_TUNER;
2649 return 0;
2650 }
2651
2652 case VIDIOC_ENUM_FMT:
2653 {
2654 struct v4l2_fmtdesc *f = arg;
2655 enum v4l2_buf_type type;
2656 unsigned int i;
2657 int index;
2658
2659 type = f->type;
2660 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2661 /* vbi */
2662 index = f->index;
2663 if (0 != index)
2664 return -EINVAL;
2665 memset(f,0,sizeof(*f));
2666 f->index = index;
2667 f->type = type;
2668 f->pixelformat = V4L2_PIX_FMT_GREY;
2669 strcpy(f->description,"vbi data");
2670 return 0;
2671 }
2672
2673 /* video capture + overlay */
2674 index = -1;
2675 for (i = 0; i < BTTV_FORMATS; i++) {
2676 if (bttv_formats[i].fourcc != -1)
2677 index++;
2678 if ((unsigned int)index == f->index)
2679 break;
2680 }
2681 if (BTTV_FORMATS == i)
2682 return -EINVAL;
2683
2684 switch (f->type) {
2685 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2686 break;
2687 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2688 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2689 return -EINVAL;
2690 break;
2691 default:
2692 return -EINVAL;
2693 }
2694 memset(f,0,sizeof(*f));
2695 f->index = index;
2696 f->type = type;
2697 f->pixelformat = bttv_formats[i].fourcc;
2698 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2699 return 0;
2700 }
2701
2702 case VIDIOC_TRY_FMT:
2703 {
2704 struct v4l2_format *f = arg;
2705 return bttv_try_fmt(fh,btv,f);
2706 }
2707 case VIDIOC_G_FMT:
2708 {
2709 struct v4l2_format *f = arg;
2710 return bttv_g_fmt(fh,f);
2711 }
2712 case VIDIOC_S_FMT:
2713 {
2714 struct v4l2_format *f = arg;
2715 return bttv_s_fmt(fh,btv,f);
2716 }
2717
2718 case VIDIOC_G_FBUF:
2719 {
2720 struct v4l2_framebuffer *fb = arg;
2721
2722 *fb = btv->fbuf;
2723 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2724 if (fh->ovfmt)
2725 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2726 return 0;
2727 }
2728 case VIDIOC_S_FBUF:
2729 {
2730 struct v4l2_framebuffer *fb = arg;
2731 const struct bttv_format *fmt;
2732
2733 if(!capable(CAP_SYS_ADMIN) &&
2734 !capable(CAP_SYS_RAWIO))
2735 return -EPERM;
2736
2737 /* check args */
2738 fmt = format_by_fourcc(fb->fmt.pixelformat);
2739 if (NULL == fmt)
2740 return -EINVAL;
2741 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2742 return -EINVAL;
2743
Ingo Molnar3593cab2006-02-07 06:49:14 -02002744 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 retval = -EINVAL;
2746 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2747 if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
2748 goto fh_unlock_and_return;
2749 if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
2750 goto fh_unlock_and_return;
2751 }
2752
2753 /* ok, accept it */
2754 btv->fbuf.base = fb->base;
2755 btv->fbuf.fmt.width = fb->fmt.width;
2756 btv->fbuf.fmt.height = fb->fmt.height;
2757 if (0 != fb->fmt.bytesperline)
2758 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2759 else
2760 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2761
2762 retval = 0;
2763 fh->ovfmt = fmt;
2764 btv->init.ovfmt = fmt;
2765 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2766 fh->ov.w.left = 0;
2767 fh->ov.w.top = 0;
2768 fh->ov.w.width = fb->fmt.width;
2769 fh->ov.w.height = fb->fmt.height;
2770 btv->init.ov.w.width = fb->fmt.width;
2771 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002772 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 fh->ov.clips = NULL;
2774 fh->ov.nclips = 0;
2775
2776 if (check_btres(fh, RESOURCE_OVERLAY)) {
2777 struct bttv_buffer *new;
2778
2779 new = videobuf_alloc(sizeof(*new));
2780 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2781 retval = bttv_switch_overlay(btv,fh,new);
2782 }
2783 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002784 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 return retval;
2786 }
2787
2788 case VIDIOC_REQBUFS:
2789 return videobuf_reqbufs(bttv_queue(fh),arg);
2790
2791 case VIDIOC_QUERYBUF:
2792 return videobuf_querybuf(bttv_queue(fh),arg);
2793
2794 case VIDIOC_QBUF:
2795 return videobuf_qbuf(bttv_queue(fh),arg);
2796
2797 case VIDIOC_DQBUF:
2798 return videobuf_dqbuf(bttv_queue(fh),arg,
2799 file->f_flags & O_NONBLOCK);
2800
2801 case VIDIOC_STREAMON:
2802 {
2803 int res = bttv_resource(fh);
2804
2805 if (!check_alloc_btres(btv,fh,res))
2806 return -EBUSY;
2807 return videobuf_streamon(bttv_queue(fh));
2808 }
2809 case VIDIOC_STREAMOFF:
2810 {
2811 int res = bttv_resource(fh);
2812
2813 retval = videobuf_streamoff(bttv_queue(fh));
2814 if (retval < 0)
2815 return retval;
2816 free_btres(btv,fh,res);
2817 return 0;
2818 }
2819
2820 case VIDIOC_QUERYCTRL:
2821 {
2822 struct v4l2_queryctrl *c = arg;
2823 int i;
2824
2825 if ((c->id < V4L2_CID_BASE ||
2826 c->id >= V4L2_CID_LASTP1) &&
2827 (c->id < V4L2_CID_PRIVATE_BASE ||
2828 c->id >= V4L2_CID_PRIVATE_LASTP1))
2829 return -EINVAL;
2830 for (i = 0; i < BTTV_CTLS; i++)
2831 if (bttv_ctls[i].id == c->id)
2832 break;
2833 if (i == BTTV_CTLS) {
2834 *c = no_ctl;
2835 return 0;
2836 }
2837 *c = bttv_ctls[i];
2838 if (i >= 4 && i <= 8) {
2839 struct video_audio va;
2840 memset(&va,0,sizeof(va));
2841 bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);
2842 if (btv->audio_hook)
2843 btv->audio_hook(btv,&va,0);
2844 switch (bttv_ctls[i].id) {
2845 case V4L2_CID_AUDIO_VOLUME:
2846 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2847 *c = no_ctl;
2848 break;
2849 case V4L2_CID_AUDIO_BALANCE:
2850 if (!(va.flags & VIDEO_AUDIO_BALANCE))
2851 *c = no_ctl;
2852 break;
2853 case V4L2_CID_AUDIO_BASS:
2854 if (!(va.flags & VIDEO_AUDIO_BASS))
2855 *c = no_ctl;
2856 break;
2857 case V4L2_CID_AUDIO_TREBLE:
2858 if (!(va.flags & VIDEO_AUDIO_TREBLE))
2859 *c = no_ctl;
2860 break;
2861 }
2862 }
2863 return 0;
2864 }
2865 case VIDIOC_G_CTRL:
2866 return get_control(btv,arg);
2867 case VIDIOC_S_CTRL:
2868 return set_control(btv,arg);
2869 case VIDIOC_G_PARM:
2870 {
2871 struct v4l2_streamparm *parm = arg;
2872 struct v4l2_standard s;
2873 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2874 return -EINVAL;
2875 memset(parm,0,sizeof(*parm));
2876 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2877 bttv_tvnorms[btv->tvnorm].name);
2878 parm->parm.capture.timeperframe = s.frameperiod;
2879 return 0;
2880 }
2881
2882 case VIDIOC_G_PRIORITY:
2883 {
2884 enum v4l2_priority *p = arg;
2885
2886 *p = v4l2_prio_max(&btv->prio);
2887 return 0;
2888 }
2889 case VIDIOC_S_PRIORITY:
2890 {
2891 enum v4l2_priority *prio = arg;
2892
2893 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
2894 }
2895
2896 case VIDIOC_ENUMSTD:
2897 case VIDIOC_G_STD:
2898 case VIDIOC_S_STD:
2899 case VIDIOC_ENUMINPUT:
2900 case VIDIOC_G_INPUT:
2901 case VIDIOC_S_INPUT:
2902 case VIDIOC_G_TUNER:
2903 case VIDIOC_S_TUNER:
2904 case VIDIOC_G_FREQUENCY:
2905 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08002906 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 return bttv_common_ioctls(btv,cmd,arg);
2908
2909 default:
2910 return -ENOIOCTLCMD;
2911 }
2912 return 0;
2913
2914 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02002915 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 return retval;
2917}
2918
2919static int bttv_ioctl(struct inode *inode, struct file *file,
2920 unsigned int cmd, unsigned long arg)
2921{
2922 struct bttv_fh *fh = file->private_data;
2923
2924 switch (cmd) {
2925 case BTTV_VBISIZE:
2926 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
2927 return fh->lines * 2 * 2048;
2928 default:
2929 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
2930 }
2931}
2932
2933static ssize_t bttv_read(struct file *file, char __user *data,
2934 size_t count, loff_t *ppos)
2935{
2936 struct bttv_fh *fh = file->private_data;
2937 int retval = 0;
2938
2939 if (fh->btv->errors)
2940 bttv_reinit_bt848(fh->btv);
2941 dprintk("bttv%d: read count=%d type=%s\n",
2942 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
2943
2944 switch (fh->type) {
2945 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2946 if (locked_btres(fh->btv,RESOURCE_VIDEO))
2947 return -EBUSY;
2948 retval = videobuf_read_one(&fh->cap, data, count, ppos,
2949 file->f_flags & O_NONBLOCK);
2950 break;
2951 case V4L2_BUF_TYPE_VBI_CAPTURE:
2952 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2953 return -EBUSY;
2954 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
2955 file->f_flags & O_NONBLOCK);
2956 break;
2957 default:
2958 BUG();
2959 }
2960 return retval;
2961}
2962
2963static unsigned int bttv_poll(struct file *file, poll_table *wait)
2964{
2965 struct bttv_fh *fh = file->private_data;
2966 struct bttv_buffer *buf;
2967 enum v4l2_field field;
2968
2969 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2970 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
2971 return POLLERR;
2972 return videobuf_poll_stream(file, &fh->vbi, wait);
2973 }
2974
2975 if (check_btres(fh,RESOURCE_VIDEO)) {
2976 /* streaming capture */
2977 if (list_empty(&fh->cap.stream))
2978 return POLLERR;
2979 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
2980 } else {
2981 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002982 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 if (NULL == fh->cap.read_buf) {
2984 /* need to capture a new frame */
2985 if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02002986 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 return POLLERR;
2988 }
2989 fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
2990 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02002991 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 return POLLERR;
2993 }
2994 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
2995 field = videobuf_next_field(&fh->cap);
2996 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08002997 kfree (fh->cap.read_buf);
2998 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002999 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 return POLLERR;
3001 }
3002 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3003 fh->cap.read_off = 0;
3004 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003005 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 buf = (struct bttv_buffer*)fh->cap.read_buf;
3007 }
3008
3009 poll_wait(file, &buf->vb.done, wait);
3010 if (buf->vb.state == STATE_DONE ||
3011 buf->vb.state == STATE_ERROR)
3012 return POLLIN|POLLRDNORM;
3013 return 0;
3014}
3015
3016static int bttv_open(struct inode *inode, struct file *file)
3017{
3018 int minor = iminor(inode);
3019 struct bttv *btv = NULL;
3020 struct bttv_fh *fh;
3021 enum v4l2_buf_type type = 0;
3022 unsigned int i;
3023
3024 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3025
3026 for (i = 0; i < bttv_num; i++) {
3027 if (bttvs[i].video_dev &&
3028 bttvs[i].video_dev->minor == minor) {
3029 btv = &bttvs[i];
3030 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3031 break;
3032 }
3033 if (bttvs[i].vbi_dev &&
3034 bttvs[i].vbi_dev->minor == minor) {
3035 btv = &bttvs[i];
3036 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3037 break;
3038 }
3039 }
3040 if (NULL == btv)
3041 return -ENODEV;
3042
3043 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3044 btv->c.nr,v4l2_type_names[type]);
3045
3046 /* allocate per filehandle data */
3047 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3048 if (NULL == fh)
3049 return -ENOMEM;
3050 file->private_data = fh;
3051 *fh = btv->init;
3052 fh->type = type;
3053 fh->ov.setup_ok = 0;
3054 v4l2_prio_open(&btv->prio,&fh->prio);
3055
3056 videobuf_queue_init(&fh->cap, &bttv_video_qops,
3057 btv->c.pci, &btv->s_lock,
3058 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3059 V4L2_FIELD_INTERLACED,
3060 sizeof(struct bttv_buffer),
3061 fh);
3062 videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
3063 btv->c.pci, &btv->s_lock,
3064 V4L2_BUF_TYPE_VBI_CAPTURE,
3065 V4L2_FIELD_SEQ_TB,
3066 sizeof(struct bttv_buffer),
3067 fh);
3068 i2c_vidiocschan(btv);
3069
3070 btv->users++;
3071 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
3072 bttv_vbi_setlines(fh,btv,16);
3073 bttv_field_count(btv);
3074 return 0;
3075}
3076
3077static int bttv_release(struct inode *inode, struct file *file)
3078{
3079 struct bttv_fh *fh = file->private_data;
3080 struct bttv *btv = fh->btv;
3081
3082 /* turn off overlay */
3083 if (check_btres(fh, RESOURCE_OVERLAY))
3084 bttv_switch_overlay(btv,fh,NULL);
3085
3086 /* stop video capture */
3087 if (check_btres(fh, RESOURCE_VIDEO)) {
3088 videobuf_streamoff(&fh->cap);
3089 free_btres(btv,fh,RESOURCE_VIDEO);
3090 }
3091 if (fh->cap.read_buf) {
3092 buffer_release(&fh->cap,fh->cap.read_buf);
3093 kfree(fh->cap.read_buf);
3094 }
3095
3096 /* stop vbi capture */
3097 if (check_btres(fh, RESOURCE_VBI)) {
3098 if (fh->vbi.streaming)
3099 videobuf_streamoff(&fh->vbi);
3100 if (fh->vbi.reading)
3101 videobuf_read_stop(&fh->vbi);
3102 free_btres(btv,fh,RESOURCE_VBI);
3103 }
3104
3105 /* free stuff */
3106 videobuf_mmap_free(&fh->cap);
3107 videobuf_mmap_free(&fh->vbi);
3108 v4l2_prio_close(&btv->prio,&fh->prio);
3109 file->private_data = NULL;
3110 kfree(fh);
3111
3112 btv->users--;
3113 bttv_field_count(btv);
3114 return 0;
3115}
3116
3117static int
3118bttv_mmap(struct file *file, struct vm_area_struct *vma)
3119{
3120 struct bttv_fh *fh = file->private_data;
3121
3122 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3123 fh->btv->c.nr, v4l2_type_names[fh->type],
3124 vma->vm_start, vma->vm_end - vma->vm_start);
3125 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3126}
3127
3128static struct file_operations bttv_fops =
3129{
3130 .owner = THIS_MODULE,
3131 .open = bttv_open,
3132 .release = bttv_release,
3133 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003134 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 .llseek = no_llseek,
3136 .read = bttv_read,
3137 .mmap = bttv_mmap,
3138 .poll = bttv_poll,
3139};
3140
3141static struct video_device bttv_video_template =
3142{
3143 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003144 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003145 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 .hardware = VID_HARDWARE_BT848,
3147 .fops = &bttv_fops,
3148 .minor = -1,
3149};
3150
3151static struct video_device bttv_vbi_template =
3152{
3153 .name = "bt848/878 vbi",
3154 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
3155 .hardware = VID_HARDWARE_BT848,
3156 .fops = &bttv_fops,
3157 .minor = -1,
3158};
3159
3160/* ----------------------------------------------------------------------- */
3161/* radio interface */
3162
3163static int radio_open(struct inode *inode, struct file *file)
3164{
3165 int minor = iminor(inode);
3166 struct bttv *btv = NULL;
3167 unsigned int i;
3168
3169 dprintk("bttv: open minor=%d\n",minor);
3170
3171 for (i = 0; i < bttv_num; i++) {
3172 if (bttvs[i].radio_dev->minor == minor) {
3173 btv = &bttvs[i];
3174 break;
3175 }
3176 }
3177 if (NULL == btv)
3178 return -ENODEV;
3179
3180 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003181 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003182
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003184
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 file->private_data = btv;
3186
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003187 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3188 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003190 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003191 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192}
3193
3194static int radio_release(struct inode *inode, struct file *file)
3195{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003196 struct bttv *btv = file->private_data;
3197 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
3199 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003200
3201 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3202
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 return 0;
3204}
3205
3206static int radio_do_ioctl(struct inode *inode, struct file *file,
3207 unsigned int cmd, void *arg)
3208{
3209 struct bttv *btv = file->private_data;
3210
3211 switch (cmd) {
3212 case VIDIOCGCAP:
3213 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003214 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
3216 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003217 strcpy(cap->name,btv->radio_dev->name);
3218 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 cap->channels = 1;
3220 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003221 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 }
3223
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003224 case VIDIOCGTUNER:
3225 {
3226 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003228 if(v->tuner)
3229 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003231 strcpy(v->name, "Radio");
3232 bttv_call_i2c_clients(btv,cmd,v);
3233 return 0;
3234 }
3235 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 /* nothing to do */
3237 return 0;
3238
3239 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003240 case VIDIOCGFREQ:
3241 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 case VIDIOCGAUDIO:
3243 case VIDIOCSAUDIO:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003244 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 return bttv_common_ioctls(btv,cmd,arg);
3246
3247 default:
3248 return -ENOIOCTLCMD;
3249 }
3250 return 0;
3251}
3252
3253static int radio_ioctl(struct inode *inode, struct file *file,
3254 unsigned int cmd, unsigned long arg)
3255{
3256 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3257}
3258
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003259static ssize_t radio_read(struct file *file, char __user *data,
3260 size_t count, loff_t *ppos)
3261{
3262 struct bttv *btv = file->private_data;
3263 struct rds_command cmd;
3264 cmd.block_count = count/3;
3265 cmd.buffer = data;
3266 cmd.instance = file;
3267 cmd.result = -ENODEV;
3268
3269 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3270
3271 return cmd.result;
3272}
3273
3274static unsigned int radio_poll(struct file *file, poll_table *wait)
3275{
3276 struct bttv *btv = file->private_data;
3277 struct rds_command cmd;
3278 cmd.instance = file;
3279 cmd.event_list = wait;
3280 cmd.result = -ENODEV;
3281 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3282
3283 return cmd.result;
3284}
3285
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286static struct file_operations radio_fops =
3287{
3288 .owner = THIS_MODULE,
3289 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003290 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 .release = radio_release,
3292 .ioctl = radio_ioctl,
3293 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003294 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295};
3296
3297static struct video_device radio_template =
3298{
3299 .name = "bt848/878 radio",
3300 .type = VID_TYPE_TUNER,
3301 .hardware = VID_HARDWARE_BT848,
3302 .fops = &radio_fops,
3303 .minor = -1,
3304};
3305
3306/* ----------------------------------------------------------------------- */
3307/* some debug code */
3308
Adrian Bunk408b6642005-05-01 08:59:29 -07003309static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310{
3311 static char *instr[16] = {
3312 [ BT848_RISC_WRITE >> 28 ] = "write",
3313 [ BT848_RISC_SKIP >> 28 ] = "skip",
3314 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3315 [ BT848_RISC_JUMP >> 28 ] = "jump",
3316 [ BT848_RISC_SYNC >> 28 ] = "sync",
3317 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3318 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3319 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3320 };
3321 static int incr[16] = {
3322 [ BT848_RISC_WRITE >> 28 ] = 2,
3323 [ BT848_RISC_JUMP >> 28 ] = 2,
3324 [ BT848_RISC_SYNC >> 28 ] = 2,
3325 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3326 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3327 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3328 };
3329 static char *bits[] = {
3330 "be0", "be1", "be2", "be3/resync",
3331 "set0", "set1", "set2", "set3",
3332 "clr0", "clr1", "clr2", "clr3",
3333 "irq", "res", "eol", "sol",
3334 };
3335 int i;
3336
3337 printk("0x%08x [ %s", risc,
3338 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3339 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3340 if (risc & (1 << (i + 12)))
3341 printk(" %s",bits[i]);
3342 printk(" count=%d ]\n", risc & 0xfff);
3343 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3344}
3345
Adrian Bunk408b6642005-05-01 08:59:29 -07003346static void bttv_risc_disasm(struct bttv *btv,
3347 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348{
3349 unsigned int i,j,n;
3350
3351 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3352 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3353 for (i = 0; i < (risc->size >> 2); i += n) {
3354 printk("%s: 0x%lx: ", btv->c.name,
3355 (unsigned long)(risc->dma + (i<<2)));
3356 n = bttv_risc_decode(risc->cpu[i]);
3357 for (j = 1; j < n; j++)
3358 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3359 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3360 risc->cpu[i+j], j);
3361 if (0 == risc->cpu[i])
3362 break;
3363 }
3364}
3365
3366static void bttv_print_riscaddr(struct bttv *btv)
3367{
3368 printk(" main: %08Lx\n",
3369 (unsigned long long)btv->main.dma);
3370 printk(" vbi : o=%08Lx e=%08Lx\n",
3371 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3372 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3373 printk(" cap : o=%08Lx e=%08Lx\n",
3374 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3375 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3376 printk(" scr : o=%08Lx e=%08Lx\n",
3377 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3378 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3379 bttv_risc_disasm(btv, &btv->main);
3380}
3381
3382/* ----------------------------------------------------------------------- */
3383/* irq handler */
3384
3385static char *irq_name[] = {
3386 "FMTCHG", // format change detected (525 vs. 625)
3387 "VSYNC", // vertical sync (new field)
3388 "HSYNC", // horizontal sync
3389 "OFLOW", // chroma/luma AGC overflow
3390 "HLOCK", // horizontal lock changed
3391 "VPRES", // video presence changed
3392 "6", "7",
3393 "I2CDONE", // hw irc operation finished
3394 "GPINT", // gpio port triggered irq
3395 "10",
3396 "RISCI", // risc instruction triggered irq
3397 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3398 "FTRGT", // pixel data fifo overrun
3399 "FDSR", // fifo data stream resyncronisation
3400 "PPERR", // parity error (data transfer)
3401 "RIPERR", // parity error (read risc instructions)
3402 "PABORT", // pci abort
3403 "OCERR", // risc instruction error
3404 "SCERR", // syncronisation error
3405};
3406
3407static void bttv_print_irqbits(u32 print, u32 mark)
3408{
3409 unsigned int i;
3410
3411 printk("bits:");
3412 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3413 if (print & (1 << i))
3414 printk(" %s",irq_name[i]);
3415 if (mark & (1 << i))
3416 printk("*");
3417 }
3418}
3419
3420static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3421{
3422 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3423 btv->c.nr,
3424 (unsigned long)btv->main.dma,
3425 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3426 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3427 (unsigned long)rc);
3428
3429 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3430 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3431 "Ok, then this is harmless, don't worry ;)\n",
3432 btv->c.nr);
3433 return;
3434 }
3435 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3436 btv->c.nr);
3437 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3438 btv->c.nr);
3439 dump_stack();
3440}
3441
3442static int
3443bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3444{
3445 struct bttv_buffer *item;
3446
3447 memset(set,0,sizeof(*set));
3448
3449 /* capture request ? */
3450 if (!list_empty(&btv->capture)) {
3451 set->frame_irq = 1;
3452 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3453 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3454 set->top = item;
3455 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3456 set->bottom = item;
3457
3458 /* capture request for other field ? */
3459 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3460 (item->vb.queue.next != &btv->capture)) {
3461 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3462 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3463 if (NULL == set->top &&
3464 V4L2_FIELD_TOP == item->vb.field) {
3465 set->top = item;
3466 }
3467 if (NULL == set->bottom &&
3468 V4L2_FIELD_BOTTOM == item->vb.field) {
3469 set->bottom = item;
3470 }
3471 if (NULL != set->top && NULL != set->bottom)
3472 set->top_irq = 2;
3473 }
3474 }
3475 }
3476
3477 /* screen overlay ? */
3478 if (NULL != btv->screen) {
3479 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3480 if (NULL == set->top && NULL == set->bottom) {
3481 set->top = btv->screen;
3482 set->bottom = btv->screen;
3483 }
3484 } else {
3485 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3486 NULL == set->top) {
3487 set->top = btv->screen;
3488 }
3489 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3490 NULL == set->bottom) {
3491 set->bottom = btv->screen;
3492 }
3493 }
3494 }
3495
3496 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3497 btv->c.nr,set->top, set->bottom,
3498 btv->screen,set->frame_irq,set->top_irq);
3499 return 0;
3500}
3501
3502static void
3503bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3504 struct bttv_buffer_set *curr, unsigned int state)
3505{
3506 struct timeval ts;
3507
3508 do_gettimeofday(&ts);
3509
3510 if (wakeup->top == wakeup->bottom) {
3511 if (NULL != wakeup->top && curr->top != wakeup->top) {
3512 if (irq_debug > 1)
3513 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3514 wakeup->top->vb.ts = ts;
3515 wakeup->top->vb.field_count = btv->field_count;
3516 wakeup->top->vb.state = state;
3517 wake_up(&wakeup->top->vb.done);
3518 }
3519 } else {
3520 if (NULL != wakeup->top && curr->top != wakeup->top) {
3521 if (irq_debug > 1)
3522 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3523 wakeup->top->vb.ts = ts;
3524 wakeup->top->vb.field_count = btv->field_count;
3525 wakeup->top->vb.state = state;
3526 wake_up(&wakeup->top->vb.done);
3527 }
3528 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3529 if (irq_debug > 1)
3530 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3531 wakeup->bottom->vb.ts = ts;
3532 wakeup->bottom->vb.field_count = btv->field_count;
3533 wakeup->bottom->vb.state = state;
3534 wake_up(&wakeup->bottom->vb.done);
3535 }
3536 }
3537}
3538
3539static void
3540bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3541 unsigned int state)
3542{
3543 struct timeval ts;
3544
3545 if (NULL == wakeup)
3546 return;
3547
3548 do_gettimeofday(&ts);
3549 wakeup->vb.ts = ts;
3550 wakeup->vb.field_count = btv->field_count;
3551 wakeup->vb.state = state;
3552 wake_up(&wakeup->vb.done);
3553}
3554
3555static void bttv_irq_timeout(unsigned long data)
3556{
3557 struct bttv *btv = (struct bttv *)data;
3558 struct bttv_buffer_set old,new;
3559 struct bttv_buffer *ovbi;
3560 struct bttv_buffer *item;
3561 unsigned long flags;
3562
3563 if (bttv_verbose) {
3564 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3565 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3566 btread(BT848_RISC_COUNT));
3567 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3568 printk("\n");
3569 }
3570
3571 spin_lock_irqsave(&btv->s_lock,flags);
3572
3573 /* deactivate stuff */
3574 memset(&new,0,sizeof(new));
3575 old = btv->curr;
3576 ovbi = btv->cvbi;
3577 btv->curr = new;
3578 btv->cvbi = NULL;
3579 btv->loop_irq = 0;
3580 bttv_buffer_activate_video(btv, &new);
3581 bttv_buffer_activate_vbi(btv, NULL);
3582 bttv_set_dma(btv, 0);
3583
3584 /* wake up */
3585 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
3586 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
3587
3588 /* cancel all outstanding capture / vbi requests */
3589 while (!list_empty(&btv->capture)) {
3590 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3591 list_del(&item->vb.queue);
3592 item->vb.state = STATE_ERROR;
3593 wake_up(&item->vb.done);
3594 }
3595 while (!list_empty(&btv->vcapture)) {
3596 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3597 list_del(&item->vb.queue);
3598 item->vb.state = STATE_ERROR;
3599 wake_up(&item->vb.done);
3600 }
3601
3602 btv->errors++;
3603 spin_unlock_irqrestore(&btv->s_lock,flags);
3604}
3605
3606static void
3607bttv_irq_wakeup_top(struct bttv *btv)
3608{
3609 struct bttv_buffer *wakeup = btv->curr.top;
3610
3611 if (NULL == wakeup)
3612 return;
3613
3614 spin_lock(&btv->s_lock);
3615 btv->curr.top_irq = 0;
3616 btv->curr.top = NULL;
3617 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3618
3619 do_gettimeofday(&wakeup->vb.ts);
3620 wakeup->vb.field_count = btv->field_count;
3621 wakeup->vb.state = STATE_DONE;
3622 wake_up(&wakeup->vb.done);
3623 spin_unlock(&btv->s_lock);
3624}
3625
3626static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3627{
3628 if (rc < risc->dma)
3629 return 0;
3630 if (rc > risc->dma + risc->size)
3631 return 0;
3632 return 1;
3633}
3634
3635static void
3636bttv_irq_switch_video(struct bttv *btv)
3637{
3638 struct bttv_buffer_set new;
3639 struct bttv_buffer_set old;
3640 dma_addr_t rc;
3641
3642 spin_lock(&btv->s_lock);
3643
3644 /* new buffer set */
3645 bttv_irq_next_video(btv, &new);
3646 rc = btread(BT848_RISC_COUNT);
3647 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3648 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3649 btv->framedrop++;
3650 if (debug_latency)
3651 bttv_irq_debug_low_latency(btv, rc);
3652 spin_unlock(&btv->s_lock);
3653 return;
3654 }
3655
3656 /* switch over */
3657 old = btv->curr;
3658 btv->curr = new;
3659 btv->loop_irq &= ~1;
3660 bttv_buffer_activate_video(btv, &new);
3661 bttv_set_dma(btv, 0);
3662
3663 /* switch input */
3664 if (UNSET != btv->new_input) {
3665 video_mux(btv,btv->new_input);
3666 btv->new_input = UNSET;
3667 }
3668
3669 /* wake up finished buffers */
3670 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
3671 spin_unlock(&btv->s_lock);
3672}
3673
3674static void
3675bttv_irq_switch_vbi(struct bttv *btv)
3676{
3677 struct bttv_buffer *new = NULL;
3678 struct bttv_buffer *old;
3679 u32 rc;
3680
3681 spin_lock(&btv->s_lock);
3682
3683 if (!list_empty(&btv->vcapture))
3684 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3685 old = btv->cvbi;
3686
3687 rc = btread(BT848_RISC_COUNT);
3688 if (NULL != old && (is_active(&old->top, rc) ||
3689 is_active(&old->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 */
3698 btv->cvbi = new;
3699 btv->loop_irq &= ~4;
3700 bttv_buffer_activate_vbi(btv, new);
3701 bttv_set_dma(btv, 0);
3702
3703 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
3704 spin_unlock(&btv->s_lock);
3705}
3706
3707static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
3708{
3709 u32 stat,astat;
3710 u32 dstat;
3711 int count;
3712 struct bttv *btv;
3713 int handled = 0;
3714
3715 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003716
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003717 if (btv->custom_irq)
3718 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003719
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 count=0;
3721 while (1) {
3722 /* get/clear interrupt status bits */
3723 stat=btread(BT848_INT_STAT);
3724 astat=stat&btread(BT848_INT_MASK);
3725 if (!astat)
3726 break;
3727 handled = 1;
3728 btwrite(stat,BT848_INT_STAT);
3729
3730 /* get device status bits */
3731 dstat=btread(BT848_DSTATUS);
3732
3733 if (irq_debug) {
3734 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
3735 "riscs=%x, riscc=%08x, ",
3736 btv->c.nr, count, btv->field_count,
3737 stat>>28, btread(BT848_RISC_COUNT));
3738 bttv_print_irqbits(stat,astat);
3739 if (stat & BT848_INT_HLOCK)
3740 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
3741 ? "yes" : "no");
3742 if (stat & BT848_INT_VPRES)
3743 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
3744 ? "yes" : "no");
3745 if (stat & BT848_INT_FMTCHG)
3746 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
3747 ? "625" : "525");
3748 printk("\n");
3749 }
3750
3751 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003752 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003754 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003756 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 }
3758
3759 if (astat & BT848_INT_I2CDONE) {
3760 btv->i2c_done = stat;
3761 wake_up(&btv->i2c_queue);
3762 }
3763
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003764 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 bttv_irq_switch_vbi(btv);
3766
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003767 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 bttv_irq_wakeup_top(btv);
3769
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003770 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 bttv_irq_switch_video(btv);
3772
3773 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003774 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775
3776 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
3777 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
3778 (astat & BT848_INT_SCERR) ? "SCERR" : "",
3779 (astat & BT848_INT_OCERR) ? "OCERR" : "",
3780 btread(BT848_RISC_COUNT));
3781 bttv_print_irqbits(stat,astat);
3782 printk("\n");
3783 if (bttv_debug)
3784 bttv_print_riscaddr(btv);
3785 }
3786 if (fdsr && astat & BT848_INT_FDSR) {
3787 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
3788 btv->c.nr,btread(BT848_RISC_COUNT));
3789 if (bttv_debug)
3790 bttv_print_riscaddr(btv);
3791 }
3792
3793 count++;
3794 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003795
3796 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003797 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003798
3799 printk(KERN_ERR
3800 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
3801 } else {
3802 printk(KERN_ERR
3803 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
3804
3805 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
3806 BT848_INT_MASK);
3807 };
3808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08003810
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 printk("]\n");
3812 }
3813 }
3814 btv->irq_total++;
3815 if (handled)
3816 btv->irq_me++;
3817 return IRQ_RETVAL(handled);
3818}
3819
3820
3821/* ----------------------------------------------------------------------- */
3822/* initialitation */
3823
3824static struct video_device *vdev_init(struct bttv *btv,
3825 struct video_device *template,
3826 char *type)
3827{
3828 struct video_device *vfd;
3829
3830 vfd = video_device_alloc();
3831 if (NULL == vfd)
3832 return NULL;
3833 *vfd = *template;
3834 vfd->minor = -1;
3835 vfd->dev = &btv->c.pci->dev;
3836 vfd->release = video_device_release;
3837 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
3838 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
3839 type, bttv_tvcards[btv->c.type].name);
3840 return vfd;
3841}
3842
3843static void bttv_unregister_video(struct bttv *btv)
3844{
3845 if (btv->video_dev) {
3846 if (-1 != btv->video_dev->minor)
3847 video_unregister_device(btv->video_dev);
3848 else
3849 video_device_release(btv->video_dev);
3850 btv->video_dev = NULL;
3851 }
3852 if (btv->vbi_dev) {
3853 if (-1 != btv->vbi_dev->minor)
3854 video_unregister_device(btv->vbi_dev);
3855 else
3856 video_device_release(btv->vbi_dev);
3857 btv->vbi_dev = NULL;
3858 }
3859 if (btv->radio_dev) {
3860 if (-1 != btv->radio_dev->minor)
3861 video_unregister_device(btv->radio_dev);
3862 else
3863 video_device_release(btv->radio_dev);
3864 btv->radio_dev = NULL;
3865 }
3866}
3867
3868/* register video4linux devices */
3869static int __devinit bttv_register_video(struct bttv *btv)
3870{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003871 if (no_overlay <= 0) {
3872 bttv_video_template.type |= VID_TYPE_OVERLAY;
3873 } else {
3874 printk("bttv: Overlay support disabled.\n");
3875 }
3876
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 /* video */
3878 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003879 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 goto err;
3881 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
3882 goto err;
3883 printk(KERN_INFO "bttv%d: registered device video%d\n",
3884 btv->c.nr,btv->video_dev->minor & 0x1f);
3885 video_device_create_file(btv->video_dev, &class_device_attr_card);
3886
3887 /* vbi */
3888 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003889 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003891 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 goto err;
3893 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
3894 btv->c.nr,btv->vbi_dev->minor & 0x1f);
3895
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003896 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 return 0;
3898 /* radio */
3899 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003900 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 goto err;
3902 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
3903 goto err;
3904 printk(KERN_INFO "bttv%d: registered device radio%d\n",
3905 btv->c.nr,btv->radio_dev->minor & 0x1f);
3906
3907 /* all done */
3908 return 0;
3909
3910 err:
3911 bttv_unregister_video(btv);
3912 return -1;
3913}
3914
3915
3916/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
3917/* response on cards with no firmware is not enabled by OF */
3918static void pci_set_command(struct pci_dev *dev)
3919{
3920#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003921 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003923 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
3924 cmd = (cmd | PCI_COMMAND_MEMORY );
3925 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926#endif
3927}
3928
3929static int __devinit bttv_probe(struct pci_dev *dev,
3930 const struct pci_device_id *pci_id)
3931{
3932 int result;
3933 unsigned char lat;
3934 struct bttv *btv;
3935
3936 if (bttv_num == BTTV_MAX)
3937 return -ENOMEM;
3938 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003939 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 memset(btv,0,sizeof(*btv));
3941 btv->c.nr = bttv_num;
3942 sprintf(btv->c.name,"bttv%d",btv->c.nr);
3943
3944 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003945 mutex_init(&btv->lock);
3946 mutex_init(&btv->reslock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003947 spin_lock_init(&btv->s_lock);
3948 spin_lock_init(&btv->gpio_lock);
3949 init_waitqueue_head(&btv->gpioq);
3950 init_waitqueue_head(&btv->i2c_queue);
3951 INIT_LIST_HEAD(&btv->c.subs);
3952 INIT_LIST_HEAD(&btv->capture);
3953 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 v4l2_prio_init(&btv->prio);
3955
3956 init_timer(&btv->timeout);
3957 btv->timeout.function = bttv_irq_timeout;
3958 btv->timeout.data = (unsigned long)btv;
3959
Michael Krufky7c08fb02005-11-08 21:36:21 -08003960 btv->i2c_rc = -1;
3961 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 btv->has_radio=radio[btv->c.nr];
3964
3965 /* pci stuff (init, get irq/mmio, ... */
3966 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08003967 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08003969 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 btv->c.nr);
3971 return -EIO;
3972 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003973 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
3974 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 btv->c.nr);
3976 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 if (!request_mem_region(pci_resource_start(dev,0),
3979 pci_resource_len(dev,0),
3980 btv->c.name)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003981 printk(KERN_WARNING "bttv%d: can't request iomem (0x%lx).\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 btv->c.nr, pci_resource_start(dev,0));
3983 return -EBUSY;
3984 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003985 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 pci_set_command(dev);
3987 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003989 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
3990 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
3991 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
3992 bttv_num,btv->id, btv->revision, pci_name(dev));
3993 printk("irq: %d, latency: %d, mmio: 0x%lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 btv->c.pci->irq, lat, pci_resource_start(dev,0));
3995 schedule();
3996
3997 btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
3998 if (NULL == ioremap(pci_resource_start(dev,0), 0x1000)) {
3999 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4000 result = -EIO;
4001 goto fail1;
4002 }
4003
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004004 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 bttv_idcard(btv);
4006
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004007 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004009 result = request_irq(btv->c.pci->irq, bttv_irq,
4010 SA_SHIRQ | SA_INTERRUPT,btv->c.name,(void *)btv);
4011 if (result < 0) {
4012 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 bttv_num,btv->c.pci->irq);
4014 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
4017 if (0 != bttv_handle_chipset(btv)) {
4018 result = -EIO;
4019 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
4022 /* init options from insmod args */
4023 btv->opt_combfilter = combfilter;
4024 btv->opt_lumafilter = lumafilter;
4025 btv->opt_automute = automute;
4026 btv->opt_chroma_agc = chroma_agc;
4027 btv->opt_adc_crush = adc_crush;
4028 btv->opt_vcr_hack = vcr_hack;
4029 btv->opt_whitecrush_upper = whitecrush_upper;
4030 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004031 btv->opt_uv_ratio = uv_ratio;
4032 btv->opt_full_luma_range = full_luma_range;
4033 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034
4035 /* fill struct bttv with some useful defaults */
4036 btv->init.btv = btv;
4037 btv->init.ov.w.width = 320;
4038 btv->init.ov.w.height = 240;
4039 btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
4040 btv->init.width = 320;
4041 btv->init.height = 240;
4042 btv->init.lines = 16;
4043 btv->input = 0;
4044
4045 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004046 if (bttv_gpio)
4047 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048
4049 bttv_risc_init_main(btv);
4050 init_bt848(btv);
4051
4052 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004053 btwrite(0x00, BT848_GPIO_REG_INP);
4054 btwrite(0x00, BT848_GPIO_OUT_EN);
4055 if (bttv_verbose)
4056 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004058 /* needs to be done before i2c is registered */
4059 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004061 /* register i2c + gpio */
4062 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004064 /* some card-specific stuff (needs working i2c) */
4065 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 init_irqreg(btv);
4067
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004068 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 if (!bttv_tvcards[btv->c.type].no_video) {
4070 bttv_register_video(btv);
4071 bt848_bright(btv,32768);
4072 bt848_contrast(btv,32768);
4073 bt848_hue(btv,32768);
4074 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004075 audio_mute(btv, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 set_input(btv,0);
4077 }
4078
4079 /* add subdevices */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 if (bttv_tvcards[btv->c.type].has_dvb)
4081 bttv_sub_add_device(&btv->c, "dvb");
4082
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004083 bttv_input_init(btv);
4084
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 /* everything is fine */
4086 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004087 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088
4089 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004090 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
4092 fail1:
4093 if (btv->bt848_mmio)
4094 iounmap(btv->bt848_mmio);
4095 release_mem_region(pci_resource_start(btv->c.pci,0),
4096 pci_resource_len(btv->c.pci,0));
4097 pci_set_drvdata(dev,NULL);
4098 return result;
4099}
4100
4101static void __devexit bttv_remove(struct pci_dev *pci_dev)
4102{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004103 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
4105 if (bttv_verbose)
4106 printk("bttv%d: unloading\n",btv->c.nr);
4107
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004108 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 btand(~15, BT848_GPIO_DMA_CTL);
4110 btwrite(0, BT848_INT_MASK);
4111 btwrite(~0x0, BT848_INT_STAT);
4112 btwrite(0x0, BT848_GPIO_OUT_EN);
4113 if (bttv_gpio)
4114 bttv_gpio_tracking(btv,"cleanup");
4115
4116 /* tell gpio modules we are leaving ... */
4117 btv->shutdown=1;
4118 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004119 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004120 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004122 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 fini_bttv_i2c(btv);
4124
4125 /* unregister video4linux */
4126 bttv_unregister_video(btv);
4127
4128 /* free allocated memory */
4129 btcx_riscmem_free(btv->c.pci,&btv->main);
4130
4131 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004132 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004134 release_mem_region(pci_resource_start(btv->c.pci,0),
4135 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136
4137 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004138 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139}
4140
4141static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4142{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004143 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 struct bttv_buffer_set idle;
4145 unsigned long flags;
4146
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004147 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148
4149 /* stop dma + irqs */
4150 spin_lock_irqsave(&btv->s_lock,flags);
4151 memset(&idle, 0, sizeof(idle));
4152 btv->state.video = btv->curr;
4153 btv->state.vbi = btv->cvbi;
4154 btv->state.loop_irq = btv->loop_irq;
4155 btv->curr = idle;
4156 btv->loop_irq = 0;
4157 bttv_buffer_activate_video(btv, &idle);
4158 bttv_buffer_activate_vbi(btv, NULL);
4159 bttv_set_dma(btv, 0);
4160 btwrite(0, BT848_INT_MASK);
4161 spin_unlock_irqrestore(&btv->s_lock,flags);
4162
4163 /* save bt878 state */
4164 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4165 btv->state.gpio_data = gpio_read();
4166
4167 /* save pci state */
4168 pci_save_state(pci_dev);
4169 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4170 pci_disable_device(pci_dev);
4171 btv->state.disabled = 1;
4172 }
4173 return 0;
4174}
4175
4176static int bttv_resume(struct pci_dev *pci_dev)
4177{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004178 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004180 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181
4182 dprintk("bttv%d: resume\n", btv->c.nr);
4183
4184 /* restore pci state */
4185 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004186 err=pci_enable_device(pci_dev);
4187 if (err) {
4188 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4189 btv->c.nr);
4190 return err;
4191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 btv->state.disabled = 0;
4193 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004194 err=pci_set_power_state(pci_dev, PCI_D0);
4195 if (err) {
4196 pci_disable_device(pci_dev);
4197 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4198 btv->c.nr);
4199 btv->state.disabled = 1;
4200 return err;
4201 }
4202
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 pci_restore_state(pci_dev);
4204
4205 /* restore bt878 state */
4206 bttv_reinit_bt848(btv);
4207 gpio_inout(0xffffff, btv->state.gpio_enable);
4208 gpio_write(btv->state.gpio_data);
4209
4210 /* restart dma */
4211 spin_lock_irqsave(&btv->s_lock,flags);
4212 btv->curr = btv->state.video;
4213 btv->cvbi = btv->state.vbi;
4214 btv->loop_irq = btv->state.loop_irq;
4215 bttv_buffer_activate_video(btv, &btv->curr);
4216 bttv_buffer_activate_vbi(btv, btv->cvbi);
4217 bttv_set_dma(btv, 0);
4218 spin_unlock_irqrestore(&btv->s_lock,flags);
4219 return 0;
4220}
4221
4222static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004223 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4224 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004226 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004228 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004230 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4231 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232};
4233
4234MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4235
4236static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004237 .name = "bttv",
4238 .id_table = bttv_pci_tbl,
4239 .probe = bttv_probe,
4240 .remove = __devexit_p(bttv_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 .suspend = bttv_suspend,
4242 .resume = bttv_resume,
4243};
4244
4245static int bttv_init_module(void)
4246{
4247 bttv_num = 0;
4248
4249 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4250 (BTTV_VERSION_CODE >> 16) & 0xff,
4251 (BTTV_VERSION_CODE >> 8) & 0xff,
4252 BTTV_VERSION_CODE & 0xff);
4253#ifdef SNAPSHOT
4254 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4255 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4256#endif
4257 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4258 gbuffers = 2;
4259 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4260 gbufsize = BTTV_MAX_FBUF;
4261 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4262 if (bttv_verbose)
4263 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4264 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4265
4266 bttv_check_chipset();
4267
4268 bus_register(&bttv_sub_bus_type);
Otavio Salvador23047592006-01-09 15:25:17 -02004269 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270}
4271
4272static void bttv_cleanup_module(void)
4273{
4274 pci_unregister_driver(&bttv_pci_driver);
4275 bus_unregister(&bttv_sub_bus_type);
4276 return;
4277}
4278
4279module_init(bttv_init_module);
4280module_exit(bttv_cleanup_module);
4281
4282/*
4283 * Local variables:
4284 * c-basic-offset: 8
4285 * End:
4286 */