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