2 hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
4 Visit http://www.mihu.de/linux/saa7146/ and follow the link
5 to "hexium" for further details about this card.
7 Copyright (C) 2003 Michael Hunold <michael@mihu.de>
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.
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.
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.
24 #define DEBUG_VARIABLE debug
26 #include <media/saa7146_vv.h>
29 MODULE_PARM(debug, "i");
30 MODULE_PARM_DESC(debug, "debug verbosity");
32 /* global variables */
33 static int hexium_num = 0;
35 #define HEXIUM_GEMINI 4
36 #define HEXIUM_GEMINI_DUAL 5
38 #define HEXIUM_INPUTS 9
39 static 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 },
51 #define HEXIUM_AUDIOS 0
59 static 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 },
70 #define HEXIUM_CONTROLS 1
71 static struct v4l2_queryctrl hexium_controls[] = {
72 { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
75 #define HEXIUM_GEMINI_V_1_0 1
76 #define HEXIUM_GEMINI_DUAL_V_1_0 2
81 struct video_device video_dev;
82 struct i2c_adapter i2c_adapter;
84 int cur_input; /* current input */
85 v4l2_std_id cur_std; /* current standard */
86 int cur_bw; /* current black/white status */
89 /* Samsung KS0127B decoder default registers */
90 static u8 hexium_ks0127b[0x100]={
91 /*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
92 /*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
93 /*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
94 /*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
95 /*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 /*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
97 /*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
98 /*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
99 /*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100 /*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101 /*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102 /*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103 /*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104 /*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105 /*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106 /*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107 /*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108 /*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109 /*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110 /*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111 /*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
112 /*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
113 /*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
114 /*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
115 /*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
116 /*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
117 /*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
118 /*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
119 /*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120 /*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
121 /*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
122 /*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
125 static struct hexium_data hexium_pal[] = {
126 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
129 static struct hexium_data hexium_pal_bw[] = {
130 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
133 static struct hexium_data hexium_ntsc[] = {
134 { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
137 static struct hexium_data hexium_ntsc_bw[] = {
138 { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
141 static struct hexium_data hexium_secam[] = {
142 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
145 static struct hexium_data hexium_input_select[] = {
157 /* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
158 are currently *not* supported*/
159 static struct saa7146_standard hexium_standards[] = {
161 .name = "PAL", .id = V4L2_STD_PAL,
162 .v_offset = 28, .v_field = 288,
163 .h_offset = 1, .h_pixels = 680,
164 .v_max_out = 576, .h_max_out = 768,
166 .name = "NTSC", .id = V4L2_STD_NTSC,
167 .v_offset = 28, .v_field = 240,
168 .h_offset = 1, .h_pixels = 640,
169 .v_max_out = 480, .h_max_out = 640,
171 .name = "SECAM", .id = V4L2_STD_SECAM,
172 .v_offset = 28, .v_field = 288,
173 .h_offset = 1, .h_pixels = 720,
174 .v_max_out = 576, .h_max_out = 768,
178 /* bring hardware to a sane state. this has to be done, just in case someone
179 wants to capture from this device before it has been properly initialized.
180 the capture engine would badly fail, because no valid signal arrives on the
181 saa7146, thus leading to timeouts and stuff. */
182 static int hexium_init_done(struct saa7146_dev *dev)
184 struct hexium *hexium = (struct hexium *) dev->ext_priv;
185 union i2c_smbus_data data;
188 DEB_D(("hexium_init_done called.\n"));
190 /* initialize the helper ics to useful values */
191 for (i = 0; i < sizeof(hexium_ks0127b); i++) {
192 data.byte = hexium_ks0127b[i];
193 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
194 printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i);
201 static int hexium_set_input(struct hexium *hexium, int input)
203 union i2c_smbus_data data;
207 data.byte = hexium_input_select[input].byte;
208 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
215 static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
217 union i2c_smbus_data data;
222 while (vdec[i].adr != -1) {
223 data.byte = vdec[i].byte;
224 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
225 printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i);
233 static struct saa7146_ext_vv vv_data;
235 /* this function only gets called when the probing was successful */
236 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
238 struct hexium *hexium = (struct hexium *) dev->ext_priv;
242 hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL);
243 if (NULL == hexium) {
244 printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
247 memset(hexium, 0x0, sizeof(struct hexium));
248 dev->ext_priv = hexium;
250 /* enable i2c-port pins */
251 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
253 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, I2C_CLASS_TV_ANALOG, SAA7146_I2C_BUS_BIT_RATE_480);
254 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
255 DEB_S(("cannot register i2c-device. skipping.\n"));
260 /* set HWControl GPIO number 2 */
261 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
263 saa7146_write(dev, DD1_INIT, 0x07000700);
264 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
265 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
268 hexium->cur_input = 0;
269 hexium_init_done(dev);
271 hexium_set_standard(hexium, hexium_pal);
272 hexium->cur_std = V4L2_STD_PAL;
274 hexium_set_input(hexium, 0);
275 hexium->cur_input = 0;
277 saa7146_vv_init(dev, &vv_data);
278 if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
279 printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
283 printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
289 static int hexium_detach(struct saa7146_dev *dev)
291 struct hexium *hexium = (struct hexium *) dev->ext_priv;
293 DEB_EE(("dev:%p\n", dev));
295 saa7146_unregister_device(&hexium->video_dev, dev);
296 saa7146_vv_release(dev);
300 i2c_del_adapter(&hexium->i2c_adapter);
305 static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
307 struct saa7146_dev *dev = fh->dev;
308 struct hexium *hexium = (struct hexium *) dev->ext_priv;
310 struct saa7146_vv *vv = dev->vv_data;
313 case VIDIOC_ENUMINPUT:
315 struct v4l2_input *i = arg;
316 DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
318 if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
322 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
324 DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
329 int *input = (int *) arg;
330 *input = hexium->cur_input;
332 DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
337 int input = *(int *) arg;
339 DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
341 if (input < 0 || input >= HEXIUM_INPUTS) {
345 hexium->cur_input = input;
346 hexium_set_input(hexium, input);
350 /* the saa7146 provides some controls (brightness, contrast, saturation)
351 which gets registered *after* this function. because of this we have
352 to return with a value != 0 even if the function succeded.. */
353 case VIDIOC_QUERYCTRL:
355 struct v4l2_queryctrl *qc = arg;
358 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
359 if (hexium_controls[i].id == qc->id) {
360 *qc = hexium_controls[i];
361 DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
369 struct v4l2_control *vc = arg;
372 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
373 if (hexium_controls[i].id == vc->id) {
383 case V4L2_CID_PRIVATE_BASE:{
384 vc->value = hexium->cur_bw;
385 DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
394 struct v4l2_control *vc = arg;
397 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
398 if (hexium_controls[i].id == vc->id) {
408 case V4L2_CID_PRIVATE_BASE:{
409 hexium->cur_bw = vc->value;
414 DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
416 if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
417 hexium_set_standard(hexium, hexium_pal);
420 if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
421 hexium_set_standard(hexium, hexium_ntsc);
424 if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
425 hexium_set_standard(hexium, hexium_secam);
428 if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
429 hexium_set_standard(hexium, hexium_pal_bw);
432 if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
433 hexium_set_standard(hexium, hexium_ntsc_bw);
436 if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
437 /* fixme: is there no bw secam mode? */
445 DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
452 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
454 struct hexium *hexium = (struct hexium *) dev->ext_priv;
456 if (V4L2_STD_PAL == std->id) {
457 hexium_set_standard(hexium, hexium_pal);
458 hexium->cur_std = V4L2_STD_PAL;
460 } else if (V4L2_STD_NTSC == std->id) {
461 hexium_set_standard(hexium, hexium_ntsc);
462 hexium->cur_std = V4L2_STD_NTSC;
464 } else if (V4L2_STD_SECAM == std->id) {
465 hexium_set_standard(hexium, hexium_secam);
466 hexium->cur_std = V4L2_STD_SECAM;
473 static struct saa7146_extension hexium_extension;
475 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
476 .ext_priv = "Hexium Gemini (4 BNC)",
477 .ext = &hexium_extension,
480 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
481 .ext_priv = "Hexium Gemini Dual (4 BNC)",
482 .ext = &hexium_extension,
485 static struct pci_device_id pci_tbl[] = {
487 .vendor = PCI_VENDOR_ID_PHILIPS,
488 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
491 .driver_data = (unsigned long) &hexium_gemini_4bnc,
494 .vendor = PCI_VENDOR_ID_PHILIPS,
495 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
498 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
505 MODULE_DEVICE_TABLE(pci, pci_tbl);
507 static struct saa7146_ext_vv vv_data = {
508 .inputs = HEXIUM_INPUTS,
510 .stds = &hexium_standards[0],
511 .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
512 .std_callback = &std_callback,
513 .ioctls = &ioctls[0],
514 .ioctl = hexium_ioctl,
517 static struct saa7146_extension hexium_extension = {
518 .name = "hexium gemini",
519 .flags = SAA7146_USE_I2C_IRQ,
521 .pci_tbl = &pci_tbl[0],
522 .module = THIS_MODULE,
524 .attach = hexium_attach,
525 .detach = hexium_detach,
531 static int __init hexium_init_module(void)
533 if (0 != saa7146_register_extension(&hexium_extension)) {
534 DEB_S(("failed to register extension.\n"));
541 static void __exit hexium_cleanup_module(void)
543 saa7146_unregister_extension(&hexium_extension);
546 module_init(hexium_init_module);
547 module_exit(hexium_cleanup_module);
549 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
550 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
551 MODULE_LICENSE("GPL");