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