blob: 3e5c50ac9139dfd2ca030b9563d9ed30335beb62 [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
Michael Schimeke5bd0262007-01-18 16:17:39 -030012 Cropping and overscan support
13 Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
14 Sponsored by OPQ Systems AB
15
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29*/
30
31#include <linux/init.h>
32#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/delay.h>
34#include <linux/errno.h>
35#include <linux/fs.h>
36#include <linux/kernel.h>
37#include <linux/sched.h>
38#include <linux/interrupt.h>
39#include <linux/kdev_t.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020040#include "bttvp.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020041#include <media/v4l2-common.h>
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -030042#include <media/tvaudio.h>
Hans Verkuil2474ed42006-03-19 12:35:57 -030043#include <media/msp3400.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020044
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -070045#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#include <asm/io.h>
48#include <asm/byteorder.h>
49
Mauro Carvalho Chehabfa3fcce2006-03-23 21:45:24 -030050#include <media/rds.h>
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070051
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053unsigned int bttv_num; /* number of Bt848s in use */
54struct bttv bttvs[BTTV_MAX];
55
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020056unsigned int bttv_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057unsigned int bttv_verbose = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020058unsigned int bttv_gpio;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
60/* config variables */
61#ifdef __BIG_ENDIAN
62static unsigned int bigendian=1;
63#else
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020064static unsigned int bigendian;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#endif
66static unsigned int radio[BTTV_MAX];
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020067static unsigned int irq_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static unsigned int gbuffers = 8;
69static unsigned int gbufsize = 0x208000;
Michael Schimeke5bd0262007-01-18 16:17:39 -030070static unsigned int reset_crop = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72static int video_nr = -1;
73static int radio_nr = -1;
74static int vbi_nr = -1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020075static int debug_latency;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020077static unsigned int fdsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79/* options */
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020080static unsigned int combfilter;
81static unsigned int lumafilter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static unsigned int automute = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020083static unsigned int chroma_agc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084static unsigned int adc_crush = 1;
85static unsigned int whitecrush_upper = 0xCF;
86static unsigned int whitecrush_lower = 0x7F;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020087static unsigned int vcr_hack;
88static unsigned int irq_iswitch;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070089static unsigned int uv_ratio = 50;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020090static unsigned int full_luma_range;
91static unsigned int coring;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070092extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94/* API features (turn on/off stuff for testing) */
95static unsigned int v4l2 = 1;
96
Linus Torvalds1da177e2005-04-16 15:20:36 -070097/* insmod args */
98module_param(bttv_verbose, int, 0644);
99module_param(bttv_gpio, int, 0644);
100module_param(bttv_debug, int, 0644);
101module_param(irq_debug, int, 0644);
102module_param(debug_latency, int, 0644);
103
104module_param(fdsr, int, 0444);
105module_param(video_nr, int, 0444);
106module_param(radio_nr, int, 0444);
107module_param(vbi_nr, int, 0444);
108module_param(gbuffers, int, 0444);
109module_param(gbufsize, int, 0444);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300110module_param(reset_crop, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112module_param(v4l2, int, 0644);
113module_param(bigendian, int, 0644);
114module_param(irq_iswitch, int, 0644);
115module_param(combfilter, int, 0444);
116module_param(lumafilter, int, 0444);
117module_param(automute, int, 0444);
118module_param(chroma_agc, int, 0444);
119module_param(adc_crush, int, 0444);
120module_param(whitecrush_upper, int, 0444);
121module_param(whitecrush_lower, int, 0444);
122module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700123module_param(uv_ratio, int, 0444);
124module_param(full_luma_range, int, 0444);
125module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127module_param_array(radio, int, NULL, 0444);
128
129MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
130MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
131MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
132MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
133MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
134MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
135MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
136MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
Michael Schimeke5bd0262007-01-18 16:17:39 -0300137MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
138 "is 1 (yes) for compatibility with older applications");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
140MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
141MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
142MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
143MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
144MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
145MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700146MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
147MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
148MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
151MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
152MODULE_LICENSE("GPL");
153
154/* ----------------------------------------------------------------------- */
155/* sysfs */
156
Kay Sievers54bd5b62007-10-08 16:26:13 -0300157static ssize_t show_card(struct device *cd,
158 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
160 struct video_device *vfd = to_video_device(cd);
161 struct bttv *btv = dev_get_drvdata(vfd->dev);
162 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
163}
Kay Sievers54bd5b62007-10-08 16:26:13 -0300164static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166/* ----------------------------------------------------------------------- */
Jarod Wilsonf992a492007-03-24 15:23:50 -0300167/* dvb auto-load setup */
168#if defined(CONFIG_MODULES) && defined(MODULE)
169static void request_module_async(struct work_struct *work)
170{
171 request_module("dvb-bt8xx");
172}
173
174static void request_modules(struct bttv *dev)
175{
176 INIT_WORK(&dev->request_module_wk, request_module_async);
177 schedule_work(&dev->request_module_wk);
178}
179#else
180#define request_modules(dev)
181#endif /* CONFIG_MODULES */
182
183
184/* ----------------------------------------------------------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185/* static data */
186
187/* special timing tables from conexant... */
188static u8 SRAM_Table[][60] =
189{
190 /* PAL digital input over GPIO[7:0] */
191 {
192 45, // 45 bytes following
193 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
194 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
195 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
196 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
197 0x37,0x00,0xAF,0x21,0x00
198 },
199 /* NTSC digital input over GPIO[7:0] */
200 {
201 51, // 51 bytes following
202 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
203 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
204 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
205 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
206 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
207 0x00,
208 },
209 // TGB_NTSC392 // quartzsight
210 // This table has been modified to be used for Fusion Rev D
211 {
212 0x2A, // size of table = 42
213 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
214 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
215 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
216 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
217 0x20, 0x00
218 }
219};
220
Michael Schimeke5bd0262007-01-18 16:17:39 -0300221/* minhdelayx1 first video pixel we can capture on a line and
222 hdelayx1 start of active video, both relative to rising edge of
223 /HRESET pulse (0H) in 1 / fCLKx1.
224 swidth width of active video and
225 totalwidth total line width, both in 1 / fCLKx1.
226 sqwidth total line width in square pixels.
227 vdelay start of active video in 2 * field lines relative to
228 trailing edge of /VRESET pulse (VDELAY register).
229 sheight height of active video in 2 * field lines.
230 videostart0 ITU-R frame line number of the line corresponding
231 to vdelay in the first field. */
232#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
233 vdelay, sheight, videostart0) \
234 .cropcap.bounds.left = minhdelayx1, \
235 /* * 2 because vertically we count field lines times two, */ \
236 /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
237 .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
238 /* 4 is a safety margin at the end of the line. */ \
239 .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
240 .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
241 .cropcap.defrect.left = hdelayx1, \
242 .cropcap.defrect.top = (videostart0) * 2, \
243 .cropcap.defrect.width = swidth, \
244 .cropcap.defrect.height = sheight, \
245 .cropcap.pixelaspect.numerator = totalwidth, \
246 .cropcap.pixelaspect.denominator = sqwidth,
247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248const struct bttv_tvnorm bttv_tvnorms[] = {
249 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800250 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
251 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 {
253 .v4l2_id = V4L2_STD_PAL,
254 .name = "PAL",
255 .Fsc = 35468950,
256 .swidth = 924,
257 .sheight = 576,
258 .totalwidth = 1135,
259 .adelay = 0x7f,
260 .bdelay = 0x72,
261 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
262 .scaledtwidth = 1135,
263 .hdelayx1 = 186,
264 .hactivex1 = 924,
265 .vdelay = 0x20,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300266 .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200268 /* ITU-R frame line number of the first VBI line
Michael Schimeke5bd0262007-01-18 16:17:39 -0300269 we can capture, of the first and second field.
270 The last line is determined by cropcap.bounds. */
271 .vbistart = { 7, 320 },
272 CROPCAP(/* minhdelayx1 */ 68,
273 /* hdelayx1 */ 186,
274 /* Should be (768 * 1135 + 944 / 2) / 944.
275 cropcap.defrect is used for image width
276 checks, so we keep the old value 924. */
277 /* swidth */ 924,
278 /* totalwidth */ 1135,
279 /* sqwidth */ 944,
280 /* vdelay */ 0x20,
281 /* sheight */ 576,
282 /* videostart0 */ 23)
283 /* bt878 (and bt848?) can capture another
284 line below active video. */
285 .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 },{
Hans Verkuild97a11e2006-02-07 06:48:40 -0200287 .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 .name = "NTSC",
289 .Fsc = 28636363,
290 .swidth = 768,
291 .sheight = 480,
292 .totalwidth = 910,
293 .adelay = 0x68,
294 .bdelay = 0x5d,
295 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
296 .scaledtwidth = 910,
297 .hdelayx1 = 128,
298 .hactivex1 = 910,
299 .vdelay = 0x1a,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300300 .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200302 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300303 CROPCAP(/* minhdelayx1 */ 68,
304 /* hdelayx1 */ 128,
305 /* Should be (640 * 910 + 780 / 2) / 780? */
306 /* swidth */ 768,
307 /* totalwidth */ 910,
308 /* sqwidth */ 780,
309 /* vdelay */ 0x1a,
310 /* sheight */ 480,
311 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 },{
313 .v4l2_id = V4L2_STD_SECAM,
314 .name = "SECAM",
315 .Fsc = 35468950,
316 .swidth = 924,
317 .sheight = 576,
318 .totalwidth = 1135,
319 .adelay = 0x7f,
320 .bdelay = 0xb0,
321 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
322 .scaledtwidth = 1135,
323 .hdelayx1 = 186,
324 .hactivex1 = 922,
325 .vdelay = 0x20,
326 .vbipack = 255,
327 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200328 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300329 CROPCAP(/* minhdelayx1 */ 68,
330 /* hdelayx1 */ 186,
331 /* swidth */ 924,
332 /* totalwidth */ 1135,
333 /* sqwidth */ 944,
334 /* vdelay */ 0x20,
335 /* sheight */ 576,
336 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 },{
338 .v4l2_id = V4L2_STD_PAL_Nc,
339 .name = "PAL-Nc",
340 .Fsc = 28636363,
341 .swidth = 640,
342 .sheight = 576,
343 .totalwidth = 910,
344 .adelay = 0x68,
345 .bdelay = 0x5d,
346 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
347 .scaledtwidth = 780,
348 .hdelayx1 = 130,
349 .hactivex1 = 734,
350 .vdelay = 0x1a,
351 .vbipack = 144,
352 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200353 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300354 CROPCAP(/* minhdelayx1 */ 68,
355 /* hdelayx1 */ 130,
356 /* swidth */ (640 * 910 + 780 / 2) / 780,
357 /* totalwidth */ 910,
358 /* sqwidth */ 780,
359 /* vdelay */ 0x1a,
360 /* sheight */ 576,
361 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 },{
363 .v4l2_id = V4L2_STD_PAL_M,
364 .name = "PAL-M",
365 .Fsc = 28636363,
366 .swidth = 640,
367 .sheight = 480,
368 .totalwidth = 910,
369 .adelay = 0x68,
370 .bdelay = 0x5d,
371 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
372 .scaledtwidth = 780,
373 .hdelayx1 = 135,
374 .hactivex1 = 754,
375 .vdelay = 0x1a,
376 .vbipack = 144,
377 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200378 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300379 CROPCAP(/* minhdelayx1 */ 68,
380 /* hdelayx1 */ 135,
381 /* swidth */ (640 * 910 + 780 / 2) / 780,
382 /* totalwidth */ 910,
383 /* sqwidth */ 780,
384 /* vdelay */ 0x1a,
385 /* sheight */ 480,
386 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 },{
388 .v4l2_id = V4L2_STD_PAL_N,
389 .name = "PAL-N",
390 .Fsc = 35468950,
391 .swidth = 768,
392 .sheight = 576,
393 .totalwidth = 1135,
394 .adelay = 0x7f,
395 .bdelay = 0x72,
396 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
397 .scaledtwidth = 944,
398 .hdelayx1 = 186,
399 .hactivex1 = 922,
400 .vdelay = 0x20,
401 .vbipack = 144,
402 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300403 .vbistart = { 7, 320 },
404 CROPCAP(/* minhdelayx1 */ 68,
405 /* hdelayx1 */ 186,
406 /* swidth */ (768 * 1135 + 944 / 2) / 944,
407 /* totalwidth */ 1135,
408 /* sqwidth */ 944,
409 /* vdelay */ 0x20,
410 /* sheight */ 576,
411 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 },{
413 .v4l2_id = V4L2_STD_NTSC_M_JP,
414 .name = "NTSC-JP",
415 .Fsc = 28636363,
416 .swidth = 640,
417 .sheight = 480,
418 .totalwidth = 910,
419 .adelay = 0x68,
420 .bdelay = 0x5d,
421 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
422 .scaledtwidth = 780,
423 .hdelayx1 = 135,
424 .hactivex1 = 754,
425 .vdelay = 0x16,
426 .vbipack = 144,
427 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300428 .vbistart = { 10, 273 },
429 CROPCAP(/* minhdelayx1 */ 68,
430 /* hdelayx1 */ 135,
431 /* swidth */ (640 * 910 + 780 / 2) / 780,
432 /* totalwidth */ 910,
433 /* sqwidth */ 780,
434 /* vdelay */ 0x16,
435 /* sheight */ 480,
436 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 },{
438 /* that one hopefully works with the strange timing
439 * which video recorders produce when playing a NTSC
440 * tape on a PAL TV ... */
441 .v4l2_id = V4L2_STD_PAL_60,
442 .name = "PAL-60",
443 .Fsc = 35468950,
444 .swidth = 924,
445 .sheight = 480,
446 .totalwidth = 1135,
447 .adelay = 0x7f,
448 .bdelay = 0x72,
449 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
450 .scaledtwidth = 1135,
451 .hdelayx1 = 186,
452 .hactivex1 = 924,
453 .vdelay = 0x1a,
454 .vbipack = 255,
455 .vtotal = 524,
456 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200457 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300458 CROPCAP(/* minhdelayx1 */ 68,
459 /* hdelayx1 */ 186,
460 /* swidth */ 924,
461 /* totalwidth */ 1135,
462 /* sqwidth */ 944,
463 /* vdelay */ 0x1a,
464 /* sheight */ 480,
465 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 }
467};
468static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
469
470/* ----------------------------------------------------------------------- */
471/* bttv format list
472 packed pixel formats must come first */
473static const struct bttv_format bttv_formats[] = {
474 {
475 .name = "8 bpp, gray",
476 .palette = VIDEO_PALETTE_GREY,
477 .fourcc = V4L2_PIX_FMT_GREY,
478 .btformat = BT848_COLOR_FMT_Y8,
479 .depth = 8,
480 .flags = FORMAT_FLAGS_PACKED,
481 },{
482 .name = "8 bpp, dithered color",
483 .palette = VIDEO_PALETTE_HI240,
484 .fourcc = V4L2_PIX_FMT_HI240,
485 .btformat = BT848_COLOR_FMT_RGB8,
486 .depth = 8,
487 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
488 },{
489 .name = "15 bpp RGB, le",
490 .palette = VIDEO_PALETTE_RGB555,
491 .fourcc = V4L2_PIX_FMT_RGB555,
492 .btformat = BT848_COLOR_FMT_RGB15,
493 .depth = 16,
494 .flags = FORMAT_FLAGS_PACKED,
495 },{
496 .name = "15 bpp RGB, be",
497 .palette = -1,
498 .fourcc = V4L2_PIX_FMT_RGB555X,
499 .btformat = BT848_COLOR_FMT_RGB15,
500 .btswap = 0x03, /* byteswap */
501 .depth = 16,
502 .flags = FORMAT_FLAGS_PACKED,
503 },{
504 .name = "16 bpp RGB, le",
505 .palette = VIDEO_PALETTE_RGB565,
506 .fourcc = V4L2_PIX_FMT_RGB565,
507 .btformat = BT848_COLOR_FMT_RGB16,
508 .depth = 16,
509 .flags = FORMAT_FLAGS_PACKED,
510 },{
511 .name = "16 bpp RGB, be",
512 .palette = -1,
513 .fourcc = V4L2_PIX_FMT_RGB565X,
514 .btformat = BT848_COLOR_FMT_RGB16,
515 .btswap = 0x03, /* byteswap */
516 .depth = 16,
517 .flags = FORMAT_FLAGS_PACKED,
518 },{
519 .name = "24 bpp RGB, le",
520 .palette = VIDEO_PALETTE_RGB24,
521 .fourcc = V4L2_PIX_FMT_BGR24,
522 .btformat = BT848_COLOR_FMT_RGB24,
523 .depth = 24,
524 .flags = FORMAT_FLAGS_PACKED,
525 },{
526 .name = "32 bpp RGB, le",
527 .palette = VIDEO_PALETTE_RGB32,
528 .fourcc = V4L2_PIX_FMT_BGR32,
529 .btformat = BT848_COLOR_FMT_RGB32,
530 .depth = 32,
531 .flags = FORMAT_FLAGS_PACKED,
532 },{
533 .name = "32 bpp RGB, be",
534 .palette = -1,
535 .fourcc = V4L2_PIX_FMT_RGB32,
536 .btformat = BT848_COLOR_FMT_RGB32,
537 .btswap = 0x0f, /* byte+word swap */
538 .depth = 32,
539 .flags = FORMAT_FLAGS_PACKED,
540 },{
541 .name = "4:2:2, packed, YUYV",
542 .palette = VIDEO_PALETTE_YUV422,
543 .fourcc = V4L2_PIX_FMT_YUYV,
544 .btformat = BT848_COLOR_FMT_YUY2,
545 .depth = 16,
546 .flags = FORMAT_FLAGS_PACKED,
547 },{
548 .name = "4:2:2, packed, YUYV",
549 .palette = VIDEO_PALETTE_YUYV,
550 .fourcc = V4L2_PIX_FMT_YUYV,
551 .btformat = BT848_COLOR_FMT_YUY2,
552 .depth = 16,
553 .flags = FORMAT_FLAGS_PACKED,
554 },{
555 .name = "4:2:2, packed, UYVY",
556 .palette = VIDEO_PALETTE_UYVY,
557 .fourcc = V4L2_PIX_FMT_UYVY,
558 .btformat = BT848_COLOR_FMT_YUY2,
559 .btswap = 0x03, /* byteswap */
560 .depth = 16,
561 .flags = FORMAT_FLAGS_PACKED,
562 },{
563 .name = "4:2:2, planar, Y-Cb-Cr",
564 .palette = VIDEO_PALETTE_YUV422P,
565 .fourcc = V4L2_PIX_FMT_YUV422P,
566 .btformat = BT848_COLOR_FMT_YCrCb422,
567 .depth = 16,
568 .flags = FORMAT_FLAGS_PLANAR,
569 .hshift = 1,
570 .vshift = 0,
571 },{
572 .name = "4:2:0, planar, Y-Cb-Cr",
573 .palette = VIDEO_PALETTE_YUV420P,
574 .fourcc = V4L2_PIX_FMT_YUV420,
575 .btformat = BT848_COLOR_FMT_YCrCb422,
576 .depth = 12,
577 .flags = FORMAT_FLAGS_PLANAR,
578 .hshift = 1,
579 .vshift = 1,
580 },{
581 .name = "4:2:0, planar, Y-Cr-Cb",
582 .palette = -1,
583 .fourcc = V4L2_PIX_FMT_YVU420,
584 .btformat = BT848_COLOR_FMT_YCrCb422,
585 .depth = 12,
586 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
587 .hshift = 1,
588 .vshift = 1,
589 },{
590 .name = "4:1:1, planar, Y-Cb-Cr",
591 .palette = VIDEO_PALETTE_YUV411P,
592 .fourcc = V4L2_PIX_FMT_YUV411P,
593 .btformat = BT848_COLOR_FMT_YCrCb411,
594 .depth = 12,
595 .flags = FORMAT_FLAGS_PLANAR,
596 .hshift = 2,
597 .vshift = 0,
598 },{
599 .name = "4:1:0, planar, Y-Cb-Cr",
600 .palette = VIDEO_PALETTE_YUV410P,
601 .fourcc = V4L2_PIX_FMT_YUV410,
602 .btformat = BT848_COLOR_FMT_YCrCb411,
603 .depth = 9,
604 .flags = FORMAT_FLAGS_PLANAR,
605 .hshift = 2,
606 .vshift = 2,
607 },{
608 .name = "4:1:0, planar, Y-Cr-Cb",
609 .palette = -1,
610 .fourcc = V4L2_PIX_FMT_YVU410,
611 .btformat = BT848_COLOR_FMT_YCrCb411,
612 .depth = 9,
613 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
614 .hshift = 2,
615 .vshift = 2,
616 },{
617 .name = "raw scanlines",
618 .palette = VIDEO_PALETTE_RAW,
619 .fourcc = -1,
620 .btformat = BT848_COLOR_FMT_RAW,
621 .depth = 8,
622 .flags = FORMAT_FLAGS_RAW,
623 }
624};
625static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
626
627/* ----------------------------------------------------------------------- */
628
629#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
630#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
631#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
632#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
633#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
634#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
635#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
636#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700637#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
638#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
639#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
640#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642static const struct v4l2_queryctrl no_ctl = {
643 .name = "42",
644 .flags = V4L2_CTRL_FLAG_DISABLED,
645};
646static const struct v4l2_queryctrl bttv_ctls[] = {
647 /* --- video --- */
648 {
649 .id = V4L2_CID_BRIGHTNESS,
650 .name = "Brightness",
651 .minimum = 0,
652 .maximum = 65535,
653 .step = 256,
654 .default_value = 32768,
655 .type = V4L2_CTRL_TYPE_INTEGER,
656 },{
657 .id = V4L2_CID_CONTRAST,
658 .name = "Contrast",
659 .minimum = 0,
660 .maximum = 65535,
661 .step = 128,
662 .default_value = 32768,
663 .type = V4L2_CTRL_TYPE_INTEGER,
664 },{
665 .id = V4L2_CID_SATURATION,
666 .name = "Saturation",
667 .minimum = 0,
668 .maximum = 65535,
669 .step = 128,
670 .default_value = 32768,
671 .type = V4L2_CTRL_TYPE_INTEGER,
672 },{
673 .id = V4L2_CID_HUE,
674 .name = "Hue",
675 .minimum = 0,
676 .maximum = 65535,
677 .step = 256,
678 .default_value = 32768,
679 .type = V4L2_CTRL_TYPE_INTEGER,
680 },
681 /* --- audio --- */
682 {
683 .id = V4L2_CID_AUDIO_MUTE,
684 .name = "Mute",
685 .minimum = 0,
686 .maximum = 1,
687 .type = V4L2_CTRL_TYPE_BOOLEAN,
688 },{
689 .id = V4L2_CID_AUDIO_VOLUME,
690 .name = "Volume",
691 .minimum = 0,
692 .maximum = 65535,
693 .step = 65535/100,
694 .default_value = 65535,
695 .type = V4L2_CTRL_TYPE_INTEGER,
696 },{
697 .id = V4L2_CID_AUDIO_BALANCE,
698 .name = "Balance",
699 .minimum = 0,
700 .maximum = 65535,
701 .step = 65535/100,
702 .default_value = 32768,
703 .type = V4L2_CTRL_TYPE_INTEGER,
704 },{
705 .id = V4L2_CID_AUDIO_BASS,
706 .name = "Bass",
707 .minimum = 0,
708 .maximum = 65535,
709 .step = 65535/100,
710 .default_value = 32768,
711 .type = V4L2_CTRL_TYPE_INTEGER,
712 },{
713 .id = V4L2_CID_AUDIO_TREBLE,
714 .name = "Treble",
715 .minimum = 0,
716 .maximum = 65535,
717 .step = 65535/100,
718 .default_value = 32768,
719 .type = V4L2_CTRL_TYPE_INTEGER,
720 },
721 /* --- private --- */
722 {
723 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
724 .name = "chroma agc",
725 .minimum = 0,
726 .maximum = 1,
727 .type = V4L2_CTRL_TYPE_BOOLEAN,
728 },{
729 .id = V4L2_CID_PRIVATE_COMBFILTER,
730 .name = "combfilter",
731 .minimum = 0,
732 .maximum = 1,
733 .type = V4L2_CTRL_TYPE_BOOLEAN,
734 },{
735 .id = V4L2_CID_PRIVATE_AUTOMUTE,
736 .name = "automute",
737 .minimum = 0,
738 .maximum = 1,
739 .type = V4L2_CTRL_TYPE_BOOLEAN,
740 },{
741 .id = V4L2_CID_PRIVATE_LUMAFILTER,
742 .name = "luma decimation filter",
743 .minimum = 0,
744 .maximum = 1,
745 .type = V4L2_CTRL_TYPE_BOOLEAN,
746 },{
747 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
748 .name = "agc crush",
749 .minimum = 0,
750 .maximum = 1,
751 .type = V4L2_CTRL_TYPE_BOOLEAN,
752 },{
753 .id = V4L2_CID_PRIVATE_VCR_HACK,
754 .name = "vcr hack",
755 .minimum = 0,
756 .maximum = 1,
757 .type = V4L2_CTRL_TYPE_BOOLEAN,
758 },{
759 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
760 .name = "whitecrush upper",
761 .minimum = 0,
762 .maximum = 255,
763 .step = 1,
764 .default_value = 0xCF,
765 .type = V4L2_CTRL_TYPE_INTEGER,
766 },{
767 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
768 .name = "whitecrush lower",
769 .minimum = 0,
770 .maximum = 255,
771 .step = 1,
772 .default_value = 0x7F,
773 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700774 },{
775 .id = V4L2_CID_PRIVATE_UV_RATIO,
776 .name = "uv ratio",
777 .minimum = 0,
778 .maximum = 100,
779 .step = 1,
780 .default_value = 50,
781 .type = V4L2_CTRL_TYPE_INTEGER,
782 },{
783 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
784 .name = "full luma range",
785 .minimum = 0,
786 .maximum = 1,
787 .type = V4L2_CTRL_TYPE_BOOLEAN,
788 },{
789 .id = V4L2_CID_PRIVATE_CORING,
790 .name = "coring",
791 .minimum = 0,
792 .maximum = 3,
793 .step = 1,
794 .default_value = 0,
795 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 }
797
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700798
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800};
801static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
802
803/* ----------------------------------------------------------------------- */
804/* resource management */
805
Michael Schimeke5bd0262007-01-18 16:17:39 -0300806/*
807 RESOURCE_ allocated by freed by
808
809 VIDEO_READ bttv_read 1) bttv_read 2)
810
811 VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
812 VIDIOC_QBUF 1) bttv_release
813 VIDIOCMCAPTURE 1)
814
815 OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
816 VIDIOC_OVERLAY on VIDIOC_OVERLAY off
817 3) bttv_release
818
819 VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
820 VIDIOC_QBUF 1) bttv_release
821 bttv_read, bttv_poll 1) 4)
822
823 1) The resource must be allocated when we enter buffer prepare functions
824 and remain allocated while buffers are in the DMA queue.
825 2) This is a single frame read.
826 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
827 RESOURCE_OVERLAY is allocated.
828 4) This is a continuous read, implies VIDIOC_STREAMON.
829
830 Note this driver permits video input and standard changes regardless if
831 resources are allocated.
832*/
833
834#define VBI_RESOURCES (RESOURCE_VBI)
835#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
836 RESOURCE_VIDEO_STREAM | \
837 RESOURCE_OVERLAY)
838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839static
840int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
841{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300842 int xbits; /* mutual exclusive resources */
843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 if (fh->resources & bit)
845 /* have it already allocated */
846 return 1;
847
Michael Schimeke5bd0262007-01-18 16:17:39 -0300848 xbits = bit;
849 if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
850 xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
851
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 /* is it free? */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300853 mutex_lock(&btv->lock);
854 if (btv->resources & xbits) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /* no, someone else uses it */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300856 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300858
859 if ((bit & VIDEO_RESOURCES)
860 && 0 == (btv->resources & VIDEO_RESOURCES)) {
861 /* Do crop - use current, don't - use default parameters. */
862 __s32 top = btv->crop[!!fh->do_crop].rect.top;
863
864 if (btv->vbi_end > top)
865 goto fail;
866
867 /* We cannot capture the same line as video and VBI data.
868 Claim scan lines crop[].rect.top to bottom. */
869 btv->crop_start = top;
870 } else if (bit & VBI_RESOURCES) {
871 __s32 end = fh->vbi_fmt.end;
872
873 if (end > btv->crop_start)
874 goto fail;
875
876 /* Claim scan lines above fh->vbi_fmt.end. */
877 btv->vbi_end = end;
878 }
879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 /* it's free, grab it */
881 fh->resources |= bit;
882 btv->resources |= bit;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300883 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return 1;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300885
886 fail:
887 mutex_unlock(&btv->lock);
888 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889}
890
891static
892int check_btres(struct bttv_fh *fh, int bit)
893{
894 return (fh->resources & bit);
895}
896
897static
898int locked_btres(struct bttv *btv, int bit)
899{
900 return (btv->resources & bit);
901}
902
Michael Schimeke5bd0262007-01-18 16:17:39 -0300903/* Call with btv->lock down. */
904static void
905disclaim_vbi_lines(struct bttv *btv)
906{
907 btv->vbi_end = 0;
908}
909
910/* Call with btv->lock down. */
911static void
912disclaim_video_lines(struct bttv *btv)
913{
914 const struct bttv_tvnorm *tvnorm;
915 u8 crop;
916
917 tvnorm = &bttv_tvnorms[btv->tvnorm];
918 btv->crop_start = tvnorm->cropcap.bounds.top
919 + tvnorm->cropcap.bounds.height;
920
921 /* VBI capturing ends at VDELAY, start of video capturing, no
922 matter how many lines the VBI RISC program expects. When video
923 capturing is off, it shall no longer "preempt" VBI capturing,
924 so we set VDELAY to maximum. */
925 crop = btread(BT848_E_CROP) | 0xc0;
926 btwrite(crop, BT848_E_CROP);
927 btwrite(0xfe, BT848_E_VDELAY_LO);
928 btwrite(crop, BT848_O_CROP);
929 btwrite(0xfe, BT848_O_VDELAY_LO);
930}
931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932static
933void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
934{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 if ((fh->resources & bits) != bits) {
936 /* trying to free ressources not allocated by us ... */
937 printk("bttv: BUG! (btres)\n");
938 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300939 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 fh->resources &= ~bits;
941 btv->resources &= ~bits;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300942
943 bits = btv->resources;
944
945 if (0 == (bits & VIDEO_RESOURCES))
946 disclaim_video_lines(btv);
947
948 if (0 == (bits & VBI_RESOURCES))
949 disclaim_vbi_lines(btv);
950
951 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952}
953
954/* ----------------------------------------------------------------------- */
955/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
956
957/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
958 PLL_X = Reference pre-divider (0=1, 1=2)
959 PLL_C = Post divider (0=6, 1=4)
960 PLL_I = Integer input
961 PLL_F = Fractional input
962
963 F_input = 28.636363 MHz:
964 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
965*/
966
967static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
968{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800969 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800971 /* prevent overflows */
972 fin/=4;
973 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800975 fout*=12;
976 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800978 fout=(fout%fin)*256;
979 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800981 fout=(fout%fin)*256;
982 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800984 btwrite(fl, BT848_PLL_F_LO);
985 btwrite(fh, BT848_PLL_F_HI);
986 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987}
988
989static void set_pll(struct bttv *btv)
990{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800991 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800993 if (!btv->pll.pll_crystal)
994 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
997 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800998 return;
999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001001 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
1002 /* no PLL needed */
1003 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001004 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001005 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001006 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001007 btwrite(0x00,BT848_TGCTRL);
1008 btwrite(0x00,BT848_PLL_XCI);
1009 btv->pll.pll_current = 0;
1010 return;
1011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001013 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001014 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
1016
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001017 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001019 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 msleep(10);
1021
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001022 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001024 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001025 btwrite(0x08,BT848_TGCTRL);
1026 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001027 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001028 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001029 }
1030 }
1031 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001032 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001033 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034}
1035
1036/* used to switch between the bt848's analog/digital video capture modes */
1037static void bt848A_set_timing(struct bttv *btv)
1038{
1039 int i, len;
1040 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
1041 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
1042
1043 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
1044 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
1045 btv->c.nr,table_idx);
1046
1047 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001048 btwrite(0x00, BT848_TGCTRL);
1049 btwrite(0x02, BT848_TGCTRL);
1050 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052 len=SRAM_Table[table_idx][0];
1053 for(i = 1; i <= len; i++)
1054 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
1055 btv->pll.pll_ofreq = 27000000;
1056
1057 set_pll(btv);
1058 btwrite(0x11, BT848_TGCTRL);
1059 btwrite(0x41, BT848_DVSIF);
1060 } else {
1061 btv->pll.pll_ofreq = fsc;
1062 set_pll(btv);
1063 btwrite(0x0, BT848_DVSIF);
1064 }
1065}
1066
1067/* ----------------------------------------------------------------------- */
1068
1069static void bt848_bright(struct bttv *btv, int bright)
1070{
1071 int value;
1072
1073 // printk("bttv: set bright: %d\n",bright); // DEBUG
1074 btv->bright = bright;
1075
1076 /* We want -128 to 127 we get 0-65535 */
1077 value = (bright >> 8) - 128;
1078 btwrite(value & 0xff, BT848_BRIGHT);
1079}
1080
1081static void bt848_hue(struct bttv *btv, int hue)
1082{
1083 int value;
1084
1085 btv->hue = hue;
1086
1087 /* -128 to 127 */
1088 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001089 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090}
1091
1092static void bt848_contrast(struct bttv *btv, int cont)
1093{
1094 int value,hibit;
1095
1096 btv->contrast = cont;
1097
1098 /* 0-511 */
1099 value = (cont >> 7);
1100 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001101 btwrite(value & 0xff, BT848_CONTRAST_LO);
1102 btaor(hibit, ~4, BT848_E_CONTROL);
1103 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
1106static void bt848_sat(struct bttv *btv, int color)
1107{
1108 int val_u,val_v,hibits;
1109
1110 btv->saturation = color;
1111
1112 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001113 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
1114 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001115 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001117 btwrite(val_u & 0xff, BT848_SAT_U_LO);
1118 btwrite(val_v & 0xff, BT848_SAT_V_LO);
1119 btaor(hibits, ~3, BT848_E_CONTROL);
1120 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121}
1122
1123/* ----------------------------------------------------------------------- */
1124
1125static int
1126video_mux(struct bttv *btv, unsigned int input)
1127{
1128 int mux,mask2;
1129
1130 if (input >= bttv_tvcards[btv->c.type].video_inputs)
1131 return -EINVAL;
1132
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001133 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
1135 if (mask2)
1136 gpio_inout(mask2,mask2);
1137
1138 if (input == btv->svhs) {
1139 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
1140 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
1141 } else {
1142 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
1143 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
1144 }
1145 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
1146 btaor(mux<<5, ~(3<<5), BT848_IFORM);
1147 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
1148 btv->c.nr,input,mux);
1149
1150 /* card specific hook */
1151 if(bttv_tvcards[btv->c.type].muxsel_hook)
1152 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
1153 return 0;
1154}
1155
1156static char *audio_modes[] = {
1157 "audio: tuner", "audio: radio", "audio: extern",
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001158 "audio: intern", "audio: mute"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159};
1160
1161static int
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001162audio_mux(struct bttv *btv, int input, int mute)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163{
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001164 int gpio_val, signal;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001165 struct v4l2_control ctrl;
1166 struct i2c_client *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
1168 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
1169 bttv_tvcards[btv->c.type].gpiomask);
1170 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
1171
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001172 btv->mute = mute;
1173 btv->audio = input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001175 /* automute */
1176 mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
1177
1178 if (mute)
1179 gpio_val = bttv_tvcards[btv->c.type].gpiomute;
1180 else
1181 gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001182
1183 gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if (bttv_gpio)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001185 bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
1186 if (in_interrupt())
1187 return 0;
1188
1189 ctrl.id = V4L2_CID_AUDIO_MUTE;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001190 ctrl.value = btv->mute;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001191 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
1192 c = btv->i2c_msp34xx_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001193 if (c) {
1194 struct v4l2_routing route;
1195
1196 /* Note: the inputs tuner/radio/extern/intern are translated
1197 to msp routings. This assumes common behavior for all msp3400
1198 based TV cards. When this assumption fails, then the
1199 specific MSP routing must be added to the card table.
1200 For now this is sufficient. */
1201 switch (input) {
1202 case TVAUDIO_INPUT_RADIO:
Hans Verkuil07151722006-04-01 18:03:23 -03001203 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1204 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001205 break;
1206 case TVAUDIO_INPUT_EXTERN:
Hans Verkuil07151722006-04-01 18:03:23 -03001207 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
1208 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001209 break;
1210 case TVAUDIO_INPUT_INTERN:
1211 /* Yes, this is the same input as for RADIO. I doubt
1212 if this is ever used. The only board with an INTERN
1213 input is the BTTV_BOARD_AVERMEDIA98. I wonder how
1214 that was tested. My guess is that the whole INTERN
1215 input does not work. */
Hans Verkuil07151722006-04-01 18:03:23 -03001216 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1217 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001218 break;
1219 case TVAUDIO_INPUT_TUNER:
1220 default:
Wade Berrier434b2522007-06-25 13:02:16 -03001221 /* This is the only card that uses TUNER2, and afaik,
1222 is the only difference between the VOODOOTV_FM
1223 and VOODOOTV_200 */
1224 if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
1225 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
1226 MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
1227 else
1228 route.input = MSP_INPUT_DEFAULT;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001229 break;
1230 }
1231 route.output = MSP_OUTPUT_DEFAULT;
1232 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1233 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001234 c = btv->i2c_tvaudio_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001235 if (c) {
1236 struct v4l2_routing route;
1237
1238 route.input = input;
1239 route.output = 0;
1240 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 return 0;
1243}
1244
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001245static inline int
1246audio_mute(struct bttv *btv, int mute)
1247{
1248 return audio_mux(btv, btv->audio, mute);
1249}
1250
1251static inline int
1252audio_input(struct bttv *btv, int input)
1253{
1254 return audio_mux(btv, input, btv->mute);
1255}
1256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257static void
Michael Schimeke5bd0262007-01-18 16:17:39 -03001258bttv_crop_calc_limits(struct bttv_crop *c)
1259{
1260 /* Scale factor min. 1:1, max. 16:1. Min. image size
1261 48 x 32. Scaled width must be a multiple of 4. */
1262
1263 if (1) {
1264 /* For bug compatibility with VIDIOCGCAP and image
1265 size checks in earlier driver versions. */
1266 c->min_scaled_width = 48;
1267 c->min_scaled_height = 32;
1268 } else {
1269 c->min_scaled_width =
1270 (max(48, c->rect.width >> 4) + 3) & ~3;
1271 c->min_scaled_height =
1272 max(32, c->rect.height >> 4);
1273 }
1274
1275 c->max_scaled_width = c->rect.width & ~3;
1276 c->max_scaled_height = c->rect.height;
1277}
1278
1279static void
1280bttv_crop_reset(struct bttv_crop *c, int norm)
1281{
1282 c->rect = bttv_tvnorms[norm].cropcap.defrect;
1283 bttv_crop_calc_limits(c);
1284}
1285
1286/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287static int
1288set_tvnorm(struct bttv *btv, unsigned int norm)
1289{
1290 const struct bttv_tvnorm *tvnorm;
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001291 v4l2_std_id id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
1293 if (norm < 0 || norm >= BTTV_TVNORMS)
1294 return -EINVAL;
1295
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 tvnorm = &bttv_tvnorms[norm];
1297
Michael Schimeke5bd0262007-01-18 16:17:39 -03001298 if (btv->tvnorm < 0 ||
1299 btv->tvnorm >= BTTV_TVNORMS ||
1300 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
1301 &tvnorm->cropcap,
1302 sizeof (tvnorm->cropcap))) {
1303 bttv_crop_reset(&btv->crop[0], norm);
1304 btv->crop[1] = btv->crop[0]; /* current = default */
1305
1306 if (0 == (btv->resources & VIDEO_RESOURCES)) {
1307 btv->crop_start = tvnorm->cropcap.bounds.top
1308 + tvnorm->cropcap.bounds.height;
1309 }
1310 }
1311
1312 btv->tvnorm = norm;
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 btwrite(tvnorm->adelay, BT848_ADELAY);
1315 btwrite(tvnorm->bdelay, BT848_BDELAY);
1316 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1317 BT848_IFORM);
1318 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1319 btwrite(1, BT848_VBI_PACK_DEL);
1320 bt848A_set_timing(btv);
1321
1322 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001323 case BTTV_BOARD_VOODOOTV_FM:
Wade Berrier434b2522007-06-25 13:02:16 -03001324 case BTTV_BOARD_VOODOOTV_200:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 bttv_tda9880_setnorm(btv,norm);
1326 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 }
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001328 id = tvnorm->v4l2_id;
1329 bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
1330
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 return 0;
1332}
1333
Michael Schimeke5bd0262007-01-18 16:17:39 -03001334/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335static void
Trent Piepho333408f2007-07-03 15:08:10 -03001336set_input(struct bttv *btv, unsigned int input, unsigned int norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337{
1338 unsigned long flags;
1339
1340 btv->input = input;
1341 if (irq_iswitch) {
1342 spin_lock_irqsave(&btv->s_lock,flags);
1343 if (btv->curr.frame_irq) {
1344 /* active capture -> delayed input switch */
1345 btv->new_input = input;
1346 } else {
1347 video_mux(btv,input);
1348 }
1349 spin_unlock_irqrestore(&btv->s_lock,flags);
1350 } else {
1351 video_mux(btv,input);
1352 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001353 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1354 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Trent Piepho333408f2007-07-03 15:08:10 -03001355 set_tvnorm(btv, norm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356}
1357
1358static void init_irqreg(struct bttv *btv)
1359{
1360 /* clear status */
1361 btwrite(0xfffffUL, BT848_INT_STAT);
1362
1363 if (bttv_tvcards[btv->c.type].no_video) {
1364 /* i2c only */
1365 btwrite(BT848_INT_I2CDONE,
1366 BT848_INT_MASK);
1367 } else {
1368 /* full video */
1369 btwrite((btv->triton1) |
1370 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1371 BT848_INT_SCERR |
1372 (fdsr ? BT848_INT_FDSR : 0) |
1373 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1374 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1375 BT848_INT_I2CDONE,
1376 BT848_INT_MASK);
1377 }
1378}
1379
1380static void init_bt848(struct bttv *btv)
1381{
1382 int val;
1383
1384 if (bttv_tvcards[btv->c.type].no_video) {
1385 /* very basic init only */
1386 init_irqreg(btv);
1387 return;
1388 }
1389
1390 btwrite(0x00, BT848_CAP_CTL);
1391 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1392 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1393
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001394 /* set planar and packed mode trigger points and */
1395 /* set rising edge of inverted GPINTR pin as irq trigger */
1396 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1397 BT848_GPIO_DMA_CTL_PLTP1_16|
1398 BT848_GPIO_DMA_CTL_PLTP23_16|
1399 BT848_GPIO_DMA_CTL_GPINTC|
1400 BT848_GPIO_DMA_CTL_GPINTI,
1401 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
1403 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001404 btwrite(val, BT848_E_SCLOOP);
1405 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001407 btwrite(0x20, BT848_E_VSCALE_HI);
1408 btwrite(0x20, BT848_O_VSCALE_HI);
1409 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 BT848_ADC);
1411
1412 btwrite(whitecrush_upper, BT848_WC_UP);
1413 btwrite(whitecrush_lower, BT848_WC_DOWN);
1414
1415 if (btv->opt_lumafilter) {
1416 btwrite(0, BT848_E_CONTROL);
1417 btwrite(0, BT848_O_CONTROL);
1418 } else {
1419 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1420 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1421 }
1422
1423 bt848_bright(btv, btv->bright);
1424 bt848_hue(btv, btv->hue);
1425 bt848_contrast(btv, btv->contrast);
1426 bt848_sat(btv, btv->saturation);
1427
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001428 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 init_irqreg(btv);
1430}
1431
1432static void bttv_reinit_bt848(struct bttv *btv)
1433{
1434 unsigned long flags;
1435
1436 if (bttv_verbose)
1437 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1438 spin_lock_irqsave(&btv->s_lock,flags);
1439 btv->errors=0;
1440 bttv_set_dma(btv,0);
1441 spin_unlock_irqrestore(&btv->s_lock,flags);
1442
1443 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001444 btv->pll.pll_current = -1;
Trent Piepho333408f2007-07-03 15:08:10 -03001445 set_input(btv, btv->input, btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446}
1447
1448static int get_control(struct bttv *btv, struct v4l2_control *c)
1449{
1450 struct video_audio va;
1451 int i;
1452
1453 for (i = 0; i < BTTV_CTLS; i++)
1454 if (bttv_ctls[i].id == c->id)
1455 break;
1456 if (i == BTTV_CTLS)
1457 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001458 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001460 btv->audio_hook(btv,&va,0);
1461 switch (c->id) {
1462 case V4L2_CID_AUDIO_MUTE:
1463 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1464 break;
1465 case V4L2_CID_AUDIO_VOLUME:
1466 c->value = va.volume;
1467 break;
1468 case V4L2_CID_AUDIO_BALANCE:
1469 c->value = va.balance;
1470 break;
1471 case V4L2_CID_AUDIO_BASS:
1472 c->value = va.bass;
1473 break;
1474 case V4L2_CID_AUDIO_TREBLE:
1475 c->value = va.treble;
1476 break;
1477 }
1478 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 }
1480 switch (c->id) {
1481 case V4L2_CID_BRIGHTNESS:
1482 c->value = btv->bright;
1483 break;
1484 case V4L2_CID_HUE:
1485 c->value = btv->hue;
1486 break;
1487 case V4L2_CID_CONTRAST:
1488 c->value = btv->contrast;
1489 break;
1490 case V4L2_CID_SATURATION:
1491 c->value = btv->saturation;
1492 break;
1493
1494 case V4L2_CID_AUDIO_MUTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001499 bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 break;
1501
1502 case V4L2_CID_PRIVATE_CHROMA_AGC:
1503 c->value = btv->opt_chroma_agc;
1504 break;
1505 case V4L2_CID_PRIVATE_COMBFILTER:
1506 c->value = btv->opt_combfilter;
1507 break;
1508 case V4L2_CID_PRIVATE_LUMAFILTER:
1509 c->value = btv->opt_lumafilter;
1510 break;
1511 case V4L2_CID_PRIVATE_AUTOMUTE:
1512 c->value = btv->opt_automute;
1513 break;
1514 case V4L2_CID_PRIVATE_AGC_CRUSH:
1515 c->value = btv->opt_adc_crush;
1516 break;
1517 case V4L2_CID_PRIVATE_VCR_HACK:
1518 c->value = btv->opt_vcr_hack;
1519 break;
1520 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1521 c->value = btv->opt_whitecrush_upper;
1522 break;
1523 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1524 c->value = btv->opt_whitecrush_lower;
1525 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001526 case V4L2_CID_PRIVATE_UV_RATIO:
1527 c->value = btv->opt_uv_ratio;
1528 break;
1529 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1530 c->value = btv->opt_full_luma_range;
1531 break;
1532 case V4L2_CID_PRIVATE_CORING:
1533 c->value = btv->opt_coring;
1534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 default:
1536 return -EINVAL;
1537 }
1538 return 0;
1539}
1540
1541static int set_control(struct bttv *btv, struct v4l2_control *c)
1542{
1543 struct video_audio va;
1544 int i,val;
1545
1546 for (i = 0; i < BTTV_CTLS; i++)
1547 if (bttv_ctls[i].id == c->id)
1548 break;
1549 if (i == BTTV_CTLS)
1550 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001551 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001553 btv->audio_hook(btv,&va,0);
1554 switch (c->id) {
1555 case V4L2_CID_AUDIO_MUTE:
1556 if (c->value) {
1557 va.flags |= VIDEO_AUDIO_MUTE;
1558 audio_mute(btv, 1);
1559 } else {
1560 va.flags &= ~VIDEO_AUDIO_MUTE;
1561 audio_mute(btv, 0);
1562 }
1563 break;
1564
1565 case V4L2_CID_AUDIO_VOLUME:
1566 va.volume = c->value;
1567 break;
1568 case V4L2_CID_AUDIO_BALANCE:
1569 va.balance = c->value;
1570 break;
1571 case V4L2_CID_AUDIO_BASS:
1572 va.bass = c->value;
1573 break;
1574 case V4L2_CID_AUDIO_TREBLE:
1575 va.treble = c->value;
1576 break;
1577 }
1578 btv->audio_hook(btv,&va,1);
1579 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 }
1581 switch (c->id) {
1582 case V4L2_CID_BRIGHTNESS:
1583 bt848_bright(btv,c->value);
1584 break;
1585 case V4L2_CID_HUE:
1586 bt848_hue(btv,c->value);
1587 break;
1588 case V4L2_CID_CONTRAST:
1589 bt848_contrast(btv,c->value);
1590 break;
1591 case V4L2_CID_SATURATION:
1592 bt848_sat(btv,c->value);
1593 break;
1594 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001595 audio_mute(btv, c->value);
1596 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001601 bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 break;
1603
1604 case V4L2_CID_PRIVATE_CHROMA_AGC:
1605 btv->opt_chroma_agc = c->value;
1606 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1607 btwrite(val, BT848_E_SCLOOP);
1608 btwrite(val, BT848_O_SCLOOP);
1609 break;
1610 case V4L2_CID_PRIVATE_COMBFILTER:
1611 btv->opt_combfilter = c->value;
1612 break;
1613 case V4L2_CID_PRIVATE_LUMAFILTER:
1614 btv->opt_lumafilter = c->value;
1615 if (btv->opt_lumafilter) {
1616 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1617 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1618 } else {
1619 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1620 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1621 }
1622 break;
1623 case V4L2_CID_PRIVATE_AUTOMUTE:
1624 btv->opt_automute = c->value;
1625 break;
1626 case V4L2_CID_PRIVATE_AGC_CRUSH:
1627 btv->opt_adc_crush = c->value;
1628 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1629 BT848_ADC);
1630 break;
1631 case V4L2_CID_PRIVATE_VCR_HACK:
1632 btv->opt_vcr_hack = c->value;
1633 break;
1634 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1635 btv->opt_whitecrush_upper = c->value;
1636 btwrite(c->value, BT848_WC_UP);
1637 break;
1638 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1639 btv->opt_whitecrush_lower = c->value;
1640 btwrite(c->value, BT848_WC_DOWN);
1641 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001642 case V4L2_CID_PRIVATE_UV_RATIO:
1643 btv->opt_uv_ratio = c->value;
1644 bt848_sat(btv, btv->saturation);
1645 break;
1646 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1647 btv->opt_full_luma_range = c->value;
1648 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1649 break;
1650 case V4L2_CID_PRIVATE_CORING:
1651 btv->opt_coring = c->value;
1652 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1653 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 default:
1655 return -EINVAL;
1656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 return 0;
1658}
1659
1660/* ----------------------------------------------------------------------- */
1661
1662void bttv_gpio_tracking(struct bttv *btv, char *comment)
1663{
1664 unsigned int outbits, data;
1665 outbits = btread(BT848_GPIO_OUT_EN);
1666 data = btread(BT848_GPIO_DATA);
1667 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1668 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1669}
1670
1671static void bttv_field_count(struct bttv *btv)
1672{
1673 int need_count = 0;
1674
1675 if (btv->users)
1676 need_count++;
1677
1678 if (need_count) {
1679 /* start field counter */
1680 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1681 } else {
1682 /* stop field counter */
1683 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1684 btv->field_count = 0;
1685 }
1686}
1687
1688static const struct bttv_format*
1689format_by_palette(int palette)
1690{
1691 unsigned int i;
1692
1693 for (i = 0; i < BTTV_FORMATS; i++) {
1694 if (-1 == bttv_formats[i].palette)
1695 continue;
1696 if (bttv_formats[i].palette == palette)
1697 return bttv_formats+i;
1698 }
1699 return NULL;
1700}
1701
1702static const struct bttv_format*
1703format_by_fourcc(int fourcc)
1704{
1705 unsigned int i;
1706
1707 for (i = 0; i < BTTV_FORMATS; i++) {
1708 if (-1 == bttv_formats[i].fourcc)
1709 continue;
1710 if (bttv_formats[i].fourcc == fourcc)
1711 return bttv_formats+i;
1712 }
1713 return NULL;
1714}
1715
1716/* ----------------------------------------------------------------------- */
1717/* misc helpers */
1718
1719static int
1720bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1721 struct bttv_buffer *new)
1722{
1723 struct bttv_buffer *old;
1724 unsigned long flags;
1725 int retval = 0;
1726
1727 dprintk("switch_overlay: enter [new=%p]\n",new);
1728 if (new)
1729 new->vb.state = STATE_DONE;
1730 spin_lock_irqsave(&btv->s_lock,flags);
1731 old = btv->screen;
1732 btv->screen = new;
1733 btv->loop_irq |= 1;
1734 bttv_set_dma(btv, 0x03);
1735 spin_unlock_irqrestore(&btv->s_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if (NULL != old) {
1737 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001738 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 kfree(old);
1740 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03001741 if (NULL == new)
1742 free_btres(btv,fh,RESOURCE_OVERLAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 dprintk("switch_overlay: done\n");
1744 return retval;
1745}
1746
1747/* ----------------------------------------------------------------------- */
1748/* video4linux (1) interface */
1749
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001750static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1751 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001752 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 unsigned int width, unsigned int height,
1754 enum v4l2_field field)
1755{
Michael Schimeke5bd0262007-01-18 16:17:39 -03001756 struct bttv_fh *fh = q->priv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 int redo_dma_risc = 0;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001758 struct bttv_crop c;
1759 int norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 int rc;
1761
1762 /* check settings */
1763 if (NULL == fmt)
1764 return -EINVAL;
1765 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1766 width = RAW_BPL;
1767 height = RAW_LINES*2;
1768 if (width*height > buf->vb.bsize)
1769 return -EINVAL;
1770 buf->vb.size = buf->vb.bsize;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001771
1772 /* Make sure tvnorm and vbi_end remain consistent
1773 until we're done. */
1774 mutex_lock(&btv->lock);
1775
1776 norm = btv->tvnorm;
1777
1778 /* In this mode capturing always starts at defrect.top
1779 (default VDELAY), ignoring cropping parameters. */
1780 if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
1781 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001783 }
1784
1785 mutex_unlock(&btv->lock);
1786
1787 c.rect = bttv_tvnorms[norm].cropcap.defrect;
1788 } else {
1789 mutex_lock(&btv->lock);
1790
1791 norm = btv->tvnorm;
1792 c = btv->crop[!!fh->do_crop];
1793
1794 mutex_unlock(&btv->lock);
1795
1796 if (width < c.min_scaled_width ||
1797 width > c.max_scaled_width ||
1798 height < c.min_scaled_height)
1799 return -EINVAL;
1800
1801 switch (field) {
1802 case V4L2_FIELD_TOP:
1803 case V4L2_FIELD_BOTTOM:
1804 case V4L2_FIELD_ALTERNATE:
1805 /* btv->crop counts frame lines. Max. scale
1806 factor is 16:1 for frames, 8:1 for fields. */
1807 if (height * 2 > c.max_scaled_height)
1808 return -EINVAL;
1809 break;
1810
1811 default:
1812 if (height > c.max_scaled_height)
1813 return -EINVAL;
1814 break;
1815 }
1816
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 buf->vb.size = (width * height * fmt->depth) >> 3;
1818 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1819 return -EINVAL;
1820 }
1821
1822 /* alloc + fill struct bttv_buffer (if changed) */
1823 if (buf->vb.width != width || buf->vb.height != height ||
1824 buf->vb.field != field ||
Michael Schimeke5bd0262007-01-18 16:17:39 -03001825 buf->tvnorm != norm || buf->fmt != fmt ||
1826 buf->crop.top != c.rect.top ||
1827 buf->crop.left != c.rect.left ||
1828 buf->crop.width != c.rect.width ||
1829 buf->crop.height != c.rect.height) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 buf->vb.width = width;
1831 buf->vb.height = height;
1832 buf->vb.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001833 buf->tvnorm = norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 buf->fmt = fmt;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001835 buf->crop = c.rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 redo_dma_risc = 1;
1837 }
1838
1839 /* alloc risc memory */
1840 if (STATE_NEEDS_INIT == buf->vb.state) {
1841 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001842 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 goto fail;
1844 }
1845
1846 if (redo_dma_risc)
1847 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1848 goto fail;
1849
1850 buf->vb.state = STATE_PREPARED;
1851 return 0;
1852
1853 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001854 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 return rc;
1856}
1857
1858static int
1859buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1860{
1861 struct bttv_fh *fh = q->priv_data;
1862
1863 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1864 if (0 == *count)
1865 *count = gbuffers;
1866 while (*size * *count > gbuffers * gbufsize)
1867 (*count)--;
1868 return 0;
1869}
1870
1871static int
1872buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1873 enum v4l2_field field)
1874{
1875 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1876 struct bttv_fh *fh = q->priv_data;
1877
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001878 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 fh->width, fh->height, field);
1880}
1881
1882static void
1883buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1884{
1885 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1886 struct bttv_fh *fh = q->priv_data;
1887 struct bttv *btv = fh->btv;
1888
1889 buf->vb.state = STATE_QUEUED;
1890 list_add_tail(&buf->vb.queue,&btv->capture);
1891 if (!btv->curr.frame_irq) {
1892 btv->loop_irq |= 1;
1893 bttv_set_dma(btv, 0x03);
1894 }
1895}
1896
1897static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1898{
1899 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1900 struct bttv_fh *fh = q->priv_data;
1901
Michael Schimekfeaba7a2007-01-26 08:30:05 -03001902 bttv_dma_free(q,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903}
1904
1905static struct videobuf_queue_ops bttv_video_qops = {
1906 .buf_setup = buffer_setup,
1907 .buf_prepare = buffer_prepare,
1908 .buf_queue = buffer_queue,
1909 .buf_release = buffer_release,
1910};
1911
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1913{
1914 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001915 case BTTV_VERSION:
1916 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918 /* *** v4l1 *** ************************************************ */
1919 case VIDIOCGFREQ:
1920 {
1921 unsigned long *freq = arg;
1922 *freq = btv->freq;
1923 return 0;
1924 }
1925 case VIDIOCSFREQ:
1926 {
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001927 struct v4l2_frequency freq;
1928
1929 memset(&freq, 0, sizeof(freq));
1930 freq.frequency = *(unsigned long *)arg;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001931 mutex_lock(&btv->lock);
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001932 freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
1933 btv->freq = *(unsigned long *)arg;
1934 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (btv->has_matchbox && btv->radio_user)
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001936 tea5757_set_freq(btv,*(unsigned long *)arg);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001937 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 return 0;
1939 }
1940
1941 case VIDIOCGTUNER:
1942 {
1943 struct video_tuner *v = arg;
1944
1945 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1946 return -EINVAL;
1947 if (v->tuner) /* Only tuner 0 */
1948 return -EINVAL;
1949 strcpy(v->name, "Television");
1950 v->rangelow = 0;
1951 v->rangehigh = 0x7FFFFFFF;
1952 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1953 v->mode = btv->tvnorm;
1954 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1955 bttv_call_i2c_clients(btv,cmd,v);
1956 return 0;
1957 }
1958 case VIDIOCSTUNER:
1959 {
1960 struct video_tuner *v = arg;
1961
1962 if (v->tuner) /* Only tuner 0 */
1963 return -EINVAL;
1964 if (v->mode >= BTTV_TVNORMS)
1965 return -EINVAL;
1966
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001967 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 set_tvnorm(btv,v->mode);
1969 bttv_call_i2c_clients(btv,cmd,v);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001970 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 return 0;
1972 }
1973
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001974 case VIDIOCGCHAN:
1975 {
1976 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 unsigned int channel = v->channel;
1978
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001979 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1980 return -EINVAL;
1981 v->tuners=0;
1982 v->flags = VIDEO_VC_AUDIO;
1983 v->type = VIDEO_TYPE_CAMERA;
1984 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001986 strcpy(v->name,"Television");
1987 v->flags|=VIDEO_VC_TUNER;
1988 v->type=VIDEO_TYPE_TV;
1989 v->tuners=1;
1990 } else if (channel == btv->svhs) {
1991 strcpy(v->name,"S-Video");
1992 } else {
1993 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 }
1995 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001996 }
1997 case VIDIOCSCHAN:
1998 {
1999 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 unsigned int channel = v->channel;
2001
2002 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
2003 return -EINVAL;
2004 if (v->norm >= BTTV_TVNORMS)
2005 return -EINVAL;
2006
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002007 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 if (channel == btv->input &&
2009 v->norm == btv->tvnorm) {
2010 /* nothing to do */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002011 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 return 0;
2013 }
2014
Trent Piepho333408f2007-07-03 15:08:10 -03002015 set_input(btv, v->channel, v->norm);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002016 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 return 0;
2018 }
2019
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002020 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 {
2022 struct video_audio *v = arg;
2023
2024 memset(v,0,sizeof(*v));
2025 strcpy(v->name,"Television");
2026 v->flags |= VIDEO_AUDIO_MUTABLE;
2027 v->mode = VIDEO_SOUND_MONO;
2028
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002029 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 bttv_call_i2c_clients(btv,cmd,v);
2031
2032 /* card specific hooks */
2033 if (btv->audio_hook)
2034 btv->audio_hook(btv,v,0);
2035
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002036 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 return 0;
2038 }
2039 case VIDIOCSAUDIO:
2040 {
2041 struct video_audio *v = arg;
2042 unsigned int audio = v->audio;
2043
2044 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
2045 return -EINVAL;
2046
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002047 mutex_lock(&btv->lock);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03002048 audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 bttv_call_i2c_clients(btv,cmd,v);
2050
2051 /* card specific hooks */
2052 if (btv->audio_hook)
2053 btv->audio_hook(btv,v,1);
2054
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002055 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 return 0;
2057 }
2058
2059 /* *** v4l2 *** ************************************************ */
2060 case VIDIOC_ENUMSTD:
2061 {
2062 struct v4l2_standard *e = arg;
2063 unsigned int index = e->index;
2064
2065 if (index >= BTTV_TVNORMS)
2066 return -EINVAL;
2067 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
2068 bttv_tvnorms[e->index].name);
2069 e->index = index;
2070 return 0;
2071 }
2072 case VIDIOC_G_STD:
2073 {
2074 v4l2_std_id *id = arg;
2075 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
2076 return 0;
2077 }
2078 case VIDIOC_S_STD:
2079 {
2080 v4l2_std_id *id = arg;
2081 unsigned int i;
2082
2083 for (i = 0; i < BTTV_TVNORMS; i++)
2084 if (*id & bttv_tvnorms[i].v4l2_id)
2085 break;
2086 if (i == BTTV_TVNORMS)
2087 return -EINVAL;
2088
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002089 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 set_tvnorm(btv,i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002091 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 return 0;
2093 }
2094 case VIDIOC_QUERYSTD:
2095 {
2096 v4l2_std_id *id = arg;
2097
2098 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
2099 *id = V4L2_STD_625_50;
2100 else
2101 *id = V4L2_STD_525_60;
2102 return 0;
2103 }
2104
2105 case VIDIOC_ENUMINPUT:
2106 {
2107 struct v4l2_input *i = arg;
2108 unsigned int n;
2109
2110 n = i->index;
2111 if (n >= bttv_tvcards[btv->c.type].video_inputs)
2112 return -EINVAL;
2113 memset(i,0,sizeof(*i));
2114 i->index = n;
2115 i->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab5d9d1712006-11-14 12:40:07 -03002116 i->audioset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 if (i->index == bttv_tvcards[btv->c.type].tuner) {
2118 sprintf(i->name, "Television");
2119 i->type = V4L2_INPUT_TYPE_TUNER;
2120 i->tuner = 0;
2121 } else if (i->index == btv->svhs) {
2122 sprintf(i->name, "S-Video");
2123 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002124 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
2126 if (i->index == btv->input) {
2127 __u32 dstatus = btread(BT848_DSTATUS);
2128 if (0 == (dstatus & BT848_DSTATUS_PRES))
2129 i->status |= V4L2_IN_ST_NO_SIGNAL;
2130 if (0 == (dstatus & BT848_DSTATUS_HLOC))
2131 i->status |= V4L2_IN_ST_NO_H_LOCK;
2132 }
2133 for (n = 0; n < BTTV_TVNORMS; n++)
2134 i->std |= bttv_tvnorms[n].v4l2_id;
2135 return 0;
2136 }
2137 case VIDIOC_G_INPUT:
2138 {
2139 int *i = arg;
2140 *i = btv->input;
2141 return 0;
2142 }
2143 case VIDIOC_S_INPUT:
2144 {
2145 unsigned int *i = arg;
2146
2147 if (*i > bttv_tvcards[btv->c.type].video_inputs)
2148 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002149 mutex_lock(&btv->lock);
Trent Piepho333408f2007-07-03 15:08:10 -03002150 set_input(btv, *i, btv->tvnorm);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002151 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 return 0;
2153 }
2154
2155 case VIDIOC_G_TUNER:
2156 {
2157 struct v4l2_tuner *t = arg;
2158
2159 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2160 return -EINVAL;
2161 if (0 != t->index)
2162 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002163 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 memset(t,0,sizeof(*t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002166 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
2167 strcpy(t->name, "Television");
2168 t->capability = V4L2_TUNER_CAP_NORM;
2169 t->type = V4L2_TUNER_ANALOG_TV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
2171 t->signal = 0xffff;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002172
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002173 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* Hmmm ... */
2175 struct video_audio va;
2176 memset(&va, 0, sizeof(struct video_audio));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002177 btv->audio_hook(btv,&va,0);
2178 t->audmode = V4L2_TUNER_MODE_MONO;
2179 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 if(va.mode & VIDEO_SOUND_STEREO) {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002181 t->audmode = V4L2_TUNER_MODE_STEREO;
2182 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 }
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002184 if(va.mode & VIDEO_SOUND_LANG2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 t->audmode = V4L2_TUNER_MODE_LANG1;
2186 t->rxsubchans = V4L2_TUNER_SUB_LANG1
2187 | V4L2_TUNER_SUB_LANG2;
2188 }
2189 }
2190 /* FIXME: fill capability+audmode */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002191 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 return 0;
2193 }
2194 case VIDIOC_S_TUNER:
2195 {
2196 struct v4l2_tuner *t = arg;
2197
2198 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2199 return -EINVAL;
2200 if (0 != t->index)
2201 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002202 mutex_lock(&btv->lock);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002203 bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
2204 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 struct video_audio va;
2206 memset(&va, 0, sizeof(struct video_audio));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 if (t->audmode == V4L2_TUNER_MODE_MONO)
2208 va.mode = VIDEO_SOUND_MONO;
Hans Verkuil301e22d2006-03-18 17:15:00 -03002209 else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
2210 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 va.mode = VIDEO_SOUND_STEREO;
2212 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
2213 va.mode = VIDEO_SOUND_LANG1;
2214 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
2215 va.mode = VIDEO_SOUND_LANG2;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002216 btv->audio_hook(btv,&va,1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002218 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return 0;
2220 }
2221
2222 case VIDIOC_G_FREQUENCY:
2223 {
2224 struct v4l2_frequency *f = arg;
2225
2226 memset(f,0,sizeof(*f));
2227 f->type = V4L2_TUNER_ANALOG_TV;
2228 f->frequency = btv->freq;
2229 return 0;
2230 }
2231 case VIDIOC_S_FREQUENCY:
2232 {
2233 struct v4l2_frequency *f = arg;
2234
2235 if (unlikely(f->tuner != 0))
2236 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07002237 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002239 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 btv->freq = f->frequency;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002241 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 if (btv->has_matchbox && btv->radio_user)
2243 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002244 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 return 0;
2246 }
Hans Verkuil299392b2005-11-08 21:37:42 -08002247 case VIDIOC_LOG_STATUS:
2248 {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002249 printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr);
Luiz Capitulino97cb4452005-12-01 00:51:24 -08002250 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002251 printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
Hans Verkuil299392b2005-11-08 21:37:42 -08002252 return 0;
2253 }
Trent Piepho55c0d102007-06-29 00:17:36 -03002254#ifdef CONFIG_VIDEO_ADV_DEBUG
2255 case VIDIOC_DBG_G_REGISTER:
2256 case VIDIOC_DBG_S_REGISTER:
2257 {
2258 struct v4l2_register *reg = arg;
2259 if (!capable(CAP_SYS_ADMIN))
2260 return -EPERM;
2261 if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
2262 return -EINVAL;
2263 /* bt848 has a 12-bit register space */
2264 reg->reg &= 0xfff;
2265 if (cmd == VIDIOC_DBG_G_REGISTER)
2266 reg->val = btread(reg->reg);
2267 else
2268 btwrite(reg->val, reg->reg);
2269 return 0;
2270 }
2271#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272
2273 default:
2274 return -ENOIOCTLCMD;
2275
2276 }
2277 return 0;
2278}
2279
Michael Schimeke5bd0262007-01-18 16:17:39 -03002280/* Given cropping boundaries b and the scaled width and height of a
2281 single field or frame, which must not exceed hardware limits, this
2282 function adjusts the cropping parameters c. */
2283static void
2284bttv_crop_adjust (struct bttv_crop * c,
2285 const struct v4l2_rect * b,
2286 __s32 width,
2287 __s32 height,
2288 enum v4l2_field field)
2289{
2290 __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
2291 __s32 max_left;
2292 __s32 max_top;
2293
2294 if (width < c->min_scaled_width) {
2295 /* Max. hor. scale factor 16:1. */
2296 c->rect.width = width * 16;
2297 } else if (width > c->max_scaled_width) {
2298 /* Min. hor. scale factor 1:1. */
2299 c->rect.width = width;
2300
2301 max_left = b->left + b->width - width;
2302 max_left = min(max_left, (__s32) MAX_HDELAY);
2303 if (c->rect.left > max_left)
2304 c->rect.left = max_left;
2305 }
2306
2307 if (height < c->min_scaled_height) {
2308 /* Max. vert. scale factor 16:1, single fields 8:1. */
2309 c->rect.height = height * 16;
2310 } else if (frame_height > c->max_scaled_height) {
2311 /* Min. vert. scale factor 1:1.
2312 Top and height count field lines times two. */
2313 c->rect.height = (frame_height + 1) & ~1;
2314
2315 max_top = b->top + b->height - c->rect.height;
2316 if (c->rect.top > max_top)
2317 c->rect.top = max_top;
2318 }
2319
2320 bttv_crop_calc_limits(c);
2321}
2322
2323/* Returns an error if scaling to a frame or single field with the given
2324 width and height is not possible with the current cropping parameters
2325 and width aligned according to width_mask. If adjust_size is TRUE the
2326 function may adjust the width and/or height instead, rounding width
2327 to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
2328 also adjust the current cropping parameters to get closer to the
2329 desired image size. */
2330static int
2331limit_scaled_size (struct bttv_fh * fh,
2332 __s32 * width,
2333 __s32 * height,
2334 enum v4l2_field field,
2335 unsigned int width_mask,
2336 unsigned int width_bias,
2337 int adjust_size,
2338 int adjust_crop)
2339{
2340 struct bttv *btv = fh->btv;
2341 const struct v4l2_rect *b;
2342 struct bttv_crop *c;
2343 __s32 min_width;
2344 __s32 min_height;
2345 __s32 max_width;
2346 __s32 max_height;
2347 int rc;
2348
2349 BUG_ON((int) width_mask >= 0 ||
2350 width_bias >= (unsigned int) -width_mask);
2351
2352 /* Make sure tvnorm, vbi_end and the current cropping parameters
2353 remain consistent until we're done. */
2354 mutex_lock(&btv->lock);
2355
2356 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
2357
2358 /* Do crop - use current, don't - use default parameters. */
2359 c = &btv->crop[!!fh->do_crop];
2360
2361 if (fh->do_crop
2362 && adjust_size
2363 && adjust_crop
2364 && !locked_btres(btv, VIDEO_RESOURCES)) {
2365 min_width = 48;
2366 min_height = 32;
2367
2368 /* We cannot scale up. When the scaled image is larger
2369 than crop.rect we adjust the crop.rect as required
2370 by the V4L2 spec, hence cropcap.bounds are our limit. */
2371 max_width = min(b->width, (__s32) MAX_HACTIVE);
2372 max_height = b->height;
2373
2374 /* We cannot capture the same line as video and VBI data.
2375 Note btv->vbi_end is really a minimum, see
2376 bttv_vbi_try_fmt(). */
2377 if (btv->vbi_end > b->top) {
2378 max_height -= btv->vbi_end - b->top;
2379 rc = -EBUSY;
2380 if (min_height > max_height)
2381 goto fail;
2382 }
2383 } else {
2384 rc = -EBUSY;
2385 if (btv->vbi_end > c->rect.top)
2386 goto fail;
2387
2388 min_width = c->min_scaled_width;
2389 min_height = c->min_scaled_height;
2390 max_width = c->max_scaled_width;
2391 max_height = c->max_scaled_height;
2392
2393 adjust_crop = 0;
2394 }
2395
2396 min_width = (min_width - width_mask - 1) & width_mask;
2397 max_width = max_width & width_mask;
2398
2399 /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
2400 min_height = min_height;
2401 /* Min. scale factor is 1:1. */
2402 max_height >>= !V4L2_FIELD_HAS_BOTH(field);
2403
2404 if (adjust_size) {
2405 *width = clamp(*width, min_width, max_width);
2406 *height = clamp(*height, min_height, max_height);
2407
2408 /* Round after clamping to avoid overflow. */
2409 *width = (*width + width_bias) & width_mask;
2410
2411 if (adjust_crop) {
2412 bttv_crop_adjust(c, b, *width, *height, field);
2413
2414 if (btv->vbi_end > c->rect.top) {
2415 /* Move the crop window out of the way. */
2416 c->rect.top = btv->vbi_end;
2417 }
2418 }
2419 } else {
2420 rc = -EINVAL;
2421 if (*width < min_width ||
2422 *height < min_height ||
2423 *width > max_width ||
2424 *height > max_height ||
2425 0 != (*width & ~width_mask))
2426 goto fail;
2427 }
2428
2429 rc = 0; /* success */
2430
2431 fail:
2432 mutex_unlock(&btv->lock);
2433
2434 return rc;
2435}
2436
2437/* Returns an error if the given overlay window dimensions are not
2438 possible with the current cropping parameters. If adjust_size is
2439 TRUE the function may adjust the window width and/or height
2440 instead, however it always rounds the horizontal position and
2441 width as btcx_align() does. If adjust_crop is TRUE the function
2442 may also adjust the current cropping parameters to get closer
2443 to the desired window size. */
2444static int
2445verify_window (struct bttv_fh * fh,
2446 struct v4l2_window * win,
2447 int adjust_size,
2448 int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449{
2450 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002451 unsigned int width_mask;
2452 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
2454 if (win->w.width < 48 || win->w.height < 32)
2455 return -EINVAL;
2456 if (win->clipcount > 2048)
2457 return -EINVAL;
2458
2459 field = win->field;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
2461 if (V4L2_FIELD_ANY == field) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03002462 __s32 height2;
2463
2464 height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
2465 field = (win->w.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 ? V4L2_FIELD_INTERLACED
2467 : V4L2_FIELD_TOP;
2468 }
2469 switch (field) {
2470 case V4L2_FIELD_TOP:
2471 case V4L2_FIELD_BOTTOM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 case V4L2_FIELD_INTERLACED:
2473 break;
2474 default:
2475 return -EINVAL;
2476 }
2477
Michael Schimeke5bd0262007-01-18 16:17:39 -03002478 /* 4-byte alignment. */
2479 if (NULL == fh->ovfmt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002481 width_mask = ~0;
2482 switch (fh->ovfmt->depth) {
2483 case 8:
2484 case 24:
2485 width_mask = ~3;
2486 break;
2487 case 16:
2488 width_mask = ~1;
2489 break;
2490 case 32:
2491 break;
2492 default:
2493 BUG();
2494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
Michael Schimeke5bd0262007-01-18 16:17:39 -03002496 win->w.width -= win->w.left & ~width_mask;
2497 win->w.left = (win->w.left - width_mask - 1) & width_mask;
2498
2499 rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
2500 field, width_mask,
2501 /* width_bias: round down */ 0,
2502 adjust_size, adjust_crop);
2503 if (0 != rc)
2504 return rc;
2505
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 win->field = field;
2507 return 0;
2508}
2509
2510static int setup_window(struct bttv_fh *fh, struct bttv *btv,
2511 struct v4l2_window *win, int fixup)
2512{
2513 struct v4l2_clip *clips = NULL;
2514 int n,size,retval = 0;
2515
2516 if (NULL == fh->ovfmt)
2517 return -EINVAL;
2518 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
2519 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002520 retval = verify_window(fh, win,
2521 /* adjust_size */ fixup,
2522 /* adjust_crop */ fixup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 if (0 != retval)
2524 return retval;
2525
2526 /* copy clips -- luckily v4l1 + v4l2 are binary
2527 compatible here ...*/
2528 n = win->clipcount;
2529 size = sizeof(*clips)*(n+4);
2530 clips = kmalloc(size,GFP_KERNEL);
2531 if (NULL == clips)
2532 return -ENOMEM;
2533 if (n > 0) {
2534 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
2535 kfree(clips);
2536 return -EFAULT;
2537 }
2538 }
2539 /* clip against screen */
2540 if (NULL != btv->fbuf.base)
2541 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
2542 &win->w, clips, n);
2543 btcx_sort_clips(clips,n);
2544
2545 /* 4-byte alignments */
2546 switch (fh->ovfmt->depth) {
2547 case 8:
2548 case 24:
2549 btcx_align(&win->w, clips, n, 3);
2550 break;
2551 case 16:
2552 btcx_align(&win->w, clips, n, 1);
2553 break;
2554 case 32:
2555 /* no alignment fixups needed */
2556 break;
2557 default:
2558 BUG();
2559 }
2560
Ingo Molnar3593cab2006-02-07 06:49:14 -02002561 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002562 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 fh->ov.clips = clips;
2564 fh->ov.nclips = n;
2565
2566 fh->ov.w = win->w;
2567 fh->ov.field = win->field;
2568 fh->ov.setup_ok = 1;
2569 btv->init.ov.w.width = win->w.width;
2570 btv->init.ov.w.height = win->w.height;
2571 btv->init.ov.field = win->field;
2572
2573 /* update overlay if needed */
2574 retval = 0;
2575 if (check_btres(fh, RESOURCE_OVERLAY)) {
2576 struct bttv_buffer *new;
2577
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03002578 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03002579 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2581 retval = bttv_switch_overlay(btv,fh,new);
2582 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002583 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 return retval;
2585}
2586
2587/* ----------------------------------------------------------------------- */
2588
2589static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2590{
2591 struct videobuf_queue* q = NULL;
2592
2593 switch (fh->type) {
2594 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2595 q = &fh->cap;
2596 break;
2597 case V4L2_BUF_TYPE_VBI_CAPTURE:
2598 q = &fh->vbi;
2599 break;
2600 default:
2601 BUG();
2602 }
2603 return q;
2604}
2605
2606static int bttv_resource(struct bttv_fh *fh)
2607{
2608 int res = 0;
2609
2610 switch (fh->type) {
2611 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002612 res = RESOURCE_VIDEO_STREAM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 break;
2614 case V4L2_BUF_TYPE_VBI_CAPTURE:
2615 res = RESOURCE_VBI;
2616 break;
2617 default:
2618 BUG();
2619 }
2620 return res;
2621}
2622
2623static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2624{
2625 struct videobuf_queue *q = bttv_queue(fh);
2626 int res = bttv_resource(fh);
2627
2628 if (check_btres(fh,res))
2629 return -EBUSY;
2630 if (videobuf_queue_is_busy(q))
2631 return -EBUSY;
2632 fh->type = type;
2633 return 0;
2634}
2635
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002636static void
2637pix_format_set_size (struct v4l2_pix_format * f,
2638 const struct bttv_format * fmt,
2639 unsigned int width,
2640 unsigned int height)
2641{
2642 f->width = width;
2643 f->height = height;
2644
2645 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2646 f->bytesperline = width; /* Y plane */
2647 f->sizeimage = (width * height * fmt->depth) >> 3;
2648 } else {
2649 f->bytesperline = (width * fmt->depth) >> 3;
2650 f->sizeimage = height * f->bytesperline;
2651 }
2652}
2653
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2655{
2656 switch (f->type) {
2657 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2658 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002659 pix_format_set_size (&f->fmt.pix, fh->fmt,
2660 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 f->fmt.pix.field = fh->cap.field;
2662 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 return 0;
2664 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2665 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2666 f->fmt.win.w = fh->ov.w;
2667 f->fmt.win.field = fh->ov.field;
2668 return 0;
2669 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002670 bttv_vbi_get_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 return 0;
2672 default:
2673 return -EINVAL;
2674 }
2675}
2676
2677static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
Michael Schimeke5bd0262007-01-18 16:17:39 -03002678 struct v4l2_format *f, int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679{
2680 switch (f->type) {
2681 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2682 {
2683 const struct bttv_format *fmt;
2684 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002685 __s32 width, height;
2686 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687
2688 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2689 if (NULL == fmt)
2690 return -EINVAL;
2691
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 field = f->fmt.pix.field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002693 if (V4L2_FIELD_ANY == field) {
2694 __s32 height2;
2695
2696 height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
2697 field = (f->fmt.pix.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 ? V4L2_FIELD_INTERLACED
2699 : V4L2_FIELD_BOTTOM;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 if (V4L2_FIELD_SEQ_BT == field)
2702 field = V4L2_FIELD_SEQ_TB;
2703 switch (field) {
2704 case V4L2_FIELD_TOP:
2705 case V4L2_FIELD_BOTTOM:
2706 case V4L2_FIELD_ALTERNATE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 case V4L2_FIELD_INTERLACED:
2708 break;
2709 case V4L2_FIELD_SEQ_TB:
2710 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2711 return -EINVAL;
2712 break;
2713 default:
2714 return -EINVAL;
2715 }
2716
Michael Schimeke5bd0262007-01-18 16:17:39 -03002717 width = f->fmt.pix.width;
2718 height = f->fmt.pix.height;
2719
2720 rc = limit_scaled_size(fh, &width, &height, field,
2721 /* width_mask: 4 pixels */ ~3,
2722 /* width_bias: nearest */ 2,
2723 /* adjust_size */ 1,
2724 adjust_crop);
2725 if (0 != rc)
2726 return rc;
2727
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 /* update data for the application */
2729 f->fmt.pix.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002730 pix_format_set_size(&f->fmt.pix, fmt, width, height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
2732 return 0;
2733 }
2734 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002735 return verify_window(fh, &f->fmt.win,
2736 /* adjust_size */ 1,
2737 /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002739 return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 default:
2741 return -EINVAL;
2742 }
2743}
2744
2745static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2746 struct v4l2_format *f)
2747{
2748 int retval;
2749
2750 switch (f->type) {
2751 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2752 {
2753 const struct bttv_format *fmt;
2754
2755 retval = bttv_switch_type(fh,f->type);
2756 if (0 != retval)
2757 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002758 retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 if (0 != retval)
2760 return retval;
2761 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2762
2763 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002764 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 fh->fmt = fmt;
2766 fh->cap.field = f->fmt.pix.field;
2767 fh->cap.last = V4L2_FIELD_NONE;
2768 fh->width = f->fmt.pix.width;
2769 fh->height = f->fmt.pix.height;
2770 btv->init.fmt = fmt;
2771 btv->init.width = f->fmt.pix.width;
2772 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002773 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775 return 0;
2776 }
2777 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002778 if (no_overlay > 0) {
2779 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2780 return -EINVAL;
2781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 return setup_window(fh, btv, &f->fmt.win, 1);
2783 case V4L2_BUF_TYPE_VBI_CAPTURE:
2784 retval = bttv_switch_type(fh,f->type);
2785 if (0 != retval)
2786 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002787 return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 default:
2789 return -EINVAL;
2790 }
2791}
2792
2793static int bttv_do_ioctl(struct inode *inode, struct file *file,
2794 unsigned int cmd, void *arg)
2795{
2796 struct bttv_fh *fh = file->private_data;
2797 struct bttv *btv = fh->btv;
2798 unsigned long flags;
2799 int retval = 0;
2800
Michael Krufky5e453dc2006-01-09 15:32:31 -02002801 if (bttv_debug > 1)
2802 v4l_print_ioctl(btv->c.name, cmd);
2803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 if (btv->errors)
2805 bttv_reinit_bt848(btv);
2806
2807 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002808 case VIDIOCSFREQ:
2809 case VIDIOCSTUNER:
2810 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 case VIDIOC_S_CTRL:
2812 case VIDIOC_S_STD:
2813 case VIDIOC_S_INPUT:
2814 case VIDIOC_S_TUNER:
2815 case VIDIOC_S_FREQUENCY:
2816 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2817 if (0 != retval)
2818 return retval;
2819 };
2820
2821 switch (cmd) {
2822
2823 /* *** v4l1 *** ************************************************ */
2824 case VIDIOCGCAP:
2825 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002826 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827
2828 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002829 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2831 /* vbi */
2832 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2833 } else {
2834 /* others */
2835 cap->type = VID_TYPE_CAPTURE|
2836 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 VID_TYPE_CLIPPING|
2838 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002839 if (no_overlay <= 0)
2840 cap->type |= VID_TYPE_OVERLAY;
2841
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2843 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2844 cap->minwidth = 48;
2845 cap->minheight = 32;
2846 }
2847 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2848 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002849 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 }
2851
2852 case VIDIOCGPICT:
2853 {
2854 struct video_picture *pic = arg;
2855
2856 memset(pic,0,sizeof(*pic));
2857 pic->brightness = btv->bright;
2858 pic->contrast = btv->contrast;
2859 pic->hue = btv->hue;
2860 pic->colour = btv->saturation;
2861 if (fh->fmt) {
2862 pic->depth = fh->fmt->depth;
2863 pic->palette = fh->fmt->palette;
2864 }
2865 return 0;
2866 }
2867 case VIDIOCSPICT:
2868 {
2869 struct video_picture *pic = arg;
2870 const struct bttv_format *fmt;
2871
2872 fmt = format_by_palette(pic->palette);
2873 if (NULL == fmt)
2874 return -EINVAL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002875 mutex_lock(&fh->cap.lock);
Michael H. Schimek13c72802005-12-01 00:51:37 -08002876 if (fmt->flags & FORMAT_FLAGS_RAW) {
2877 /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
2878 RAW_LINES * 2. F1 is stored at offset 0, F2
2879 at buffer size / 2. */
2880 fh->width = RAW_BPL;
2881 fh->height = gbufsize / RAW_BPL;
2882 btv->init.width = RAW_BPL;
2883 btv->init.height = gbufsize / RAW_BPL;
2884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 fh->ovfmt = fmt;
2886 fh->fmt = fmt;
2887 btv->init.ovfmt = fmt;
2888 btv->init.fmt = fmt;
2889 if (bigendian) {
2890 /* dirty hack time: swap bytes for overlay if the
2891 display adaptor is big endian (insmod option) */
2892 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2893 fmt->palette == VIDEO_PALETTE_RGB565 ||
2894 fmt->palette == VIDEO_PALETTE_RGB32) {
2895 fh->ovfmt = fmt+1;
2896 }
2897 }
2898 bt848_bright(btv,pic->brightness);
2899 bt848_contrast(btv,pic->contrast);
2900 bt848_hue(btv,pic->hue);
2901 bt848_sat(btv,pic->colour);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002902 mutex_unlock(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002903 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 }
2905
2906 case VIDIOCGWIN:
2907 {
2908 struct video_window *win = arg;
2909
2910 memset(win,0,sizeof(*win));
2911 win->x = fh->ov.w.left;
2912 win->y = fh->ov.w.top;
2913 win->width = fh->ov.w.width;
2914 win->height = fh->ov.w.height;
2915 return 0;
2916 }
2917 case VIDIOCSWIN:
2918 {
2919 struct video_window *win = arg;
2920 struct v4l2_window w2;
2921
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002922 if (no_overlay > 0) {
2923 printk ("VIDIOCSWIN: no_overlay\n");
2924 return -EINVAL;
2925 }
2926
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 w2.field = V4L2_FIELD_ANY;
2928 w2.w.left = win->x;
2929 w2.w.top = win->y;
2930 w2.w.width = win->width;
2931 w2.w.height = win->height;
2932 w2.clipcount = win->clipcount;
2933 w2.clips = (struct v4l2_clip __user *)win->clips;
2934 retval = setup_window(fh, btv, &w2, 0);
2935 if (0 == retval) {
2936 /* on v4l1 this ioctl affects the read() size too */
2937 fh->width = fh->ov.w.width;
2938 fh->height = fh->ov.w.height;
2939 btv->init.width = fh->ov.w.width;
2940 btv->init.height = fh->ov.w.height;
2941 }
2942 return retval;
2943 }
2944
2945 case VIDIOCGFBUF:
2946 {
2947 struct video_buffer *fbuf = arg;
2948
2949 fbuf->base = btv->fbuf.base;
2950 fbuf->width = btv->fbuf.fmt.width;
2951 fbuf->height = btv->fbuf.fmt.height;
2952 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2953 if (fh->ovfmt)
2954 fbuf->depth = fh->ovfmt->depth;
Mauro Carvalho Chehab37026272006-08-06 09:10:06 -03002955 else {
2956 if (fbuf->width)
2957 fbuf->depth = ((fbuf->bytesperline<<3)
Trent Piephoa2b9e3e2006-08-07 20:01:01 -03002958 + (fbuf->width-1) )
2959 /fbuf->width;
Mauro Carvalho Chehab37026272006-08-06 09:10:06 -03002960 else
2961 fbuf->depth = 0;
2962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 return 0;
2964 }
2965 case VIDIOCSFBUF:
2966 {
2967 struct video_buffer *fbuf = arg;
2968 const struct bttv_format *fmt;
2969 unsigned long end;
2970
2971 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002972 !capable(CAP_SYS_RAWIO))
2973 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 end = (unsigned long)fbuf->base +
2975 fbuf->height * fbuf->bytesperline;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002976 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 retval = -EINVAL;
2978
2979 switch (fbuf->depth) {
2980 case 8:
2981 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2982 break;
2983 case 16:
2984 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2985 break;
2986 case 24:
2987 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2988 break;
2989 case 32:
2990 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2991 break;
2992 case 15:
2993 fbuf->depth = 16;
2994 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2995 break;
2996 default:
2997 fmt = NULL;
2998 break;
2999 }
3000 if (NULL == fmt)
3001 goto fh_unlock_and_return;
3002
3003 fh->ovfmt = fmt;
3004 fh->fmt = fmt;
3005 btv->init.ovfmt = fmt;
3006 btv->init.fmt = fmt;
3007 btv->fbuf.base = fbuf->base;
3008 btv->fbuf.fmt.width = fbuf->width;
3009 btv->fbuf.fmt.height = fbuf->height;
3010 if (fbuf->bytesperline)
3011 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
3012 else
3013 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003014 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 return 0;
3016 }
3017
3018 case VIDIOCCAPTURE:
3019 case VIDIOC_OVERLAY:
3020 {
3021 struct bttv_buffer *new;
3022 int *on = arg;
3023
3024 if (*on) {
3025 /* verify args */
3026 if (NULL == btv->fbuf.base)
3027 return -EINVAL;
3028 if (!fh->ov.setup_ok) {
3029 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
3030 return -EINVAL;
3031 }
3032 }
3033
3034 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
3035 return -EBUSY;
3036
Ingo Molnar3593cab2006-02-07 06:49:14 -02003037 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 if (*on) {
3039 fh->ov.tvnorm = btv->tvnorm;
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003040 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03003041 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
3043 } else {
3044 new = NULL;
3045 }
3046
3047 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003048 retval = bttv_switch_overlay(btv,fh,new);
Ingo Molnar3593cab2006-02-07 06:49:14 -02003049 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 return retval;
3051 }
3052
3053 case VIDIOCGMBUF:
3054 {
3055 struct video_mbuf *mbuf = arg;
3056 unsigned int i;
3057
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
3059 V4L2_MEMORY_MMAP);
3060 if (retval < 0)
Gregor Jasnyd9030f52008-01-06 11:15:54 -03003061 return retval;
Brandon Philips49ee7182007-10-05 16:26:27 -03003062
3063 gbuffers = retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 memset(mbuf,0,sizeof(*mbuf));
3065 mbuf->frames = gbuffers;
3066 mbuf->size = gbuffers * gbufsize;
3067 for (i = 0; i < gbuffers; i++)
3068 mbuf->offsets[i] = i * gbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 return 0;
3070 }
3071 case VIDIOCMCAPTURE:
3072 {
3073 struct video_mmap *vm = arg;
3074 struct bttv_buffer *buf;
3075 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003076 __s32 height2;
3077 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078
3079 if (vm->frame >= VIDEO_MAX_FRAME)
3080 return -EINVAL;
3081
Michael Schimeke5bd0262007-01-18 16:17:39 -03003082 res = bttv_resource(fh);
3083 if (!check_alloc_btres(btv, fh, res))
3084 return -EBUSY;
3085
Ingo Molnar3593cab2006-02-07 06:49:14 -02003086 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 retval = -EINVAL;
3088 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
3089 if (NULL == buf)
3090 goto fh_unlock_and_return;
3091 if (0 == buf->vb.baddr)
3092 goto fh_unlock_and_return;
3093 if (buf->vb.state == STATE_QUEUED ||
3094 buf->vb.state == STATE_ACTIVE)
3095 goto fh_unlock_and_return;
3096
Michael Schimeke5bd0262007-01-18 16:17:39 -03003097 height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
3098 field = (vm->height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 ? V4L2_FIELD_INTERLACED
3100 : V4L2_FIELD_BOTTOM;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03003101 retval = bttv_prepare_buffer(&fh->cap,btv,buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 format_by_palette(vm->format),
3103 vm->width,vm->height,field);
3104 if (0 != retval)
3105 goto fh_unlock_and_return;
Trent Piephoa8ab68b2007-10-22 17:44:55 -03003106 btv->init.width = vm->width;
3107 btv->init.height = vm->height;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 spin_lock_irqsave(&btv->s_lock,flags);
3109 buffer_queue(&fh->cap,&buf->vb);
3110 spin_unlock_irqrestore(&btv->s_lock,flags);
Ingo Molnar3593cab2006-02-07 06:49:14 -02003111 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 return 0;
3113 }
3114 case VIDIOCSYNC:
3115 {
3116 int *frame = arg;
3117 struct bttv_buffer *buf;
3118
3119 if (*frame >= VIDEO_MAX_FRAME)
3120 return -EINVAL;
3121
Ingo Molnar3593cab2006-02-07 06:49:14 -02003122 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 retval = -EINVAL;
3124 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
3125 if (NULL == buf)
3126 goto fh_unlock_and_return;
3127 retval = videobuf_waiton(&buf->vb,0,1);
3128 if (0 != retval)
3129 goto fh_unlock_and_return;
3130 switch (buf->vb.state) {
3131 case STATE_ERROR:
3132 retval = -EIO;
3133 /* fall through */
3134 case STATE_DONE:
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003135 {
3136 struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
3137 videobuf_dma_sync(&fh->cap,dma);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03003138 bttv_dma_free(&fh->cap,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 break;
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 default:
3142 retval = -EINVAL;
3143 break;
3144 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003145 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 return retval;
3147 }
3148
3149 case VIDIOCGVBIFMT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
3151 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
3152 if (0 != retval)
3153 return retval;
3154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
Michael Schimeke5bd0262007-01-18 16:17:39 -03003156 /* fall through */
3157
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 case VIDIOCSVBIFMT:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003159 return v4l_compat_translate_ioctl(inode, file, cmd,
3160 arg, bttv_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003162 case BTTV_VERSION:
3163 case VIDIOCGFREQ:
3164 case VIDIOCSFREQ:
3165 case VIDIOCGTUNER:
3166 case VIDIOCSTUNER:
3167 case VIDIOCGCHAN:
3168 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 case VIDIOCGAUDIO:
3170 case VIDIOCSAUDIO:
3171 return bttv_common_ioctls(btv,cmd,arg);
3172
3173 /* *** v4l2 *** ************************************************ */
3174 case VIDIOC_QUERYCAP:
3175 {
3176 struct v4l2_capability *cap = arg;
3177
3178 if (0 == v4l2)
3179 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08003180 memset(cap, 0, sizeof (*cap));
3181 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
3182 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
3183 snprintf(cap->bus_info, sizeof (cap->bus_info),
3184 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 cap->version = BTTV_VERSION_CODE;
3186 cap->capabilities =
3187 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 V4L2_CAP_VBI_CAPTURE |
3189 V4L2_CAP_READWRITE |
3190 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003191 if (no_overlay <= 0)
3192 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
3193
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
3195 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
3196 cap->capabilities |= V4L2_CAP_TUNER;
3197 return 0;
3198 }
3199
3200 case VIDIOC_ENUM_FMT:
3201 {
3202 struct v4l2_fmtdesc *f = arg;
3203 enum v4l2_buf_type type;
3204 unsigned int i;
3205 int index;
3206
3207 type = f->type;
3208 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
3209 /* vbi */
3210 index = f->index;
3211 if (0 != index)
3212 return -EINVAL;
3213 memset(f,0,sizeof(*f));
3214 f->index = index;
3215 f->type = type;
3216 f->pixelformat = V4L2_PIX_FMT_GREY;
3217 strcpy(f->description,"vbi data");
3218 return 0;
3219 }
3220
3221 /* video capture + overlay */
3222 index = -1;
3223 for (i = 0; i < BTTV_FORMATS; i++) {
3224 if (bttv_formats[i].fourcc != -1)
3225 index++;
3226 if ((unsigned int)index == f->index)
3227 break;
3228 }
3229 if (BTTV_FORMATS == i)
3230 return -EINVAL;
3231
3232 switch (f->type) {
3233 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
3234 break;
3235 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
3236 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
3237 return -EINVAL;
3238 break;
3239 default:
3240 return -EINVAL;
3241 }
3242 memset(f,0,sizeof(*f));
3243 f->index = index;
3244 f->type = type;
3245 f->pixelformat = bttv_formats[i].fourcc;
3246 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
3247 return 0;
3248 }
3249
3250 case VIDIOC_TRY_FMT:
3251 {
3252 struct v4l2_format *f = arg;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003253 return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 }
3255 case VIDIOC_G_FMT:
3256 {
3257 struct v4l2_format *f = arg;
3258 return bttv_g_fmt(fh,f);
3259 }
3260 case VIDIOC_S_FMT:
3261 {
3262 struct v4l2_format *f = arg;
3263 return bttv_s_fmt(fh,btv,f);
3264 }
3265
3266 case VIDIOC_G_FBUF:
3267 {
3268 struct v4l2_framebuffer *fb = arg;
3269
3270 *fb = btv->fbuf;
3271 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
3272 if (fh->ovfmt)
3273 fb->fmt.pixelformat = fh->ovfmt->fourcc;
3274 return 0;
3275 }
3276 case VIDIOC_S_FBUF:
3277 {
3278 struct v4l2_framebuffer *fb = arg;
3279 const struct bttv_format *fmt;
3280
3281 if(!capable(CAP_SYS_ADMIN) &&
3282 !capable(CAP_SYS_RAWIO))
3283 return -EPERM;
3284
3285 /* check args */
3286 fmt = format_by_fourcc(fb->fmt.pixelformat);
3287 if (NULL == fmt)
3288 return -EINVAL;
3289 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
3290 return -EINVAL;
3291
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 retval = -EINVAL;
3293 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03003294 __s32 width = fb->fmt.width;
3295 __s32 height = fb->fmt.height;
3296
3297 retval = limit_scaled_size(fh, &width, &height,
3298 V4L2_FIELD_INTERLACED,
3299 /* width_mask */ ~3,
3300 /* width_bias */ 2,
3301 /* adjust_size */ 0,
3302 /* adjust_crop */ 0);
3303 if (0 != retval)
3304 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 }
3306
3307 /* ok, accept it */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003308 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 btv->fbuf.base = fb->base;
3310 btv->fbuf.fmt.width = fb->fmt.width;
3311 btv->fbuf.fmt.height = fb->fmt.height;
3312 if (0 != fb->fmt.bytesperline)
3313 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
3314 else
3315 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
3316
3317 retval = 0;
3318 fh->ovfmt = fmt;
3319 btv->init.ovfmt = fmt;
3320 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
3321 fh->ov.w.left = 0;
3322 fh->ov.w.top = 0;
3323 fh->ov.w.width = fb->fmt.width;
3324 fh->ov.w.height = fb->fmt.height;
3325 btv->init.ov.w.width = fb->fmt.width;
3326 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08003327 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 fh->ov.clips = NULL;
3329 fh->ov.nclips = 0;
3330
3331 if (check_btres(fh, RESOURCE_OVERLAY)) {
3332 struct bttv_buffer *new;
3333
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003334 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03003335 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
3337 retval = bttv_switch_overlay(btv,fh,new);
3338 }
3339 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003340 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 return retval;
3342 }
3343
3344 case VIDIOC_REQBUFS:
3345 return videobuf_reqbufs(bttv_queue(fh),arg);
3346
3347 case VIDIOC_QUERYBUF:
3348 return videobuf_querybuf(bttv_queue(fh),arg);
3349
3350 case VIDIOC_QBUF:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003351 {
3352 int res = bttv_resource(fh);
3353
3354 if (!check_alloc_btres(btv, fh, res))
3355 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 return videobuf_qbuf(bttv_queue(fh),arg);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358
3359 case VIDIOC_DQBUF:
3360 return videobuf_dqbuf(bttv_queue(fh),arg,
3361 file->f_flags & O_NONBLOCK);
3362
3363 case VIDIOC_STREAMON:
3364 {
3365 int res = bttv_resource(fh);
3366
3367 if (!check_alloc_btres(btv,fh,res))
3368 return -EBUSY;
3369 return videobuf_streamon(bttv_queue(fh));
3370 }
3371 case VIDIOC_STREAMOFF:
3372 {
3373 int res = bttv_resource(fh);
3374
3375 retval = videobuf_streamoff(bttv_queue(fh));
3376 if (retval < 0)
3377 return retval;
3378 free_btres(btv,fh,res);
3379 return 0;
3380 }
3381
3382 case VIDIOC_QUERYCTRL:
3383 {
3384 struct v4l2_queryctrl *c = arg;
3385 int i;
3386
3387 if ((c->id < V4L2_CID_BASE ||
3388 c->id >= V4L2_CID_LASTP1) &&
3389 (c->id < V4L2_CID_PRIVATE_BASE ||
3390 c->id >= V4L2_CID_PRIVATE_LASTP1))
3391 return -EINVAL;
3392 for (i = 0; i < BTTV_CTLS; i++)
3393 if (bttv_ctls[i].id == c->id)
3394 break;
3395 if (i == BTTV_CTLS) {
3396 *c = no_ctl;
3397 return 0;
3398 }
3399 *c = bttv_ctls[i];
Hans Verkuil0020d3e2006-03-30 19:50:34 -03003400 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 struct video_audio va;
3402 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03003403 btv->audio_hook(btv,&va,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 switch (bttv_ctls[i].id) {
3405 case V4L2_CID_AUDIO_VOLUME:
3406 if (!(va.flags & VIDEO_AUDIO_VOLUME))
3407 *c = no_ctl;
3408 break;
3409 case V4L2_CID_AUDIO_BALANCE:
3410 if (!(va.flags & VIDEO_AUDIO_BALANCE))
3411 *c = no_ctl;
3412 break;
3413 case V4L2_CID_AUDIO_BASS:
3414 if (!(va.flags & VIDEO_AUDIO_BASS))
3415 *c = no_ctl;
3416 break;
3417 case V4L2_CID_AUDIO_TREBLE:
3418 if (!(va.flags & VIDEO_AUDIO_TREBLE))
3419 *c = no_ctl;
3420 break;
3421 }
3422 }
3423 return 0;
3424 }
3425 case VIDIOC_G_CTRL:
3426 return get_control(btv,arg);
3427 case VIDIOC_S_CTRL:
3428 return set_control(btv,arg);
3429 case VIDIOC_G_PARM:
3430 {
3431 struct v4l2_streamparm *parm = arg;
3432 struct v4l2_standard s;
3433 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
3434 return -EINVAL;
3435 memset(parm,0,sizeof(*parm));
3436 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
3437 bttv_tvnorms[btv->tvnorm].name);
3438 parm->parm.capture.timeperframe = s.frameperiod;
3439 return 0;
3440 }
3441
3442 case VIDIOC_G_PRIORITY:
3443 {
3444 enum v4l2_priority *p = arg;
3445
3446 *p = v4l2_prio_max(&btv->prio);
3447 return 0;
3448 }
3449 case VIDIOC_S_PRIORITY:
3450 {
3451 enum v4l2_priority *prio = arg;
3452
3453 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
3454 }
3455
Michael Schimeke5bd0262007-01-18 16:17:39 -03003456 case VIDIOC_CROPCAP:
3457 {
3458 struct v4l2_cropcap *cap = arg;
3459 enum v4l2_buf_type type;
3460
3461 type = cap->type;
3462
3463 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3464 type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3465 return -EINVAL;
3466
3467 *cap = bttv_tvnorms[btv->tvnorm].cropcap;
3468 cap->type = type;
3469
3470 return 0;
3471 }
3472 case VIDIOC_G_CROP:
3473 {
3474 struct v4l2_crop * crop = arg;
3475
3476 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3477 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3478 return -EINVAL;
3479
3480 /* No fh->do_crop = 1; because btv->crop[1] may be
3481 inconsistent with fh->width or fh->height and apps
3482 do not expect a change here. */
3483
3484 crop->c = btv->crop[!!fh->do_crop].rect;
3485
3486 return 0;
3487 }
3488 case VIDIOC_S_CROP:
3489 {
3490 struct v4l2_crop *crop = arg;
3491 const struct v4l2_rect *b;
3492 struct bttv_crop c;
3493 __s32 b_left;
3494 __s32 b_top;
3495 __s32 b_right;
3496 __s32 b_bottom;
3497
3498 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3499 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3500 return -EINVAL;
3501
3502 retval = v4l2_prio_check(&btv->prio,&fh->prio);
3503 if (0 != retval)
3504 return retval;
3505
3506 /* Make sure tvnorm, vbi_end and the current cropping
3507 parameters remain consistent until we're done. Note
3508 read() may change vbi_end in check_alloc_btres(). */
3509 mutex_lock(&btv->lock);
3510
3511 retval = -EBUSY;
3512
3513 if (locked_btres(fh->btv, VIDEO_RESOURCES))
3514 goto btv_unlock_and_return;
3515
3516 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
3517
3518 b_left = b->left;
3519 b_right = b_left + b->width;
3520 b_bottom = b->top + b->height;
3521
3522 b_top = max(b->top, btv->vbi_end);
3523 if (b_top + 32 >= b_bottom)
3524 goto btv_unlock_and_return;
3525
3526 /* Min. scaled size 48 x 32. */
3527 c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
3528 c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
3529
3530 c.rect.width = clamp(crop->c.width,
3531 48, b_right - c.rect.left);
3532
3533 c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
3534 /* Top and height must be a multiple of two. */
3535 c.rect.top = (c.rect.top + 1) & ~1;
3536
3537 c.rect.height = clamp(crop->c.height,
3538 32, b_bottom - c.rect.top);
3539 c.rect.height = (c.rect.height + 1) & ~1;
3540
3541 bttv_crop_calc_limits(&c);
3542
3543 btv->crop[1] = c;
3544
3545 mutex_unlock(&btv->lock);
3546
3547 fh->do_crop = 1;
3548
3549 mutex_lock(&fh->cap.lock);
3550
3551 if (fh->width < c.min_scaled_width) {
3552 fh->width = c.min_scaled_width;
3553 btv->init.width = c.min_scaled_width;
3554 } else if (fh->width > c.max_scaled_width) {
3555 fh->width = c.max_scaled_width;
3556 btv->init.width = c.max_scaled_width;
3557 }
3558
3559 if (fh->height < c.min_scaled_height) {
3560 fh->height = c.min_scaled_height;
3561 btv->init.height = c.min_scaled_height;
3562 } else if (fh->height > c.max_scaled_height) {
3563 fh->height = c.max_scaled_height;
3564 btv->init.height = c.max_scaled_height;
3565 }
3566
3567 mutex_unlock(&fh->cap.lock);
3568
3569 return 0;
3570 }
3571
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 case VIDIOC_ENUMSTD:
3573 case VIDIOC_G_STD:
3574 case VIDIOC_S_STD:
3575 case VIDIOC_ENUMINPUT:
3576 case VIDIOC_G_INPUT:
3577 case VIDIOC_S_INPUT:
3578 case VIDIOC_G_TUNER:
3579 case VIDIOC_S_TUNER:
3580 case VIDIOC_G_FREQUENCY:
3581 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08003582 case VIDIOC_LOG_STATUS:
Trent Piepho55c0d102007-06-29 00:17:36 -03003583 case VIDIOC_DBG_G_REGISTER:
3584 case VIDIOC_DBG_S_REGISTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 return bttv_common_ioctls(btv,cmd,arg);
3586
3587 default:
3588 return -ENOIOCTLCMD;
3589 }
3590 return 0;
3591
3592 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02003593 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003595
3596 btv_unlock_and_return:
3597 mutex_unlock(&btv->lock);
3598 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599}
3600
3601static int bttv_ioctl(struct inode *inode, struct file *file,
3602 unsigned int cmd, unsigned long arg)
3603{
3604 struct bttv_fh *fh = file->private_data;
3605
3606 switch (cmd) {
3607 case BTTV_VBISIZE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003608 {
3609 const struct bttv_tvnorm *tvnorm;
3610
3611 tvnorm = fh->vbi_fmt.tvnorm;
3612
3613 if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
3614 fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
3615 fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
3616 /* BTTV_VBISIZE cannot express these parameters,
3617 however open() resets the paramters to defaults
3618 and apps shouldn't call BTTV_VBISIZE after
3619 VIDIOC_S_FMT. */
3620 return -EINVAL;
3621 }
3622
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003624 return (fh->vbi_fmt.fmt.count[0] * 2
3625 * fh->vbi_fmt.fmt.samples_per_line);
3626 }
3627
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 default:
3629 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
3630 }
3631}
3632
3633static ssize_t bttv_read(struct file *file, char __user *data,
3634 size_t count, loff_t *ppos)
3635{
3636 struct bttv_fh *fh = file->private_data;
3637 int retval = 0;
3638
3639 if (fh->btv->errors)
3640 bttv_reinit_bt848(fh->btv);
3641 dprintk("bttv%d: read count=%d type=%s\n",
3642 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
3643
3644 switch (fh->type) {
3645 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003646 if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
3647 /* VIDEO_READ in use by another fh,
3648 or VIDEO_STREAM by any fh. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 return -EBUSY;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 retval = videobuf_read_one(&fh->cap, data, count, ppos,
3652 file->f_flags & O_NONBLOCK);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003653 free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 break;
3655 case V4L2_BUF_TYPE_VBI_CAPTURE:
3656 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3657 return -EBUSY;
3658 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
3659 file->f_flags & O_NONBLOCK);
3660 break;
3661 default:
3662 BUG();
3663 }
3664 return retval;
3665}
3666
3667static unsigned int bttv_poll(struct file *file, poll_table *wait)
3668{
3669 struct bttv_fh *fh = file->private_data;
3670 struct bttv_buffer *buf;
3671 enum v4l2_field field;
3672
3673 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
3674 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3675 return POLLERR;
3676 return videobuf_poll_stream(file, &fh->vbi, wait);
3677 }
3678
Michael Schimeke5bd0262007-01-18 16:17:39 -03003679 if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 /* streaming capture */
3681 if (list_empty(&fh->cap.stream))
3682 return POLLERR;
3683 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
3684 } else {
3685 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02003686 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 if (NULL == fh->cap.read_buf) {
3688 /* need to capture a new frame */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003689 if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003690 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 return POLLERR;
3692 }
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003693 fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003695 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 return POLLERR;
3697 }
3698 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
3699 field = videobuf_next_field(&fh->cap);
3700 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08003701 kfree (fh->cap.read_buf);
3702 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003703 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 return POLLERR;
3705 }
3706 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3707 fh->cap.read_off = 0;
3708 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003709 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 buf = (struct bttv_buffer*)fh->cap.read_buf;
3711 }
3712
3713 poll_wait(file, &buf->vb.done, wait);
3714 if (buf->vb.state == STATE_DONE ||
3715 buf->vb.state == STATE_ERROR)
3716 return POLLIN|POLLRDNORM;
3717 return 0;
3718}
3719
3720static int bttv_open(struct inode *inode, struct file *file)
3721{
3722 int minor = iminor(inode);
3723 struct bttv *btv = NULL;
3724 struct bttv_fh *fh;
3725 enum v4l2_buf_type type = 0;
3726 unsigned int i;
3727
3728 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3729
3730 for (i = 0; i < bttv_num; i++) {
3731 if (bttvs[i].video_dev &&
3732 bttvs[i].video_dev->minor == minor) {
3733 btv = &bttvs[i];
3734 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3735 break;
3736 }
3737 if (bttvs[i].vbi_dev &&
3738 bttvs[i].vbi_dev->minor == minor) {
3739 btv = &bttvs[i];
3740 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3741 break;
3742 }
3743 }
3744 if (NULL == btv)
3745 return -ENODEV;
3746
3747 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3748 btv->c.nr,v4l2_type_names[type]);
3749
3750 /* allocate per filehandle data */
3751 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3752 if (NULL == fh)
3753 return -ENOMEM;
3754 file->private_data = fh;
3755 *fh = btv->init;
3756 fh->type = type;
3757 fh->ov.setup_ok = 0;
3758 v4l2_prio_open(&btv->prio,&fh->prio);
3759
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003760 videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 btv->c.pci, &btv->s_lock,
3762 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3763 V4L2_FIELD_INTERLACED,
3764 sizeof(struct bttv_buffer),
3765 fh);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003766 videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 btv->c.pci, &btv->s_lock,
3768 V4L2_BUF_TYPE_VBI_CAPTURE,
3769 V4L2_FIELD_SEQ_TB,
3770 sizeof(struct bttv_buffer),
3771 fh);
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03003772 set_tvnorm(btv,btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773
3774 btv->users++;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003775
3776 /* The V4L2 spec requires one global set of cropping parameters
3777 which only change on request. These are stored in btv->crop[1].
3778 However for compatibility with V4L apps and cropping unaware
3779 V4L2 apps we now reset the cropping parameters as seen through
3780 this fh, which is to say VIDIOC_G_CROP and scaling limit checks
3781 will use btv->crop[0], the default cropping parameters for the
3782 current video standard, and VIDIOC_S_FMT will not implicitely
3783 change the cropping parameters until VIDIOC_S_CROP has been
3784 called. */
3785 fh->do_crop = !reset_crop; /* module parameter */
3786
3787 /* Likewise there should be one global set of VBI capture
3788 parameters, but for compatibility with V4L apps and earlier
3789 driver versions each fh has its own parameters. */
3790 bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
3791
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 bttv_field_count(btv);
3793 return 0;
3794}
3795
3796static int bttv_release(struct inode *inode, struct file *file)
3797{
3798 struct bttv_fh *fh = file->private_data;
3799 struct bttv *btv = fh->btv;
3800
3801 /* turn off overlay */
3802 if (check_btres(fh, RESOURCE_OVERLAY))
3803 bttv_switch_overlay(btv,fh,NULL);
3804
3805 /* stop video capture */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003806 if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 videobuf_streamoff(&fh->cap);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003808 free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 }
3810 if (fh->cap.read_buf) {
3811 buffer_release(&fh->cap,fh->cap.read_buf);
3812 kfree(fh->cap.read_buf);
3813 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03003814 if (check_btres(fh, RESOURCE_VIDEO_READ)) {
3815 free_btres(btv, fh, RESOURCE_VIDEO_READ);
3816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
3818 /* stop vbi capture */
3819 if (check_btres(fh, RESOURCE_VBI)) {
Brandon Philips053fcb62007-11-13 20:11:26 -03003820 videobuf_stop(&fh->vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 free_btres(btv,fh,RESOURCE_VBI);
3822 }
3823
3824 /* free stuff */
3825 videobuf_mmap_free(&fh->cap);
3826 videobuf_mmap_free(&fh->vbi);
3827 v4l2_prio_close(&btv->prio,&fh->prio);
3828 file->private_data = NULL;
3829 kfree(fh);
3830
3831 btv->users--;
3832 bttv_field_count(btv);
3833 return 0;
3834}
3835
3836static int
3837bttv_mmap(struct file *file, struct vm_area_struct *vma)
3838{
3839 struct bttv_fh *fh = file->private_data;
3840
3841 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3842 fh->btv->c.nr, v4l2_type_names[fh->type],
3843 vma->vm_start, vma->vm_end - vma->vm_start);
3844 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3845}
3846
Arjan van de Venfa027c22007-02-12 00:55:33 -08003847static const struct file_operations bttv_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848{
3849 .owner = THIS_MODULE,
3850 .open = bttv_open,
3851 .release = bttv_release,
3852 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003853 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 .llseek = no_llseek,
3855 .read = bttv_read,
3856 .mmap = bttv_mmap,
3857 .poll = bttv_poll,
3858};
3859
3860static struct video_device bttv_video_template =
3861{
3862 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003863 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003864 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 .fops = &bttv_fops,
3866 .minor = -1,
3867};
3868
3869static struct video_device bttv_vbi_template =
3870{
3871 .name = "bt848/878 vbi",
3872 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 .fops = &bttv_fops,
3874 .minor = -1,
3875};
3876
3877/* ----------------------------------------------------------------------- */
3878/* radio interface */
3879
3880static int radio_open(struct inode *inode, struct file *file)
3881{
3882 int minor = iminor(inode);
3883 struct bttv *btv = NULL;
3884 unsigned int i;
3885
3886 dprintk("bttv: open minor=%d\n",minor);
3887
3888 for (i = 0; i < bttv_num; i++) {
3889 if (bttvs[i].radio_dev->minor == minor) {
3890 btv = &bttvs[i];
3891 break;
3892 }
3893 }
3894 if (NULL == btv)
3895 return -ENODEV;
3896
3897 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003898 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003899
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003901
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 file->private_data = btv;
3903
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003904 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3905 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003907 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003908 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909}
3910
3911static int radio_release(struct inode *inode, struct file *file)
3912{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003913 struct bttv *btv = file->private_data;
3914 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
3916 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003917
3918 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3919
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 return 0;
3921}
3922
3923static int radio_do_ioctl(struct inode *inode, struct file *file,
3924 unsigned int cmd, void *arg)
3925{
3926 struct bttv *btv = file->private_data;
3927
3928 switch (cmd) {
3929 case VIDIOCGCAP:
3930 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003931 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932
3933 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003934 strcpy(cap->name,btv->radio_dev->name);
3935 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 cap->channels = 1;
3937 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003938 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 }
3940
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003941 case VIDIOCGTUNER:
3942 {
3943 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003945 if(v->tuner)
3946 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003948 strcpy(v->name, "Radio");
3949 bttv_call_i2c_clients(btv,cmd,v);
3950 return 0;
3951 }
3952 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 /* nothing to do */
3954 return 0;
3955
3956 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003957 case VIDIOCGFREQ:
3958 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 case VIDIOCGAUDIO:
3960 case VIDIOCSAUDIO:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003961 case VIDIOC_LOG_STATUS:
Trent Piepho55c0d102007-06-29 00:17:36 -03003962 case VIDIOC_DBG_G_REGISTER:
3963 case VIDIOC_DBG_S_REGISTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 return bttv_common_ioctls(btv,cmd,arg);
3965
3966 default:
3967 return -ENOIOCTLCMD;
3968 }
3969 return 0;
3970}
3971
3972static int radio_ioctl(struct inode *inode, struct file *file,
3973 unsigned int cmd, unsigned long arg)
3974{
3975 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3976}
3977
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003978static ssize_t radio_read(struct file *file, char __user *data,
3979 size_t count, loff_t *ppos)
3980{
3981 struct bttv *btv = file->private_data;
3982 struct rds_command cmd;
3983 cmd.block_count = count/3;
3984 cmd.buffer = data;
3985 cmd.instance = file;
3986 cmd.result = -ENODEV;
3987
3988 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3989
3990 return cmd.result;
3991}
3992
3993static unsigned int radio_poll(struct file *file, poll_table *wait)
3994{
3995 struct bttv *btv = file->private_data;
3996 struct rds_command cmd;
3997 cmd.instance = file;
3998 cmd.event_list = wait;
3999 cmd.result = -ENODEV;
4000 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
4001
4002 return cmd.result;
4003}
4004
Arjan van de Venfa027c22007-02-12 00:55:33 -08004005static const struct file_operations radio_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006{
4007 .owner = THIS_MODULE,
4008 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07004009 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 .release = radio_release,
4011 .ioctl = radio_ioctl,
4012 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07004013 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014};
4015
4016static struct video_device radio_template =
4017{
4018 .name = "bt848/878 radio",
4019 .type = VID_TYPE_TUNER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 .fops = &radio_fops,
4021 .minor = -1,
4022};
4023
4024/* ----------------------------------------------------------------------- */
4025/* some debug code */
4026
Adrian Bunk408b6642005-05-01 08:59:29 -07004027static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028{
4029 static char *instr[16] = {
4030 [ BT848_RISC_WRITE >> 28 ] = "write",
4031 [ BT848_RISC_SKIP >> 28 ] = "skip",
4032 [ BT848_RISC_WRITEC >> 28 ] = "writec",
4033 [ BT848_RISC_JUMP >> 28 ] = "jump",
4034 [ BT848_RISC_SYNC >> 28 ] = "sync",
4035 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
4036 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
4037 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
4038 };
4039 static int incr[16] = {
4040 [ BT848_RISC_WRITE >> 28 ] = 2,
4041 [ BT848_RISC_JUMP >> 28 ] = 2,
4042 [ BT848_RISC_SYNC >> 28 ] = 2,
4043 [ BT848_RISC_WRITE123 >> 28 ] = 5,
4044 [ BT848_RISC_SKIP123 >> 28 ] = 2,
4045 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
4046 };
4047 static char *bits[] = {
4048 "be0", "be1", "be2", "be3/resync",
4049 "set0", "set1", "set2", "set3",
4050 "clr0", "clr1", "clr2", "clr3",
4051 "irq", "res", "eol", "sol",
4052 };
4053 int i;
4054
4055 printk("0x%08x [ %s", risc,
4056 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
4057 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
4058 if (risc & (1 << (i + 12)))
4059 printk(" %s",bits[i]);
4060 printk(" count=%d ]\n", risc & 0xfff);
4061 return incr[risc >> 28] ? incr[risc >> 28] : 1;
4062}
4063
Adrian Bunk408b6642005-05-01 08:59:29 -07004064static void bttv_risc_disasm(struct bttv *btv,
4065 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066{
4067 unsigned int i,j,n;
4068
4069 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
4070 btv->c.name, risc->cpu, (unsigned long)risc->dma);
4071 for (i = 0; i < (risc->size >> 2); i += n) {
4072 printk("%s: 0x%lx: ", btv->c.name,
4073 (unsigned long)(risc->dma + (i<<2)));
4074 n = bttv_risc_decode(risc->cpu[i]);
4075 for (j = 1; j < n; j++)
4076 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
4077 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
4078 risc->cpu[i+j], j);
4079 if (0 == risc->cpu[i])
4080 break;
4081 }
4082}
4083
4084static void bttv_print_riscaddr(struct bttv *btv)
4085{
4086 printk(" main: %08Lx\n",
4087 (unsigned long long)btv->main.dma);
4088 printk(" vbi : o=%08Lx e=%08Lx\n",
4089 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
4090 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
4091 printk(" cap : o=%08Lx e=%08Lx\n",
4092 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
4093 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
4094 printk(" scr : o=%08Lx e=%08Lx\n",
4095 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
4096 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
4097 bttv_risc_disasm(btv, &btv->main);
4098}
4099
4100/* ----------------------------------------------------------------------- */
4101/* irq handler */
4102
4103static char *irq_name[] = {
4104 "FMTCHG", // format change detected (525 vs. 625)
4105 "VSYNC", // vertical sync (new field)
4106 "HSYNC", // horizontal sync
4107 "OFLOW", // chroma/luma AGC overflow
4108 "HLOCK", // horizontal lock changed
4109 "VPRES", // video presence changed
4110 "6", "7",
4111 "I2CDONE", // hw irc operation finished
4112 "GPINT", // gpio port triggered irq
4113 "10",
4114 "RISCI", // risc instruction triggered irq
4115 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
4116 "FTRGT", // pixel data fifo overrun
4117 "FDSR", // fifo data stream resyncronisation
4118 "PPERR", // parity error (data transfer)
4119 "RIPERR", // parity error (read risc instructions)
4120 "PABORT", // pci abort
4121 "OCERR", // risc instruction error
4122 "SCERR", // syncronisation error
4123};
4124
4125static void bttv_print_irqbits(u32 print, u32 mark)
4126{
4127 unsigned int i;
4128
4129 printk("bits:");
4130 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
4131 if (print & (1 << i))
4132 printk(" %s",irq_name[i]);
4133 if (mark & (1 << i))
4134 printk("*");
4135 }
4136}
4137
4138static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
4139{
4140 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
4141 btv->c.nr,
4142 (unsigned long)btv->main.dma,
4143 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
4144 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
4145 (unsigned long)rc);
4146
4147 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
4148 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
4149 "Ok, then this is harmless, don't worry ;)\n",
4150 btv->c.nr);
4151 return;
4152 }
4153 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
4154 btv->c.nr);
4155 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
4156 btv->c.nr);
4157 dump_stack();
4158}
4159
4160static int
4161bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
4162{
4163 struct bttv_buffer *item;
4164
4165 memset(set,0,sizeof(*set));
4166
4167 /* capture request ? */
4168 if (!list_empty(&btv->capture)) {
4169 set->frame_irq = 1;
4170 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
4171 if (V4L2_FIELD_HAS_TOP(item->vb.field))
4172 set->top = item;
4173 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
4174 set->bottom = item;
4175
4176 /* capture request for other field ? */
4177 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
4178 (item->vb.queue.next != &btv->capture)) {
4179 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
4180 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
4181 if (NULL == set->top &&
4182 V4L2_FIELD_TOP == item->vb.field) {
4183 set->top = item;
4184 }
4185 if (NULL == set->bottom &&
4186 V4L2_FIELD_BOTTOM == item->vb.field) {
4187 set->bottom = item;
4188 }
4189 if (NULL != set->top && NULL != set->bottom)
4190 set->top_irq = 2;
4191 }
4192 }
4193 }
4194
4195 /* screen overlay ? */
4196 if (NULL != btv->screen) {
4197 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
4198 if (NULL == set->top && NULL == set->bottom) {
4199 set->top = btv->screen;
4200 set->bottom = btv->screen;
4201 }
4202 } else {
4203 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
4204 NULL == set->top) {
4205 set->top = btv->screen;
4206 }
4207 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
4208 NULL == set->bottom) {
4209 set->bottom = btv->screen;
4210 }
4211 }
4212 }
4213
4214 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
4215 btv->c.nr,set->top, set->bottom,
4216 btv->screen,set->frame_irq,set->top_irq);
4217 return 0;
4218}
4219
4220static void
4221bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
4222 struct bttv_buffer_set *curr, unsigned int state)
4223{
4224 struct timeval ts;
4225
4226 do_gettimeofday(&ts);
4227
4228 if (wakeup->top == wakeup->bottom) {
4229 if (NULL != wakeup->top && curr->top != wakeup->top) {
4230 if (irq_debug > 1)
4231 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
4232 wakeup->top->vb.ts = ts;
4233 wakeup->top->vb.field_count = btv->field_count;
4234 wakeup->top->vb.state = state;
4235 wake_up(&wakeup->top->vb.done);
4236 }
4237 } else {
4238 if (NULL != wakeup->top && curr->top != wakeup->top) {
4239 if (irq_debug > 1)
4240 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
4241 wakeup->top->vb.ts = ts;
4242 wakeup->top->vb.field_count = btv->field_count;
4243 wakeup->top->vb.state = state;
4244 wake_up(&wakeup->top->vb.done);
4245 }
4246 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
4247 if (irq_debug > 1)
4248 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
4249 wakeup->bottom->vb.ts = ts;
4250 wakeup->bottom->vb.field_count = btv->field_count;
4251 wakeup->bottom->vb.state = state;
4252 wake_up(&wakeup->bottom->vb.done);
4253 }
4254 }
4255}
4256
4257static void
4258bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
4259 unsigned int state)
4260{
4261 struct timeval ts;
4262
4263 if (NULL == wakeup)
4264 return;
4265
4266 do_gettimeofday(&ts);
4267 wakeup->vb.ts = ts;
4268 wakeup->vb.field_count = btv->field_count;
4269 wakeup->vb.state = state;
4270 wake_up(&wakeup->vb.done);
4271}
4272
4273static void bttv_irq_timeout(unsigned long data)
4274{
4275 struct bttv *btv = (struct bttv *)data;
4276 struct bttv_buffer_set old,new;
4277 struct bttv_buffer *ovbi;
4278 struct bttv_buffer *item;
4279 unsigned long flags;
4280
4281 if (bttv_verbose) {
4282 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
4283 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
4284 btread(BT848_RISC_COUNT));
4285 bttv_print_irqbits(btread(BT848_INT_STAT),0);
4286 printk("\n");
4287 }
4288
4289 spin_lock_irqsave(&btv->s_lock,flags);
4290
4291 /* deactivate stuff */
4292 memset(&new,0,sizeof(new));
4293 old = btv->curr;
4294 ovbi = btv->cvbi;
4295 btv->curr = new;
4296 btv->cvbi = NULL;
4297 btv->loop_irq = 0;
4298 bttv_buffer_activate_video(btv, &new);
4299 bttv_buffer_activate_vbi(btv, NULL);
4300 bttv_set_dma(btv, 0);
4301
4302 /* wake up */
4303 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
4304 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
4305
4306 /* cancel all outstanding capture / vbi requests */
4307 while (!list_empty(&btv->capture)) {
4308 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
4309 list_del(&item->vb.queue);
4310 item->vb.state = STATE_ERROR;
4311 wake_up(&item->vb.done);
4312 }
4313 while (!list_empty(&btv->vcapture)) {
4314 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
4315 list_del(&item->vb.queue);
4316 item->vb.state = STATE_ERROR;
4317 wake_up(&item->vb.done);
4318 }
4319
4320 btv->errors++;
4321 spin_unlock_irqrestore(&btv->s_lock,flags);
4322}
4323
4324static void
4325bttv_irq_wakeup_top(struct bttv *btv)
4326{
4327 struct bttv_buffer *wakeup = btv->curr.top;
4328
4329 if (NULL == wakeup)
4330 return;
4331
4332 spin_lock(&btv->s_lock);
4333 btv->curr.top_irq = 0;
4334 btv->curr.top = NULL;
4335 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
4336
4337 do_gettimeofday(&wakeup->vb.ts);
4338 wakeup->vb.field_count = btv->field_count;
4339 wakeup->vb.state = STATE_DONE;
4340 wake_up(&wakeup->vb.done);
4341 spin_unlock(&btv->s_lock);
4342}
4343
4344static inline int is_active(struct btcx_riscmem *risc, u32 rc)
4345{
4346 if (rc < risc->dma)
4347 return 0;
4348 if (rc > risc->dma + risc->size)
4349 return 0;
4350 return 1;
4351}
4352
4353static void
4354bttv_irq_switch_video(struct bttv *btv)
4355{
4356 struct bttv_buffer_set new;
4357 struct bttv_buffer_set old;
4358 dma_addr_t rc;
4359
4360 spin_lock(&btv->s_lock);
4361
4362 /* new buffer set */
4363 bttv_irq_next_video(btv, &new);
4364 rc = btread(BT848_RISC_COUNT);
4365 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
4366 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
4367 btv->framedrop++;
4368 if (debug_latency)
4369 bttv_irq_debug_low_latency(btv, rc);
4370 spin_unlock(&btv->s_lock);
4371 return;
4372 }
4373
4374 /* switch over */
4375 old = btv->curr;
4376 btv->curr = new;
4377 btv->loop_irq &= ~1;
4378 bttv_buffer_activate_video(btv, &new);
4379 bttv_set_dma(btv, 0);
4380
4381 /* switch input */
4382 if (UNSET != btv->new_input) {
4383 video_mux(btv,btv->new_input);
4384 btv->new_input = UNSET;
4385 }
4386
4387 /* wake up finished buffers */
4388 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
4389 spin_unlock(&btv->s_lock);
4390}
4391
4392static void
4393bttv_irq_switch_vbi(struct bttv *btv)
4394{
4395 struct bttv_buffer *new = NULL;
4396 struct bttv_buffer *old;
4397 u32 rc;
4398
4399 spin_lock(&btv->s_lock);
4400
4401 if (!list_empty(&btv->vcapture))
4402 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
4403 old = btv->cvbi;
4404
4405 rc = btread(BT848_RISC_COUNT);
4406 if (NULL != old && (is_active(&old->top, rc) ||
4407 is_active(&old->bottom, rc))) {
4408 btv->framedrop++;
4409 if (debug_latency)
4410 bttv_irq_debug_low_latency(btv, rc);
4411 spin_unlock(&btv->s_lock);
4412 return;
4413 }
4414
4415 /* switch */
4416 btv->cvbi = new;
4417 btv->loop_irq &= ~4;
4418 bttv_buffer_activate_vbi(btv, new);
4419 bttv_set_dma(btv, 0);
4420
4421 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
4422 spin_unlock(&btv->s_lock);
4423}
4424
David Howells7d12e782006-10-05 14:55:46 +01004425static irqreturn_t bttv_irq(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426{
4427 u32 stat,astat;
4428 u32 dstat;
4429 int count;
4430 struct bttv *btv;
4431 int handled = 0;
4432
4433 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08004434
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004435 if (btv->custom_irq)
4436 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08004437
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 count=0;
4439 while (1) {
4440 /* get/clear interrupt status bits */
4441 stat=btread(BT848_INT_STAT);
4442 astat=stat&btread(BT848_INT_MASK);
4443 if (!astat)
4444 break;
4445 handled = 1;
4446 btwrite(stat,BT848_INT_STAT);
4447
4448 /* get device status bits */
4449 dstat=btread(BT848_DSTATUS);
4450
4451 if (irq_debug) {
4452 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
4453 "riscs=%x, riscc=%08x, ",
4454 btv->c.nr, count, btv->field_count,
4455 stat>>28, btread(BT848_RISC_COUNT));
4456 bttv_print_irqbits(stat,astat);
4457 if (stat & BT848_INT_HLOCK)
4458 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
4459 ? "yes" : "no");
4460 if (stat & BT848_INT_VPRES)
4461 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
4462 ? "yes" : "no");
4463 if (stat & BT848_INT_FMTCHG)
4464 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
4465 ? "625" : "525");
4466 printk("\n");
4467 }
4468
4469 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004470 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004472 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004474 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 }
4476
4477 if (astat & BT848_INT_I2CDONE) {
4478 btv->i2c_done = stat;
4479 wake_up(&btv->i2c_queue);
4480 }
4481
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004482 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 bttv_irq_switch_vbi(btv);
4484
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004485 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 bttv_irq_wakeup_top(btv);
4487
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004488 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 bttv_irq_switch_video(btv);
4490
4491 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004492 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
4494 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
4495 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
4496 (astat & BT848_INT_SCERR) ? "SCERR" : "",
4497 (astat & BT848_INT_OCERR) ? "OCERR" : "",
4498 btread(BT848_RISC_COUNT));
4499 bttv_print_irqbits(stat,astat);
4500 printk("\n");
4501 if (bttv_debug)
4502 bttv_print_riscaddr(btv);
4503 }
4504 if (fdsr && astat & BT848_INT_FDSR) {
4505 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
4506 btv->c.nr,btread(BT848_RISC_COUNT));
4507 if (bttv_debug)
4508 bttv_print_riscaddr(btv);
4509 }
4510
4511 count++;
4512 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004513
4514 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004515 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004516
4517 printk(KERN_ERR
4518 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
4519 } else {
4520 printk(KERN_ERR
4521 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
4522
4523 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
4524 BT848_INT_MASK);
4525 };
4526
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004528
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 printk("]\n");
4530 }
4531 }
4532 btv->irq_total++;
4533 if (handled)
4534 btv->irq_me++;
4535 return IRQ_RETVAL(handled);
4536}
4537
4538
4539/* ----------------------------------------------------------------------- */
4540/* initialitation */
4541
4542static struct video_device *vdev_init(struct bttv *btv,
4543 struct video_device *template,
4544 char *type)
4545{
4546 struct video_device *vfd;
4547
4548 vfd = video_device_alloc();
4549 if (NULL == vfd)
4550 return NULL;
4551 *vfd = *template;
4552 vfd->minor = -1;
4553 vfd->dev = &btv->c.pci->dev;
4554 vfd->release = video_device_release;
4555 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
4556 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
4557 type, bttv_tvcards[btv->c.type].name);
4558 return vfd;
4559}
4560
4561static void bttv_unregister_video(struct bttv *btv)
4562{
4563 if (btv->video_dev) {
4564 if (-1 != btv->video_dev->minor)
4565 video_unregister_device(btv->video_dev);
4566 else
4567 video_device_release(btv->video_dev);
4568 btv->video_dev = NULL;
4569 }
4570 if (btv->vbi_dev) {
4571 if (-1 != btv->vbi_dev->minor)
4572 video_unregister_device(btv->vbi_dev);
4573 else
4574 video_device_release(btv->vbi_dev);
4575 btv->vbi_dev = NULL;
4576 }
4577 if (btv->radio_dev) {
4578 if (-1 != btv->radio_dev->minor)
4579 video_unregister_device(btv->radio_dev);
4580 else
4581 video_device_release(btv->radio_dev);
4582 btv->radio_dev = NULL;
4583 }
4584}
4585
4586/* register video4linux devices */
4587static int __devinit bttv_register_video(struct bttv *btv)
4588{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07004589 if (no_overlay <= 0) {
4590 bttv_video_template.type |= VID_TYPE_OVERLAY;
4591 } else {
4592 printk("bttv: Overlay support disabled.\n");
4593 }
4594
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 /* video */
4596 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004597 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 goto err;
4599 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
4600 goto err;
4601 printk(KERN_INFO "bttv%d: registered device video%d\n",
4602 btv->c.nr,btv->video_dev->minor & 0x1f);
Kay Sievers54bd5b62007-10-08 16:26:13 -03004603 if (device_create_file(&btv->video_dev->class_dev,
4604 &dev_attr_card)<0) {
4605 printk(KERN_ERR "bttv%d: device_create_file 'card' "
Trent Piephod94fc9a2006-07-29 17:18:06 -03004606 "failed\n", btv->c.nr);
4607 goto err;
4608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609
4610 /* vbi */
4611 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004612 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004614 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 goto err;
4616 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
4617 btv->c.nr,btv->vbi_dev->minor & 0x1f);
4618
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004619 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 return 0;
4621 /* radio */
4622 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004623 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 goto err;
4625 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
4626 goto err;
4627 printk(KERN_INFO "bttv%d: registered device radio%d\n",
4628 btv->c.nr,btv->radio_dev->minor & 0x1f);
4629
4630 /* all done */
4631 return 0;
4632
4633 err:
4634 bttv_unregister_video(btv);
4635 return -1;
4636}
4637
4638
4639/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
4640/* response on cards with no firmware is not enabled by OF */
4641static void pci_set_command(struct pci_dev *dev)
4642{
4643#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004644 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004646 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
4647 cmd = (cmd | PCI_COMMAND_MEMORY );
4648 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649#endif
4650}
4651
4652static int __devinit bttv_probe(struct pci_dev *dev,
4653 const struct pci_device_id *pci_id)
4654{
4655 int result;
4656 unsigned char lat;
4657 struct bttv *btv;
4658
4659 if (bttv_num == BTTV_MAX)
4660 return -ENOMEM;
4661 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004662 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 memset(btv,0,sizeof(*btv));
4664 btv->c.nr = bttv_num;
4665 sprintf(btv->c.name,"bttv%d",btv->c.nr);
4666
4667 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02004668 mutex_init(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004669 spin_lock_init(&btv->s_lock);
4670 spin_lock_init(&btv->gpio_lock);
4671 init_waitqueue_head(&btv->gpioq);
4672 init_waitqueue_head(&btv->i2c_queue);
4673 INIT_LIST_HEAD(&btv->c.subs);
4674 INIT_LIST_HEAD(&btv->capture);
4675 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 v4l2_prio_init(&btv->prio);
4677
4678 init_timer(&btv->timeout);
4679 btv->timeout.function = bttv_irq_timeout;
4680 btv->timeout.data = (unsigned long)btv;
4681
Michael Krufky7c08fb02005-11-08 21:36:21 -08004682 btv->i2c_rc = -1;
4683 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 btv->has_radio=radio[btv->c.nr];
4686
4687 /* pci stuff (init, get irq/mmio, ... */
4688 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08004689 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08004691 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 btv->c.nr);
4693 return -EIO;
4694 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004695 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
4696 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 btv->c.nr);
4698 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700 if (!request_mem_region(pci_resource_start(dev,0),
4701 pci_resource_len(dev,0),
4702 btv->c.name)) {
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004703 printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
4704 btv->c.nr,
4705 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 return -EBUSY;
4707 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004708 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 pci_set_command(dev);
4710 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004712 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
4713 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
4714 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
4715 bttv_num,btv->id, btv->revision, pci_name(dev));
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004716 printk("irq: %d, latency: %d, mmio: 0x%llx\n",
4717 btv->c.pci->irq, lat,
4718 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 schedule();
4720
Akinobu Mita5f1693f2006-12-20 10:08:56 -03004721 btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
4722 if (NULL == btv->bt848_mmio) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4724 result = -EIO;
4725 goto fail1;
4726 }
4727
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004728 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 bttv_idcard(btv);
4730
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004731 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004733 result = request_irq(btv->c.pci->irq, bttv_irq,
Thomas Gleixner8076fe32006-07-01 19:29:37 -07004734 IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004735 if (result < 0) {
4736 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 bttv_num,btv->c.pci->irq);
4738 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740
4741 if (0 != bttv_handle_chipset(btv)) {
4742 result = -EIO;
4743 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745
4746 /* init options from insmod args */
4747 btv->opt_combfilter = combfilter;
4748 btv->opt_lumafilter = lumafilter;
4749 btv->opt_automute = automute;
4750 btv->opt_chroma_agc = chroma_agc;
4751 btv->opt_adc_crush = adc_crush;
4752 btv->opt_vcr_hack = vcr_hack;
4753 btv->opt_whitecrush_upper = whitecrush_upper;
4754 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004755 btv->opt_uv_ratio = uv_ratio;
4756 btv->opt_full_luma_range = full_luma_range;
4757 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
4759 /* fill struct bttv with some useful defaults */
4760 btv->init.btv = btv;
4761 btv->init.ov.w.width = 320;
4762 btv->init.ov.w.height = 240;
4763 btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
4764 btv->init.width = 320;
4765 btv->init.height = 240;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 btv->input = 0;
4767
4768 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004769 if (bttv_gpio)
4770 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
4772 bttv_risc_init_main(btv);
4773 init_bt848(btv);
4774
4775 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004776 btwrite(0x00, BT848_GPIO_REG_INP);
4777 btwrite(0x00, BT848_GPIO_OUT_EN);
4778 if (bttv_verbose)
4779 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004781 /* needs to be done before i2c is registered */
4782 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004784 /* register i2c + gpio */
4785 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004787 /* some card-specific stuff (needs working i2c) */
4788 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 init_irqreg(btv);
4790
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004791 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 if (!bttv_tvcards[btv->c.type].no_video) {
4793 bttv_register_video(btv);
4794 bt848_bright(btv,32768);
4795 bt848_contrast(btv,32768);
4796 bt848_hue(btv,32768);
4797 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004798 audio_mute(btv, 1);
Trent Piepho333408f2007-07-03 15:08:10 -03004799 set_input(btv, 0, btv->tvnorm);
Michael Schimeke5bd0262007-01-18 16:17:39 -03004800 bttv_crop_reset(&btv->crop[0], btv->tvnorm);
4801 btv->crop[1] = btv->crop[0]; /* current = default */
4802 disclaim_vbi_lines(btv);
4803 disclaim_video_lines(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 }
4805
Jarod Wilsonf992a492007-03-24 15:23:50 -03004806 /* add subdevices and autoload dvb-bt8xx if needed */
4807 if (bttv_tvcards[btv->c.type].has_dvb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 bttv_sub_add_device(&btv->c, "dvb");
Jarod Wilsonf992a492007-03-24 15:23:50 -03004809 request_modules(btv);
4810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004812 bttv_input_init(btv);
4813
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 /* everything is fine */
4815 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004816 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
4818 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004819 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820
4821 fail1:
4822 if (btv->bt848_mmio)
4823 iounmap(btv->bt848_mmio);
4824 release_mem_region(pci_resource_start(btv->c.pci,0),
4825 pci_resource_len(btv->c.pci,0));
4826 pci_set_drvdata(dev,NULL);
4827 return result;
4828}
4829
4830static void __devexit bttv_remove(struct pci_dev *pci_dev)
4831{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004832 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
4834 if (bttv_verbose)
4835 printk("bttv%d: unloading\n",btv->c.nr);
4836
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004837 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 btand(~15, BT848_GPIO_DMA_CTL);
4839 btwrite(0, BT848_INT_MASK);
4840 btwrite(~0x0, BT848_INT_STAT);
4841 btwrite(0x0, BT848_GPIO_OUT_EN);
4842 if (bttv_gpio)
4843 bttv_gpio_tracking(btv,"cleanup");
4844
4845 /* tell gpio modules we are leaving ... */
4846 btv->shutdown=1;
4847 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004848 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004849 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004851 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 fini_bttv_i2c(btv);
4853
4854 /* unregister video4linux */
4855 bttv_unregister_video(btv);
4856
4857 /* free allocated memory */
4858 btcx_riscmem_free(btv->c.pci,&btv->main);
4859
4860 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004861 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004863 release_mem_region(pci_resource_start(btv->c.pci,0),
4864 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
4866 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004867 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868}
4869
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004870#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4872{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004873 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 struct bttv_buffer_set idle;
4875 unsigned long flags;
4876
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004877 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878
4879 /* stop dma + irqs */
4880 spin_lock_irqsave(&btv->s_lock,flags);
4881 memset(&idle, 0, sizeof(idle));
4882 btv->state.video = btv->curr;
4883 btv->state.vbi = btv->cvbi;
4884 btv->state.loop_irq = btv->loop_irq;
4885 btv->curr = idle;
4886 btv->loop_irq = 0;
4887 bttv_buffer_activate_video(btv, &idle);
4888 bttv_buffer_activate_vbi(btv, NULL);
4889 bttv_set_dma(btv, 0);
4890 btwrite(0, BT848_INT_MASK);
4891 spin_unlock_irqrestore(&btv->s_lock,flags);
4892
4893 /* save bt878 state */
4894 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4895 btv->state.gpio_data = gpio_read();
4896
4897 /* save pci state */
4898 pci_save_state(pci_dev);
4899 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4900 pci_disable_device(pci_dev);
4901 btv->state.disabled = 1;
4902 }
4903 return 0;
4904}
4905
4906static int bttv_resume(struct pci_dev *pci_dev)
4907{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004908 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004910 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911
4912 dprintk("bttv%d: resume\n", btv->c.nr);
4913
4914 /* restore pci state */
4915 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004916 err=pci_enable_device(pci_dev);
4917 if (err) {
4918 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4919 btv->c.nr);
4920 return err;
4921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 btv->state.disabled = 0;
4923 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004924 err=pci_set_power_state(pci_dev, PCI_D0);
4925 if (err) {
4926 pci_disable_device(pci_dev);
4927 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4928 btv->c.nr);
4929 btv->state.disabled = 1;
4930 return err;
4931 }
4932
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 pci_restore_state(pci_dev);
4934
4935 /* restore bt878 state */
4936 bttv_reinit_bt848(btv);
4937 gpio_inout(0xffffff, btv->state.gpio_enable);
4938 gpio_write(btv->state.gpio_data);
4939
4940 /* restart dma */
4941 spin_lock_irqsave(&btv->s_lock,flags);
4942 btv->curr = btv->state.video;
4943 btv->cvbi = btv->state.vbi;
4944 btv->loop_irq = btv->state.loop_irq;
4945 bttv_buffer_activate_video(btv, &btv->curr);
4946 bttv_buffer_activate_vbi(btv, btv->cvbi);
4947 bttv_set_dma(btv, 0);
4948 spin_unlock_irqrestore(&btv->s_lock,flags);
4949 return 0;
4950}
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004951#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
4953static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004954 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4955 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004957 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004959 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004961 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4962 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963};
4964
4965MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4966
4967static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004968 .name = "bttv",
4969 .id_table = bttv_pci_tbl,
4970 .probe = bttv_probe,
4971 .remove = __devexit_p(bttv_remove),
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004972#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 .suspend = bttv_suspend,
4974 .resume = bttv_resume,
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004975#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976};
4977
Adrian Bunk7d44e892007-12-11 19:23:43 -03004978static int __init bttv_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979{
Randy Dunlapc526e222006-07-15 09:08:26 -03004980 int ret;
4981
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 bttv_num = 0;
4983
4984 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4985 (BTTV_VERSION_CODE >> 16) & 0xff,
4986 (BTTV_VERSION_CODE >> 8) & 0xff,
4987 BTTV_VERSION_CODE & 0xff);
4988#ifdef SNAPSHOT
4989 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4990 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4991#endif
4992 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4993 gbuffers = 2;
4994 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4995 gbufsize = BTTV_MAX_FBUF;
4996 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4997 if (bttv_verbose)
4998 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4999 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
5000
5001 bttv_check_chipset();
5002
Randy Dunlapc526e222006-07-15 09:08:26 -03005003 ret = bus_register(&bttv_sub_bus_type);
5004 if (ret < 0) {
5005 printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
5006 return ret;
5007 }
Otavio Salvador23047592006-01-09 15:25:17 -02005008 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009}
5010
Adrian Bunk7d44e892007-12-11 19:23:43 -03005011static void __exit bttv_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012{
5013 pci_unregister_driver(&bttv_pci_driver);
5014 bus_unregister(&bttv_sub_bus_type);
5015 return;
5016}
5017
5018module_init(bttv_init_module);
5019module_exit(bttv_cleanup_module);
5020
5021/*
5022 * Local variables:
5023 * c-basic-offset: 8
5024 * End:
5025 */