?? budget-av.c
字號:
/* * budget-av.c: driver for the SAA7146 based Budget DVB cards * with analog video in * * Compiled from various sources by Michael Hunold <michael@mihu.de> * * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> & * Andrew de Quincey <adq_dvb@lidskialf.net> * * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> * * Copyright (C) 1999-2002 Ralph Metzler * & Marcus Metzler for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * * the project's page is at http://www.linuxtv.org/dvb/ */#include "budget.h"#include "stv0299.h"#include "tda10021.h"#include "tda1004x.h"#include "dvb-pll.h"#include <media/saa7146_vv.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/input.h>#include <linux/spinlock.h>#include "dvb_ca_en50221.h"#define DEBICICAM 0x02420000struct budget_av { struct budget budget; struct video_device *vd; int cur_input; int has_saa7113; struct tasklet_struct ciintf_irq_tasklet; int slot_status; struct dvb_ca_en50221 ca;};/* GPIO Connections: * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory * 2 - CI Card Enable (Active Low) * 3 - CI Card Detect *//**************************************************************************** * INITIALIZATION ****************************************************************************/static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg){ u8 mm1[] = { 0x00 }; u8 mm2[] = { 0x00 }; struct i2c_msg msgs[2]; msgs[0].flags = 0; msgs[1].flags = I2C_M_RD; msgs[0].addr = msgs[1].addr = id / 2; mm1[0] = reg; msgs[0].len = 1; msgs[1].len = 1; msgs[0].buf = mm1; msgs[1].buf = mm2; i2c_transfer(i2c, msgs, 2); return mm2[0];}static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len){ u8 mm1[] = { reg }; struct i2c_msg msgs[2] = { {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1}, {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len} }; if (i2c_transfer(i2c, msgs, 2) != 2) return -EIO; return 0;}static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val){ u8 msg[2] = { reg, val }; struct i2c_msg msgs; msgs.flags = 0; msgs.addr = id / 2; msgs.len = 2; msgs.buf = msg; return i2c_transfer(i2c, &msgs, 1);}static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address){ struct budget_av *budget_av = (struct budget_av *) ca->data; int result; if (slot != 0) return -EINVAL; saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); if (result == -ETIMEDOUT) budget_av->slot_status = 0; return result;}static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value){ struct budget_av *budget_av = (struct budget_av *) ca->data; int result; if (slot != 0) return -EINVAL; saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); udelay(1); result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); if (result == -ETIMEDOUT) budget_av->slot_status = 0; return result;}static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address){ struct budget_av *budget_av = (struct budget_av *) ca->data; int result; if (slot != 0) return -EINVAL; saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); udelay(1); result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); if (result == -ETIMEDOUT) budget_av->slot_status = 0; return result;}static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value){ struct budget_av *budget_av = (struct budget_av *) ca->data; int result; if (slot != 0) return -EINVAL; saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); udelay(1); result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); if (result == -ETIMEDOUT) budget_av->slot_status = 0; return result;}static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot){ struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; int timeout = 50; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; dprintk(1, "ciintf_slot_reset\n"); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */ msleep(2); saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */ msleep(20); /* 20 ms Vcc settling time */ saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ /* This should have been based on pin 16 READY of the pcmcia port, * but AFAICS it is not routed to the saa7146 */ while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) msleep(100); /* reinitialise the frontend */ dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); if (timeout <= 0) { printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ return -ETIMEDOUT; } return 0;}static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot){ struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; if (slot != 0) return -EINVAL; dprintk(1, "ciintf_slot_shutdown\n"); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); budget_av->slot_status = 0; return 0;}static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot){ struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; if (slot != 0) return -EINVAL; dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); return 0;}static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open){ struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; int cam_present = 0; if (slot != 0) return -EINVAL; if (!budget_av->slot_status) { // first of all test the card detect line saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); udelay(1); if (saa7146_read(saa, PSR) & MASK_06) { cam_present = 1; } saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); // that is unreliable however, so try and read from IO memory if (!cam_present) { saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) { cam_present = 1; } } // did we find something? if (cam_present) { printk(KERN_INFO "budget-av: cam inserted\n"); budget_av->slot_status = 1; } } else if (!open) { saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) { printk(KERN_INFO "budget-av: cam ejected\n"); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ budget_av->slot_status = 0; } } if (budget_av->slot_status == 1) return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; return 0;}static int ciintf_init(struct budget_av *budget_av){ struct saa7146_dev *saa = budget_av->budget.dev; int result; memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); /* Enable DEBI pins */ saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); /* register CI interface */ budget_av->ca.owner = THIS_MODULE; budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; budget_av->ca.read_cam_control = ciintf_read_cam_control; budget_av->ca.write_cam_control = ciintf_write_cam_control; budget_av->ca.slot_reset = ciintf_slot_reset; budget_av->ca.slot_shutdown = ciintf_slot_shutdown; budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; budget_av->ca.poll_slot_status = ciintf_poll_slot_status; budget_av->ca.data = budget_av; if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, &budget_av->ca, 0, 1)) != 0) { printk(KERN_ERR "budget-av: ci initialisation failed.\n"); goto error; } printk(KERN_INFO "budget-av: ci interface initialised.\n"); budget_av->budget.ci_present = 1; return 0;error: saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16)); return result;}static void ciintf_deinit(struct budget_av *budget_av){ struct saa7146_dev *saa = budget_av->budget.dev; saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); /* release the CA device */ dvb_ca_en50221_release(&budget_av->ca); /* disable DEBI pins */ saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));}static const u8 saa7113_tab[] = { 0x01, 0x08, 0x02, 0xc0, 0x03, 0x33, 0x04, 0x00, 0x05, 0x00, 0x06, 0xeb, 0x07, 0xe0, 0x08, 0x28, 0x09, 0x00, 0x0a, 0x80, 0x0b, 0x47, 0x0c, 0x40, 0x0d, 0x00, 0x0e, 0x01, 0x0f, 0x44, 0x10, 0x08, 0x11, 0x0c, 0x12, 0x7b, 0x13, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, 0x57, 0xff, 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07, 0x5b, 0x83, 0x5e, 0x00, 0xff};static int saa7113_init(struct budget_av *budget_av){ struct budget *budget = &budget_av->budget; struct saa7146_dev *saa = budget->dev; const u8 *data = saa7113_tab; saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); msleep(200); if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) { dprintk(1, "saa7113 not found on KNC card\n"); return -ENODEV; } dprintk(1, "saa7113 detected and initializing\n"); while (*data != 0xff) { i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1)); data += 2; } dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f)); return 0;}static int saa7113_setinput(struct budget_av *budget_av, int input){ struct budget *budget = &budget_av->budget; if (1 != budget_av->has_saa7113) return -ENODEV; if (input == 1) { i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7); i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80); } else if (input == 0) { i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0); i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00); } else return -EINVAL; budget_av->cur_input = input; return 0;}static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio){ u8 aclk = 0; u8 bclk = 0; u8 m1; aclk = 0xb5; if (srate < 2000000) bclk = 0x86; else if (srate < 5000000)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -