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