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