Path: blob/master/drivers/media/video/hexium_orion.c
17602 views
/*1hexium_orion.c - v4l2 driver for the Hexium Orion frame grabber cards23Visit http://www.mihu.de/linux/saa7146/ and follow the link4to "hexium" for further details about this card.56Copyright (C) 2003 Michael Hunold <[email protected]>78This program is free software; you can redistribute it and/or modify9it under the terms of the GNU General Public License as published by10the Free Software Foundation; either version 2 of the License, or11(at your option) any later version.1213This program is distributed in the hope that it will be useful,14but WITHOUT ANY WARRANTY; without even the implied warranty of15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16GNU General Public License for more details.1718You should have received a copy of the GNU General Public License19along with this program; if not, write to the Free Software20Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.21*/2223#define DEBUG_VARIABLE debug2425#include <media/saa7146_vv.h>2627static int debug;28module_param(debug, int, 0);29MODULE_PARM_DESC(debug, "debug verbosity");3031/* global variables */32static int hexium_num;3334#define HEXIUM_HV_PCI6_ORION 135#define HEXIUM_ORION_1SVHS_3BNC 236#define HEXIUM_ORION_4BNC 33738#define HEXIUM_INPUTS 939static 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, V4L2_IN_CAP_STD },41{ 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },42{ 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },43{ 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },44{ 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },45{ 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },46{ 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },47{ 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },48{ 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },49};5051#define HEXIUM_AUDIOS 05253struct hexium_data54{55s8 adr;56u8 byte;57};5859struct hexium60{61int type;62struct video_device *video_dev;63struct i2c_adapter i2c_adapter;6465int cur_input; /* current input */66};6768/* Philips SAA7110 decoder default registers */69static u8 hexium_saa7110[53]={70/*00*/ 0x4C,0x3C,0x0D,0xEF,0xBD,0xF0,0x00,0x00,71/*08*/ 0xF8,0xF8,0x60,0x60,0x40,0x86,0x18,0x90,72/*10*/ 0x00,0x2C,0x40,0x46,0x42,0x1A,0xFF,0xDA,73/*18*/ 0xF0,0x8B,0x00,0x00,0x00,0x00,0x00,0x00,74/*20*/ 0xD9,0x17,0x40,0x41,0x80,0x41,0x80,0x4F,75/*28*/ 0xFE,0x01,0x0F,0x0F,0x03,0x01,0x81,0x03,76/*30*/ 0x44,0x75,0x01,0x8C,0x0377};7879static struct {80struct hexium_data data[8];81} hexium_input_select[] = {82{83{ /* cvbs 1 */84{ 0x06, 0x00 },85{ 0x20, 0xD9 },86{ 0x21, 0x17 }, // 0x16,87{ 0x22, 0x40 },88{ 0x2C, 0x03 },89{ 0x30, 0x44 },90{ 0x31, 0x75 }, // ??91{ 0x21, 0x16 }, // 0x03,92}93}, {94{ /* cvbs 2 */95{ 0x06, 0x00 },96{ 0x20, 0x78 },97{ 0x21, 0x07 }, // 0x03,98{ 0x22, 0xD2 },99{ 0x2C, 0x83 },100{ 0x30, 0x60 },101{ 0x31, 0xB5 }, // ?102{ 0x21, 0x03 },103}104}, {105{ /* cvbs 3 */106{ 0x06, 0x00 },107{ 0x20, 0xBA },108{ 0x21, 0x07 }, // 0x05,109{ 0x22, 0x91 },110{ 0x2C, 0x03 },111{ 0x30, 0x60 },112{ 0x31, 0xB5 }, // ??113{ 0x21, 0x05 }, // 0x03,114}115}, {116{ /* cvbs 4 */117{ 0x06, 0x00 },118{ 0x20, 0xD8 },119{ 0x21, 0x17 }, // 0x16,120{ 0x22, 0x40 },121{ 0x2C, 0x03 },122{ 0x30, 0x44 },123{ 0x31, 0x75 }, // ??124{ 0x21, 0x16 }, // 0x03,125}126}, {127{ /* cvbs 5 */128{ 0x06, 0x00 },129{ 0x20, 0xB8 },130{ 0x21, 0x07 }, // 0x05,131{ 0x22, 0x91 },132{ 0x2C, 0x03 },133{ 0x30, 0x60 },134{ 0x31, 0xB5 }, // ??135{ 0x21, 0x05 }, // 0x03,136}137}, {138{ /* cvbs 6 */139{ 0x06, 0x00 },140{ 0x20, 0x7C },141{ 0x21, 0x07 }, // 0x03142{ 0x22, 0xD2 },143{ 0x2C, 0x83 },144{ 0x30, 0x60 },145{ 0x31, 0xB5 }, // ??146{ 0x21, 0x03 },147}148}, {149{ /* y/c 1 */150{ 0x06, 0x80 },151{ 0x20, 0x59 },152{ 0x21, 0x17 },153{ 0x22, 0x42 },154{ 0x2C, 0xA3 },155{ 0x30, 0x44 },156{ 0x31, 0x75 },157{ 0x21, 0x12 },158}159}, {160{ /* y/c 2 */161{ 0x06, 0x80 },162{ 0x20, 0x9A },163{ 0x21, 0x17 },164{ 0x22, 0xB1 },165{ 0x2C, 0x13 },166{ 0x30, 0x60 },167{ 0x31, 0xB5 },168{ 0x21, 0x14 },169}170}, {171{ /* y/c 3 */172{ 0x06, 0x80 },173{ 0x20, 0x3C },174{ 0x21, 0x27 },175{ 0x22, 0xC1 },176{ 0x2C, 0x23 },177{ 0x30, 0x44 },178{ 0x31, 0x75 },179{ 0x21, 0x21 },180}181}182};183184static struct saa7146_standard hexium_standards[] = {185{186.name = "PAL", .id = V4L2_STD_PAL,187.v_offset = 16, .v_field = 288,188.h_offset = 1, .h_pixels = 680,189.v_max_out = 576, .h_max_out = 768,190}, {191.name = "NTSC", .id = V4L2_STD_NTSC,192.v_offset = 16, .v_field = 240,193.h_offset = 1, .h_pixels = 640,194.v_max_out = 480, .h_max_out = 640,195}, {196.name = "SECAM", .id = V4L2_STD_SECAM,197.v_offset = 16, .v_field = 288,198.h_offset = 1, .h_pixels = 720,199.v_max_out = 576, .h_max_out = 768,200}201};202203/* this is only called for old HV-PCI6/Orion cards204without eeprom */205static int hexium_probe(struct saa7146_dev *dev)206{207struct hexium *hexium = NULL;208union i2c_smbus_data data;209int err = 0;210211DEB_EE((".\n"));212213/* there are no hexium orion cards with revision 0 saa7146s */214if (0 == dev->revision) {215return -EFAULT;216}217218hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);219if (NULL == hexium) {220printk("hexium_orion: hexium_probe: not enough kernel memory.\n");221return -ENOMEM;222}223224/* enable i2c-port pins */225saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));226227saa7146_write(dev, DD1_INIT, 0x01000100);228saa7146_write(dev, DD1_STREAM_B, 0x00000000);229saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));230231hexium->i2c_adapter = (struct i2c_adapter) {232.name = "hexium orion",233};234saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);235if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {236DEB_S(("cannot register i2c-device. skipping.\n"));237kfree(hexium);238return -EFAULT;239}240241/* set SAA7110 control GPIO 0 */242saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI);243/* set HWControl GPIO number 2 */244saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);245246mdelay(10);247248/* detect newer Hexium Orion cards by subsystem ids */249if (0x17c8 == dev->pci->subsystem_vendor && 0x0101 == dev->pci->subsystem_device) {250printk("hexium_orion: device is a Hexium Orion w/ 1 SVHS + 3 BNC inputs.\n");251/* we store the pointer in our private data field */252dev->ext_priv = hexium;253hexium->type = HEXIUM_ORION_1SVHS_3BNC;254return 0;255}256257if (0x17c8 == dev->pci->subsystem_vendor && 0x2101 == dev->pci->subsystem_device) {258printk("hexium_orion: device is a Hexium Orion w/ 4 BNC inputs.\n");259/* we store the pointer in our private data field */260dev->ext_priv = hexium;261hexium->type = HEXIUM_ORION_4BNC;262return 0;263}264265/* check if this is an old hexium Orion card by looking at266a saa7110 at address 0x4e */267if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) {268printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n");269/* we store the pointer in our private data field */270dev->ext_priv = hexium;271hexium->type = HEXIUM_HV_PCI6_ORION;272return 0;273}274275i2c_del_adapter(&hexium->i2c_adapter);276kfree(hexium);277return -EFAULT;278}279280/* bring hardware to a sane state. this has to be done, just in case someone281wants to capture from this device before it has been properly initialized.282the capture engine would badly fail, because no valid signal arrives on the283saa7146, thus leading to timeouts and stuff. */284static int hexium_init_done(struct saa7146_dev *dev)285{286struct hexium *hexium = (struct hexium *) dev->ext_priv;287union i2c_smbus_data data;288int i = 0;289290DEB_D(("hexium_init_done called.\n"));291292/* initialize the helper ics to useful values */293for (i = 0; i < sizeof(hexium_saa7110); i++) {294data.byte = hexium_saa7110[i];295if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, i, I2C_SMBUS_BYTE_DATA, &data)) {296printk("hexium_orion: failed for address 0x%02x\n", i);297}298}299300return 0;301}302303static int hexium_set_input(struct hexium *hexium, int input)304{305union i2c_smbus_data data;306int i = 0;307308DEB_D((".\n"));309310for (i = 0; i < 8; i++) {311int adr = hexium_input_select[input].data[i].adr;312data.byte = hexium_input_select[input].data[i].byte;313if (0 != i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_WRITE, adr, I2C_SMBUS_BYTE_DATA, &data)) {314return -1;315}316printk("%d: 0x%02x => 0x%02x\n",input, adr,data.byte);317}318319return 0;320}321322static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)323{324DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));325326if (i->index >= HEXIUM_INPUTS)327return -EINVAL;328329memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));330331DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));332return 0;333}334335static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)336{337struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;338struct hexium *hexium = (struct hexium *) dev->ext_priv;339340*input = hexium->cur_input;341342DEB_D(("VIDIOC_G_INPUT: %d\n", *input));343return 0;344}345346static int vidioc_s_input(struct file *file, void *fh, unsigned int input)347{348struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;349struct hexium *hexium = (struct hexium *) dev->ext_priv;350351if (input >= HEXIUM_INPUTS)352return -EINVAL;353354hexium->cur_input = input;355hexium_set_input(hexium, input);356357return 0;358}359360static struct saa7146_ext_vv vv_data;361362/* this function only gets called when the probing was successful */363static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)364{365struct hexium *hexium = (struct hexium *) dev->ext_priv;366367DEB_EE((".\n"));368369saa7146_vv_init(dev, &vv_data);370vv_data.ops.vidioc_enum_input = vidioc_enum_input;371vv_data.ops.vidioc_g_input = vidioc_g_input;372vv_data.ops.vidioc_s_input = vidioc_s_input;373if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {374printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");375return -1;376}377378printk("hexium_orion: found 'hexium orion' frame grabber-%d.\n", hexium_num);379hexium_num++;380381/* the rest */382hexium->cur_input = 0;383hexium_init_done(dev);384385return 0;386}387388static int hexium_detach(struct saa7146_dev *dev)389{390struct hexium *hexium = (struct hexium *) dev->ext_priv;391392DEB_EE(("dev:%p\n", dev));393394saa7146_unregister_device(&hexium->video_dev, dev);395saa7146_vv_release(dev);396397hexium_num--;398399i2c_del_adapter(&hexium->i2c_adapter);400kfree(hexium);401return 0;402}403404static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)405{406return 0;407}408409static struct saa7146_extension extension;410411static struct saa7146_pci_extension_data hexium_hv_pci6 = {412.ext_priv = "Hexium HV-PCI6 / Orion",413.ext = &extension,414};415416static struct saa7146_pci_extension_data hexium_orion_1svhs_3bnc = {417.ext_priv = "Hexium HV-PCI6 / Orion (1 SVHS/3 BNC)",418.ext = &extension,419};420421static struct saa7146_pci_extension_data hexium_orion_4bnc = {422.ext_priv = "Hexium HV-PCI6 / Orion (4 BNC)",423.ext = &extension,424};425426static struct pci_device_id pci_tbl[] = {427{428.vendor = PCI_VENDOR_ID_PHILIPS,429.device = PCI_DEVICE_ID_PHILIPS_SAA7146,430.subvendor = 0x0000,431.subdevice = 0x0000,432.driver_data = (unsigned long) &hexium_hv_pci6,433},434{435.vendor = PCI_VENDOR_ID_PHILIPS,436.device = PCI_DEVICE_ID_PHILIPS_SAA7146,437.subvendor = 0x17c8,438.subdevice = 0x0101,439.driver_data = (unsigned long) &hexium_orion_1svhs_3bnc,440},441{442.vendor = PCI_VENDOR_ID_PHILIPS,443.device = PCI_DEVICE_ID_PHILIPS_SAA7146,444.subvendor = 0x17c8,445.subdevice = 0x2101,446.driver_data = (unsigned long) &hexium_orion_4bnc,447},448{449.vendor = 0,450}451};452453MODULE_DEVICE_TABLE(pci, pci_tbl);454455static struct saa7146_ext_vv vv_data = {456.inputs = HEXIUM_INPUTS,457.capabilities = 0,458.stds = &hexium_standards[0],459.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),460.std_callback = &std_callback,461};462463static struct saa7146_extension extension = {464.name = "hexium HV-PCI6 Orion",465.flags = 0, // SAA7146_USE_I2C_IRQ,466467.pci_tbl = &pci_tbl[0],468.module = THIS_MODULE,469470.probe = hexium_probe,471.attach = hexium_attach,472.detach = hexium_detach,473474.irq_mask = 0,475.irq_func = NULL,476};477478static int __init hexium_init_module(void)479{480if (0 != saa7146_register_extension(&extension)) {481DEB_S(("failed to register extension.\n"));482return -ENODEV;483}484485return 0;486}487488static void __exit hexium_cleanup_module(void)489{490saa7146_unregister_extension(&extension);491}492493module_init(hexium_init_module);494module_exit(hexium_cleanup_module);495496MODULE_DESCRIPTION("video4linux-2 driver for Hexium Orion frame grabber cards");497MODULE_AUTHOR("Michael Hunold <[email protected]>");498MODULE_LICENSE("GPL");499500501