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>
 
  29 module_param(debug, int, 0);
 
  30 MODULE_PARM_DESC(debug, "debug verbosity");
 
  32 /* global variables */
 
  33 static int hexium_num = 0;
 
  35 #define HEXIUM_GEMINI                   4
 
  36 #define HEXIUM_GEMINI_DUAL              5
 
  38 #define HEXIUM_INPUTS   9
 
  39 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
 
  40         { 0, "CVBS 1",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  41         { 1, "CVBS 2",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  42         { 2, "CVBS 3",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  43         { 3, "CVBS 4",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  44         { 4, "CVBS 5",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  45         { 5, "CVBS 6",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  46         { 6, "Y/C 1",   V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  47         { 7, "Y/C 2",   V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  48         { 8, "Y/C 3",   V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
 
  51 #define HEXIUM_AUDIOS   0
 
  59 static struct saa7146_extension_ioctls ioctls[] = {
 
  60         { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
 
  61         { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
 
  62         { VIDIOC_QUERYCTRL,     SAA7146_BEFORE },
 
  63         { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
 
  64         { VIDIOC_S_STD,         SAA7146_AFTER },
 
  65         { VIDIOC_G_CTRL,        SAA7146_BEFORE },
 
  66         { VIDIOC_S_CTRL,        SAA7146_BEFORE },
 
  70 #define HEXIUM_CONTROLS 1
 
  71 static struct v4l2_queryctrl hexium_controls[] = {
 
  72         { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
 
  75 #define HEXIUM_GEMINI_V_1_0             1
 
  76 #define HEXIUM_GEMINI_DUAL_V_1_0        2
 
  82         struct video_device     *video_dev;
 
  83         struct i2c_adapter      i2c_adapter;
 
  85         int             cur_input;      /* current input */
 
  86         v4l2_std_id     cur_std;        /* current standard */
 
  87         int             cur_bw;         /* current black/white status */
 
  90 /* Samsung KS0127B decoder default registers */
 
  91 static u8 hexium_ks0127b[0x100]={
 
  92 /*00*/ 0x00,0x52,0x30,0x40,0x01,0x0C,0x2A,0x10,
 
  93 /*08*/ 0x00,0x00,0x00,0x60,0x00,0x00,0x0F,0x06,
 
  94 /*10*/ 0x00,0x00,0xE4,0xC0,0x00,0x00,0x00,0x00,
 
  95 /*18*/ 0x14,0x9B,0xFE,0xFF,0xFC,0xFF,0x03,0x22,
 
  96 /*20*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
  97 /*28*/ 0x00,0x00,0x00,0x00,0x00,0x2C,0x9B,0x00,
 
  98 /*30*/ 0x00,0x00,0x10,0x80,0x80,0x10,0x80,0x80,
 
  99 /*38*/ 0x01,0x04,0x00,0x00,0x00,0x29,0xC0,0x00,
 
 100 /*40*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 101 /*48*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 102 /*50*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 103 /*58*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 104 /*60*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 105 /*68*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 106 /*70*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 107 /*78*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 108 /*80*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 109 /*88*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 110 /*90*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 111 /*98*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 112 /*A0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 113 /*A8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 114 /*B0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 115 /*B8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 116 /*C0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 117 /*C8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 118 /*D0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 119 /*D8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 120 /*E0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 121 /*E8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 122 /*F0*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
 123 /*F8*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
 
 126 static struct hexium_data hexium_pal[] = {
 
 127         { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
 
 130 static struct hexium_data hexium_pal_bw[] = {
 
 131         { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
 
 134 static struct hexium_data hexium_ntsc[] = {
 
 135         { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
 
 138 static struct hexium_data hexium_ntsc_bw[] = {
 
 139         { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
 
 142 static struct hexium_data hexium_secam[] = {
 
 143         { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
 
 146 static struct hexium_data hexium_input_select[] = {
 
 158 /* fixme: h_offset = 0 for Hexium Gemini *Dual*, which
 
 159    are currently *not* supported*/
 
 160 static struct saa7146_standard hexium_standards[] = {
 
 162                 .name   = "PAL",        .id     = V4L2_STD_PAL,
 
 163                 .v_offset       = 28,   .v_field        = 288,
 
 164                 .h_offset       = 1,    .h_pixels       = 680,
 
 165                 .v_max_out      = 576,  .h_max_out      = 768,
 
 167                 .name   = "NTSC",       .id     = V4L2_STD_NTSC,
 
 168                 .v_offset       = 28,   .v_field        = 240,
 
 169                 .h_offset       = 1,    .h_pixels       = 640,
 
 170                 .v_max_out      = 480,  .h_max_out      = 640,
 
 172                 .name   = "SECAM",      .id     = V4L2_STD_SECAM,
 
 173                 .v_offset       = 28,   .v_field        = 288,
 
 174                 .h_offset       = 1,    .h_pixels       = 720,
 
 175                 .v_max_out      = 576,  .h_max_out      = 768,
 
 179 /* bring hardware to a sane state. this has to be done, just in case someone
 
 180    wants to capture from this device before it has been properly initialized.
 
 181    the capture engine would badly fail, because no valid signal arrives on the
 
 182    saa7146, thus leading to timeouts and stuff. */
 
 183 static int hexium_init_done(struct saa7146_dev *dev)
 
 185         struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
 186         union i2c_smbus_data data;
 
 189         DEB_D(("hexium_init_done called.\n"));
 
 191         /* initialize the helper ics to useful values */
 
 192         for (i = 0; i < sizeof(hexium_ks0127b); i++) {
 
 193                 data.byte = hexium_ks0127b[i];
 
 194                 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
 
 195                         printk("hexium_gemini: hexium_init_done() failed for address 0x%02x\n", i);
 
 202 static int hexium_set_input(struct hexium *hexium, int input)
 
 204         union i2c_smbus_data data;
 
 208         data.byte = hexium_input_select[input].byte;
 
 209         if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, hexium_input_select[input].adr, I2C_SMBUS_BYTE_DATA, &data)) {
 
 216 static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
 
 218         union i2c_smbus_data data;
 
 223         while (vdec[i].adr != -1) {
 
 224                 data.byte = vdec[i].byte;
 
 225                 if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x6c, 0, I2C_SMBUS_WRITE, vdec[i].adr, I2C_SMBUS_BYTE_DATA, &data)) {
 
 226                         printk("hexium_init_done: hexium_set_standard() failed for address 0x%02x\n", i);
 
 234 static struct saa7146_ext_vv vv_data;
 
 236 /* this function only gets called when the probing was successful */
 
 237 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 
 239         struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
 243         hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
 
 244         if (NULL == hexium) {
 
 245                 printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
 
 248         dev->ext_priv = hexium;
 
 250         /* enable i2c-port pins */
 
 251         saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 
 253         hexium->i2c_adapter = (struct i2c_adapter) {
 
 254                 .class = I2C_CLASS_TV_ANALOG,
 
 255                 .name = "hexium gemini",
 
 257         saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 
 258         if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 
 259                 DEB_S(("cannot register i2c-device. skipping.\n"));
 
 264         /*  set HWControl GPIO number 2 */
 
 265         saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 
 267         saa7146_write(dev, DD1_INIT, 0x07000700);
 
 268         saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 
 269         saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 
 272         hexium->cur_input = 0;
 
 273         hexium_init_done(dev);
 
 275         hexium_set_standard(hexium, hexium_pal);
 
 276         hexium->cur_std = V4L2_STD_PAL;
 
 278         hexium_set_input(hexium, 0);
 
 279         hexium->cur_input = 0;
 
 281         saa7146_vv_init(dev, &vv_data);
 
 282         if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
 
 283                 printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
 
 287         printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
 
 293 static int hexium_detach(struct saa7146_dev *dev)
 
 295         struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
 297         DEB_EE(("dev:%p\n", dev));
 
 299         saa7146_unregister_device(&hexium->video_dev, dev);
 
 300         saa7146_vv_release(dev);
 
 304         i2c_del_adapter(&hexium->i2c_adapter);
 
 309 static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 
 311         struct saa7146_dev *dev = fh->dev;
 
 312         struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
 314         struct saa7146_vv *vv = dev->vv_data;
 
 317         case VIDIOC_ENUMINPUT:
 
 319                         struct v4l2_input *i = arg;
 
 320                         DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
 
 322                         if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
 
 326                         memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
 
 328                         DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
 
 333                         int *input = (int *) arg;
 
 334                         *input = hexium->cur_input;
 
 336                         DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
 
 341                         int input = *(int *) arg;
 
 343                         DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
 
 345                         if (input < 0 || input >= HEXIUM_INPUTS) {
 
 349                         hexium->cur_input = input;
 
 350                         hexium_set_input(hexium, input);
 
 354                 /* the saa7146 provides some controls (brightness, contrast, saturation)
 
 355                    which gets registered *after* this function. because of this we have
 
 356                    to return with a value != 0 even if the function succeded.. */
 
 357         case VIDIOC_QUERYCTRL:
 
 359                         struct v4l2_queryctrl *qc = arg;
 
 362                         for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
 
 363                                 if (hexium_controls[i].id == qc->id) {
 
 364                                         *qc = hexium_controls[i];
 
 365                                         DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
 
 373                         struct v4l2_control *vc = arg;
 
 376                         for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
 
 377                                 if (hexium_controls[i].id == vc->id) {
 
 387                         case V4L2_CID_PRIVATE_BASE:{
 
 388                                         vc->value = hexium->cur_bw;
 
 389                                         DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
 
 398                         struct v4l2_control *vc = arg;
 
 401                         for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
 
 402                                 if (hexium_controls[i].id == vc->id) {
 
 412                         case V4L2_CID_PRIVATE_BASE:{
 
 413                                         hexium->cur_bw = vc->value;
 
 418                         DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
 
 420                         if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
 
 421                                 hexium_set_standard(hexium, hexium_pal);
 
 424                         if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
 
 425                                 hexium_set_standard(hexium, hexium_ntsc);
 
 428                         if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
 
 429                                 hexium_set_standard(hexium, hexium_secam);
 
 432                         if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
 
 433                                 hexium_set_standard(hexium, hexium_pal_bw);
 
 436                         if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
 
 437                                 hexium_set_standard(hexium, hexium_ntsc_bw);
 
 440                         if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
 
 441                                 /* fixme: is there no bw secam mode? */
 
 449                 DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
 
 456 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
 
 458         struct hexium *hexium = (struct hexium *) dev->ext_priv;
 
 460         if (V4L2_STD_PAL == std->id) {
 
 461                 hexium_set_standard(hexium, hexium_pal);
 
 462                 hexium->cur_std = V4L2_STD_PAL;
 
 464         } else if (V4L2_STD_NTSC == std->id) {
 
 465                 hexium_set_standard(hexium, hexium_ntsc);
 
 466                 hexium->cur_std = V4L2_STD_NTSC;
 
 468         } else if (V4L2_STD_SECAM == std->id) {
 
 469                 hexium_set_standard(hexium, hexium_secam);
 
 470                 hexium->cur_std = V4L2_STD_SECAM;
 
 477 static struct saa7146_extension hexium_extension;
 
 479 static struct saa7146_pci_extension_data hexium_gemini_4bnc = {
 
 480         .ext_priv = "Hexium Gemini (4 BNC)",
 
 481         .ext = &hexium_extension,
 
 484 static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = {
 
 485         .ext_priv = "Hexium Gemini Dual (4 BNC)",
 
 486         .ext = &hexium_extension,
 
 489 static struct pci_device_id pci_tbl[] = {
 
 491          .vendor = PCI_VENDOR_ID_PHILIPS,
 
 492          .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 
 495          .driver_data = (unsigned long) &hexium_gemini_4bnc,
 
 498          .vendor = PCI_VENDOR_ID_PHILIPS,
 
 499          .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 
 502          .driver_data = (unsigned long) &hexium_gemini_dual_4bnc,
 
 509 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 511 static struct saa7146_ext_vv vv_data = {
 
 512         .inputs = HEXIUM_INPUTS,
 
 514         .stds = &hexium_standards[0],
 
 515         .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
 
 516         .std_callback = &std_callback,
 
 517         .ioctls = &ioctls[0],
 
 518         .ioctl = hexium_ioctl,
 
 521 static struct saa7146_extension hexium_extension = {
 
 522         .name = "hexium gemini",
 
 523         .flags = SAA7146_USE_I2C_IRQ,
 
 525         .pci_tbl = &pci_tbl[0],
 
 526         .module = THIS_MODULE,
 
 528         .attach = hexium_attach,
 
 529         .detach = hexium_detach,
 
 535 static int __init hexium_init_module(void)
 
 537         if (0 != saa7146_register_extension(&hexium_extension)) {
 
 538                 DEB_S(("failed to register extension.\n"));
 
 545 static void __exit hexium_cleanup_module(void)
 
 547         saa7146_unregister_extension(&hexium_extension);
 
 550 module_init(hexium_init_module);
 
 551 module_exit(hexium_cleanup_module);
 
 553 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Gemini frame grabber cards");
 
 554 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 
 555 MODULE_LICENSE("GPL");