aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/hexium_gemini.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/hexium_gemini.c')
-rw-r--r--drivers/media/video/hexium_gemini.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
new file mode 100644
index 000000000000..c9b00eafefde
--- /dev/null
+++ b/drivers/media/video/hexium_gemini.c
@@ -0,0 +1,556 @@
1/*
2 hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
3
4 Visit http://www.mihu.de/linux/saa7146/ and follow the link
5 to "hexium" for further details about this card.
6
7 Copyright (C) 2003 Michael Hunold <michael@mihu.de>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#define DEBUG_VARIABLE debug
25
26#include <media/saa7146_vv.h>
27
28static int debug = 0;
29module_param(debug, int, 0);
30MODULE_PARM_DESC(debug, "debug verbosity");
31
32/* global variables */
33static int hexium_num = 0;
34
35#define HEXIUM_GEMINI 4
36#define HEXIUM_GEMINI_DUAL 5
37
38#define HEXIUM_INPUTS 9
39static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
40 { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
41 { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
42 { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
43 { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
44 { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
45 { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
46 { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
47 { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
48 { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
49};
50
51#define HEXIUM_AUDIOS 0
52
53struct hexium_data
54{
55 s8 adr;
56 u8 byte;
57};
58
59static struct saa7146_extension_ioctls ioctls[] = {
60 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
61 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
62 { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
63 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
64 { VIDIOC_S_STD, SAA7146_AFTER },
65 { VIDIOC_G_CTRL, SAA7146_BEFORE },
66 { VIDIOC_S_CTRL, SAA7146_BEFORE },
67 { 0, 0 }
68};
69
70#define HEXIUM_CONTROLS 1
71static struct v4l2_queryctrl hexium_controls[] = {
72 { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
73};
74
75#define HEXIUM_GEMINI_V_1_0 1
76#define HEXIUM_GEMINI_DUAL_V_1_0 2
77
78struct hexium
79{
80 int type;
81
82 struct video_device *video_dev;
83 struct i2c_adapter i2c_adapter;
84
85 int cur_input; /* current input */
86 v4l2_std_id cur_std; /* current standard */
87 int cur_bw; /* current black/white status */
88};
89
90/* Samsung KS0127B decoder default registers */
91static u8 hexium_ks0127b[0x100]={
92/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
93/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
94/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
95/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
96/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
98/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
99/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
100/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
112/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
113/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
114/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
115/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
116/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
117/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
118/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
119/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
121/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
122/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
123/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
124};
125
126static struct hexium_data hexium_pal[] = {
127 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
128};
129
130static struct hexium_data hexium_pal_bw[] = {
131 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
132};
133
134static struct hexium_data hexium_ntsc[] = {
135 { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
136};
137
138static struct hexium_data hexium_ntsc_bw[] = {
139 { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
140};
141
142static struct hexium_data hexium_secam[] = {
143 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
144};
145
146static struct hexium_data hexium_input_select[] = {
147 { 0x02, 0x60 },
148 { 0x02, 0x64 },
149 { 0x02, 0x61 },
150 { 0x02, 0x65 },
151 { 0x02, 0x62 },
152 { 0x02, 0x66 },
153 { 0x02, 0x68 },
154 { 0x02, 0x69 },
155 { 0x02, 0x6A },
156};
157
158/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
159 are currently *not* supported*/
160static struct saa7146_standard hexium_standards[] = {
161 {
162 .name = "PAL", .id = V4L2_STD_PAL,
163 .v_offset = 28, .v_field = 288,
164 .h_offset = 1, .h_pixels = 680,
165 .v_max_out = 576, .h_max_out = 768,
166 }, {
167 .name = "NTSC", .id = V4L2_STD_NTSC,
168 .v_offset = 28, .v_field = 240,
169 .h_offset = 1, .h_pixels = 640,
170 .v_max_out = 480, .h_max_out = 640,
171 }, {
172 .name = "SECAM", .id = V4L2_STD_SECAM,
173 .v_offset = 28, .v_field = 288,
174 .h_offset = 1, .h_pixels = 720,
175 .v_max_out = 576, .h_max_out = 768,
176 }
177};
178
179/* bring hardware to a sane state. this has to be done, just in case someone
180 wants to capture from this device before it has been properly initialized.
181 the capture engine would badly fail, because no valid signal arrives on the
182 saa7146, thus leading to timeouts and stuff. */
183static int hexium_init_done(struct saa7146_dev *dev)
184{
185 struct hexium *hexium = (struct hexium *) dev->ext_priv;
186 union i2c_smbus_data data;
187 int i = 0;
188
189 DEB_D(("hexium_init_done called.\n"));
190
191 /* initialize the helper ics to useful values */
192 for (i = 0; i < sizeof(hexium_ks0127b); i++) {
193 data.byte = hexium_ks0127b[i];
194 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
195 printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i);
196 }
197 }
198
199 return 0;
200}
201
202static int hexium_set_input(struct hexium *hexium, int input)
203{
204 union i2c_smbus_data data;
205
206 DEB_D((".\n"));
207
208 data.byte = hexium_input_select[input].byte;
209 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
210 return -1;
211 }
212
213 return 0;
214}
215
216static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
217{
218 union i2c_smbus_data data;
219 int i = 0;
220
221 DEB_D((".\n"));
222
223 while (vdec[i].adr != -1) {
224 data.byte = vdec[i].byte;
225 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
226 printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i);
227 return -1;
228 }
229 i++;
230 }
231 return 0;
232}
233
234static struct saa7146_ext_vv vv_data;
235
236/* this function only gets called when the probing was successful */
237static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
238{
239 struct hexium *hexium = (struct hexium *) dev->ext_priv;
240
241 DEB_EE((".\n"));
242
243 hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL);
244 if (NULL == hexium) {
245 printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
246 return -ENOMEM;
247 }
248 memset(hexium, 0x0, sizeof(struct hexium));
249 dev->ext_priv = hexium;
250
251 /* enable i2c-port pins */
252 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
253
254 hexium->i2c_adapter = (struct i2c_adapter) {
255 .class = I2C_CLASS_TV_ANALOG,
256 .name = "hexium gemini",
257 };
258 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
259 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
260 DEB_S(("cannot register i2c-device. skipping.\n"));
261 kfree(hexium);
262 return -EFAULT;
263 }
264
265 /* set HWControl GPIO number 2 */
266 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
267
268 saa7146_write(dev, DD1_INIT, 0x07000700);
269 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
270 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
271
272 /* the rest */
273 hexium->cur_input = 0;
274 hexium_init_done(dev);
275
276 hexium_set_standard(hexium, hexium_pal);
277 hexium->cur_std = V4L2_STD_PAL;
278
279 hexium_set_input(hexium, 0);
280 hexium->cur_input = 0;
281
282 saa7146_vv_init(dev, &vv_data);
283 if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
284 printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
285 return -1;
286 }
287
288 printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
289 hexium_num++;
290
291 return 0;
292}
293
294static int hexium_detach(struct saa7146_dev *dev)
295{
296 struct hexium *hexium = (struct hexium *) dev->ext_priv;
297
298 DEB_EE(("dev:%p\n", dev));
299
300 saa7146_unregister_device(&hexium->video_dev, dev);
301 saa7146_vv_release(dev);
302
303 hexium_num--;
304
305 i2c_del_adapter(&hexium->i2c_adapter);
306 kfree(hexium);
307 return 0;
308}
309
310static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
311{
312 struct saa7146_dev *dev = fh->dev;
313 struct hexium *hexium = (struct hexium *) dev->ext_priv;
314/*
315 struct saa7146_vv *vv = dev->vv_data;
316*/
317 switch (cmd) {
318 case VIDIOC_ENUMINPUT:
319 {
320 struct v4l2_input *i = arg;
321 DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
322
323 if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
324 return -EINVAL;
325 }
326
327 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
328
329 DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
330 return 0;
331 }
332 case VIDIOC_G_INPUT:
333 {
334 int *input = (int *) arg;
335 *input = hexium->cur_input;
336
337 DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
338 return 0;
339 }
340 case VIDIOC_S_INPUT:
341 {
342 int input = *(int *) arg;
343
344 DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
345
346 if (input < 0 || input >= HEXIUM_INPUTS) {
347 return -EINVAL;
348 }
349
350 hexium->cur_input = input;
351 hexium_set_input(hexium, input);
352
353 return 0;
354 }
355 /* the saa7146 provides some controls (brightness, contrast, saturation)
356 which gets registered *after* this function. because of this we have
357 to return with a value != 0 even if the function succeded.. */
358 case VIDIOC_QUERYCTRL:
359 {
360 struct v4l2_queryctrl *qc = arg;
361 int i;
362
363 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
364 if (hexium_controls[i].id == qc->id) {
365 *qc = hexium_controls[i];
366 DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
367 return 0;
368 }
369 }
370 return -EAGAIN;
371 }
372 case VIDIOC_G_CTRL:
373 {
374 struct v4l2_control *vc = arg;
375 int i;
376
377 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
378 if (hexium_controls[i].id == vc->id) {
379 break;
380 }
381 }
382
383 if (i < 0) {
384 return -EAGAIN;
385 }
386
387 switch (vc->id) {
388 case V4L2_CID_PRIVATE_BASE:{
389 vc->value = hexium->cur_bw;
390 DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
391 return 0;
392 }
393 }
394 return -EINVAL;
395 }
396
397 case VIDIOC_S_CTRL:
398 {
399 struct v4l2_control *vc = arg;
400 int i = 0;
401
402 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
403 if (hexium_controls[i].id == vc->id) {
404 break;
405 }
406 }
407
408 if (i < 0) {
409 return -EAGAIN;
410 }
411
412 switch (vc->id) {
413 case V4L2_CID_PRIVATE_BASE:{
414 hexium->cur_bw = vc->value;
415 break;
416 }
417 }
418
419 DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
420
421 if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
422 hexium_set_standard(hexium, hexium_pal);
423 return 0;
424 }
425 if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
426 hexium_set_standard(hexium, hexium_ntsc);
427 return 0;
428 }
429 if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
430 hexium_set_standard(hexium, hexium_secam);
431 return 0;
432 }
433 if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
434 hexium_set_standard(hexium, hexium_pal_bw);
435 return 0;
436 }
437 if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
438 hexium_set_standard(hexium, hexium_ntsc_bw);
439 return 0;
440 }
441 if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
442 /* fixme: is there no bw secam mode? */
443 return -EINVAL;
444 }
445
446 return -EINVAL;
447 }
448 default:
449/*
450 DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
451*/
452 return -ENOIOCTLCMD;
453 }
454 return 0;
455}
456
457static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
458{
459 struct hexium *hexium = (struct hexium *) dev->ext_priv;
460
461 if (V4L2_STD_PAL == std->id) {
462 hexium_set_standard(hexium, hexium_pal);
463 hexium->cur_std = V4L2_STD_PAL;
464 return 0;
465 } else if (V4L2_STD_NTSC == std->id) {
466 hexium_set_standard(hexium, hexium_ntsc);
467 hexium->cur_std = V4L2_STD_NTSC;
468 return 0;
469 } else if (V4L2_STD_SECAM == std->id) {
470 hexium_set_standard(hexium, hexium_secam);
471 hexium->cur_std = V4L2_STD_SECAM;
472 return 0;
473 }
474
475 return -1;
476}
477
478static struct saa7146_extension hexium_extension;
479
480static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
481 .ext_priv = "Hexium Gemini (4 BNC)",
482 .ext = &hexium_extension,
483};
484
485static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
486 .ext_priv = "Hexium Gemini Dual (4 BNC)",
487 .ext = &hexium_extension,
488};
489
490static struct pci_device_id pci_tbl[] = {
491 {
492 .vendor = PCI_VENDOR_ID_PHILIPS,
493 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
494 .subvendor = 0x17c8,
495 .subdevice = 0x2401,
496 .driver_data = (unsigned long) &hexium_gemini_4bnc,
497 },
498 {
499 .vendor = PCI_VENDOR_ID_PHILIPS,
500 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
501 .subvendor = 0x17c8,
502 .subdevice = 0x2402,
503 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
504 },
505 {
506 .vendor = 0,
507 }
508};
509
510MODULE_DEVICE_TABLE(pci, pci_tbl);
511
512static struct saa7146_ext_vv vv_data = {
513 .inputs = HEXIUM_INPUTS,
514 .capabilities = 0,
515 .stds = &hexium_standards[0],
516 .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
517 .std_callback = &std_callback,
518 .ioctls = &ioctls[0],
519 .ioctl = hexium_ioctl,
520};
521
522static struct saa7146_extension hexium_extension = {
523 .name = "hexium gemini",
524 .flags = SAA7146_USE_I2C_IRQ,
525
526 .pci_tbl = &pci_tbl[0],
527 .module = THIS_MODULE,
528
529 .attach = hexium_attach,
530 .detach = hexium_detach,
531
532 .irq_mask = 0,
533 .irq_func = NULL,
534};
535
536static int __init hexium_init_module(void)
537{
538 if (0 != saa7146_register_extension(&hexium_extension)) {
539 DEB_S(("failed to register extension.\n"));
540 return -ENODEV;
541 }
542
543 return 0;
544}
545
546static void __exit hexium_cleanup_module(void)
547{
548 saa7146_unregister_extension(&hexium_extension);
549}
550
551module_init(hexium_init_module);
552module_exit(hexium_cleanup_module);
553
554MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
555MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
556MODULE_LICENSE("GPL");