blob: 352f84d440fb64272e6818fc2439122fa0c43230 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 Visit http://www.mihu.de/linux/saa7146/ and follow the link
5 to "hexium" for further details about this card.
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03006
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 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
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030028static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029module_param(debug, int, 0);
30MODULE_PARM_DESC(debug, "debug verbosity");
31
32/* global variables */
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030033static int hexium_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
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;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030084
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 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 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300177};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
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
Panagiotis Issaris74081872006-01-11 19:40:56 -0200243 hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 if (NULL == hexium) {
245 printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
246 return -ENOMEM;
247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 dev->ext_priv = hexium;
249
250 /* enable i2c-port pins */
251 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
252
253 hexium->i2c_adapter = (struct i2c_adapter) {
254 .class = I2C_CLASS_TV_ANALOG,
255 .name = "hexium gemini",
256 };
257 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
258 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
259 DEB_S(("cannot register i2c-device. skipping.\n"));
260 kfree(hexium);
261 return -EFAULT;
262 }
263
264 /* set HWControl GPIO number 2 */
265 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
266
267 saa7146_write(dev, DD1_INIT, 0x07000700);
268 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
269 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
270
271 /* the rest */
272 hexium->cur_input = 0;
273 hexium_init_done(dev);
274
275 hexium_set_standard(hexium, hexium_pal);
276 hexium->cur_std = V4L2_STD_PAL;
277
278 hexium_set_input(hexium, 0);
279 hexium->cur_input = 0;
280
281 saa7146_vv_init(dev, &vv_data);
282 if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
283 printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
284 return -1;
285 }
286
287 printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
288 hexium_num++;
289
290 return 0;
291}
292
293static int hexium_detach(struct saa7146_dev *dev)
294{
295 struct hexium *hexium = (struct hexium *) dev->ext_priv;
296
297 DEB_EE(("dev:%p\n", dev));
298
299 saa7146_unregister_device(&hexium->video_dev, dev);
300 saa7146_vv_release(dev);
301
302 hexium_num--;
303
304 i2c_del_adapter(&hexium->i2c_adapter);
305 kfree(hexium);
306 return 0;
307}
308
309static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
310{
311 struct saa7146_dev *dev = fh->dev;
312 struct hexium *hexium = (struct hexium *) dev->ext_priv;
313/*
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300314 struct saa7146_vv *vv = dev->vv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315*/
316 switch (cmd) {
317 case VIDIOC_ENUMINPUT:
318 {
319 struct v4l2_input *i = arg;
320 DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
321
322 if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
323 return -EINVAL;
324 }
325
326 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
327
328 DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
329 return 0;
330 }
331 case VIDIOC_G_INPUT:
332 {
333 int *input = (int *) arg;
334 *input = hexium->cur_input;
335
336 DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
337 return 0;
338 }
339 case VIDIOC_S_INPUT:
340 {
341 int input = *(int *) arg;
342
343 DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
344
345 if (input < 0 || input >= HEXIUM_INPUTS) {
346 return -EINVAL;
347 }
348
349 hexium->cur_input = input;
350 hexium_set_input(hexium, input);
351
352 return 0;
353 }
354 /* the saa7146 provides some controls (brightness, contrast, saturation)
355 which gets registered *after* this function. because of this we have
356 to return with a value != 0 even if the function succeded.. */
357 case VIDIOC_QUERYCTRL:
358 {
359 struct v4l2_queryctrl *qc = arg;
360 int i;
361
362 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
363 if (hexium_controls[i].id == qc->id) {
364 *qc = hexium_controls[i];
365 DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
366 return 0;
367 }
368 }
369 return -EAGAIN;
370 }
371 case VIDIOC_G_CTRL:
372 {
373 struct v4l2_control *vc = arg;
374 int i;
375
376 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
377 if (hexium_controls[i].id == vc->id) {
378 break;
379 }
380 }
381
382 if (i < 0) {
383 return -EAGAIN;
384 }
385
386 switch (vc->id) {
387 case V4L2_CID_PRIVATE_BASE:{
388 vc->value = hexium->cur_bw;
389 DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
390 return 0;
391 }
392 }
393 return -EINVAL;
394 }
395
396 case VIDIOC_S_CTRL:
397 {
398 struct v4l2_control *vc = arg;
399 int i = 0;
400
401 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
402 if (hexium_controls[i].id == vc->id) {
403 break;
404 }
405 }
406
407 if (i < 0) {
408 return -EAGAIN;
409 }
410
411 switch (vc->id) {
412 case V4L2_CID_PRIVATE_BASE:{
413 hexium->cur_bw = vc->value;
414 break;
415 }
416 }
417
418 DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
419
420 if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
421 hexium_set_standard(hexium, hexium_pal);
422 return 0;
423 }
424 if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
425 hexium_set_standard(hexium, hexium_ntsc);
426 return 0;
427 }
428 if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
429 hexium_set_standard(hexium, hexium_secam);
430 return 0;
431 }
432 if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
433 hexium_set_standard(hexium, hexium_pal_bw);
434 return 0;
435 }
436 if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
437 hexium_set_standard(hexium, hexium_ntsc_bw);
438 return 0;
439 }
440 if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
441 /* fixme: is there no bw secam mode? */
442 return -EINVAL;
443 }
444
445 return -EINVAL;
446 }
447 default:
448/*
449 DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
450*/
451 return -ENOIOCTLCMD;
452 }
453 return 0;
454}
455
456static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
457{
458 struct hexium *hexium = (struct hexium *) dev->ext_priv;
459
460 if (V4L2_STD_PAL == std->id) {
461 hexium_set_standard(hexium, hexium_pal);
462 hexium->cur_std = V4L2_STD_PAL;
463 return 0;
464 } else if (V4L2_STD_NTSC == std->id) {
465 hexium_set_standard(hexium, hexium_ntsc);
466 hexium->cur_std = V4L2_STD_NTSC;
467 return 0;
468 } else if (V4L2_STD_SECAM == std->id) {
469 hexium_set_standard(hexium, hexium_secam);
470 hexium->cur_std = V4L2_STD_SECAM;
471 return 0;
472 }
473
474 return -1;
475}
476
477static struct saa7146_extension hexium_extension;
478
479static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
480 .ext_priv = "Hexium Gemini (4 BNC)",
481 .ext = &hexium_extension,
482};
483
484static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
485 .ext_priv = "Hexium Gemini Dual (4 BNC)",
486 .ext = &hexium_extension,
487};
488
489static struct pci_device_id pci_tbl[] = {
490 {
491 .vendor = PCI_VENDOR_ID_PHILIPS,
492 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
493 .subvendor = 0x17c8,
494 .subdevice = 0x2401,
495 .driver_data = (unsigned long) &hexium_gemini_4bnc,
496 },
497 {
498 .vendor = PCI_VENDOR_ID_PHILIPS,
499 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
500 .subvendor = 0x17c8,
501 .subdevice = 0x2402,
502 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
503 },
504 {
505 .vendor = 0,
506 }
507};
508
509MODULE_DEVICE_TABLE(pci, pci_tbl);
510
511static struct saa7146_ext_vv vv_data = {
512 .inputs = HEXIUM_INPUTS,
513 .capabilities = 0,
514 .stds = &hexium_standards[0],
515 .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
516 .std_callback = &std_callback,
517 .ioctls = &ioctls[0],
518 .ioctl = hexium_ioctl,
519};
520
521static struct saa7146_extension hexium_extension = {
522 .name = "hexium gemini",
523 .flags = SAA7146_USE_I2C_IRQ,
524
525 .pci_tbl = &pci_tbl[0],
526 .module = THIS_MODULE,
527
528 .attach = hexium_attach,
529 .detach = hexium_detach,
530
531 .irq_mask = 0,
532 .irq_func = NULL,
533};
534
535static int __init hexium_init_module(void)
536{
537 if (0 != saa7146_register_extension(&hexium_extension)) {
538 DEB_S(("failed to register extension.\n"));
539 return -ENODEV;
540 }
541
542 return 0;
543}
544
545static void __exit hexium_cleanup_module(void)
546{
547 saa7146_unregister_extension(&hexium_extension);
548}
549
550module_init(hexium_init_module);
551module_exit(hexium_cleanup_module);
552
553MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
554MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
555MODULE_LICENSE("GPL");