[PATCH] Add two drivers for Hexium frame grabber cards
[linux-2.6/history.git] / drivers / media / video / hexium_gemini.c
blob8ab432a9b0187037fc48f99ad4d6cac4e023d6c6
1 /*
2 hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards
4 Visit http://www.mihu.de/linux/saa7146/ and follow the link
5 to "hexium" for further details about this card.
7 Copyright (C) 2003 Michael Hunold <michael@mihu.de>
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.
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.
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.
24 #define DEBUG_VARIABLE debug
26 #include <media/saa7146_vv.h>
28 static int debug = 255;
29 MODULE_PARM(debug, "i");
30 MODULE_PARM_DESC(debug, "debug verbosity");
32 /* global variables */
33 int hexium_num = 0;
35 #include "hexium_gemini.h"
37 /* bring hardware to a sane state. this has to be done, just in case someone
38 wants to capture from this device before it has been properly initialized.
39 the capture engine would badly fail, because no valid signal arrives on the
40 saa7146, thus leading to timeouts and stuff. */
41 static int hexium_init_done(struct saa7146_dev *dev)
43 struct hexium *hexium = (struct hexium *) dev->ext_priv;
44 union i2c_smbus_data data;
45 int i = 0;
47 DEB_D(("hexium_init_done called.\n"));
49 /* initialize the helper ics to useful values */
50 for (i = 0; i < sizeof(hexium_ks0127b); i++) {
51 data.byte = hexium_ks0127b[i];
52 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
53 printk("failed for address 0x%02x\n", i);
57 return 0;
60 static int hexium_set_input(struct hexium *hexium, int input)
62 union i2c_smbus_data data;
64 DEB_D((".\n"));
66 data.byte = hexium_input_select[input].byte;
67 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
68 return -1;
71 return 0;
74 static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
76 union i2c_smbus_data data;
77 int i = 0;
79 DEB_D((".\n"));
81 while (vdec[i].adr != -1) {
82 data.byte = vdec[i].byte;
83 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
84 printk("failed for address 0x%02x\n", i);
85 return -1;
87 i++;
89 return 0;
92 static struct saa7146_ext_vv vv_data;
94 /* this function only gets called when the probing was successful */
95 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
97 struct hexium *hexium = (struct hexium *) dev->ext_priv;
99 DEB_EE((".\n"));
101 hexium = (struct hexium *) kmalloc(sizeof(struct hexium), GFP_KERNEL);
102 if (NULL == hexium) {
103 printk("hexium_v4l2.o: hexium_probe: not enough kernel memory.\n");
104 return -ENOMEM;
106 memset(hexium, 0x0, sizeof(struct hexium));
107 (struct hexium *) dev->ext_priv = hexium;
109 /* FIXME: enable i2c-port pins, video-port-pins
110 video port pins should be enabled here ?! */
111 saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
113 saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
114 if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
115 DEB_S(("cannot register i2c-device. skipping.\n"));
116 kfree(hexium);
117 return -EFAULT;
120 /* set HWControl GPIO number 2 */
121 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
123 saa7146_write(dev, DD1_INIT, 0x07000700);
124 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
125 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
127 /* the rest */
128 hexium->cur_input = 0;
129 hexium_init_done(dev);
131 hexium_set_standard(hexium, hexium_pal);
132 hexium->cur_std = V4L2_STD_PAL;
134 hexium_set_input(hexium, 0);
135 hexium->cur_input = 0;
137 saa7146_vv_init(dev, &vv_data);
138 if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium", VFL_TYPE_GRABBER)) {
139 ERR(("cannot register capture v4l2 device. skipping.\n"));
140 return -1;
143 printk("hexium: found 'hexium frame grabber'-%d.\n", hexium_num);
144 hexium_num++;
146 return 0;
149 static int hexium_detach(struct saa7146_dev *dev)
151 struct hexium *hexium = (struct hexium *) dev->ext_priv;
153 DEB_EE(("dev:%p\n", dev));
155 saa7146_unregister_device(&hexium->video_dev, dev);
156 saa7146_vv_release(dev);
158 hexium_num--;
160 i2c_del_adapter(&hexium->i2c_adapter);
161 kfree(hexium);
162 return 0;
165 static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
167 struct saa7146_dev *dev = fh->dev;
168 struct hexium *hexium = (struct hexium *) dev->ext_priv;
170 struct saa7146_vv *vv = dev->vv_data;
172 switch (cmd) {
173 case VIDIOC_ENUMINPUT:
175 struct v4l2_input *i = arg;
176 DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
178 if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
179 return -EINVAL;
182 memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
184 DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
185 return 0;
187 case VIDIOC_G_INPUT:
189 int *input = (int *) arg;
190 *input = hexium->cur_input;
192 DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
193 return 0;
195 case VIDIOC_S_INPUT:
197 int input = *(int *) arg;
199 DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
201 if (input < 0 || input >= HEXIUM_INPUTS) {
202 return -EINVAL;
205 hexium->cur_input = input;
206 hexium_set_input(hexium, input);
208 return 0;
210 /* the saa7146 provides some controls (brightness, contrast, saturation)
211 which gets registered *after* this function. because of this we have
212 to return with a value != 0 even if the function succeded.. */
213 case VIDIOC_QUERYCTRL:
215 struct v4l2_queryctrl *qc = arg;
216 int i;
218 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
219 if (hexium_controls[i].id == qc->id) {
220 *qc = hexium_controls[i];
221 DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
222 return 0;
225 return -EAGAIN;
227 case VIDIOC_G_CTRL:
229 struct v4l2_control *vc = arg;
230 int i;
232 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
233 if (hexium_controls[i].id == vc->id) {
234 break;
238 if (i < 0) {
239 return -EAGAIN;
242 switch (vc->id) {
243 case V4L2_CID_PRIVATE_BASE:{
244 vc->value = hexium->cur_bw;
245 DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
246 return 0;
249 return -EINVAL;
252 case VIDIOC_S_CTRL:
254 struct v4l2_control *vc = arg;
255 int i = 0;
257 for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
258 if (hexium_controls[i].id == vc->id) {
259 break;
263 if (i < 0) {
264 return -EAGAIN;
267 switch (vc->id) {
268 case V4L2_CID_PRIVATE_BASE:{
269 hexium->cur_bw = vc->value;
270 break;
274 DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
276 if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
277 hexium_set_standard(hexium, hexium_pal);
278 return 0;
280 if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
281 hexium_set_standard(hexium, hexium_ntsc);
282 return 0;
284 if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
285 hexium_set_standard(hexium, hexium_secam);
286 return 0;
288 if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
289 hexium_set_standard(hexium, hexium_pal_bw);
290 return 0;
292 if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
293 hexium_set_standard(hexium, hexium_ntsc_bw);
294 return 0;
296 if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
297 /* fixme: is there no bw secam mode? */
298 return -EINVAL;
301 return -EINVAL;
303 default:
305 DEB_D(("v4l2_ioctl does not handle this ioctl.\n"));
307 return -ENOIOCTLCMD;
309 return 0;
312 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
314 struct hexium *hexium = (struct hexium *) dev->ext_priv;
316 if (V4L2_STD_PAL == std->id) {
317 hexium_set_standard(hexium, hexium_pal);
318 hexium->cur_std = V4L2_STD_PAL;
319 return 0;
320 } else if (V4L2_STD_NTSC == std->id) {
321 hexium_set_standard(hexium, hexium_ntsc);
322 hexium->cur_std = V4L2_STD_NTSC;
323 return 0;
324 } else if (V4L2_STD_SECAM == std->id) {
325 hexium_set_standard(hexium, hexium_secam);
326 hexium->cur_std = V4L2_STD_SECAM;
327 return 0;
330 return -1;
333 static struct saa7146_extension hexium_extension;
335 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
336 .ext_priv = "Hexium Gemini (4 BNC)",
337 .ext = &hexium_extension,
340 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
341 .ext_priv = "Hexium Gemini Dual (4 BNC)",
342 .ext = &hexium_extension,
345 static struct pci_device_id pci_tbl[] = {
347 .vendor = PCI_VENDOR_ID_PHILIPS,
348 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
349 .subvendor = 0x17c8,
350 .subdevice = 0x2401,
351 .driver_data = (unsigned long) &hexium_gemini_4bnc,
354 .vendor = PCI_VENDOR_ID_PHILIPS,
355 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
356 .subvendor = 0x17c8,
357 .subdevice = 0x2402,
358 .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
361 .vendor = 0,
365 MODULE_DEVICE_TABLE(pci, pci_tbl);
367 static struct saa7146_ext_vv vv_data = {
368 .inputs = HEXIUM_INPUTS,
369 .capabilities = 0,
370 .stds = &hexium_standards[0],
371 .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
372 .std_callback = &std_callback,
373 .ioctls = &ioctls[0],
374 .ioctl = hexium_ioctl,
377 static struct saa7146_extension hexium_extension = {
378 .name = "hexium gemini",
379 .flags = SAA7146_USE_I2C_IRQ,
381 .pci_tbl = &pci_tbl[0],
382 .module = THIS_MODULE,
384 .attach = hexium_attach,
385 .detach = hexium_detach,
387 .irq_mask = 0,
388 .irq_func = NULL,
391 int __init hexium_init_module(void)
393 if (0 != saa7146_register_extension(&hexium_extension)) {
394 DEB_S(("failed to register extension.\n"));
395 return -ENODEV;
398 return 0;
401 void __exit hexium_cleanup_module(void)
403 saa7146_unregister_extension(&hexium_extension);
406 module_init(hexium_init_module);
407 module_exit(hexium_cleanup_module);
409 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
410 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
411 MODULE_LICENSE("GPL");