blob: 50dfad47ccffbf1365703b4eebabd3aea0533f37 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3 bttv - Bt848 frame grabber driver
4
5 Copyright (C) 1996,97,98 Ralph Metzler <rjkm@thp.uni-koeln.de>
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08006 & Marcus Metzler <mocm@thp.uni-koeln.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 (c) 1999-2002 Gerd Knorr <kraxel@bytesex.org>
8
9 some v4l2 code lines are taken from Justin's bttv2 driver which is
10 (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
11
Michael Schimeke5bd0262007-01-18 16:17:39 -030012 Cropping and overscan support
13 Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
14 Sponsored by OPQ Systems AB
15
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29*/
30
31#include <linux/init.h>
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/delay.h>
35#include <linux/errno.h>
36#include <linux/fs.h>
37#include <linux/kernel.h>
38#include <linux/sched.h>
39#include <linux/interrupt.h>
40#include <linux/kdev_t.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020041#include "bttvp.h"
Michael Krufky5e453dc2006-01-09 15:32:31 -020042#include <media/v4l2-common.h>
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -030043#include <media/tvaudio.h>
Hans Verkuil2474ed42006-03-19 12:35:57 -030044#include <media/msp3400.h>
Mauro Carvalho Chehabb5b8ab82006-01-09 15:25:20 -020045
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -070046#include <linux/dma-mapping.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#include <asm/io.h>
49#include <asm/byteorder.h>
50
Mauro Carvalho Chehabfa3fcce2006-03-23 21:45:24 -030051#include <media/rds.h>
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -070052
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054unsigned int bttv_num; /* number of Bt848s in use */
55struct bttv bttvs[BTTV_MAX];
56
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020057unsigned int bttv_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058unsigned int bttv_verbose = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020059unsigned int bttv_gpio;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
61/* config variables */
62#ifdef __BIG_ENDIAN
63static unsigned int bigendian=1;
64#else
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020065static unsigned int bigendian;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#endif
67static unsigned int radio[BTTV_MAX];
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020068static unsigned int irq_debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static unsigned int gbuffers = 8;
70static unsigned int gbufsize = 0x208000;
Michael Schimeke5bd0262007-01-18 16:17:39 -030071static unsigned int reset_crop = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
73static int video_nr = -1;
74static int radio_nr = -1;
75static int vbi_nr = -1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020076static int debug_latency;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020078static unsigned int fdsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80/* options */
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020081static unsigned int combfilter;
82static unsigned int lumafilter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static unsigned int automute = 1;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020084static unsigned int chroma_agc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085static unsigned int adc_crush = 1;
86static unsigned int whitecrush_upper = 0xCF;
87static unsigned int whitecrush_lower = 0x7F;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020088static unsigned int vcr_hack;
89static unsigned int irq_iswitch;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -070090static unsigned int uv_ratio = 50;
Mauro Carvalho Chehaba5ed4252006-01-13 14:10:19 -020091static unsigned int full_luma_range;
92static unsigned int coring;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -070093extern int no_overlay;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/* API features (turn on/off stuff for testing) */
96static unsigned int v4l2 = 1;
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098/* insmod args */
99module_param(bttv_verbose, int, 0644);
100module_param(bttv_gpio, int, 0644);
101module_param(bttv_debug, int, 0644);
102module_param(irq_debug, int, 0644);
103module_param(debug_latency, int, 0644);
104
105module_param(fdsr, int, 0444);
106module_param(video_nr, int, 0444);
107module_param(radio_nr, int, 0444);
108module_param(vbi_nr, int, 0444);
109module_param(gbuffers, int, 0444);
110module_param(gbufsize, int, 0444);
Michael Schimeke5bd0262007-01-18 16:17:39 -0300111module_param(reset_crop, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113module_param(v4l2, int, 0644);
114module_param(bigendian, int, 0644);
115module_param(irq_iswitch, int, 0644);
116module_param(combfilter, int, 0444);
117module_param(lumafilter, int, 0444);
118module_param(automute, int, 0444);
119module_param(chroma_agc, int, 0444);
120module_param(adc_crush, int, 0444);
121module_param(whitecrush_upper, int, 0444);
122module_param(whitecrush_lower, int, 0444);
123module_param(vcr_hack, int, 0444);
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700124module_param(uv_ratio, int, 0444);
125module_param(full_luma_range, int, 0444);
126module_param(coring, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128module_param_array(radio, int, NULL, 0444);
129
130MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");
131MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");
132MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");
133MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");
134MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
135MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
136MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
137MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
Michael Schimeke5bd0262007-01-18 16:17:39 -0300138MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
139 "is 1 (yes) for compatibility with older applications");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
141MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
142MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
143MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207");
144MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
145MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
146MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700147MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
148MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
149MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
152MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
153MODULE_LICENSE("GPL");
154
155/* ----------------------------------------------------------------------- */
156/* sysfs */
157
158static ssize_t show_card(struct class_device *cd, char *buf)
159{
160 struct video_device *vfd = to_video_device(cd);
161 struct bttv *btv = dev_get_drvdata(vfd->dev);
162 return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
163}
164static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
165
166/* ----------------------------------------------------------------------- */
167/* static data */
168
169/* special timing tables from conexant... */
170static u8 SRAM_Table[][60] =
171{
172 /* PAL digital input over GPIO[7:0] */
173 {
174 45, // 45 bytes following
175 0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,
176 0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,
177 0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,
178 0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,
179 0x37,0x00,0xAF,0x21,0x00
180 },
181 /* NTSC digital input over GPIO[7:0] */
182 {
183 51, // 51 bytes following
184 0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,
185 0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,
186 0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,
187 0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,
188 0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,
189 0x00,
190 },
191 // TGB_NTSC392 // quartzsight
192 // This table has been modified to be used for Fusion Rev D
193 {
194 0x2A, // size of table = 42
195 0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,
196 0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,
197 0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,
198 0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,
199 0x20, 0x00
200 }
201};
202
Michael Schimeke5bd0262007-01-18 16:17:39 -0300203/* minhdelayx1 first video pixel we can capture on a line and
204 hdelayx1 start of active video, both relative to rising edge of
205 /HRESET pulse (0H) in 1 / fCLKx1.
206 swidth width of active video and
207 totalwidth total line width, both in 1 / fCLKx1.
208 sqwidth total line width in square pixels.
209 vdelay start of active video in 2 * field lines relative to
210 trailing edge of /VRESET pulse (VDELAY register).
211 sheight height of active video in 2 * field lines.
212 videostart0 ITU-R frame line number of the line corresponding
213 to vdelay in the first field. */
214#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
215 vdelay, sheight, videostart0) \
216 .cropcap.bounds.left = minhdelayx1, \
217 /* * 2 because vertically we count field lines times two, */ \
218 /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
219 .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
220 /* 4 is a safety margin at the end of the line. */ \
221 .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
222 .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
223 .cropcap.defrect.left = hdelayx1, \
224 .cropcap.defrect.top = (videostart0) * 2, \
225 .cropcap.defrect.width = swidth, \
226 .cropcap.defrect.height = sheight, \
227 .cropcap.pixelaspect.numerator = totalwidth, \
228 .cropcap.pixelaspect.denominator = sqwidth,
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230const struct bttv_tvnorm bttv_tvnorms[] = {
231 /* PAL-BDGHI */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -0800232 /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
233 /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 {
235 .v4l2_id = V4L2_STD_PAL,
236 .name = "PAL",
237 .Fsc = 35468950,
238 .swidth = 924,
239 .sheight = 576,
240 .totalwidth = 1135,
241 .adelay = 0x7f,
242 .bdelay = 0x72,
243 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
244 .scaledtwidth = 1135,
245 .hdelayx1 = 186,
246 .hactivex1 = 924,
247 .vdelay = 0x20,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300248 .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 .sram = 0,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200250 /* ITU-R frame line number of the first VBI line
Michael Schimeke5bd0262007-01-18 16:17:39 -0300251 we can capture, of the first and second field.
252 The last line is determined by cropcap.bounds. */
253 .vbistart = { 7, 320 },
254 CROPCAP(/* minhdelayx1 */ 68,
255 /* hdelayx1 */ 186,
256 /* Should be (768 * 1135 + 944 / 2) / 944.
257 cropcap.defrect is used for image width
258 checks, so we keep the old value 924. */
259 /* swidth */ 924,
260 /* totalwidth */ 1135,
261 /* sqwidth */ 944,
262 /* vdelay */ 0x20,
263 /* sheight */ 576,
264 /* videostart0 */ 23)
265 /* bt878 (and bt848?) can capture another
266 line below active video. */
267 .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 },{
Hans Verkuild97a11e2006-02-07 06:48:40 -0200269 .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 .name = "NTSC",
271 .Fsc = 28636363,
272 .swidth = 768,
273 .sheight = 480,
274 .totalwidth = 910,
275 .adelay = 0x68,
276 .bdelay = 0x5d,
277 .iform = (BT848_IFORM_NTSC|BT848_IFORM_XT0),
278 .scaledtwidth = 910,
279 .hdelayx1 = 128,
280 .hactivex1 = 910,
281 .vdelay = 0x1a,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300282 .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 .sram = 1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200284 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300285 CROPCAP(/* minhdelayx1 */ 68,
286 /* hdelayx1 */ 128,
287 /* Should be (640 * 910 + 780 / 2) / 780? */
288 /* swidth */ 768,
289 /* totalwidth */ 910,
290 /* sqwidth */ 780,
291 /* vdelay */ 0x1a,
292 /* sheight */ 480,
293 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 },{
295 .v4l2_id = V4L2_STD_SECAM,
296 .name = "SECAM",
297 .Fsc = 35468950,
298 .swidth = 924,
299 .sheight = 576,
300 .totalwidth = 1135,
301 .adelay = 0x7f,
302 .bdelay = 0xb0,
303 .iform = (BT848_IFORM_SECAM|BT848_IFORM_XT1),
304 .scaledtwidth = 1135,
305 .hdelayx1 = 186,
306 .hactivex1 = 922,
307 .vdelay = 0x20,
308 .vbipack = 255,
309 .sram = 0, /* like PAL, correct? */
Michael H. Schimek67f15702006-01-09 15:25:27 -0200310 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300311 CROPCAP(/* minhdelayx1 */ 68,
312 /* hdelayx1 */ 186,
313 /* swidth */ 924,
314 /* totalwidth */ 1135,
315 /* sqwidth */ 944,
316 /* vdelay */ 0x20,
317 /* sheight */ 576,
318 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 },{
320 .v4l2_id = V4L2_STD_PAL_Nc,
321 .name = "PAL-Nc",
322 .Fsc = 28636363,
323 .swidth = 640,
324 .sheight = 576,
325 .totalwidth = 910,
326 .adelay = 0x68,
327 .bdelay = 0x5d,
328 .iform = (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
329 .scaledtwidth = 780,
330 .hdelayx1 = 130,
331 .hactivex1 = 734,
332 .vdelay = 0x1a,
333 .vbipack = 144,
334 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200335 .vbistart = { 7, 320 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300336 CROPCAP(/* minhdelayx1 */ 68,
337 /* hdelayx1 */ 130,
338 /* swidth */ (640 * 910 + 780 / 2) / 780,
339 /* totalwidth */ 910,
340 /* sqwidth */ 780,
341 /* vdelay */ 0x1a,
342 /* sheight */ 576,
343 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 },{
345 .v4l2_id = V4L2_STD_PAL_M,
346 .name = "PAL-M",
347 .Fsc = 28636363,
348 .swidth = 640,
349 .sheight = 480,
350 .totalwidth = 910,
351 .adelay = 0x68,
352 .bdelay = 0x5d,
353 .iform = (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
354 .scaledtwidth = 780,
355 .hdelayx1 = 135,
356 .hactivex1 = 754,
357 .vdelay = 0x1a,
358 .vbipack = 144,
359 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200360 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300361 CROPCAP(/* minhdelayx1 */ 68,
362 /* hdelayx1 */ 135,
363 /* swidth */ (640 * 910 + 780 / 2) / 780,
364 /* totalwidth */ 910,
365 /* sqwidth */ 780,
366 /* vdelay */ 0x1a,
367 /* sheight */ 480,
368 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 },{
370 .v4l2_id = V4L2_STD_PAL_N,
371 .name = "PAL-N",
372 .Fsc = 35468950,
373 .swidth = 768,
374 .sheight = 576,
375 .totalwidth = 1135,
376 .adelay = 0x7f,
377 .bdelay = 0x72,
378 .iform = (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
379 .scaledtwidth = 944,
380 .hdelayx1 = 186,
381 .hactivex1 = 922,
382 .vdelay = 0x20,
383 .vbipack = 144,
384 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300385 .vbistart = { 7, 320 },
386 CROPCAP(/* minhdelayx1 */ 68,
387 /* hdelayx1 */ 186,
388 /* swidth */ (768 * 1135 + 944 / 2) / 944,
389 /* totalwidth */ 1135,
390 /* sqwidth */ 944,
391 /* vdelay */ 0x20,
392 /* sheight */ 576,
393 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 },{
395 .v4l2_id = V4L2_STD_NTSC_M_JP,
396 .name = "NTSC-JP",
397 .Fsc = 28636363,
398 .swidth = 640,
399 .sheight = 480,
400 .totalwidth = 910,
401 .adelay = 0x68,
402 .bdelay = 0x5d,
403 .iform = (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
404 .scaledtwidth = 780,
405 .hdelayx1 = 135,
406 .hactivex1 = 754,
407 .vdelay = 0x16,
408 .vbipack = 144,
409 .sram = -1,
Michael Schimeke5bd0262007-01-18 16:17:39 -0300410 .vbistart = { 10, 273 },
411 CROPCAP(/* minhdelayx1 */ 68,
412 /* hdelayx1 */ 135,
413 /* swidth */ (640 * 910 + 780 / 2) / 780,
414 /* totalwidth */ 910,
415 /* sqwidth */ 780,
416 /* vdelay */ 0x16,
417 /* sheight */ 480,
418 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 },{
420 /* that one hopefully works with the strange timing
421 * which video recorders produce when playing a NTSC
422 * tape on a PAL TV ... */
423 .v4l2_id = V4L2_STD_PAL_60,
424 .name = "PAL-60",
425 .Fsc = 35468950,
426 .swidth = 924,
427 .sheight = 480,
428 .totalwidth = 1135,
429 .adelay = 0x7f,
430 .bdelay = 0x72,
431 .iform = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
432 .scaledtwidth = 1135,
433 .hdelayx1 = 186,
434 .hactivex1 = 924,
435 .vdelay = 0x1a,
436 .vbipack = 255,
437 .vtotal = 524,
438 .sram = -1,
Michael H. Schimek67f15702006-01-09 15:25:27 -0200439 .vbistart = { 10, 273 },
Michael Schimeke5bd0262007-01-18 16:17:39 -0300440 CROPCAP(/* minhdelayx1 */ 68,
441 /* hdelayx1 */ 186,
442 /* swidth */ 924,
443 /* totalwidth */ 1135,
444 /* sqwidth */ 944,
445 /* vdelay */ 0x1a,
446 /* sheight */ 480,
447 /* videostart0 */ 23)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 }
449};
450static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
451
452/* ----------------------------------------------------------------------- */
453/* bttv format list
454 packed pixel formats must come first */
455static const struct bttv_format bttv_formats[] = {
456 {
457 .name = "8 bpp, gray",
458 .palette = VIDEO_PALETTE_GREY,
459 .fourcc = V4L2_PIX_FMT_GREY,
460 .btformat = BT848_COLOR_FMT_Y8,
461 .depth = 8,
462 .flags = FORMAT_FLAGS_PACKED,
463 },{
464 .name = "8 bpp, dithered color",
465 .palette = VIDEO_PALETTE_HI240,
466 .fourcc = V4L2_PIX_FMT_HI240,
467 .btformat = BT848_COLOR_FMT_RGB8,
468 .depth = 8,
469 .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER,
470 },{
471 .name = "15 bpp RGB, le",
472 .palette = VIDEO_PALETTE_RGB555,
473 .fourcc = V4L2_PIX_FMT_RGB555,
474 .btformat = BT848_COLOR_FMT_RGB15,
475 .depth = 16,
476 .flags = FORMAT_FLAGS_PACKED,
477 },{
478 .name = "15 bpp RGB, be",
479 .palette = -1,
480 .fourcc = V4L2_PIX_FMT_RGB555X,
481 .btformat = BT848_COLOR_FMT_RGB15,
482 .btswap = 0x03, /* byteswap */
483 .depth = 16,
484 .flags = FORMAT_FLAGS_PACKED,
485 },{
486 .name = "16 bpp RGB, le",
487 .palette = VIDEO_PALETTE_RGB565,
488 .fourcc = V4L2_PIX_FMT_RGB565,
489 .btformat = BT848_COLOR_FMT_RGB16,
490 .depth = 16,
491 .flags = FORMAT_FLAGS_PACKED,
492 },{
493 .name = "16 bpp RGB, be",
494 .palette = -1,
495 .fourcc = V4L2_PIX_FMT_RGB565X,
496 .btformat = BT848_COLOR_FMT_RGB16,
497 .btswap = 0x03, /* byteswap */
498 .depth = 16,
499 .flags = FORMAT_FLAGS_PACKED,
500 },{
501 .name = "24 bpp RGB, le",
502 .palette = VIDEO_PALETTE_RGB24,
503 .fourcc = V4L2_PIX_FMT_BGR24,
504 .btformat = BT848_COLOR_FMT_RGB24,
505 .depth = 24,
506 .flags = FORMAT_FLAGS_PACKED,
507 },{
508 .name = "32 bpp RGB, le",
509 .palette = VIDEO_PALETTE_RGB32,
510 .fourcc = V4L2_PIX_FMT_BGR32,
511 .btformat = BT848_COLOR_FMT_RGB32,
512 .depth = 32,
513 .flags = FORMAT_FLAGS_PACKED,
514 },{
515 .name = "32 bpp RGB, be",
516 .palette = -1,
517 .fourcc = V4L2_PIX_FMT_RGB32,
518 .btformat = BT848_COLOR_FMT_RGB32,
519 .btswap = 0x0f, /* byte+word swap */
520 .depth = 32,
521 .flags = FORMAT_FLAGS_PACKED,
522 },{
523 .name = "4:2:2, packed, YUYV",
524 .palette = VIDEO_PALETTE_YUV422,
525 .fourcc = V4L2_PIX_FMT_YUYV,
526 .btformat = BT848_COLOR_FMT_YUY2,
527 .depth = 16,
528 .flags = FORMAT_FLAGS_PACKED,
529 },{
530 .name = "4:2:2, packed, YUYV",
531 .palette = VIDEO_PALETTE_YUYV,
532 .fourcc = V4L2_PIX_FMT_YUYV,
533 .btformat = BT848_COLOR_FMT_YUY2,
534 .depth = 16,
535 .flags = FORMAT_FLAGS_PACKED,
536 },{
537 .name = "4:2:2, packed, UYVY",
538 .palette = VIDEO_PALETTE_UYVY,
539 .fourcc = V4L2_PIX_FMT_UYVY,
540 .btformat = BT848_COLOR_FMT_YUY2,
541 .btswap = 0x03, /* byteswap */
542 .depth = 16,
543 .flags = FORMAT_FLAGS_PACKED,
544 },{
545 .name = "4:2:2, planar, Y-Cb-Cr",
546 .palette = VIDEO_PALETTE_YUV422P,
547 .fourcc = V4L2_PIX_FMT_YUV422P,
548 .btformat = BT848_COLOR_FMT_YCrCb422,
549 .depth = 16,
550 .flags = FORMAT_FLAGS_PLANAR,
551 .hshift = 1,
552 .vshift = 0,
553 },{
554 .name = "4:2:0, planar, Y-Cb-Cr",
555 .palette = VIDEO_PALETTE_YUV420P,
556 .fourcc = V4L2_PIX_FMT_YUV420,
557 .btformat = BT848_COLOR_FMT_YCrCb422,
558 .depth = 12,
559 .flags = FORMAT_FLAGS_PLANAR,
560 .hshift = 1,
561 .vshift = 1,
562 },{
563 .name = "4:2:0, planar, Y-Cr-Cb",
564 .palette = -1,
565 .fourcc = V4L2_PIX_FMT_YVU420,
566 .btformat = BT848_COLOR_FMT_YCrCb422,
567 .depth = 12,
568 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
569 .hshift = 1,
570 .vshift = 1,
571 },{
572 .name = "4:1:1, planar, Y-Cb-Cr",
573 .palette = VIDEO_PALETTE_YUV411P,
574 .fourcc = V4L2_PIX_FMT_YUV411P,
575 .btformat = BT848_COLOR_FMT_YCrCb411,
576 .depth = 12,
577 .flags = FORMAT_FLAGS_PLANAR,
578 .hshift = 2,
579 .vshift = 0,
580 },{
581 .name = "4:1:0, planar, Y-Cb-Cr",
582 .palette = VIDEO_PALETTE_YUV410P,
583 .fourcc = V4L2_PIX_FMT_YUV410,
584 .btformat = BT848_COLOR_FMT_YCrCb411,
585 .depth = 9,
586 .flags = FORMAT_FLAGS_PLANAR,
587 .hshift = 2,
588 .vshift = 2,
589 },{
590 .name = "4:1:0, planar, Y-Cr-Cb",
591 .palette = -1,
592 .fourcc = V4L2_PIX_FMT_YVU410,
593 .btformat = BT848_COLOR_FMT_YCrCb411,
594 .depth = 9,
595 .flags = FORMAT_FLAGS_PLANAR | FORMAT_FLAGS_CrCb,
596 .hshift = 2,
597 .vshift = 2,
598 },{
599 .name = "raw scanlines",
600 .palette = VIDEO_PALETTE_RAW,
601 .fourcc = -1,
602 .btformat = BT848_COLOR_FMT_RAW,
603 .depth = 8,
604 .flags = FORMAT_FLAGS_RAW,
605 }
606};
607static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
608
609/* ----------------------------------------------------------------------- */
610
611#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0)
612#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1)
613#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2)
614#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3)
615#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4)
616#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
617#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
618#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700619#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
620#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
621#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
622#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624static const struct v4l2_queryctrl no_ctl = {
625 .name = "42",
626 .flags = V4L2_CTRL_FLAG_DISABLED,
627};
628static const struct v4l2_queryctrl bttv_ctls[] = {
629 /* --- video --- */
630 {
631 .id = V4L2_CID_BRIGHTNESS,
632 .name = "Brightness",
633 .minimum = 0,
634 .maximum = 65535,
635 .step = 256,
636 .default_value = 32768,
637 .type = V4L2_CTRL_TYPE_INTEGER,
638 },{
639 .id = V4L2_CID_CONTRAST,
640 .name = "Contrast",
641 .minimum = 0,
642 .maximum = 65535,
643 .step = 128,
644 .default_value = 32768,
645 .type = V4L2_CTRL_TYPE_INTEGER,
646 },{
647 .id = V4L2_CID_SATURATION,
648 .name = "Saturation",
649 .minimum = 0,
650 .maximum = 65535,
651 .step = 128,
652 .default_value = 32768,
653 .type = V4L2_CTRL_TYPE_INTEGER,
654 },{
655 .id = V4L2_CID_HUE,
656 .name = "Hue",
657 .minimum = 0,
658 .maximum = 65535,
659 .step = 256,
660 .default_value = 32768,
661 .type = V4L2_CTRL_TYPE_INTEGER,
662 },
663 /* --- audio --- */
664 {
665 .id = V4L2_CID_AUDIO_MUTE,
666 .name = "Mute",
667 .minimum = 0,
668 .maximum = 1,
669 .type = V4L2_CTRL_TYPE_BOOLEAN,
670 },{
671 .id = V4L2_CID_AUDIO_VOLUME,
672 .name = "Volume",
673 .minimum = 0,
674 .maximum = 65535,
675 .step = 65535/100,
676 .default_value = 65535,
677 .type = V4L2_CTRL_TYPE_INTEGER,
678 },{
679 .id = V4L2_CID_AUDIO_BALANCE,
680 .name = "Balance",
681 .minimum = 0,
682 .maximum = 65535,
683 .step = 65535/100,
684 .default_value = 32768,
685 .type = V4L2_CTRL_TYPE_INTEGER,
686 },{
687 .id = V4L2_CID_AUDIO_BASS,
688 .name = "Bass",
689 .minimum = 0,
690 .maximum = 65535,
691 .step = 65535/100,
692 .default_value = 32768,
693 .type = V4L2_CTRL_TYPE_INTEGER,
694 },{
695 .id = V4L2_CID_AUDIO_TREBLE,
696 .name = "Treble",
697 .minimum = 0,
698 .maximum = 65535,
699 .step = 65535/100,
700 .default_value = 32768,
701 .type = V4L2_CTRL_TYPE_INTEGER,
702 },
703 /* --- private --- */
704 {
705 .id = V4L2_CID_PRIVATE_CHROMA_AGC,
706 .name = "chroma agc",
707 .minimum = 0,
708 .maximum = 1,
709 .type = V4L2_CTRL_TYPE_BOOLEAN,
710 },{
711 .id = V4L2_CID_PRIVATE_COMBFILTER,
712 .name = "combfilter",
713 .minimum = 0,
714 .maximum = 1,
715 .type = V4L2_CTRL_TYPE_BOOLEAN,
716 },{
717 .id = V4L2_CID_PRIVATE_AUTOMUTE,
718 .name = "automute",
719 .minimum = 0,
720 .maximum = 1,
721 .type = V4L2_CTRL_TYPE_BOOLEAN,
722 },{
723 .id = V4L2_CID_PRIVATE_LUMAFILTER,
724 .name = "luma decimation filter",
725 .minimum = 0,
726 .maximum = 1,
727 .type = V4L2_CTRL_TYPE_BOOLEAN,
728 },{
729 .id = V4L2_CID_PRIVATE_AGC_CRUSH,
730 .name = "agc crush",
731 .minimum = 0,
732 .maximum = 1,
733 .type = V4L2_CTRL_TYPE_BOOLEAN,
734 },{
735 .id = V4L2_CID_PRIVATE_VCR_HACK,
736 .name = "vcr hack",
737 .minimum = 0,
738 .maximum = 1,
739 .type = V4L2_CTRL_TYPE_BOOLEAN,
740 },{
741 .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER,
742 .name = "whitecrush upper",
743 .minimum = 0,
744 .maximum = 255,
745 .step = 1,
746 .default_value = 0xCF,
747 .type = V4L2_CTRL_TYPE_INTEGER,
748 },{
749 .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER,
750 .name = "whitecrush lower",
751 .minimum = 0,
752 .maximum = 255,
753 .step = 1,
754 .default_value = 0x7F,
755 .type = V4L2_CTRL_TYPE_INTEGER,
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700756 },{
757 .id = V4L2_CID_PRIVATE_UV_RATIO,
758 .name = "uv ratio",
759 .minimum = 0,
760 .maximum = 100,
761 .step = 1,
762 .default_value = 50,
763 .type = V4L2_CTRL_TYPE_INTEGER,
764 },{
765 .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
766 .name = "full luma range",
767 .minimum = 0,
768 .maximum = 1,
769 .type = V4L2_CTRL_TYPE_BOOLEAN,
770 },{
771 .id = V4L2_CID_PRIVATE_CORING,
772 .name = "coring",
773 .minimum = 0,
774 .maximum = 3,
775 .step = 1,
776 .default_value = 0,
777 .type = V4L2_CTRL_TYPE_INTEGER,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
779
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -0700780
781
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782};
783static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
784
785/* ----------------------------------------------------------------------- */
786/* resource management */
787
Michael Schimeke5bd0262007-01-18 16:17:39 -0300788/*
789 RESOURCE_ allocated by freed by
790
791 VIDEO_READ bttv_read 1) bttv_read 2)
792
793 VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
794 VIDIOC_QBUF 1) bttv_release
795 VIDIOCMCAPTURE 1)
796
797 OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
798 VIDIOC_OVERLAY on VIDIOC_OVERLAY off
799 3) bttv_release
800
801 VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
802 VIDIOC_QBUF 1) bttv_release
803 bttv_read, bttv_poll 1) 4)
804
805 1) The resource must be allocated when we enter buffer prepare functions
806 and remain allocated while buffers are in the DMA queue.
807 2) This is a single frame read.
808 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
809 RESOURCE_OVERLAY is allocated.
810 4) This is a continuous read, implies VIDIOC_STREAMON.
811
812 Note this driver permits video input and standard changes regardless if
813 resources are allocated.
814*/
815
816#define VBI_RESOURCES (RESOURCE_VBI)
817#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
818 RESOURCE_VIDEO_STREAM | \
819 RESOURCE_OVERLAY)
820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821static
822int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
823{
Michael Schimeke5bd0262007-01-18 16:17:39 -0300824 int xbits; /* mutual exclusive resources */
825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (fh->resources & bit)
827 /* have it already allocated */
828 return 1;
829
Michael Schimeke5bd0262007-01-18 16:17:39 -0300830 xbits = bit;
831 if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
832 xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 /* is it free? */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300835 mutex_lock(&btv->lock);
836 if (btv->resources & xbits) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 /* no, someone else uses it */
Michael Schimeke5bd0262007-01-18 16:17:39 -0300838 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300840
841 if ((bit & VIDEO_RESOURCES)
842 && 0 == (btv->resources & VIDEO_RESOURCES)) {
843 /* Do crop - use current, don't - use default parameters. */
844 __s32 top = btv->crop[!!fh->do_crop].rect.top;
845
846 if (btv->vbi_end > top)
847 goto fail;
848
849 /* We cannot capture the same line as video and VBI data.
850 Claim scan lines crop[].rect.top to bottom. */
851 btv->crop_start = top;
852 } else if (bit & VBI_RESOURCES) {
853 __s32 end = fh->vbi_fmt.end;
854
855 if (end > btv->crop_start)
856 goto fail;
857
858 /* Claim scan lines above fh->vbi_fmt.end. */
859 btv->vbi_end = end;
860 }
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 /* it's free, grab it */
863 fh->resources |= bit;
864 btv->resources |= bit;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300865 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return 1;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300867
868 fail:
869 mutex_unlock(&btv->lock);
870 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871}
872
873static
874int check_btres(struct bttv_fh *fh, int bit)
875{
876 return (fh->resources & bit);
877}
878
879static
880int locked_btres(struct bttv *btv, int bit)
881{
882 return (btv->resources & bit);
883}
884
Michael Schimeke5bd0262007-01-18 16:17:39 -0300885/* Call with btv->lock down. */
886static void
887disclaim_vbi_lines(struct bttv *btv)
888{
889 btv->vbi_end = 0;
890}
891
892/* Call with btv->lock down. */
893static void
894disclaim_video_lines(struct bttv *btv)
895{
896 const struct bttv_tvnorm *tvnorm;
897 u8 crop;
898
899 tvnorm = &bttv_tvnorms[btv->tvnorm];
900 btv->crop_start = tvnorm->cropcap.bounds.top
901 + tvnorm->cropcap.bounds.height;
902
903 /* VBI capturing ends at VDELAY, start of video capturing, no
904 matter how many lines the VBI RISC program expects. When video
905 capturing is off, it shall no longer "preempt" VBI capturing,
906 so we set VDELAY to maximum. */
907 crop = btread(BT848_E_CROP) | 0xc0;
908 btwrite(crop, BT848_E_CROP);
909 btwrite(0xfe, BT848_E_VDELAY_LO);
910 btwrite(crop, BT848_O_CROP);
911 btwrite(0xfe, BT848_O_VDELAY_LO);
912}
913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914static
915void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
916{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if ((fh->resources & bits) != bits) {
918 /* trying to free ressources not allocated by us ... */
919 printk("bttv: BUG! (btres)\n");
920 }
Michael Schimeke5bd0262007-01-18 16:17:39 -0300921 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 fh->resources &= ~bits;
923 btv->resources &= ~bits;
Michael Schimeke5bd0262007-01-18 16:17:39 -0300924
925 bits = btv->resources;
926
927 if (0 == (bits & VIDEO_RESOURCES))
928 disclaim_video_lines(btv);
929
930 if (0 == (bits & VBI_RESOURCES))
931 disclaim_vbi_lines(btv);
932
933 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934}
935
936/* ----------------------------------------------------------------------- */
937/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC */
938
939/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
940 PLL_X = Reference pre-divider (0=1, 1=2)
941 PLL_C = Post divider (0=6, 1=4)
942 PLL_I = Integer input
943 PLL_F = Fractional input
944
945 F_input = 28.636363 MHz:
946 PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
947*/
948
949static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
950{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800951 unsigned char fl, fh, fi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800953 /* prevent overflows */
954 fin/=4;
955 fout/=4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800957 fout*=12;
958 fi=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800960 fout=(fout%fin)*256;
961 fh=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800963 fout=(fout%fin)*256;
964 fl=fout/fin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800966 btwrite(fl, BT848_PLL_F_LO);
967 btwrite(fh, BT848_PLL_F_HI);
968 btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
971static void set_pll(struct bttv *btv)
972{
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800973 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800975 if (!btv->pll.pll_crystal)
976 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
978 if (btv->pll.pll_ofreq == btv->pll.pll_current) {
979 dprintk("bttv%d: PLL: no change required\n",btv->c.nr);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800980 return;
981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800983 if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {
984 /* no PLL needed */
985 if (btv->pll.pll_current == 0)
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800986 return;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700987 bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800988 btv->c.nr,btv->pll.pll_ifreq);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800989 btwrite(0x00,BT848_TGCTRL);
990 btwrite(0x00,BT848_PLL_XCI);
991 btv->pll.pll_current = 0;
992 return;
993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -0700995 bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr,
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -0800996 btv->pll.pll_ifreq, btv->pll.pll_ofreq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
998
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -0800999 for (i=0; i<10; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 /* Let other people run while the PLL stabilizes */
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001001 bttv_printk(".");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 msleep(10);
1003
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001004 if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 btwrite(0,BT848_DSTATUS);
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001006 } else {
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001007 btwrite(0x08,BT848_TGCTRL);
1008 btv->pll.pll_current = btv->pll.pll_ofreq;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001009 bttv_printk(" ok\n");
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08001010 return;
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001011 }
1012 }
1013 btv->pll.pll_current = -1;
Bernd Petrovitsche1e70a22005-09-22 21:43:53 -07001014 bttv_printk("failed\n");
Mauro Carvalho Chehabafd1a0c2005-12-12 00:37:27 -08001015 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016}
1017
1018/* used to switch between the bt848's analog/digital video capture modes */
1019static void bt848A_set_timing(struct bttv *btv)
1020{
1021 int i, len;
1022 int table_idx = bttv_tvnorms[btv->tvnorm].sram;
1023 int fsc = bttv_tvnorms[btv->tvnorm].Fsc;
1024
1025 if (UNSET == bttv_tvcards[btv->c.type].muxsel[btv->input]) {
1026 dprintk("bttv%d: load digital timing table (table_idx=%d)\n",
1027 btv->c.nr,table_idx);
1028
1029 /* timing change...reset timing generator address */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001030 btwrite(0x00, BT848_TGCTRL);
1031 btwrite(0x02, BT848_TGCTRL);
1032 btwrite(0x00, BT848_TGCTRL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 len=SRAM_Table[table_idx][0];
1035 for(i = 1; i <= len; i++)
1036 btwrite(SRAM_Table[table_idx][i],BT848_TGLB);
1037 btv->pll.pll_ofreq = 27000000;
1038
1039 set_pll(btv);
1040 btwrite(0x11, BT848_TGCTRL);
1041 btwrite(0x41, BT848_DVSIF);
1042 } else {
1043 btv->pll.pll_ofreq = fsc;
1044 set_pll(btv);
1045 btwrite(0x0, BT848_DVSIF);
1046 }
1047}
1048
1049/* ----------------------------------------------------------------------- */
1050
1051static void bt848_bright(struct bttv *btv, int bright)
1052{
1053 int value;
1054
1055 // printk("bttv: set bright: %d\n",bright); // DEBUG
1056 btv->bright = bright;
1057
1058 /* We want -128 to 127 we get 0-65535 */
1059 value = (bright >> 8) - 128;
1060 btwrite(value & 0xff, BT848_BRIGHT);
1061}
1062
1063static void bt848_hue(struct bttv *btv, int hue)
1064{
1065 int value;
1066
1067 btv->hue = hue;
1068
1069 /* -128 to 127 */
1070 value = (hue >> 8) - 128;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001071 btwrite(value & 0xff, BT848_HUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072}
1073
1074static void bt848_contrast(struct bttv *btv, int cont)
1075{
1076 int value,hibit;
1077
1078 btv->contrast = cont;
1079
1080 /* 0-511 */
1081 value = (cont >> 7);
1082 hibit = (value >> 6) & 4;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001083 btwrite(value & 0xff, BT848_CONTRAST_LO);
1084 btaor(hibit, ~4, BT848_E_CONTROL);
1085 btaor(hibit, ~4, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086}
1087
1088static void bt848_sat(struct bttv *btv, int color)
1089{
1090 int val_u,val_v,hibits;
1091
1092 btv->saturation = color;
1093
1094 /* 0-511 for the color */
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001095 val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
1096 val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001097 hibits = (val_u >> 7) & 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 hibits |= (val_v >> 8) & 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001099 btwrite(val_u & 0xff, BT848_SAT_U_LO);
1100 btwrite(val_v & 0xff, BT848_SAT_V_LO);
1101 btaor(hibits, ~3, BT848_E_CONTROL);
1102 btaor(hibits, ~3, BT848_O_CONTROL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103}
1104
1105/* ----------------------------------------------------------------------- */
1106
1107static int
1108video_mux(struct bttv *btv, unsigned int input)
1109{
1110 int mux,mask2;
1111
1112 if (input >= bttv_tvcards[btv->c.type].video_inputs)
1113 return -EINVAL;
1114
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001115 /* needed by RemoteVideo MX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 mask2 = bttv_tvcards[btv->c.type].gpiomask2;
1117 if (mask2)
1118 gpio_inout(mask2,mask2);
1119
1120 if (input == btv->svhs) {
1121 btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
1122 btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
1123 } else {
1124 btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
1125 btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
1126 }
1127 mux = bttv_tvcards[btv->c.type].muxsel[input] & 3;
1128 btaor(mux<<5, ~(3<<5), BT848_IFORM);
1129 dprintk(KERN_DEBUG "bttv%d: video mux: input=%d mux=%d\n",
1130 btv->c.nr,input,mux);
1131
1132 /* card specific hook */
1133 if(bttv_tvcards[btv->c.type].muxsel_hook)
1134 bttv_tvcards[btv->c.type].muxsel_hook (btv, input);
1135 return 0;
1136}
1137
1138static char *audio_modes[] = {
1139 "audio: tuner", "audio: radio", "audio: extern",
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001140 "audio: intern", "audio: mute"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141};
1142
1143static int
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001144audio_mux(struct bttv *btv, int input, int mute)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001146 int gpio_val, signal;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001147 struct v4l2_control ctrl;
1148 struct i2c_client *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
1150 gpio_inout(bttv_tvcards[btv->c.type].gpiomask,
1151 bttv_tvcards[btv->c.type].gpiomask);
1152 signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC;
1153
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001154 btv->mute = mute;
1155 btv->audio = input;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001157 /* automute */
1158 mute = mute || (btv->opt_automute && !signal && !btv->radio_user);
1159
1160 if (mute)
1161 gpio_val = bttv_tvcards[btv->c.type].gpiomute;
1162 else
1163 gpio_val = bttv_tvcards[btv->c.type].gpiomux[input];
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001164
1165 gpio_bits(bttv_tvcards[btv->c.type].gpiomask, gpio_val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 if (bttv_gpio)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001167 bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]);
1168 if (in_interrupt())
1169 return 0;
1170
1171 ctrl.id = V4L2_CID_AUDIO_MUTE;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001172 ctrl.value = btv->mute;
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001173 bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, &ctrl);
1174 c = btv->i2c_msp34xx_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001175 if (c) {
1176 struct v4l2_routing route;
1177
1178 /* Note: the inputs tuner/radio/extern/intern are translated
1179 to msp routings. This assumes common behavior for all msp3400
1180 based TV cards. When this assumption fails, then the
1181 specific MSP routing must be added to the card table.
1182 For now this is sufficient. */
1183 switch (input) {
1184 case TVAUDIO_INPUT_RADIO:
Hans Verkuil07151722006-04-01 18:03:23 -03001185 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1186 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001187 break;
1188 case TVAUDIO_INPUT_EXTERN:
Hans Verkuil07151722006-04-01 18:03:23 -03001189 route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
1190 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001191 break;
1192 case TVAUDIO_INPUT_INTERN:
1193 /* Yes, this is the same input as for RADIO. I doubt
1194 if this is ever used. The only board with an INTERN
1195 input is the BTTV_BOARD_AVERMEDIA98. I wonder how
1196 that was tested. My guess is that the whole INTERN
1197 input does not work. */
Hans Verkuil07151722006-04-01 18:03:23 -03001198 route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
1199 MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
Hans Verkuil2474ed42006-03-19 12:35:57 -03001200 break;
1201 case TVAUDIO_INPUT_TUNER:
1202 default:
1203 route.input = MSP_INPUT_DEFAULT;
1204 break;
1205 }
1206 route.output = MSP_OUTPUT_DEFAULT;
1207 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1208 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001209 c = btv->i2c_tvaudio_client;
Hans Verkuil2474ed42006-03-19 12:35:57 -03001210 if (c) {
1211 struct v4l2_routing route;
1212
1213 route.input = input;
1214 route.output = 0;
1215 c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route);
1216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 return 0;
1218}
1219
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001220static inline int
1221audio_mute(struct bttv *btv, int mute)
1222{
1223 return audio_mux(btv, btv->audio, mute);
1224}
1225
1226static inline int
1227audio_input(struct bttv *btv, int input)
1228{
1229 return audio_mux(btv, input, btv->mute);
1230}
1231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232static void
1233i2c_vidiocschan(struct bttv *btv)
1234{
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001235 v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001237 bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001238 if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001239 bttv_tda9880_setnorm(btv,btv->tvnorm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240}
1241
Michael Schimeke5bd0262007-01-18 16:17:39 -03001242static void
1243bttv_crop_calc_limits(struct bttv_crop *c)
1244{
1245 /* Scale factor min. 1:1, max. 16:1. Min. image size
1246 48 x 32. Scaled width must be a multiple of 4. */
1247
1248 if (1) {
1249 /* For bug compatibility with VIDIOCGCAP and image
1250 size checks in earlier driver versions. */
1251 c->min_scaled_width = 48;
1252 c->min_scaled_height = 32;
1253 } else {
1254 c->min_scaled_width =
1255 (max(48, c->rect.width >> 4) + 3) & ~3;
1256 c->min_scaled_height =
1257 max(32, c->rect.height >> 4);
1258 }
1259
1260 c->max_scaled_width = c->rect.width & ~3;
1261 c->max_scaled_height = c->rect.height;
1262}
1263
1264static void
1265bttv_crop_reset(struct bttv_crop *c, int norm)
1266{
1267 c->rect = bttv_tvnorms[norm].cropcap.defrect;
1268 bttv_crop_calc_limits(c);
1269}
1270
1271/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272static int
1273set_tvnorm(struct bttv *btv, unsigned int norm)
1274{
1275 const struct bttv_tvnorm *tvnorm;
1276
1277 if (norm < 0 || norm >= BTTV_TVNORMS)
1278 return -EINVAL;
1279
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 tvnorm = &bttv_tvnorms[norm];
1281
Michael Schimeke5bd0262007-01-18 16:17:39 -03001282 if (btv->tvnorm < 0 ||
1283 btv->tvnorm >= BTTV_TVNORMS ||
1284 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
1285 &tvnorm->cropcap,
1286 sizeof (tvnorm->cropcap))) {
1287 bttv_crop_reset(&btv->crop[0], norm);
1288 btv->crop[1] = btv->crop[0]; /* current = default */
1289
1290 if (0 == (btv->resources & VIDEO_RESOURCES)) {
1291 btv->crop_start = tvnorm->cropcap.bounds.top
1292 + tvnorm->cropcap.bounds.height;
1293 }
1294 }
1295
1296 btv->tvnorm = norm;
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 btwrite(tvnorm->adelay, BT848_ADELAY);
1299 btwrite(tvnorm->bdelay, BT848_BDELAY);
1300 btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
1301 BT848_IFORM);
1302 btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE);
1303 btwrite(1, BT848_VBI_PACK_DEL);
1304 bt848A_set_timing(btv);
1305
1306 switch (btv->c.type) {
Mauro Carvalho Chehab5a25e842005-11-08 21:36:52 -08001307 case BTTV_BOARD_VOODOOTV_FM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 bttv_tda9880_setnorm(btv,norm);
1309 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 }
1311 return 0;
1312}
1313
Michael Schimeke5bd0262007-01-18 16:17:39 -03001314/* Call with btv->lock down. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315static void
1316set_input(struct bttv *btv, unsigned int input)
1317{
1318 unsigned long flags;
1319
1320 btv->input = input;
1321 if (irq_iswitch) {
1322 spin_lock_irqsave(&btv->s_lock,flags);
1323 if (btv->curr.frame_irq) {
1324 /* active capture -> delayed input switch */
1325 btv->new_input = input;
1326 } else {
1327 video_mux(btv,input);
1328 }
1329 spin_unlock_irqrestore(&btv->s_lock,flags);
1330 } else {
1331 video_mux(btv,input);
1332 }
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03001333 audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ?
1334 TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 set_tvnorm(btv,btv->tvnorm);
1336 i2c_vidiocschan(btv);
1337}
1338
1339static void init_irqreg(struct bttv *btv)
1340{
1341 /* clear status */
1342 btwrite(0xfffffUL, BT848_INT_STAT);
1343
1344 if (bttv_tvcards[btv->c.type].no_video) {
1345 /* i2c only */
1346 btwrite(BT848_INT_I2CDONE,
1347 BT848_INT_MASK);
1348 } else {
1349 /* full video */
1350 btwrite((btv->triton1) |
1351 (btv->gpioirq ? BT848_INT_GPINT : 0) |
1352 BT848_INT_SCERR |
1353 (fdsr ? BT848_INT_FDSR : 0) |
1354 BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
1355 BT848_INT_FMTCHG|BT848_INT_HLOCK|
1356 BT848_INT_I2CDONE,
1357 BT848_INT_MASK);
1358 }
1359}
1360
1361static void init_bt848(struct bttv *btv)
1362{
1363 int val;
1364
1365 if (bttv_tvcards[btv->c.type].no_video) {
1366 /* very basic init only */
1367 init_irqreg(btv);
1368 return;
1369 }
1370
1371 btwrite(0x00, BT848_CAP_CTL);
1372 btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
1373 btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM);
1374
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001375 /* set planar and packed mode trigger points and */
1376 /* set rising edge of inverted GPINTR pin as irq trigger */
1377 btwrite(BT848_GPIO_DMA_CTL_PKTP_32|
1378 BT848_GPIO_DMA_CTL_PLTP1_16|
1379 BT848_GPIO_DMA_CTL_PLTP23_16|
1380 BT848_GPIO_DMA_CTL_GPINTC|
1381 BT848_GPIO_DMA_CTL_GPINTI,
1382 BT848_GPIO_DMA_CTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001385 btwrite(val, BT848_E_SCLOOP);
1386 btwrite(val, BT848_O_SCLOOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001388 btwrite(0x20, BT848_E_VSCALE_HI);
1389 btwrite(0x20, BT848_O_VSCALE_HI);
1390 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 BT848_ADC);
1392
1393 btwrite(whitecrush_upper, BT848_WC_UP);
1394 btwrite(whitecrush_lower, BT848_WC_DOWN);
1395
1396 if (btv->opt_lumafilter) {
1397 btwrite(0, BT848_E_CONTROL);
1398 btwrite(0, BT848_O_CONTROL);
1399 } else {
1400 btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1401 btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1402 }
1403
1404 bt848_bright(btv, btv->bright);
1405 bt848_hue(btv, btv->hue);
1406 bt848_contrast(btv, btv->contrast);
1407 bt848_sat(btv, btv->saturation);
1408
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001409 /* interrupt */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 init_irqreg(btv);
1411}
1412
1413static void bttv_reinit_bt848(struct bttv *btv)
1414{
1415 unsigned long flags;
1416
1417 if (bttv_verbose)
1418 printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr);
1419 spin_lock_irqsave(&btv->s_lock,flags);
1420 btv->errors=0;
1421 bttv_set_dma(btv,0);
1422 spin_unlock_irqrestore(&btv->s_lock,flags);
1423
1424 init_bt848(btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001425 btv->pll.pll_current = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 set_input(btv,btv->input);
1427}
1428
1429static int get_control(struct bttv *btv, struct v4l2_control *c)
1430{
1431 struct video_audio va;
1432 int i;
1433
1434 for (i = 0; i < BTTV_CTLS; i++)
1435 if (bttv_ctls[i].id == c->id)
1436 break;
1437 if (i == BTTV_CTLS)
1438 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001439 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001441 btv->audio_hook(btv,&va,0);
1442 switch (c->id) {
1443 case V4L2_CID_AUDIO_MUTE:
1444 c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0;
1445 break;
1446 case V4L2_CID_AUDIO_VOLUME:
1447 c->value = va.volume;
1448 break;
1449 case V4L2_CID_AUDIO_BALANCE:
1450 c->value = va.balance;
1451 break;
1452 case V4L2_CID_AUDIO_BASS:
1453 c->value = va.bass;
1454 break;
1455 case V4L2_CID_AUDIO_TREBLE:
1456 c->value = va.treble;
1457 break;
1458 }
1459 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 }
1461 switch (c->id) {
1462 case V4L2_CID_BRIGHTNESS:
1463 c->value = btv->bright;
1464 break;
1465 case V4L2_CID_HUE:
1466 c->value = btv->hue;
1467 break;
1468 case V4L2_CID_CONTRAST:
1469 c->value = btv->contrast;
1470 break;
1471 case V4L2_CID_SATURATION:
1472 c->value = btv->saturation;
1473 break;
1474
1475 case V4L2_CID_AUDIO_MUTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001480 bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 break;
1482
1483 case V4L2_CID_PRIVATE_CHROMA_AGC:
1484 c->value = btv->opt_chroma_agc;
1485 break;
1486 case V4L2_CID_PRIVATE_COMBFILTER:
1487 c->value = btv->opt_combfilter;
1488 break;
1489 case V4L2_CID_PRIVATE_LUMAFILTER:
1490 c->value = btv->opt_lumafilter;
1491 break;
1492 case V4L2_CID_PRIVATE_AUTOMUTE:
1493 c->value = btv->opt_automute;
1494 break;
1495 case V4L2_CID_PRIVATE_AGC_CRUSH:
1496 c->value = btv->opt_adc_crush;
1497 break;
1498 case V4L2_CID_PRIVATE_VCR_HACK:
1499 c->value = btv->opt_vcr_hack;
1500 break;
1501 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1502 c->value = btv->opt_whitecrush_upper;
1503 break;
1504 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1505 c->value = btv->opt_whitecrush_lower;
1506 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001507 case V4L2_CID_PRIVATE_UV_RATIO:
1508 c->value = btv->opt_uv_ratio;
1509 break;
1510 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1511 c->value = btv->opt_full_luma_range;
1512 break;
1513 case V4L2_CID_PRIVATE_CORING:
1514 c->value = btv->opt_coring;
1515 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 default:
1517 return -EINVAL;
1518 }
1519 return 0;
1520}
1521
1522static int set_control(struct bttv *btv, struct v4l2_control *c)
1523{
1524 struct video_audio va;
1525 int i,val;
1526
1527 for (i = 0; i < BTTV_CTLS; i++)
1528 if (bttv_ctls[i].id == c->id)
1529 break;
1530 if (i == BTTV_CTLS)
1531 return -EINVAL;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001532 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001534 btv->audio_hook(btv,&va,0);
1535 switch (c->id) {
1536 case V4L2_CID_AUDIO_MUTE:
1537 if (c->value) {
1538 va.flags |= VIDEO_AUDIO_MUTE;
1539 audio_mute(btv, 1);
1540 } else {
1541 va.flags &= ~VIDEO_AUDIO_MUTE;
1542 audio_mute(btv, 0);
1543 }
1544 break;
1545
1546 case V4L2_CID_AUDIO_VOLUME:
1547 va.volume = c->value;
1548 break;
1549 case V4L2_CID_AUDIO_BALANCE:
1550 va.balance = c->value;
1551 break;
1552 case V4L2_CID_AUDIO_BASS:
1553 va.bass = c->value;
1554 break;
1555 case V4L2_CID_AUDIO_TREBLE:
1556 va.treble = c->value;
1557 break;
1558 }
1559 btv->audio_hook(btv,&va,1);
1560 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 }
1562 switch (c->id) {
1563 case V4L2_CID_BRIGHTNESS:
1564 bt848_bright(btv,c->value);
1565 break;
1566 case V4L2_CID_HUE:
1567 bt848_hue(btv,c->value);
1568 break;
1569 case V4L2_CID_CONTRAST:
1570 bt848_contrast(btv,c->value);
1571 break;
1572 case V4L2_CID_SATURATION:
1573 bt848_sat(btv,c->value);
1574 break;
1575 case V4L2_CID_AUDIO_MUTE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001576 audio_mute(btv, c->value);
1577 /* fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 case V4L2_CID_AUDIO_VOLUME:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 case V4L2_CID_AUDIO_BALANCE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 case V4L2_CID_AUDIO_BASS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 case V4L2_CID_AUDIO_TREBLE:
Hans Verkuil0020d3e2006-03-30 19:50:34 -03001582 bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 break;
1584
1585 case V4L2_CID_PRIVATE_CHROMA_AGC:
1586 btv->opt_chroma_agc = c->value;
1587 val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0;
1588 btwrite(val, BT848_E_SCLOOP);
1589 btwrite(val, BT848_O_SCLOOP);
1590 break;
1591 case V4L2_CID_PRIVATE_COMBFILTER:
1592 btv->opt_combfilter = c->value;
1593 break;
1594 case V4L2_CID_PRIVATE_LUMAFILTER:
1595 btv->opt_lumafilter = c->value;
1596 if (btv->opt_lumafilter) {
1597 btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL);
1598 btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL);
1599 } else {
1600 btor(BT848_CONTROL_LDEC, BT848_E_CONTROL);
1601 btor(BT848_CONTROL_LDEC, BT848_O_CONTROL);
1602 }
1603 break;
1604 case V4L2_CID_PRIVATE_AUTOMUTE:
1605 btv->opt_automute = c->value;
1606 break;
1607 case V4L2_CID_PRIVATE_AGC_CRUSH:
1608 btv->opt_adc_crush = c->value;
1609 btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0),
1610 BT848_ADC);
1611 break;
1612 case V4L2_CID_PRIVATE_VCR_HACK:
1613 btv->opt_vcr_hack = c->value;
1614 break;
1615 case V4L2_CID_PRIVATE_WHITECRUSH_UPPER:
1616 btv->opt_whitecrush_upper = c->value;
1617 btwrite(c->value, BT848_WC_UP);
1618 break;
1619 case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
1620 btv->opt_whitecrush_lower = c->value;
1621 btwrite(c->value, BT848_WC_DOWN);
1622 break;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07001623 case V4L2_CID_PRIVATE_UV_RATIO:
1624 btv->opt_uv_ratio = c->value;
1625 bt848_sat(btv, btv->saturation);
1626 break;
1627 case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
1628 btv->opt_full_luma_range = c->value;
1629 btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
1630 break;
1631 case V4L2_CID_PRIVATE_CORING:
1632 btv->opt_coring = c->value;
1633 btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
1634 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 default:
1636 return -EINVAL;
1637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 return 0;
1639}
1640
1641/* ----------------------------------------------------------------------- */
1642
1643void bttv_gpio_tracking(struct bttv *btv, char *comment)
1644{
1645 unsigned int outbits, data;
1646 outbits = btread(BT848_GPIO_OUT_EN);
1647 data = btread(BT848_GPIO_DATA);
1648 printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",
1649 btv->c.nr,outbits,data & outbits, data & ~outbits, comment);
1650}
1651
1652static void bttv_field_count(struct bttv *btv)
1653{
1654 int need_count = 0;
1655
1656 if (btv->users)
1657 need_count++;
1658
1659 if (need_count) {
1660 /* start field counter */
1661 btor(BT848_INT_VSYNC,BT848_INT_MASK);
1662 } else {
1663 /* stop field counter */
1664 btand(~BT848_INT_VSYNC,BT848_INT_MASK);
1665 btv->field_count = 0;
1666 }
1667}
1668
1669static const struct bttv_format*
1670format_by_palette(int palette)
1671{
1672 unsigned int i;
1673
1674 for (i = 0; i < BTTV_FORMATS; i++) {
1675 if (-1 == bttv_formats[i].palette)
1676 continue;
1677 if (bttv_formats[i].palette == palette)
1678 return bttv_formats+i;
1679 }
1680 return NULL;
1681}
1682
1683static const struct bttv_format*
1684format_by_fourcc(int fourcc)
1685{
1686 unsigned int i;
1687
1688 for (i = 0; i < BTTV_FORMATS; i++) {
1689 if (-1 == bttv_formats[i].fourcc)
1690 continue;
1691 if (bttv_formats[i].fourcc == fourcc)
1692 return bttv_formats+i;
1693 }
1694 return NULL;
1695}
1696
1697/* ----------------------------------------------------------------------- */
1698/* misc helpers */
1699
1700static int
1701bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
1702 struct bttv_buffer *new)
1703{
1704 struct bttv_buffer *old;
1705 unsigned long flags;
1706 int retval = 0;
1707
1708 dprintk("switch_overlay: enter [new=%p]\n",new);
1709 if (new)
1710 new->vb.state = STATE_DONE;
1711 spin_lock_irqsave(&btv->s_lock,flags);
1712 old = btv->screen;
1713 btv->screen = new;
1714 btv->loop_irq |= 1;
1715 bttv_set_dma(btv, 0x03);
1716 spin_unlock_irqrestore(&btv->s_lock,flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 if (NULL != old) {
1718 dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001719 bttv_dma_free(&fh->cap,btv, old);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 kfree(old);
1721 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03001722 if (NULL == new)
1723 free_btres(btv,fh,RESOURCE_OVERLAY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 dprintk("switch_overlay: done\n");
1725 return retval;
1726}
1727
1728/* ----------------------------------------------------------------------- */
1729/* video4linux (1) interface */
1730
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001731static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
1732 struct bttv_buffer *buf,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001733 const struct bttv_format *fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 unsigned int width, unsigned int height,
1735 enum v4l2_field field)
1736{
Michael Schimeke5bd0262007-01-18 16:17:39 -03001737 struct bttv_fh *fh = q->priv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 int redo_dma_risc = 0;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001739 struct bttv_crop c;
1740 int norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 int rc;
1742
1743 /* check settings */
1744 if (NULL == fmt)
1745 return -EINVAL;
1746 if (fmt->btformat == BT848_COLOR_FMT_RAW) {
1747 width = RAW_BPL;
1748 height = RAW_LINES*2;
1749 if (width*height > buf->vb.bsize)
1750 return -EINVAL;
1751 buf->vb.size = buf->vb.bsize;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001752
1753 /* Make sure tvnorm and vbi_end remain consistent
1754 until we're done. */
1755 mutex_lock(&btv->lock);
1756
1757 norm = btv->tvnorm;
1758
1759 /* In this mode capturing always starts at defrect.top
1760 (default VDELAY), ignoring cropping parameters. */
1761 if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
1762 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001764 }
1765
1766 mutex_unlock(&btv->lock);
1767
1768 c.rect = bttv_tvnorms[norm].cropcap.defrect;
1769 } else {
1770 mutex_lock(&btv->lock);
1771
1772 norm = btv->tvnorm;
1773 c = btv->crop[!!fh->do_crop];
1774
1775 mutex_unlock(&btv->lock);
1776
1777 if (width < c.min_scaled_width ||
1778 width > c.max_scaled_width ||
1779 height < c.min_scaled_height)
1780 return -EINVAL;
1781
1782 switch (field) {
1783 case V4L2_FIELD_TOP:
1784 case V4L2_FIELD_BOTTOM:
1785 case V4L2_FIELD_ALTERNATE:
1786 /* btv->crop counts frame lines. Max. scale
1787 factor is 16:1 for frames, 8:1 for fields. */
1788 if (height * 2 > c.max_scaled_height)
1789 return -EINVAL;
1790 break;
1791
1792 default:
1793 if (height > c.max_scaled_height)
1794 return -EINVAL;
1795 break;
1796 }
1797
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 buf->vb.size = (width * height * fmt->depth) >> 3;
1799 if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
1800 return -EINVAL;
1801 }
1802
1803 /* alloc + fill struct bttv_buffer (if changed) */
1804 if (buf->vb.width != width || buf->vb.height != height ||
1805 buf->vb.field != field ||
Michael Schimeke5bd0262007-01-18 16:17:39 -03001806 buf->tvnorm != norm || buf->fmt != fmt ||
1807 buf->crop.top != c.rect.top ||
1808 buf->crop.left != c.rect.left ||
1809 buf->crop.width != c.rect.width ||
1810 buf->crop.height != c.rect.height) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 buf->vb.width = width;
1812 buf->vb.height = height;
1813 buf->vb.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001814 buf->tvnorm = norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 buf->fmt = fmt;
Michael Schimeke5bd0262007-01-18 16:17:39 -03001816 buf->crop = c.rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 redo_dma_risc = 1;
1818 }
1819
1820 /* alloc risc memory */
1821 if (STATE_NEEDS_INIT == buf->vb.state) {
1822 redo_dma_risc = 1;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001823 if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 goto fail;
1825 }
1826
1827 if (redo_dma_risc)
1828 if (0 != (rc = bttv_buffer_risc(btv,buf)))
1829 goto fail;
1830
1831 buf->vb.state = STATE_PREPARED;
1832 return 0;
1833
1834 fail:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001835 bttv_dma_free(q,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 return rc;
1837}
1838
1839static int
1840buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
1841{
1842 struct bttv_fh *fh = q->priv_data;
1843
1844 *size = fh->fmt->depth*fh->width*fh->height >> 3;
1845 if (0 == *count)
1846 *count = gbuffers;
1847 while (*size * *count > gbuffers * gbufsize)
1848 (*count)--;
1849 return 0;
1850}
1851
1852static int
1853buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
1854 enum v4l2_field field)
1855{
1856 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1857 struct bttv_fh *fh = q->priv_data;
1858
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001859 return bttv_prepare_buffer(q,fh->btv, buf, fh->fmt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 fh->width, fh->height, field);
1861}
1862
1863static void
1864buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
1865{
1866 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1867 struct bttv_fh *fh = q->priv_data;
1868 struct bttv *btv = fh->btv;
1869
1870 buf->vb.state = STATE_QUEUED;
1871 list_add_tail(&buf->vb.queue,&btv->capture);
1872 if (!btv->curr.frame_irq) {
1873 btv->loop_irq |= 1;
1874 bttv_set_dma(btv, 0x03);
1875 }
1876}
1877
1878static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1879{
1880 struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
1881 struct bttv_fh *fh = q->priv_data;
1882
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03001883 bttv_dma_free(&fh->cap,fh->btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884}
1885
1886static struct videobuf_queue_ops bttv_video_qops = {
1887 .buf_setup = buffer_setup,
1888 .buf_prepare = buffer_prepare,
1889 .buf_queue = buffer_queue,
1890 .buf_release = buffer_release,
1891};
1892
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
1894{
1895 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001896 case BTTV_VERSION:
1897 return BTTV_VERSION_CODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 /* *** v4l1 *** ************************************************ */
1900 case VIDIOCGFREQ:
1901 {
1902 unsigned long *freq = arg;
1903 *freq = btv->freq;
1904 return 0;
1905 }
1906 case VIDIOCSFREQ:
1907 {
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001908 struct v4l2_frequency freq;
1909
1910 memset(&freq, 0, sizeof(freq));
1911 freq.frequency = *(unsigned long *)arg;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001912 mutex_lock(&btv->lock);
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001913 freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
1914 btv->freq = *(unsigned long *)arg;
1915 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 if (btv->has_matchbox && btv->radio_user)
Hans Verkuil3bbe5a82006-04-01 15:27:52 -03001917 tea5757_set_freq(btv,*(unsigned long *)arg);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001918 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 return 0;
1920 }
1921
1922 case VIDIOCGTUNER:
1923 {
1924 struct video_tuner *v = arg;
1925
1926 if (UNSET == bttv_tvcards[btv->c.type].tuner)
1927 return -EINVAL;
1928 if (v->tuner) /* Only tuner 0 */
1929 return -EINVAL;
1930 strcpy(v->name, "Television");
1931 v->rangelow = 0;
1932 v->rangehigh = 0x7FFFFFFF;
1933 v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
1934 v->mode = btv->tvnorm;
1935 v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
1936 bttv_call_i2c_clients(btv,cmd,v);
1937 return 0;
1938 }
1939 case VIDIOCSTUNER:
1940 {
1941 struct video_tuner *v = arg;
1942
1943 if (v->tuner) /* Only tuner 0 */
1944 return -EINVAL;
1945 if (v->mode >= BTTV_TVNORMS)
1946 return -EINVAL;
1947
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001948 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 set_tvnorm(btv,v->mode);
1950 bttv_call_i2c_clients(btv,cmd,v);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001951 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 return 0;
1953 }
1954
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001955 case VIDIOCGCHAN:
1956 {
1957 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 unsigned int channel = v->channel;
1959
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001960 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1961 return -EINVAL;
1962 v->tuners=0;
1963 v->flags = VIDEO_VC_AUDIO;
1964 v->type = VIDEO_TYPE_CAMERA;
1965 v->norm = btv->tvnorm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 if (channel == bttv_tvcards[btv->c.type].tuner) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001967 strcpy(v->name,"Television");
1968 v->flags|=VIDEO_VC_TUNER;
1969 v->type=VIDEO_TYPE_TV;
1970 v->tuners=1;
1971 } else if (channel == btv->svhs) {
1972 strcpy(v->name,"S-Video");
1973 } else {
1974 sprintf(v->name,"Composite%d",channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 }
1976 return 0;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08001977 }
1978 case VIDIOCSCHAN:
1979 {
1980 struct video_channel *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 unsigned int channel = v->channel;
1982
1983 if (channel >= bttv_tvcards[btv->c.type].video_inputs)
1984 return -EINVAL;
1985 if (v->norm >= BTTV_TVNORMS)
1986 return -EINVAL;
1987
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001988 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 if (channel == btv->input &&
1990 v->norm == btv->tvnorm) {
1991 /* nothing to do */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001992 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 return 0;
1994 }
1995
1996 btv->tvnorm = v->norm;
1997 set_input(btv,v->channel);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02001998 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return 0;
2000 }
2001
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002002 case VIDIOCGAUDIO:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 {
2004 struct video_audio *v = arg;
2005
2006 memset(v,0,sizeof(*v));
2007 strcpy(v->name,"Television");
2008 v->flags |= VIDEO_AUDIO_MUTABLE;
2009 v->mode = VIDEO_SOUND_MONO;
2010
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002011 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 bttv_call_i2c_clients(btv,cmd,v);
2013
2014 /* card specific hooks */
2015 if (btv->audio_hook)
2016 btv->audio_hook(btv,v,0);
2017
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002018 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 return 0;
2020 }
2021 case VIDIOCSAUDIO:
2022 {
2023 struct video_audio *v = arg;
2024 unsigned int audio = v->audio;
2025
2026 if (audio >= bttv_tvcards[btv->c.type].audio_inputs)
2027 return -EINVAL;
2028
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002029 mutex_lock(&btv->lock);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03002030 audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 bttv_call_i2c_clients(btv,cmd,v);
2032
2033 /* card specific hooks */
2034 if (btv->audio_hook)
2035 btv->audio_hook(btv,v,1);
2036
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002037 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 return 0;
2039 }
2040
2041 /* *** v4l2 *** ************************************************ */
2042 case VIDIOC_ENUMSTD:
2043 {
2044 struct v4l2_standard *e = arg;
2045 unsigned int index = e->index;
2046
2047 if (index >= BTTV_TVNORMS)
2048 return -EINVAL;
2049 v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id,
2050 bttv_tvnorms[e->index].name);
2051 e->index = index;
2052 return 0;
2053 }
2054 case VIDIOC_G_STD:
2055 {
2056 v4l2_std_id *id = arg;
2057 *id = bttv_tvnorms[btv->tvnorm].v4l2_id;
2058 return 0;
2059 }
2060 case VIDIOC_S_STD:
2061 {
2062 v4l2_std_id *id = arg;
2063 unsigned int i;
2064
2065 for (i = 0; i < BTTV_TVNORMS; i++)
2066 if (*id & bttv_tvnorms[i].v4l2_id)
2067 break;
2068 if (i == BTTV_TVNORMS)
2069 return -EINVAL;
2070
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002071 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 set_tvnorm(btv,i);
2073 i2c_vidiocschan(btv);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002074 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 return 0;
2076 }
2077 case VIDIOC_QUERYSTD:
2078 {
2079 v4l2_std_id *id = arg;
2080
2081 if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML)
2082 *id = V4L2_STD_625_50;
2083 else
2084 *id = V4L2_STD_525_60;
2085 return 0;
2086 }
2087
2088 case VIDIOC_ENUMINPUT:
2089 {
2090 struct v4l2_input *i = arg;
2091 unsigned int n;
2092
2093 n = i->index;
2094 if (n >= bttv_tvcards[btv->c.type].video_inputs)
2095 return -EINVAL;
2096 memset(i,0,sizeof(*i));
2097 i->index = n;
2098 i->type = V4L2_INPUT_TYPE_CAMERA;
Mauro Carvalho Chehab5d9d1712006-11-14 12:40:07 -03002099 i->audioset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 if (i->index == bttv_tvcards[btv->c.type].tuner) {
2101 sprintf(i->name, "Television");
2102 i->type = V4L2_INPUT_TYPE_TUNER;
2103 i->tuner = 0;
2104 } else if (i->index == btv->svhs) {
2105 sprintf(i->name, "S-Video");
2106 } else {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002107 sprintf(i->name,"Composite%d",i->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 }
2109 if (i->index == btv->input) {
2110 __u32 dstatus = btread(BT848_DSTATUS);
2111 if (0 == (dstatus & BT848_DSTATUS_PRES))
2112 i->status |= V4L2_IN_ST_NO_SIGNAL;
2113 if (0 == (dstatus & BT848_DSTATUS_HLOC))
2114 i->status |= V4L2_IN_ST_NO_H_LOCK;
2115 }
2116 for (n = 0; n < BTTV_TVNORMS; n++)
2117 i->std |= bttv_tvnorms[n].v4l2_id;
2118 return 0;
2119 }
2120 case VIDIOC_G_INPUT:
2121 {
2122 int *i = arg;
2123 *i = btv->input;
2124 return 0;
2125 }
2126 case VIDIOC_S_INPUT:
2127 {
2128 unsigned int *i = arg;
2129
2130 if (*i > bttv_tvcards[btv->c.type].video_inputs)
2131 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002132 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 set_input(btv,*i);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002134 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 return 0;
2136 }
2137
2138 case VIDIOC_G_TUNER:
2139 {
2140 struct v4l2_tuner *t = arg;
2141
2142 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2143 return -EINVAL;
2144 if (0 != t->index)
2145 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002146 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 memset(t,0,sizeof(*t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002149 bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t);
2150 strcpy(t->name, "Television");
2151 t->capability = V4L2_TUNER_CAP_NORM;
2152 t->type = V4L2_TUNER_ANALOG_TV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)
2154 t->signal = 0xffff;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08002155
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002156 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 /* Hmmm ... */
2158 struct video_audio va;
2159 memset(&va, 0, sizeof(struct video_audio));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002160 btv->audio_hook(btv,&va,0);
2161 t->audmode = V4L2_TUNER_MODE_MONO;
2162 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 if(va.mode & VIDEO_SOUND_STEREO) {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002164 t->audmode = V4L2_TUNER_MODE_STEREO;
2165 t->rxsubchans = V4L2_TUNER_SUB_STEREO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 }
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002167 if(va.mode & VIDEO_SOUND_LANG2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 t->audmode = V4L2_TUNER_MODE_LANG1;
2169 t->rxsubchans = V4L2_TUNER_SUB_LANG1
2170 | V4L2_TUNER_SUB_LANG2;
2171 }
2172 }
2173 /* FIXME: fill capability+audmode */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002174 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 return 0;
2176 }
2177 case VIDIOC_S_TUNER:
2178 {
2179 struct v4l2_tuner *t = arg;
2180
2181 if (UNSET == bttv_tvcards[btv->c.type].tuner)
2182 return -EINVAL;
2183 if (0 != t->index)
2184 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002185 mutex_lock(&btv->lock);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002186 bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t);
2187 if (btv->audio_hook) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 struct video_audio va;
2189 memset(&va, 0, sizeof(struct video_audio));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 if (t->audmode == V4L2_TUNER_MODE_MONO)
2191 va.mode = VIDEO_SOUND_MONO;
Hans Verkuil301e22d2006-03-18 17:15:00 -03002192 else if (t->audmode == V4L2_TUNER_MODE_STEREO ||
2193 t->audmode == V4L2_TUNER_MODE_LANG1_LANG2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 va.mode = VIDEO_SOUND_STEREO;
2195 else if (t->audmode == V4L2_TUNER_MODE_LANG1)
2196 va.mode = VIDEO_SOUND_LANG1;
2197 else if (t->audmode == V4L2_TUNER_MODE_LANG2)
2198 va.mode = VIDEO_SOUND_LANG2;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002199 btv->audio_hook(btv,&va,1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 }
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002201 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 return 0;
2203 }
2204
2205 case VIDIOC_G_FREQUENCY:
2206 {
2207 struct v4l2_frequency *f = arg;
2208
2209 memset(f,0,sizeof(*f));
2210 f->type = V4L2_TUNER_ANALOG_TV;
2211 f->frequency = btv->freq;
2212 return 0;
2213 }
2214 case VIDIOC_S_FREQUENCY:
2215 {
2216 struct v4l2_frequency *f = arg;
2217
2218 if (unlikely(f->tuner != 0))
2219 return -EINVAL;
Mauro Carvalho Chehabfa9846a2005-07-12 13:58:42 -07002220 if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 return -EINVAL;
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002222 mutex_lock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 btv->freq = f->frequency;
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002224 bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 if (btv->has_matchbox && btv->radio_user)
2226 tea5757_set_freq(btv,btv->freq);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02002227 mutex_unlock(&btv->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 return 0;
2229 }
Hans Verkuil299392b2005-11-08 21:37:42 -08002230 case VIDIOC_LOG_STATUS:
2231 {
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002232 printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr);
Luiz Capitulino97cb4452005-12-01 00:51:24 -08002233 bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL);
Hans Verkuil0020d3e2006-03-30 19:50:34 -03002234 printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
Hans Verkuil299392b2005-11-08 21:37:42 -08002235 return 0;
2236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 default:
2239 return -ENOIOCTLCMD;
2240
2241 }
2242 return 0;
2243}
2244
Michael Schimeke5bd0262007-01-18 16:17:39 -03002245/* Given cropping boundaries b and the scaled width and height of a
2246 single field or frame, which must not exceed hardware limits, this
2247 function adjusts the cropping parameters c. */
2248static void
2249bttv_crop_adjust (struct bttv_crop * c,
2250 const struct v4l2_rect * b,
2251 __s32 width,
2252 __s32 height,
2253 enum v4l2_field field)
2254{
2255 __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
2256 __s32 max_left;
2257 __s32 max_top;
2258
2259 if (width < c->min_scaled_width) {
2260 /* Max. hor. scale factor 16:1. */
2261 c->rect.width = width * 16;
2262 } else if (width > c->max_scaled_width) {
2263 /* Min. hor. scale factor 1:1. */
2264 c->rect.width = width;
2265
2266 max_left = b->left + b->width - width;
2267 max_left = min(max_left, (__s32) MAX_HDELAY);
2268 if (c->rect.left > max_left)
2269 c->rect.left = max_left;
2270 }
2271
2272 if (height < c->min_scaled_height) {
2273 /* Max. vert. scale factor 16:1, single fields 8:1. */
2274 c->rect.height = height * 16;
2275 } else if (frame_height > c->max_scaled_height) {
2276 /* Min. vert. scale factor 1:1.
2277 Top and height count field lines times two. */
2278 c->rect.height = (frame_height + 1) & ~1;
2279
2280 max_top = b->top + b->height - c->rect.height;
2281 if (c->rect.top > max_top)
2282 c->rect.top = max_top;
2283 }
2284
2285 bttv_crop_calc_limits(c);
2286}
2287
2288/* Returns an error if scaling to a frame or single field with the given
2289 width and height is not possible with the current cropping parameters
2290 and width aligned according to width_mask. If adjust_size is TRUE the
2291 function may adjust the width and/or height instead, rounding width
2292 to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
2293 also adjust the current cropping parameters to get closer to the
2294 desired image size. */
2295static int
2296limit_scaled_size (struct bttv_fh * fh,
2297 __s32 * width,
2298 __s32 * height,
2299 enum v4l2_field field,
2300 unsigned int width_mask,
2301 unsigned int width_bias,
2302 int adjust_size,
2303 int adjust_crop)
2304{
2305 struct bttv *btv = fh->btv;
2306 const struct v4l2_rect *b;
2307 struct bttv_crop *c;
2308 __s32 min_width;
2309 __s32 min_height;
2310 __s32 max_width;
2311 __s32 max_height;
2312 int rc;
2313
2314 BUG_ON((int) width_mask >= 0 ||
2315 width_bias >= (unsigned int) -width_mask);
2316
2317 /* Make sure tvnorm, vbi_end and the current cropping parameters
2318 remain consistent until we're done. */
2319 mutex_lock(&btv->lock);
2320
2321 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
2322
2323 /* Do crop - use current, don't - use default parameters. */
2324 c = &btv->crop[!!fh->do_crop];
2325
2326 if (fh->do_crop
2327 && adjust_size
2328 && adjust_crop
2329 && !locked_btres(btv, VIDEO_RESOURCES)) {
2330 min_width = 48;
2331 min_height = 32;
2332
2333 /* We cannot scale up. When the scaled image is larger
2334 than crop.rect we adjust the crop.rect as required
2335 by the V4L2 spec, hence cropcap.bounds are our limit. */
2336 max_width = min(b->width, (__s32) MAX_HACTIVE);
2337 max_height = b->height;
2338
2339 /* We cannot capture the same line as video and VBI data.
2340 Note btv->vbi_end is really a minimum, see
2341 bttv_vbi_try_fmt(). */
2342 if (btv->vbi_end > b->top) {
2343 max_height -= btv->vbi_end - b->top;
2344 rc = -EBUSY;
2345 if (min_height > max_height)
2346 goto fail;
2347 }
2348 } else {
2349 rc = -EBUSY;
2350 if (btv->vbi_end > c->rect.top)
2351 goto fail;
2352
2353 min_width = c->min_scaled_width;
2354 min_height = c->min_scaled_height;
2355 max_width = c->max_scaled_width;
2356 max_height = c->max_scaled_height;
2357
2358 adjust_crop = 0;
2359 }
2360
2361 min_width = (min_width - width_mask - 1) & width_mask;
2362 max_width = max_width & width_mask;
2363
2364 /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
2365 min_height = min_height;
2366 /* Min. scale factor is 1:1. */
2367 max_height >>= !V4L2_FIELD_HAS_BOTH(field);
2368
2369 if (adjust_size) {
2370 *width = clamp(*width, min_width, max_width);
2371 *height = clamp(*height, min_height, max_height);
2372
2373 /* Round after clamping to avoid overflow. */
2374 *width = (*width + width_bias) & width_mask;
2375
2376 if (adjust_crop) {
2377 bttv_crop_adjust(c, b, *width, *height, field);
2378
2379 if (btv->vbi_end > c->rect.top) {
2380 /* Move the crop window out of the way. */
2381 c->rect.top = btv->vbi_end;
2382 }
2383 }
2384 } else {
2385 rc = -EINVAL;
2386 if (*width < min_width ||
2387 *height < min_height ||
2388 *width > max_width ||
2389 *height > max_height ||
2390 0 != (*width & ~width_mask))
2391 goto fail;
2392 }
2393
2394 rc = 0; /* success */
2395
2396 fail:
2397 mutex_unlock(&btv->lock);
2398
2399 return rc;
2400}
2401
2402/* Returns an error if the given overlay window dimensions are not
2403 possible with the current cropping parameters. If adjust_size is
2404 TRUE the function may adjust the window width and/or height
2405 instead, however it always rounds the horizontal position and
2406 width as btcx_align() does. If adjust_crop is TRUE the function
2407 may also adjust the current cropping parameters to get closer
2408 to the desired window size. */
2409static int
2410verify_window (struct bttv_fh * fh,
2411 struct v4l2_window * win,
2412 int adjust_size,
2413 int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414{
2415 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002416 unsigned int width_mask;
2417 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
2419 if (win->w.width < 48 || win->w.height < 32)
2420 return -EINVAL;
2421 if (win->clipcount > 2048)
2422 return -EINVAL;
2423
2424 field = win->field;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426 if (V4L2_FIELD_ANY == field) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03002427 __s32 height2;
2428
2429 height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
2430 field = (win->w.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 ? V4L2_FIELD_INTERLACED
2432 : V4L2_FIELD_TOP;
2433 }
2434 switch (field) {
2435 case V4L2_FIELD_TOP:
2436 case V4L2_FIELD_BOTTOM:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 case V4L2_FIELD_INTERLACED:
2438 break;
2439 default:
2440 return -EINVAL;
2441 }
2442
Michael Schimeke5bd0262007-01-18 16:17:39 -03002443 /* 4-byte alignment. */
2444 if (NULL == fh->ovfmt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002446 width_mask = ~0;
2447 switch (fh->ovfmt->depth) {
2448 case 8:
2449 case 24:
2450 width_mask = ~3;
2451 break;
2452 case 16:
2453 width_mask = ~1;
2454 break;
2455 case 32:
2456 break;
2457 default:
2458 BUG();
2459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Michael Schimeke5bd0262007-01-18 16:17:39 -03002461 win->w.width -= win->w.left & ~width_mask;
2462 win->w.left = (win->w.left - width_mask - 1) & width_mask;
2463
2464 rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
2465 field, width_mask,
2466 /* width_bias: round down */ 0,
2467 adjust_size, adjust_crop);
2468 if (0 != rc)
2469 return rc;
2470
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 win->field = field;
2472 return 0;
2473}
2474
2475static int setup_window(struct bttv_fh *fh, struct bttv *btv,
2476 struct v4l2_window *win, int fixup)
2477{
2478 struct v4l2_clip *clips = NULL;
2479 int n,size,retval = 0;
2480
2481 if (NULL == fh->ovfmt)
2482 return -EINVAL;
2483 if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
2484 return -EINVAL;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002485 retval = verify_window(fh, win,
2486 /* adjust_size */ fixup,
2487 /* adjust_crop */ fixup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 if (0 != retval)
2489 return retval;
2490
2491 /* copy clips -- luckily v4l1 + v4l2 are binary
2492 compatible here ...*/
2493 n = win->clipcount;
2494 size = sizeof(*clips)*(n+4);
2495 clips = kmalloc(size,GFP_KERNEL);
2496 if (NULL == clips)
2497 return -ENOMEM;
2498 if (n > 0) {
2499 if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
2500 kfree(clips);
2501 return -EFAULT;
2502 }
2503 }
2504 /* clip against screen */
2505 if (NULL != btv->fbuf.base)
2506 n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
2507 &win->w, clips, n);
2508 btcx_sort_clips(clips,n);
2509
2510 /* 4-byte alignments */
2511 switch (fh->ovfmt->depth) {
2512 case 8:
2513 case 24:
2514 btcx_align(&win->w, clips, n, 3);
2515 break;
2516 case 16:
2517 btcx_align(&win->w, clips, n, 1);
2518 break;
2519 case 32:
2520 /* no alignment fixups needed */
2521 break;
2522 default:
2523 BUG();
2524 }
2525
Ingo Molnar3593cab2006-02-07 06:49:14 -02002526 mutex_lock(&fh->cap.lock);
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08002527 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 fh->ov.clips = clips;
2529 fh->ov.nclips = n;
2530
2531 fh->ov.w = win->w;
2532 fh->ov.field = win->field;
2533 fh->ov.setup_ok = 1;
2534 btv->init.ov.w.width = win->w.width;
2535 btv->init.ov.w.height = win->w.height;
2536 btv->init.ov.field = win->field;
2537
2538 /* update overlay if needed */
2539 retval = 0;
2540 if (check_btres(fh, RESOURCE_OVERLAY)) {
2541 struct bttv_buffer *new;
2542
2543 new = videobuf_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03002544 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
2546 retval = bttv_switch_overlay(btv,fh,new);
2547 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02002548 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 return retval;
2550}
2551
2552/* ----------------------------------------------------------------------- */
2553
2554static struct videobuf_queue* bttv_queue(struct bttv_fh *fh)
2555{
2556 struct videobuf_queue* q = NULL;
2557
2558 switch (fh->type) {
2559 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2560 q = &fh->cap;
2561 break;
2562 case V4L2_BUF_TYPE_VBI_CAPTURE:
2563 q = &fh->vbi;
2564 break;
2565 default:
2566 BUG();
2567 }
2568 return q;
2569}
2570
2571static int bttv_resource(struct bttv_fh *fh)
2572{
2573 int res = 0;
2574
2575 switch (fh->type) {
2576 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002577 res = RESOURCE_VIDEO_STREAM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 break;
2579 case V4L2_BUF_TYPE_VBI_CAPTURE:
2580 res = RESOURCE_VBI;
2581 break;
2582 default:
2583 BUG();
2584 }
2585 return res;
2586}
2587
2588static int bttv_switch_type(struct bttv_fh *fh, enum v4l2_buf_type type)
2589{
2590 struct videobuf_queue *q = bttv_queue(fh);
2591 int res = bttv_resource(fh);
2592
2593 if (check_btres(fh,res))
2594 return -EBUSY;
2595 if (videobuf_queue_is_busy(q))
2596 return -EBUSY;
2597 fh->type = type;
2598 return 0;
2599}
2600
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002601static void
2602pix_format_set_size (struct v4l2_pix_format * f,
2603 const struct bttv_format * fmt,
2604 unsigned int width,
2605 unsigned int height)
2606{
2607 f->width = width;
2608 f->height = height;
2609
2610 if (fmt->flags & FORMAT_FLAGS_PLANAR) {
2611 f->bytesperline = width; /* Y plane */
2612 f->sizeimage = (width * height * fmt->depth) >> 3;
2613 } else {
2614 f->bytesperline = (width * fmt->depth) >> 3;
2615 f->sizeimage = height * f->bytesperline;
2616 }
2617}
2618
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
2620{
2621 switch (f->type) {
2622 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2623 memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format));
Michael H. Schimekc87c9482005-12-01 00:51:33 -08002624 pix_format_set_size (&f->fmt.pix, fh->fmt,
2625 fh->width, fh->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 f->fmt.pix.field = fh->cap.field;
2627 f->fmt.pix.pixelformat = fh->fmt->fourcc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 return 0;
2629 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
2630 memset(&f->fmt.win,0,sizeof(struct v4l2_window));
2631 f->fmt.win.w = fh->ov.w;
2632 f->fmt.win.field = fh->ov.field;
2633 return 0;
2634 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002635 bttv_vbi_get_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 return 0;
2637 default:
2638 return -EINVAL;
2639 }
2640}
2641
2642static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
Michael Schimeke5bd0262007-01-18 16:17:39 -03002643 struct v4l2_format *f, int adjust_crop)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644{
2645 switch (f->type) {
2646 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2647 {
2648 const struct bttv_format *fmt;
2649 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002650 __s32 width, height;
2651 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
2653 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2654 if (NULL == fmt)
2655 return -EINVAL;
2656
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 field = f->fmt.pix.field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002658 if (V4L2_FIELD_ANY == field) {
2659 __s32 height2;
2660
2661 height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
2662 field = (f->fmt.pix.height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 ? V4L2_FIELD_INTERLACED
2664 : V4L2_FIELD_BOTTOM;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 if (V4L2_FIELD_SEQ_BT == field)
2667 field = V4L2_FIELD_SEQ_TB;
2668 switch (field) {
2669 case V4L2_FIELD_TOP:
2670 case V4L2_FIELD_BOTTOM:
2671 case V4L2_FIELD_ALTERNATE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 case V4L2_FIELD_INTERLACED:
2673 break;
2674 case V4L2_FIELD_SEQ_TB:
2675 if (fmt->flags & FORMAT_FLAGS_PLANAR)
2676 return -EINVAL;
2677 break;
2678 default:
2679 return -EINVAL;
2680 }
2681
Michael Schimeke5bd0262007-01-18 16:17:39 -03002682 width = f->fmt.pix.width;
2683 height = f->fmt.pix.height;
2684
2685 rc = limit_scaled_size(fh, &width, &height, field,
2686 /* width_mask: 4 pixels */ ~3,
2687 /* width_bias: nearest */ 2,
2688 /* adjust_size */ 1,
2689 adjust_crop);
2690 if (0 != rc)
2691 return rc;
2692
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 /* update data for the application */
2694 f->fmt.pix.field = field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002695 pix_format_set_size(&f->fmt.pix, fmt, width, height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
2697 return 0;
2698 }
2699 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002700 return verify_window(fh, &f->fmt.win,
2701 /* adjust_size */ 1,
2702 /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 case V4L2_BUF_TYPE_VBI_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03002704 return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 default:
2706 return -EINVAL;
2707 }
2708}
2709
2710static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
2711 struct v4l2_format *f)
2712{
2713 int retval;
2714
2715 switch (f->type) {
2716 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
2717 {
2718 const struct bttv_format *fmt;
2719
2720 retval = bttv_switch_type(fh,f->type);
2721 if (0 != retval)
2722 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002723 retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 if (0 != retval)
2725 return retval;
2726 fmt = format_by_fourcc(f->fmt.pix.pixelformat);
2727
2728 /* update our state informations */
Ingo Molnar3593cab2006-02-07 06:49:14 -02002729 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 fh->fmt = fmt;
2731 fh->cap.field = f->fmt.pix.field;
2732 fh->cap.last = V4L2_FIELD_NONE;
2733 fh->width = f->fmt.pix.width;
2734 fh->height = f->fmt.pix.height;
2735 btv->init.fmt = fmt;
2736 btv->init.width = f->fmt.pix.width;
2737 btv->init.height = f->fmt.pix.height;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002738 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740 return 0;
2741 }
2742 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002743 if (no_overlay > 0) {
2744 printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
2745 return -EINVAL;
2746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 return setup_window(fh, btv, &f->fmt.win, 1);
2748 case V4L2_BUF_TYPE_VBI_CAPTURE:
2749 retval = bttv_switch_type(fh,f->type);
2750 if (0 != retval)
2751 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03002752 return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 default:
2754 return -EINVAL;
2755 }
2756}
2757
2758static int bttv_do_ioctl(struct inode *inode, struct file *file,
2759 unsigned int cmd, void *arg)
2760{
2761 struct bttv_fh *fh = file->private_data;
2762 struct bttv *btv = fh->btv;
2763 unsigned long flags;
2764 int retval = 0;
2765
Michael Krufky5e453dc2006-01-09 15:32:31 -02002766 if (bttv_debug > 1)
2767 v4l_print_ioctl(btv->c.name, cmd);
2768
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 if (btv->errors)
2770 bttv_reinit_bt848(btv);
2771
2772 switch (cmd) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002773 case VIDIOCSFREQ:
2774 case VIDIOCSTUNER:
2775 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 case VIDIOC_S_CTRL:
2777 case VIDIOC_S_STD:
2778 case VIDIOC_S_INPUT:
2779 case VIDIOC_S_TUNER:
2780 case VIDIOC_S_FREQUENCY:
2781 retval = v4l2_prio_check(&btv->prio,&fh->prio);
2782 if (0 != retval)
2783 return retval;
2784 };
2785
2786 switch (cmd) {
2787
2788 /* *** v4l1 *** ************************************************ */
2789 case VIDIOCGCAP:
2790 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002791 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792
2793 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002794 strcpy(cap->name,btv->video_dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
2796 /* vbi */
2797 cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT;
2798 } else {
2799 /* others */
2800 cap->type = VID_TYPE_CAPTURE|
2801 VID_TYPE_TUNER|
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 VID_TYPE_CLIPPING|
2803 VID_TYPE_SCALES;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002804 if (no_overlay <= 0)
2805 cap->type |= VID_TYPE_OVERLAY;
2806
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;
2808 cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;
2809 cap->minwidth = 48;
2810 cap->minheight = 32;
2811 }
2812 cap->channels = bttv_tvcards[btv->c.type].video_inputs;
2813 cap->audios = bttv_tvcards[btv->c.type].audio_inputs;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002814 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 }
2816
2817 case VIDIOCGPICT:
2818 {
2819 struct video_picture *pic = arg;
2820
2821 memset(pic,0,sizeof(*pic));
2822 pic->brightness = btv->bright;
2823 pic->contrast = btv->contrast;
2824 pic->hue = btv->hue;
2825 pic->colour = btv->saturation;
2826 if (fh->fmt) {
2827 pic->depth = fh->fmt->depth;
2828 pic->palette = fh->fmt->palette;
2829 }
2830 return 0;
2831 }
2832 case VIDIOCSPICT:
2833 {
2834 struct video_picture *pic = arg;
2835 const struct bttv_format *fmt;
2836
2837 fmt = format_by_palette(pic->palette);
2838 if (NULL == fmt)
2839 return -EINVAL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002840 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 if (fmt->depth != pic->depth) {
2842 retval = -EINVAL;
2843 goto fh_unlock_and_return;
2844 }
Michael H. Schimek13c72802005-12-01 00:51:37 -08002845 if (fmt->flags & FORMAT_FLAGS_RAW) {
2846 /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
2847 RAW_LINES * 2. F1 is stored at offset 0, F2
2848 at buffer size / 2. */
2849 fh->width = RAW_BPL;
2850 fh->height = gbufsize / RAW_BPL;
2851 btv->init.width = RAW_BPL;
2852 btv->init.height = gbufsize / RAW_BPL;
2853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 fh->ovfmt = fmt;
2855 fh->fmt = fmt;
2856 btv->init.ovfmt = fmt;
2857 btv->init.fmt = fmt;
2858 if (bigendian) {
2859 /* dirty hack time: swap bytes for overlay if the
2860 display adaptor is big endian (insmod option) */
2861 if (fmt->palette == VIDEO_PALETTE_RGB555 ||
2862 fmt->palette == VIDEO_PALETTE_RGB565 ||
2863 fmt->palette == VIDEO_PALETTE_RGB32) {
2864 fh->ovfmt = fmt+1;
2865 }
2866 }
2867 bt848_bright(btv,pic->brightness);
2868 bt848_contrast(btv,pic->contrast);
2869 bt848_hue(btv,pic->hue);
2870 bt848_sat(btv,pic->colour);
Ingo Molnar3593cab2006-02-07 06:49:14 -02002871 mutex_unlock(&fh->cap.lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002872 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 }
2874
2875 case VIDIOCGWIN:
2876 {
2877 struct video_window *win = arg;
2878
2879 memset(win,0,sizeof(*win));
2880 win->x = fh->ov.w.left;
2881 win->y = fh->ov.w.top;
2882 win->width = fh->ov.w.width;
2883 win->height = fh->ov.w.height;
2884 return 0;
2885 }
2886 case VIDIOCSWIN:
2887 {
2888 struct video_window *win = arg;
2889 struct v4l2_window w2;
2890
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07002891 if (no_overlay > 0) {
2892 printk ("VIDIOCSWIN: no_overlay\n");
2893 return -EINVAL;
2894 }
2895
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 w2.field = V4L2_FIELD_ANY;
2897 w2.w.left = win->x;
2898 w2.w.top = win->y;
2899 w2.w.width = win->width;
2900 w2.w.height = win->height;
2901 w2.clipcount = win->clipcount;
2902 w2.clips = (struct v4l2_clip __user *)win->clips;
2903 retval = setup_window(fh, btv, &w2, 0);
2904 if (0 == retval) {
2905 /* on v4l1 this ioctl affects the read() size too */
2906 fh->width = fh->ov.w.width;
2907 fh->height = fh->ov.w.height;
2908 btv->init.width = fh->ov.w.width;
2909 btv->init.height = fh->ov.w.height;
2910 }
2911 return retval;
2912 }
2913
2914 case VIDIOCGFBUF:
2915 {
2916 struct video_buffer *fbuf = arg;
2917
2918 fbuf->base = btv->fbuf.base;
2919 fbuf->width = btv->fbuf.fmt.width;
2920 fbuf->height = btv->fbuf.fmt.height;
2921 fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
2922 if (fh->ovfmt)
2923 fbuf->depth = fh->ovfmt->depth;
Mauro Carvalho Chehab37026272006-08-06 09:10:06 -03002924 else {
2925 if (fbuf->width)
2926 fbuf->depth = ((fbuf->bytesperline<<3)
Trent Piephoa2b9e3e2006-08-07 20:01:01 -03002927 + (fbuf->width-1) )
2928 /fbuf->width;
Mauro Carvalho Chehab37026272006-08-06 09:10:06 -03002929 else
2930 fbuf->depth = 0;
2931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 return 0;
2933 }
2934 case VIDIOCSFBUF:
2935 {
2936 struct video_buffer *fbuf = arg;
2937 const struct bttv_format *fmt;
2938 unsigned long end;
2939
2940 if(!capable(CAP_SYS_ADMIN) &&
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08002941 !capable(CAP_SYS_RAWIO))
2942 return -EPERM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 end = (unsigned long)fbuf->base +
2944 fbuf->height * fbuf->bytesperline;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002945 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 retval = -EINVAL;
2947
2948 switch (fbuf->depth) {
2949 case 8:
2950 fmt = format_by_palette(VIDEO_PALETTE_HI240);
2951 break;
2952 case 16:
2953 fmt = format_by_palette(VIDEO_PALETTE_RGB565);
2954 break;
2955 case 24:
2956 fmt = format_by_palette(VIDEO_PALETTE_RGB24);
2957 break;
2958 case 32:
2959 fmt = format_by_palette(VIDEO_PALETTE_RGB32);
2960 break;
2961 case 15:
2962 fbuf->depth = 16;
2963 fmt = format_by_palette(VIDEO_PALETTE_RGB555);
2964 break;
2965 default:
2966 fmt = NULL;
2967 break;
2968 }
2969 if (NULL == fmt)
2970 goto fh_unlock_and_return;
2971
2972 fh->ovfmt = fmt;
2973 fh->fmt = fmt;
2974 btv->init.ovfmt = fmt;
2975 btv->init.fmt = fmt;
2976 btv->fbuf.base = fbuf->base;
2977 btv->fbuf.fmt.width = fbuf->width;
2978 btv->fbuf.fmt.height = fbuf->height;
2979 if (fbuf->bytesperline)
2980 btv->fbuf.fmt.bytesperline = fbuf->bytesperline;
2981 else
2982 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8;
Ingo Molnar3593cab2006-02-07 06:49:14 -02002983 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 return 0;
2985 }
2986
2987 case VIDIOCCAPTURE:
2988 case VIDIOC_OVERLAY:
2989 {
2990 struct bttv_buffer *new;
2991 int *on = arg;
2992
2993 if (*on) {
2994 /* verify args */
2995 if (NULL == btv->fbuf.base)
2996 return -EINVAL;
2997 if (!fh->ov.setup_ok) {
2998 dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr);
2999 return -EINVAL;
3000 }
3001 }
3002
3003 if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))
3004 return -EBUSY;
3005
Ingo Molnar3593cab2006-02-07 06:49:14 -02003006 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 if (*on) {
3008 fh->ov.tvnorm = btv->tvnorm;
3009 new = videobuf_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03003010 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
3012 } else {
3013 new = NULL;
3014 }
3015
3016 /* switch over */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003017 retval = bttv_switch_overlay(btv,fh,new);
Ingo Molnar3593cab2006-02-07 06:49:14 -02003018 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 return retval;
3020 }
3021
3022 case VIDIOCGMBUF:
3023 {
3024 struct video_mbuf *mbuf = arg;
3025 unsigned int i;
3026
Ingo Molnar3593cab2006-02-07 06:49:14 -02003027 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize,
3029 V4L2_MEMORY_MMAP);
3030 if (retval < 0)
3031 goto fh_unlock_and_return;
3032 memset(mbuf,0,sizeof(*mbuf));
3033 mbuf->frames = gbuffers;
3034 mbuf->size = gbuffers * gbufsize;
3035 for (i = 0; i < gbuffers; i++)
3036 mbuf->offsets[i] = i * gbufsize;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003037 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 return 0;
3039 }
3040 case VIDIOCMCAPTURE:
3041 {
3042 struct video_mmap *vm = arg;
3043 struct bttv_buffer *buf;
3044 enum v4l2_field field;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003045 __s32 height2;
3046 int res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047
3048 if (vm->frame >= VIDEO_MAX_FRAME)
3049 return -EINVAL;
3050
Michael Schimeke5bd0262007-01-18 16:17:39 -03003051 res = bttv_resource(fh);
3052 if (!check_alloc_btres(btv, fh, res))
3053 return -EBUSY;
3054
Ingo Molnar3593cab2006-02-07 06:49:14 -02003055 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 retval = -EINVAL;
3057 buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
3058 if (NULL == buf)
3059 goto fh_unlock_and_return;
3060 if (0 == buf->vb.baddr)
3061 goto fh_unlock_and_return;
3062 if (buf->vb.state == STATE_QUEUED ||
3063 buf->vb.state == STATE_ACTIVE)
3064 goto fh_unlock_and_return;
3065
Michael Schimeke5bd0262007-01-18 16:17:39 -03003066 height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
3067 field = (vm->height > height2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 ? V4L2_FIELD_INTERLACED
3069 : V4L2_FIELD_BOTTOM;
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03003070 retval = bttv_prepare_buffer(&fh->cap,btv,buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 format_by_palette(vm->format),
3072 vm->width,vm->height,field);
3073 if (0 != retval)
3074 goto fh_unlock_and_return;
3075 spin_lock_irqsave(&btv->s_lock,flags);
3076 buffer_queue(&fh->cap,&buf->vb);
3077 spin_unlock_irqrestore(&btv->s_lock,flags);
Ingo Molnar3593cab2006-02-07 06:49:14 -02003078 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 return 0;
3080 }
3081 case VIDIOCSYNC:
3082 {
3083 int *frame = arg;
3084 struct bttv_buffer *buf;
3085
3086 if (*frame >= VIDEO_MAX_FRAME)
3087 return -EINVAL;
3088
Ingo Molnar3593cab2006-02-07 06:49:14 -02003089 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 retval = -EINVAL;
3091 buf = (struct bttv_buffer *)fh->cap.bufs[*frame];
3092 if (NULL == buf)
3093 goto fh_unlock_and_return;
3094 retval = videobuf_waiton(&buf->vb,0,1);
3095 if (0 != retval)
3096 goto fh_unlock_and_return;
3097 switch (buf->vb.state) {
3098 case STATE_ERROR:
3099 retval = -EIO;
3100 /* fall through */
3101 case STATE_DONE:
Mauro Carvalho Chehabc7b0ac02006-03-10 12:29:15 -03003102 videobuf_dma_sync(&fh->cap,&buf->vb.dma);
3103 bttv_dma_free(&fh->cap,btv,buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 break;
3105 default:
3106 retval = -EINVAL;
3107 break;
3108 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003109 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 return retval;
3111 }
3112
3113 case VIDIOCGVBIFMT:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
3115 retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
3116 if (0 != retval)
3117 return retval;
3118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
Michael Schimeke5bd0262007-01-18 16:17:39 -03003120 /* fall through */
3121
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 case VIDIOCSVBIFMT:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003123 return v4l_compat_translate_ioctl(inode, file, cmd,
3124 arg, bttv_do_ioctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003126 case BTTV_VERSION:
3127 case VIDIOCGFREQ:
3128 case VIDIOCSFREQ:
3129 case VIDIOCGTUNER:
3130 case VIDIOCSTUNER:
3131 case VIDIOCGCHAN:
3132 case VIDIOCSCHAN:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 case VIDIOCGAUDIO:
3134 case VIDIOCSAUDIO:
3135 return bttv_common_ioctls(btv,cmd,arg);
3136
3137 /* *** v4l2 *** ************************************************ */
3138 case VIDIOC_QUERYCAP:
3139 {
3140 struct v4l2_capability *cap = arg;
3141
3142 if (0 == v4l2)
3143 return -EINVAL;
Michael H. Schimekbbf78712005-12-01 00:51:40 -08003144 memset(cap, 0, sizeof (*cap));
3145 strlcpy(cap->driver, "bttv", sizeof (cap->driver));
3146 strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card));
3147 snprintf(cap->bus_info, sizeof (cap->bus_info),
3148 "PCI:%s", pci_name(btv->c.pci));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 cap->version = BTTV_VERSION_CODE;
3150 cap->capabilities =
3151 V4L2_CAP_VIDEO_CAPTURE |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 V4L2_CAP_VBI_CAPTURE |
3153 V4L2_CAP_READWRITE |
3154 V4L2_CAP_STREAMING;
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003155 if (no_overlay <= 0)
3156 cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
3157
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 if (bttv_tvcards[btv->c.type].tuner != UNSET &&
3159 bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT)
3160 cap->capabilities |= V4L2_CAP_TUNER;
3161 return 0;
3162 }
3163
3164 case VIDIOC_ENUM_FMT:
3165 {
3166 struct v4l2_fmtdesc *f = arg;
3167 enum v4l2_buf_type type;
3168 unsigned int i;
3169 int index;
3170
3171 type = f->type;
3172 if (V4L2_BUF_TYPE_VBI_CAPTURE == type) {
3173 /* vbi */
3174 index = f->index;
3175 if (0 != index)
3176 return -EINVAL;
3177 memset(f,0,sizeof(*f));
3178 f->index = index;
3179 f->type = type;
3180 f->pixelformat = V4L2_PIX_FMT_GREY;
3181 strcpy(f->description,"vbi data");
3182 return 0;
3183 }
3184
3185 /* video capture + overlay */
3186 index = -1;
3187 for (i = 0; i < BTTV_FORMATS; i++) {
3188 if (bttv_formats[i].fourcc != -1)
3189 index++;
3190 if ((unsigned int)index == f->index)
3191 break;
3192 }
3193 if (BTTV_FORMATS == i)
3194 return -EINVAL;
3195
3196 switch (f->type) {
3197 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
3198 break;
3199 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
3200 if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED))
3201 return -EINVAL;
3202 break;
3203 default:
3204 return -EINVAL;
3205 }
3206 memset(f,0,sizeof(*f));
3207 f->index = index;
3208 f->type = type;
3209 f->pixelformat = bttv_formats[i].fourcc;
3210 strlcpy(f->description,bttv_formats[i].name,sizeof(f->description));
3211 return 0;
3212 }
3213
3214 case VIDIOC_TRY_FMT:
3215 {
3216 struct v4l2_format *f = arg;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003217 return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 }
3219 case VIDIOC_G_FMT:
3220 {
3221 struct v4l2_format *f = arg;
3222 return bttv_g_fmt(fh,f);
3223 }
3224 case VIDIOC_S_FMT:
3225 {
3226 struct v4l2_format *f = arg;
3227 return bttv_s_fmt(fh,btv,f);
3228 }
3229
3230 case VIDIOC_G_FBUF:
3231 {
3232 struct v4l2_framebuffer *fb = arg;
3233
3234 *fb = btv->fbuf;
3235 fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
3236 if (fh->ovfmt)
3237 fb->fmt.pixelformat = fh->ovfmt->fourcc;
3238 return 0;
3239 }
3240 case VIDIOC_S_FBUF:
3241 {
3242 struct v4l2_framebuffer *fb = arg;
3243 const struct bttv_format *fmt;
3244
3245 if(!capable(CAP_SYS_ADMIN) &&
3246 !capable(CAP_SYS_RAWIO))
3247 return -EPERM;
3248
3249 /* check args */
3250 fmt = format_by_fourcc(fb->fmt.pixelformat);
3251 if (NULL == fmt)
3252 return -EINVAL;
3253 if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
3254 return -EINVAL;
3255
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 retval = -EINVAL;
3257 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
Michael Schimeke5bd0262007-01-18 16:17:39 -03003258 __s32 width = fb->fmt.width;
3259 __s32 height = fb->fmt.height;
3260
3261 retval = limit_scaled_size(fh, &width, &height,
3262 V4L2_FIELD_INTERLACED,
3263 /* width_mask */ ~3,
3264 /* width_bias */ 2,
3265 /* adjust_size */ 0,
3266 /* adjust_crop */ 0);
3267 if (0 != retval)
3268 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 }
3270
3271 /* ok, accept it */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003272 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 btv->fbuf.base = fb->base;
3274 btv->fbuf.fmt.width = fb->fmt.width;
3275 btv->fbuf.fmt.height = fb->fmt.height;
3276 if (0 != fb->fmt.bytesperline)
3277 btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline;
3278 else
3279 btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8;
3280
3281 retval = 0;
3282 fh->ovfmt = fmt;
3283 btv->init.ovfmt = fmt;
3284 if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
3285 fh->ov.w.left = 0;
3286 fh->ov.w.top = 0;
3287 fh->ov.w.width = fb->fmt.width;
3288 fh->ov.w.height = fb->fmt.height;
3289 btv->init.ov.w.width = fb->fmt.width;
3290 btv->init.ov.w.height = fb->fmt.height;
Mauro Carvalho Chehab674434c2005-12-12 00:37:28 -08003291 kfree(fh->ov.clips);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 fh->ov.clips = NULL;
3293 fh->ov.nclips = 0;
3294
3295 if (check_btres(fh, RESOURCE_OVERLAY)) {
3296 struct bttv_buffer *new;
3297
3298 new = videobuf_alloc(sizeof(*new));
Michael Schimeke5bd0262007-01-18 16:17:39 -03003299 new->crop = btv->crop[!!fh->do_crop].rect;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300 bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
3301 retval = bttv_switch_overlay(btv,fh,new);
3302 }
3303 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003304 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 return retval;
3306 }
3307
3308 case VIDIOC_REQBUFS:
3309 return videobuf_reqbufs(bttv_queue(fh),arg);
3310
3311 case VIDIOC_QUERYBUF:
3312 return videobuf_querybuf(bttv_queue(fh),arg);
3313
3314 case VIDIOC_QBUF:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003315 {
3316 int res = bttv_resource(fh);
3317
3318 if (!check_alloc_btres(btv, fh, res))
3319 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 return videobuf_qbuf(bttv_queue(fh),arg);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322
3323 case VIDIOC_DQBUF:
3324 return videobuf_dqbuf(bttv_queue(fh),arg,
3325 file->f_flags & O_NONBLOCK);
3326
3327 case VIDIOC_STREAMON:
3328 {
3329 int res = bttv_resource(fh);
3330
3331 if (!check_alloc_btres(btv,fh,res))
3332 return -EBUSY;
3333 return videobuf_streamon(bttv_queue(fh));
3334 }
3335 case VIDIOC_STREAMOFF:
3336 {
3337 int res = bttv_resource(fh);
3338
3339 retval = videobuf_streamoff(bttv_queue(fh));
3340 if (retval < 0)
3341 return retval;
3342 free_btres(btv,fh,res);
3343 return 0;
3344 }
3345
3346 case VIDIOC_QUERYCTRL:
3347 {
3348 struct v4l2_queryctrl *c = arg;
3349 int i;
3350
3351 if ((c->id < V4L2_CID_BASE ||
3352 c->id >= V4L2_CID_LASTP1) &&
3353 (c->id < V4L2_CID_PRIVATE_BASE ||
3354 c->id >= V4L2_CID_PRIVATE_LASTP1))
3355 return -EINVAL;
3356 for (i = 0; i < BTTV_CTLS; i++)
3357 if (bttv_ctls[i].id == c->id)
3358 break;
3359 if (i == BTTV_CTLS) {
3360 *c = no_ctl;
3361 return 0;
3362 }
3363 *c = bttv_ctls[i];
Hans Verkuil0020d3e2006-03-30 19:50:34 -03003364 if (btv->audio_hook && i >= 4 && i <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 struct video_audio va;
3366 memset(&va,0,sizeof(va));
Hans Verkuil0020d3e2006-03-30 19:50:34 -03003367 btv->audio_hook(btv,&va,0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 switch (bttv_ctls[i].id) {
3369 case V4L2_CID_AUDIO_VOLUME:
3370 if (!(va.flags & VIDEO_AUDIO_VOLUME))
3371 *c = no_ctl;
3372 break;
3373 case V4L2_CID_AUDIO_BALANCE:
3374 if (!(va.flags & VIDEO_AUDIO_BALANCE))
3375 *c = no_ctl;
3376 break;
3377 case V4L2_CID_AUDIO_BASS:
3378 if (!(va.flags & VIDEO_AUDIO_BASS))
3379 *c = no_ctl;
3380 break;
3381 case V4L2_CID_AUDIO_TREBLE:
3382 if (!(va.flags & VIDEO_AUDIO_TREBLE))
3383 *c = no_ctl;
3384 break;
3385 }
3386 }
3387 return 0;
3388 }
3389 case VIDIOC_G_CTRL:
3390 return get_control(btv,arg);
3391 case VIDIOC_S_CTRL:
3392 return set_control(btv,arg);
3393 case VIDIOC_G_PARM:
3394 {
3395 struct v4l2_streamparm *parm = arg;
3396 struct v4l2_standard s;
3397 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
3398 return -EINVAL;
3399 memset(parm,0,sizeof(*parm));
3400 v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id,
3401 bttv_tvnorms[btv->tvnorm].name);
3402 parm->parm.capture.timeperframe = s.frameperiod;
3403 return 0;
3404 }
3405
3406 case VIDIOC_G_PRIORITY:
3407 {
3408 enum v4l2_priority *p = arg;
3409
3410 *p = v4l2_prio_max(&btv->prio);
3411 return 0;
3412 }
3413 case VIDIOC_S_PRIORITY:
3414 {
3415 enum v4l2_priority *prio = arg;
3416
3417 return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
3418 }
3419
Michael Schimeke5bd0262007-01-18 16:17:39 -03003420 case VIDIOC_CROPCAP:
3421 {
3422 struct v4l2_cropcap *cap = arg;
3423 enum v4l2_buf_type type;
3424
3425 type = cap->type;
3426
3427 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3428 type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3429 return -EINVAL;
3430
3431 *cap = bttv_tvnorms[btv->tvnorm].cropcap;
3432 cap->type = type;
3433
3434 return 0;
3435 }
3436 case VIDIOC_G_CROP:
3437 {
3438 struct v4l2_crop * crop = arg;
3439
3440 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3441 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3442 return -EINVAL;
3443
3444 /* No fh->do_crop = 1; because btv->crop[1] may be
3445 inconsistent with fh->width or fh->height and apps
3446 do not expect a change here. */
3447
3448 crop->c = btv->crop[!!fh->do_crop].rect;
3449
3450 return 0;
3451 }
3452 case VIDIOC_S_CROP:
3453 {
3454 struct v4l2_crop *crop = arg;
3455 const struct v4l2_rect *b;
3456 struct bttv_crop c;
3457 __s32 b_left;
3458 __s32 b_top;
3459 __s32 b_right;
3460 __s32 b_bottom;
3461
3462 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
3463 crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
3464 return -EINVAL;
3465
3466 retval = v4l2_prio_check(&btv->prio,&fh->prio);
3467 if (0 != retval)
3468 return retval;
3469
3470 /* Make sure tvnorm, vbi_end and the current cropping
3471 parameters remain consistent until we're done. Note
3472 read() may change vbi_end in check_alloc_btres(). */
3473 mutex_lock(&btv->lock);
3474
3475 retval = -EBUSY;
3476
3477 if (locked_btres(fh->btv, VIDEO_RESOURCES))
3478 goto btv_unlock_and_return;
3479
3480 b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
3481
3482 b_left = b->left;
3483 b_right = b_left + b->width;
3484 b_bottom = b->top + b->height;
3485
3486 b_top = max(b->top, btv->vbi_end);
3487 if (b_top + 32 >= b_bottom)
3488 goto btv_unlock_and_return;
3489
3490 /* Min. scaled size 48 x 32. */
3491 c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
3492 c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
3493
3494 c.rect.width = clamp(crop->c.width,
3495 48, b_right - c.rect.left);
3496
3497 c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
3498 /* Top and height must be a multiple of two. */
3499 c.rect.top = (c.rect.top + 1) & ~1;
3500
3501 c.rect.height = clamp(crop->c.height,
3502 32, b_bottom - c.rect.top);
3503 c.rect.height = (c.rect.height + 1) & ~1;
3504
3505 bttv_crop_calc_limits(&c);
3506
3507 btv->crop[1] = c;
3508
3509 mutex_unlock(&btv->lock);
3510
3511 fh->do_crop = 1;
3512
3513 mutex_lock(&fh->cap.lock);
3514
3515 if (fh->width < c.min_scaled_width) {
3516 fh->width = c.min_scaled_width;
3517 btv->init.width = c.min_scaled_width;
3518 } else if (fh->width > c.max_scaled_width) {
3519 fh->width = c.max_scaled_width;
3520 btv->init.width = c.max_scaled_width;
3521 }
3522
3523 if (fh->height < c.min_scaled_height) {
3524 fh->height = c.min_scaled_height;
3525 btv->init.height = c.min_scaled_height;
3526 } else if (fh->height > c.max_scaled_height) {
3527 fh->height = c.max_scaled_height;
3528 btv->init.height = c.max_scaled_height;
3529 }
3530
3531 mutex_unlock(&fh->cap.lock);
3532
3533 return 0;
3534 }
3535
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 case VIDIOC_ENUMSTD:
3537 case VIDIOC_G_STD:
3538 case VIDIOC_S_STD:
3539 case VIDIOC_ENUMINPUT:
3540 case VIDIOC_G_INPUT:
3541 case VIDIOC_S_INPUT:
3542 case VIDIOC_G_TUNER:
3543 case VIDIOC_S_TUNER:
3544 case VIDIOC_G_FREQUENCY:
3545 case VIDIOC_S_FREQUENCY:
Hans Verkuil299392b2005-11-08 21:37:42 -08003546 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 return bttv_common_ioctls(btv,cmd,arg);
3548
3549 default:
3550 return -ENOIOCTLCMD;
3551 }
3552 return 0;
3553
3554 fh_unlock_and_return:
Ingo Molnar3593cab2006-02-07 06:49:14 -02003555 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 return retval;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003557
3558 btv_unlock_and_return:
3559 mutex_unlock(&btv->lock);
3560 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561}
3562
3563static int bttv_ioctl(struct inode *inode, struct file *file,
3564 unsigned int cmd, unsigned long arg)
3565{
3566 struct bttv_fh *fh = file->private_data;
3567
3568 switch (cmd) {
3569 case BTTV_VBISIZE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003570 {
3571 const struct bttv_tvnorm *tvnorm;
3572
3573 tvnorm = fh->vbi_fmt.tvnorm;
3574
3575 if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
3576 fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
3577 fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
3578 /* BTTV_VBISIZE cannot express these parameters,
3579 however open() resets the paramters to defaults
3580 and apps shouldn't call BTTV_VBISIZE after
3581 VIDIOC_S_FMT. */
3582 return -EINVAL;
3583 }
3584
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003586 return (fh->vbi_fmt.fmt.count[0] * 2
3587 * fh->vbi_fmt.fmt.samples_per_line);
3588 }
3589
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 default:
3591 return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
3592 }
3593}
3594
3595static ssize_t bttv_read(struct file *file, char __user *data,
3596 size_t count, loff_t *ppos)
3597{
3598 struct bttv_fh *fh = file->private_data;
3599 int retval = 0;
3600
3601 if (fh->btv->errors)
3602 bttv_reinit_bt848(fh->btv);
3603 dprintk("bttv%d: read count=%d type=%s\n",
3604 fh->btv->c.nr,(int)count,v4l2_type_names[fh->type]);
3605
3606 switch (fh->type) {
3607 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Michael Schimeke5bd0262007-01-18 16:17:39 -03003608 if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
3609 /* VIDEO_READ in use by another fh,
3610 or VIDEO_STREAM by any fh. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 return -EBUSY;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 retval = videobuf_read_one(&fh->cap, data, count, ppos,
3614 file->f_flags & O_NONBLOCK);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003615 free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 break;
3617 case V4L2_BUF_TYPE_VBI_CAPTURE:
3618 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3619 return -EBUSY;
3620 retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
3621 file->f_flags & O_NONBLOCK);
3622 break;
3623 default:
3624 BUG();
3625 }
3626 return retval;
3627}
3628
3629static unsigned int bttv_poll(struct file *file, poll_table *wait)
3630{
3631 struct bttv_fh *fh = file->private_data;
3632 struct bttv_buffer *buf;
3633 enum v4l2_field field;
3634
3635 if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
3636 if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
3637 return POLLERR;
3638 return videobuf_poll_stream(file, &fh->vbi, wait);
3639 }
3640
Michael Schimeke5bd0262007-01-18 16:17:39 -03003641 if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 /* streaming capture */
3643 if (list_empty(&fh->cap.stream))
3644 return POLLERR;
3645 buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
3646 } else {
3647 /* read() capture */
Ingo Molnar3593cab2006-02-07 06:49:14 -02003648 mutex_lock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 if (NULL == fh->cap.read_buf) {
3650 /* need to capture a new frame */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003651 if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003652 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 return POLLERR;
3654 }
3655 fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
3656 if (NULL == fh->cap.read_buf) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02003657 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 return POLLERR;
3659 }
3660 fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
3661 field = videobuf_next_field(&fh->cap);
3662 if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) {
Nickolay V. Shmyrev50ab5ed2005-12-01 00:51:32 -08003663 kfree (fh->cap.read_buf);
3664 fh->cap.read_buf = NULL;
Ingo Molnar3593cab2006-02-07 06:49:14 -02003665 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 return POLLERR;
3667 }
3668 fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
3669 fh->cap.read_off = 0;
3670 }
Ingo Molnar3593cab2006-02-07 06:49:14 -02003671 mutex_unlock(&fh->cap.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 buf = (struct bttv_buffer*)fh->cap.read_buf;
3673 }
3674
3675 poll_wait(file, &buf->vb.done, wait);
3676 if (buf->vb.state == STATE_DONE ||
3677 buf->vb.state == STATE_ERROR)
3678 return POLLIN|POLLRDNORM;
3679 return 0;
3680}
3681
3682static int bttv_open(struct inode *inode, struct file *file)
3683{
3684 int minor = iminor(inode);
3685 struct bttv *btv = NULL;
3686 struct bttv_fh *fh;
3687 enum v4l2_buf_type type = 0;
3688 unsigned int i;
3689
3690 dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor);
3691
3692 for (i = 0; i < bttv_num; i++) {
3693 if (bttvs[i].video_dev &&
3694 bttvs[i].video_dev->minor == minor) {
3695 btv = &bttvs[i];
3696 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3697 break;
3698 }
3699 if (bttvs[i].vbi_dev &&
3700 bttvs[i].vbi_dev->minor == minor) {
3701 btv = &bttvs[i];
3702 type = V4L2_BUF_TYPE_VBI_CAPTURE;
3703 break;
3704 }
3705 }
3706 if (NULL == btv)
3707 return -ENODEV;
3708
3709 dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
3710 btv->c.nr,v4l2_type_names[type]);
3711
3712 /* allocate per filehandle data */
3713 fh = kmalloc(sizeof(*fh),GFP_KERNEL);
3714 if (NULL == fh)
3715 return -ENOMEM;
3716 file->private_data = fh;
3717 *fh = btv->init;
3718 fh->type = type;
3719 fh->ov.setup_ok = 0;
3720 v4l2_prio_open(&btv->prio,&fh->prio);
3721
3722 videobuf_queue_init(&fh->cap, &bttv_video_qops,
3723 btv->c.pci, &btv->s_lock,
3724 V4L2_BUF_TYPE_VIDEO_CAPTURE,
3725 V4L2_FIELD_INTERLACED,
3726 sizeof(struct bttv_buffer),
3727 fh);
3728 videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
3729 btv->c.pci, &btv->s_lock,
3730 V4L2_BUF_TYPE_VBI_CAPTURE,
3731 V4L2_FIELD_SEQ_TB,
3732 sizeof(struct bttv_buffer),
3733 fh);
3734 i2c_vidiocschan(btv);
3735
3736 btv->users++;
Michael Schimeke5bd0262007-01-18 16:17:39 -03003737
3738 /* The V4L2 spec requires one global set of cropping parameters
3739 which only change on request. These are stored in btv->crop[1].
3740 However for compatibility with V4L apps and cropping unaware
3741 V4L2 apps we now reset the cropping parameters as seen through
3742 this fh, which is to say VIDIOC_G_CROP and scaling limit checks
3743 will use btv->crop[0], the default cropping parameters for the
3744 current video standard, and VIDIOC_S_FMT will not implicitely
3745 change the cropping parameters until VIDIOC_S_CROP has been
3746 called. */
3747 fh->do_crop = !reset_crop; /* module parameter */
3748
3749 /* Likewise there should be one global set of VBI capture
3750 parameters, but for compatibility with V4L apps and earlier
3751 driver versions each fh has its own parameters. */
3752 bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
3753
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 bttv_field_count(btv);
3755 return 0;
3756}
3757
3758static int bttv_release(struct inode *inode, struct file *file)
3759{
3760 struct bttv_fh *fh = file->private_data;
3761 struct bttv *btv = fh->btv;
3762
3763 /* turn off overlay */
3764 if (check_btres(fh, RESOURCE_OVERLAY))
3765 bttv_switch_overlay(btv,fh,NULL);
3766
3767 /* stop video capture */
Michael Schimeke5bd0262007-01-18 16:17:39 -03003768 if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 videobuf_streamoff(&fh->cap);
Michael Schimeke5bd0262007-01-18 16:17:39 -03003770 free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 }
3772 if (fh->cap.read_buf) {
3773 buffer_release(&fh->cap,fh->cap.read_buf);
3774 kfree(fh->cap.read_buf);
3775 }
Michael Schimeke5bd0262007-01-18 16:17:39 -03003776 if (check_btres(fh, RESOURCE_VIDEO_READ)) {
3777 free_btres(btv, fh, RESOURCE_VIDEO_READ);
3778 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
3780 /* stop vbi capture */
3781 if (check_btres(fh, RESOURCE_VBI)) {
3782 if (fh->vbi.streaming)
3783 videobuf_streamoff(&fh->vbi);
3784 if (fh->vbi.reading)
3785 videobuf_read_stop(&fh->vbi);
3786 free_btres(btv,fh,RESOURCE_VBI);
3787 }
3788
3789 /* free stuff */
3790 videobuf_mmap_free(&fh->cap);
3791 videobuf_mmap_free(&fh->vbi);
3792 v4l2_prio_close(&btv->prio,&fh->prio);
3793 file->private_data = NULL;
3794 kfree(fh);
3795
3796 btv->users--;
3797 bttv_field_count(btv);
3798 return 0;
3799}
3800
3801static int
3802bttv_mmap(struct file *file, struct vm_area_struct *vma)
3803{
3804 struct bttv_fh *fh = file->private_data;
3805
3806 dprintk("bttv%d: mmap type=%s 0x%lx+%ld\n",
3807 fh->btv->c.nr, v4l2_type_names[fh->type],
3808 vma->vm_start, vma->vm_end - vma->vm_start);
3809 return videobuf_mmap_mapper(bttv_queue(fh),vma);
3810}
3811
Arjan van de Venfa027c22007-02-12 00:55:33 -08003812static const struct file_operations bttv_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813{
3814 .owner = THIS_MODULE,
3815 .open = bttv_open,
3816 .release = bttv_release,
3817 .ioctl = bttv_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02003818 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 .llseek = no_llseek,
3820 .read = bttv_read,
3821 .mmap = bttv_mmap,
3822 .poll = bttv_poll,
3823};
3824
3825static struct video_device bttv_video_template =
3826{
3827 .name = "UNSET",
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07003828 .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003829 VID_TYPE_CLIPPING|VID_TYPE_SCALES,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 .hardware = VID_HARDWARE_BT848,
3831 .fops = &bttv_fops,
3832 .minor = -1,
3833};
3834
3835static struct video_device bttv_vbi_template =
3836{
3837 .name = "bt848/878 vbi",
3838 .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
3839 .hardware = VID_HARDWARE_BT848,
3840 .fops = &bttv_fops,
3841 .minor = -1,
3842};
3843
3844/* ----------------------------------------------------------------------- */
3845/* radio interface */
3846
3847static int radio_open(struct inode *inode, struct file *file)
3848{
3849 int minor = iminor(inode);
3850 struct bttv *btv = NULL;
3851 unsigned int i;
3852
3853 dprintk("bttv: open minor=%d\n",minor);
3854
3855 for (i = 0; i < bttv_num; i++) {
3856 if (bttvs[i].radio_dev->minor == minor) {
3857 btv = &bttvs[i];
3858 break;
3859 }
3860 }
3861 if (NULL == btv)
3862 return -ENODEV;
3863
3864 dprintk("bttv%d: open called (radio)\n",btv->c.nr);
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003865 mutex_lock(&btv->lock);
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003866
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 btv->radio_user++;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003868
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 file->private_data = btv;
3870
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03003871 bttv_call_i2c_clients(btv,AUDC_SET_RADIO,NULL);
3872 audio_input(btv,TVAUDIO_INPUT_RADIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02003874 mutex_unlock(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003875 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876}
3877
3878static int radio_release(struct inode *inode, struct file *file)
3879{
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003880 struct bttv *btv = file->private_data;
3881 struct rds_command cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882
3883 btv->radio_user--;
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003884
3885 bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
3886
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 return 0;
3888}
3889
3890static int radio_do_ioctl(struct inode *inode, struct file *file,
3891 unsigned int cmd, void *arg)
3892{
3893 struct bttv *btv = file->private_data;
3894
3895 switch (cmd) {
3896 case VIDIOCGCAP:
3897 {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003898 struct video_capability *cap = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899
3900 memset(cap,0,sizeof(*cap));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003901 strcpy(cap->name,btv->radio_dev->name);
3902 cap->type = VID_TYPE_TUNER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 cap->channels = 1;
3904 cap->audios = 1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003905 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 }
3907
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003908 case VIDIOCGTUNER:
3909 {
3910 struct video_tuner *v = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003912 if(v->tuner)
3913 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 memset(v,0,sizeof(*v));
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003915 strcpy(v->name, "Radio");
3916 bttv_call_i2c_clients(btv,cmd,v);
3917 return 0;
3918 }
3919 case VIDIOCSTUNER:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 /* nothing to do */
3921 return 0;
3922
3923 case BTTV_VERSION:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08003924 case VIDIOCGFREQ:
3925 case VIDIOCSFREQ:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 case VIDIOCGAUDIO:
3927 case VIDIOCSAUDIO:
Hans Verkuil5af0c8f2006-01-09 18:21:37 -02003928 case VIDIOC_LOG_STATUS:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 return bttv_common_ioctls(btv,cmd,arg);
3930
3931 default:
3932 return -ENOIOCTLCMD;
3933 }
3934 return 0;
3935}
3936
3937static int radio_ioctl(struct inode *inode, struct file *file,
3938 unsigned int cmd, unsigned long arg)
3939{
3940 return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
3941}
3942
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003943static ssize_t radio_read(struct file *file, char __user *data,
3944 size_t count, loff_t *ppos)
3945{
3946 struct bttv *btv = file->private_data;
3947 struct rds_command cmd;
3948 cmd.block_count = count/3;
3949 cmd.buffer = data;
3950 cmd.instance = file;
3951 cmd.result = -ENODEV;
3952
3953 bttv_call_i2c_clients(btv, RDS_CMD_READ, &cmd);
3954
3955 return cmd.result;
3956}
3957
3958static unsigned int radio_poll(struct file *file, poll_table *wait)
3959{
3960 struct bttv *btv = file->private_data;
3961 struct rds_command cmd;
3962 cmd.instance = file;
3963 cmd.event_list = wait;
3964 cmd.result = -ENODEV;
3965 bttv_call_i2c_clients(btv, RDS_CMD_POLL, &cmd);
3966
3967 return cmd.result;
3968}
3969
Arjan van de Venfa027c22007-02-12 00:55:33 -08003970static const struct file_operations radio_fops =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971{
3972 .owner = THIS_MODULE,
3973 .open = radio_open,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003974 .read = radio_read,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 .release = radio_release,
3976 .ioctl = radio_ioctl,
3977 .llseek = no_llseek,
Mauro Carvalho Chehab24a70fd2005-09-09 13:03:39 -07003978 .poll = radio_poll,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979};
3980
3981static struct video_device radio_template =
3982{
3983 .name = "bt848/878 radio",
3984 .type = VID_TYPE_TUNER,
3985 .hardware = VID_HARDWARE_BT848,
3986 .fops = &radio_fops,
3987 .minor = -1,
3988};
3989
3990/* ----------------------------------------------------------------------- */
3991/* some debug code */
3992
Adrian Bunk408b6642005-05-01 08:59:29 -07003993static int bttv_risc_decode(u32 risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994{
3995 static char *instr[16] = {
3996 [ BT848_RISC_WRITE >> 28 ] = "write",
3997 [ BT848_RISC_SKIP >> 28 ] = "skip",
3998 [ BT848_RISC_WRITEC >> 28 ] = "writec",
3999 [ BT848_RISC_JUMP >> 28 ] = "jump",
4000 [ BT848_RISC_SYNC >> 28 ] = "sync",
4001 [ BT848_RISC_WRITE123 >> 28 ] = "write123",
4002 [ BT848_RISC_SKIP123 >> 28 ] = "skip123",
4003 [ BT848_RISC_WRITE1S23 >> 28 ] = "write1s23",
4004 };
4005 static int incr[16] = {
4006 [ BT848_RISC_WRITE >> 28 ] = 2,
4007 [ BT848_RISC_JUMP >> 28 ] = 2,
4008 [ BT848_RISC_SYNC >> 28 ] = 2,
4009 [ BT848_RISC_WRITE123 >> 28 ] = 5,
4010 [ BT848_RISC_SKIP123 >> 28 ] = 2,
4011 [ BT848_RISC_WRITE1S23 >> 28 ] = 3,
4012 };
4013 static char *bits[] = {
4014 "be0", "be1", "be2", "be3/resync",
4015 "set0", "set1", "set2", "set3",
4016 "clr0", "clr1", "clr2", "clr3",
4017 "irq", "res", "eol", "sol",
4018 };
4019 int i;
4020
4021 printk("0x%08x [ %s", risc,
4022 instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
4023 for (i = ARRAY_SIZE(bits)-1; i >= 0; i--)
4024 if (risc & (1 << (i + 12)))
4025 printk(" %s",bits[i]);
4026 printk(" count=%d ]\n", risc & 0xfff);
4027 return incr[risc >> 28] ? incr[risc >> 28] : 1;
4028}
4029
Adrian Bunk408b6642005-05-01 08:59:29 -07004030static void bttv_risc_disasm(struct bttv *btv,
4031 struct btcx_riscmem *risc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032{
4033 unsigned int i,j,n;
4034
4035 printk("%s: risc disasm: %p [dma=0x%08lx]\n",
4036 btv->c.name, risc->cpu, (unsigned long)risc->dma);
4037 for (i = 0; i < (risc->size >> 2); i += n) {
4038 printk("%s: 0x%lx: ", btv->c.name,
4039 (unsigned long)(risc->dma + (i<<2)));
4040 n = bttv_risc_decode(risc->cpu[i]);
4041 for (j = 1; j < n; j++)
4042 printk("%s: 0x%lx: 0x%08x [ arg #%d ]\n",
4043 btv->c.name, (unsigned long)(risc->dma + ((i+j)<<2)),
4044 risc->cpu[i+j], j);
4045 if (0 == risc->cpu[i])
4046 break;
4047 }
4048}
4049
4050static void bttv_print_riscaddr(struct bttv *btv)
4051{
4052 printk(" main: %08Lx\n",
4053 (unsigned long long)btv->main.dma);
4054 printk(" vbi : o=%08Lx e=%08Lx\n",
4055 btv->cvbi ? (unsigned long long)btv->cvbi->top.dma : 0,
4056 btv->cvbi ? (unsigned long long)btv->cvbi->bottom.dma : 0);
4057 printk(" cap : o=%08Lx e=%08Lx\n",
4058 btv->curr.top ? (unsigned long long)btv->curr.top->top.dma : 0,
4059 btv->curr.bottom ? (unsigned long long)btv->curr.bottom->bottom.dma : 0);
4060 printk(" scr : o=%08Lx e=%08Lx\n",
4061 btv->screen ? (unsigned long long)btv->screen->top.dma : 0,
4062 btv->screen ? (unsigned long long)btv->screen->bottom.dma : 0);
4063 bttv_risc_disasm(btv, &btv->main);
4064}
4065
4066/* ----------------------------------------------------------------------- */
4067/* irq handler */
4068
4069static char *irq_name[] = {
4070 "FMTCHG", // format change detected (525 vs. 625)
4071 "VSYNC", // vertical sync (new field)
4072 "HSYNC", // horizontal sync
4073 "OFLOW", // chroma/luma AGC overflow
4074 "HLOCK", // horizontal lock changed
4075 "VPRES", // video presence changed
4076 "6", "7",
4077 "I2CDONE", // hw irc operation finished
4078 "GPINT", // gpio port triggered irq
4079 "10",
4080 "RISCI", // risc instruction triggered irq
4081 "FBUS", // pixel data fifo dropped data (high pci bus latencies)
4082 "FTRGT", // pixel data fifo overrun
4083 "FDSR", // fifo data stream resyncronisation
4084 "PPERR", // parity error (data transfer)
4085 "RIPERR", // parity error (read risc instructions)
4086 "PABORT", // pci abort
4087 "OCERR", // risc instruction error
4088 "SCERR", // syncronisation error
4089};
4090
4091static void bttv_print_irqbits(u32 print, u32 mark)
4092{
4093 unsigned int i;
4094
4095 printk("bits:");
4096 for (i = 0; i < ARRAY_SIZE(irq_name); i++) {
4097 if (print & (1 << i))
4098 printk(" %s",irq_name[i]);
4099 if (mark & (1 << i))
4100 printk("*");
4101 }
4102}
4103
4104static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc)
4105{
4106 printk("bttv%d: irq: skipped frame [main=%lx,o_vbi=%lx,o_field=%lx,rc=%lx]\n",
4107 btv->c.nr,
4108 (unsigned long)btv->main.dma,
4109 (unsigned long)btv->main.cpu[RISC_SLOT_O_VBI+1],
4110 (unsigned long)btv->main.cpu[RISC_SLOT_O_FIELD+1],
4111 (unsigned long)rc);
4112
4113 if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) {
4114 printk("bttv%d: Oh, there (temporarely?) is no input signal. "
4115 "Ok, then this is harmless, don't worry ;)\n",
4116 btv->c.nr);
4117 return;
4118 }
4119 printk("bttv%d: Uhm. Looks like we have unusual high IRQ latencies.\n",
4120 btv->c.nr);
4121 printk("bttv%d: Lets try to catch the culpit red-handed ...\n",
4122 btv->c.nr);
4123 dump_stack();
4124}
4125
4126static int
4127bttv_irq_next_video(struct bttv *btv, struct bttv_buffer_set *set)
4128{
4129 struct bttv_buffer *item;
4130
4131 memset(set,0,sizeof(*set));
4132
4133 /* capture request ? */
4134 if (!list_empty(&btv->capture)) {
4135 set->frame_irq = 1;
4136 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
4137 if (V4L2_FIELD_HAS_TOP(item->vb.field))
4138 set->top = item;
4139 if (V4L2_FIELD_HAS_BOTTOM(item->vb.field))
4140 set->bottom = item;
4141
4142 /* capture request for other field ? */
4143 if (!V4L2_FIELD_HAS_BOTH(item->vb.field) &&
4144 (item->vb.queue.next != &btv->capture)) {
4145 item = list_entry(item->vb.queue.next, struct bttv_buffer, vb.queue);
4146 if (!V4L2_FIELD_HAS_BOTH(item->vb.field)) {
4147 if (NULL == set->top &&
4148 V4L2_FIELD_TOP == item->vb.field) {
4149 set->top = item;
4150 }
4151 if (NULL == set->bottom &&
4152 V4L2_FIELD_BOTTOM == item->vb.field) {
4153 set->bottom = item;
4154 }
4155 if (NULL != set->top && NULL != set->bottom)
4156 set->top_irq = 2;
4157 }
4158 }
4159 }
4160
4161 /* screen overlay ? */
4162 if (NULL != btv->screen) {
4163 if (V4L2_FIELD_HAS_BOTH(btv->screen->vb.field)) {
4164 if (NULL == set->top && NULL == set->bottom) {
4165 set->top = btv->screen;
4166 set->bottom = btv->screen;
4167 }
4168 } else {
4169 if (V4L2_FIELD_TOP == btv->screen->vb.field &&
4170 NULL == set->top) {
4171 set->top = btv->screen;
4172 }
4173 if (V4L2_FIELD_BOTTOM == btv->screen->vb.field &&
4174 NULL == set->bottom) {
4175 set->bottom = btv->screen;
4176 }
4177 }
4178 }
4179
4180 dprintk("bttv%d: next set: top=%p bottom=%p [screen=%p,irq=%d,%d]\n",
4181 btv->c.nr,set->top, set->bottom,
4182 btv->screen,set->frame_irq,set->top_irq);
4183 return 0;
4184}
4185
4186static void
4187bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup,
4188 struct bttv_buffer_set *curr, unsigned int state)
4189{
4190 struct timeval ts;
4191
4192 do_gettimeofday(&ts);
4193
4194 if (wakeup->top == wakeup->bottom) {
4195 if (NULL != wakeup->top && curr->top != wakeup->top) {
4196 if (irq_debug > 1)
4197 printk("bttv%d: wakeup: both=%p\n",btv->c.nr,wakeup->top);
4198 wakeup->top->vb.ts = ts;
4199 wakeup->top->vb.field_count = btv->field_count;
4200 wakeup->top->vb.state = state;
4201 wake_up(&wakeup->top->vb.done);
4202 }
4203 } else {
4204 if (NULL != wakeup->top && curr->top != wakeup->top) {
4205 if (irq_debug > 1)
4206 printk("bttv%d: wakeup: top=%p\n",btv->c.nr,wakeup->top);
4207 wakeup->top->vb.ts = ts;
4208 wakeup->top->vb.field_count = btv->field_count;
4209 wakeup->top->vb.state = state;
4210 wake_up(&wakeup->top->vb.done);
4211 }
4212 if (NULL != wakeup->bottom && curr->bottom != wakeup->bottom) {
4213 if (irq_debug > 1)
4214 printk("bttv%d: wakeup: bottom=%p\n",btv->c.nr,wakeup->bottom);
4215 wakeup->bottom->vb.ts = ts;
4216 wakeup->bottom->vb.field_count = btv->field_count;
4217 wakeup->bottom->vb.state = state;
4218 wake_up(&wakeup->bottom->vb.done);
4219 }
4220 }
4221}
4222
4223static void
4224bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
4225 unsigned int state)
4226{
4227 struct timeval ts;
4228
4229 if (NULL == wakeup)
4230 return;
4231
4232 do_gettimeofday(&ts);
4233 wakeup->vb.ts = ts;
4234 wakeup->vb.field_count = btv->field_count;
4235 wakeup->vb.state = state;
4236 wake_up(&wakeup->vb.done);
4237}
4238
4239static void bttv_irq_timeout(unsigned long data)
4240{
4241 struct bttv *btv = (struct bttv *)data;
4242 struct bttv_buffer_set old,new;
4243 struct bttv_buffer *ovbi;
4244 struct bttv_buffer *item;
4245 unsigned long flags;
4246
4247 if (bttv_verbose) {
4248 printk(KERN_INFO "bttv%d: timeout: drop=%d irq=%d/%d, risc=%08x, ",
4249 btv->c.nr, btv->framedrop, btv->irq_me, btv->irq_total,
4250 btread(BT848_RISC_COUNT));
4251 bttv_print_irqbits(btread(BT848_INT_STAT),0);
4252 printk("\n");
4253 }
4254
4255 spin_lock_irqsave(&btv->s_lock,flags);
4256
4257 /* deactivate stuff */
4258 memset(&new,0,sizeof(new));
4259 old = btv->curr;
4260 ovbi = btv->cvbi;
4261 btv->curr = new;
4262 btv->cvbi = NULL;
4263 btv->loop_irq = 0;
4264 bttv_buffer_activate_video(btv, &new);
4265 bttv_buffer_activate_vbi(btv, NULL);
4266 bttv_set_dma(btv, 0);
4267
4268 /* wake up */
4269 bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR);
4270 bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR);
4271
4272 /* cancel all outstanding capture / vbi requests */
4273 while (!list_empty(&btv->capture)) {
4274 item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue);
4275 list_del(&item->vb.queue);
4276 item->vb.state = STATE_ERROR;
4277 wake_up(&item->vb.done);
4278 }
4279 while (!list_empty(&btv->vcapture)) {
4280 item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
4281 list_del(&item->vb.queue);
4282 item->vb.state = STATE_ERROR;
4283 wake_up(&item->vb.done);
4284 }
4285
4286 btv->errors++;
4287 spin_unlock_irqrestore(&btv->s_lock,flags);
4288}
4289
4290static void
4291bttv_irq_wakeup_top(struct bttv *btv)
4292{
4293 struct bttv_buffer *wakeup = btv->curr.top;
4294
4295 if (NULL == wakeup)
4296 return;
4297
4298 spin_lock(&btv->s_lock);
4299 btv->curr.top_irq = 0;
4300 btv->curr.top = NULL;
4301 bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0);
4302
4303 do_gettimeofday(&wakeup->vb.ts);
4304 wakeup->vb.field_count = btv->field_count;
4305 wakeup->vb.state = STATE_DONE;
4306 wake_up(&wakeup->vb.done);
4307 spin_unlock(&btv->s_lock);
4308}
4309
4310static inline int is_active(struct btcx_riscmem *risc, u32 rc)
4311{
4312 if (rc < risc->dma)
4313 return 0;
4314 if (rc > risc->dma + risc->size)
4315 return 0;
4316 return 1;
4317}
4318
4319static void
4320bttv_irq_switch_video(struct bttv *btv)
4321{
4322 struct bttv_buffer_set new;
4323 struct bttv_buffer_set old;
4324 dma_addr_t rc;
4325
4326 spin_lock(&btv->s_lock);
4327
4328 /* new buffer set */
4329 bttv_irq_next_video(btv, &new);
4330 rc = btread(BT848_RISC_COUNT);
4331 if ((btv->curr.top && is_active(&btv->curr.top->top, rc)) ||
4332 (btv->curr.bottom && is_active(&btv->curr.bottom->bottom, rc))) {
4333 btv->framedrop++;
4334 if (debug_latency)
4335 bttv_irq_debug_low_latency(btv, rc);
4336 spin_unlock(&btv->s_lock);
4337 return;
4338 }
4339
4340 /* switch over */
4341 old = btv->curr;
4342 btv->curr = new;
4343 btv->loop_irq &= ~1;
4344 bttv_buffer_activate_video(btv, &new);
4345 bttv_set_dma(btv, 0);
4346
4347 /* switch input */
4348 if (UNSET != btv->new_input) {
4349 video_mux(btv,btv->new_input);
4350 btv->new_input = UNSET;
4351 }
4352
4353 /* wake up finished buffers */
4354 bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE);
4355 spin_unlock(&btv->s_lock);
4356}
4357
4358static void
4359bttv_irq_switch_vbi(struct bttv *btv)
4360{
4361 struct bttv_buffer *new = NULL;
4362 struct bttv_buffer *old;
4363 u32 rc;
4364
4365 spin_lock(&btv->s_lock);
4366
4367 if (!list_empty(&btv->vcapture))
4368 new = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue);
4369 old = btv->cvbi;
4370
4371 rc = btread(BT848_RISC_COUNT);
4372 if (NULL != old && (is_active(&old->top, rc) ||
4373 is_active(&old->bottom, rc))) {
4374 btv->framedrop++;
4375 if (debug_latency)
4376 bttv_irq_debug_low_latency(btv, rc);
4377 spin_unlock(&btv->s_lock);
4378 return;
4379 }
4380
4381 /* switch */
4382 btv->cvbi = new;
4383 btv->loop_irq &= ~4;
4384 bttv_buffer_activate_vbi(btv, new);
4385 bttv_set_dma(btv, 0);
4386
4387 bttv_irq_wakeup_vbi(btv, old, STATE_DONE);
4388 spin_unlock(&btv->s_lock);
4389}
4390
David Howells7d12e782006-10-05 14:55:46 +01004391static irqreturn_t bttv_irq(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392{
4393 u32 stat,astat;
4394 u32 dstat;
4395 int count;
4396 struct bttv *btv;
4397 int handled = 0;
4398
4399 btv=(struct bttv *)dev_id;
Mark Weaver6c6c0b22005-11-13 16:07:52 -08004400
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004401 if (btv->custom_irq)
4402 handled = btv->custom_irq(btv);
Mark Weaver6c6c0b22005-11-13 16:07:52 -08004403
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 count=0;
4405 while (1) {
4406 /* get/clear interrupt status bits */
4407 stat=btread(BT848_INT_STAT);
4408 astat=stat&btread(BT848_INT_MASK);
4409 if (!astat)
4410 break;
4411 handled = 1;
4412 btwrite(stat,BT848_INT_STAT);
4413
4414 /* get device status bits */
4415 dstat=btread(BT848_DSTATUS);
4416
4417 if (irq_debug) {
4418 printk(KERN_DEBUG "bttv%d: irq loop=%d fc=%d "
4419 "riscs=%x, riscc=%08x, ",
4420 btv->c.nr, count, btv->field_count,
4421 stat>>28, btread(BT848_RISC_COUNT));
4422 bttv_print_irqbits(stat,astat);
4423 if (stat & BT848_INT_HLOCK)
4424 printk(" HLOC => %s", (dstat & BT848_DSTATUS_HLOC)
4425 ? "yes" : "no");
4426 if (stat & BT848_INT_VPRES)
4427 printk(" PRES => %s", (dstat & BT848_DSTATUS_PRES)
4428 ? "yes" : "no");
4429 if (stat & BT848_INT_FMTCHG)
4430 printk(" NUML => %s", (dstat & BT848_DSTATUS_NUML)
4431 ? "625" : "525");
4432 printk("\n");
4433 }
4434
4435 if (astat&BT848_INT_VSYNC)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004436 btv->field_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004438 if ((astat & BT848_INT_GPINT) && btv->remote) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004440 bttv_input_irq(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 }
4442
4443 if (astat & BT848_INT_I2CDONE) {
4444 btv->i2c_done = stat;
4445 wake_up(&btv->i2c_queue);
4446 }
4447
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004448 if ((astat & BT848_INT_RISCI) && (stat & (4<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 bttv_irq_switch_vbi(btv);
4450
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004451 if ((astat & BT848_INT_RISCI) && (stat & (2<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 bttv_irq_wakeup_top(btv);
4453
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004454 if ((astat & BT848_INT_RISCI) && (stat & (1<<28)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 bttv_irq_switch_video(btv);
4456
4457 if ((astat & BT848_INT_HLOCK) && btv->opt_automute)
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004458 audio_mute(btv, btv->mute); /* trigger automute */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
4460 if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) {
4461 printk(KERN_INFO "bttv%d: %s%s @ %08x,",btv->c.nr,
4462 (astat & BT848_INT_SCERR) ? "SCERR" : "",
4463 (astat & BT848_INT_OCERR) ? "OCERR" : "",
4464 btread(BT848_RISC_COUNT));
4465 bttv_print_irqbits(stat,astat);
4466 printk("\n");
4467 if (bttv_debug)
4468 bttv_print_riscaddr(btv);
4469 }
4470 if (fdsr && astat & BT848_INT_FDSR) {
4471 printk(KERN_INFO "bttv%d: FDSR @ %08x\n",
4472 btv->c.nr,btread(BT848_RISC_COUNT));
4473 if (bttv_debug)
4474 bttv_print_riscaddr(btv);
4475 }
4476
4477 count++;
4478 if (count > 4) {
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004479
4480 if (count > 8 || !(astat & BT848_INT_GPINT)) {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004481 btwrite(0, BT848_INT_MASK);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004482
4483 printk(KERN_ERR
4484 "bttv%d: IRQ lockup, cleared int mask [", btv->c.nr);
4485 } else {
4486 printk(KERN_ERR
4487 "bttv%d: IRQ lockup, clearing GPINT from int mask [", btv->c.nr);
4488
4489 btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT),
4490 BT848_INT_MASK);
4491 };
4492
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 bttv_print_irqbits(stat,astat);
nshmyrev@yandex.ruc58c21c2005-11-08 21:37:41 -08004494
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 printk("]\n");
4496 }
4497 }
4498 btv->irq_total++;
4499 if (handled)
4500 btv->irq_me++;
4501 return IRQ_RETVAL(handled);
4502}
4503
4504
4505/* ----------------------------------------------------------------------- */
4506/* initialitation */
4507
4508static struct video_device *vdev_init(struct bttv *btv,
4509 struct video_device *template,
4510 char *type)
4511{
4512 struct video_device *vfd;
4513
4514 vfd = video_device_alloc();
4515 if (NULL == vfd)
4516 return NULL;
4517 *vfd = *template;
4518 vfd->minor = -1;
4519 vfd->dev = &btv->c.pci->dev;
4520 vfd->release = video_device_release;
4521 snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
4522 btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
4523 type, bttv_tvcards[btv->c.type].name);
4524 return vfd;
4525}
4526
4527static void bttv_unregister_video(struct bttv *btv)
4528{
4529 if (btv->video_dev) {
4530 if (-1 != btv->video_dev->minor)
4531 video_unregister_device(btv->video_dev);
4532 else
4533 video_device_release(btv->video_dev);
4534 btv->video_dev = NULL;
4535 }
4536 if (btv->vbi_dev) {
4537 if (-1 != btv->vbi_dev->minor)
4538 video_unregister_device(btv->vbi_dev);
4539 else
4540 video_device_release(btv->vbi_dev);
4541 btv->vbi_dev = NULL;
4542 }
4543 if (btv->radio_dev) {
4544 if (-1 != btv->radio_dev->minor)
4545 video_unregister_device(btv->radio_dev);
4546 else
4547 video_device_release(btv->radio_dev);
4548 btv->radio_dev = NULL;
4549 }
4550}
4551
4552/* register video4linux devices */
4553static int __devinit bttv_register_video(struct bttv *btv)
4554{
Mauro Carvalho Chehab4dcef522005-08-04 12:53:30 -07004555 if (no_overlay <= 0) {
4556 bttv_video_template.type |= VID_TYPE_OVERLAY;
4557 } else {
4558 printk("bttv: Overlay support disabled.\n");
4559 }
4560
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 /* video */
4562 btv->video_dev = vdev_init(btv, &bttv_video_template, "video");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004563 if (NULL == btv->video_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 goto err;
4565 if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
4566 goto err;
4567 printk(KERN_INFO "bttv%d: registered device video%d\n",
4568 btv->c.nr,btv->video_dev->minor & 0x1f);
Trent Piephod94fc9a2006-07-29 17:18:06 -03004569 if (class_device_create_file(&btv->video_dev->class_dev,
4570 &class_device_attr_card)<0) {
4571 printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
4572 "failed\n", btv->c.nr);
4573 goto err;
4574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575
4576 /* vbi */
4577 btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004578 if (NULL == btv->vbi_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 goto err;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004580 if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 goto err;
4582 printk(KERN_INFO "bttv%d: registered device vbi%d\n",
4583 btv->c.nr,btv->vbi_dev->minor & 0x1f);
4584
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004585 if (!btv->has_radio)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 return 0;
4587 /* radio */
4588 btv->radio_dev = vdev_init(btv, &radio_template, "radio");
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004589 if (NULL == btv->radio_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 goto err;
4591 if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0)
4592 goto err;
4593 printk(KERN_INFO "bttv%d: registered device radio%d\n",
4594 btv->c.nr,btv->radio_dev->minor & 0x1f);
4595
4596 /* all done */
4597 return 0;
4598
4599 err:
4600 bttv_unregister_video(btv);
4601 return -1;
4602}
4603
4604
4605/* on OpenFirmware machines (PowerMac at least), PCI memory cycle */
4606/* response on cards with no firmware is not enabled by OF */
4607static void pci_set_command(struct pci_dev *dev)
4608{
4609#if defined(__powerpc__)
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004610 unsigned int cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004612 pci_read_config_dword(dev, PCI_COMMAND, &cmd);
4613 cmd = (cmd | PCI_COMMAND_MEMORY );
4614 pci_write_config_dword(dev, PCI_COMMAND, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615#endif
4616}
4617
4618static int __devinit bttv_probe(struct pci_dev *dev,
4619 const struct pci_device_id *pci_id)
4620{
4621 int result;
4622 unsigned char lat;
4623 struct bttv *btv;
4624
4625 if (bttv_num == BTTV_MAX)
4626 return -ENOMEM;
4627 printk(KERN_INFO "bttv: Bt8xx card found (%d).\n", bttv_num);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004628 btv=&bttvs[bttv_num];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 memset(btv,0,sizeof(*btv));
4630 btv->c.nr = bttv_num;
4631 sprintf(btv->c.name,"bttv%d",btv->c.nr);
4632
4633 /* initialize structs / fill in defaults */
Ingo Molnarbd5f0ac2006-01-13 14:10:24 -02004634 mutex_init(&btv->lock);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004635 spin_lock_init(&btv->s_lock);
4636 spin_lock_init(&btv->gpio_lock);
4637 init_waitqueue_head(&btv->gpioq);
4638 init_waitqueue_head(&btv->i2c_queue);
4639 INIT_LIST_HEAD(&btv->c.subs);
4640 INIT_LIST_HEAD(&btv->capture);
4641 INIT_LIST_HEAD(&btv->vcapture);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 v4l2_prio_init(&btv->prio);
4643
4644 init_timer(&btv->timeout);
4645 btv->timeout.function = bttv_irq_timeout;
4646 btv->timeout.data = (unsigned long)btv;
4647
Michael Krufky7c08fb02005-11-08 21:36:21 -08004648 btv->i2c_rc = -1;
4649 btv->tuner_type = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 btv->new_input = UNSET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 btv->has_radio=radio[btv->c.nr];
4652
4653 /* pci stuff (init, get irq/mmio, ... */
4654 btv->c.pci = dev;
Michael Krufky7c08fb02005-11-08 21:36:21 -08004655 btv->id = dev->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 if (pci_enable_device(dev)) {
Michael Krufky7c08fb02005-11-08 21:36:21 -08004657 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 btv->c.nr);
4659 return -EIO;
4660 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004661 if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
4662 printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 btv->c.nr);
4664 return -EIO;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 if (!request_mem_region(pci_resource_start(dev,0),
4667 pci_resource_len(dev,0),
4668 btv->c.name)) {
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004669 printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
4670 btv->c.nr,
4671 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 return -EBUSY;
4673 }
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004674 pci_set_master(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 pci_set_command(dev);
4676 pci_set_drvdata(dev,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004678 pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
4679 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
4680 printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
4681 bttv_num,btv->id, btv->revision, pci_name(dev));
Greg Kroah-Hartman228aef62006-06-12 15:16:52 -07004682 printk("irq: %d, latency: %d, mmio: 0x%llx\n",
4683 btv->c.pci->irq, lat,
4684 (unsigned long long)pci_resource_start(dev,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 schedule();
4686
Akinobu Mita5f1693f2006-12-20 10:08:56 -03004687 btv->bt848_mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
4688 if (NULL == btv->bt848_mmio) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 printk("bttv%d: ioremap() failed\n", btv->c.nr);
4690 result = -EIO;
4691 goto fail1;
4692 }
4693
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004694 /* identify card */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 bttv_idcard(btv);
4696
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004697 /* disable irqs, register irq handler */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 btwrite(0, BT848_INT_MASK);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004699 result = request_irq(btv->c.pci->irq, bttv_irq,
Thomas Gleixner8076fe32006-07-01 19:29:37 -07004700 IRQF_SHARED | IRQF_DISABLED,btv->c.name,(void *)btv);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004701 if (result < 0) {
4702 printk(KERN_ERR "bttv%d: can't get IRQ %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 bttv_num,btv->c.pci->irq);
4704 goto fail1;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
4707 if (0 != bttv_handle_chipset(btv)) {
4708 result = -EIO;
4709 goto fail2;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
4712 /* init options from insmod args */
4713 btv->opt_combfilter = combfilter;
4714 btv->opt_lumafilter = lumafilter;
4715 btv->opt_automute = automute;
4716 btv->opt_chroma_agc = chroma_agc;
4717 btv->opt_adc_crush = adc_crush;
4718 btv->opt_vcr_hack = vcr_hack;
4719 btv->opt_whitecrush_upper = whitecrush_upper;
4720 btv->opt_whitecrush_lower = whitecrush_lower;
Mauro Carvalho Chehab060d3022005-06-28 20:45:25 -07004721 btv->opt_uv_ratio = uv_ratio;
4722 btv->opt_full_luma_range = full_luma_range;
4723 btv->opt_coring = coring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724
4725 /* fill struct bttv with some useful defaults */
4726 btv->init.btv = btv;
4727 btv->init.ov.w.width = 320;
4728 btv->init.ov.w.height = 240;
4729 btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
4730 btv->init.width = 320;
4731 btv->init.height = 240;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 btv->input = 0;
4733
4734 /* initialize hardware */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004735 if (bttv_gpio)
4736 bttv_gpio_tracking(btv,"pre-init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737
4738 bttv_risc_init_main(btv);
4739 init_bt848(btv);
4740
4741 /* gpio */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004742 btwrite(0x00, BT848_GPIO_REG_INP);
4743 btwrite(0x00, BT848_GPIO_OUT_EN);
4744 if (bttv_verbose)
4745 bttv_gpio_tracking(btv,"init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004747 /* needs to be done before i2c is registered */
4748 bttv_init_card1(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004750 /* register i2c + gpio */
4751 init_bttv_i2c(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004753 /* some card-specific stuff (needs working i2c) */
4754 bttv_init_card2(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 init_irqreg(btv);
4756
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004757 /* register video4linux + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 if (!bttv_tvcards[btv->c.type].no_video) {
4759 bttv_register_video(btv);
4760 bt848_bright(btv,32768);
4761 bt848_contrast(btv,32768);
4762 bt848_hue(btv,32768);
4763 bt848_sat(btv,32768);
Hans Verkuil8bf2f8e2006-03-18 21:31:00 -03004764 audio_mute(btv, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 set_input(btv,0);
Michael Schimeke5bd0262007-01-18 16:17:39 -03004766 bttv_crop_reset(&btv->crop[0], btv->tvnorm);
4767 btv->crop[1] = btv->crop[0]; /* current = default */
4768 disclaim_vbi_lines(btv);
4769 disclaim_video_lines(btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 }
4771
4772 /* add subdevices */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 if (bttv_tvcards[btv->c.type].has_dvb)
4774 bttv_sub_add_device(&btv->c, "dvb");
4775
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004776 bttv_input_init(btv);
4777
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 /* everything is fine */
4779 bttv_num++;
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004780 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781
4782 fail2:
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004783 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784
4785 fail1:
4786 if (btv->bt848_mmio)
4787 iounmap(btv->bt848_mmio);
4788 release_mem_region(pci_resource_start(btv->c.pci,0),
4789 pci_resource_len(btv->c.pci,0));
4790 pci_set_drvdata(dev,NULL);
4791 return result;
4792}
4793
4794static void __devexit bttv_remove(struct pci_dev *pci_dev)
4795{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004796 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797
4798 if (bttv_verbose)
4799 printk("bttv%d: unloading\n",btv->c.nr);
4800
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004801 /* shutdown everything (DMA+IRQs) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 btand(~15, BT848_GPIO_DMA_CTL);
4803 btwrite(0, BT848_INT_MASK);
4804 btwrite(~0x0, BT848_INT_STAT);
4805 btwrite(0x0, BT848_GPIO_OUT_EN);
4806 if (bttv_gpio)
4807 bttv_gpio_tracking(btv,"cleanup");
4808
4809 /* tell gpio modules we are leaving ... */
4810 btv->shutdown=1;
4811 wake_up(&btv->gpioq);
Ricardo Cerqueira4abdfed2006-01-09 15:25:25 -02004812 bttv_input_fini(btv);
Christopher Pascoe889aee82006-01-09 15:25:28 -02004813 bttv_sub_del_devices(&btv->c);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004815 /* unregister i2c_bus + input */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 fini_bttv_i2c(btv);
4817
4818 /* unregister video4linux */
4819 bttv_unregister_video(btv);
4820
4821 /* free allocated memory */
4822 btcx_riscmem_free(btv->c.pci,&btv->main);
4823
4824 /* free ressources */
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004825 free_irq(btv->c.pci->irq,btv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 iounmap(btv->bt848_mmio);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004827 release_mem_region(pci_resource_start(btv->c.pci,0),
4828 pci_resource_len(btv->c.pci,0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829
4830 pci_set_drvdata(pci_dev, NULL);
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004831 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832}
4833
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004834#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
4836{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004837 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 struct bttv_buffer_set idle;
4839 unsigned long flags;
4840
Mauro Carvalho Chehab0f97a932005-09-09 13:04:05 -07004841 dprintk("bttv%d: suspend %d\n", btv->c.nr, state.event);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842
4843 /* stop dma + irqs */
4844 spin_lock_irqsave(&btv->s_lock,flags);
4845 memset(&idle, 0, sizeof(idle));
4846 btv->state.video = btv->curr;
4847 btv->state.vbi = btv->cvbi;
4848 btv->state.loop_irq = btv->loop_irq;
4849 btv->curr = idle;
4850 btv->loop_irq = 0;
4851 bttv_buffer_activate_video(btv, &idle);
4852 bttv_buffer_activate_vbi(btv, NULL);
4853 bttv_set_dma(btv, 0);
4854 btwrite(0, BT848_INT_MASK);
4855 spin_unlock_irqrestore(&btv->s_lock,flags);
4856
4857 /* save bt878 state */
4858 btv->state.gpio_enable = btread(BT848_GPIO_OUT_EN);
4859 btv->state.gpio_data = gpio_read();
4860
4861 /* save pci state */
4862 pci_save_state(pci_dev);
4863 if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
4864 pci_disable_device(pci_dev);
4865 btv->state.disabled = 1;
4866 }
4867 return 0;
4868}
4869
4870static int bttv_resume(struct pci_dev *pci_dev)
4871{
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004872 struct bttv *btv = pci_get_drvdata(pci_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 unsigned long flags;
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004874 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875
4876 dprintk("bttv%d: resume\n", btv->c.nr);
4877
4878 /* restore pci state */
4879 if (btv->state.disabled) {
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004880 err=pci_enable_device(pci_dev);
4881 if (err) {
4882 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4883 btv->c.nr);
4884 return err;
4885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 btv->state.disabled = 0;
4887 }
Mauro Carvalho Chehab08adb9e2005-09-09 13:03:55 -07004888 err=pci_set_power_state(pci_dev, PCI_D0);
4889 if (err) {
4890 pci_disable_device(pci_dev);
4891 printk(KERN_WARNING "bttv%d: Can't enable device.\n",
4892 btv->c.nr);
4893 btv->state.disabled = 1;
4894 return err;
4895 }
4896
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 pci_restore_state(pci_dev);
4898
4899 /* restore bt878 state */
4900 bttv_reinit_bt848(btv);
4901 gpio_inout(0xffffff, btv->state.gpio_enable);
4902 gpio_write(btv->state.gpio_data);
4903
4904 /* restart dma */
4905 spin_lock_irqsave(&btv->s_lock,flags);
4906 btv->curr = btv->state.video;
4907 btv->cvbi = btv->state.vbi;
4908 btv->loop_irq = btv->state.loop_irq;
4909 bttv_buffer_activate_video(btv, &btv->curr);
4910 bttv_buffer_activate_vbi(btv, btv->cvbi);
4911 bttv_set_dma(btv, 0);
4912 spin_unlock_irqrestore(&btv->s_lock,flags);
4913 return 0;
4914}
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004915#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
4917static struct pci_device_id bttv_pci_tbl[] = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004918 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
4919 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004921 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004923 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004925 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
4926 {0,}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927};
4928
4929MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
4930
4931static struct pci_driver bttv_pci_driver = {
Mauro Carvalho Chehab4ac97912005-11-08 21:37:43 -08004932 .name = "bttv",
4933 .id_table = bttv_pci_tbl,
4934 .probe = bttv_probe,
4935 .remove = __devexit_p(bttv_remove),
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004936#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 .suspend = bttv_suspend,
4938 .resume = bttv_resume,
Alexey Dobriyan17bc98a2006-08-12 22:01:27 -03004939#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940};
4941
4942static int bttv_init_module(void)
4943{
Randy Dunlapc526e222006-07-15 09:08:26 -03004944 int ret;
4945
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 bttv_num = 0;
4947
4948 printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
4949 (BTTV_VERSION_CODE >> 16) & 0xff,
4950 (BTTV_VERSION_CODE >> 8) & 0xff,
4951 BTTV_VERSION_CODE & 0xff);
4952#ifdef SNAPSHOT
4953 printk(KERN_INFO "bttv: snapshot date %04d-%02d-%02d\n",
4954 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
4955#endif
4956 if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
4957 gbuffers = 2;
4958 if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
4959 gbufsize = BTTV_MAX_FBUF;
4960 gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
4961 if (bttv_verbose)
4962 printk(KERN_INFO "bttv: using %d buffers with %dk (%d pages) each for capture\n",
4963 gbuffers, gbufsize >> 10, gbufsize >> PAGE_SHIFT);
4964
4965 bttv_check_chipset();
4966
Randy Dunlapc526e222006-07-15 09:08:26 -03004967 ret = bus_register(&bttv_sub_bus_type);
4968 if (ret < 0) {
4969 printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
4970 return ret;
4971 }
Otavio Salvador23047592006-01-09 15:25:17 -02004972 return pci_register_driver(&bttv_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973}
4974
4975static void bttv_cleanup_module(void)
4976{
4977 pci_unregister_driver(&bttv_pci_driver);
4978 bus_unregister(&bttv_sub_bus_type);
4979 return;
4980}
4981
4982module_init(bttv_init_module);
4983module_exit(bttv_cleanup_module);
4984
4985/*
4986 * Local variables:
4987 * c-basic-offset: 8
4988 * End:
4989 */