Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hexium_gemini.c
Go to the documentation of this file.
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 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_GEMINI 4
39 #define HEXIUM_GEMINI_DUAL 5
40 
41 #define HEXIUM_INPUTS 9
42 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
43  { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
44  { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
45  { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
46  { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
47  { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
48  { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
49  { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
50  { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
51  { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
52 };
53 
54 #define HEXIUM_AUDIOS 0
55 
57 {
60 };
61 
62 #define HEXIUM_GEMINI_V_1_0 1
63 #define HEXIUM_GEMINI_DUAL_V_1_0 2
64 
65 struct hexium
66 {
67  int type;
68 
71 
72  int cur_input; /* current input */
73  v4l2_std_id cur_std; /* current standard */
74 };
75 
76 /* Samsung KS0127B decoder default registers */
77 static u8 hexium_ks0127b[0x100]={
78 /*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
79 /*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
80 /*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
81 /*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
82 /*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
83 /*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
84 /*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
85 /*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
86 /*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
87 /*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
88 /*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
89 /*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
90 /*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
91 /*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
92 /*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
93 /*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
94 /*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
95 /*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
96 /*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
97 /*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
98 /*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
99 /*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
100 /*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
101 /*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
102 /*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
103 /*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
104 /*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
105 /*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
106 /*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
107 /*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
108 /*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
109 /*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
110 };
111 
112 static struct hexium_data hexium_pal[] = {
113  { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
114 };
115 
116 static struct hexium_data hexium_ntsc[] = {
117  { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
118 };
119 
120 static struct hexium_data hexium_secam[] = {
121  { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
122 };
123 
124 static struct hexium_data hexium_input_select[] = {
125  { 0x02, 0x60 },
126  { 0x02, 0x64 },
127  { 0x02, 0x61 },
128  { 0x02, 0x65 },
129  { 0x02, 0x62 },
130  { 0x02, 0x66 },
131  { 0x02, 0x68 },
132  { 0x02, 0x69 },
133  { 0x02, 0x6A },
134 };
135 
136 /* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
137  are currently *not* supported*/
138 static struct saa7146_standard hexium_standards[] = {
139  {
140  .name = "PAL", .id = V4L2_STD_PAL,
141  .v_offset = 28, .v_field = 288,
142  .h_offset = 1, .h_pixels = 680,
143  .v_max_out = 576, .h_max_out = 768,
144  }, {
145  .name = "NTSC", .id = V4L2_STD_NTSC,
146  .v_offset = 28, .v_field = 240,
147  .h_offset = 1, .h_pixels = 640,
148  .v_max_out = 480, .h_max_out = 640,
149  }, {
150  .name = "SECAM", .id = V4L2_STD_SECAM,
151  .v_offset = 28, .v_field = 288,
152  .h_offset = 1, .h_pixels = 720,
153  .v_max_out = 576, .h_max_out = 768,
154  }
155 };
156 
157 /* bring hardware to a sane state. this has to be done, just in case someone
158  wants to capture from this device before it has been properly initialized.
159  the capture engine would badly fail, because no valid signal arrives on the
160  saa7146, thus leading to timeouts and stuff. */
161 static int hexium_init_done(struct saa7146_dev *dev)
162 {
163  struct hexium *hexium = (struct hexium *) dev->ext_priv;
164  union i2c_smbus_data data;
165  int i = 0;
166 
167  DEB_D("hexium_init_done called\n");
168 
169  /* initialize the helper ics to useful values */
170  for (i = 0; i < sizeof(hexium_ks0127b); i++) {
171  data.byte = hexium_ks0127b[i];
172  if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
173  pr_err("hexium_init_done() failed for address 0x%02x\n",
174  i);
175  }
176  }
177 
178  return 0;
179 }
180 
181 static int hexium_set_input(struct hexium *hexium, int input)
182 {
183  union i2c_smbus_data data;
184 
185  DEB_D("\n");
186 
187  data.byte = hexium_input_select[input].byte;
188  if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
189  return -1;
190  }
191 
192  return 0;
193 }
194 
195 static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
196 {
197  union i2c_smbus_data data;
198  int i = 0;
199 
200  DEB_D("\n");
201 
202  while (vdec[i].adr != -1) {
203  data.byte = vdec[i].byte;
204  if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
205  pr_err("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n",
206  i);
207  return -1;
208  }
209  i++;
210  }
211  return 0;
212 }
213 
214 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
215 {
216  DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
217 
218  if (i->index >= HEXIUM_INPUTS)
219  return -EINVAL;
220 
221  memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
222 
223  DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
224  return 0;
225 }
226 
227 static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
228 {
229  struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
230  struct hexium *hexium = (struct hexium *) dev->ext_priv;
231 
232  *input = hexium->cur_input;
233 
234  DEB_D("VIDIOC_G_INPUT: %d\n", *input);
235  return 0;
236 }
237 
238 static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
239 {
240  struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
241  struct hexium *hexium = (struct hexium *) dev->ext_priv;
242 
243  DEB_EE("VIDIOC_S_INPUT %d\n", input);
244 
245  if (input >= HEXIUM_INPUTS)
246  return -EINVAL;
247 
248  hexium->cur_input = input;
249  hexium_set_input(hexium, input);
250  return 0;
251 }
252 
253 static struct saa7146_ext_vv vv_data;
254 
255 /* this function only gets called when the probing was successful */
256 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
257 {
258  struct hexium *hexium;
259  int ret;
260 
261  DEB_EE("\n");
262 
263  hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
264  if (NULL == hexium) {
265  pr_err("not enough kernel memory in hexium_attach()\n");
266  return -ENOMEM;
267  }
268  dev->ext_priv = hexium;
269 
270  /* enable i2c-port pins */
272 
273  hexium->i2c_adapter = (struct i2c_adapter) {
274  .name = "hexium gemini",
275  };
277  if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
278  DEB_S("cannot register i2c-device. skipping.\n");
279  kfree(hexium);
280  return -EFAULT;
281  }
282 
283  /* set HWControl GPIO number 2 */
285 
286  saa7146_write(dev, DD1_INIT, 0x07000700);
287  saa7146_write(dev, DD1_STREAM_B, 0x00000000);
289 
290  /* the rest */
291  hexium->cur_input = 0;
292  hexium_init_done(dev);
293 
294  hexium_set_standard(hexium, hexium_pal);
295  hexium->cur_std = V4L2_STD_PAL;
296 
297  hexium_set_input(hexium, 0);
298  hexium->cur_input = 0;
299 
300  saa7146_vv_init(dev, &vv_data);
301 
302  vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
303  vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
304  vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
305  ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
306  if (ret < 0) {
307  pr_err("cannot register capture v4l2 device. skipping.\n");
308  return ret;
309  }
310 
311  pr_info("found 'hexium gemini' frame grabber-%d\n", hexium_num);
312  hexium_num++;
313 
314  return 0;
315 }
316 
317 static int hexium_detach(struct saa7146_dev *dev)
318 {
319  struct hexium *hexium = (struct hexium *) dev->ext_priv;
320 
321  DEB_EE("dev:%p\n", dev);
322 
323  saa7146_unregister_device(&hexium->video_dev, dev);
324  saa7146_vv_release(dev);
325 
326  hexium_num--;
327 
328  i2c_del_adapter(&hexium->i2c_adapter);
329  kfree(hexium);
330  return 0;
331 }
332 
333 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
334 {
335  struct hexium *hexium = (struct hexium *) dev->ext_priv;
336 
337  if (V4L2_STD_PAL == std->id) {
338  hexium_set_standard(hexium, hexium_pal);
339  hexium->cur_std = V4L2_STD_PAL;
340  return 0;
341  } else if (V4L2_STD_NTSC == std->id) {
342  hexium_set_standard(hexium, hexium_ntsc);
343  hexium->cur_std = V4L2_STD_NTSC;
344  return 0;
345  } else if (V4L2_STD_SECAM == std->id) {
346  hexium_set_standard(hexium, hexium_secam);
347  hexium->cur_std = V4L2_STD_SECAM;
348  return 0;
349  }
350 
351  return -1;
352 }
353 
354 static struct saa7146_extension hexium_extension;
355 
356 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
357  .ext_priv = "Hexium Gemini (4 BNC)",
358  .ext = &hexium_extension,
359 };
360 
361 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
362  .ext_priv = "Hexium Gemini Dual (4 BNC)",
363  .ext = &hexium_extension,
364 };
365 
366 static struct pci_device_id pci_tbl[] = {
367  {
368  .vendor = PCI_VENDOR_ID_PHILIPS,
370  .subvendor = 0x17c8,
371  .subdevice = 0x2401,
372  .driver_data = (unsigned long) &hexium_gemini_4bnc,
373  },
374  {
375  .vendor = PCI_VENDOR_ID_PHILIPS,
377  .subvendor = 0x17c8,
378  .subdevice = 0x2402,
379  .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
380  },
381  {
382  .vendor = 0,
383  }
384 };
385 
386 MODULE_DEVICE_TABLE(pci, pci_tbl);
387 
388 static struct saa7146_ext_vv vv_data = {
389  .inputs = HEXIUM_INPUTS,
390  .capabilities = 0,
391  .stds = &hexium_standards[0],
392  .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
393  .std_callback = &std_callback,
394 };
395 
396 static struct saa7146_extension hexium_extension = {
397  .name = "hexium gemini",
398  .flags = SAA7146_USE_I2C_IRQ,
399 
400  .pci_tbl = &pci_tbl[0],
401  .module = THIS_MODULE,
402 
403  .attach = hexium_attach,
404  .detach = hexium_detach,
405 
406  .irq_mask = 0,
407  .irq_func = NULL,
408 };
409 
410 static int __init hexium_init_module(void)
411 {
412  if (0 != saa7146_register_extension(&hexium_extension)) {
413  DEB_S("failed to register extension\n");
414  return -ENODEV;
415  }
416 
417  return 0;
418 }
419 
420 static void __exit hexium_cleanup_module(void)
421 {
422  saa7146_unregister_extension(&hexium_extension);
423 }
424 
425 module_init(hexium_init_module);
426 module_exit(hexium_cleanup_module);
427 
428 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
429 MODULE_AUTHOR("Michael Hunold <[email protected]>");
430 MODULE_LICENSE("GPL");