blob: 74861a4b601aff51589e96fabb61167b51fa993f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 hexium_orion.c - v4l2 driver for the Hexium Orion 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.
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
Joe Perches44d0b802011-08-21 19:56:44 -030024#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#define DEBUG_VARIABLE debug
27
28#include <media/saa7146_vv.h>
29
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030030static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070031module_param(debug, int, 0);
32MODULE_PARM_DESC(debug, "debug verbosity");
33
34/* global variables */
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030035static int hexium_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#define HEXIUM_HV_PCI6_ORION 1
38#define HEXIUM_ORION_1SVHS_3BNC 2
39#define HEXIUM_ORION_4BNC 3
40
41#define HEXIUM_INPUTS 9
42static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
Hans Verkuil657f2272010-12-29 14:29:55 -030043 { 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 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070052};
53
54#define HEXIUM_AUDIOS 0
55
56struct hexium_data
57{
58 s8 adr;
59 u8 byte;
60};
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062struct hexium
63{
64 int type;
65 struct video_device *video_dev;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030066 struct i2c_adapter i2c_adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68 int cur_input; /* current input */
69};
70
71/* Philips SAA7110 decoder default registers */
72static u8 hexium_saa7110[53]={
73/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
74/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
75/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
76/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
77/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
78/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
79/*30*/ 0x44,0x75,0x01,0x8C,0x03
80};
81
82static struct {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030083 struct hexium_data data[8];
Linus Torvalds1da177e2005-04-16 15:20:36 -070084} hexium_input_select[] = {
85{
86 { /* cvbs 1 */
87 { 0x06, 0x00 },
88 { 0x20, 0xD9 },
89 { 0x21, 0x17 }, // 0x16,
90 { 0x22, 0x40 },
91 { 0x2C, 0x03 },
92 { 0x30, 0x44 },
93 { 0x31, 0x75 }, // ??
94 { 0x21, 0x16 }, // 0x03,
95 }
96}, {
97 { /* cvbs 2 */
98 { 0x06, 0x00 },
99 { 0x20, 0x78 },
100 { 0x21, 0x07 }, // 0x03,
101 { 0x22, 0xD2 },
102 { 0x2C, 0x83 },
103 { 0x30, 0x60 },
104 { 0x31, 0xB5 }, // ?
105 { 0x21, 0x03 },
106 }
107}, {
108 { /* cvbs 3 */
109 { 0x06, 0x00 },
110 { 0x20, 0xBA },
111 { 0x21, 0x07 }, // 0x05,
112 { 0x22, 0x91 },
113 { 0x2C, 0x03 },
114 { 0x30, 0x60 },
115 { 0x31, 0xB5 }, // ??
116 { 0x21, 0x05 }, // 0x03,
117 }
118}, {
119 { /* cvbs 4 */
120 { 0x06, 0x00 },
121 { 0x20, 0xD8 },
122 { 0x21, 0x17 }, // 0x16,
123 { 0x22, 0x40 },
124 { 0x2C, 0x03 },
125 { 0x30, 0x44 },
126 { 0x31, 0x75 }, // ??
127 { 0x21, 0x16 }, // 0x03,
128 }
129}, {
130 { /* cvbs 5 */
131 { 0x06, 0x00 },
132 { 0x20, 0xB8 },
133 { 0x21, 0x07 }, // 0x05,
134 { 0x22, 0x91 },
135 { 0x2C, 0x03 },
136 { 0x30, 0x60 },
137 { 0x31, 0xB5 }, // ??
138 { 0x21, 0x05 }, // 0x03,
139 }
140}, {
141 { /* cvbs 6 */
142 { 0x06, 0x00 },
143 { 0x20, 0x7C },
144 { 0x21, 0x07 }, // 0x03
145 { 0x22, 0xD2 },
146 { 0x2C, 0x83 },
147 { 0x30, 0x60 },
148 { 0x31, 0xB5 }, // ??
149 { 0x21, 0x03 },
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151}, {
152 { /* y/c 1 */
153 { 0x06, 0x80 },
154 { 0x20, 0x59 },
155 { 0x21, 0x17 },
156 { 0x22, 0x42 },
157 { 0x2C, 0xA3 },
158 { 0x30, 0x44 },
159 { 0x31, 0x75 },
160 { 0x21, 0x12 },
161 }
162}, {
163 { /* y/c 2 */
164 { 0x06, 0x80 },
165 { 0x20, 0x9A },
166 { 0x21, 0x17 },
167 { 0x22, 0xB1 },
168 { 0x2C, 0x13 },
169 { 0x30, 0x60 },
170 { 0x31, 0xB5 },
171 { 0x21, 0x14 },
172 }
173}, {
174 { /* y/c 3 */
175 { 0x06, 0x80 },
176 { 0x20, 0x3C },
177 { 0x21, 0x27 },
178 { 0x22, 0xC1 },
179 { 0x2C, 0x23 },
180 { 0x30, 0x44 },
181 { 0x31, 0x75 },
182 { 0x21, 0x21 },
183 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300184}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185};
186
187static struct saa7146_standard hexium_standards[] = {
188 {
189 .name = "PAL", .id = V4L2_STD_PAL,
190 .v_offset = 16, .v_field = 288,
191 .h_offset = 1, .h_pixels = 680,
192 .v_max_out = 576, .h_max_out = 768,
193 }, {
194 .name = "NTSC", .id = V4L2_STD_NTSC,
195 .v_offset = 16, .v_field = 240,
196 .h_offset = 1, .h_pixels = 640,
197 .v_max_out = 480, .h_max_out = 640,
198 }, {
199 .name = "SECAM", .id = V4L2_STD_SECAM,
200 .v_offset = 16, .v_field = 288,
201 .h_offset = 1, .h_pixels = 720,
202 .v_max_out = 576, .h_max_out = 768,
203 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300204};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206/* this is only called for old HV-PCI6/Orion cards
207 without eeprom */
208static int hexium_probe(struct saa7146_dev *dev)
209{
210 struct hexium *hexium = NULL;
211 union i2c_smbus_data data;
212 int err = 0;
213
Joe Perches44d0b802011-08-21 19:56:44 -0300214 DEB_EE("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 /* there are no hexium orion cards with revision 0 saa7146s */
217 if (0 == dev->revision) {
218 return -EFAULT;
219 }
220
Panagiotis Issaris74081872006-01-11 19:40:56 -0200221 hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 if (NULL == hexium) {
Joe Perches44d0b802011-08-21 19:56:44 -0300223 pr_err("hexium_probe: not enough kernel memory\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return -ENOMEM;
225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
227 /* enable i2c-port pins */
228 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
229
230 saa7146_write(dev, DD1_INIT, 0x01000100);
231 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
232 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
233
234 hexium->i2c_adapter = (struct i2c_adapter) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 .name = "hexium orion",
236 };
237 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
238 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
Joe Perches44d0b802011-08-21 19:56:44 -0300239 DEB_S("cannot register i2c-device. skipping.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 kfree(hexium);
241 return -EFAULT;
242 }
243
244 /* set SAA7110 control GPIO 0 */
245 saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
246 /* set HWControl GPIO number 2 */
247 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
248
249 mdelay(10);
250
251 /* detect newer Hexium Orion cards by subsystem ids */
252 if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
Joe Perches44d0b802011-08-21 19:56:44 -0300253 pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 /* we store the pointer in our private data field */
255 dev->ext_priv = hexium;
256 hexium->type = HEXIUM_ORION_1SVHS_3BNC;
257 return 0;
258 }
259
260 if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
Joe Perches44d0b802011-08-21 19:56:44 -0300261 pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 /* we store the pointer in our private data field */
263 dev->ext_priv = hexium;
264 hexium->type = HEXIUM_ORION_4BNC;
265 return 0;
266 }
267
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300268 /* check if this is an old hexium Orion card by looking at
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 a saa7110 at address 0x4e */
270 if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
Joe Perches44d0b802011-08-21 19:56:44 -0300271 pr_info("device is a Hexium HV-PCI6/Orion (old)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 /* we store the pointer in our private data field */
273 dev->ext_priv = hexium;
274 hexium->type = HEXIUM_HV_PCI6_ORION;
275 return 0;
276 }
277
278 i2c_del_adapter(&hexium->i2c_adapter);
279 kfree(hexium);
280 return -EFAULT;
281}
282
283/* bring hardware to a sane state. this has to be done, just in case someone
284 wants to capture from this device before it has been properly initialized.
285 the capture engine would badly fail, because no valid signal arrives on the
286 saa7146, thus leading to timeouts and stuff. */
287static int hexium_init_done(struct saa7146_dev *dev)
288{
289 struct hexium *hexium = (struct hexium *) dev->ext_priv;
290 union i2c_smbus_data data;
291 int i = 0;
292
Joe Perches44d0b802011-08-21 19:56:44 -0300293 DEB_D("hexium_init_done called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 /* initialize the helper ics to useful values */
296 for (i = 0; i < sizeof(hexium_saa7110); i++) {
297 data.byte = hexium_saa7110[i];
298 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
Joe Perches44d0b802011-08-21 19:56:44 -0300299 pr_err("failed for address 0x%02x\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301 }
302
303 return 0;
304}
305
306static int hexium_set_input(struct hexium *hexium, int input)
307{
308 union i2c_smbus_data data;
309 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300310
Joe Perches44d0b802011-08-21 19:56:44 -0300311 DEB_D("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 for (i = 0; i < 8; i++) {
314 int adr = hexium_input_select[input].data[i].adr;
315 data.byte = hexium_input_select[input].data[i].byte;
316 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
317 return -1;
318 }
Joe Perches44d0b802011-08-21 19:56:44 -0300319 pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 }
321
322 return 0;
323}
324
Hans Verkuilb9600742009-01-18 19:59:11 -0300325static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
326{
Joe Perches44d0b802011-08-21 19:56:44 -0300327 DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
Hans Verkuilb9600742009-01-18 19:59:11 -0300328
Roel Kluin223ffe52009-05-02 16:38:47 -0300329 if (i->index >= HEXIUM_INPUTS)
Hans Verkuilb9600742009-01-18 19:59:11 -0300330 return -EINVAL;
331
332 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
333
Joe Perches44d0b802011-08-21 19:56:44 -0300334 DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
Hans Verkuilb9600742009-01-18 19:59:11 -0300335 return 0;
336}
337
338static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
339{
340 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
341 struct hexium *hexium = (struct hexium *) dev->ext_priv;
342
343 *input = hexium->cur_input;
344
Joe Perches44d0b802011-08-21 19:56:44 -0300345 DEB_D("VIDIOC_G_INPUT: %d\n", *input);
Hans Verkuilb9600742009-01-18 19:59:11 -0300346 return 0;
347}
348
349static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
350{
351 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
352 struct hexium *hexium = (struct hexium *) dev->ext_priv;
353
Roel Kluinf14a2972009-10-23 07:59:42 -0300354 if (input >= HEXIUM_INPUTS)
Hans Verkuilb9600742009-01-18 19:59:11 -0300355 return -EINVAL;
356
357 hexium->cur_input = input;
358 hexium_set_input(hexium, input);
359
360 return 0;
361}
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363static struct saa7146_ext_vv vv_data;
364
365/* this function only gets called when the probing was successful */
366static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
367{
368 struct hexium *hexium = (struct hexium *) dev->ext_priv;
369
Joe Perches44d0b802011-08-21 19:56:44 -0300370 DEB_EE("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 saa7146_vv_init(dev, &vv_data);
Hans Verkuilb9600742009-01-18 19:59:11 -0300373 vv_data.ops.vidioc_enum_input = vidioc_enum_input;
374 vv_data.ops.vidioc_g_input = vidioc_g_input;
375 vv_data.ops.vidioc_s_input = vidioc_s_input;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
Joe Perches44d0b802011-08-21 19:56:44 -0300377 pr_err("cannot register capture v4l2 device. skipping.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 return -1;
379 }
380
Joe Perches44d0b802011-08-21 19:56:44 -0300381 pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 hexium_num++;
383
384 /* the rest */
385 hexium->cur_input = 0;
386 hexium_init_done(dev);
387
388 return 0;
389}
390
391static int hexium_detach(struct saa7146_dev *dev)
392{
393 struct hexium *hexium = (struct hexium *) dev->ext_priv;
394
Joe Perches44d0b802011-08-21 19:56:44 -0300395 DEB_EE("dev:%p\n", dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
397 saa7146_unregister_device(&hexium->video_dev, dev);
398 saa7146_vv_release(dev);
399
400 hexium_num--;
401
402 i2c_del_adapter(&hexium->i2c_adapter);
403 kfree(hexium);
404 return 0;
405}
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
408{
409 return 0;
410}
411
412static struct saa7146_extension extension;
413
414static struct saa7146_pci_extension_data hexium_hv_pci6 = {
415 .ext_priv = "Hexium HV-PCI6 / Orion",
416 .ext = &extension,
417};
418
419static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
420 .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
421 .ext = &extension,
422};
423
424static struct saa7146_pci_extension_data hexium_orion_4bnc = {
425 .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
426 .ext = &extension,
427};
428
429static struct pci_device_id pci_tbl[] = {
430 {
431 .vendor = PCI_VENDOR_ID_PHILIPS,
432 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
433 .subvendor = 0x0000,
434 .subdevice = 0x0000,
435 .driver_data = (unsigned long) &hexium_hv_pci6,
436 },
437 {
438 .vendor = PCI_VENDOR_ID_PHILIPS,
439 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
440 .subvendor = 0x17c8,
441 .subdevice = 0x0101,
442 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
443 },
444 {
445 .vendor = PCI_VENDOR_ID_PHILIPS,
446 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
447 .subvendor = 0x17c8,
448 .subdevice = 0x2101,
449 .driver_data = (unsigned long) &hexium_orion_4bnc,
450 },
451 {
452 .vendor = 0,
453 }
454};
455
456MODULE_DEVICE_TABLE(pci, pci_tbl);
457
458static struct saa7146_ext_vv vv_data = {
459 .inputs = HEXIUM_INPUTS,
460 .capabilities = 0,
461 .stds = &hexium_standards[0],
462 .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
463 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464};
465
466static struct saa7146_extension extension = {
Dave Jones922f77d2006-02-07 06:49:15 -0200467 .name = "hexium HV-PCI6 Orion",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 .flags = 0, // SAA7146_USE_I2C_IRQ,
469
470 .pci_tbl = &pci_tbl[0],
471 .module = THIS_MODULE,
472
473 .probe = hexium_probe,
474 .attach = hexium_attach,
475 .detach = hexium_detach,
476
477 .irq_mask = 0,
478 .irq_func = NULL,
479};
480
481static int __init hexium_init_module(void)
482{
483 if (0 != saa7146_register_extension(&extension)) {
Joe Perches44d0b802011-08-21 19:56:44 -0300484 DEB_S("failed to register extension\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 return -ENODEV;
486 }
487
488 return 0;
489}
490
491static void __exit hexium_cleanup_module(void)
492{
493 saa7146_unregister_extension(&extension);
494}
495
496module_init(hexium_init_module);
497module_exit(hexium_cleanup_module);
498
499MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
500MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
501MODULE_LICENSE("GPL");