0001
0002
0003
0004
0005
0006
0007
0008
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
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;
0059 };
0060
0061
0062 static u8 hexium_saa7110[53]={
0063 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,
0064 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,
0065 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,
0066 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,
0067 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,
0068 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,
0069 0x44,0x75,0x01,0x8C,0x03
0070 };
0071
0072 static struct {
0073 struct hexium_data data[8];
0074 } hexium_input_select[] = {
0075 {
0076 {
0077 { 0x06, 0x00 },
0078 { 0x20, 0xD9 },
0079 { 0x21, 0x17 },
0080 { 0x22, 0x40 },
0081 { 0x2C, 0x03 },
0082 { 0x30, 0x44 },
0083 { 0x31, 0x75 },
0084 { 0x21, 0x16 },
0085 }
0086 }, {
0087 {
0088 { 0x06, 0x00 },
0089 { 0x20, 0x78 },
0090 { 0x21, 0x07 },
0091 { 0x22, 0xD2 },
0092 { 0x2C, 0x83 },
0093 { 0x30, 0x60 },
0094 { 0x31, 0xB5 },
0095 { 0x21, 0x03 },
0096 }
0097 }, {
0098 {
0099 { 0x06, 0x00 },
0100 { 0x20, 0xBA },
0101 { 0x21, 0x07 },
0102 { 0x22, 0x91 },
0103 { 0x2C, 0x03 },
0104 { 0x30, 0x60 },
0105 { 0x31, 0xB5 },
0106 { 0x21, 0x05 },
0107 }
0108 }, {
0109 {
0110 { 0x06, 0x00 },
0111 { 0x20, 0xD8 },
0112 { 0x21, 0x17 },
0113 { 0x22, 0x40 },
0114 { 0x2C, 0x03 },
0115 { 0x30, 0x44 },
0116 { 0x31, 0x75 },
0117 { 0x21, 0x16 },
0118 }
0119 }, {
0120 {
0121 { 0x06, 0x00 },
0122 { 0x20, 0xB8 },
0123 { 0x21, 0x07 },
0124 { 0x22, 0x91 },
0125 { 0x2C, 0x03 },
0126 { 0x30, 0x60 },
0127 { 0x31, 0xB5 },
0128 { 0x21, 0x05 },
0129 }
0130 }, {
0131 {
0132 { 0x06, 0x00 },
0133 { 0x20, 0x7C },
0134 { 0x21, 0x07 },
0135 { 0x22, 0xD2 },
0136 { 0x2C, 0x83 },
0137 { 0x30, 0x60 },
0138 { 0x31, 0xB5 },
0139 { 0x21, 0x03 },
0140 }
0141 }, {
0142 {
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 {
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 {
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
0197
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
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
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
0232 saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);
0233
0234 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
0235
0236 mdelay(10);
0237
0238
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
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
0250 dev->ext_priv = hexium;
0251 hexium->type = HEXIUM_ORION_4BNC;
0252 return 0;
0253 }
0254
0255
0256
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
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
0273
0274
0275
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
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
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
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,
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");