• 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 	hexium->i2c_adapter = (struct i2c_adapter) {
236 		.name = "hexium orion",
237 	};
238 	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
239 	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
240 		DEB_S("cannot register i2c-device. skipping.\n");
241 		kfree(hexium);
242 		return -EFAULT;
243 	}
244 
245 	/* set SAA7110 control GPIO 0 */
246 	saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
247 	/*  set HWControl GPIO number 2 */
248 	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
249 
250 	mdelay(10);
251 
252 	/* detect newer Hexium Orion cards by subsystem ids */
253 	if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
254 		pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");
255 		/* we store the pointer in our private data field */
256 		dev->ext_priv = hexium;
257 		hexium->type = HEXIUM_ORION_1SVHS_3BNC;
258 		return 0;
259 	}
260 
261 	if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
262 		pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");
263 		/* we store the pointer in our private data field */
264 		dev->ext_priv = hexium;
265 		hexium->type = HEXIUM_ORION_4BNC;
266 		return 0;
267 	}
268 
269 	/* check if this is an old hexium Orion card by looking at
270 	   a saa7110 at address 0x4e */
271 	if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
272 		pr_info("device is a Hexium HV-PCI6/Orion (old)\n");
273 		/* we store the pointer in our private data field */
274 		dev->ext_priv = hexium;
275 		hexium->type = HEXIUM_HV_PCI6_ORION;
276 		return 0;
277 	}
278 
279 	i2c_del_adapter(&hexium->i2c_adapter);
280 	kfree(hexium);
281 	return -EFAULT;
282 }
283 
284 /* bring hardware to a sane state. this has to be done, just in case someone
285    wants to capture from this device before it has been properly initialized.
286    the capture engine would badly fail, because no valid signal arrives on the
287    saa7146, thus leading to timeouts and stuff. */
hexium_init_done(struct saa7146_dev * dev)288 static int hexium_init_done(struct saa7146_dev *dev)
289 {
290 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
291 	union i2c_smbus_data data;
292 	int i = 0;
293 
294 	DEB_D("hexium_init_done called\n");
295 
296 	/* initialize the helper ics to useful values */
297 	for (i = 0; i < sizeof(hexium_saa7110); i++) {
298 		data.byte = hexium_saa7110[i];
299 		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
300 			pr_err("failed for address 0x%02x\n", i);
301 		}
302 	}
303 
304 	return 0;
305 }
306 
hexium_set_input(struct hexium * hexium,int input)307 static int hexium_set_input(struct hexium *hexium, int input)
308 {
309 	union i2c_smbus_data data;
310 	int i = 0;
311 
312 	DEB_D("\n");
313 
314 	for (i = 0; i < 8; i++) {
315 		int adr = hexium_input_select[input].data[i].adr;
316 		data.byte = hexium_input_select[input].data[i].byte;
317 		if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
318 			return -1;
319 		}
320 		pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);
321 	}
322 
323 	return 0;
324 }
325 
vidioc_enum_input(struct file * file,void * fh,struct v4l2_input * i)326 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
327 {
328 	DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
329 
330 	if (i->index >= HEXIUM_INPUTS)
331 		return -EINVAL;
332 
333 	memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
334 
335 	DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
336 	return 0;
337 }
338 
vidioc_g_input(struct file * file,void * fh,unsigned int * input)339 static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
340 {
341 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
342 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
343 
344 	*input = hexium->cur_input;
345 
346 	DEB_D("VIDIOC_G_INPUT: %d\n", *input);
347 	return 0;
348 }
349 
vidioc_s_input(struct file * file,void * fh,unsigned int input)350 static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
351 {
352 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
353 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
354 
355 	if (input >= HEXIUM_INPUTS)
356 		return -EINVAL;
357 
358 	hexium->cur_input = input;
359 	hexium_set_input(hexium, input);
360 
361 	return 0;
362 }
363 
364 static struct saa7146_ext_vv vv_data;
365 
366 /* this function only gets called when the probing was successful */
hexium_attach(struct saa7146_dev * dev,struct saa7146_pci_extension_data * info)367 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
368 {
369 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
370 
371 	DEB_EE("\n");
372 
373 	saa7146_vv_init(dev, &vv_data);
374 	vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
375 	vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
376 	vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
377 	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
378 		pr_err("cannot register capture v4l2 device. skipping.\n");
379 		return -1;
380 	}
381 
382 	pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
383 	hexium_num++;
384 
385 	/* the rest */
386 	hexium->cur_input = 0;
387 	hexium_init_done(dev);
388 
389 	return 0;
390 }
391 
hexium_detach(struct saa7146_dev * dev)392 static int hexium_detach(struct saa7146_dev *dev)
393 {
394 	struct hexium *hexium = (struct hexium *) dev->ext_priv;
395 
396 	DEB_EE("dev:%p\n", dev);
397 
398 	saa7146_unregister_device(&hexium->video_dev, dev);
399 	saa7146_vv_release(dev);
400 
401 	hexium_num--;
402 
403 	i2c_del_adapter(&hexium->i2c_adapter);
404 	kfree(hexium);
405 	return 0;
406 }
407 
std_callback(struct saa7146_dev * dev,struct saa7146_standard * std)408 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
409 {
410 	return 0;
411 }
412 
413 static struct saa7146_extension extension;
414 
415 static struct saa7146_pci_extension_data hexium_hv_pci6 = {
416 	.ext_priv = "Hexium HV-PCI6 / Orion",
417 	.ext = &extension,
418 };
419 
420 static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
421 	.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
422 	.ext = &extension,
423 };
424 
425 static struct saa7146_pci_extension_data hexium_orion_4bnc = {
426 	.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
427 	.ext = &extension,
428 };
429 
430 static struct pci_device_id pci_tbl[] = {
431 	{
432 	 .vendor = PCI_VENDOR_ID_PHILIPS,
433 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
434 	 .subvendor = 0x0000,
435 	 .subdevice = 0x0000,
436 	 .driver_data = (unsigned long) &hexium_hv_pci6,
437 	 },
438 	{
439 	 .vendor = PCI_VENDOR_ID_PHILIPS,
440 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
441 	 .subvendor = 0x17c8,
442 	 .subdevice = 0x0101,
443 	 .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
444 	 },
445 	{
446 	 .vendor = PCI_VENDOR_ID_PHILIPS,
447 	 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
448 	 .subvendor = 0x17c8,
449 	 .subdevice = 0x2101,
450 	 .driver_data = (unsigned long) &hexium_orion_4bnc,
451 	 },
452 	{
453 	 .vendor = 0,
454 	 }
455 };
456 
457 MODULE_DEVICE_TABLE(pci, pci_tbl);
458 
459 static struct saa7146_ext_vv vv_data = {
460 	.inputs = HEXIUM_INPUTS,
461 	.capabilities = 0,
462 	.stds = &hexium_standards[0],
463 	.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
464 	.std_callback = &std_callback,
465 };
466 
467 static struct saa7146_extension extension = {
468 	.name = "hexium HV-PCI6 Orion",
469 	.flags = 0,		// SAA7146_USE_I2C_IRQ,
470 
471 	.pci_tbl = &pci_tbl[0],
472 	.module = THIS_MODULE,
473 
474 	.probe = hexium_probe,
475 	.attach = hexium_attach,
476 	.detach = hexium_detach,
477 
478 	.irq_mask = 0,
479 	.irq_func = NULL,
480 };
481 
hexium_init_module(void)482 static int __init hexium_init_module(void)
483 {
484 	if (0 != saa7146_register_extension(&extension)) {
485 		DEB_S("failed to register extension\n");
486 		return -ENODEV;
487 	}
488 
489 	return 0;
490 }
491 
hexium_cleanup_module(void)492 static void __exit hexium_cleanup_module(void)
493 {
494 	saa7146_unregister_extension(&extension);
495 }
496 
497 module_init(hexium_init_module);
498 module_exit(hexium_cleanup_module);
499 
500 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
501 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
502 MODULE_LICENSE("GPL");
503