Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hexium_orion.c
Go to the documentation of this file.
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 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 */
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 */
230 
231  saa7146_write(dev, DD1_INIT, 0x01000100);
232  saa7146_write(dev, DD1_STREAM_B, 0x00000000);
234 
235  hexium->i2c_adapter = (struct i2c_adapter) {
236  .name = "hexium orion",
237  };
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 */
247  /* set HWControl GPIO number 2 */
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. */
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 
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 
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 
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 
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 */
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 
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 
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,
434  .subvendor = 0x0000,
435  .subdevice = 0x0000,
436  .driver_data = (unsigned long) &hexium_hv_pci6,
437  },
438  {
439  .vendor = PCI_VENDOR_ID_PHILIPS,
441  .subvendor = 0x17c8,
442  .subdevice = 0x0101,
443  .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
444  },
445  {
446  .vendor = PCI_VENDOR_ID_PHILIPS,
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 
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 
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 <[email protected]>");
502 MODULE_LICENSE("GPL");