Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/hexium_gemini.c
17540 views
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 <[email protected]>
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;
29
module_param(debug, int, 0);
30
MODULE_PARM_DESC(debug, "debug verbosity");
31
32
/* global variables */
33
static int hexium_num;
34
35
#define HEXIUM_GEMINI 4
36
#define HEXIUM_GEMINI_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, V4L2_IN_CAP_STD },
41
{ 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
42
{ 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
43
{ 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
44
{ 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
45
{ 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
46
{ 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
47
{ 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
48
{ 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
49
};
50
51
#define HEXIUM_AUDIOS 0
52
53
struct hexium_data
54
{
55
s8 adr;
56
u8 byte;
57
};
58
59
#define HEXIUM_CONTROLS 1
60
static struct v4l2_queryctrl hexium_controls[] = {
61
{ V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
62
};
63
64
#define HEXIUM_GEMINI_V_1_0 1
65
#define HEXIUM_GEMINI_DUAL_V_1_0 2
66
67
struct hexium
68
{
69
int type;
70
71
struct video_device *video_dev;
72
struct i2c_adapter i2c_adapter;
73
74
int cur_input; /* current input */
75
v4l2_std_id cur_std; /* current standard */
76
int cur_bw; /* current black/white status */
77
};
78
79
/* Samsung KS0127B decoder default registers */
80
static u8 hexium_ks0127b[0x100]={
81
/*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
82
/*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
83
/*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
84
/*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
85
/*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
86
/*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
87
/*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
88
/*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
89
/*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90
/*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
91
/*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
92
/*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
93
/*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
94
/*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
95
/*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96
/*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97
/*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98
/*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99
/*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100
/*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101
/*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102
/*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103
/*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104
/*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105
/*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106
/*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107
/*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108
/*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109
/*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
110
/*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
111
/*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
112
/*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
113
};
114
115
static struct hexium_data hexium_pal[] = {
116
{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
117
};
118
119
static struct hexium_data hexium_pal_bw[] = {
120
{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
121
};
122
123
static struct hexium_data hexium_ntsc[] = {
124
{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
125
};
126
127
static struct hexium_data hexium_ntsc_bw[] = {
128
{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
129
};
130
131
static struct hexium_data hexium_secam[] = {
132
{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
133
};
134
135
static struct hexium_data hexium_input_select[] = {
136
{ 0x02, 0x60 },
137
{ 0x02, 0x64 },
138
{ 0x02, 0x61 },
139
{ 0x02, 0x65 },
140
{ 0x02, 0x62 },
141
{ 0x02, 0x66 },
142
{ 0x02, 0x68 },
143
{ 0x02, 0x69 },
144
{ 0x02, 0x6A },
145
};
146
147
/* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
148
are currently *not* supported*/
149
static struct saa7146_standard hexium_standards[] = {
150
{
151
.name = "PAL", .id = V4L2_STD_PAL,
152
.v_offset = 28, .v_field = 288,
153
.h_offset = 1, .h_pixels = 680,
154
.v_max_out = 576, .h_max_out = 768,
155
}, {
156
.name = "NTSC", .id = V4L2_STD_NTSC,
157
.v_offset = 28, .v_field = 240,
158
.h_offset = 1, .h_pixels = 640,
159
.v_max_out = 480, .h_max_out = 640,
160
}, {
161
.name = "SECAM", .id = V4L2_STD_SECAM,
162
.v_offset = 28, .v_field = 288,
163
.h_offset = 1, .h_pixels = 720,
164
.v_max_out = 576, .h_max_out = 768,
165
}
166
};
167
168
/* bring hardware to a sane state. this has to be done, just in case someone
169
wants to capture from this device before it has been properly initialized.
170
the capture engine would badly fail, because no valid signal arrives on the
171
saa7146, thus leading to timeouts and stuff. */
172
static int hexium_init_done(struct saa7146_dev *dev)
173
{
174
struct hexium *hexium = (struct hexium *) dev->ext_priv;
175
union i2c_smbus_data data;
176
int i = 0;
177
178
DEB_D(("hexium_init_done called.\n"));
179
180
/* initialize the helper ics to useful values */
181
for (i = 0; i < sizeof(hexium_ks0127b); i++) {
182
data.byte = hexium_ks0127b[i];
183
if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
184
printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i);
185
}
186
}
187
188
return 0;
189
}
190
191
static int hexium_set_input(struct hexium *hexium, int input)
192
{
193
union i2c_smbus_data data;
194
195
DEB_D((".\n"));
196
197
data.byte = hexium_input_select[input].byte;
198
if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
199
return -1;
200
}
201
202
return 0;
203
}
204
205
static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
206
{
207
union i2c_smbus_data data;
208
int i = 0;
209
210
DEB_D((".\n"));
211
212
while (vdec[i].adr != -1) {
213
data.byte = vdec[i].byte;
214
if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
215
printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i);
216
return -1;
217
}
218
i++;
219
}
220
return 0;
221
}
222
223
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
224
{
225
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
226
227
if (i->index >= HEXIUM_INPUTS)
228
return -EINVAL;
229
230
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
231
232
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
233
return 0;
234
}
235
236
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
237
{
238
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
239
struct hexium *hexium = (struct hexium *) dev->ext_priv;
240
241
*input = hexium->cur_input;
242
243
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
244
return 0;
245
}
246
247
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
248
{
249
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
250
struct hexium *hexium = (struct hexium *) dev->ext_priv;
251
252
DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
253
254
if (input >= HEXIUM_INPUTS)
255
return -EINVAL;
256
257
hexium->cur_input = input;
258
hexium_set_input(hexium, input);
259
return 0;
260
}
261
262
/* the saa7146 provides some controls (brightness, contrast, saturation)
263
which gets registered *after* this function. because of this we have
264
to return with a value != 0 even if the function succeeded.. */
265
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
266
{
267
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
268
int i;
269
270
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
271
if (hexium_controls[i].id == qc->id) {
272
*qc = hexium_controls[i];
273
DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
274
return 0;
275
}
276
}
277
return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
278
}
279
280
static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
281
{
282
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
283
struct hexium *hexium = (struct hexium *) dev->ext_priv;
284
int i;
285
286
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
287
if (hexium_controls[i].id == vc->id)
288
break;
289
}
290
291
if (i < 0)
292
return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
293
294
if (vc->id == V4L2_CID_PRIVATE_BASE) {
295
vc->value = hexium->cur_bw;
296
DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
297
return 0;
298
}
299
return -EINVAL;
300
}
301
302
static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
303
{
304
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
305
struct hexium *hexium = (struct hexium *) dev->ext_priv;
306
int i = 0;
307
308
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
309
if (hexium_controls[i].id == vc->id)
310
break;
311
}
312
313
if (i < 0)
314
return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
315
316
if (vc->id == V4L2_CID_PRIVATE_BASE)
317
hexium->cur_bw = vc->value;
318
319
DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
320
321
if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
322
hexium_set_standard(hexium, hexium_pal);
323
return 0;
324
}
325
if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
326
hexium_set_standard(hexium, hexium_ntsc);
327
return 0;
328
}
329
if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
330
hexium_set_standard(hexium, hexium_secam);
331
return 0;
332
}
333
if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
334
hexium_set_standard(hexium, hexium_pal_bw);
335
return 0;
336
}
337
if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
338
hexium_set_standard(hexium, hexium_ntsc_bw);
339
return 0;
340
}
341
if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
342
/* fixme: is there no bw secam mode? */
343
return -EINVAL;
344
345
return -EINVAL;
346
}
347
348
349
static struct saa7146_ext_vv vv_data;
350
351
/* this function only gets called when the probing was successful */
352
static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
353
{
354
struct hexium *hexium = (struct hexium *) dev->ext_priv;
355
int ret;
356
357
DEB_EE((".\n"));
358
359
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
360
if (NULL == hexium) {
361
printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
362
return -ENOMEM;
363
}
364
dev->ext_priv = hexium;
365
366
/* enable i2c-port pins */
367
saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
368
369
hexium->i2c_adapter = (struct i2c_adapter) {
370
.name = "hexium gemini",
371
};
372
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
373
if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
374
DEB_S(("cannot register i2c-device. skipping.\n"));
375
kfree(hexium);
376
return -EFAULT;
377
}
378
379
/* set HWControl GPIO number 2 */
380
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
381
382
saa7146_write(dev, DD1_INIT, 0x07000700);
383
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
384
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
385
386
/* the rest */
387
hexium->cur_input = 0;
388
hexium_init_done(dev);
389
390
hexium_set_standard(hexium, hexium_pal);
391
hexium->cur_std = V4L2_STD_PAL;
392
393
hexium_set_input(hexium, 0);
394
hexium->cur_input = 0;
395
396
saa7146_vv_init(dev, &vv_data);
397
vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
398
vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
399
vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
400
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
401
vv_data.ops.vidioc_g_input = vidioc_g_input;
402
vv_data.ops.vidioc_s_input = vidioc_s_input;
403
ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
404
if (ret < 0) {
405
printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
406
return ret;
407
}
408
409
printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
410
hexium_num++;
411
412
return 0;
413
}
414
415
static int hexium_detach(struct saa7146_dev *dev)
416
{
417
struct hexium *hexium = (struct hexium *) dev->ext_priv;
418
419
DEB_EE(("dev:%p\n", dev));
420
421
saa7146_unregister_device(&hexium->video_dev, dev);
422
saa7146_vv_release(dev);
423
424
hexium_num--;
425
426
i2c_del_adapter(&hexium->i2c_adapter);
427
kfree(hexium);
428
return 0;
429
}
430
431
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
432
{
433
struct hexium *hexium = (struct hexium *) dev->ext_priv;
434
435
if (V4L2_STD_PAL == std->id) {
436
hexium_set_standard(hexium, hexium_pal);
437
hexium->cur_std = V4L2_STD_PAL;
438
return 0;
439
} else if (V4L2_STD_NTSC == std->id) {
440
hexium_set_standard(hexium, hexium_ntsc);
441
hexium->cur_std = V4L2_STD_NTSC;
442
return 0;
443
} else if (V4L2_STD_SECAM == std->id) {
444
hexium_set_standard(hexium, hexium_secam);
445
hexium->cur_std = V4L2_STD_SECAM;
446
return 0;
447
}
448
449
return -1;
450
}
451
452
static struct saa7146_extension hexium_extension;
453
454
static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
455
.ext_priv = "Hexium Gemini (4 BNC)",
456
.ext = &hexium_extension,
457
};
458
459
static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
460
.ext_priv = "Hexium Gemini Dual (4 BNC)",
461
.ext = &hexium_extension,
462
};
463
464
static struct pci_device_id pci_tbl[] = {
465
{
466
.vendor = PCI_VENDOR_ID_PHILIPS,
467
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
468
.subvendor = 0x17c8,
469
.subdevice = 0x2401,
470
.driver_data = (unsigned long) &hexium_gemini_4bnc,
471
},
472
{
473
.vendor = PCI_VENDOR_ID_PHILIPS,
474
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
475
.subvendor = 0x17c8,
476
.subdevice = 0x2402,
477
.driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
478
},
479
{
480
.vendor = 0,
481
}
482
};
483
484
MODULE_DEVICE_TABLE(pci, pci_tbl);
485
486
static struct saa7146_ext_vv vv_data = {
487
.inputs = HEXIUM_INPUTS,
488
.capabilities = 0,
489
.stds = &hexium_standards[0],
490
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
491
.std_callback = &std_callback,
492
};
493
494
static struct saa7146_extension hexium_extension = {
495
.name = "hexium gemini",
496
.flags = SAA7146_USE_I2C_IRQ,
497
498
.pci_tbl = &pci_tbl[0],
499
.module = THIS_MODULE,
500
501
.attach = hexium_attach,
502
.detach = hexium_detach,
503
504
.irq_mask = 0,
505
.irq_func = NULL,
506
};
507
508
static int __init hexium_init_module(void)
509
{
510
if (0 != saa7146_register_extension(&hexium_extension)) {
511
DEB_S(("failed to register extension.\n"));
512
return -ENODEV;
513
}
514
515
return 0;
516
}
517
518
static void __exit hexium_cleanup_module(void)
519
{
520
saa7146_unregister_extension(&hexium_extension);
521
}
522
523
module_init(hexium_init_module);
524
module_exit(hexium_cleanup_module);
525
526
MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
527
MODULE_AUTHOR("Michael Hunold <[email protected]>");
528
MODULE_LICENSE("GPL");
529
530