linux/drivers/media/video/hexium_orion.c
<<
>>
Prefs
   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 DEBUG_VARIABLE debug
  25
  26#include <media/saa7146_vv.h>
  27
  28static int debug = 0;
  29module_param(debug, int, 0);
  30MODULE_PARM_DESC(debug, "debug verbosity");
  31
  32/* global variables */
  33static int hexium_num = 0;
  34
  35#define HEXIUM_HV_PCI6_ORION            1
  36#define HEXIUM_ORION_1SVHS_3BNC         2
  37#define HEXIUM_ORION_4BNC               3
  38
  39#define HEXIUM_INPUTS   9
  40static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
  41        { 0, "CVBS 1",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  42        { 1, "CVBS 2",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  43        { 2, "CVBS 3",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  44        { 3, "CVBS 4",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  45        { 4, "CVBS 5",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  46        { 5, "CVBS 6",  V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  47        { 6, "Y/C 1",   V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  48        { 7, "Y/C 2",   V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  49        { 8, "Y/C 3",   V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
  50};
  51
  52#define HEXIUM_AUDIOS   0
  53
  54struct hexium_data
  55{
  56        s8 adr;
  57        u8 byte;
  58};
  59
  60static struct saa7146_extension_ioctls ioctls[] = {
  61        { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
  62        { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
  63        { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
  64        { VIDIOC_S_STD,         SAA7146_AFTER },
  65        { 0,                    0 }
  66};
  67
  68struct hexium
  69{
  70        int type;
  71        struct video_device     *video_dev;
  72        struct i2c_adapter      i2c_adapter;
  73
  74        int cur_input;  /* current input */
  75};
  76
  77/* Philips SAA7110 decoder default registers */
  78static u8 hexium_saa7110[53]={
  79/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
  80/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
  81/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
  82/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
  83/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
  84/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
  85/*30*/ 0x44,0x75,0x01,0x8C,0x03
  86};
  87
  88static struct {
  89        struct hexium_data data[8];
  90} hexium_input_select[] = {
  91{
  92        { /* cvbs 1 */
  93                { 0x06, 0x00 },
  94                { 0x20, 0xD9 },
  95                { 0x21, 0x17 }, // 0x16,
  96                { 0x22, 0x40 },
  97                { 0x2C, 0x03 },
  98                { 0x30, 0x44 },
  99                { 0x31, 0x75 }, // ??
 100                { 0x21, 0x16 }, // 0x03,
 101        }
 102}, {
 103        { /* cvbs 2 */
 104                { 0x06, 0x00 },
 105                { 0x20, 0x78 },
 106                { 0x21, 0x07 }, // 0x03,
 107                { 0x22, 0xD2 },
 108                { 0x2C, 0x83 },
 109                { 0x30, 0x60 },
 110                { 0x31, 0xB5 }, // ?
 111                { 0x21, 0x03 },
 112        }
 113}, {
 114        { /* cvbs 3 */
 115                { 0x06, 0x00 },
 116                { 0x20, 0xBA },
 117                { 0x21, 0x07 }, // 0x05,
 118                { 0x22, 0x91 },
 119                { 0x2C, 0x03 },
 120                { 0x30, 0x60 },
 121                { 0x31, 0xB5 }, // ??
 122                { 0x21, 0x05 }, // 0x03,
 123        }
 124}, {
 125        { /* cvbs 4 */
 126                { 0x06, 0x00 },
 127                { 0x20, 0xD8 },
 128                { 0x21, 0x17 }, // 0x16,
 129                { 0x22, 0x40 },
 130                { 0x2C, 0x03 },
 131                { 0x30, 0x44 },
 132                { 0x31, 0x75 }, // ??
 133                { 0x21, 0x16 }, // 0x03,
 134        }
 135}, {
 136        { /* cvbs 5 */
 137                { 0x06, 0x00 },
 138                { 0x20, 0xB8 },
 139                { 0x21, 0x07 }, // 0x05,
 140                { 0x22, 0x91 },
 141                { 0x2C, 0x03 },
 142                { 0x30, 0x60 },
 143                { 0x31, 0xB5 }, // ??
 144                { 0x21, 0x05 }, // 0x03,
 145        }
 146}, {
 147        { /* cvbs 6 */
 148                { 0x06, 0x00 },
 149                { 0x20, 0x7C },
 150                { 0x21, 0x07 }, // 0x03
 151                { 0x22, 0xD2 },
 152                { 0x2C, 0x83 },
 153                { 0x30, 0x60 },
 154                { 0x31, 0xB5 }, // ??
 155                { 0x21, 0x03 },
 156        }
 157}, {
 158        { /* y/c 1 */
 159                { 0x06, 0x80 },
 160                { 0x20, 0x59 },
 161                { 0x21, 0x17 },
 162                { 0x22, 0x42 },
 163                { 0x2C, 0xA3 },
 164                { 0x30, 0x44 },
 165                { 0x31, 0x75 },
 166                { 0x21, 0x12 },
 167        }
 168}, {
 169        { /* y/c 2 */
 170                { 0x06, 0x80 },
 171                { 0x20, 0x9A },
 172                { 0x21, 0x17 },
 173                { 0x22, 0xB1 },
 174                { 0x2C, 0x13 },
 175                { 0x30, 0x60 },
 176                { 0x31, 0xB5 },
 177                { 0x21, 0x14 },
 178        }
 179}, {
 180        { /* y/c 3 */
 181                { 0x06, 0x80 },
 182                { 0x20, 0x3C },
 183                { 0x21, 0x27 },
 184                { 0x22, 0xC1 },
 185                { 0x2C, 0x23 },
 186                { 0x30, 0x44 },
 187                { 0x31, 0x75 },
 188                { 0x21, 0x21 },
 189        }
 190}
 191};
 192
 193static struct saa7146_standard hexium_standards[] = {
 194        {
 195                .name   = "PAL",        .id     = V4L2_STD_PAL,
 196                .v_offset       = 16,   .v_field        = 288,
 197                .h_offset       = 1,    .h_pixels       = 680,
 198                .v_max_out      = 576,  .h_max_out      = 768,
 199        }, {
 200                .name   = "NTSC",       .id     = V4L2_STD_NTSC,
 201                .v_offset       = 16,   .v_field        = 240,
 202                .h_offset       = 1,    .h_pixels       = 640,
 203                .v_max_out      = 480,  .h_max_out      = 640,
 204        }, {
 205                .name   = "SECAM",      .id     = V4L2_STD_SECAM,
 206                .v_offset       = 16,   .v_field        = 288,
 207                .h_offset       = 1,    .h_pixels       = 720,
 208                .v_max_out      = 576,  .h_max_out      = 768,
 209        }
 210};
 211
 212/* this is only called for old HV-PCI6/Orion cards
 213   without eeprom */
 214static int hexium_probe(struct saa7146_dev *dev)
 215{
 216        struct hexium *hexium = NULL;
 217        union i2c_smbus_data data;
 218        int err = 0;
 219
 220        DEB_EE((".\n"));
 221
 222        /* there are no hexium orion cards with revision 0 saa7146s */
 223        if (0 == dev->revision) {
 224                return -EFAULT;
 225        }
 226
 227        hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
 228        if (NULL == hexium) {
 229                printk("hexium_orion: hexium_probe: not enough kernel memory.\n");
 230                return -ENOMEM;
 231        }
 232
 233        /* enable i2c-port pins */
 234        saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
 235
 236        saa7146_write(dev, DD1_INIT, 0x01000100);
 237        saa7146_write(dev, DD1_STREAM_B, 0x00000000);
 238        saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
 239
 240        hexium->i2c_adapter = (struct i2c_adapter) {
 241                .class = I2C_CLASS_TV_ANALOG,
 242                .name = "hexium orion",
 243        };
 244        saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
 245        if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
 246                DEB_S(("cannot register i2c-device. skipping.\n"));
 247                kfree(hexium);
 248                return -EFAULT;
 249        }
 250
 251        /* set SAA7110 control GPIO 0 */
 252        saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
 253        /*  set HWControl GPIO number 2 */
 254        saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
 255
 256        mdelay(10);
 257
 258        /* detect newer Hexium Orion cards by subsystem ids */
 259        if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
 260                printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n");
 261                /* we store the pointer in our private data field */
 262                dev->ext_priv = hexium;
 263                hexium->type = HEXIUM_ORION_1SVHS_3BNC;
 264                return 0;
 265        }
 266
 267        if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
 268                printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n");
 269                /* we store the pointer in our private data field */
 270                dev->ext_priv = hexium;
 271                hexium->type = HEXIUM_ORION_4BNC;
 272                return 0;
 273        }
 274
 275        /* check if this is an old hexium Orion card by looking at
 276           a saa7110 at address 0x4e */
 277        if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {
 278                printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");
 279                /* we store the pointer in our private data field */
 280                dev->ext_priv = hexium;
 281                hexium->type = HEXIUM_HV_PCI6_ORION;
 282                return 0;
 283        }
 284
 285        i2c_del_adapter(&hexium->i2c_adapter);
 286        kfree(hexium);
 287        return -EFAULT;
 288}
 289
 290/* bring hardware to a sane state. this has to be done, just in case someone
 291   wants to capture from this device before it has been properly initialized.
 292   the capture engine would badly fail, because no valid signal arrives on the
 293   saa7146, thus leading to timeouts and stuff. */
 294static int hexium_init_done(struct saa7146_dev *dev)
 295{
 296        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 297        union i2c_smbus_data data;
 298        int i = 0;
 299
 300        DEB_D(("hexium_init_done called.\n"));
 301
 302        /* initialize the helper ics to useful values */
 303        for (i = 0; i < sizeof(hexium_saa7110); i++) {
 304                data.byte = hexium_saa7110[i];
 305                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
 306                        printk("hexium_orion: failed for address 0x%02x\n", i);
 307                }
 308        }
 309
 310        return 0;
 311}
 312
 313static int hexium_set_input(struct hexium *hexium, int input)
 314{
 315        union i2c_smbus_data data;
 316        int i = 0;
 317
 318        DEB_D((".\n"));
 319
 320        for (i = 0; i < 8; i++) {
 321                int adr = hexium_input_select[input].data[i].adr;
 322                data.byte = hexium_input_select[input].data[i].byte;
 323                if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
 324                        return -1;
 325                }
 326                printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte);
 327        }
 328
 329        return 0;
 330}
 331
 332static struct saa7146_ext_vv vv_data;
 333
 334/* this function only gets called when the probing was successful */
 335static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
 336{
 337        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 338
 339        DEB_EE((".\n"));
 340
 341        saa7146_vv_init(dev, &vv_data);
 342        if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
 343                printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
 344                return -1;
 345        }
 346
 347        printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num);
 348        hexium_num++;
 349
 350        /* the rest */
 351        hexium->cur_input = 0;
 352        hexium_init_done(dev);
 353
 354        return 0;
 355}
 356
 357static int hexium_detach(struct saa7146_dev *dev)
 358{
 359        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 360
 361        DEB_EE(("dev:%p\n", dev));
 362
 363        saa7146_unregister_device(&hexium->video_dev, dev);
 364        saa7146_vv_release(dev);
 365
 366        hexium_num--;
 367
 368        i2c_del_adapter(&hexium->i2c_adapter);
 369        kfree(hexium);
 370        return 0;
 371}
 372
 373static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
 374{
 375        struct saa7146_dev *dev = fh->dev;
 376        struct hexium *hexium = (struct hexium *) dev->ext_priv;
 377/*
 378        struct saa7146_vv *vv = dev->vv_data;
 379*/
 380        switch (cmd) {
 381        case VIDIOC_ENUMINPUT:
 382                {
 383                        struct v4l2_input *i = arg;
 384                        DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
 385
 386                        if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
 387                                return -EINVAL;
 388                        }
 389
 390                        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
 391
 392                        DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
 393                        return 0;
 394                }
 395        case VIDIOC_G_INPUT:
 396                {
 397                        int *input = (int *) arg;
 398                        *input = hexium->cur_input;
 399
 400                        DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
 401                        return 0;
 402                }
 403        case VIDIOC_S_INPUT:
 404                {
 405                        int input = *(int *) arg;
 406
 407                        if (input < 0 || input >= HEXIUM_INPUTS) {
 408                                return -EINVAL;
 409                        }
 410
 411                        hexium->cur_input = input;
 412                        hexium_set_input(hexium, input);
 413
 414                        return 0;
 415                }
 416        default:
 417/*
 418                DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
 419*/
 420                return -ENOIOCTLCMD;
 421        }
 422        return 0;
 423}
 424
 425static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
 426{
 427        return 0;
 428}
 429
 430static struct saa7146_extension extension;
 431
 432static struct saa7146_pci_extension_data hexium_hv_pci6 = {
 433        .ext_priv = "Hexium HV-PCI6 / Orion",
 434        .ext = &extension,
 435};
 436
 437static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
 438        .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
 439        .ext = &extension,
 440};
 441
 442static struct saa7146_pci_extension_data hexium_orion_4bnc = {
 443        .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
 444        .ext = &extension,
 445};
 446
 447static struct pci_device_id pci_tbl[] = {
 448        {
 449         .vendor = PCI_VENDOR_ID_PHILIPS,
 450         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 451         .subvendor = 0x0000,
 452         .subdevice = 0x0000,
 453         .driver_data = (unsigned long) &hexium_hv_pci6,
 454         },
 455        {
 456         .vendor = PCI_VENDOR_ID_PHILIPS,
 457         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 458         .subvendor = 0x17c8,
 459         .subdevice = 0x0101,
 460         .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
 461         },
 462        {
 463         .vendor = PCI_VENDOR_ID_PHILIPS,
 464         .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
 465         .subvendor = 0x17c8,
 466         .subdevice = 0x2101,
 467         .driver_data = (unsigned long) &hexium_orion_4bnc,
 468         },
 469        {
 470         .vendor = 0,
 471         }
 472};
 473
 474MODULE_DEVICE_TABLE(pci, pci_tbl);
 475
 476static struct saa7146_ext_vv vv_data = {
 477        .inputs = HEXIUM_INPUTS,
 478        .capabilities = 0,
 479        .stds = &hexium_standards[0],
 480        .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
 481        .std_callback = &std_callback,
 482        .ioctls = &ioctls[0],
 483        .ioctl = hexium_ioctl,
 484};
 485
 486static struct saa7146_extension extension = {
 487        .name = "hexium HV-PCI6 Orion",
 488        .flags = 0,             // SAA7146_USE_I2C_IRQ,
 489
 490        .pci_tbl = &pci_tbl[0],
 491        .module = THIS_MODULE,
 492
 493        .probe = hexium_probe,
 494        .attach = hexium_attach,
 495        .detach = hexium_detach,
 496
 497        .irq_mask = 0,
 498        .irq_func = NULL,
 499};
 500
 501static int __init hexium_init_module(void)
 502{
 503        if (0 != saa7146_register_extension(&extension)) {
 504                DEB_S(("failed to register extension.\n"));
 505                return -ENODEV;
 506        }
 507
 508        return 0;
 509}
 510
 511static void __exit hexium_cleanup_module(void)
 512{
 513        saa7146_unregister_extension(&extension);
 514}
 515
 516module_init(hexium_init_module);
 517module_exit(hexium_cleanup_module);
 518
 519MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
 520MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 521MODULE_LICENSE("GPL");
 522