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