Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/hexium_orion.c
17602 views
1
/*
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.
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_HV_PCI6_ORION 1
36
#define HEXIUM_ORION_1SVHS_3BNC 2
37
#define HEXIUM_ORION_4BNC 3
38
39
#define HEXIUM_INPUTS 9
40
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
41
{ 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
42
{ 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
43
{ 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
44
{ 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
45
{ 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
46
{ 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
47
{ 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
48
{ 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
49
{ 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
50
};
51
52
#define HEXIUM_AUDIOS 0
53
54
struct hexium_data
55
{
56
s8 adr;
57
u8 byte;
58
};
59
60
struct hexium
61
{
62
int type;
63
struct video_device *video_dev;
64
struct i2c_adapter i2c_adapter;
65
66
int cur_input; /* current input */
67
};
68
69
/* Philips SAA7110 decoder default registers */
70
static u8 hexium_saa7110[53]={
71
/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
72
/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
73
/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
74
/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
75
/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
76
/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
77
/*30*/ 0x44,0x75,0x01,0x8C,0x03
78
};
79
80
static struct {
81
struct hexium_data data[8];
82
} hexium_input_select[] = {
83
{
84
{ /* cvbs 1 */
85
{ 0x06, 0x00 },
86
{ 0x20, 0xD9 },
87
{ 0x21, 0x17 }, // 0x16,
88
{ 0x22, 0x40 },
89
{ 0x2C, 0x03 },
90
{ 0x30, 0x44 },
91
{ 0x31, 0x75 }, // ??
92
{ 0x21, 0x16 }, // 0x03,
93
}
94
}, {
95
{ /* cvbs 2 */
96
{ 0x06, 0x00 },
97
{ 0x20, 0x78 },
98
{ 0x21, 0x07 }, // 0x03,
99
{ 0x22, 0xD2 },
100
{ 0x2C, 0x83 },
101
{ 0x30, 0x60 },
102
{ 0x31, 0xB5 }, // ?
103
{ 0x21, 0x03 },
104
}
105
}, {
106
{ /* cvbs 3 */
107
{ 0x06, 0x00 },
108
{ 0x20, 0xBA },
109
{ 0x21, 0x07 }, // 0x05,
110
{ 0x22, 0x91 },
111
{ 0x2C, 0x03 },
112
{ 0x30, 0x60 },
113
{ 0x31, 0xB5 }, // ??
114
{ 0x21, 0x05 }, // 0x03,
115
}
116
}, {
117
{ /* cvbs 4 */
118
{ 0x06, 0x00 },
119
{ 0x20, 0xD8 },
120
{ 0x21, 0x17 }, // 0x16,
121
{ 0x22, 0x40 },
122
{ 0x2C, 0x03 },
123
{ 0x30, 0x44 },
124
{ 0x31, 0x75 }, // ??
125
{ 0x21, 0x16 }, // 0x03,
126
}
127
}, {
128
{ /* cvbs 5 */
129
{ 0x06, 0x00 },
130
{ 0x20, 0xB8 },
131
{ 0x21, 0x07 }, // 0x05,
132
{ 0x22, 0x91 },
133
{ 0x2C, 0x03 },
134
{ 0x30, 0x60 },
135
{ 0x31, 0xB5 }, // ??
136
{ 0x21, 0x05 }, // 0x03,
137
}
138
}, {
139
{ /* cvbs 6 */
140
{ 0x06, 0x00 },
141
{ 0x20, 0x7C },
142
{ 0x21, 0x07 }, // 0x03
143
{ 0x22, 0xD2 },
144
{ 0x2C, 0x83 },
145
{ 0x30, 0x60 },
146
{ 0x31, 0xB5 }, // ??
147
{ 0x21, 0x03 },
148
}
149
}, {
150
{ /* y/c 1 */
151
{ 0x06, 0x80 },
152
{ 0x20, 0x59 },
153
{ 0x21, 0x17 },
154
{ 0x22, 0x42 },
155
{ 0x2C, 0xA3 },
156
{ 0x30, 0x44 },
157
{ 0x31, 0x75 },
158
{ 0x21, 0x12 },
159
}
160
}, {
161
{ /* y/c 2 */
162
{ 0x06, 0x80 },
163
{ 0x20, 0x9A },
164
{ 0x21, 0x17 },
165
{ 0x22, 0xB1 },
166
{ 0x2C, 0x13 },
167
{ 0x30, 0x60 },
168
{ 0x31, 0xB5 },
169
{ 0x21, 0x14 },
170
}
171
}, {
172
{ /* y/c 3 */
173
{ 0x06, 0x80 },
174
{ 0x20, 0x3C },
175
{ 0x21, 0x27 },
176
{ 0x22, 0xC1 },
177
{ 0x2C, 0x23 },
178
{ 0x30, 0x44 },
179
{ 0x31, 0x75 },
180
{ 0x21, 0x21 },
181
}
182
}
183
};
184
185
static struct saa7146_standard hexium_standards[] = {
186
{
187
.name = "PAL", .id = V4L2_STD_PAL,
188
.v_offset = 16, .v_field = 288,
189
.h_offset = 1, .h_pixels = 680,
190
.v_max_out = 576, .h_max_out = 768,
191
}, {
192
.name = "NTSC", .id = V4L2_STD_NTSC,
193
.v_offset = 16, .v_field = 240,
194
.h_offset = 1, .h_pixels = 640,
195
.v_max_out = 480, .h_max_out = 640,
196
}, {
197
.name = "SECAM", .id = V4L2_STD_SECAM,
198
.v_offset = 16, .v_field = 288,
199
.h_offset = 1, .h_pixels = 720,
200
.v_max_out = 576, .h_max_out = 768,
201
}
202
};
203
204
/* this is only called for old HV-PCI6/Orion cards
205
without eeprom */
206
static int hexium_probe(struct saa7146_dev *dev)
207
{
208
struct hexium *hexium = NULL;
209
union i2c_smbus_data data;
210
int err = 0;
211
212
DEB_EE((".\n"));
213
214
/* there are no hexium orion cards with revision 0 saa7146s */
215
if (0 == dev->revision) {
216
return -EFAULT;
217
}
218
219
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
220
if (NULL == hexium) {
221
printk("hexium_orion: hexium_probe: not enough kernel memory.\n");
222
return -ENOMEM;
223
}
224
225
/* enable i2c-port pins */
226
saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
227
228
saa7146_write(dev, DD1_INIT, 0x01000100);
229
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
230
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
231
232
hexium->i2c_adapter = (struct i2c_adapter) {
233
.name = "hexium orion",
234
};
235
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
236
if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
237
DEB_S(("cannot register i2c-device. skipping.\n"));
238
kfree(hexium);
239
return -EFAULT;
240
}
241
242
/* set SAA7110 control GPIO 0 */
243
saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
244
/* set HWControl GPIO number 2 */
245
saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
246
247
mdelay(10);
248
249
/* detect newer Hexium Orion cards by subsystem ids */
250
if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
251
printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n");
252
/* we store the pointer in our private data field */
253
dev->ext_priv = hexium;
254
hexium->type = HEXIUM_ORION_1SVHS_3BNC;
255
return 0;
256
}
257
258
if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
259
printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n");
260
/* we store the pointer in our private data field */
261
dev->ext_priv = hexium;
262
hexium->type = HEXIUM_ORION_4BNC;
263
return 0;
264
}
265
266
/* check if this is an old hexium Orion card by looking at
267
a saa7110 at address 0x4e */
268
if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
269
printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
270
/* we store the pointer in our private data field */
271
dev->ext_priv = hexium;
272
hexium->type = HEXIUM_HV_PCI6_ORION;
273
return 0;
274
}
275
276
i2c_del_adapter(&hexium->i2c_adapter);
277
kfree(hexium);
278
return -EFAULT;
279
}
280
281
/* bring hardware to a sane state. this has to be done, just in case someone
282
wants to capture from this device before it has been properly initialized.
283
the capture engine would badly fail, because no valid signal arrives on the
284
saa7146, thus leading to timeouts and stuff. */
285
static int hexium_init_done(struct saa7146_dev *dev)
286
{
287
struct hexium *hexium = (struct hexium *) dev->ext_priv;
288
union i2c_smbus_data data;
289
int i = 0;
290
291
DEB_D(("hexium_init_done called.\n"));
292
293
/* initialize the helper ics to useful values */
294
for (i = 0; i < sizeof(hexium_saa7110); i++) {
295
data.byte = hexium_saa7110[i];
296
if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
297
printk("hexium_orion: failed for address 0x%02x\n", i);
298
}
299
}
300
301
return 0;
302
}
303
304
static int hexium_set_input(struct hexium *hexium, int input)
305
{
306
union i2c_smbus_data data;
307
int i = 0;
308
309
DEB_D((".\n"));
310
311
for (i = 0; i < 8; i++) {
312
int adr = hexium_input_select[input].data[i].adr;
313
data.byte = hexium_input_select[input].data[i].byte;
314
if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
315
return -1;
316
}
317
printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte);
318
}
319
320
return 0;
321
}
322
323
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
324
{
325
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
326
327
if (i->index >= HEXIUM_INPUTS)
328
return -EINVAL;
329
330
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
331
332
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
333
return 0;
334
}
335
336
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
337
{
338
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
339
struct hexium *hexium = (struct hexium *) dev->ext_priv;
340
341
*input = hexium->cur_input;
342
343
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
344
return 0;
345
}
346
347
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
348
{
349
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
350
struct hexium *hexium = (struct hexium *) dev->ext_priv;
351
352
if (input >= HEXIUM_INPUTS)
353
return -EINVAL;
354
355
hexium->cur_input = input;
356
hexium_set_input(hexium, input);
357
358
return 0;
359
}
360
361
static struct saa7146_ext_vv vv_data;
362
363
/* this function only gets called when the probing was successful */
364
static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
365
{
366
struct hexium *hexium = (struct hexium *) dev->ext_priv;
367
368
DEB_EE((".\n"));
369
370
saa7146_vv_init(dev, &vv_data);
371
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
372
vv_data.ops.vidioc_g_input = vidioc_g_input;
373
vv_data.ops.vidioc_s_input = vidioc_s_input;
374
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
375
printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
376
return -1;
377
}
378
379
printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num);
380
hexium_num++;
381
382
/* the rest */
383
hexium->cur_input = 0;
384
hexium_init_done(dev);
385
386
return 0;
387
}
388
389
static int hexium_detach(struct saa7146_dev *dev)
390
{
391
struct hexium *hexium = (struct hexium *) dev->ext_priv;
392
393
DEB_EE(("dev:%p\n", dev));
394
395
saa7146_unregister_device(&hexium->video_dev, dev);
396
saa7146_vv_release(dev);
397
398
hexium_num--;
399
400
i2c_del_adapter(&hexium->i2c_adapter);
401
kfree(hexium);
402
return 0;
403
}
404
405
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
406
{
407
return 0;
408
}
409
410
static struct saa7146_extension extension;
411
412
static struct saa7146_pci_extension_data hexium_hv_pci6 = {
413
.ext_priv = "Hexium HV-PCI6 / Orion",
414
.ext = &extension,
415
};
416
417
static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
418
.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
419
.ext = &extension,
420
};
421
422
static struct saa7146_pci_extension_data hexium_orion_4bnc = {
423
.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
424
.ext = &extension,
425
};
426
427
static struct pci_device_id pci_tbl[] = {
428
{
429
.vendor = PCI_VENDOR_ID_PHILIPS,
430
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
431
.subvendor = 0x0000,
432
.subdevice = 0x0000,
433
.driver_data = (unsigned long) &hexium_hv_pci6,
434
},
435
{
436
.vendor = PCI_VENDOR_ID_PHILIPS,
437
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
438
.subvendor = 0x17c8,
439
.subdevice = 0x0101,
440
.driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
441
},
442
{
443
.vendor = PCI_VENDOR_ID_PHILIPS,
444
.device = PCI_DEVICE_ID_PHILIPS_SAA7146,
445
.subvendor = 0x17c8,
446
.subdevice = 0x2101,
447
.driver_data = (unsigned long) &hexium_orion_4bnc,
448
},
449
{
450
.vendor = 0,
451
}
452
};
453
454
MODULE_DEVICE_TABLE(pci, pci_tbl);
455
456
static struct saa7146_ext_vv vv_data = {
457
.inputs = HEXIUM_INPUTS,
458
.capabilities = 0,
459
.stds = &hexium_standards[0],
460
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
461
.std_callback = &std_callback,
462
};
463
464
static struct saa7146_extension extension = {
465
.name = "hexium HV-PCI6 Orion",
466
.flags = 0, // SAA7146_USE_I2C_IRQ,
467
468
.pci_tbl = &pci_tbl[0],
469
.module = THIS_MODULE,
470
471
.probe = hexium_probe,
472
.attach = hexium_attach,
473
.detach = hexium_detach,
474
475
.irq_mask = 0,
476
.irq_func = NULL,
477
};
478
479
static int __init hexium_init_module(void)
480
{
481
if (0 != saa7146_register_extension(&extension)) {
482
DEB_S(("failed to register extension.\n"));
483
return -ENODEV;
484
}
485
486
return 0;
487
}
488
489
static void __exit hexium_cleanup_module(void)
490
{
491
saa7146_unregister_extension(&extension);
492
}
493
494
module_init(hexium_init_module);
495
module_exit(hexium_cleanup_module);
496
497
MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
498
MODULE_AUTHOR("Michael Hunold <[email protected]>");
499
MODULE_LICENSE("GPL");
500
501