blob: 061f52ba824a705d3fc1f799f587cdd1ba9e7c17 [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
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -030012 V4L1 removal from:
13 (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
14
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -030015 Fixes to be fully V4L2 compliant by
16 (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
17
Michael Schimeke5bd0262007-01-18 16:17:39 -030018 Cropping and overscan support
19 Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
20 Sponsored by OPQ Systems AB
21
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 This program is free software; you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24 the Free Software Foundation; either version 2 of the License, or
25 (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35*/
36
37#include <linux/init.h>
38#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/delay.h>
40#include <linux/errno.h>
41#include <linux/fs.h>
42#include <linux/kernel.h>
43#include <linux/sched.h>
44#include <linux/interrupt.h>
45#include <linux/kdev_t.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020046#include "bttvp.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020047#include <media/v4l2-common.h>
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -030048#include <media/tvaudio.h>
Hans Verkuil2474ed42006-03-19 12:35:57 -030049#include <media/msp3400.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020050
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -070051#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53#include <asm/io.h>
54#include <asm/byteorder.h>
55
Mauro Carvalho Chehabfa3fcce2006-03-23 21:45:24 -030056#include <media/rds.h>
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070057
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059unsigned int bttv_num; /* number of Bt848s in use */
60struct bttv bttvs[BTTV_MAX];
61
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020062unsigned int bttv_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063unsigned int bttv_verbose = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020064unsigned int bttv_gpio;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66/* config variables */
67#ifdef __BIG_ENDIAN
68static unsigned int bigendian=1;
69#else
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020070static unsigned int bigendian;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#endif
72static unsigned int radio[BTTV_MAX];
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020073static unsigned int irq_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static unsigned int gbuffers = 8;
75static unsigned int gbufsize = 0x208000;
Michael Schimeke5bd0262007-01-18 16:17:39 -030076static unsigned int reset_crop = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static int video_nr = -1;
79static int radio_nr = -1;
80static int vbi_nr = -1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020081static int debug_latency;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020083static unsigned int fdsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* options */
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020086static unsigned int combfilter;
87static unsigned int lumafilter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088static unsigned int automute = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020089static unsigned int chroma_agc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static unsigned int adc_crush = 1;
91static unsigned int whitecrush_upper = 0xCF;
92static unsigned int whitecrush_lower = 0x7F;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020093static unsigned int vcr_hack;
94static unsigned int irq_iswitch;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070095static unsigned int uv_ratio = 50;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020096static unsigned int full_luma_range;
97static unsigned int coring;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070098extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
100/* API features (turn on/off stuff for testing) */
101static unsigned int v4l2 = 1;
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/* insmod args */
104module_param(bttv_verbose, int, 0644);
105module_param(bttv_gpio, int, 0644);
106module_param(bttv_debug, int, 0644);
107module_param(irq_debug, int, 0644);
108module_param(debug_latency, int, 0644);
109
110module_param(fdsr, int, 0444);
111module_param(video_nr, int, 0444);
112module_param(radio_nr, int, 0444);
113module_param(vbi_nr, int, 0444);
114module_param(gbuffers, int, 0444);
115module_param(gbufsize, int, 0444);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300116module_param(reset_crop, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118module_param(v4l2, int, 0644);
119module_param(bigendian, int, 0644);
120module_param(irq_iswitch, int, 0644);
121module_param(combfilter, int, 0444);
122module_param(lumafilter, int, 0444);
123module_param(automute, int, 0444);
124module_param(chroma_agc, int, 0444);
125module_param(adc_crush, int, 0444);
126module_param(whitecrush_upper, int, 0444);
127module_param(whitecrush_lower, int, 0444);
128module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700129module_param(uv_ratio, int, 0444);
130module_param(full_luma_range, int, 0444);
131module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133module_param_array(radio, int, NULL, 0444);
134
135MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
136MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
137MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
138MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
139MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
140MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
141MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
142MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
Michael Schimeke5bd0262007-01-18 16:17:39 -0300143MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
144 "is 1 (yes) for compatibility with older applications");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
146MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
147MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
148MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
149MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
150MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
151MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700152MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
153MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
154MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
157MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
158MODULE_LICENSE("GPL");
159
160/* ----------------------------------------------------------------------- */
161/* sysfs */
162
Kay Sievers54bd5b62007-10-08 16:26:13 -0300163static ssize_t show_card(struct device *cd,
164 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165{
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -0300166 struct video_device *vfd = container_of(cd, struct video_device, class_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 struct bttv *btv = dev_get_drvdata(vfd->dev);
168 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
169}
Kay Sievers54bd5b62007-10-08 16:26:13 -0300170static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172/* ----------------------------------------------------------------------- */
Jarod Wilsonf992a492007-03-24 15:23:50 -0300173/* dvb auto-load setup */
174#if defined(CONFIG_MODULES) && defined(MODULE)
175static void request_module_async(struct work_struct *work)
176{
177 request_module("dvb-bt8xx");
178}
179
180static void request_modules(struct bttv *dev)
181{
182 INIT_WORK(&dev->request_module_wk, request_module_async);
183 schedule_work(&dev->request_module_wk);
184}
185#else
186#define request_modules(dev)
187#endif /* CONFIG_MODULES */
188
189
190/* ----------------------------------------------------------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191/* static data */
192
193/* special timing tables from conexant... */
194static u8 SRAM_Table[][60] =
195{
196 /* PAL digital input over GPIO[7:0] */
197 {
198 45, // 45 bytes following
199 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
200 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
201 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
202 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
203 0x37,0x00,0xAF,0x21,0x00
204 },
205 /* NTSC digital input over GPIO[7:0] */
206 {
207 51, // 51 bytes following
208 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
209 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
210 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
211 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
212 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
213 0x00,
214 },
215 // TGB_NTSC392 // quartzsight
216 // This table has been modified to be used for Fusion Rev D
217 {
218 0x2A, // size of table = 42
219 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
220 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
221 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
222 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
223 0x20, 0x00
224 }
225};
226
Michael Schimeke5bd0262007-01-18 16:17:39 -0300227/* minhdelayx1 first video pixel we can capture on a line and
228 hdelayx1 start of active video, both relative to rising edge of
229 /HRESET pulse (0H) in 1 / fCLKx1.
230 swidth width of active video and
231 totalwidth total line width, both in 1 / fCLKx1.
232 sqwidth total line width in square pixels.
233 vdelay start of active video in 2 * field lines relative to
234 trailing edge of /VRESET pulse (VDELAY register).
235 sheight height of active video in 2 * field lines.
236 videostart0 ITU-R frame line number of the line corresponding
237 to vdelay in the first field. */
238#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
239 vdelay, sheight, videostart0) \
240 .cropcap.bounds.left = minhdelayx1, \
241 /* * 2 because vertically we count field lines times two, */ \
242 /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
243 .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
244 /* 4 is a safety margin at the end of the line. */ \
245 .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
246 .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
247 .cropcap.defrect.left = hdelayx1, \
248 .cropcap.defrect.top = (videostart0) * 2, \
249 .cropcap.defrect.width = swidth, \
250 .cropcap.defrect.height = sheight, \
251 .cropcap.pixelaspect.numerator = totalwidth, \
252 .cropcap.pixelaspect.denominator = sqwidth,
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254const struct bttv_tvnorm bttv_tvnorms[] = {
255 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800256 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
257 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 {
259 .v4l2_id = V4L2_STD_PAL,
260 .name = "PAL",
261 .Fsc = 35468950,
262 .swidth = 924,
263 .sheight = 576,
264 .totalwidth = 1135,
265 .adelay = 0x7f,
266 .bdelay = 0x72,
267 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
268 .scaledtwidth = 1135,
269 .hdelayx1 = 186,
270 .hactivex1 = 924,
271 .vdelay = 0x20,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300272 .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200274 /* ITU-R frame line number of the first VBI line
Michael Schimeke5bd0262007-01-18 16:17:39 -0300275 we can capture, of the first and second field.
276 The last line is determined by cropcap.bounds. */
277 .vbistart = { 7, 320 },
278 CROPCAP(/* minhdelayx1 */ 68,
279 /* hdelayx1 */ 186,
280 /* Should be (768 * 1135 + 944 / 2) / 944.
281 cropcap.defrect is used for image width
282 checks, so we keep the old value 924. */
283 /* swidth */ 924,
284 /* totalwidth */ 1135,
285 /* sqwidth */ 944,
286 /* vdelay */ 0x20,
287 /* sheight */ 576,
288 /* videostart0 */ 23)
289 /* bt878 (and bt848?) can capture another
290 line below active video. */
291 .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 },{
Hans Verkuild97a11e2006-02-07 06:48:40 -0200293 .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 .name = "NTSC",
295 .Fsc = 28636363,
296 .swidth = 768,
297 .sheight = 480,
298 .totalwidth = 910,
299 .adelay = 0x68,
300 .bdelay = 0x5d,
301 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
302 .scaledtwidth = 910,
303 .hdelayx1 = 128,
304 .hactivex1 = 910,
305 .vdelay = 0x1a,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300306 .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200308 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300309 CROPCAP(/* minhdelayx1 */ 68,
310 /* hdelayx1 */ 128,
311 /* Should be (640 * 910 + 780 / 2) / 780? */
312 /* swidth */ 768,
313 /* totalwidth */ 910,
314 /* sqwidth */ 780,
315 /* vdelay */ 0x1a,
316 /* sheight */ 480,
317 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 },{
319 .v4l2_id = V4L2_STD_SECAM,
320 .name = "SECAM",
321 .Fsc = 35468950,
322 .swidth = 924,
323 .sheight = 576,
324 .totalwidth = 1135,
325 .adelay = 0x7f,
326 .bdelay = 0xb0,
327 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
328 .scaledtwidth = 1135,
329 .hdelayx1 = 186,
330 .hactivex1 = 922,
331 .vdelay = 0x20,
332 .vbipack = 255,
333 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200334 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300335 CROPCAP(/* minhdelayx1 */ 68,
336 /* hdelayx1 */ 186,
337 /* swidth */ 924,
338 /* totalwidth */ 1135,
339 /* sqwidth */ 944,
340 /* vdelay */ 0x20,
341 /* sheight */ 576,
342 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 },{
344 .v4l2_id = V4L2_STD_PAL_Nc,
345 .name = "PAL-Nc",
346 .Fsc = 28636363,
347 .swidth = 640,
348 .sheight = 576,
349 .totalwidth = 910,
350 .adelay = 0x68,
351 .bdelay = 0x5d,
352 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
353 .scaledtwidth = 780,
354 .hdelayx1 = 130,
355 .hactivex1 = 734,
356 .vdelay = 0x1a,
357 .vbipack = 144,
358 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200359 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300360 CROPCAP(/* minhdelayx1 */ 68,
361 /* hdelayx1 */ 130,
362 /* swidth */ (640 * 910 + 780 / 2) / 780,
363 /* totalwidth */ 910,
364 /* sqwidth */ 780,
365 /* vdelay */ 0x1a,
366 /* sheight */ 576,
367 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 },{
369 .v4l2_id = V4L2_STD_PAL_M,
370 .name = "PAL-M",
371 .Fsc = 28636363,
372 .swidth = 640,
373 .sheight = 480,
374 .totalwidth = 910,
375 .adelay = 0x68,
376 .bdelay = 0x5d,
377 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
378 .scaledtwidth = 780,
379 .hdelayx1 = 135,
380 .hactivex1 = 754,
381 .vdelay = 0x1a,
382 .vbipack = 144,
383 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200384 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300385 CROPCAP(/* minhdelayx1 */ 68,
386 /* hdelayx1 */ 135,
387 /* swidth */ (640 * 910 + 780 / 2) / 780,
388 /* totalwidth */ 910,
389 /* sqwidth */ 780,
390 /* vdelay */ 0x1a,
391 /* sheight */ 480,
392 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 },{
394 .v4l2_id = V4L2_STD_PAL_N,
395 .name = "PAL-N",
396 .Fsc = 35468950,
397 .swidth = 768,
398 .sheight = 576,
399 .totalwidth = 1135,
400 .adelay = 0x7f,
401 .bdelay = 0x72,
402 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
403 .scaledtwidth = 944,
404 .hdelayx1 = 186,
405 .hactivex1 = 922,
406 .vdelay = 0x20,
407 .vbipack = 144,
408 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300409 .vbistart = { 7, 320 },
410 CROPCAP(/* minhdelayx1 */ 68,
411 /* hdelayx1 */ 186,
412 /* swidth */ (768 * 1135 + 944 / 2) / 944,
413 /* totalwidth */ 1135,
414 /* sqwidth */ 944,
415 /* vdelay */ 0x20,
416 /* sheight */ 576,
417 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 },{
419 .v4l2_id = V4L2_STD_NTSC_M_JP,
420 .name = "NTSC-JP",
421 .Fsc = 28636363,
422 .swidth = 640,
423 .sheight = 480,
424 .totalwidth = 910,
425 .adelay = 0x68,
426 .bdelay = 0x5d,
427 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
428 .scaledtwidth = 780,
429 .hdelayx1 = 135,
430 .hactivex1 = 754,
431 .vdelay = 0x16,
432 .vbipack = 144,
433 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300434 .vbistart = { 10, 273 },
435 CROPCAP(/* minhdelayx1 */ 68,
436 /* hdelayx1 */ 135,
437 /* swidth */ (640 * 910 + 780 / 2) / 780,
438 /* totalwidth */ 910,
439 /* sqwidth */ 780,
440 /* vdelay */ 0x16,
441 /* sheight */ 480,
442 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 },{
444 /* that one hopefully works with the strange timing
445 * which video recorders produce when playing a NTSC
446 * tape on a PAL TV ... */
447 .v4l2_id = V4L2_STD_PAL_60,
448 .name = "PAL-60",
449 .Fsc = 35468950,
450 .swidth = 924,
451 .sheight = 480,
452 .totalwidth = 1135,
453 .adelay = 0x7f,
454 .bdelay = 0x72,
455 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
456 .scaledtwidth = 1135,
457 .hdelayx1 = 186,
458 .hactivex1 = 924,
459 .vdelay = 0x1a,
460 .vbipack = 255,
461 .vtotal = 524,
462 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200463 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300464 CROPCAP(/* minhdelayx1 */ 68,
465 /* hdelayx1 */ 186,
466 /* swidth */ 924,
467 /* totalwidth */ 1135,
468 /* sqwidth */ 944,
469 /* vdelay */ 0x1a,
470 /* sheight */ 480,
471 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
473};
474static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
475
476/* ----------------------------------------------------------------------- */
477/* bttv format list
478 packed pixel formats must come first */
479static const struct bttv_format bttv_formats[] = {
480 {
481 .name = "8 bpp, gray",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 .fourcc = V4L2_PIX_FMT_GREY,
483 .btformat = BT848_COLOR_FMT_Y8,
484 .depth = 8,
485 .flags = FORMAT_FLAGS_PACKED,
486 },{
487 .name = "8 bpp, dithered color",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 .fourcc = V4L2_PIX_FMT_HI240,
489 .btformat = BT848_COLOR_FMT_RGB8,
490 .depth = 8,
491 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
492 },{
493 .name = "15 bpp RGB, le",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 .fourcc = V4L2_PIX_FMT_RGB555,
495 .btformat = BT848_COLOR_FMT_RGB15,
496 .depth = 16,
497 .flags = FORMAT_FLAGS_PACKED,
498 },{
499 .name = "15 bpp RGB, be",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 .fourcc = V4L2_PIX_FMT_RGB555X,
501 .btformat = BT848_COLOR_FMT_RGB15,
502 .btswap = 0x03, /* byteswap */
503 .depth = 16,
504 .flags = FORMAT_FLAGS_PACKED,
505 },{
506 .name = "16 bpp RGB, le",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 .fourcc = V4L2_PIX_FMT_RGB565,
508 .btformat = BT848_COLOR_FMT_RGB16,
509 .depth = 16,
510 .flags = FORMAT_FLAGS_PACKED,
511 },{
512 .name = "16 bpp RGB, be",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 .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",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 .fourcc = V4L2_PIX_FMT_BGR24,
521 .btformat = BT848_COLOR_FMT_RGB24,
522 .depth = 24,
523 .flags = FORMAT_FLAGS_PACKED,
524 },{
525 .name = "32 bpp RGB, le",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 .fourcc = V4L2_PIX_FMT_BGR32,
527 .btformat = BT848_COLOR_FMT_RGB32,
528 .depth = 32,
529 .flags = FORMAT_FLAGS_PACKED,
530 },{
531 .name = "32 bpp RGB, be",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 .fourcc = V4L2_PIX_FMT_RGB32,
533 .btformat = BT848_COLOR_FMT_RGB32,
534 .btswap = 0x0f, /* byte+word swap */
535 .depth = 32,
536 .flags = FORMAT_FLAGS_PACKED,
537 },{
538 .name = "4:2:2, packed, YUYV",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 .fourcc = V4L2_PIX_FMT_YUYV,
540 .btformat = BT848_COLOR_FMT_YUY2,
541 .depth = 16,
542 .flags = FORMAT_FLAGS_PACKED,
543 },{
544 .name = "4:2:2, packed, YUYV",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 .fourcc = V4L2_PIX_FMT_YUYV,
546 .btformat = BT848_COLOR_FMT_YUY2,
547 .depth = 16,
548 .flags = FORMAT_FLAGS_PACKED,
549 },{
550 .name = "4:2:2, packed, UYVY",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 .fourcc = V4L2_PIX_FMT_UYVY,
552 .btformat = BT848_COLOR_FMT_YUY2,
553 .btswap = 0x03, /* byteswap */
554 .depth = 16,
555 .flags = FORMAT_FLAGS_PACKED,
556 },{
557 .name = "4:2:2, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 .fourcc = V4L2_PIX_FMT_YUV422P,
559 .btformat = BT848_COLOR_FMT_YCrCb422,
560 .depth = 16,
561 .flags = FORMAT_FLAGS_PLANAR,
562 .hshift = 1,
563 .vshift = 0,
564 },{
565 .name = "4:2:0, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 .fourcc = V4L2_PIX_FMT_YUV420,
567 .btformat = BT848_COLOR_FMT_YCrCb422,
568 .depth = 12,
569 .flags = FORMAT_FLAGS_PLANAR,
570 .hshift = 1,
571 .vshift = 1,
572 },{
573 .name = "4:2:0, planar, Y-Cr-Cb",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 .fourcc = V4L2_PIX_FMT_YVU420,
575 .btformat = BT848_COLOR_FMT_YCrCb422,
576 .depth = 12,
577 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
578 .hshift = 1,
579 .vshift = 1,
580 },{
581 .name = "4:1:1, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 .fourcc = V4L2_PIX_FMT_YUV411P,
583 .btformat = BT848_COLOR_FMT_YCrCb411,
584 .depth = 12,
585 .flags = FORMAT_FLAGS_PLANAR,
586 .hshift = 2,
587 .vshift = 0,
588 },{
589 .name = "4:1:0, planar, Y-Cb-Cr",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 .fourcc = V4L2_PIX_FMT_YUV410,
591 .btformat = BT848_COLOR_FMT_YCrCb411,
592 .depth = 9,
593 .flags = FORMAT_FLAGS_PLANAR,
594 .hshift = 2,
595 .vshift = 2,
596 },{
597 .name = "4:1:0, planar, Y-Cr-Cb",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 .fourcc = V4L2_PIX_FMT_YVU410,
599 .btformat = BT848_COLOR_FMT_YCrCb411,
600 .depth = 9,
601 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
602 .hshift = 2,
603 .vshift = 2,
604 },{
605 .name = "raw scanlines",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 .fourcc = -1,
607 .btformat = BT848_COLOR_FMT_RAW,
608 .depth = 8,
609 .flags = FORMAT_FLAGS_RAW,
610 }
611};
612static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
613
614/* ----------------------------------------------------------------------- */
615
616#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
617#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
618#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
619#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
620#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
621#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
622#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
623#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700624#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
625#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
626#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
627#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629static const struct v4l2_queryctrl no_ctl = {
630 .name = "42",
631 .flags = V4L2_CTRL_FLAG_DISABLED,
632};
633static const struct v4l2_queryctrl bttv_ctls[] = {
634 /* --- video --- */
635 {
636 .id = V4L2_CID_BRIGHTNESS,
637 .name = "Brightness",
638 .minimum = 0,
639 .maximum = 65535,
640 .step = 256,
641 .default_value = 32768,
642 .type = V4L2_CTRL_TYPE_INTEGER,
643 },{
644 .id = V4L2_CID_CONTRAST,
645 .name = "Contrast",
646 .minimum = 0,
647 .maximum = 65535,
648 .step = 128,
649 .default_value = 32768,
650 .type = V4L2_CTRL_TYPE_INTEGER,
651 },{
652 .id = V4L2_CID_SATURATION,
653 .name = "Saturation",
654 .minimum = 0,
655 .maximum = 65535,
656 .step = 128,
657 .default_value = 32768,
658 .type = V4L2_CTRL_TYPE_INTEGER,
659 },{
660 .id = V4L2_CID_HUE,
661 .name = "Hue",
662 .minimum = 0,
663 .maximum = 65535,
664 .step = 256,
665 .default_value = 32768,
666 .type = V4L2_CTRL_TYPE_INTEGER,
667 },
668 /* --- audio --- */
669 {
670 .id = V4L2_CID_AUDIO_MUTE,
671 .name = "Mute",
672 .minimum = 0,
673 .maximum = 1,
674 .type = V4L2_CTRL_TYPE_BOOLEAN,
675 },{
676 .id = V4L2_CID_AUDIO_VOLUME,
677 .name = "Volume",
678 .minimum = 0,
679 .maximum = 65535,
680 .step = 65535/100,
681 .default_value = 65535,
682 .type = V4L2_CTRL_TYPE_INTEGER,
683 },{
684 .id = V4L2_CID_AUDIO_BALANCE,
685 .name = "Balance",
686 .minimum = 0,
687 .maximum = 65535,
688 .step = 65535/100,
689 .default_value = 32768,
690 .type = V4L2_CTRL_TYPE_INTEGER,
691 },{
692 .id = V4L2_CID_AUDIO_BASS,
693 .name = "Bass",
694 .minimum = 0,
695 .maximum = 65535,
696 .step = 65535/100,
697 .default_value = 32768,
698 .type = V4L2_CTRL_TYPE_INTEGER,
699 },{
700 .id = V4L2_CID_AUDIO_TREBLE,
701 .name = "Treble",
702 .minimum = 0,
703 .maximum = 65535,
704 .step = 65535/100,
705 .default_value = 32768,
706 .type = V4L2_CTRL_TYPE_INTEGER,
707 },
708 /* --- private --- */
709 {
710 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
711 .name = "chroma agc",
712 .minimum = 0,
713 .maximum = 1,
714 .type = V4L2_CTRL_TYPE_BOOLEAN,
715 },{
716 .id = V4L2_CID_PRIVATE_COMBFILTER,
717 .name = "combfilter",
718 .minimum = 0,
719 .maximum = 1,
720 .type = V4L2_CTRL_TYPE_BOOLEAN,
721 },{
722 .id = V4L2_CID_PRIVATE_AUTOMUTE,
723 .name = "automute",
724 .minimum = 0,
725 .maximum = 1,
726 .type = V4L2_CTRL_TYPE_BOOLEAN,
727 },{
728 .id = V4L2_CID_PRIVATE_LUMAFILTER,
729 .name = "luma decimation filter",
730 .minimum = 0,
731 .maximum = 1,
732 .type = V4L2_CTRL_TYPE_BOOLEAN,
733 },{
734 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
735 .name = "agc crush",
736 .minimum = 0,
737 .maximum = 1,
738 .type = V4L2_CTRL_TYPE_BOOLEAN,
739 },{
740 .id = V4L2_CID_PRIVATE_VCR_HACK,
741 .name = "vcr hack",
742 .minimum = 0,
743 .maximum = 1,
744 .type = V4L2_CTRL_TYPE_BOOLEAN,
745 },{
746 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
747 .name = "whitecrush upper",
748 .minimum = 0,
749 .maximum = 255,
750 .step = 1,
751 .default_value = 0xCF,
752 .type = V4L2_CTRL_TYPE_INTEGER,
753 },{
754 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
755 .name = "whitecrush lower",
756 .minimum = 0,
757 .maximum = 255,
758 .step = 1,
759 .default_value = 0x7F,
760 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700761 },{
762 .id = V4L2_CID_PRIVATE_UV_RATIO,
763 .name = "uv ratio",
764 .minimum = 0,
765 .maximum = 100,
766 .step = 1,
767 .default_value = 50,
768 .type = V4L2_CTRL_TYPE_INTEGER,
769 },{
770 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
771 .name = "full luma range",
772 .minimum = 0,
773 .maximum = 1,
774 .type = V4L2_CTRL_TYPE_BOOLEAN,
775 },{
776 .id = V4L2_CID_PRIVATE_CORING,
777 .name = "coring",
778 .minimum = 0,
779 .maximum = 3,
780 .step = 1,
781 .default_value = 0,
782 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
784
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700785
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787};
788static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
789
790/* ----------------------------------------------------------------------- */
791/* resource management */
792
Michael Schimeke5bd0262007-01-18 16:17:39 -0300793/*
794 RESOURCE_ allocated by freed by
795
796 VIDEO_READ bttv_read 1) bttv_read 2)
797
798 VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
799 VIDIOC_QBUF 1) bttv_release
800 VIDIOCMCAPTURE 1)
801
802 OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
803 VIDIOC_OVERLAY on VIDIOC_OVERLAY off
804 3) bttv_release
805
806 VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
807 VIDIOC_QBUF 1) bttv_release
808 bttv_read, bttv_poll 1) 4)
809
810 1) The resource must be allocated when we enter buffer prepare functions
811 and remain allocated while buffers are in the DMA queue.
812 2) This is a single frame read.
813 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
814 RESOURCE_OVERLAY is allocated.
815 4) This is a continuous read, implies VIDIOC_STREAMON.
816
817 Note this driver permits video input and standard changes regardless if
818 resources are allocated.
819*/
820
821#define VBI_RESOURCES (RESOURCE_VBI)
822#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
823 RESOURCE_VIDEO_STREAM | \
824 RESOURCE_OVERLAY)
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826static
827int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
828{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300829 int xbits; /* mutual exclusive resources */
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (fh->resources & bit)
832 /* have it already allocated */
833 return 1;
834
Michael Schimeke5bd0262007-01-18 16:17:39 -0300835 xbits = bit;
836 if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
837 xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 /* is it free? */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300840 mutex_lock(&btv->lock);
841 if (btv->resources & xbits) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 /* no, someone else uses it */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300843 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300845
846 if ((bit & VIDEO_RESOURCES)
847 && 0 == (btv->resources & VIDEO_RESOURCES)) {
848 /* Do crop - use current, don't - use default parameters. */
849 __s32 top = btv->crop[!!fh->do_crop].rect.top;
850
851 if (btv->vbi_end > top)
852 goto fail;
853
854 /* We cannot capture the same line as video and VBI data.
855 Claim scan lines crop[].rect.top to bottom. */
856 btv->crop_start = top;
857 } else if (bit & VBI_RESOURCES) {
858 __s32 end = fh->vbi_fmt.end;
859
860 if (end > btv->crop_start)
861 goto fail;
862
863 /* Claim scan lines above fh->vbi_fmt.end. */
864 btv->vbi_end = end;
865 }
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* it's free, grab it */
868 fh->resources |= bit;
869 btv->resources |= bit;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300870 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return 1;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300872
873 fail:
874 mutex_unlock(&btv->lock);
875 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878static
879int check_btres(struct bttv_fh *fh, int bit)
880{
881 return (fh->resources & bit);
882}
883
884static
885int locked_btres(struct bttv *btv, int bit)
886{
887 return (btv->resources & bit);
888}
889
Michael Schimeke5bd0262007-01-18 16:17:39 -0300890/* Call with btv->lock down. */
891static void
892disclaim_vbi_lines(struct bttv *btv)
893{
894 btv->vbi_end = 0;
895}
896
897/* Call with btv->lock down. */
898static void
899disclaim_video_lines(struct bttv *btv)
900{
901 const struct bttv_tvnorm *tvnorm;
902 u8 crop;
903
904 tvnorm = &bttv_tvnorms[btv->tvnorm];
905 btv->crop_start = tvnorm->cropcap.bounds.top
906 + tvnorm->cropcap.bounds.height;
907
908 /* VBI capturing ends at VDELAY, start of video capturing, no
909 matter how many lines the VBI RISC program expects. When video
910 capturing is off, it shall no longer "preempt" VBI capturing,
911 so we set VDELAY to maximum. */
912 crop = btread(BT848_E_CROP) | 0xc0;
913 btwrite(crop, BT848_E_CROP);
914 btwrite(0xfe, BT848_E_VDELAY_LO);
915 btwrite(crop, BT848_O_CROP);
916 btwrite(0xfe, BT848_O_VDELAY_LO);
917}
918
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919static
920void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
921{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 if ((fh->resources & bits) != bits) {
923 /* trying to free ressources not allocated by us ... */
924 printk("bttv: BUG! (btres)\n");
925 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300926 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 fh->resources &= ~bits;
928 btv->resources &= ~bits;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300929
930 bits = btv->resources;
931
932 if (0 == (bits & VIDEO_RESOURCES))
933 disclaim_video_lines(btv);
934
935 if (0 == (bits & VBI_RESOURCES))
936 disclaim_vbi_lines(btv);
937
938 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939}
940
941/* ----------------------------------------------------------------------- */
942/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
943
944/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
945 PLL_X = Reference pre-divider (0=1, 1=2)
946 PLL_C = Post divider (0=6, 1=4)
947 PLL_I = Integer input
948 PLL_F = Fractional input
949
950 F_input = 28.636363 MHz:
951 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
952*/
953
954static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
955{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800956 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800958 /* prevent overflows */
959 fin/=4;
960 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800962 fout*=12;
963 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800965 fout=(fout%fin)*256;
966 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800968 fout=(fout%fin)*256;
969 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800971 btwrite(fl, BT848_PLL_F_LO);
972 btwrite(fh, BT848_PLL_F_HI);
973 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974}
975
976static void set_pll(struct bttv *btv)
977{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800978 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800980 if (!btv->pll.pll_crystal)
981 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
984 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800985 return;
986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800988 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
989 /* no PLL needed */
990 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800991 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700992 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800993 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800994 btwrite(0x00,BT848_TGCTRL);
995 btwrite(0x00,BT848_PLL_XCI);
996 btv->pll.pll_current = 0;
997 return;
998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001000 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001001 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
1003
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001004 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001006 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 msleep(10);
1008
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001009 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001011 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001012 btwrite(0x08,BT848_TGCTRL);
1013 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001014 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001015 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001016 }
1017 }
1018 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001019 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001020 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021}
1022
1023/* used to switch between the bt848's analog/digital video capture modes */
1024static void bt848A_set_timing(struct bttv *btv)
1025{
1026 int i, len;
1027 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
1028 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
1029
1030 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
1031 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
1032 btv->c.nr,table_idx);
1033
1034 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001035 btwrite(0x00, BT848_TGCTRL);
1036 btwrite(0x02, BT848_TGCTRL);
1037 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
1039 len=SRAM_Table[table_idx][0];
1040 for(i = 1; i <= len; i++)
1041 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
1042 btv->pll.pll_ofreq = 27000000;
1043
1044 set_pll(btv);
1045 btwrite(0x11, BT848_TGCTRL);
1046 btwrite(0x41, BT848_DVSIF);
1047 } else {
1048 btv->pll.pll_ofreq = fsc;
1049 set_pll(btv);
1050 btwrite(0x0, BT848_DVSIF);
1051 }
1052}
1053
1054/* ----------------------------------------------------------------------- */
1055
1056static void bt848_bright(struct bttv *btv, int bright)
1057{
1058 int value;
1059
1060 // printk("bttv: set bright: %d\n",bright); // DEBUG
1061 btv->bright = bright;
1062
1063 /* We want -128 to 127 we get 0-65535 */
1064 value = (bright >> 8) - 128;
1065 btwrite(value & 0xff, BT848_BRIGHT);
1066}
1067
1068static void bt848_hue(struct bttv *btv, int hue)
1069{
1070 int value;
1071
1072 btv->hue = hue;
1073
1074 /* -128 to 127 */
1075 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001076 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077}
1078
1079static void bt848_contrast(struct bttv *btv, int cont)
1080{
1081 int value,hibit;
1082
1083 btv->contrast = cont;
1084
1085 /* 0-511 */
1086 value = (cont >> 7);
1087 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001088 btwrite(value & 0xff, BT848_CONTRAST_LO);
1089 btaor(hibit, ~4, BT848_E_CONTROL);
1090 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091}
1092
1093static void bt848_sat(struct bttv *btv, int color)
1094{
1095 int val_u,val_v,hibits;
1096
1097 btv->saturation = color;
1098
1099 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001100 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
1101 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001102 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001104 btwrite(val_u & 0xff, BT848_SAT_U_LO);
1105 btwrite(val_v & 0xff, BT848_SAT_V_LO);
1106 btaor(hibits, ~3, BT848_E_CONTROL);
1107 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108}
1109
1110/* ----------------------------------------------------------------------- */
1111
1112static int
1113video_mux(struct bttv *btv, unsigned int input)
1114{
1115 int mux,mask2;
1116
1117 if (input >= bttv_tvcards[btv->c.type].video_inputs)
1118 return -EINVAL;
1119
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001120 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
1122 if (mask2)
1123 gpio_inout(mask2,mask2);
1124
1125 if (input == btv->svhs) {
1126 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
1127 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
1128 } else {
1129 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
1130 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
1131 }
1132 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
1133 btaor(mux<<5, ~(3<<5), BT848_IFORM);
1134 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
1135 btv->c.nr,input,mux);
1136
1137 /* card specific hook */
1138 if(bttv_tvcards[btv->c.type].muxsel_hook)
1139 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
1140 return 0;
1141}
1142
1143static char *audio_modes[] = {
1144 "audio: tuner", "audio: radio", "audio: extern",
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001145 "audio: intern", "audio: mute"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146};
1147
1148static int
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001149audio_mux(struct bttv *btv, int input, int mute)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150{
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001151 int gpio_val, signal;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001152 struct v4l2_control ctrl;
1153 struct i2c_client *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
1155 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
1156 bttv_tvcards[btv->c.type].gpiomask);
1157 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
1158
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001159 btv->mute = mute;
1160 btv->audio = input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001162 /* automute */
1163 mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
1164
1165 if (mute)
1166 gpio_val = bttv_tvcards[btv->c.type].gpiomute;
1167 else
1168 gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001169
1170 gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (bttv_gpio)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001172 bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
1173 if (in_interrupt())
1174 return 0;
1175
1176 ctrl.id = V4L2_CID_AUDIO_MUTE;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001177 ctrl.value = btv->mute;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001178 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
1179 c = btv->i2c_msp34xx_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001180 if (c) {
1181 struct v4l2_routing route;
1182
1183 /* Note: the inputs tuner/radio/extern/intern are translated
1184 to msp routings. This assumes common behavior for all msp3400
1185 based TV cards. When this assumption fails, then the
1186 specific MSP routing must be added to the card table.
1187 For now this is sufficient. */
1188 switch (input) {
1189 case TVAUDIO_INPUT_RADIO:
Hans Verkuil07151722006-04-01 18:03:23 -03001190 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1191 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001192 break;
1193 case TVAUDIO_INPUT_EXTERN:
Hans Verkuil07151722006-04-01 18:03:23 -03001194 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
1195 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001196 break;
1197 case TVAUDIO_INPUT_INTERN:
1198 /* Yes, this is the same input as for RADIO. I doubt
1199 if this is ever used. The only board with an INTERN
1200 input is the BTTV_BOARD_AVERMEDIA98. I wonder how
1201 that was tested. My guess is that the whole INTERN
1202 input does not work. */
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_TUNER:
1207 default:
Wade Berrier434b2522007-06-25 13:02:16 -03001208 /* This is the only card that uses TUNER2, and afaik,
1209 is the only difference between the VOODOOTV_FM
1210 and VOODOOTV_200 */
1211 if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
1212 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
1213 MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
1214 else
1215 route.input = MSP_INPUT_DEFAULT;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001216 break;
1217 }
1218 route.output = MSP_OUTPUT_DEFAULT;
1219 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1220 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001221 c = btv->i2c_tvaudio_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001222 if (c) {
1223 struct v4l2_routing route;
1224
1225 route.input = input;
1226 route.output = 0;
1227 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 return 0;
1230}
1231
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001232static inline int
1233audio_mute(struct bttv *btv, int mute)
1234{
1235 return audio_mux(btv, btv->audio, mute);
1236}
1237
1238static inline int
1239audio_input(struct bttv *btv, int input)
1240{
1241 return audio_mux(btv, input, btv->mute);
1242}
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244static void
Michael Schimeke5bd0262007-01-18 16:17:39 -03001245bttv_crop_calc_limits(struct bttv_crop *c)
1246{
1247 /* Scale factor min. 1:1, max. 16:1. Min. image size
1248 48 x 32. Scaled width must be a multiple of 4. */
1249
1250 if (1) {
1251 /* For bug compatibility with VIDIOCGCAP and image
1252 size checks in earlier driver versions. */
1253 c->min_scaled_width = 48;
1254 c->min_scaled_height = 32;
1255 } else {
1256 c->min_scaled_width =
1257 (max(48, c->rect.width >> 4) + 3) & ~3;
1258 c->min_scaled_height =
1259 max(32, c->rect.height >> 4);
1260 }
1261
1262 c->max_scaled_width = c->rect.width & ~3;
1263 c->max_scaled_height = c->rect.height;
1264}
1265
1266static void
1267bttv_crop_reset(struct bttv_crop *c, int norm)
1268{
1269 c->rect = bttv_tvnorms[norm].cropcap.defrect;
1270 bttv_crop_calc_limits(c);
1271}
1272
1273/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274static int
1275set_tvnorm(struct bttv *btv, unsigned int norm)
1276{
1277 const struct bttv_tvnorm *tvnorm;
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001278 v4l2_std_id id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
1280 if (norm < 0 || norm >= BTTV_TVNORMS)
1281 return -EINVAL;
1282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 tvnorm = &bttv_tvnorms[norm];
1284
Michael Schimeke5bd0262007-01-18 16:17:39 -03001285 if (btv->tvnorm < 0 ||
1286 btv->tvnorm >= BTTV_TVNORMS ||
1287 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
1288 &tvnorm->cropcap,
1289 sizeof (tvnorm->cropcap))) {
1290 bttv_crop_reset(&btv->crop[0], norm);
1291 btv->crop[1] = btv->crop[0]; /* current = default */
1292
1293 if (0 == (btv->resources & VIDEO_RESOURCES)) {
1294 btv->crop_start = tvnorm->cropcap.bounds.top
1295 + tvnorm->cropcap.bounds.height;
1296 }
1297 }
1298
1299 btv->tvnorm = norm;
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 btwrite(tvnorm->adelay, BT848_ADELAY);
1302 btwrite(tvnorm->bdelay, BT848_BDELAY);
1303 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1304 BT848_IFORM);
1305 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1306 btwrite(1, BT848_VBI_PACK_DEL);
1307 bt848A_set_timing(btv);
1308
1309 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001310 case BTTV_BOARD_VOODOOTV_FM:
Wade Berrier434b2522007-06-25 13:02:16 -03001311 case BTTV_BOARD_VOODOOTV_200:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 bttv_tda9880_setnorm(btv,norm);
1313 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03001315 id = tvnorm->v4l2_id;
1316 bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id);
1317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 return 0;
1319}
1320
Michael Schimeke5bd0262007-01-18 16:17:39 -03001321/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322static void
Trent Piepho333408f2007-07-03 15:08:10 -03001323set_input(struct bttv *btv, unsigned int input, unsigned int norm)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324{
1325 unsigned long flags;
1326
1327 btv->input = input;
1328 if (irq_iswitch) {
1329 spin_lock_irqsave(&btv->s_lock,flags);
1330 if (btv->curr.frame_irq) {
1331 /* active capture -> delayed input switch */
1332 btv->new_input = input;
1333 } else {
1334 video_mux(btv,input);
1335 }
1336 spin_unlock_irqrestore(&btv->s_lock,flags);
1337 } else {
1338 video_mux(btv,input);
1339 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001340 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1341 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Trent Piepho333408f2007-07-03 15:08:10 -03001342 set_tvnorm(btv, norm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343}
1344
1345static void init_irqreg(struct bttv *btv)
1346{
1347 /* clear status */
1348 btwrite(0xfffffUL, BT848_INT_STAT);
1349
1350 if (bttv_tvcards[btv->c.type].no_video) {
1351 /* i2c only */
1352 btwrite(BT848_INT_I2CDONE,
1353 BT848_INT_MASK);
1354 } else {
1355 /* full video */
1356 btwrite((btv->triton1) |
1357 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1358 BT848_INT_SCERR |
1359 (fdsr ? BT848_INT_FDSR : 0) |
1360 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1361 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1362 BT848_INT_I2CDONE,
1363 BT848_INT_MASK);
1364 }
1365}
1366
1367static void init_bt848(struct bttv *btv)
1368{
1369 int val;
1370
1371 if (bttv_tvcards[btv->c.type].no_video) {
1372 /* very basic init only */
1373 init_irqreg(btv);
1374 return;
1375 }
1376
1377 btwrite(0x00, BT848_CAP_CTL);
1378 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1379 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1380
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001381 /* set planar and packed mode trigger points and */
1382 /* set rising edge of inverted GPINTR pin as irq trigger */
1383 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1384 BT848_GPIO_DMA_CTL_PLTP1_16|
1385 BT848_GPIO_DMA_CTL_PLTP23_16|
1386 BT848_GPIO_DMA_CTL_GPINTC|
1387 BT848_GPIO_DMA_CTL_GPINTI,
1388 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001391 btwrite(val, BT848_E_SCLOOP);
1392 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001394 btwrite(0x20, BT848_E_VSCALE_HI);
1395 btwrite(0x20, BT848_O_VSCALE_HI);
1396 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 BT848_ADC);
1398
1399 btwrite(whitecrush_upper, BT848_WC_UP);
1400 btwrite(whitecrush_lower, BT848_WC_DOWN);
1401
1402 if (btv->opt_lumafilter) {
1403 btwrite(0, BT848_E_CONTROL);
1404 btwrite(0, BT848_O_CONTROL);
1405 } else {
1406 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1407 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1408 }
1409
1410 bt848_bright(btv, btv->bright);
1411 bt848_hue(btv, btv->hue);
1412 bt848_contrast(btv, btv->contrast);
1413 bt848_sat(btv, btv->saturation);
1414
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001415 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 init_irqreg(btv);
1417}
1418
1419static void bttv_reinit_bt848(struct bttv *btv)
1420{
1421 unsigned long flags;
1422
1423 if (bttv_verbose)
1424 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1425 spin_lock_irqsave(&btv->s_lock,flags);
1426 btv->errors=0;
1427 bttv_set_dma(btv,0);
1428 spin_unlock_irqrestore(&btv->s_lock,flags);
1429
1430 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001431 btv->pll.pll_current = -1;
Trent Piepho333408f2007-07-03 15:08:10 -03001432 set_input(btv, btv->input, btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433}
1434
1435static int get_control(struct bttv *btv, struct v4l2_control *c)
1436{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 int i;
1438
1439 for (i = 0; i < BTTV_CTLS; i++)
1440 if (bttv_ctls[i].id == c->id)
1441 break;
1442 if (i == BTTV_CTLS)
1443 return -EINVAL;
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001444#ifdef CONFIG_VIDEO_V4L1
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001445 if (btv->audio_hook && i >= 4 && i <= 8) {
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001446 struct video_audio va;
1447
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001449 btv->audio_hook(btv,&va,0);
1450 switch (c->id) {
1451 case V4L2_CID_AUDIO_MUTE:
1452 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1453 break;
1454 case V4L2_CID_AUDIO_VOLUME:
1455 c->value = va.volume;
1456 break;
1457 case V4L2_CID_AUDIO_BALANCE:
1458 c->value = va.balance;
1459 break;
1460 case V4L2_CID_AUDIO_BASS:
1461 c->value = va.bass;
1462 break;
1463 case V4L2_CID_AUDIO_TREBLE:
1464 c->value = va.treble;
1465 break;
1466 }
1467 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001469#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 switch (c->id) {
1471 case V4L2_CID_BRIGHTNESS:
1472 c->value = btv->bright;
1473 break;
1474 case V4L2_CID_HUE:
1475 c->value = btv->hue;
1476 break;
1477 case V4L2_CID_CONTRAST:
1478 c->value = btv->contrast;
1479 break;
1480 case V4L2_CID_SATURATION:
1481 c->value = btv->saturation;
1482 break;
1483
1484 case V4L2_CID_AUDIO_MUTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001489 bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 break;
1491
1492 case V4L2_CID_PRIVATE_CHROMA_AGC:
1493 c->value = btv->opt_chroma_agc;
1494 break;
1495 case V4L2_CID_PRIVATE_COMBFILTER:
1496 c->value = btv->opt_combfilter;
1497 break;
1498 case V4L2_CID_PRIVATE_LUMAFILTER:
1499 c->value = btv->opt_lumafilter;
1500 break;
1501 case V4L2_CID_PRIVATE_AUTOMUTE:
1502 c->value = btv->opt_automute;
1503 break;
1504 case V4L2_CID_PRIVATE_AGC_CRUSH:
1505 c->value = btv->opt_adc_crush;
1506 break;
1507 case V4L2_CID_PRIVATE_VCR_HACK:
1508 c->value = btv->opt_vcr_hack;
1509 break;
1510 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1511 c->value = btv->opt_whitecrush_upper;
1512 break;
1513 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1514 c->value = btv->opt_whitecrush_lower;
1515 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001516 case V4L2_CID_PRIVATE_UV_RATIO:
1517 c->value = btv->opt_uv_ratio;
1518 break;
1519 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1520 c->value = btv->opt_full_luma_range;
1521 break;
1522 case V4L2_CID_PRIVATE_CORING:
1523 c->value = btv->opt_coring;
1524 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 default:
1526 return -EINVAL;
1527 }
1528 return 0;
1529}
1530
1531static int set_control(struct bttv *btv, struct v4l2_control *c)
1532{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 int i,val;
1534
1535 for (i = 0; i < BTTV_CTLS; i++)
1536 if (bttv_ctls[i].id == c->id)
1537 break;
1538 if (i == BTTV_CTLS)
1539 return -EINVAL;
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001540#ifdef CONFIG_VIDEO_V4L1
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001541 if (btv->audio_hook && i >= 4 && i <= 8) {
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001542 struct video_audio va;
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001545 btv->audio_hook(btv,&va,0);
1546 switch (c->id) {
1547 case V4L2_CID_AUDIO_MUTE:
1548 if (c->value) {
1549 va.flags |= VIDEO_AUDIO_MUTE;
1550 audio_mute(btv, 1);
1551 } else {
1552 va.flags &= ~VIDEO_AUDIO_MUTE;
1553 audio_mute(btv, 0);
1554 }
1555 break;
1556
1557 case V4L2_CID_AUDIO_VOLUME:
1558 va.volume = c->value;
1559 break;
1560 case V4L2_CID_AUDIO_BALANCE:
1561 va.balance = c->value;
1562 break;
1563 case V4L2_CID_AUDIO_BASS:
1564 va.bass = c->value;
1565 break;
1566 case V4L2_CID_AUDIO_TREBLE:
1567 va.treble = c->value;
1568 break;
1569 }
1570 btv->audio_hook(btv,&va,1);
1571 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001573#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 switch (c->id) {
1575 case V4L2_CID_BRIGHTNESS:
1576 bt848_bright(btv,c->value);
1577 break;
1578 case V4L2_CID_HUE:
1579 bt848_hue(btv,c->value);
1580 break;
1581 case V4L2_CID_CONTRAST:
1582 bt848_contrast(btv,c->value);
1583 break;
1584 case V4L2_CID_SATURATION:
1585 bt848_sat(btv,c->value);
1586 break;
1587 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001588 audio_mute(btv, c->value);
1589 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001594 bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 break;
1596
1597 case V4L2_CID_PRIVATE_CHROMA_AGC:
1598 btv->opt_chroma_agc = c->value;
1599 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1600 btwrite(val, BT848_E_SCLOOP);
1601 btwrite(val, BT848_O_SCLOOP);
1602 break;
1603 case V4L2_CID_PRIVATE_COMBFILTER:
1604 btv->opt_combfilter = c->value;
1605 break;
1606 case V4L2_CID_PRIVATE_LUMAFILTER:
1607 btv->opt_lumafilter = c->value;
1608 if (btv->opt_lumafilter) {
1609 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1610 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1611 } else {
1612 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1613 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1614 }
1615 break;
1616 case V4L2_CID_PRIVATE_AUTOMUTE:
1617 btv->opt_automute = c->value;
1618 break;
1619 case V4L2_CID_PRIVATE_AGC_CRUSH:
1620 btv->opt_adc_crush = c->value;
1621 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1622 BT848_ADC);
1623 break;
1624 case V4L2_CID_PRIVATE_VCR_HACK:
1625 btv->opt_vcr_hack = c->value;
1626 break;
1627 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1628 btv->opt_whitecrush_upper = c->value;
1629 btwrite(c->value, BT848_WC_UP);
1630 break;
1631 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1632 btv->opt_whitecrush_lower = c->value;
1633 btwrite(c->value, BT848_WC_DOWN);
1634 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001635 case V4L2_CID_PRIVATE_UV_RATIO:
1636 btv->opt_uv_ratio = c->value;
1637 bt848_sat(btv, btv->saturation);
1638 break;
1639 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1640 btv->opt_full_luma_range = c->value;
1641 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1642 break;
1643 case V4L2_CID_PRIVATE_CORING:
1644 btv->opt_coring = c->value;
1645 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1646 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 default:
1648 return -EINVAL;
1649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 return 0;
1651}
1652
1653/* ----------------------------------------------------------------------- */
1654
1655void bttv_gpio_tracking(struct bttv *btv, char *comment)
1656{
1657 unsigned int outbits, data;
1658 outbits = btread(BT848_GPIO_OUT_EN);
1659 data = btread(BT848_GPIO_DATA);
1660 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1661 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1662}
1663
1664static void bttv_field_count(struct bttv *btv)
1665{
1666 int need_count = 0;
1667
1668 if (btv->users)
1669 need_count++;
1670
1671 if (need_count) {
1672 /* start field counter */
1673 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1674 } else {
1675 /* stop field counter */
1676 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1677 btv->field_count = 0;
1678 }
1679}
1680
1681static const struct bttv_format*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682format_by_fourcc(int fourcc)
1683{
1684 unsigned int i;
1685
1686 for (i = 0; i < BTTV_FORMATS; i++) {
1687 if (-1 == bttv_formats[i].fourcc)
1688 continue;
1689 if (bttv_formats[i].fourcc == fourcc)
1690 return bttv_formats+i;
1691 }
1692 return NULL;
1693}
1694
1695/* ----------------------------------------------------------------------- */
1696/* misc helpers */
1697
1698static int
1699bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1700 struct bttv_buffer *new)
1701{
1702 struct bttv_buffer *old;
1703 unsigned long flags;
1704 int retval = 0;
1705
1706 dprintk("switch_overlay: enter [new=%p]\n",new);
1707 if (new)
1708 new->vb.state = STATE_DONE;
1709 spin_lock_irqsave(&btv->s_lock,flags);
1710 old = btv->screen;
1711 btv->screen = new;
1712 btv->loop_irq |= 1;
1713 bttv_set_dma(btv, 0x03);
1714 spin_unlock_irqrestore(&btv->s_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 if (NULL != old) {
1716 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001717 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 kfree(old);
1719 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03001720 if (NULL == new)
1721 free_btres(btv,fh,RESOURCE_OVERLAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 dprintk("switch_overlay: done\n");
1723 return retval;
1724}
1725
1726/* ----------------------------------------------------------------------- */
1727/* video4linux (1) interface */
1728
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001729static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1730 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001731 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 unsigned int width, unsigned int height,
1733 enum v4l2_field field)
1734{
Michael Schimeke5bd0262007-01-18 16:17:39 -03001735 struct bttv_fh *fh = q->priv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 int redo_dma_risc = 0;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001737 struct bttv_crop c;
1738 int norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 int rc;
1740
1741 /* check settings */
1742 if (NULL == fmt)
1743 return -EINVAL;
1744 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1745 width = RAW_BPL;
1746 height = RAW_LINES*2;
1747 if (width*height > buf->vb.bsize)
1748 return -EINVAL;
1749 buf->vb.size = buf->vb.bsize;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001750
1751 /* Make sure tvnorm and vbi_end remain consistent
1752 until we're done. */
1753 mutex_lock(&btv->lock);
1754
1755 norm = btv->tvnorm;
1756
1757 /* In this mode capturing always starts at defrect.top
1758 (default VDELAY), ignoring cropping parameters. */
1759 if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
1760 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001762 }
1763
1764 mutex_unlock(&btv->lock);
1765
1766 c.rect = bttv_tvnorms[norm].cropcap.defrect;
1767 } else {
1768 mutex_lock(&btv->lock);
1769
1770 norm = btv->tvnorm;
1771 c = btv->crop[!!fh->do_crop];
1772
1773 mutex_unlock(&btv->lock);
1774
1775 if (width < c.min_scaled_width ||
1776 width > c.max_scaled_width ||
1777 height < c.min_scaled_height)
1778 return -EINVAL;
1779
1780 switch (field) {
1781 case V4L2_FIELD_TOP:
1782 case V4L2_FIELD_BOTTOM:
1783 case V4L2_FIELD_ALTERNATE:
1784 /* btv->crop counts frame lines. Max. scale
1785 factor is 16:1 for frames, 8:1 for fields. */
1786 if (height * 2 > c.max_scaled_height)
1787 return -EINVAL;
1788 break;
1789
1790 default:
1791 if (height > c.max_scaled_height)
1792 return -EINVAL;
1793 break;
1794 }
1795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 buf->vb.size = (width * height * fmt->depth) >> 3;
1797 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1798 return -EINVAL;
1799 }
1800
1801 /* alloc + fill struct bttv_buffer (if changed) */
1802 if (buf->vb.width != width || buf->vb.height != height ||
1803 buf->vb.field != field ||
Michael Schimeke5bd0262007-01-18 16:17:39 -03001804 buf->tvnorm != norm || buf->fmt != fmt ||
1805 buf->crop.top != c.rect.top ||
1806 buf->crop.left != c.rect.left ||
1807 buf->crop.width != c.rect.width ||
1808 buf->crop.height != c.rect.height) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 buf->vb.width = width;
1810 buf->vb.height = height;
1811 buf->vb.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001812 buf->tvnorm = norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 buf->fmt = fmt;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001814 buf->crop = c.rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 redo_dma_risc = 1;
1816 }
1817
1818 /* alloc risc memory */
1819 if (STATE_NEEDS_INIT == buf->vb.state) {
1820 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001821 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 goto fail;
1823 }
1824
1825 if (redo_dma_risc)
1826 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1827 goto fail;
1828
1829 buf->vb.state = STATE_PREPARED;
1830 return 0;
1831
1832 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001833 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 return rc;
1835}
1836
1837static int
1838buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1839{
1840 struct bttv_fh *fh = q->priv_data;
1841
1842 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1843 if (0 == *count)
1844 *count = gbuffers;
1845 while (*size * *count > gbuffers * gbufsize)
1846 (*count)--;
1847 return 0;
1848}
1849
1850static int
1851buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1852 enum v4l2_field field)
1853{
1854 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1855 struct bttv_fh *fh = q->priv_data;
1856
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001857 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 fh->width, fh->height, field);
1859}
1860
1861static void
1862buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1863{
1864 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1865 struct bttv_fh *fh = q->priv_data;
1866 struct bttv *btv = fh->btv;
1867
1868 buf->vb.state = STATE_QUEUED;
1869 list_add_tail(&buf->vb.queue,&btv->capture);
1870 if (!btv->curr.frame_irq) {
1871 btv->loop_irq |= 1;
1872 bttv_set_dma(btv, 0x03);
1873 }
1874}
1875
1876static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1877{
1878 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1879 struct bttv_fh *fh = q->priv_data;
1880
Michael Schimekfeaba7a2007-01-26 08:30:05 -03001881 bttv_dma_free(q,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882}
1883
1884static struct videobuf_queue_ops bttv_video_qops = {
1885 .buf_setup = buffer_setup,
1886 .buf_prepare = buffer_prepare,
1887 .buf_queue = buffer_queue,
1888 .buf_release = buffer_release,
1889};
1890
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1892{
1893 switch (cmd) {
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001894#ifdef CONFIG_VIDEO_V4L1
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001895 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 {
1897 struct video_audio *v = arg;
1898
1899 memset(v,0,sizeof(*v));
1900 strcpy(v->name,"Television");
1901 v->flags |= VIDEO_AUDIO_MUTABLE;
1902 v->mode = VIDEO_SOUND_MONO;
1903
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001904 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 bttv_call_i2c_clients(btv,cmd,v);
1906
1907 /* card specific hooks */
1908 if (btv->audio_hook)
1909 btv->audio_hook(btv,v,0);
1910
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001911 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 return 0;
1913 }
1914 case VIDIOCSAUDIO:
1915 {
1916 struct video_audio *v = arg;
1917 unsigned int audio = v->audio;
1918
1919 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
1920 return -EINVAL;
1921
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001922 mutex_lock(&btv->lock);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001923 audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 bttv_call_i2c_clients(btv,cmd,v);
1925
1926 /* card specific hooks */
1927 if (btv->audio_hook)
1928 btv->audio_hook(btv,v,1);
1929
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001930 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 return 0;
1932 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03001933#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 /* *** v4l2 *** ************************************************ */
1935 case VIDIOC_ENUMSTD:
1936 {
1937 struct v4l2_standard *e = arg;
1938 unsigned int index = e->index;
1939
1940 if (index >= BTTV_TVNORMS)
1941 return -EINVAL;
1942 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
1943 bttv_tvnorms[e->index].name);
1944 e->index = index;
1945 return 0;
1946 }
1947 case VIDIOC_G_STD:
1948 {
1949 v4l2_std_id *id = arg;
1950 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
1951 return 0;
1952 }
1953 case VIDIOC_S_STD:
1954 {
1955 v4l2_std_id *id = arg;
1956 unsigned int i;
1957
1958 for (i = 0; i < BTTV_TVNORMS; i++)
1959 if (*id & bttv_tvnorms[i].v4l2_id)
1960 break;
1961 if (i == BTTV_TVNORMS)
1962 return -EINVAL;
1963
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001964 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 set_tvnorm(btv,i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001966 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 return 0;
1968 }
1969 case VIDIOC_QUERYSTD:
1970 {
1971 v4l2_std_id *id = arg;
1972
1973 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
1974 *id = V4L2_STD_625_50;
1975 else
1976 *id = V4L2_STD_525_60;
1977 return 0;
1978 }
1979
1980 case VIDIOC_ENUMINPUT:
1981 {
1982 struct v4l2_input *i = arg;
1983 unsigned int n;
1984
1985 n = i->index;
1986 if (n >= bttv_tvcards[btv->c.type].video_inputs)
1987 return -EINVAL;
1988 memset(i,0,sizeof(*i));
1989 i->index = n;
1990 i->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab5d9d1712006-11-14 12:40:07 -03001991 i->audioset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 if (i->index == bttv_tvcards[btv->c.type].tuner) {
1993 sprintf(i->name, "Television");
1994 i->type = V4L2_INPUT_TYPE_TUNER;
1995 i->tuner = 0;
1996 } else if (i->index == btv->svhs) {
1997 sprintf(i->name, "S-Video");
1998 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001999 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 }
2001 if (i->index == btv->input) {
2002 __u32 dstatus = btread(BT848_DSTATUS);
2003 if (0 == (dstatus & BT848_DSTATUS_PRES))
2004 i->status |= V4L2_IN_ST_NO_SIGNAL;
2005 if (0 == (dstatus & BT848_DSTATUS_HLOC))
2006 i->status |= V4L2_IN_ST_NO_H_LOCK;
2007 }
2008 for (n = 0; n < BTTV_TVNORMS; n++)
2009 i->std |= bttv_tvnorms[n].v4l2_id;
2010 return 0;
2011 }
2012 case VIDIOC_G_INPUT:
2013 {
2014 int *i = arg;
2015 *i = btv->input;
2016 return 0;
2017 }
2018 case VIDIOC_S_INPUT:
2019 {
2020 unsigned int *i = arg;
2021
2022 if (*i > bttv_tvcards[btv->c.type].video_inputs)
2023 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002024 mutex_lock(&btv->lock);
Trent Piepho333408f2007-07-03 15:08:10 -03002025 set_input(btv, *i, btv->tvnorm);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002026 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 return 0;
2028 }
2029
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 case VIDIOC_S_TUNER:
2031 {
2032 struct v4l2_tuner *t = arg;
2033
2034 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2035 return -EINVAL;
2036 if (0 != t->index)
2037 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002038 mutex_lock(&btv->lock);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002039 bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002040#ifdef CONFIG_VIDEO_V4L1
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002041 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 struct video_audio va;
2043 memset(&va, 0, sizeof(struct video_audio));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 if (t->audmode == V4L2_TUNER_MODE_MONO)
2045 va.mode = VIDEO_SOUND_MONO;
Hans Verkuil301e22d2006-03-18 17:15:00 -03002046 else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
2047 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 va.mode = VIDEO_SOUND_STEREO;
2049 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
2050 va.mode = VIDEO_SOUND_LANG1;
2051 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
2052 va.mode = VIDEO_SOUND_LANG2;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002053 btv->audio_hook(btv,&va,1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002055#endif
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002056 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 return 0;
2058 }
2059
2060 case VIDIOC_G_FREQUENCY:
2061 {
2062 struct v4l2_frequency *f = arg;
2063
2064 memset(f,0,sizeof(*f));
2065 f->type = V4L2_TUNER_ANALOG_TV;
2066 f->frequency = btv->freq;
2067 return 0;
2068 }
2069 case VIDIOC_S_FREQUENCY:
2070 {
2071 struct v4l2_frequency *f = arg;
2072
2073 if (unlikely(f->tuner != 0))
2074 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07002075 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002077 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 btv->freq = f->frequency;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002079 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 if (btv->has_matchbox && btv->radio_user)
2081 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002082 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 return 0;
2084 }
Hans Verkuil299392b2005-11-08 21:37:42 -08002085 case VIDIOC_LOG_STATUS:
2086 {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002087 printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr);
Luiz Capitulino97cb4452005-12-01 00:51:24 -08002088 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002089 printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
Hans Verkuil299392b2005-11-08 21:37:42 -08002090 return 0;
2091 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002092 case VIDIOC_G_CTRL:
2093 return get_control(btv,arg);
2094 case VIDIOC_S_CTRL:
2095 return set_control(btv,arg);
Trent Piepho55c0d102007-06-29 00:17:36 -03002096#ifdef CONFIG_VIDEO_ADV_DEBUG
2097 case VIDIOC_DBG_G_REGISTER:
2098 case VIDIOC_DBG_S_REGISTER:
2099 {
2100 struct v4l2_register *reg = arg;
2101 if (!capable(CAP_SYS_ADMIN))
2102 return -EPERM;
2103 if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
2104 return -EINVAL;
2105 /* bt848 has a 12-bit register space */
2106 reg->reg &= 0xfff;
2107 if (cmd == VIDIOC_DBG_G_REGISTER)
2108 reg->val = btread(reg->reg);
2109 else
2110 btwrite(reg->val, reg->reg);
2111 return 0;
2112 }
2113#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
2115 default:
2116 return -ENOIOCTLCMD;
2117
2118 }
2119 return 0;
2120}
2121
Michael Schimeke5bd0262007-01-18 16:17:39 -03002122/* Given cropping boundaries b and the scaled width and height of a
2123 single field or frame, which must not exceed hardware limits, this
2124 function adjusts the cropping parameters c. */
2125static void
2126bttv_crop_adjust (struct bttv_crop * c,
2127 const struct v4l2_rect * b,
2128 __s32 width,
2129 __s32 height,
2130 enum v4l2_field field)
2131{
2132 __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
2133 __s32 max_left;
2134 __s32 max_top;
2135
2136 if (width < c->min_scaled_width) {
2137 /* Max. hor. scale factor 16:1. */
2138 c->rect.width = width * 16;
2139 } else if (width > c->max_scaled_width) {
2140 /* Min. hor. scale factor 1:1. */
2141 c->rect.width = width;
2142
2143 max_left = b->left + b->width - width;
2144 max_left = min(max_left, (__s32) MAX_HDELAY);
2145 if (c->rect.left > max_left)
2146 c->rect.left = max_left;
2147 }
2148
2149 if (height < c->min_scaled_height) {
2150 /* Max. vert. scale factor 16:1, single fields 8:1. */
2151 c->rect.height = height * 16;
2152 } else if (frame_height > c->max_scaled_height) {
2153 /* Min. vert. scale factor 1:1.
2154 Top and height count field lines times two. */
2155 c->rect.height = (frame_height + 1) & ~1;
2156
2157 max_top = b->top + b->height - c->rect.height;
2158 if (c->rect.top > max_top)
2159 c->rect.top = max_top;
2160 }
2161
2162 bttv_crop_calc_limits(c);
2163}
2164
2165/* Returns an error if scaling to a frame or single field with the given
2166 width and height is not possible with the current cropping parameters
2167 and width aligned according to width_mask. If adjust_size is TRUE the
2168 function may adjust the width and/or height instead, rounding width
2169 to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
2170 also adjust the current cropping parameters to get closer to the
2171 desired image size. */
2172static int
2173limit_scaled_size (struct bttv_fh * fh,
2174 __s32 * width,
2175 __s32 * height,
2176 enum v4l2_field field,
2177 unsigned int width_mask,
2178 unsigned int width_bias,
2179 int adjust_size,
2180 int adjust_crop)
2181{
2182 struct bttv *btv = fh->btv;
2183 const struct v4l2_rect *b;
2184 struct bttv_crop *c;
2185 __s32 min_width;
2186 __s32 min_height;
2187 __s32 max_width;
2188 __s32 max_height;
2189 int rc;
2190
2191 BUG_ON((int) width_mask >= 0 ||
2192 width_bias >= (unsigned int) -width_mask);
2193
2194 /* Make sure tvnorm, vbi_end and the current cropping parameters
2195 remain consistent until we're done. */
2196 mutex_lock(&btv->lock);
2197
2198 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
2199
2200 /* Do crop - use current, don't - use default parameters. */
2201 c = &btv->crop[!!fh->do_crop];
2202
2203 if (fh->do_crop
2204 && adjust_size
2205 && adjust_crop
2206 && !locked_btres(btv, VIDEO_RESOURCES)) {
2207 min_width = 48;
2208 min_height = 32;
2209
2210 /* We cannot scale up. When the scaled image is larger
2211 than crop.rect we adjust the crop.rect as required
2212 by the V4L2 spec, hence cropcap.bounds are our limit. */
2213 max_width = min(b->width, (__s32) MAX_HACTIVE);
2214 max_height = b->height;
2215
2216 /* We cannot capture the same line as video and VBI data.
2217 Note btv->vbi_end is really a minimum, see
2218 bttv_vbi_try_fmt(). */
2219 if (btv->vbi_end > b->top) {
2220 max_height -= btv->vbi_end - b->top;
2221 rc = -EBUSY;
2222 if (min_height > max_height)
2223 goto fail;
2224 }
2225 } else {
2226 rc = -EBUSY;
2227 if (btv->vbi_end > c->rect.top)
2228 goto fail;
2229
2230 min_width = c->min_scaled_width;
2231 min_height = c->min_scaled_height;
2232 max_width = c->max_scaled_width;
2233 max_height = c->max_scaled_height;
2234
2235 adjust_crop = 0;
2236 }
2237
2238 min_width = (min_width - width_mask - 1) & width_mask;
2239 max_width = max_width & width_mask;
2240
2241 /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
2242 min_height = min_height;
2243 /* Min. scale factor is 1:1. */
2244 max_height >>= !V4L2_FIELD_HAS_BOTH(field);
2245
2246 if (adjust_size) {
2247 *width = clamp(*width, min_width, max_width);
2248 *height = clamp(*height, min_height, max_height);
2249
2250 /* Round after clamping to avoid overflow. */
2251 *width = (*width + width_bias) & width_mask;
2252
2253 if (adjust_crop) {
2254 bttv_crop_adjust(c, b, *width, *height, field);
2255
2256 if (btv->vbi_end > c->rect.top) {
2257 /* Move the crop window out of the way. */
2258 c->rect.top = btv->vbi_end;
2259 }
2260 }
2261 } else {
2262 rc = -EINVAL;
2263 if (*width < min_width ||
2264 *height < min_height ||
2265 *width > max_width ||
2266 *height > max_height ||
2267 0 != (*width & ~width_mask))
2268 goto fail;
2269 }
2270
2271 rc = 0; /* success */
2272
2273 fail:
2274 mutex_unlock(&btv->lock);
2275
2276 return rc;
2277}
2278
2279/* Returns an error if the given overlay window dimensions are not
2280 possible with the current cropping parameters. If adjust_size is
2281 TRUE the function may adjust the window width and/or height
2282 instead, however it always rounds the horizontal position and
2283 width as btcx_align() does. If adjust_crop is TRUE the function
2284 may also adjust the current cropping parameters to get closer
2285 to the desired window size. */
2286static int
2287verify_window (struct bttv_fh * fh,
2288 struct v4l2_window * win,
2289 int adjust_size,
2290 int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291{
2292 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002293 unsigned int width_mask;
2294 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
2296 if (win->w.width < 48 || win->w.height < 32)
2297 return -EINVAL;
2298 if (win->clipcount > 2048)
2299 return -EINVAL;
2300
2301 field = win->field;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
2303 if (V4L2_FIELD_ANY == field) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03002304 __s32 height2;
2305
2306 height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
2307 field = (win->w.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 ? V4L2_FIELD_INTERLACED
2309 : V4L2_FIELD_TOP;
2310 }
2311 switch (field) {
2312 case V4L2_FIELD_TOP:
2313 case V4L2_FIELD_BOTTOM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 case V4L2_FIELD_INTERLACED:
2315 break;
2316 default:
2317 return -EINVAL;
2318 }
2319
Michael Schimeke5bd0262007-01-18 16:17:39 -03002320 /* 4-byte alignment. */
2321 if (NULL == fh->ovfmt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002323 width_mask = ~0;
2324 switch (fh->ovfmt->depth) {
2325 case 8:
2326 case 24:
2327 width_mask = ~3;
2328 break;
2329 case 16:
2330 width_mask = ~1;
2331 break;
2332 case 32:
2333 break;
2334 default:
2335 BUG();
2336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
Michael Schimeke5bd0262007-01-18 16:17:39 -03002338 win->w.width -= win->w.left & ~width_mask;
2339 win->w.left = (win->w.left - width_mask - 1) & width_mask;
2340
2341 rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
2342 field, width_mask,
2343 /* width_bias: round down */ 0,
2344 adjust_size, adjust_crop);
2345 if (0 != rc)
2346 return rc;
2347
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 win->field = field;
2349 return 0;
2350}
2351
2352static int setup_window(struct bttv_fh *fh, struct bttv *btv,
2353 struct v4l2_window *win, int fixup)
2354{
2355 struct v4l2_clip *clips = NULL;
2356 int n,size,retval = 0;
2357
2358 if (NULL == fh->ovfmt)
2359 return -EINVAL;
2360 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
2361 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002362 retval = verify_window(fh, win,
2363 /* adjust_size */ fixup,
2364 /* adjust_crop */ fixup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 if (0 != retval)
2366 return retval;
2367
2368 /* copy clips -- luckily v4l1 + v4l2 are binary
2369 compatible here ...*/
2370 n = win->clipcount;
2371 size = sizeof(*clips)*(n+4);
2372 clips = kmalloc(size,GFP_KERNEL);
2373 if (NULL == clips)
2374 return -ENOMEM;
2375 if (n > 0) {
2376 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
2377 kfree(clips);
2378 return -EFAULT;
2379 }
2380 }
2381 /* clip against screen */
2382 if (NULL != btv->fbuf.base)
2383 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
2384 &win->w, clips, n);
2385 btcx_sort_clips(clips,n);
2386
2387 /* 4-byte alignments */
2388 switch (fh->ovfmt->depth) {
2389 case 8:
2390 case 24:
2391 btcx_align(&win->w, clips, n, 3);
2392 break;
2393 case 16:
2394 btcx_align(&win->w, clips, n, 1);
2395 break;
2396 case 32:
2397 /* no alignment fixups needed */
2398 break;
2399 default:
2400 BUG();
2401 }
2402
Ingo Molnar3593cab2006-02-07 06:49:14 -02002403 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002404 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 fh->ov.clips = clips;
2406 fh->ov.nclips = n;
2407
2408 fh->ov.w = win->w;
2409 fh->ov.field = win->field;
2410 fh->ov.setup_ok = 1;
2411 btv->init.ov.w.width = win->w.width;
2412 btv->init.ov.w.height = win->w.height;
2413 btv->init.ov.field = win->field;
2414
2415 /* update overlay if needed */
2416 retval = 0;
2417 if (check_btres(fh, RESOURCE_OVERLAY)) {
2418 struct bttv_buffer *new;
2419
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03002420 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03002421 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2423 retval = bttv_switch_overlay(btv,fh,new);
2424 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002425 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 return retval;
2427}
2428
2429/* ----------------------------------------------------------------------- */
2430
2431static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2432{
2433 struct videobuf_queue* q = NULL;
2434
2435 switch (fh->type) {
2436 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2437 q = &fh->cap;
2438 break;
2439 case V4L2_BUF_TYPE_VBI_CAPTURE:
2440 q = &fh->vbi;
2441 break;
2442 default:
2443 BUG();
2444 }
2445 return q;
2446}
2447
2448static int bttv_resource(struct bttv_fh *fh)
2449{
2450 int res = 0;
2451
2452 switch (fh->type) {
2453 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002454 res = RESOURCE_VIDEO_STREAM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 break;
2456 case V4L2_BUF_TYPE_VBI_CAPTURE:
2457 res = RESOURCE_VBI;
2458 break;
2459 default:
2460 BUG();
2461 }
2462 return res;
2463}
2464
2465static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2466{
2467 struct videobuf_queue *q = bttv_queue(fh);
2468 int res = bttv_resource(fh);
2469
2470 if (check_btres(fh,res))
2471 return -EBUSY;
2472 if (videobuf_queue_is_busy(q))
2473 return -EBUSY;
2474 fh->type = type;
2475 return 0;
2476}
2477
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002478static void
2479pix_format_set_size (struct v4l2_pix_format * f,
2480 const struct bttv_format * fmt,
2481 unsigned int width,
2482 unsigned int height)
2483{
2484 f->width = width;
2485 f->height = height;
2486
2487 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2488 f->bytesperline = width; /* Y plane */
2489 f->sizeimage = (width * height * fmt->depth) >> 3;
2490 } else {
2491 f->bytesperline = (width * fmt->depth) >> 3;
2492 f->sizeimage = height * f->bytesperline;
2493 }
2494}
2495
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2497{
2498 switch (f->type) {
2499 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2500 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002501 pix_format_set_size (&f->fmt.pix, fh->fmt,
2502 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 f->fmt.pix.field = fh->cap.field;
2504 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 return 0;
2506 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2507 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2508 f->fmt.win.w = fh->ov.w;
2509 f->fmt.win.field = fh->ov.field;
2510 return 0;
2511 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002512 bttv_vbi_get_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 return 0;
2514 default:
2515 return -EINVAL;
2516 }
2517}
2518
2519static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
Michael Schimeke5bd0262007-01-18 16:17:39 -03002520 struct v4l2_format *f, int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521{
2522 switch (f->type) {
2523 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2524 {
2525 const struct bttv_format *fmt;
2526 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002527 __s32 width, height;
2528 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2531 if (NULL == fmt)
2532 return -EINVAL;
2533
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 field = f->fmt.pix.field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002535 if (V4L2_FIELD_ANY == field) {
2536 __s32 height2;
2537
2538 height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
2539 field = (f->fmt.pix.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 ? V4L2_FIELD_INTERLACED
2541 : V4L2_FIELD_BOTTOM;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 if (V4L2_FIELD_SEQ_BT == field)
2544 field = V4L2_FIELD_SEQ_TB;
2545 switch (field) {
2546 case V4L2_FIELD_TOP:
2547 case V4L2_FIELD_BOTTOM:
2548 case V4L2_FIELD_ALTERNATE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 case V4L2_FIELD_INTERLACED:
2550 break;
2551 case V4L2_FIELD_SEQ_TB:
2552 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2553 return -EINVAL;
2554 break;
2555 default:
2556 return -EINVAL;
2557 }
2558
Michael Schimeke5bd0262007-01-18 16:17:39 -03002559 width = f->fmt.pix.width;
2560 height = f->fmt.pix.height;
2561
2562 rc = limit_scaled_size(fh, &width, &height, field,
2563 /* width_mask: 4 pixels */ ~3,
2564 /* width_bias: nearest */ 2,
2565 /* adjust_size */ 1,
2566 adjust_crop);
2567 if (0 != rc)
2568 return rc;
2569
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 /* update data for the application */
2571 f->fmt.pix.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002572 pix_format_set_size(&f->fmt.pix, fmt, width, height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573
2574 return 0;
2575 }
2576 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002577 return verify_window(fh, &f->fmt.win,
2578 /* adjust_size */ 1,
2579 /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002581 return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 default:
2583 return -EINVAL;
2584 }
2585}
2586
2587static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2588 struct v4l2_format *f)
2589{
2590 int retval;
2591
2592 switch (f->type) {
2593 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2594 {
2595 const struct bttv_format *fmt;
2596
2597 retval = bttv_switch_type(fh,f->type);
2598 if (0 != retval)
2599 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002600 retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 if (0 != retval)
2602 return retval;
2603 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2604
2605 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002606 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 fh->fmt = fmt;
2608 fh->cap.field = f->fmt.pix.field;
2609 fh->cap.last = V4L2_FIELD_NONE;
2610 fh->width = f->fmt.pix.width;
2611 fh->height = f->fmt.pix.height;
2612 btv->init.fmt = fmt;
2613 btv->init.width = f->fmt.pix.width;
2614 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002615 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
2617 return 0;
2618 }
2619 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002620 if (no_overlay > 0) {
2621 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2622 return -EINVAL;
2623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 return setup_window(fh, btv, &f->fmt.win, 1);
2625 case V4L2_BUF_TYPE_VBI_CAPTURE:
2626 retval = bttv_switch_type(fh,f->type);
2627 if (0 != retval)
2628 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002629 return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 default:
2631 return -EINVAL;
2632 }
2633}
2634
2635static int bttv_do_ioctl(struct inode *inode, struct file *file,
2636 unsigned int cmd, void *arg)
2637{
2638 struct bttv_fh *fh = file->private_data;
2639 struct bttv *btv = fh->btv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 int retval = 0;
2641
Michael Krufky5e453dc2006-01-09 15:32:31 -02002642 if (bttv_debug > 1)
2643 v4l_print_ioctl(btv->c.name, cmd);
2644
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 if (btv->errors)
2646 bttv_reinit_bt848(btv);
2647
2648 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 case VIDIOC_S_CTRL:
2650 case VIDIOC_S_STD:
2651 case VIDIOC_S_INPUT:
2652 case VIDIOC_S_TUNER:
2653 case VIDIOC_S_FREQUENCY:
2654 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2655 if (0 != retval)
2656 return retval;
2657 };
2658
2659 switch (cmd) {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002660#ifdef CONFIG_VIDEO_V4L1_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 case VIDIOCGMBUF:
2662 {
2663 struct video_mbuf *mbuf = arg;
2664 unsigned int i;
2665
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
2667 V4L2_MEMORY_MMAP);
2668 if (retval < 0)
Gregor Jasnyd9030f52008-01-06 11:15:54 -03002669 return retval;
Brandon Philips49ee7182007-10-05 16:26:27 -03002670
2671 gbuffers = retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 memset(mbuf,0,sizeof(*mbuf));
2673 mbuf->frames = gbuffers;
2674 mbuf->size = gbuffers * gbufsize;
2675 for (i = 0; i < gbuffers; i++)
2676 mbuf->offsets[i] = i * gbufsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 return 0;
2678 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002679#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
2681 /* *** v4l2 *** ************************************************ */
2682 case VIDIOC_QUERYCAP:
2683 {
2684 struct v4l2_capability *cap = arg;
2685
2686 if (0 == v4l2)
2687 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002688 memset(cap, 0, sizeof (*cap));
2689 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
2690 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
2691 snprintf(cap->bus_info, sizeof (cap->bus_info),
2692 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 cap->version = BTTV_VERSION_CODE;
2694 cap->capabilities =
2695 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 V4L2_CAP_VBI_CAPTURE |
2697 V4L2_CAP_READWRITE |
2698 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002699 if (no_overlay <= 0)
2700 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
2701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
2703 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
2704 cap->capabilities |= V4L2_CAP_TUNER;
2705 return 0;
2706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 case VIDIOC_ENUM_FMT:
2708 {
2709 struct v4l2_fmtdesc *f = arg;
2710 enum v4l2_buf_type type;
2711 unsigned int i;
2712 int index;
2713
2714 type = f->type;
2715 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
2716 /* vbi */
2717 index = f->index;
2718 if (0 != index)
2719 return -EINVAL;
2720 memset(f,0,sizeof(*f));
2721 f->index = index;
2722 f->type = type;
2723 f->pixelformat = V4L2_PIX_FMT_GREY;
2724 strcpy(f->description,"vbi data");
2725 return 0;
2726 }
2727
2728 /* video capture + overlay */
2729 index = -1;
2730 for (i = 0; i < BTTV_FORMATS; i++) {
2731 if (bttv_formats[i].fourcc != -1)
2732 index++;
2733 if ((unsigned int)index == f->index)
2734 break;
2735 }
2736 if (BTTV_FORMATS == i)
2737 return -EINVAL;
2738
2739 switch (f->type) {
2740 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2741 break;
2742 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2743 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
2744 return -EINVAL;
2745 break;
2746 default:
2747 return -EINVAL;
2748 }
2749 memset(f,0,sizeof(*f));
2750 f->index = index;
2751 f->type = type;
2752 f->pixelformat = bttv_formats[i].fourcc;
2753 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
2754 return 0;
2755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 case VIDIOC_TRY_FMT:
2757 {
2758 struct v4l2_format *f = arg;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002759 return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 }
2761 case VIDIOC_G_FMT:
2762 {
2763 struct v4l2_format *f = arg;
2764 return bttv_g_fmt(fh,f);
2765 }
2766 case VIDIOC_S_FMT:
2767 {
2768 struct v4l2_format *f = arg;
2769 return bttv_s_fmt(fh,btv,f);
2770 }
2771
2772 case VIDIOC_G_FBUF:
2773 {
2774 struct v4l2_framebuffer *fb = arg;
2775
2776 *fb = btv->fbuf;
2777 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
2778 if (fh->ovfmt)
2779 fb->fmt.pixelformat = fh->ovfmt->fourcc;
2780 return 0;
2781 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002782 case VIDIOC_OVERLAY:
2783 {
2784 struct bttv_buffer *new;
2785 int *on = arg;
2786
2787 if (*on) {
2788 /* verify args */
2789 if (NULL == btv->fbuf.base)
2790 return -EINVAL;
2791 if (!fh->ov.setup_ok) {
2792 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2793 return -EINVAL;
2794 }
2795 }
2796
2797 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
2798 return -EBUSY;
2799
2800 mutex_lock(&fh->cap.lock);
2801 if (*on) {
2802 fh->ov.tvnorm = btv->tvnorm;
2803 new = videobuf_pci_alloc(sizeof(*new));
2804 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2805 } else {
2806 new = NULL;
2807 }
2808
2809 /* switch over */
2810 retval = bttv_switch_overlay(btv,fh,new);
2811 mutex_unlock(&fh->cap.lock);
2812 return retval;
2813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 case VIDIOC_S_FBUF:
2815 {
2816 struct v4l2_framebuffer *fb = arg;
2817 const struct bttv_format *fmt;
2818
2819 if(!capable(CAP_SYS_ADMIN) &&
2820 !capable(CAP_SYS_RAWIO))
2821 return -EPERM;
2822
2823 /* check args */
2824 fmt = format_by_fourcc(fb->fmt.pixelformat);
2825 if (NULL == fmt)
2826 return -EINVAL;
2827 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
2828 return -EINVAL;
2829
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 retval = -EINVAL;
2831 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03002832 __s32 width = fb->fmt.width;
2833 __s32 height = fb->fmt.height;
2834
2835 retval = limit_scaled_size(fh, &width, &height,
2836 V4L2_FIELD_INTERLACED,
2837 /* width_mask */ ~3,
2838 /* width_bias */ 2,
2839 /* adjust_size */ 0,
2840 /* adjust_crop */ 0);
2841 if (0 != retval)
2842 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 }
2844
2845 /* ok, accept it */
Michael Schimeke5bd0262007-01-18 16:17:39 -03002846 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 btv->fbuf.base = fb->base;
2848 btv->fbuf.fmt.width = fb->fmt.width;
2849 btv->fbuf.fmt.height = fb->fmt.height;
2850 if (0 != fb->fmt.bytesperline)
2851 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
2852 else
2853 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
2854
2855 retval = 0;
2856 fh->ovfmt = fmt;
2857 btv->init.ovfmt = fmt;
2858 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
2859 fh->ov.w.left = 0;
2860 fh->ov.w.top = 0;
2861 fh->ov.w.width = fb->fmt.width;
2862 fh->ov.w.height = fb->fmt.height;
2863 btv->init.ov.w.width = fb->fmt.width;
2864 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002865 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 fh->ov.clips = NULL;
2867 fh->ov.nclips = 0;
2868
2869 if (check_btres(fh, RESOURCE_OVERLAY)) {
2870 struct bttv_buffer *new;
2871
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03002872 new = videobuf_pci_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03002873 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
2875 retval = bttv_switch_overlay(btv,fh,new);
2876 }
2877 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002878 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 return retval;
2880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 case VIDIOC_REQBUFS:
2882 return videobuf_reqbufs(bttv_queue(fh),arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 case VIDIOC_QUERYBUF:
2884 return videobuf_querybuf(bttv_queue(fh),arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 case VIDIOC_QBUF:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002886 {
2887 int res = bttv_resource(fh);
2888
2889 if (!check_alloc_btres(btv, fh, res))
2890 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 return videobuf_qbuf(bttv_queue(fh),arg);
Michael Schimeke5bd0262007-01-18 16:17:39 -03002892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 case VIDIOC_DQBUF:
2894 return videobuf_dqbuf(bttv_queue(fh),arg,
2895 file->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 case VIDIOC_STREAMON:
2897 {
2898 int res = bttv_resource(fh);
2899
2900 if (!check_alloc_btres(btv,fh,res))
2901 return -EBUSY;
2902 return videobuf_streamon(bttv_queue(fh));
2903 }
2904 case VIDIOC_STREAMOFF:
2905 {
2906 int res = bttv_resource(fh);
2907
2908 retval = videobuf_streamoff(bttv_queue(fh));
2909 if (retval < 0)
2910 return retval;
2911 free_btres(btv,fh,res);
2912 return 0;
2913 }
2914
2915 case VIDIOC_QUERYCTRL:
2916 {
2917 struct v4l2_queryctrl *c = arg;
2918 int i;
2919
2920 if ((c->id < V4L2_CID_BASE ||
2921 c->id >= V4L2_CID_LASTP1) &&
2922 (c->id < V4L2_CID_PRIVATE_BASE ||
2923 c->id >= V4L2_CID_PRIVATE_LASTP1))
2924 return -EINVAL;
2925 for (i = 0; i < BTTV_CTLS; i++)
2926 if (bttv_ctls[i].id == c->id)
2927 break;
2928 if (i == BTTV_CTLS) {
2929 *c = no_ctl;
2930 return 0;
2931 }
2932 *c = bttv_ctls[i];
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002933#ifdef CONFIG_VIDEO_V4L1
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002934 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 struct video_audio va;
2936 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002937 btv->audio_hook(btv,&va,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 switch (bttv_ctls[i].id) {
2939 case V4L2_CID_AUDIO_VOLUME:
2940 if (!(va.flags & VIDEO_AUDIO_VOLUME))
2941 *c = no_ctl;
2942 break;
2943 case V4L2_CID_AUDIO_BALANCE:
2944 if (!(va.flags & VIDEO_AUDIO_BALANCE))
2945 *c = no_ctl;
2946 break;
2947 case V4L2_CID_AUDIO_BASS:
2948 if (!(va.flags & VIDEO_AUDIO_BASS))
2949 *c = no_ctl;
2950 break;
2951 case V4L2_CID_AUDIO_TREBLE:
2952 if (!(va.flags & VIDEO_AUDIO_TREBLE))
2953 *c = no_ctl;
2954 break;
2955 }
2956 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002957#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 return 0;
2959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 case VIDIOC_G_PARM:
2961 {
2962 struct v4l2_streamparm *parm = arg;
2963 struct v4l2_standard s;
2964 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
2965 return -EINVAL;
2966 memset(parm,0,sizeof(*parm));
2967 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
2968 bttv_tvnorms[btv->tvnorm].name);
2969 parm->parm.capture.timeperframe = s.frameperiod;
2970 return 0;
2971 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002972 case VIDIOC_G_TUNER:
2973 {
2974 struct v4l2_tuner *t = arg;
2975
2976 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2977 return -EINVAL;
2978 if (0 != t->index)
2979 return -EINVAL;
2980 mutex_lock(&btv->lock);
2981 memset(t,0,sizeof(*t));
2982 t->rxsubchans = V4L2_TUNER_SUB_MONO;
2983 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
2984 strcpy(t->name, "Television");
2985 t->capability = V4L2_TUNER_CAP_NORM;
2986 t->type = V4L2_TUNER_ANALOG_TV;
2987 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
2988 t->signal = 0xffff;
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03002989#ifdef CONFIG_VIDEO_V4L1
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03002990 if (btv->audio_hook) {
2991 /* Hmmm ... */
2992 struct video_audio va;
2993 memset(&va, 0, sizeof(struct video_audio));
2994 btv->audio_hook(btv,&va,0);
2995 t->audmode = V4L2_TUNER_MODE_MONO;
2996 t->rxsubchans = V4L2_TUNER_SUB_MONO;
2997 if(va.mode & VIDEO_SOUND_STEREO) {
2998 t->audmode = V4L2_TUNER_MODE_STEREO;
2999 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
3000 }
3001 if(va.mode & VIDEO_SOUND_LANG2) {
3002 t->audmode = V4L2_TUNER_MODE_LANG1;
3003 t->rxsubchans = V4L2_TUNER_SUB_LANG1
3004 | V4L2_TUNER_SUB_LANG2;
3005 }
3006 }
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03003007#endif
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003008 /* FIXME: fill capability+audmode */
3009 mutex_unlock(&btv->lock);
3010 return 0;
3011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012
3013 case VIDIOC_G_PRIORITY:
3014 {
3015 enum v4l2_priority *p = arg;
3016
3017 *p = v4l2_prio_max(&btv->prio);
3018 return 0;
3019 }
3020 case VIDIOC_S_PRIORITY:
3021 {
3022 enum v4l2_priority *prio = arg;
3023
3024 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
3025 }
3026
Michael Schimeke5bd0262007-01-18 16:17:39 -03003027 case VIDIOC_CROPCAP:
3028 {
3029 struct v4l2_cropcap *cap = arg;
3030 enum v4l2_buf_type type;
3031
3032 type = cap->type;
3033
3034 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3035 type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3036 return -EINVAL;
3037
3038 *cap = bttv_tvnorms[btv->tvnorm].cropcap;
3039 cap->type = type;
3040
3041 return 0;
3042 }
3043 case VIDIOC_G_CROP:
3044 {
3045 struct v4l2_crop * crop = arg;
3046
3047 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3048 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3049 return -EINVAL;
3050
3051 /* No fh->do_crop = 1; because btv->crop[1] may be
3052 inconsistent with fh->width or fh->height and apps
3053 do not expect a change here. */
3054
3055 crop->c = btv->crop[!!fh->do_crop].rect;
3056
3057 return 0;
3058 }
3059 case VIDIOC_S_CROP:
3060 {
3061 struct v4l2_crop *crop = arg;
3062 const struct v4l2_rect *b;
3063 struct bttv_crop c;
3064 __s32 b_left;
3065 __s32 b_top;
3066 __s32 b_right;
3067 __s32 b_bottom;
3068
3069 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3070 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3071 return -EINVAL;
3072
3073 retval = v4l2_prio_check(&btv->prio,&fh->prio);
3074 if (0 != retval)
3075 return retval;
3076
3077 /* Make sure tvnorm, vbi_end and the current cropping
3078 parameters remain consistent until we're done. Note
3079 read() may change vbi_end in check_alloc_btres(). */
3080 mutex_lock(&btv->lock);
3081
3082 retval = -EBUSY;
3083
3084 if (locked_btres(fh->btv, VIDEO_RESOURCES))
3085 goto btv_unlock_and_return;
3086
3087 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
3088
3089 b_left = b->left;
3090 b_right = b_left + b->width;
3091 b_bottom = b->top + b->height;
3092
3093 b_top = max(b->top, btv->vbi_end);
3094 if (b_top + 32 >= b_bottom)
3095 goto btv_unlock_and_return;
3096
3097 /* Min. scaled size 48 x 32. */
3098 c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
3099 c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
3100
3101 c.rect.width = clamp(crop->c.width,
3102 48, b_right - c.rect.left);
3103
3104 c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
3105 /* Top and height must be a multiple of two. */
3106 c.rect.top = (c.rect.top + 1) & ~1;
3107
3108 c.rect.height = clamp(crop->c.height,
3109 32, b_bottom - c.rect.top);
3110 c.rect.height = (c.rect.height + 1) & ~1;
3111
3112 bttv_crop_calc_limits(&c);
3113
3114 btv->crop[1] = c;
3115
3116 mutex_unlock(&btv->lock);
3117
3118 fh->do_crop = 1;
3119
3120 mutex_lock(&fh->cap.lock);
3121
3122 if (fh->width < c.min_scaled_width) {
3123 fh->width = c.min_scaled_width;
3124 btv->init.width = c.min_scaled_width;
3125 } else if (fh->width > c.max_scaled_width) {
3126 fh->width = c.max_scaled_width;
3127 btv->init.width = c.max_scaled_width;
3128 }
3129
3130 if (fh->height < c.min_scaled_height) {
3131 fh->height = c.min_scaled_height;
3132 btv->init.height = c.min_scaled_height;
3133 } else if (fh->height > c.max_scaled_height) {
3134 fh->height = c.max_scaled_height;
3135 btv->init.height = c.max_scaled_height;
3136 }
3137
3138 mutex_unlock(&fh->cap.lock);
3139
3140 return 0;
3141 }
3142
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 case VIDIOC_ENUMSTD:
3144 case VIDIOC_G_STD:
3145 case VIDIOC_S_STD:
3146 case VIDIOC_ENUMINPUT:
3147 case VIDIOC_G_INPUT:
3148 case VIDIOC_S_INPUT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 case VIDIOC_S_TUNER:
3150 case VIDIOC_G_FREQUENCY:
3151 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08003152 case VIDIOC_LOG_STATUS:
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003153 case VIDIOC_G_CTRL:
3154 case VIDIOC_S_CTRL:
Trent Piepho55c0d102007-06-29 00:17:36 -03003155 case VIDIOC_DBG_G_REGISTER:
3156 case VIDIOC_DBG_S_REGISTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 return bttv_common_ioctls(btv,cmd,arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 default:
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03003159 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
3160 bttv_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 }
3162 return 0;
3163
3164 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02003165 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003167
3168 btv_unlock_and_return:
3169 mutex_unlock(&btv->lock);
3170 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171}
3172
3173static int bttv_ioctl(struct inode *inode, struct file *file,
3174 unsigned int cmd, unsigned long arg)
3175{
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003176 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177}
3178
3179static ssize_t bttv_read(struct file *file, char __user *data,
3180 size_t count, loff_t *ppos)
3181{
3182 struct bttv_fh *fh = file->private_data;
3183 int retval = 0;
3184
3185 if (fh->btv->errors)
3186 bttv_reinit_bt848(fh->btv);
3187 dprintk("bttv%d: read count=%d type=%s\n",
3188 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
3189
3190 switch (fh->type) {
3191 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003192 if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
3193 /* VIDEO_READ in use by another fh,
3194 or VIDEO_STREAM by any fh. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 return -EBUSY;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 retval = videobuf_read_one(&fh->cap, data, count, ppos,
3198 file->f_flags & O_NONBLOCK);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003199 free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 break;
3201 case V4L2_BUF_TYPE_VBI_CAPTURE:
3202 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3203 return -EBUSY;
3204 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
3205 file->f_flags & O_NONBLOCK);
3206 break;
3207 default:
3208 BUG();
3209 }
3210 return retval;
3211}
3212
3213static unsigned int bttv_poll(struct file *file, poll_table *wait)
3214{
3215 struct bttv_fh *fh = file->private_data;
3216 struct bttv_buffer *buf;
3217 enum v4l2_field field;
3218
3219 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
3220 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3221 return POLLERR;
3222 return videobuf_poll_stream(file, &fh->vbi, wait);
3223 }
3224
Michael Schimeke5bd0262007-01-18 16:17:39 -03003225 if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 /* streaming capture */
3227 if (list_empty(&fh->cap.stream))
3228 return POLLERR;
3229 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
3230 } else {
3231 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02003232 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 if (NULL == fh->cap.read_buf) {
3234 /* need to capture a new frame */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003235 if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003236 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 return POLLERR;
3238 }
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003239 fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003241 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 return POLLERR;
3243 }
3244 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
3245 field = videobuf_next_field(&fh->cap);
3246 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08003247 kfree (fh->cap.read_buf);
3248 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003249 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 return POLLERR;
3251 }
3252 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3253 fh->cap.read_off = 0;
3254 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003255 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 buf = (struct bttv_buffer*)fh->cap.read_buf;
3257 }
3258
3259 poll_wait(file, &buf->vb.done, wait);
3260 if (buf->vb.state == STATE_DONE ||
3261 buf->vb.state == STATE_ERROR)
3262 return POLLIN|POLLRDNORM;
3263 return 0;
3264}
3265
3266static int bttv_open(struct inode *inode, struct file *file)
3267{
3268 int minor = iminor(inode);
3269 struct bttv *btv = NULL;
3270 struct bttv_fh *fh;
3271 enum v4l2_buf_type type = 0;
3272 unsigned int i;
3273
3274 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3275
3276 for (i = 0; i < bttv_num; i++) {
3277 if (bttvs[i].video_dev &&
3278 bttvs[i].video_dev->minor == minor) {
3279 btv = &bttvs[i];
3280 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3281 break;
3282 }
3283 if (bttvs[i].vbi_dev &&
3284 bttvs[i].vbi_dev->minor == minor) {
3285 btv = &bttvs[i];
3286 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3287 break;
3288 }
3289 }
3290 if (NULL == btv)
3291 return -ENODEV;
3292
3293 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3294 btv->c.nr,v4l2_type_names[type]);
3295
3296 /* allocate per filehandle data */
3297 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3298 if (NULL == fh)
3299 return -ENOMEM;
3300 file->private_data = fh;
3301 *fh = btv->init;
3302 fh->type = type;
3303 fh->ov.setup_ok = 0;
3304 v4l2_prio_open(&btv->prio,&fh->prio);
3305
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003306 videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 btv->c.pci, &btv->s_lock,
3308 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3309 V4L2_FIELD_INTERLACED,
3310 sizeof(struct bttv_buffer),
3311 fh);
Mauro Carvalho Chehabc1accaa2007-08-23 16:37:49 -03003312 videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 btv->c.pci, &btv->s_lock,
3314 V4L2_BUF_TYPE_VBI_CAPTURE,
3315 V4L2_FIELD_SEQ_TB,
3316 sizeof(struct bttv_buffer),
3317 fh);
Nickolay V. Shmyrev302f61a2007-10-26 10:53:21 -03003318 set_tvnorm(btv,btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319
3320 btv->users++;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003321
3322 /* The V4L2 spec requires one global set of cropping parameters
3323 which only change on request. These are stored in btv->crop[1].
3324 However for compatibility with V4L apps and cropping unaware
3325 V4L2 apps we now reset the cropping parameters as seen through
3326 this fh, which is to say VIDIOC_G_CROP and scaling limit checks
3327 will use btv->crop[0], the default cropping parameters for the
3328 current video standard, and VIDIOC_S_FMT will not implicitely
3329 change the cropping parameters until VIDIOC_S_CROP has been
3330 called. */
3331 fh->do_crop = !reset_crop; /* module parameter */
3332
3333 /* Likewise there should be one global set of VBI capture
3334 parameters, but for compatibility with V4L apps and earlier
3335 driver versions each fh has its own parameters. */
3336 bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
3337
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 bttv_field_count(btv);
3339 return 0;
3340}
3341
3342static int bttv_release(struct inode *inode, struct file *file)
3343{
3344 struct bttv_fh *fh = file->private_data;
3345 struct bttv *btv = fh->btv;
3346
3347 /* turn off overlay */
3348 if (check_btres(fh, RESOURCE_OVERLAY))
3349 bttv_switch_overlay(btv,fh,NULL);
3350
3351 /* stop video capture */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003352 if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 videobuf_streamoff(&fh->cap);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003354 free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 }
3356 if (fh->cap.read_buf) {
3357 buffer_release(&fh->cap,fh->cap.read_buf);
3358 kfree(fh->cap.read_buf);
3359 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03003360 if (check_btres(fh, RESOURCE_VIDEO_READ)) {
3361 free_btres(btv, fh, RESOURCE_VIDEO_READ);
3362 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
3364 /* stop vbi capture */
3365 if (check_btres(fh, RESOURCE_VBI)) {
Brandon Philips053fcb62007-11-13 20:11:26 -03003366 videobuf_stop(&fh->vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 free_btres(btv,fh,RESOURCE_VBI);
3368 }
3369
3370 /* free stuff */
3371 videobuf_mmap_free(&fh->cap);
3372 videobuf_mmap_free(&fh->vbi);
3373 v4l2_prio_close(&btv->prio,&fh->prio);
3374 file->private_data = NULL;
3375 kfree(fh);
3376
3377 btv->users--;
3378 bttv_field_count(btv);
3379 return 0;
3380}
3381
3382static int
3383bttv_mmap(struct file *file, struct vm_area_struct *vma)
3384{
3385 struct bttv_fh *fh = file->private_data;
3386
3387 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3388 fh->btv->c.nr, v4l2_type_names[fh->type],
3389 vma->vm_start, vma->vm_end - vma->vm_start);
3390 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3391}
3392
Arjan van de Venfa027c22007-02-12 00:55:33 -08003393static const struct file_operations bttv_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394{
3395 .owner = THIS_MODULE,
3396 .open = bttv_open,
3397 .release = bttv_release,
3398 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003399 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 .llseek = no_llseek,
3401 .read = bttv_read,
3402 .mmap = bttv_mmap,
3403 .poll = bttv_poll,
3404};
3405
3406static struct video_device bttv_video_template =
3407{
3408 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003409 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003410 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 .fops = &bttv_fops,
3412 .minor = -1,
3413};
3414
3415static struct video_device bttv_vbi_template =
3416{
3417 .name = "bt848/878 vbi",
3418 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 .fops = &bttv_fops,
3420 .minor = -1,
3421};
3422
3423/* ----------------------------------------------------------------------- */
3424/* radio interface */
3425
3426static int radio_open(struct inode *inode, struct file *file)
3427{
3428 int minor = iminor(inode);
3429 struct bttv *btv = NULL;
3430 unsigned int i;
3431
3432 dprintk("bttv: open minor=%d\n",minor);
3433
3434 for (i = 0; i < bttv_num; i++) {
3435 if (bttvs[i].radio_dev->minor == minor) {
3436 btv = &bttvs[i];
3437 break;
3438 }
3439 }
3440 if (NULL == btv)
3441 return -ENODEV;
3442
3443 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003444 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003445
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003447
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 file->private_data = btv;
3449
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003450 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3451 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003453 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003454 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455}
3456
3457static int radio_release(struct inode *inode, struct file *file)
3458{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003459 struct bttv *btv = file->private_data;
3460 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461
3462 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003463
3464 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3465
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 return 0;
3467}
3468
3469static int radio_do_ioctl(struct inode *inode, struct file *file,
3470 unsigned int cmd, void *arg)
3471{
3472 struct bttv *btv = file->private_data;
3473
3474 switch (cmd) {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003475 case VIDIOC_QUERYCAP:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003477 struct v4l2_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478
3479 memset(cap,0,sizeof(*cap));
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003480 strcpy(cap->driver, "bttv");
3481 strlcpy(cap->card, btv->radio_dev->name,sizeof(cap->card));
3482 sprintf(cap->bus_info,"PCI:%s",pci_name(btv->c.pci));
3483 cap->version = BTTV_VERSION_CODE;
3484 cap->capabilities = V4L2_CAP_TUNER;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003485 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003487 case VIDIOC_G_TUNER:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003488 {
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003489 struct v4l2_tuner *t = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003491 if (UNSET == bttv_tvcards[btv->c.type].tuner)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003492 return -EINVAL;
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003493 if (0 != t->index)
3494 return -EINVAL;
3495 mutex_lock(&btv->lock);
3496 memset(t,0,sizeof(*t));
3497 strcpy(t->name, "Radio");
3498 t->type = V4L2_TUNER_RADIO;
3499
3500 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
3501
3502 mutex_unlock(&btv->lock);
3503
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003504 return 0;
3505 }
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003506 case VIDIOC_S_TUNER:
3507 case VIDIOC_G_FREQUENCY:
3508 case VIDIOC_S_FREQUENCY:
3509 case VIDIOC_G_CTRL:
3510 case VIDIOC_S_CTRL:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003511 case VIDIOC_LOG_STATUS:
Trent Piepho55c0d102007-06-29 00:17:36 -03003512 case VIDIOC_DBG_G_REGISTER:
3513 case VIDIOC_DBG_S_REGISTER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 return bttv_common_ioctls(btv,cmd,arg);
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03003515 default:
Nickolay V. Shmyreve84619b2007-10-26 11:01:08 -03003516 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
3517 radio_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 }
3519 return 0;
3520}
3521
3522static int radio_ioctl(struct inode *inode, struct file *file,
3523 unsigned int cmd, unsigned long arg)
3524{
3525 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3526}
3527
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003528static ssize_t radio_read(struct file *file, char __user *data,
3529 size_t count, loff_t *ppos)
3530{
3531 struct bttv *btv = file->private_data;
3532 struct rds_command cmd;
3533 cmd.block_count = count/3;
3534 cmd.buffer = data;
3535 cmd.instance = file;
3536 cmd.result = -ENODEV;
3537
3538 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3539
3540 return cmd.result;
3541}
3542
3543static unsigned int radio_poll(struct file *file, poll_table *wait)
3544{
3545 struct bttv *btv = file->private_data;
3546 struct rds_command cmd;
3547 cmd.instance = file;
3548 cmd.event_list = wait;
3549 cmd.result = -ENODEV;
3550 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3551
3552 return cmd.result;
3553}
3554
Arjan van de Venfa027c22007-02-12 00:55:33 -08003555static const struct file_operations radio_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556{
3557 .owner = THIS_MODULE,
3558 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003559 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 .release = radio_release,
3561 .ioctl = radio_ioctl,
3562 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003563 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564};
3565
3566static struct video_device radio_template =
3567{
3568 .name = "bt848/878 radio",
3569 .type = VID_TYPE_TUNER,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 .fops = &radio_fops,
3571 .minor = -1,
3572};
3573
3574/* ----------------------------------------------------------------------- */
3575/* some debug code */
3576
Adrian Bunk408b6642005-05-01 08:59:29 -07003577static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578{
3579 static char *instr[16] = {
3580 [ BT848_RISC_WRITE >> 28 ] = "write",
3581 [ BT848_RISC_SKIP >> 28 ] = "skip",
3582 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3583 [ BT848_RISC_JUMP >> 28 ] = "jump",
3584 [ BT848_RISC_SYNC >> 28 ] = "sync",
3585 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
3586 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
3587 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
3588 };
3589 static int incr[16] = {
3590 [ BT848_RISC_WRITE >> 28 ] = 2,
3591 [ BT848_RISC_JUMP >> 28 ] = 2,
3592 [ BT848_RISC_SYNC >> 28 ] = 2,
3593 [ BT848_RISC_WRITE123 >> 28 ] = 5,
3594 [ BT848_RISC_SKIP123 >> 28 ] = 2,
3595 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
3596 };
3597 static char *bits[] = {
3598 "be0", "be1", "be2", "be3/resync",
3599 "set0", "set1", "set2", "set3",
3600 "clr0", "clr1", "clr2", "clr3",
3601 "irq", "res", "eol", "sol",
3602 };
3603 int i;
3604
3605 printk("0x%08x [ %s", risc,
3606 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
3607 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
3608 if (risc & (1 << (i + 12)))
3609 printk(" %s",bits[i]);
3610 printk(" count=%d ]\n", risc & 0xfff);
3611 return incr[risc >> 28] ? incr[risc >> 28] : 1;
3612}
3613
Adrian Bunk408b6642005-05-01 08:59:29 -07003614static void bttv_risc_disasm(struct bttv *btv,
3615 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616{
3617 unsigned int i,j,n;
3618
3619 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
3620 btv->c.name, risc->cpu, (unsigned long)risc->dma);
3621 for (i = 0; i < (risc->size >> 2); i += n) {
3622 printk("%s: 0x%lx: ", btv->c.name,
3623 (unsigned long)(risc->dma + (i<<2)));
3624 n = bttv_risc_decode(risc->cpu[i]);
3625 for (j = 1; j < n; j++)
3626 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
3627 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
3628 risc->cpu[i+j], j);
3629 if (0 == risc->cpu[i])
3630 break;
3631 }
3632}
3633
3634static void bttv_print_riscaddr(struct bttv *btv)
3635{
3636 printk(" main: %08Lx\n",
3637 (unsigned long long)btv->main.dma);
3638 printk(" vbi : o=%08Lx e=%08Lx\n",
3639 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
3640 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
3641 printk(" cap : o=%08Lx e=%08Lx\n",
3642 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
3643 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
3644 printk(" scr : o=%08Lx e=%08Lx\n",
3645 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
3646 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
3647 bttv_risc_disasm(btv, &btv->main);
3648}
3649
3650/* ----------------------------------------------------------------------- */
3651/* irq handler */
3652
3653static char *irq_name[] = {
3654 "FMTCHG", // format change detected (525 vs. 625)
3655 "VSYNC", // vertical sync (new field)
3656 "HSYNC", // horizontal sync
3657 "OFLOW", // chroma/luma AGC overflow
3658 "HLOCK", // horizontal lock changed
3659 "VPRES", // video presence changed
3660 "6", "7",
3661 "I2CDONE", // hw irc operation finished
3662 "GPINT", // gpio port triggered irq
3663 "10",
3664 "RISCI", // risc instruction triggered irq
3665 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
3666 "FTRGT", // pixel data fifo overrun
3667 "FDSR", // fifo data stream resyncronisation
3668 "PPERR", // parity error (data transfer)
3669 "RIPERR", // parity error (read risc instructions)
3670 "PABORT", // pci abort
3671 "OCERR", // risc instruction error
3672 "SCERR", // syncronisation error
3673};
3674
3675static void bttv_print_irqbits(u32 print, u32 mark)
3676{
3677 unsigned int i;
3678
3679 printk("bits:");
3680 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
3681 if (print & (1 << i))
3682 printk(" %s",irq_name[i]);
3683 if (mark & (1 << i))
3684 printk("*");
3685 }
3686}
3687
3688static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
3689{
3690 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
3691 btv->c.nr,
3692 (unsigned long)btv->main.dma,
3693 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
3694 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
3695 (unsigned long)rc);
3696
3697 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
3698 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
3699 "Ok, then this is harmless, don't worry ;)\n",
3700 btv->c.nr);
3701 return;
3702 }
3703 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
3704 btv->c.nr);
3705 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
3706 btv->c.nr);
3707 dump_stack();
3708}
3709
3710static int
3711bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
3712{
3713 struct bttv_buffer *item;
3714
3715 memset(set,0,sizeof(*set));
3716
3717 /* capture request ? */
3718 if (!list_empty(&btv->capture)) {
3719 set->frame_irq = 1;
3720 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3721 if (V4L2_FIELD_HAS_TOP(item->vb.field))
3722 set->top = item;
3723 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
3724 set->bottom = item;
3725
3726 /* capture request for other field ? */
3727 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
3728 (item->vb.queue.next != &btv->capture)) {
3729 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
3730 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
3731 if (NULL == set->top &&
3732 V4L2_FIELD_TOP == item->vb.field) {
3733 set->top = item;
3734 }
3735 if (NULL == set->bottom &&
3736 V4L2_FIELD_BOTTOM == item->vb.field) {
3737 set->bottom = item;
3738 }
3739 if (NULL != set->top && NULL != set->bottom)
3740 set->top_irq = 2;
3741 }
3742 }
3743 }
3744
3745 /* screen overlay ? */
3746 if (NULL != btv->screen) {
3747 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
3748 if (NULL == set->top && NULL == set->bottom) {
3749 set->top = btv->screen;
3750 set->bottom = btv->screen;
3751 }
3752 } else {
3753 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
3754 NULL == set->top) {
3755 set->top = btv->screen;
3756 }
3757 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
3758 NULL == set->bottom) {
3759 set->bottom = btv->screen;
3760 }
3761 }
3762 }
3763
3764 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
3765 btv->c.nr,set->top, set->bottom,
3766 btv->screen,set->frame_irq,set->top_irq);
3767 return 0;
3768}
3769
3770static void
3771bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
3772 struct bttv_buffer_set *curr, unsigned int state)
3773{
3774 struct timeval ts;
3775
3776 do_gettimeofday(&ts);
3777
3778 if (wakeup->top == wakeup->bottom) {
3779 if (NULL != wakeup->top && curr->top != wakeup->top) {
3780 if (irq_debug > 1)
3781 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
3782 wakeup->top->vb.ts = ts;
3783 wakeup->top->vb.field_count = btv->field_count;
3784 wakeup->top->vb.state = state;
3785 wake_up(&wakeup->top->vb.done);
3786 }
3787 } else {
3788 if (NULL != wakeup->top && curr->top != wakeup->top) {
3789 if (irq_debug > 1)
3790 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
3791 wakeup->top->vb.ts = ts;
3792 wakeup->top->vb.field_count = btv->field_count;
3793 wakeup->top->vb.state = state;
3794 wake_up(&wakeup->top->vb.done);
3795 }
3796 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
3797 if (irq_debug > 1)
3798 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
3799 wakeup->bottom->vb.ts = ts;
3800 wakeup->bottom->vb.field_count = btv->field_count;
3801 wakeup->bottom->vb.state = state;
3802 wake_up(&wakeup->bottom->vb.done);
3803 }
3804 }
3805}
3806
3807static void
3808bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
3809 unsigned int state)
3810{
3811 struct timeval ts;
3812
3813 if (NULL == wakeup)
3814 return;
3815
3816 do_gettimeofday(&ts);
3817 wakeup->vb.ts = ts;
3818 wakeup->vb.field_count = btv->field_count;
3819 wakeup->vb.state = state;
3820 wake_up(&wakeup->vb.done);
3821}
3822
3823static void bttv_irq_timeout(unsigned long data)
3824{
3825 struct bttv *btv = (struct bttv *)data;
3826 struct bttv_buffer_set old,new;
3827 struct bttv_buffer *ovbi;
3828 struct bttv_buffer *item;
3829 unsigned long flags;
3830
3831 if (bttv_verbose) {
3832 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
3833 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
3834 btread(BT848_RISC_COUNT));
3835 bttv_print_irqbits(btread(BT848_INT_STAT),0);
3836 printk("\n");
3837 }
3838
3839 spin_lock_irqsave(&btv->s_lock,flags);
3840
3841 /* deactivate stuff */
3842 memset(&new,0,sizeof(new));
3843 old = btv->curr;
3844 ovbi = btv->cvbi;
3845 btv->curr = new;
3846 btv->cvbi = NULL;
3847 btv->loop_irq = 0;
3848 bttv_buffer_activate_video(btv, &new);
3849 bttv_buffer_activate_vbi(btv, NULL);
3850 bttv_set_dma(btv, 0);
3851
3852 /* wake up */
3853 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
3854 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
3855
3856 /* cancel all outstanding capture / vbi requests */
3857 while (!list_empty(&btv->capture)) {
3858 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
3859 list_del(&item->vb.queue);
3860 item->vb.state = STATE_ERROR;
3861 wake_up(&item->vb.done);
3862 }
3863 while (!list_empty(&btv->vcapture)) {
3864 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3865 list_del(&item->vb.queue);
3866 item->vb.state = STATE_ERROR;
3867 wake_up(&item->vb.done);
3868 }
3869
3870 btv->errors++;
3871 spin_unlock_irqrestore(&btv->s_lock,flags);
3872}
3873
3874static void
3875bttv_irq_wakeup_top(struct bttv *btv)
3876{
3877 struct bttv_buffer *wakeup = btv->curr.top;
3878
3879 if (NULL == wakeup)
3880 return;
3881
3882 spin_lock(&btv->s_lock);
3883 btv->curr.top_irq = 0;
3884 btv->curr.top = NULL;
3885 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
3886
3887 do_gettimeofday(&wakeup->vb.ts);
3888 wakeup->vb.field_count = btv->field_count;
3889 wakeup->vb.state = STATE_DONE;
3890 wake_up(&wakeup->vb.done);
3891 spin_unlock(&btv->s_lock);
3892}
3893
3894static inline int is_active(struct btcx_riscmem *risc, u32 rc)
3895{
3896 if (rc < risc->dma)
3897 return 0;
3898 if (rc > risc->dma + risc->size)
3899 return 0;
3900 return 1;
3901}
3902
3903static void
3904bttv_irq_switch_video(struct bttv *btv)
3905{
3906 struct bttv_buffer_set new;
3907 struct bttv_buffer_set old;
3908 dma_addr_t rc;
3909
3910 spin_lock(&btv->s_lock);
3911
3912 /* new buffer set */
3913 bttv_irq_next_video(btv, &new);
3914 rc = btread(BT848_RISC_COUNT);
3915 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
3916 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
3917 btv->framedrop++;
3918 if (debug_latency)
3919 bttv_irq_debug_low_latency(btv, rc);
3920 spin_unlock(&btv->s_lock);
3921 return;
3922 }
3923
3924 /* switch over */
3925 old = btv->curr;
3926 btv->curr = new;
3927 btv->loop_irq &= ~1;
3928 bttv_buffer_activate_video(btv, &new);
3929 bttv_set_dma(btv, 0);
3930
3931 /* switch input */
3932 if (UNSET != btv->new_input) {
3933 video_mux(btv,btv->new_input);
3934 btv->new_input = UNSET;
3935 }
3936
3937 /* wake up finished buffers */
3938 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
3939 spin_unlock(&btv->s_lock);
3940}
3941
3942static void
3943bttv_irq_switch_vbi(struct bttv *btv)
3944{
3945 struct bttv_buffer *new = NULL;
3946 struct bttv_buffer *old;
3947 u32 rc;
3948
3949 spin_lock(&btv->s_lock);
3950
3951 if (!list_empty(&btv->vcapture))
3952 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
3953 old = btv->cvbi;
3954
3955 rc = btread(BT848_RISC_COUNT);
3956 if (NULL != old && (is_active(&old->top, rc) ||
3957 is_active(&old->bottom, rc))) {
3958 btv->framedrop++;
3959 if (debug_latency)
3960 bttv_irq_debug_low_latency(btv, rc);
3961 spin_unlock(&btv->s_lock);
3962 return;
3963 }
3964
3965 /* switch */
3966 btv->cvbi = new;
3967 btv->loop_irq &= ~4;
3968 bttv_buffer_activate_vbi(btv, new);
3969 bttv_set_dma(btv, 0);
3970
3971 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
3972 spin_unlock(&btv->s_lock);
3973}
3974
David Howells7d12e782006-10-05 14:55:46 +01003975static irqreturn_t bttv_irq(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976{
3977 u32 stat,astat;
3978 u32 dstat;
3979 int count;
3980 struct bttv *btv;
3981 int handled = 0;
3982
3983 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003984
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02003985 if (btv->custom_irq)
3986 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08003987
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 count=0;
3989 while (1) {
3990 /* get/clear interrupt status bits */
3991 stat=btread(BT848_INT_STAT);
3992 astat=stat&btread(BT848_INT_MASK);
3993 if (!astat)
3994 break;
3995 handled = 1;
3996 btwrite(stat,BT848_INT_STAT);
3997
3998 /* get device status bits */
3999 dstat=btread(BT848_DSTATUS);
4000
4001 if (irq_debug) {
4002 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
4003 "riscs=%x, riscc=%08x, ",
4004 btv->c.nr, count, btv->field_count,
4005 stat>>28, btread(BT848_RISC_COUNT));
4006 bttv_print_irqbits(stat,astat);
4007 if (stat & BT848_INT_HLOCK)
4008 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
4009 ? "yes" : "no");
4010 if (stat & BT848_INT_VPRES)
4011 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
4012 ? "yes" : "no");
4013 if (stat & BT848_INT_FMTCHG)
4014 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
4015 ? "625" : "525");
4016 printk("\n");
4017 }
4018
4019 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004020 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004022 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004024 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 }
4026
4027 if (astat & BT848_INT_I2CDONE) {
4028 btv->i2c_done = stat;
4029 wake_up(&btv->i2c_queue);
4030 }
4031
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004032 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 bttv_irq_switch_vbi(btv);
4034
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004035 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 bttv_irq_wakeup_top(btv);
4037
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004038 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 bttv_irq_switch_video(btv);
4040
4041 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004042 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
4044 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
4045 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
4046 (astat & BT848_INT_SCERR) ? "SCERR" : "",
4047 (astat & BT848_INT_OCERR) ? "OCERR" : "",
4048 btread(BT848_RISC_COUNT));
4049 bttv_print_irqbits(stat,astat);
4050 printk("\n");
4051 if (bttv_debug)
4052 bttv_print_riscaddr(btv);
4053 }
4054 if (fdsr && astat & BT848_INT_FDSR) {
4055 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
4056 btv->c.nr,btread(BT848_RISC_COUNT));
4057 if (bttv_debug)
4058 bttv_print_riscaddr(btv);
4059 }
4060
4061 count++;
4062 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004063
4064 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004065 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004066
4067 printk(KERN_ERR
4068 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
4069 } else {
4070 printk(KERN_ERR
4071 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
4072
4073 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
4074 BT848_INT_MASK);
4075 };
4076
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004078
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 printk("]\n");
4080 }
4081 }
4082 btv->irq_total++;
4083 if (handled)
4084 btv->irq_me++;
4085 return IRQ_RETVAL(handled);
4086}
4087
4088
4089/* ----------------------------------------------------------------------- */
4090/* initialitation */
4091
4092static struct video_device *vdev_init(struct bttv *btv,
4093 struct video_device *template,
4094 char *type)
4095{
4096 struct video_device *vfd;
4097
4098 vfd = video_device_alloc();
4099 if (NULL == vfd)
4100 return NULL;
4101 *vfd = *template;
4102 vfd->minor = -1;
4103 vfd->dev = &btv->c.pci->dev;
4104 vfd->release = video_device_release;
4105 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
4106 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
4107 type, bttv_tvcards[btv->c.type].name);
4108 return vfd;
4109}
4110
4111static void bttv_unregister_video(struct bttv *btv)
4112{
4113 if (btv->video_dev) {
4114 if (-1 != btv->video_dev->minor)
4115 video_unregister_device(btv->video_dev);
4116 else
4117 video_device_release(btv->video_dev);
4118 btv->video_dev = NULL;
4119 }
4120 if (btv->vbi_dev) {
4121 if (-1 != btv->vbi_dev->minor)
4122 video_unregister_device(btv->vbi_dev);
4123 else
4124 video_device_release(btv->vbi_dev);
4125 btv->vbi_dev = NULL;
4126 }
4127 if (btv->radio_dev) {
4128 if (-1 != btv->radio_dev->minor)
4129 video_unregister_device(btv->radio_dev);
4130 else
4131 video_device_release(btv->radio_dev);
4132 btv->radio_dev = NULL;
4133 }
4134}
4135
4136/* register video4linux devices */
4137static int __devinit bttv_register_video(struct bttv *btv)
4138{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07004139 if (no_overlay <= 0) {
4140 bttv_video_template.type |= VID_TYPE_OVERLAY;
4141 } else {
4142 printk("bttv: Overlay support disabled.\n");
4143 }
4144
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 /* video */
4146 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004147 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 goto err;
4149 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
4150 goto err;
4151 printk(KERN_INFO "bttv%d: registered device video%d\n",
4152 btv->c.nr,btv->video_dev->minor & 0x1f);
Kay Sievers54bd5b62007-10-08 16:26:13 -03004153 if (device_create_file(&btv->video_dev->class_dev,
4154 &dev_attr_card)<0) {
4155 printk(KERN_ERR "bttv%d: device_create_file 'card' "
Trent Piephod94fc9a2006-07-29 17:18:06 -03004156 "failed\n", btv->c.nr);
4157 goto err;
4158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
4160 /* vbi */
4161 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004162 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004164 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 goto err;
4166 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
4167 btv->c.nr,btv->vbi_dev->minor & 0x1f);
4168
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004169 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 return 0;
4171 /* radio */
4172 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004173 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 goto err;
4175 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
4176 goto err;
4177 printk(KERN_INFO "bttv%d: registered device radio%d\n",
4178 btv->c.nr,btv->radio_dev->minor & 0x1f);
4179
4180 /* all done */
4181 return 0;
4182
4183 err:
4184 bttv_unregister_video(btv);
4185 return -1;
4186}
4187
4188
4189/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
4190/* response on cards with no firmware is not enabled by OF */
4191static void pci_set_command(struct pci_dev *dev)
4192{
4193#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004194 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004196 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
4197 cmd = (cmd | PCI_COMMAND_MEMORY );
4198 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199#endif
4200}
4201
4202static int __devinit bttv_probe(struct pci_dev *dev,
4203 const struct pci_device_id *pci_id)
4204{
4205 int result;
4206 unsigned char lat;
4207 struct bttv *btv;
4208
4209 if (bttv_num == BTTV_MAX)
4210 return -ENOMEM;
4211 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004212 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 memset(btv,0,sizeof(*btv));
4214 btv->c.nr = bttv_num;
4215 sprintf(btv->c.name,"bttv%d",btv->c.nr);
4216
4217 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02004218 mutex_init(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004219 spin_lock_init(&btv->s_lock);
4220 spin_lock_init(&btv->gpio_lock);
4221 init_waitqueue_head(&btv->gpioq);
4222 init_waitqueue_head(&btv->i2c_queue);
4223 INIT_LIST_HEAD(&btv->c.subs);
4224 INIT_LIST_HEAD(&btv->capture);
4225 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 v4l2_prio_init(&btv->prio);
4227
4228 init_timer(&btv->timeout);
4229 btv->timeout.function = bttv_irq_timeout;
4230 btv->timeout.data = (unsigned long)btv;
4231
Michael Krufky7c08fb02005-11-08 21:36:21 -08004232 btv->i2c_rc = -1;
4233 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 btv->has_radio=radio[btv->c.nr];
4236
4237 /* pci stuff (init, get irq/mmio, ... */
4238 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08004239 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08004241 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 btv->c.nr);
4243 return -EIO;
4244 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004245 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
4246 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 btv->c.nr);
4248 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 if (!request_mem_region(pci_resource_start(dev,0),
4251 pci_resource_len(dev,0),
4252 btv->c.name)) {
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004253 printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
4254 btv->c.nr,
4255 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 return -EBUSY;
4257 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004258 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 pci_set_command(dev);
4260 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004262 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
4263 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
4264 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
4265 bttv_num,btv->id, btv->revision, pci_name(dev));
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004266 printk("irq: %d, latency: %d, mmio: 0x%llx\n",
4267 btv->c.pci->irq, lat,
4268 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 schedule();
4270
Akinobu Mita5f1693f2006-12-20 10:08:56 -03004271 btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
4272 if (NULL == btv->bt848_mmio) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4274 result = -EIO;
4275 goto fail1;
4276 }
4277
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004278 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 bttv_idcard(btv);
4280
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004281 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004283 result = request_irq(btv->c.pci->irq, bttv_irq,
Thomas Gleixner8076fe32006-07-01 19:29:37 -07004284 IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004285 if (result < 0) {
4286 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 bttv_num,btv->c.pci->irq);
4288 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290
4291 if (0 != bttv_handle_chipset(btv)) {
4292 result = -EIO;
4293 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295
4296 /* init options from insmod args */
4297 btv->opt_combfilter = combfilter;
4298 btv->opt_lumafilter = lumafilter;
4299 btv->opt_automute = automute;
4300 btv->opt_chroma_agc = chroma_agc;
4301 btv->opt_adc_crush = adc_crush;
4302 btv->opt_vcr_hack = vcr_hack;
4303 btv->opt_whitecrush_upper = whitecrush_upper;
4304 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004305 btv->opt_uv_ratio = uv_ratio;
4306 btv->opt_full_luma_range = full_luma_range;
4307 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308
4309 /* fill struct bttv with some useful defaults */
4310 btv->init.btv = btv;
4311 btv->init.ov.w.width = 320;
4312 btv->init.ov.w.height = 240;
Mauro Carvalho Chehabc96dd072007-10-26 16:51:47 -03004313 btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 btv->init.width = 320;
4315 btv->init.height = 240;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 btv->input = 0;
4317
4318 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004319 if (bttv_gpio)
4320 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321
4322 bttv_risc_init_main(btv);
4323 init_bt848(btv);
4324
4325 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004326 btwrite(0x00, BT848_GPIO_REG_INP);
4327 btwrite(0x00, BT848_GPIO_OUT_EN);
4328 if (bttv_verbose)
4329 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004331 /* needs to be done before i2c is registered */
4332 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004334 /* register i2c + gpio */
4335 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004337 /* some card-specific stuff (needs working i2c) */
4338 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 init_irqreg(btv);
4340
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004341 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 if (!bttv_tvcards[btv->c.type].no_video) {
4343 bttv_register_video(btv);
4344 bt848_bright(btv,32768);
4345 bt848_contrast(btv,32768);
4346 bt848_hue(btv,32768);
4347 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004348 audio_mute(btv, 1);
Trent Piepho333408f2007-07-03 15:08:10 -03004349 set_input(btv, 0, btv->tvnorm);
Michael Schimeke5bd0262007-01-18 16:17:39 -03004350 bttv_crop_reset(&btv->crop[0], btv->tvnorm);
4351 btv->crop[1] = btv->crop[0]; /* current = default */
4352 disclaim_vbi_lines(btv);
4353 disclaim_video_lines(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 }
4355
Jarod Wilsonf992a492007-03-24 15:23:50 -03004356 /* add subdevices and autoload dvb-bt8xx if needed */
4357 if (bttv_tvcards[btv->c.type].has_dvb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 bttv_sub_add_device(&btv->c, "dvb");
Jarod Wilsonf992a492007-03-24 15:23:50 -03004359 request_modules(btv);
4360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004362 bttv_input_init(btv);
4363
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 /* everything is fine */
4365 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004366 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
4368 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004369 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370
4371 fail1:
4372 if (btv->bt848_mmio)
4373 iounmap(btv->bt848_mmio);
4374 release_mem_region(pci_resource_start(btv->c.pci,0),
4375 pci_resource_len(btv->c.pci,0));
4376 pci_set_drvdata(dev,NULL);
4377 return result;
4378}
4379
4380static void __devexit bttv_remove(struct pci_dev *pci_dev)
4381{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004382 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383
4384 if (bttv_verbose)
4385 printk("bttv%d: unloading\n",btv->c.nr);
4386
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004387 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 btand(~15, BT848_GPIO_DMA_CTL);
4389 btwrite(0, BT848_INT_MASK);
4390 btwrite(~0x0, BT848_INT_STAT);
4391 btwrite(0x0, BT848_GPIO_OUT_EN);
4392 if (bttv_gpio)
4393 bttv_gpio_tracking(btv,"cleanup");
4394
4395 /* tell gpio modules we are leaving ... */
4396 btv->shutdown=1;
4397 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004398 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004399 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004401 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 fini_bttv_i2c(btv);
4403
4404 /* unregister video4linux */
4405 bttv_unregister_video(btv);
4406
4407 /* free allocated memory */
4408 btcx_riscmem_free(btv->c.pci,&btv->main);
4409
4410 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004411 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004413 release_mem_region(pci_resource_start(btv->c.pci,0),
4414 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
4416 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004417 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418}
4419
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004420#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4422{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004423 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 struct bttv_buffer_set idle;
4425 unsigned long flags;
4426
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004427 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428
4429 /* stop dma + irqs */
4430 spin_lock_irqsave(&btv->s_lock,flags);
4431 memset(&idle, 0, sizeof(idle));
4432 btv->state.video = btv->curr;
4433 btv->state.vbi = btv->cvbi;
4434 btv->state.loop_irq = btv->loop_irq;
4435 btv->curr = idle;
4436 btv->loop_irq = 0;
4437 bttv_buffer_activate_video(btv, &idle);
4438 bttv_buffer_activate_vbi(btv, NULL);
4439 bttv_set_dma(btv, 0);
4440 btwrite(0, BT848_INT_MASK);
4441 spin_unlock_irqrestore(&btv->s_lock,flags);
4442
4443 /* save bt878 state */
4444 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4445 btv->state.gpio_data = gpio_read();
4446
4447 /* save pci state */
4448 pci_save_state(pci_dev);
4449 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4450 pci_disable_device(pci_dev);
4451 btv->state.disabled = 1;
4452 }
4453 return 0;
4454}
4455
4456static int bttv_resume(struct pci_dev *pci_dev)
4457{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004458 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004460 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
4462 dprintk("bttv%d: resume\n", btv->c.nr);
4463
4464 /* restore pci state */
4465 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004466 err=pci_enable_device(pci_dev);
4467 if (err) {
4468 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4469 btv->c.nr);
4470 return err;
4471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 btv->state.disabled = 0;
4473 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004474 err=pci_set_power_state(pci_dev, PCI_D0);
4475 if (err) {
4476 pci_disable_device(pci_dev);
4477 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4478 btv->c.nr);
4479 btv->state.disabled = 1;
4480 return err;
4481 }
4482
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 pci_restore_state(pci_dev);
4484
4485 /* restore bt878 state */
4486 bttv_reinit_bt848(btv);
4487 gpio_inout(0xffffff, btv->state.gpio_enable);
4488 gpio_write(btv->state.gpio_data);
4489
4490 /* restart dma */
4491 spin_lock_irqsave(&btv->s_lock,flags);
4492 btv->curr = btv->state.video;
4493 btv->cvbi = btv->state.vbi;
4494 btv->loop_irq = btv->state.loop_irq;
4495 bttv_buffer_activate_video(btv, &btv->curr);
4496 bttv_buffer_activate_vbi(btv, btv->cvbi);
4497 bttv_set_dma(btv, 0);
4498 spin_unlock_irqrestore(&btv->s_lock,flags);
4499 return 0;
4500}
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004501#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502
4503static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004504 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4505 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004507 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004509 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004511 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4512 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513};
4514
4515MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4516
4517static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004518 .name = "bttv",
4519 .id_table = bttv_pci_tbl,
4520 .probe = bttv_probe,
4521 .remove = __devexit_p(bttv_remove),
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004522#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 .suspend = bttv_suspend,
4524 .resume = bttv_resume,
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004525#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526};
4527
Adrian Bunk7d44e892007-12-11 19:23:43 -03004528static int __init bttv_init_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529{
Randy Dunlapc526e222006-07-15 09:08:26 -03004530 int ret;
4531
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 bttv_num = 0;
4533
4534 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4535 (BTTV_VERSION_CODE >> 16) & 0xff,
4536 (BTTV_VERSION_CODE >> 8) & 0xff,
4537 BTTV_VERSION_CODE & 0xff);
4538#ifdef SNAPSHOT
4539 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4540 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4541#endif
4542 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4543 gbuffers = 2;
4544 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4545 gbufsize = BTTV_MAX_FBUF;
4546 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4547 if (bttv_verbose)
4548 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4549 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4550
4551 bttv_check_chipset();
4552
Randy Dunlapc526e222006-07-15 09:08:26 -03004553 ret = bus_register(&bttv_sub_bus_type);
4554 if (ret < 0) {
4555 printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
4556 return ret;
4557 }
Otavio Salvador23047592006-01-09 15:25:17 -02004558 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559}
4560
Adrian Bunk7d44e892007-12-11 19:23:43 -03004561static void __exit bttv_cleanup_module(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562{
4563 pci_unregister_driver(&bttv_pci_driver);
4564 bus_unregister(&bttv_sub_bus_type);
4565 return;
4566}
4567
4568module_init(bttv_init_module);
4569module_exit(bttv_cleanup_module);
4570
4571/*
4572 * Local variables:
4573 * c-basic-offset: 8
4574 * End:
4575 */