Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards
0004 
0005     Visit http://www.mihu.de/linux/saa7146/ and follow the link
0006     to "hexium" for further details about this card.
0007 
0008     Copyright (C) 2003 Michael Hunold <michael@mihu.de>
0009 
0010 */
0011 
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013 
0014 #define DEBUG_VARIABLE debug
0015 
0016 #include <media/drv-intf/saa7146_vv.h>
0017 #include <linux/module.h>
0018 #include <linux/kernel.h>
0019 
0020 static int debug;
0021 module_param(debug, int, 0);
0022 MODULE_PARM_DESC(debug, "debug verbosity");
0023 
0024 /* global variables */
0025 static int hexium_num;
0026 
0027 #define HEXIUM_HV_PCI6_ORION        1
0028 #define HEXIUM_ORION_1SVHS_3BNC     2
0029 #define HEXIUM_ORION_4BNC       3
0030 
0031 #define HEXIUM_INPUTS   9
0032 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
0033     { 0, "CVBS 1",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0034     { 1, "CVBS 2",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0035     { 2, "CVBS 3",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0036     { 3, "CVBS 4",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0037     { 4, "CVBS 5",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0038     { 5, "CVBS 6",  V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0039     { 6, "Y/C 1",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0040     { 7, "Y/C 2",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0041     { 8, "Y/C 3",   V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
0042 };
0043 
0044 #define HEXIUM_AUDIOS   0
0045 
0046 struct hexium_data
0047 {
0048     s8 adr;
0049     u8 byte;
0050 };
0051 
0052 struct hexium
0053 {
0054     int type;
0055     struct video_device video_dev;
0056     struct i2c_adapter  i2c_adapter;
0057 
0058     int cur_input;  /* current input */
0059 };
0060 
0061 /* Philips SAA7110 decoder default registers */
0062 static u8 hexium_saa7110[53]={
0063 /*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
0064 /*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
0065 /*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
0066 /*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
0067 /*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
0068 /*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
0069 /*30*/ 0x44,0x75,0x01,0x8C,0x03
0070 };
0071 
0072 static struct {
0073     struct hexium_data data[8];
0074 } hexium_input_select[] = {
0075 {
0076     { /* cvbs 1 */
0077         { 0x06, 0x00 },
0078         { 0x20, 0xD9 },
0079         { 0x21, 0x17 }, // 0x16,
0080         { 0x22, 0x40 },
0081         { 0x2C, 0x03 },
0082         { 0x30, 0x44 },
0083         { 0x31, 0x75 }, // ??
0084         { 0x21, 0x16 }, // 0x03,
0085     }
0086 }, {
0087     { /* cvbs 2 */
0088         { 0x06, 0x00 },
0089         { 0x20, 0x78 },
0090         { 0x21, 0x07 }, // 0x03,
0091         { 0x22, 0xD2 },
0092         { 0x2C, 0x83 },
0093         { 0x30, 0x60 },
0094         { 0x31, 0xB5 }, // ?
0095         { 0x21, 0x03 },
0096     }
0097 }, {
0098     { /* cvbs 3 */
0099         { 0x06, 0x00 },
0100         { 0x20, 0xBA },
0101         { 0x21, 0x07 }, // 0x05,
0102         { 0x22, 0x91 },
0103         { 0x2C, 0x03 },
0104         { 0x30, 0x60 },
0105         { 0x31, 0xB5 }, // ??
0106         { 0x21, 0x05 }, // 0x03,
0107     }
0108 }, {
0109     { /* cvbs 4 */
0110         { 0x06, 0x00 },
0111         { 0x20, 0xD8 },
0112         { 0x21, 0x17 }, // 0x16,
0113         { 0x22, 0x40 },
0114         { 0x2C, 0x03 },
0115         { 0x30, 0x44 },
0116         { 0x31, 0x75 }, // ??
0117         { 0x21, 0x16 }, // 0x03,
0118     }
0119 }, {
0120     { /* cvbs 5 */
0121         { 0x06, 0x00 },
0122         { 0x20, 0xB8 },
0123         { 0x21, 0x07 }, // 0x05,
0124         { 0x22, 0x91 },
0125         { 0x2C, 0x03 },
0126         { 0x30, 0x60 },
0127         { 0x31, 0xB5 }, // ??
0128         { 0x21, 0x05 }, // 0x03,
0129     }
0130 }, {
0131     { /* cvbs 6 */
0132         { 0x06, 0x00 },
0133         { 0x20, 0x7C },
0134         { 0x21, 0x07 }, // 0x03
0135         { 0x22, 0xD2 },
0136         { 0x2C, 0x83 },
0137         { 0x30, 0x60 },
0138         { 0x31, 0xB5 }, // ??
0139         { 0x21, 0x03 },
0140     }
0141 }, {
0142     { /* y/c 1 */
0143         { 0x06, 0x80 },
0144         { 0x20, 0x59 },
0145         { 0x21, 0x17 },
0146         { 0x22, 0x42 },
0147         { 0x2C, 0xA3 },
0148         { 0x30, 0x44 },
0149         { 0x31, 0x75 },
0150         { 0x21, 0x12 },
0151     }
0152 }, {
0153     { /* y/c 2 */
0154         { 0x06, 0x80 },
0155         { 0x20, 0x9A },
0156         { 0x21, 0x17 },
0157         { 0x22, 0xB1 },
0158         { 0x2C, 0x13 },
0159         { 0x30, 0x60 },
0160         { 0x31, 0xB5 },
0161         { 0x21, 0x14 },
0162     }
0163 }, {
0164     { /* y/c 3 */
0165         { 0x06, 0x80 },
0166         { 0x20, 0x3C },
0167         { 0x21, 0x27 },
0168         { 0x22, 0xC1 },
0169         { 0x2C, 0x23 },
0170         { 0x30, 0x44 },
0171         { 0x31, 0x75 },
0172         { 0x21, 0x21 },
0173     }
0174 }
0175 };
0176 
0177 static struct saa7146_standard hexium_standards[] = {
0178     {
0179         .name   = "PAL",    .id = V4L2_STD_PAL,
0180         .v_offset   = 16,   .v_field    = 288,
0181         .h_offset   = 1,    .h_pixels   = 680,
0182         .v_max_out  = 576,  .h_max_out  = 768,
0183     }, {
0184         .name   = "NTSC",   .id = V4L2_STD_NTSC,
0185         .v_offset   = 16,   .v_field    = 240,
0186         .h_offset   = 1,    .h_pixels   = 640,
0187         .v_max_out  = 480,  .h_max_out  = 640,
0188     }, {
0189         .name   = "SECAM",  .id = V4L2_STD_SECAM,
0190         .v_offset   = 16,   .v_field    = 288,
0191         .h_offset   = 1,    .h_pixels   = 720,
0192         .v_max_out  = 576,  .h_max_out  = 768,
0193     }
0194 };
0195 
0196 /* this is only called for old HV-PCI6/Orion cards
0197    without eeprom */
0198 static int hexium_probe(struct saa7146_dev *dev)
0199 {
0200     struct hexium *hexium = NULL;
0201     union i2c_smbus_data data;
0202     int err = 0;
0203 
0204     DEB_EE("\n");
0205 
0206     /* there are no hexium orion cards with revision 0 saa7146s */
0207     if (0 == dev->revision) {
0208         return -EFAULT;
0209     }
0210 
0211     hexium = kzalloc(sizeof(*hexium), GFP_KERNEL);
0212     if (!hexium)
0213         return -ENOMEM;
0214 
0215     /* enable i2c-port pins */
0216     saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
0217 
0218     saa7146_write(dev, DD1_INIT, 0x01000100);
0219     saa7146_write(dev, DD1_STREAM_B, 0x00000000);
0220     saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
0221 
0222     strscpy(hexium->i2c_adapter.name, "hexium orion",
0223         sizeof(hexium->i2c_adapter.name));
0224     saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
0225     if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
0226         DEB_S("cannot register i2c-device. skipping.\n");
0227         kfree(hexium);
0228         return -EFAULT;
0229     }
0230 
0231     /* set SAA7110 control GPIO 0 */
0232     saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
0233     /*  set HWControl GPIO number 2 */
0234     saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
0235 
0236     mdelay(10);
0237 
0238     /* detect newer Hexium Orion cards by subsystem ids */
0239     if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {
0240         pr_info("device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs\n");
0241         /* we store the pointer in our private data field */
0242         dev->ext_priv = hexium;
0243         hexium->type = HEXIUM_ORION_1SVHS_3BNC;
0244         return 0;
0245     }
0246 
0247     if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {
0248         pr_info("device is a Hexium Orion w/ 4 BNC inputs\n");
0249         /* we store the pointer in our private data field */
0250         dev->ext_priv = hexium;
0251         hexium->type = HEXIUM_ORION_4BNC;
0252         return 0;
0253     }
0254 
0255     /* check if this is an old hexium Orion card by looking at
0256        a saa7110 at address 0x4e */
0257     err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ,
0258                  0x00, I2C_SMBUS_BYTE_DATA, &data);
0259     if (err == 0) {
0260         pr_info("device is a Hexium HV-PCI6/Orion (old)\n");
0261         /* we store the pointer in our private data field */
0262         dev->ext_priv = hexium;
0263         hexium->type = HEXIUM_HV_PCI6_ORION;
0264         return 0;
0265     }
0266 
0267     i2c_del_adapter(&hexium->i2c_adapter);
0268     kfree(hexium);
0269     return -EFAULT;
0270 }
0271 
0272 /* bring hardware to a sane state. this has to be done, just in case someone
0273    wants to capture from this device before it has been properly initialized.
0274    the capture engine would badly fail, because no valid signal arrives on the
0275    saa7146, thus leading to timeouts and stuff. */
0276 static int hexium_init_done(struct saa7146_dev *dev)
0277 {
0278     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0279     union i2c_smbus_data data;
0280     int i = 0;
0281 
0282     DEB_D("hexium_init_done called\n");
0283 
0284     /* initialize the helper ics to useful values */
0285     for (i = 0; i < sizeof(hexium_saa7110); i++) {
0286         data.byte = hexium_saa7110[i];
0287         if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {
0288             pr_err("failed for address 0x%02x\n", i);
0289         }
0290     }
0291 
0292     return 0;
0293 }
0294 
0295 static int hexium_set_input(struct hexium *hexium, int input)
0296 {
0297     union i2c_smbus_data data;
0298     int i = 0;
0299 
0300     DEB_D("\n");
0301 
0302     for (i = 0; i < 8; i++) {
0303         int adr = hexium_input_select[input].data[i].adr;
0304         data.byte = hexium_input_select[input].data[i].byte;
0305         if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {
0306             return -1;
0307         }
0308         pr_debug("%d: 0x%02x => 0x%02x\n", input, adr, data.byte);
0309     }
0310 
0311     return 0;
0312 }
0313 
0314 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
0315 {
0316     DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
0317 
0318     if (i->index >= HEXIUM_INPUTS)
0319         return -EINVAL;
0320 
0321     memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
0322 
0323     DEB_D("v4l2_ioctl: VIDIOC_ENUMINPUT %d\n", i->index);
0324     return 0;
0325 }
0326 
0327 static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
0328 {
0329     struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
0330     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0331 
0332     *input = hexium->cur_input;
0333 
0334     DEB_D("VIDIOC_G_INPUT: %d\n", *input);
0335     return 0;
0336 }
0337 
0338 static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
0339 {
0340     struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
0341     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0342 
0343     if (input >= HEXIUM_INPUTS)
0344         return -EINVAL;
0345 
0346     hexium->cur_input = input;
0347     hexium_set_input(hexium, input);
0348 
0349     return 0;
0350 }
0351 
0352 static struct saa7146_ext_vv vv_data;
0353 
0354 /* this function only gets called when the probing was successful */
0355 static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
0356 {
0357     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0358     int ret;
0359 
0360     DEB_EE("\n");
0361 
0362     ret = saa7146_vv_init(dev, &vv_data);
0363     if (ret) {
0364         pr_err("Error in saa7146_vv_init()\n");
0365         return ret;
0366     }
0367 
0368     vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
0369     vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
0370     vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
0371     if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_VIDEO)) {
0372         pr_err("cannot register capture v4l2 device. skipping.\n");
0373         return -1;
0374     }
0375 
0376     pr_err("found 'hexium orion' frame grabber-%d\n", hexium_num);
0377     hexium_num++;
0378 
0379     /* the rest */
0380     hexium->cur_input = 0;
0381     hexium_init_done(dev);
0382 
0383     return 0;
0384 }
0385 
0386 static int hexium_detach(struct saa7146_dev *dev)
0387 {
0388     struct hexium *hexium = (struct hexium *) dev->ext_priv;
0389 
0390     DEB_EE("dev:%p\n", dev);
0391 
0392     saa7146_unregister_device(&hexium->video_dev, dev);
0393     saa7146_vv_release(dev);
0394 
0395     hexium_num--;
0396 
0397     i2c_del_adapter(&hexium->i2c_adapter);
0398     kfree(hexium);
0399     return 0;
0400 }
0401 
0402 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
0403 {
0404     return 0;
0405 }
0406 
0407 static struct saa7146_extension extension;
0408 
0409 static struct saa7146_pci_extension_data hexium_hv_pci6 = {
0410     .ext_priv = "Hexium HV-PCI6 / Orion",
0411     .ext = &extension,
0412 };
0413 
0414 static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {
0415     .ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",
0416     .ext = &extension,
0417 };
0418 
0419 static struct saa7146_pci_extension_data hexium_orion_4bnc = {
0420     .ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",
0421     .ext = &extension,
0422 };
0423 
0424 static const struct pci_device_id pci_tbl[] = {
0425     {
0426      .vendor = PCI_VENDOR_ID_PHILIPS,
0427      .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
0428      .subvendor = 0x0000,
0429      .subdevice = 0x0000,
0430      .driver_data = (unsigned long) &hexium_hv_pci6,
0431      },
0432     {
0433      .vendor = PCI_VENDOR_ID_PHILIPS,
0434      .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
0435      .subvendor = 0x17c8,
0436      .subdevice = 0x0101,
0437      .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,
0438      },
0439     {
0440      .vendor = PCI_VENDOR_ID_PHILIPS,
0441      .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
0442      .subvendor = 0x17c8,
0443      .subdevice = 0x2101,
0444      .driver_data = (unsigned long) &hexium_orion_4bnc,
0445      },
0446     {
0447      .vendor = 0,
0448      }
0449 };
0450 
0451 MODULE_DEVICE_TABLE(pci, pci_tbl);
0452 
0453 static struct saa7146_ext_vv vv_data = {
0454     .inputs = HEXIUM_INPUTS,
0455     .capabilities = 0,
0456     .stds = &hexium_standards[0],
0457     .num_stds = ARRAY_SIZE(hexium_standards),
0458     .std_callback = &std_callback,
0459 };
0460 
0461 static struct saa7146_extension extension = {
0462     .name = "hexium HV-PCI6 Orion",
0463     .flags = 0,     // SAA7146_USE_I2C_IRQ,
0464 
0465     .pci_tbl = &pci_tbl[0],
0466     .module = THIS_MODULE,
0467 
0468     .probe = hexium_probe,
0469     .attach = hexium_attach,
0470     .detach = hexium_detach,
0471 
0472     .irq_mask = 0,
0473     .irq_func = NULL,
0474 };
0475 
0476 static int __init hexium_init_module(void)
0477 {
0478     if (0 != saa7146_register_extension(&extension)) {
0479         DEB_S("failed to register extension\n");
0480         return -ENODEV;
0481     }
0482 
0483     return 0;
0484 }
0485 
0486 static void __exit hexium_cleanup_module(void)
0487 {
0488     saa7146_unregister_extension(&extension);
0489 }
0490 
0491 module_init(hexium_init_module);
0492 module_exit(hexium_cleanup_module);
0493 
0494 MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");
0495 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
0496 MODULE_LICENSE("GPL");