1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
31static int debug;
32module_param(debug, int, 0);
33MODULE_PARM_DESC(debug, "debug verbosity");
34
35
36static int hexium_num;
37
38#define HEXIUM_GEMINI 4
39#define HEXIUM_GEMINI_DUAL 5
40
41#define HEXIUM_INPUTS 9
42static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
43 { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
44 { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
45 { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
46 { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
47 { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
48 { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
49 { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
50 { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
51 { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
52};
53
54#define HEXIUM_AUDIOS 0
55
56struct hexium_data
57{
58 s8 adr;
59 u8 byte;
60};
61
62#define HEXIUM_GEMINI_V_1_0 1
63#define HEXIUM_GEMINI_DUAL_V_1_0 2
64
65struct hexium
66{
67 int type;
68
69 struct video_device *video_dev;
70 struct i2c_adapter i2c_adapter;
71
72 int cur_input;
73 v4l2_std_id cur_std;
74};
75
76
77static u8 hexium_ks0127b[0x100]={
78 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
79 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
80 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
81 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
82 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
84 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
85 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
86 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
87 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
88 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
89 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
91 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
92 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
93 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
94 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
95 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
110};
111
112static struct hexium_data hexium_pal[] = {
113 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
114};
115
116static struct hexium_data hexium_ntsc[] = {
117 { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
118};
119
120static struct hexium_data hexium_secam[] = {
121 { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
122};
123
124static struct hexium_data hexium_input_select[] = {
125 { 0x02, 0x60 },
126 { 0x02, 0x64 },
127 { 0x02, 0x61 },
128 { 0x02, 0x65 },
129 { 0x02, 0x62 },
130 { 0x02, 0x66 },
131 { 0x02, 0x68 },
132 { 0x02, 0x69 },
133 { 0x02, 0x6A },
134};
135
136
137
138static struct saa7146_standard hexium_standards[] = {
139 {
140 .name = "PAL", .id = V4L2_STD_PAL,
141 .v_offset = 28, .v_field = 288,
142 .h_offset = 1, .h_pixels = 680,
143 .v_max_out = 576, .h_max_out = 768,
144 }, {
145 .name = "NTSC", .id = V4L2_STD_NTSC,
146 .v_offset = 28, .v_field = 240,
147 .h_offset = 1, .h_pixels = 640,
148 .v_max_out = 480, .h_max_out = 640,
149 }, {
150 .name = "SECAM", .id = V4L2_STD_SECAM,
151 .v_offset = 28, .v_field = 288,
152 .h_offset = 1, .h_pixels = 720,
153 .v_max_out = 576, .h_max_out = 768,
154 }
155};
156
157
158
159
160
161static int hexium_init_done(struct saa7146_dev *dev)
162{
163 struct hexium *hexium = (struct hexium *) dev->ext_priv;
164 union i2c_smbus_data data;
165 int i = 0;
166
167 DEB_D("hexium_init_done called\n");
168
169
170 for (i = 0; i < sizeof(hexium_ks0127b); i++) {
171 data.byte = hexium_ks0127b[i];
172 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
173 pr_err("hexium_init_done() failed for address 0x%02x\n",
174 i);
175 }
176 }
177
178 return 0;
179}
180
181static int hexium_set_input(struct hexium *hexium, int input)
182{
183 union i2c_smbus_data data;
184
185 DEB_D("\n");
186
187 data.byte = hexium_input_select[input].byte;
188 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
189 return -1;
190 }
191
192 return 0;
193}
194
195static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
196{
197 union i2c_smbus_data data;
198 int i = 0;
199
200 DEB_D("\n");
201
202 while (vdec[i].adr != -1) {
203 data.byte = vdec[i].byte;
204 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
205 pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
206 i);
207 return -1;
208 }
209 i++;
210 }
211 return 0;
212}
213
214static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
215{
216 DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
217
218 if (i->index >= HEXIUM_INPUTS)
219 return -EINVAL;
220
221 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
222
223 DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
224 return 0;
225}
226
227static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
228{
229 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
230 struct hexium *hexium = (struct hexium *) dev->ext_priv;
231
232 *input = hexium->cur_input;
233
234 DEB_D("VIDIOC_G_INPUT: %d\n", *input);
235 return 0;
236}
237
238static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
239{
240 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
241 struct hexium *hexium = (struct hexium *) dev->ext_priv;
242
243 DEB_EE("VIDIOC_S_INPUT %d\n", input);
244
245 if (input >= HEXIUM_INPUTS)
246 return -EINVAL;
247
248 hexium->cur_input = input;
249 hexium_set_input(hexium, input);
250 return 0;
251}
252
253static struct saa7146_ext_vv vv_data;
254
255
256static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
257{
258 struct hexium *hexium;
259 int ret;
260
261 DEB_EE("\n");
262
263 hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
264 if (NULL == hexium) {
265 pr_err("not enough kernel memory in hexium_attach()\n");
266 return -ENOMEM;
267 }
268 dev->ext_priv = hexium;
269
270
271 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
272
273 hexium->i2c_adapter = (struct i2c_adapter) {
274 .name = "hexium gemini",
275 };
276 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
277 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
278 DEB_S("cannot register i2c-device. skipping.\n");
279 kfree(hexium);
280 return -EFAULT;
281 }
282
283
284 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
285
286 saa7146_write(dev, DD1_INIT, 0x07000700);
287 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
288 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
289
290
291 hexium->cur_input = 0;
292 hexium_init_done(dev);
293
294 hexium_set_standard(hexium, hexium_pal);
295 hexium->cur_std = V4L2_STD_PAL;
296
297 hexium_set_input(hexium, 0);
298 hexium->cur_input = 0;
299
300 saa7146_vv_init(dev, &vv_data);
301
302 vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
303 vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
304 vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
305 ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
306 if (ret < 0) {
307 pr_err("cannot register capture v4l2 device. skipping.\n");
308 return ret;
309 }
310
311 pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
312 hexium_num++;
313
314 return 0;
315}
316
317static int hexium_detach(struct saa7146_dev *dev)
318{
319 struct hexium *hexium = (struct hexium *) dev->ext_priv;
320
321 DEB_EE("dev:%p\n", dev);
322
323 saa7146_unregister_device(&hexium->video_dev, dev);
324 saa7146_vv_release(dev);
325
326 hexium_num--;
327
328 i2c_del_adapter(&hexium->i2c_adapter);
329 kfree(hexium);
330 return 0;
331}
332
333static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
334{
335 struct hexium *hexium = (struct hexium *) dev->ext_priv;
336
337 if (V4L2_STD_PAL == std->id) {
338 hexium_set_standard(hexium, hexium_pal);
339 hexium->cur_std = V4L2_STD_PAL;
340 return 0;
341 } else if (V4L2_STD_NTSC == std->id) {
342 hexium_set_standard(hexium, hexium_ntsc);
343 hexium->cur_std = V4L2_STD_NTSC;
344 return 0;
345 } else if (V4L2_STD_SECAM == std->id) {
346 hexium_set_standard(hexium, hexium_secam);
347 hexium->cur_std = V4L2_STD_SECAM;
348 return 0;
349 }
350
351 return -1;
352}
353
354static struct saa7146_extension hexium_extension;
355
356static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
357 .ext_priv = "Hexium Gemini (4 BNC)",
358 .ext = &hexium_extension,
359};
360
361static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
362 .ext_priv = "Hexium Gemini Dual (4 BNC)",
363 .ext = &hexium_extension,
364};
365
366static struct pci_device_id pci_tbl[] = {
367 {
368 .vendor = PCI_VENDOR_ID_PHILIPS,
369 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
370 .subvendor = 0x17c8,
371 .subdevice = 0x2401,
372 .driver_data = (unsigned long) &hexium_gemini_4bnc,
373 },
374 {
375 .vendor = PCI_VENDOR_ID_PHILIPS,
376 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
377 .subvendor = 0x17c8,
378 .subdevice = 0x2402,
379 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
380 },
381 {
382 .vendor = 0,
383 }
384};
385
386MODULE_DEVICE_TABLE(pci, pci_tbl);
387
388static struct saa7146_ext_vv vv_data = {
389 .inputs = HEXIUM_INPUTS,
390 .capabilities = 0,
391 .stds = &hexium_standards[0],
392 .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
393 .std_callback = &std_callback,
394};
395
396static struct saa7146_extension hexium_extension = {
397 .name = "hexium gemini",
398 .flags = SAA7146_USE_I2C_IRQ,
399
400 .pci_tbl = &pci_tbl[0],
401 .module = THIS_MODULE,
402
403 .attach = hexium_attach,
404 .detach = hexium_detach,
405
406 .irq_mask = 0,
407 .irq_func = NULL,
408};
409
410static int __init hexium_init_module(void)
411{
412 if (0 != saa7146_register_extension(&hexium_extension)) {
413 DEB_S("failed to register extension\n");
414 return -ENODEV;
415 }
416
417 return 0;
418}
419
420static void __exit hexium_cleanup_module(void)
421{
422 saa7146_unregister_extension(&hexium_extension);
423}
424
425module_init(hexium_init_module);
426module_exit(hexium_cleanup_module);
427
428MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
429MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
430MODULE_LICENSE("GPL");
431