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