2005-04-17 02:20:36 +04:00
/*
* driver for the SAA7146 based AV110 cards ( like the Fujitsu - Siemens DVB )
* av7110 . c : initialization and demux stuff
*
* Copyright ( C ) 1999 - 2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
*
* originally based on code by :
* Copyright ( C ) 1998 , 1999 Christian Theiss < mistert @ rz . fh - augsburg . de >
*
* 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 <linux/module.h>
# include <linux/kmod.h>
# include <linux/delay.h>
# include <linux/fs.h>
# include <linux/timer.h>
# include <linux/poll.h>
# include <linux/byteorder/swabb.h>
# include <linux/smp_lock.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/interrupt.h>
# include <linux/string.h>
# include <linux/pci.h>
# include <linux/vmalloc.h>
# include <linux/firmware.h>
# include <linux/crc32.h>
# include <linux/i2c.h>
2007-02-08 20:32:43 +03:00
# include <linux/kthread.h>
2005-04-17 02:20:36 +04:00
# include <asm/system.h>
# include <linux/dvb/frontend.h>
# include "dvb_frontend.h"
# include "ttpci-eeprom.h"
# include "av7110.h"
# include "av7110_hw.h"
# include "av7110_av.h"
# include "av7110_ca.h"
# include "av7110_ipack.h"
2006-02-28 16:32:25 +03:00
# include "bsbe1.h"
# include "lnbp21.h"
2006-03-16 17:22:47 +03:00
# include "bsru6.h"
2006-02-28 16:32:25 +03:00
2005-04-17 02:20:36 +04:00
# define TS_WIDTH 376
# define TS_HEIGHT 512
# define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
# define TS_MAX_PACKETS (TS_BUFLEN / TS_SIZE)
int av7110_debug ;
static int vidmode = CVBS_RGB_OUT ;
static int pids_off ;
static int adac = DVB_ADAC_TI ;
static int hw_sections ;
static int rgb_on ;
static int volume = 255 ;
2006-01-13 19:10:19 +03:00
static int budgetpatch ;
2006-03-17 11:29:15 +03:00
static int wss_cfg_4_3 = 0x4008 ;
static int wss_cfg_16_9 = 0x0007 ;
2006-03-30 11:31:48 +04:00
static int tv_standard ;
2005-04-17 02:20:36 +04:00
module_param_named ( debug , av7110_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " debug level (bitmask, default 0) " ) ;
module_param ( vidmode , int , 0444 ) ;
MODULE_PARM_DESC ( vidmode , " analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC " ) ;
module_param ( pids_off , int , 0444 ) ;
MODULE_PARM_DESC ( pids_off , " clear video/audio/PCR PID filters when demux is closed " ) ;
module_param ( adac , int , 0444 ) ;
MODULE_PARM_DESC ( adac , " audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails) " ) ;
module_param ( hw_sections , int , 0444 ) ;
MODULE_PARM_DESC ( hw_sections , " 0 use software section filter, 1 use hardware " ) ;
module_param ( rgb_on , int , 0444 ) ;
MODULE_PARM_DESC ( rgb_on , " For Siemens DVB-C cards only: Enable RGB control "
" signal on SCART pin 16 to switch SCART video mode from CVBS to RGB " ) ;
module_param ( volume , int , 0444 ) ;
MODULE_PARM_DESC ( volume , " initial volume: default 255 (range 0-255) " ) ;
module_param ( budgetpatch , int , 0444 ) ;
MODULE_PARM_DESC ( budgetpatch , " use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always) " ) ;
2006-03-17 11:29:15 +03:00
module_param ( wss_cfg_4_3 , int , 0444 ) ;
MODULE_PARM_DESC ( wss_cfg_4_3 , " WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data " ) ;
module_param ( wss_cfg_16_9 , int , 0444 ) ;
MODULE_PARM_DESC ( wss_cfg_16_9 , " WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data " ) ;
2006-03-30 11:31:48 +04:00
module_param ( tv_standard , int , 0444 ) ;
MODULE_PARM_DESC ( tv_standard , " TV standard: 0 PAL (default), 1 NTSC " ) ;
2005-04-17 02:20:36 +04:00
2008-04-10 02:13:13 +04:00
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2005-04-17 02:20:36 +04:00
static void restart_feeds ( struct av7110 * av7110 ) ;
2006-01-13 19:10:19 +03:00
static int av7110_num ;
2005-04-17 02:20:36 +04:00
# define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \
{ \
if ( fe_func ! = NULL ) { \
av7110_copy = fe_func ; \
fe_func = av7110_func ; \
} \
}
static void init_av7110_av ( struct av7110 * av7110 )
{
2005-07-08 04:57:59 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
struct saa7146_dev * dev = av7110 - > dev ;
/* set internal volume control to maximum */
av7110 - > adac_type = DVB_ADAC_TI ;
2005-07-08 04:57:59 +04:00
ret = av7110_set_volume ( av7110 , av7110 - > mixer . volume_left , av7110 - > mixer . volume_right ) ;
2005-07-08 04:58:01 +04:00
if ( ret < 0 )
2005-07-08 04:57:59 +04:00
printk ( " dvb-ttpci:cannot set internal volume to maximum:%d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
2007-07-13 06:08:07 +04:00
ret = av7110_fw_cmd ( av7110 , COMTYPE_ENCODER , SetMonitorType ,
1 , ( u16 ) av7110 - > display_ar ) ;
if ( ret < 0 )
printk ( " dvb-ttpci: unable to set aspect ratio \n " ) ;
ret = av7110_fw_cmd ( av7110 , COMTYPE_ENCODER , SetPanScanType ,
1 , av7110 - > display_panscan ) ;
if ( ret < 0 )
printk ( " dvb-ttpci: unable to set pan scan \n " ) ;
2006-03-17 11:29:15 +03:00
ret = av7110_fw_cmd ( av7110 , COMTYPE_ENCODER , SetWSSConfig , 2 , 2 , wss_cfg_4_3 ) ;
if ( ret < 0 )
printk ( " dvb-ttpci: unable to configure 4:3 wss \n " ) ;
ret = av7110_fw_cmd ( av7110 , COMTYPE_ENCODER , SetWSSConfig , 2 , 3 , wss_cfg_16_9 ) ;
if ( ret < 0 )
printk ( " dvb-ttpci: unable to configure 16:9 wss \n " ) ;
2005-07-08 04:57:59 +04:00
ret = av7710_set_video_mode ( av7110 , vidmode ) ;
2005-07-08 04:58:01 +04:00
if ( ret < 0 )
2005-07-08 04:57:59 +04:00
printk ( " dvb-ttpci:cannot set video mode:%d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
/* handle different card types */
/* remaining inits according to card and frontend type */
av7110 - > analog_tuner_flags = 0 ;
av7110 - > current_input = 0 ;
2006-06-25 16:14:07 +04:00
if ( dev - > pci - > subsystem_vendor = = 0x13c2 & & dev - > pci - > subsystem_device = = 0x000a )
2006-01-09 20:25:06 +03:00
av7110_fw_cmd ( av7110 , COMTYPE_AUDIODAC , ADSwitch , 1 , 0 ) ; // SPDIF on
2006-06-25 16:14:07 +04:00
if ( i2c_writereg ( av7110 , 0x20 , 0x00 , 0x00 ) = = 1 ) {
2005-04-17 02:20:36 +04:00
printk ( " dvb-ttpci: Crystal audio DAC @ card %d detected \n " ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . num ) ;
2005-04-17 02:20:36 +04:00
av7110 - > adac_type = DVB_ADAC_CRYSTAL ;
i2c_writereg ( av7110 , 0x20 , 0x01 , 0xd2 ) ;
i2c_writereg ( av7110 , 0x20 , 0x02 , 0x49 ) ;
i2c_writereg ( av7110 , 0x20 , 0x03 , 0x00 ) ;
i2c_writereg ( av7110 , 0x20 , 0x04 , 0x00 ) ;
/**
* some special handling for the Siemens DVB - C cards . . .
*/
} else if ( 0 = = av7110_init_analog_module ( av7110 ) ) {
/* done. */
}
else if ( dev - > pci - > subsystem_vendor = = 0x110a ) {
printk ( " dvb-ttpci: DVB-C w/o analog module @ card %d detected \n " ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . num ) ;
2005-04-17 02:20:36 +04:00
av7110 - > adac_type = DVB_ADAC_NONE ;
}
else {
av7110 - > adac_type = adac ;
printk ( " dvb-ttpci: adac type set to %d @ card %d \n " ,
2006-01-09 20:25:06 +03:00
av7110 - > adac_type , av7110 - > dvb_adapter . num ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-09 20:25:06 +03:00
if ( av7110 - > adac_type = = DVB_ADAC_NONE | | av7110 - > adac_type = = DVB_ADAC_MSP34x0 ) {
2005-04-17 02:20:36 +04:00
// switch DVB SCART on
2005-07-08 04:57:59 +04:00
ret = av7110_fw_cmd ( av7110 , COMTYPE_AUDIODAC , MainSwitch , 1 , 0 ) ;
2005-07-08 04:58:01 +04:00
if ( ret < 0 )
2005-07-08 04:57:59 +04:00
printk ( " dvb-ttpci:cannot switch on SCART(Main):%d \n " , ret ) ;
ret = av7110_fw_cmd ( av7110 , COMTYPE_AUDIODAC , ADSwitch , 1 , 1 ) ;
2005-07-08 04:58:01 +04:00
if ( ret < 0 )
2005-07-08 04:57:59 +04:00
printk ( " dvb-ttpci:cannot switch on SCART(AD):%d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
if ( rgb_on & &
2005-09-10 00:03:13 +04:00
( ( av7110 - > dev - > pci - > subsystem_vendor = = 0x110a ) | |
( av7110 - > dev - > pci - > subsystem_vendor = = 0x13c2 ) ) & &
( av7110 - > dev - > pci - > subsystem_device = = 0x0000 ) ) {
2005-04-17 02:20:36 +04:00
saa7146_setgpio ( dev , 1 , SAA7146_GPIO_OUTHI ) ; // RGB on, SCART pin 16
//saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // SCARTpin 8
}
}
2005-12-19 13:54:11 +03:00
if ( dev - > pci - > subsystem_vendor = = 0x13c2 & & dev - > pci - > subsystem_device = = 0x000e )
av7110_fw_cmd ( av7110 , COMTYPE_AUDIODAC , SpdifSwitch , 1 , 0 ) ; // SPDIF on
2005-07-08 04:57:59 +04:00
ret = av7110_set_volume ( av7110 , av7110 - > mixer . volume_left , av7110 - > mixer . volume_right ) ;
2005-07-08 04:58:01 +04:00
if ( ret < 0 )
2005-07-08 04:57:59 +04:00
printk ( " dvb-ttpci:cannot set volume :%d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
}
static void recover_arm ( struct av7110 * av7110 )
{
dprintk ( 4 , " %p \n " , av7110 ) ;
av7110_bootarm ( av7110 ) ;
msleep ( 100 ) ;
2006-01-09 20:32:42 +03:00
init_av7110_av ( av7110 ) ;
2005-04-17 02:20:36 +04:00
2006-01-09 20:32:42 +03:00
/* card-specific recovery */
if ( av7110 - > recover )
av7110 - > recover ( av7110 ) ;
restart_feeds ( av7110 ) ;
2007-04-27 19:31:21 +04:00
# if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
av7110_check_ir_config ( av7110 , true ) ;
# endif
2005-04-17 02:20:36 +04:00
}
static void av7110_arm_sync ( struct av7110 * av7110 )
{
2007-02-08 20:32:43 +03:00
if ( av7110 - > arm_thread )
kthread_stop ( av7110 - > arm_thread ) ;
2005-04-17 02:20:36 +04:00
2007-02-08 20:32:43 +03:00
av7110 - > arm_thread = NULL ;
2005-04-17 02:20:36 +04:00
}
static int arm_thread ( void * data )
{
struct av7110 * av7110 = data ;
u16 newloops = 0 ;
int timeout ;
dprintk ( 4 , " %p \n " , av7110 ) ;
for ( ; ; ) {
timeout = wait_event_interruptible_timeout ( av7110 - > arm_wait ,
2007-02-08 20:32:43 +03:00
kthread_should_stop ( ) , 5 * HZ ) ;
if ( - ERESTARTSYS = = timeout | | kthread_should_stop ( ) ) {
2005-04-17 02:20:36 +04:00
/* got signal or told to quit*/
break ;
}
if ( ! av7110 - > arm_ready )
continue ;
2007-04-27 19:31:21 +04:00
# if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
av7110_check_ir_config ( av7110 , false ) ;
# endif
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > dcomlock ) )
2005-04-17 02:20:36 +04:00
break ;
newloops = rdebi ( av7110 , DEBINOSWAP , STATUS_LOOPS , 0 , 2 ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
2006-01-09 20:32:42 +03:00
if ( newloops = = av7110 - > arm_loops | | av7110 - > arm_errors > 3 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: ARM crashed @ card %d \n " ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . num ) ;
2005-04-17 02:20:36 +04:00
2006-01-09 20:32:42 +03:00
recover_arm ( av7110 ) ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > dcomlock ) )
2005-04-17 02:20:36 +04:00
break ;
newloops = rdebi ( av7110 , DEBINOSWAP , STATUS_LOOPS , 0 , 2 ) - 1 ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
}
av7110 - > arm_loops = newloops ;
2006-01-09 20:32:42 +03:00
av7110 - > arm_errors = 0 ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/****************************************************************************
* IRQ handling
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int DvbDmxFilterCallback ( u8 * buffer1 , size_t buffer1_len ,
u8 * buffer2 , size_t buffer2_len ,
struct dvb_demux_filter * dvbdmxfilter ,
enum dmx_success success ,
struct av7110 * av7110 )
{
if ( ! dvbdmxfilter - > feed - > demux - > dmx . frontend )
return 0 ;
if ( dvbdmxfilter - > feed - > demux - > dmx . frontend - > source = = DMX_MEMORY_FE )
return 0 ;
switch ( dvbdmxfilter - > type ) {
case DMX_TYPE_SEC :
if ( ( ( ( buffer1 [ 1 ] < < 8 ) | buffer1 [ 2 ] ) & 0xfff ) + 3 ! = buffer1_len )
return 0 ;
if ( dvbdmxfilter - > doneq ) {
struct dmx_section_filter * filter = & dvbdmxfilter - > filter ;
int i ;
u8 xor , neq = 0 ;
for ( i = 0 ; i < DVB_DEMUX_MASK_MAX ; i + + ) {
xor = filter - > filter_value [ i ] ^ buffer1 [ i ] ;
neq | = dvbdmxfilter - > maskandnotmode [ i ] & xor ;
}
if ( ! neq )
return 0 ;
}
return dvbdmxfilter - > feed - > cb . sec ( buffer1 , buffer1_len ,
buffer2 , buffer2_len ,
& dvbdmxfilter - > filter ,
DMX_OK ) ;
case DMX_TYPE_TS :
if ( ! ( dvbdmxfilter - > feed - > ts_type & TS_PACKET ) )
return 0 ;
if ( dvbdmxfilter - > feed - > ts_type & TS_PAYLOAD_ONLY )
return dvbdmxfilter - > feed - > cb . ts ( buffer1 , buffer1_len ,
buffer2 , buffer2_len ,
& dvbdmxfilter - > feed - > feed . ts ,
DMX_OK ) ;
else
av7110_p2t_write ( buffer1 , buffer1_len ,
dvbdmxfilter - > feed - > pid ,
& av7110 - > p2t_filter [ dvbdmxfilter - > index ] ) ;
default :
return 0 ;
}
}
//#define DEBUG_TIMING
static inline void print_time ( char * s )
{
# ifdef DEBUG_TIMING
struct timeval tv ;
do_gettimeofday ( & tv ) ;
printk ( " %s: %d.%d \n " , s , ( int ) tv . tv_sec , ( int ) tv . tv_usec ) ;
# endif
}
# define DEBI_READ 0
# define DEBI_WRITE 1
static inline void start_debi_dma ( struct av7110 * av7110 , int dir ,
unsigned long addr , unsigned int len )
{
dprintk ( 8 , " %c %08lx %u \n " , dir = = DEBI_READ ? ' R ' : ' W ' , addr , len ) ;
if ( saa7146_wait_for_debi_done ( av7110 - > dev , 0 ) ) {
2008-04-09 06:20:00 +04:00
printk ( KERN_ERR " %s: saa7146_wait_for_debi_done timed out \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
SAA7146_ISR_CLEAR ( av7110 - > dev , MASK_19 ) ; /* for good measure */
SAA7146_IER_ENABLE ( av7110 - > dev , MASK_19 ) ;
if ( len < 5 )
len = 5 ; /* we want a real DEBI DMA */
if ( dir = = DEBI_WRITE )
iwdebi ( av7110 , DEBISWAB , addr , 0 , ( len + 3 ) & ~ 3 ) ;
else
irdebi ( av7110 , DEBISWAB , addr , 0 , len ) ;
}
static void debiirq ( unsigned long data )
{
struct av7110 * av7110 = ( struct av7110 * ) data ;
int type = av7110 - > debitype ;
int handle = ( type > > 8 ) & 0x1f ;
unsigned int xfer = 0 ;
print_time ( " debi " ) ;
dprintk ( 4 , " type 0x%04x \n " , type ) ;
if ( type = = - 1 ) {
printk ( " DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x \n " ,
jiffies , saa7146_read ( av7110 - > dev , PSR ) ,
saa7146_read ( av7110 - > dev , SSR ) ) ;
goto debi_done ;
}
av7110 - > debitype = - 1 ;
switch ( type & 0xff ) {
case DATA_TS_RECORD :
dvb_dmx_swfilter_packets ( & av7110 - > demux ,
( const u8 * ) av7110 - > debi_virt ,
av7110 - > debilen / 188 ) ;
xfer = RX_BUFF ;
break ;
case DATA_PES_RECORD :
if ( av7110 - > demux . recording )
av7110_record_cb ( & av7110 - > p2t [ handle ] ,
( u8 * ) av7110 - > debi_virt ,
av7110 - > debilen ) ;
xfer = RX_BUFF ;
break ;
case DATA_IPMPE :
case DATA_FSECTION :
case DATA_PIPING :
if ( av7110 - > handle2filter [ handle ] )
DvbDmxFilterCallback ( ( u8 * ) av7110 - > debi_virt ,
av7110 - > debilen , NULL , 0 ,
av7110 - > handle2filter [ handle ] ,
DMX_OK , av7110 ) ;
xfer = RX_BUFF ;
break ;
case DATA_CI_GET :
{
u8 * data = av7110 - > debi_virt ;
if ( ( data [ 0 ] < 2 ) & & data [ 2 ] = = 0xff ) {
int flags = 0 ;
if ( data [ 5 ] > 0 )
flags | = CA_CI_MODULE_PRESENT ;
if ( data [ 5 ] > 5 )
flags | = CA_CI_MODULE_READY ;
av7110 - > ci_slot [ data [ 0 ] ] . flags = flags ;
} else
ci_get_data ( & av7110 - > ci_rbuffer ,
av7110 - > debi_virt ,
av7110 - > debilen ) ;
xfer = RX_BUFF ;
break ;
}
case DATA_COMMON_INTERFACE :
CI_handle ( av7110 , ( u8 * ) av7110 - > debi_virt , av7110 - > debilen ) ;
#if 0
{
int i ;
printk ( " av7110%d: " , av7110 - > num ) ;
printk ( " %02x " , * ( u8 * ) av7110 - > debi_virt ) ;
printk ( " %02x " , * ( 1 + ( u8 * ) av7110 - > debi_virt ) ) ;
for ( i = 2 ; i < av7110 - > debilen ; i + + )
printk ( " %02x " , ( * ( i + ( unsigned char * ) av7110 - > debi_virt ) ) ) ;
for ( i = 2 ; i < av7110 - > debilen ; i + + )
printk ( " %c " , chtrans ( * ( i + ( unsigned char * ) av7110 - > debi_virt ) ) ) ;
printk ( " \n " ) ;
}
# endif
xfer = RX_BUFF ;
break ;
case DATA_DEBUG_MESSAGE :
( ( s8 * ) av7110 - > debi_virt ) [ Reserved_SIZE - 1 ] = 0 ;
printk ( " %s \n " , ( s8 * ) av7110 - > debi_virt ) ;
xfer = RX_BUFF ;
break ;
case DATA_CI_PUT :
dprintk ( 4 , " debi DATA_CI_PUT \n " ) ;
case DATA_MPEG_PLAY :
dprintk ( 4 , " debi DATA_MPEG_PLAY \n " ) ;
case DATA_BMP_LOAD :
dprintk ( 4 , " debi DATA_BMP_LOAD \n " ) ;
xfer = TX_BUFF ;
break ;
default :
break ;
}
debi_done :
spin_lock ( & av7110 - > debilock ) ;
if ( xfer )
iwdebi ( av7110 , DEBINOSWAP , xfer , 0 , 2 ) ;
ARM_ClearMailBox ( av7110 ) ;
spin_unlock ( & av7110 - > debilock ) ;
}
/* irq from av7110 firmware writing the mailbox register in the DPRAM */
static void gpioirq ( unsigned long data )
{
struct av7110 * av7110 = ( struct av7110 * ) data ;
u32 rxbuf , txbuf ;
int len ;
if ( av7110 - > debitype ! = - 1 )
/* we shouldn't get any irq while a debi xfer is running */
printk ( " dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x \n " ,
jiffies , saa7146_read ( av7110 - > dev , PSR ) ,
saa7146_read ( av7110 - > dev , SSR ) ) ;
if ( saa7146_wait_for_debi_done ( av7110 - > dev , 0 ) ) {
2008-04-09 06:20:00 +04:00
printk ( KERN_ERR " %s: saa7146_wait_for_debi_done timed out \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
BUG ( ) ; /* maybe we should try resetting the debi? */
}
spin_lock ( & av7110 - > debilock ) ;
ARM_ClearIrq ( av7110 ) ;
/* see what the av7110 wants */
av7110 - > debitype = irdebi ( av7110 , DEBINOSWAP , IRQ_STATE , 0 , 2 ) ;
av7110 - > debilen = irdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , 0 , 2 ) ;
rxbuf = irdebi ( av7110 , DEBINOSWAP , RX_BUFF , 0 , 2 ) ;
txbuf = irdebi ( av7110 , DEBINOSWAP , TX_BUFF , 0 , 2 ) ;
len = ( av7110 - > debilen + 3 ) & ~ 3 ;
print_time ( " gpio " ) ;
dprintk ( 8 , " GPIO0 irq 0x%04x %d \n " , av7110 - > debitype , av7110 - > debilen ) ;
switch ( av7110 - > debitype & 0xff ) {
case DATA_TS_PLAY :
case DATA_PES_PLAY :
break ;
case DATA_MPEG_VIDEO_EVENT :
{
u32 h_ar ;
struct video_event event ;
av7110 - > video_size . w = irdebi ( av7110 , DEBINOSWAP , STATUS_MPEG_WIDTH , 0 , 2 ) ;
h_ar = irdebi ( av7110 , DEBINOSWAP , STATUS_MPEG_HEIGHT_AR , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , RX_BUFF , 0 , 2 ) ;
av7110 - > video_size . h = h_ar & 0xfff ;
event . type = VIDEO_EVENT_SIZE_CHANGED ;
event . u . size . w = av7110 - > video_size . w ;
event . u . size . h = av7110 - > video_size . h ;
switch ( ( h_ar > > 12 ) & 0xf )
{
case 3 :
av7110 - > video_size . aspect_ratio = VIDEO_FORMAT_16_9 ;
event . u . size . aspect_ratio = VIDEO_FORMAT_16_9 ;
av7110 - > videostate . video_format = VIDEO_FORMAT_16_9 ;
break ;
case 4 :
av7110 - > video_size . aspect_ratio = VIDEO_FORMAT_221_1 ;
event . u . size . aspect_ratio = VIDEO_FORMAT_221_1 ;
av7110 - > videostate . video_format = VIDEO_FORMAT_221_1 ;
break ;
default :
av7110 - > video_size . aspect_ratio = VIDEO_FORMAT_4_3 ;
event . u . size . aspect_ratio = VIDEO_FORMAT_4_3 ;
av7110 - > videostate . video_format = VIDEO_FORMAT_4_3 ;
}
2006-01-09 20:32:42 +03:00
dprintk ( 8 , " GPIO0 irq: DATA_MPEG_VIDEO_EVENT: w/h/ar = %u/%u/%u \n " ,
av7110 - > video_size . w , av7110 - > video_size . h ,
av7110 - > video_size . aspect_ratio ) ;
2005-04-17 02:20:36 +04:00
dvb_video_add_event ( av7110 , & event ) ;
break ;
}
case DATA_CI_PUT :
{
int avail ;
struct dvb_ringbuffer * cibuf = & av7110 - > ci_wbuffer ;
avail = dvb_ringbuffer_avail ( cibuf ) ;
if ( avail < = 2 ) {
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_BUFF , 0 , 2 ) ;
break ;
}
len = DVB_RINGBUFFER_PEEK ( cibuf , 0 ) < < 8 ;
len | = DVB_RINGBUFFER_PEEK ( cibuf , 1 ) ;
if ( avail < len + 2 ) {
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_BUFF , 0 , 2 ) ;
break ;
}
DVB_RINGBUFFER_SKIP ( cibuf , 2 ) ;
dvb_ringbuffer_read ( cibuf , av7110 - > debi_virt , len , 0 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , len , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , len , 2 ) ;
dprintk ( 8 , " DMA: CI \n " ) ;
start_debi_dma ( av7110 , DEBI_WRITE , DPRAM_BASE + txbuf , len ) ;
spin_unlock ( & av7110 - > debilock ) ;
wake_up ( & cibuf - > queue ) ;
return ;
}
case DATA_MPEG_PLAY :
if ( ! av7110 - > playing ) {
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_BUFF , 0 , 2 ) ;
break ;
}
len = 0 ;
if ( av7110 - > debitype & 0x100 ) {
spin_lock ( & av7110 - > aout . lock ) ;
len = av7110_pes_play ( av7110 - > debi_virt , & av7110 - > aout , 2048 ) ;
spin_unlock ( & av7110 - > aout . lock ) ;
}
if ( len < = 0 & & ( av7110 - > debitype & 0x200 )
& & av7110 - > videostate . play_state ! = VIDEO_FREEZED ) {
spin_lock ( & av7110 - > avout . lock ) ;
len = av7110_pes_play ( av7110 - > debi_virt , & av7110 - > avout , 2048 ) ;
spin_unlock ( & av7110 - > avout . lock ) ;
}
if ( len < = 0 ) {
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_BUFF , 0 , 2 ) ;
break ;
}
dprintk ( 8 , " GPIO0 PES_PLAY len=%04x \n " , len ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , len , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , len , 2 ) ;
dprintk ( 8 , " DMA: MPEG_PLAY \n " ) ;
start_debi_dma ( av7110 , DEBI_WRITE , DPRAM_BASE + txbuf , len ) ;
spin_unlock ( & av7110 - > debilock ) ;
return ;
case DATA_BMP_LOAD :
len = av7110 - > debilen ;
dprintk ( 8 , " gpio DATA_BMP_LOAD len %d \n " , len ) ;
if ( ! len ) {
av7110 - > bmp_state = BMP_LOADED ;
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , TX_BUFF , 0 , 2 ) ;
wake_up ( & av7110 - > bmpq ) ;
dprintk ( 8 , " gpio DATA_BMP_LOAD done \n " ) ;
break ;
}
if ( len > av7110 - > bmplen )
len = av7110 - > bmplen ;
if ( len > 2 * 1024 )
len = 2 * 1024 ;
iwdebi ( av7110 , DEBINOSWAP , TX_LEN , len , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , IRQ_STATE_EXT , len , 2 ) ;
memcpy ( av7110 - > debi_virt , av7110 - > bmpbuf + av7110 - > bmpp , len ) ;
av7110 - > bmpp + = len ;
av7110 - > bmplen - = len ;
dprintk ( 8 , " gpio DATA_BMP_LOAD DMA len %d \n " , len ) ;
start_debi_dma ( av7110 , DEBI_WRITE , DPRAM_BASE + txbuf , len ) ;
spin_unlock ( & av7110 - > debilock ) ;
return ;
case DATA_CI_GET :
case DATA_COMMON_INTERFACE :
case DATA_FSECTION :
case DATA_IPMPE :
case DATA_PIPING :
if ( ! len | | len > 4 * 1024 ) {
iwdebi ( av7110 , DEBINOSWAP , RX_BUFF , 0 , 2 ) ;
break ;
}
/* fall through */
case DATA_TS_RECORD :
case DATA_PES_RECORD :
dprintk ( 8 , " DMA: TS_REC etc. \n " ) ;
start_debi_dma ( av7110 , DEBI_READ , DPRAM_BASE + rxbuf , len ) ;
spin_unlock ( & av7110 - > debilock ) ;
return ;
case DATA_DEBUG_MESSAGE :
if ( ! len | | len > 0xff ) {
iwdebi ( av7110 , DEBINOSWAP , RX_BUFF , 0 , 2 ) ;
break ;
}
start_debi_dma ( av7110 , DEBI_READ , Reserved , len ) ;
spin_unlock ( & av7110 - > debilock ) ;
return ;
case DATA_IRCOMMAND :
2007-04-27 19:31:21 +04:00
if ( av7110 - > ir . ir_handler )
av7110 - > ir . ir_handler ( av7110 ,
2005-09-10 00:03:12 +04:00
swahw32 ( irdebi ( av7110 , DEBINOSWAP , Reserved , 0 , 4 ) ) ) ;
2005-04-17 02:20:36 +04:00
iwdebi ( av7110 , DEBINOSWAP , RX_BUFF , 0 , 2 ) ;
break ;
default :
printk ( " dvb-ttpci: gpioirq unknown type=%d len=%d \n " ,
av7110 - > debitype , av7110 - > debilen ) ;
break ;
}
av7110 - > debitype = - 1 ;
ARM_ClearMailBox ( av7110 ) ;
spin_unlock ( & av7110 - > debilock ) ;
}
# ifdef CONFIG_DVB_AV7110_OSD
static int dvb_osd_ioctl ( struct inode * inode , struct file * file ,
unsigned int cmd , void * parg )
{
2006-12-26 13:33:48 +03:00
struct dvb_device * dvbdev = file - > private_data ;
struct av7110 * av7110 = dvbdev - > priv ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( cmd = = OSD_SEND_CMD )
return av7110_osd_cmd ( av7110 , ( osd_cmd_t * ) parg ) ;
if ( cmd = = OSD_GET_CAPABILITY )
return av7110_osd_capability ( av7110 , ( osd_cap_t * ) parg ) ;
return - EINVAL ;
}
static struct file_operations dvb_osd_fops = {
. owner = THIS_MODULE ,
. ioctl = dvb_generic_ioctl ,
. open = dvb_generic_open ,
. release = dvb_generic_release ,
} ;
static struct dvb_device dvbdev_osd = {
. priv = NULL ,
. users = 1 ,
. writers = 1 ,
. fops = & dvb_osd_fops ,
. kernel_ioctl = dvb_osd_ioctl ,
} ;
# endif /* CONFIG_DVB_AV7110_OSD */
static inline int SetPIDs ( struct av7110 * av7110 , u16 vpid , u16 apid , u16 ttpid ,
u16 subpid , u16 pcrpid )
{
2006-01-09 20:25:07 +03:00
u16 aflags = 0 ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( vpid = = 0x1fff | | apid = = 0x1fff | |
ttpid = = 0x1fff | | subpid = = 0x1fff | | pcrpid = = 0x1fff ) {
vpid = apid = ttpid = subpid = pcrpid = 0 ;
av7110 - > pids [ DMX_PES_VIDEO ] = 0 ;
av7110 - > pids [ DMX_PES_AUDIO ] = 0 ;
av7110 - > pids [ DMX_PES_TELETEXT ] = 0 ;
av7110 - > pids [ DMX_PES_PCR ] = 0 ;
}
2006-01-09 20:25:07 +03:00
if ( av7110 - > audiostate . bypass_mode )
aflags | = 0x8000 ;
return av7110_fw_cmd ( av7110 , COMTYPE_PIDFILTER , MultiPID , 6 ,
pcrpid , vpid , apid , ttpid , subpid , aflags ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:59 +04:00
int ChangePIDs ( struct av7110 * av7110 , u16 vpid , u16 apid , u16 ttpid ,
2005-04-17 02:20:36 +04:00
u16 subpid , u16 pcrpid )
{
2005-07-08 04:57:59 +04:00
int ret = 0 ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > pid_mutex ) )
2005-07-08 04:57:59 +04:00
return - ERESTARTSYS ;
2005-04-17 02:20:36 +04:00
if ( ! ( vpid & 0x8000 ) )
av7110 - > pids [ DMX_PES_VIDEO ] = vpid ;
if ( ! ( apid & 0x8000 ) )
av7110 - > pids [ DMX_PES_AUDIO ] = apid ;
if ( ! ( ttpid & 0x8000 ) )
av7110 - > pids [ DMX_PES_TELETEXT ] = ttpid ;
if ( ! ( pcrpid & 0x8000 ) )
av7110 - > pids [ DMX_PES_PCR ] = pcrpid ;
av7110 - > pids [ DMX_PES_SUBTITLE ] = 0 ;
if ( av7110 - > fe_synced ) {
pcrpid = av7110 - > pids [ DMX_PES_PCR ] ;
2005-07-08 04:57:59 +04:00
ret = SetPIDs ( av7110 , vpid , apid , ttpid , subpid , pcrpid ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > pid_mutex ) ;
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
/******************************************************************************
* hardware filter functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int StartHWFilter ( struct dvb_demux_filter * dvbdmxfilter )
{
struct dvb_demux_feed * dvbdmxfeed = dvbdmxfilter - > feed ;
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = dvbdmxfeed - > demux - > priv ;
2005-04-17 02:20:36 +04:00
u16 buf [ 20 ] ;
int ret , i ;
u16 handle ;
// u16 mode = 0x0320;
u16 mode = 0xb96a ;
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( dvbdmxfilter - > type = = DMX_TYPE_SEC ) {
if ( hw_sections ) {
buf [ 4 ] = ( dvbdmxfilter - > filter . filter_value [ 0 ] < < 8 ) |
dvbdmxfilter - > maskandmode [ 0 ] ;
for ( i = 3 ; i < 18 ; i + + )
buf [ i + 4 - 2 ] =
( dvbdmxfilter - > filter . filter_value [ i ] < < 8 ) |
dvbdmxfilter - > maskandmode [ i ] ;
mode = 4 ;
}
} else if ( ( dvbdmxfeed - > ts_type & TS_PACKET ) & &
! ( dvbdmxfeed - > ts_type & TS_PAYLOAD_ONLY ) ) {
av7110_p2t_init ( & av7110 - > p2t_filter [ dvbdmxfilter - > index ] , dvbdmxfeed ) ;
}
buf [ 0 ] = ( COMTYPE_PID_FILTER < < 8 ) + AddPIDFilter ;
buf [ 1 ] = 16 ;
buf [ 2 ] = dvbdmxfeed - > pid ;
buf [ 3 ] = mode ;
ret = av7110_fw_request ( av7110 , buf , 20 , & handle , 1 ) ;
if ( ret ! = 0 | | handle > = 32 ) {
printk ( " dvb-ttpci: %s error buf %04x %04x %04x %04x "
2005-07-08 04:57:59 +04:00
" ret %d handle %04x \n " ,
2008-04-09 06:20:00 +04:00
__func__ , buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , buf [ 3 ] ,
2005-04-17 02:20:36 +04:00
ret , handle ) ;
dvbdmxfilter - > hw_handle = 0xffff ;
2005-07-08 04:57:59 +04:00
if ( ! ret )
ret = - 1 ;
return ret ;
2005-04-17 02:20:36 +04:00
}
av7110 - > handle2filter [ handle ] = dvbdmxfilter ;
dvbdmxfilter - > hw_handle = handle ;
return ret ;
}
static int StopHWFilter ( struct dvb_demux_filter * dvbdmxfilter )
{
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = dvbdmxfilter - > feed - > demux - > priv ;
2005-04-17 02:20:36 +04:00
u16 buf [ 3 ] ;
u16 answ [ 2 ] ;
int ret ;
u16 handle ;
dprintk ( 4 , " %p \n " , av7110 ) ;
handle = dvbdmxfilter - > hw_handle ;
if ( handle > = 32 ) {
printk ( " %s tried to stop invalid filter %04x, filter type = %x \n " ,
2008-04-09 06:20:00 +04:00
__func__ , handle , dvbdmxfilter - > type ) ;
2005-07-08 04:57:59 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
av7110 - > handle2filter [ handle ] = NULL ;
buf [ 0 ] = ( COMTYPE_PID_FILTER < < 8 ) + DelPIDFilter ;
buf [ 1 ] = 1 ;
buf [ 2 ] = handle ;
ret = av7110_fw_request ( av7110 , buf , 3 , answ , 2 ) ;
if ( ret ! = 0 | | answ [ 1 ] ! = handle ) {
printk ( " dvb-ttpci: %s error cmd %04x %04x %04x ret %x "
" resp %04x %04x pid %d \n " ,
2008-04-09 06:20:00 +04:00
__func__ , buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , ret ,
2005-04-17 02:20:36 +04:00
answ [ 0 ] , answ [ 1 ] , dvbdmxfilter - > feed - > pid ) ;
2005-07-08 04:57:59 +04:00
if ( ! ret )
ret = - 1 ;
2005-04-17 02:20:36 +04:00
}
return ret ;
}
2005-07-08 04:57:59 +04:00
static int dvb_feed_start_pid ( struct dvb_demux_feed * dvbdmxfeed )
2005-04-17 02:20:36 +04:00
{
struct dvb_demux * dvbdmx = dvbdmxfeed - > demux ;
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = dvbdmx - > priv ;
2005-04-17 02:20:36 +04:00
u16 * pid = dvbdmx - > pids , npids [ 5 ] ;
int i ;
2005-07-08 04:57:59 +04:00
int ret = 0 ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
npids [ 0 ] = npids [ 1 ] = npids [ 2 ] = npids [ 3 ] = npids [ 4 ] = 0xffff ;
i = dvbdmxfeed - > pes_type ;
npids [ i ] = ( pid [ i ] & 0x8000 ) ? 0 : pid [ i ] ;
if ( ( i = = 2 ) & & npids [ i ] & & ( dvbdmxfeed - > ts_type & TS_PACKET ) ) {
npids [ i ] = 0 ;
2005-07-08 04:57:59 +04:00
ret = ChangePIDs ( av7110 , npids [ 1 ] , npids [ 0 ] , npids [ 2 ] , npids [ 3 ] , npids [ 4 ] ) ;
if ( ! ret )
ret = StartHWFilter ( dvbdmxfeed - > filter ) ;
return ret ;
}
if ( dvbdmxfeed - > pes_type < = 2 | | dvbdmxfeed - > pes_type = = 4 ) {
ret = ChangePIDs ( av7110 , npids [ 1 ] , npids [ 0 ] , npids [ 2 ] , npids [ 3 ] , npids [ 4 ] ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
}
if ( dvbdmxfeed - > pes_type < 2 & & npids [ 0 ] )
if ( av7110 - > fe_synced )
2005-07-08 04:57:59 +04:00
{
ret = av7110_fw_cmd ( av7110 , COMTYPE_PIDFILTER , Scan , 0 ) ;
if ( ret )
return ret ;
}
2005-04-17 02:20:36 +04:00
if ( ( dvbdmxfeed - > ts_type & TS_PACKET ) ) {
if ( dvbdmxfeed - > pes_type = = 0 & & ! ( dvbdmx - > pids [ 0 ] & 0x8000 ) )
2005-07-08 04:57:59 +04:00
ret = av7110_av_start_record ( av7110 , RP_AUDIO , dvbdmxfeed ) ;
2005-04-17 02:20:36 +04:00
if ( dvbdmxfeed - > pes_type = = 1 & & ! ( dvbdmx - > pids [ 1 ] & 0x8000 ) )
2005-07-08 04:57:59 +04:00
ret = av7110_av_start_record ( av7110 , RP_VIDEO , dvbdmxfeed ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:59 +04:00
static int dvb_feed_stop_pid ( struct dvb_demux_feed * dvbdmxfeed )
2005-04-17 02:20:36 +04:00
{
struct dvb_demux * dvbdmx = dvbdmxfeed - > demux ;
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = dvbdmx - > priv ;
2005-04-17 02:20:36 +04:00
u16 * pid = dvbdmx - > pids , npids [ 5 ] ;
int i ;
2005-07-08 04:57:59 +04:00
int ret = 0 ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( dvbdmxfeed - > pes_type < = 1 ) {
2005-07-08 04:57:59 +04:00
ret = av7110_av_stop ( av7110 , dvbdmxfeed - > pes_type ? RP_VIDEO : RP_AUDIO ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
if ( ! av7110 - > rec_mode )
dvbdmx - > recording = 0 ;
if ( ! av7110 - > playing )
dvbdmx - > playing = 0 ;
}
npids [ 0 ] = npids [ 1 ] = npids [ 2 ] = npids [ 3 ] = npids [ 4 ] = 0xffff ;
i = dvbdmxfeed - > pes_type ;
switch ( i ) {
case 2 : //teletext
if ( dvbdmxfeed - > ts_type & TS_PACKET )
2005-07-08 04:57:59 +04:00
ret = StopHWFilter ( dvbdmxfeed - > filter ) ;
2005-04-17 02:20:36 +04:00
npids [ 2 ] = 0 ;
break ;
case 0 :
case 1 :
case 4 :
if ( ! pids_off )
2005-07-08 04:57:59 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
npids [ i ] = ( pid [ i ] & 0x8000 ) ? 0 : pid [ i ] ;
break ;
}
2005-07-08 04:57:59 +04:00
if ( ! ret )
ret = ChangePIDs ( av7110 , npids [ 1 ] , npids [ 0 ] , npids [ 2 ] , npids [ 3 ] , npids [ 4 ] ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_start_feed ( struct dvb_demux_feed * feed )
{
struct dvb_demux * demux = feed - > demux ;
struct av7110 * av7110 = demux - > priv ;
2005-07-08 04:57:59 +04:00
int ret = 0 ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( ! demux - > dmx . frontend )
return - EINVAL ;
if ( feed - > pid > 0x1fff )
return - EINVAL ;
if ( feed - > type = = DMX_TYPE_TS ) {
if ( ( feed - > ts_type & TS_DECODER ) & &
( feed - > pes_type < DMX_TS_PES_OTHER ) ) {
switch ( demux - > dmx . frontend - > source ) {
case DMX_MEMORY_FE :
if ( feed - > ts_type & TS_DECODER )
if ( feed - > pes_type < 2 & &
! ( demux - > pids [ 0 ] & 0x8000 ) & &
! ( demux - > pids [ 1 ] & 0x8000 ) ) {
dvb_ringbuffer_flush_spinlock_wakeup ( & av7110 - > avout ) ;
dvb_ringbuffer_flush_spinlock_wakeup ( & av7110 - > aout ) ;
2005-07-08 04:57:59 +04:00
ret = av7110_av_start_play ( av7110 , RP_AV ) ;
if ( ! ret )
demux - > playing = 1 ;
2005-04-17 02:20:36 +04:00
}
break ;
default :
2005-07-08 04:57:59 +04:00
ret = dvb_feed_start_pid ( feed ) ;
2005-04-17 02:20:36 +04:00
break ;
}
} else if ( ( feed - > ts_type & TS_PACKET ) & &
( demux - > dmx . frontend - > source ! = DMX_MEMORY_FE ) ) {
2005-07-08 04:57:59 +04:00
ret = StartHWFilter ( feed - > filter ) ;
2005-04-17 02:20:36 +04:00
}
}
2005-07-08 04:57:59 +04:00
else if ( feed - > type = = DMX_TYPE_SEC ) {
2005-04-17 02:20:36 +04:00
int i ;
for ( i = 0 ; i < demux - > filternum ; i + + ) {
if ( demux - > filter [ i ] . state ! = DMX_STATE_READY )
continue ;
if ( demux - > filter [ i ] . type ! = DMX_TYPE_SEC )
continue ;
if ( demux - > filter [ i ] . filter . parent ! = & feed - > feed . sec )
continue ;
demux - > filter [ i ] . state = DMX_STATE_GO ;
2005-07-08 04:57:59 +04:00
if ( demux - > dmx . frontend - > source ! = DMX_MEMORY_FE ) {
ret = StartHWFilter ( & demux - > filter [ i ] ) ;
if ( ret )
break ;
}
2005-04-17 02:20:36 +04:00
}
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_stop_feed ( struct dvb_demux_feed * feed )
{
struct dvb_demux * demux = feed - > demux ;
struct av7110 * av7110 = demux - > priv ;
2005-07-08 04:58:00 +04:00
int i , rc , ret = 0 ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( feed - > type = = DMX_TYPE_TS ) {
if ( feed - > ts_type & TS_DECODER ) {
if ( feed - > pes_type > = DMX_TS_PES_OTHER | |
! demux - > pesfilter [ feed - > pes_type ] )
return - EINVAL ;
demux - > pids [ feed - > pes_type ] | = 0x8000 ;
demux - > pesfilter [ feed - > pes_type ] = NULL ;
}
if ( feed - > ts_type & TS_DECODER & &
feed - > pes_type < DMX_TS_PES_OTHER ) {
2005-07-08 04:57:59 +04:00
ret = dvb_feed_stop_pid ( feed ) ;
2005-04-17 02:20:36 +04:00
} else
if ( ( feed - > ts_type & TS_PACKET ) & &
( demux - > dmx . frontend - > source ! = DMX_MEMORY_FE ) )
2005-07-08 04:57:59 +04:00
ret = StopHWFilter ( feed - > filter ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:59 +04:00
if ( ! ret & & feed - > type = = DMX_TYPE_SEC ) {
2005-07-08 04:58:00 +04:00
for ( i = 0 ; i < demux - > filternum ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( demux - > filter [ i ] . state = = DMX_STATE_GO & &
demux - > filter [ i ] . filter . parent = = & feed - > feed . sec ) {
demux - > filter [ i ] . state = DMX_STATE_READY ;
2005-07-08 04:57:59 +04:00
if ( demux - > dmx . frontend - > source ! = DMX_MEMORY_FE ) {
2005-07-08 04:58:00 +04:00
rc = StopHWFilter ( & demux - > filter [ i ] ) ;
if ( ! ret )
ret = rc ;
/* keep going, stop as many filters as possible */
2005-07-08 04:57:59 +04:00
}
2005-07-08 04:58:00 +04:00
}
2005-04-17 02:20:36 +04:00
}
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static void restart_feeds ( struct av7110 * av7110 )
{
struct dvb_demux * dvbdmx = & av7110 - > demux ;
struct dvb_demux_feed * feed ;
int mode ;
2006-01-09 20:32:42 +03:00
int i , j ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
mode = av7110 - > playing ;
av7110 - > playing = 0 ;
av7110 - > rec_mode = 0 ;
2006-01-09 20:32:42 +03:00
for ( i = 0 ; i < dvbdmx - > feednum ; i + + ) {
2005-04-17 02:20:36 +04:00
feed = & dvbdmx - > feed [ i ] ;
2006-01-09 20:32:42 +03:00
if ( feed - > state = = DMX_STATE_GO ) {
if ( feed - > type = = DMX_TYPE_SEC ) {
for ( j = 0 ; j < dvbdmx - > filternum ; j + + ) {
if ( dvbdmx - > filter [ j ] . type ! = DMX_TYPE_SEC )
continue ;
if ( dvbdmx - > filter [ j ] . filter . parent ! = & feed - > feed . sec )
continue ;
if ( dvbdmx - > filter [ j ] . state = = DMX_STATE_GO )
dvbdmx - > filter [ j ] . state = DMX_STATE_READY ;
}
}
2005-04-17 02:20:36 +04:00
av7110_start_feed ( feed ) ;
2006-01-09 20:32:42 +03:00
}
2005-04-17 02:20:36 +04:00
}
if ( mode )
av7110_av_start_play ( av7110 , mode ) ;
}
static int dvb_get_stc ( struct dmx_demux * demux , unsigned int num ,
uint64_t * stc , unsigned int * base )
{
int ret ;
u16 fwstc [ 4 ] ;
u16 tag = ( ( COMTYPE_REQUEST < < 8 ) + ReqSTC ) ;
struct dvb_demux * dvbdemux ;
struct av7110 * av7110 ;
/* pointer casting paranoia... */
2006-03-13 19:17:11 +03:00
BUG_ON ( ! demux ) ;
2006-12-26 13:33:48 +03:00
dvbdemux = demux - > priv ;
2006-03-13 19:17:11 +03:00
BUG_ON ( ! dvbdemux ) ;
2006-12-26 13:33:48 +03:00
av7110 = dvbdemux - > priv ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( num ! = 0 )
return - EINVAL ;
ret = av7110_fw_request ( av7110 , & tag , 0 , fwstc , 4 ) ;
if ( ret ) {
2008-04-09 06:20:00 +04:00
printk ( KERN_ERR " %s: av7110_fw_request error \n " , __func__ ) ;
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
dprintk ( 2 , " fwstc = %04hx %04hx %04hx %04hx \n " ,
fwstc [ 0 ] , fwstc [ 1 ] , fwstc [ 2 ] , fwstc [ 3 ] ) ;
* stc = ( ( ( uint64_t ) ( ( fwstc [ 3 ] & 0x8000 ) > > 15 ) ) < < 32 ) |
( ( ( uint64_t ) fwstc [ 1 ] ) < < 16 ) | ( ( uint64_t ) fwstc [ 0 ] ) ;
* base = 1 ;
dprintk ( 4 , " stc = %lu \n " , ( unsigned long ) * stc ) ;
return 0 ;
}
/******************************************************************************
* SEC device file operations
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int av7110_set_tone ( struct dvb_frontend * fe , fe_sec_tone_mode_t tone )
{
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-04-17 02:20:36 +04:00
switch ( tone ) {
case SEC_TONE_ON :
2005-07-08 04:57:59 +04:00
return Set22K ( av7110 , 1 ) ;
2005-04-17 02:20:36 +04:00
case SEC_TONE_OFF :
2005-07-08 04:57:59 +04:00
return Set22K ( av7110 , 0 ) ;
2005-04-17 02:20:36 +04:00
default :
return - EINVAL ;
}
}
static int av7110_diseqc_send_master_cmd ( struct dvb_frontend * fe ,
struct dvb_diseqc_master_cmd * cmd )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
return av7110_diseqc_send ( av7110 , cmd - > msg_len , cmd - > msg , - 1 ) ;
2005-04-17 02:20:36 +04:00
}
static int av7110_diseqc_send_burst ( struct dvb_frontend * fe ,
fe_sec_mini_cmd_t minicmd )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
return av7110_diseqc_send ( av7110 , 0 , NULL , minicmd ) ;
2005-04-17 02:20:36 +04:00
}
/* simplified code from budget-core.c */
static int stop_ts_capture ( struct av7110 * budget )
{
dprintk ( 2 , " budget: %p \n " , budget ) ;
if ( - - budget - > feeding1 )
return budget - > feeding1 ;
saa7146_write ( budget - > dev , MC1 , MASK_20 ) ; /* DMA3 off */
SAA7146_IER_DISABLE ( budget - > dev , MASK_10 ) ;
SAA7146_ISR_CLEAR ( budget - > dev , MASK_10 ) ;
return 0 ;
}
static int start_ts_capture ( struct av7110 * budget )
{
dprintk ( 2 , " budget: %p \n " , budget ) ;
if ( budget - > feeding1 )
return + + budget - > feeding1 ;
memset ( budget - > grabbing , 0x00 , TS_HEIGHT * TS_WIDTH ) ;
budget - > tsf = 0xff ;
budget - > ttbp = 0 ;
SAA7146_IER_ENABLE ( budget - > dev , MASK_10 ) ; /* VPE */
saa7146_write ( budget - > dev , MC1 , ( MASK_04 | MASK_20 ) ) ; /* DMA3 on */
return + + budget - > feeding1 ;
}
static int budget_start_feed ( struct dvb_demux_feed * feed )
{
struct dvb_demux * demux = feed - > demux ;
2006-12-26 13:33:48 +03:00
struct av7110 * budget = demux - > priv ;
2005-04-17 02:20:36 +04:00
int status ;
dprintk ( 2 , " av7110: %p \n " , budget ) ;
spin_lock ( & budget - > feedlock1 ) ;
feed - > pusi_seen = 0 ; /* have a clean section start */
status = start_ts_capture ( budget ) ;
spin_unlock ( & budget - > feedlock1 ) ;
return status ;
}
static int budget_stop_feed ( struct dvb_demux_feed * feed )
{
struct dvb_demux * demux = feed - > demux ;
2006-12-26 13:33:48 +03:00
struct av7110 * budget = demux - > priv ;
2005-04-17 02:20:36 +04:00
int status ;
dprintk ( 2 , " budget: %p \n " , budget ) ;
spin_lock ( & budget - > feedlock1 ) ;
status = stop_ts_capture ( budget ) ;
spin_unlock ( & budget - > feedlock1 ) ;
return status ;
}
static void vpeirq ( unsigned long data )
{
struct av7110 * budget = ( struct av7110 * ) data ;
u8 * mem = ( u8 * ) ( budget - > grabbing ) ;
u32 olddma = budget - > ttbp ;
u32 newdma = saa7146_read ( budget - > dev , PCI_VDP3 ) ;
if ( ! budgetpatch ) {
printk ( " av7110.c: vpeirq() called while budgetpatch disabled! "
" check saa7146 IER register \n " ) ;
BUG ( ) ;
}
/* nearest lower position divisible by 188 */
newdma - = newdma % 188 ;
if ( newdma > = TS_BUFLEN )
return ;
budget - > ttbp = newdma ;
if ( ! budget - > feeding1 | | ( newdma = = olddma ) )
return ;
2007-05-03 19:23:44 +04:00
/* Ensure streamed PCI data is synced to CPU */
pci_dma_sync_sg_for_cpu ( budget - > dev - > pci , budget - > pt . slist , budget - > pt . nents , PCI_DMA_FROMDEVICE ) ;
2005-04-17 02:20:36 +04:00
#if 0
/* track rps1 activity */
printk ( " vpeirq: %02x Event Counter 1 0x%04x \n " ,
mem [ olddma ] ,
saa7146_read ( budget - > dev , EC1R ) & 0x3fff ) ;
# endif
if ( newdma > olddma )
/* no wraparound, dump olddma..newdma */
dvb_dmx_swfilter_packets ( & budget - > demux1 , mem + olddma , ( newdma - olddma ) / 188 ) ;
else {
/* wraparound, dump olddma..buflen and 0..newdma */
dvb_dmx_swfilter_packets ( & budget - > demux1 , mem + olddma , ( TS_BUFLEN - olddma ) / 188 ) ;
dvb_dmx_swfilter_packets ( & budget - > demux1 , mem , newdma / 188 ) ;
}
}
static int av7110_register ( struct av7110 * av7110 )
{
int ret , i ;
struct dvb_demux * dvbdemux = & av7110 - > demux ;
struct dvb_demux * dvbdemux1 = & av7110 - > demux1 ;
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( av7110 - > registered )
return - 1 ;
av7110 - > registered = 1 ;
dvbdemux - > priv = ( void * ) av7110 ;
for ( i = 0 ; i < 32 ; i + + )
av7110 - > handle2filter [ i ] = NULL ;
dvbdemux - > filternum = 32 ;
dvbdemux - > feednum = 32 ;
dvbdemux - > start_feed = av7110_start_feed ;
dvbdemux - > stop_feed = av7110_stop_feed ;
dvbdemux - > write_to_decoder = av7110_write_to_decoder ;
dvbdemux - > dmx . capabilities = ( DMX_TS_FILTERING | DMX_SECTION_FILTERING |
DMX_MEMORY_BASED_FILTERING ) ;
dvb_dmx_init ( & av7110 - > demux ) ;
av7110 - > demux . dmx . get_stc = dvb_get_stc ;
av7110 - > dmxdev . filternum = 32 ;
av7110 - > dmxdev . demux = & dvbdemux - > dmx ;
av7110 - > dmxdev . capabilities = 0 ;
2005-05-17 08:54:39 +04:00
dvb_dmxdev_init ( & av7110 - > dmxdev , & av7110 - > dvb_adapter ) ;
2005-04-17 02:20:36 +04:00
av7110 - > hw_frontend . source = DMX_FRONTEND_0 ;
ret = dvbdemux - > dmx . add_frontend ( & dvbdemux - > dmx , & av7110 - > hw_frontend ) ;
if ( ret < 0 )
return ret ;
av7110 - > mem_frontend . source = DMX_MEMORY_FE ;
ret = dvbdemux - > dmx . add_frontend ( & dvbdemux - > dmx , & av7110 - > mem_frontend ) ;
if ( ret < 0 )
return ret ;
ret = dvbdemux - > dmx . connect_frontend ( & dvbdemux - > dmx ,
& av7110 - > hw_frontend ) ;
if ( ret < 0 )
return ret ;
av7110_av_register ( av7110 ) ;
av7110_ca_register ( av7110 ) ;
# ifdef CONFIG_DVB_AV7110_OSD
2005-05-17 08:54:39 +04:00
dvb_register_device ( & av7110 - > dvb_adapter , & av7110 - > osd_dev ,
2005-04-17 02:20:36 +04:00
& dvbdev_osd , av7110 , DVB_DEVICE_OSD ) ;
# endif
2005-05-17 08:54:39 +04:00
dvb_net_init ( & av7110 - > dvb_adapter , & av7110 - > dvb_net , & dvbdemux - > dmx ) ;
2005-04-17 02:20:36 +04:00
if ( budgetpatch ) {
/* initialize software demux1 without its own frontend
* demux1 hardware is connected to frontend0 of demux0
*/
dvbdemux1 - > priv = ( void * ) av7110 ;
dvbdemux1 - > filternum = 256 ;
dvbdemux1 - > feednum = 256 ;
dvbdemux1 - > start_feed = budget_start_feed ;
dvbdemux1 - > stop_feed = budget_stop_feed ;
dvbdemux1 - > write_to_decoder = NULL ;
dvbdemux1 - > dmx . capabilities = ( DMX_TS_FILTERING | DMX_SECTION_FILTERING |
DMX_MEMORY_BASED_FILTERING ) ;
dvb_dmx_init ( & av7110 - > demux1 ) ;
av7110 - > dmxdev1 . filternum = 256 ;
av7110 - > dmxdev1 . demux = & dvbdemux1 - > dmx ;
av7110 - > dmxdev1 . capabilities = 0 ;
2005-05-17 08:54:39 +04:00
dvb_dmxdev_init ( & av7110 - > dmxdev1 , & av7110 - > dvb_adapter ) ;
2005-04-17 02:20:36 +04:00
2005-05-17 08:54:39 +04:00
dvb_net_init ( & av7110 - > dvb_adapter , & av7110 - > dvb_net1 , & dvbdemux1 - > dmx ) ;
2005-04-17 02:20:36 +04:00
printk ( " dvb-ttpci: additional demux1 for budget-patch registered \n " ) ;
}
return 0 ;
}
static void dvb_unregister ( struct av7110 * av7110 )
{
struct dvb_demux * dvbdemux = & av7110 - > demux ;
struct dvb_demux * dvbdemux1 = & av7110 - > demux1 ;
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( ! av7110 - > registered )
return ;
if ( budgetpatch ) {
dvb_net_release ( & av7110 - > dvb_net1 ) ;
dvbdemux - > dmx . close ( & dvbdemux1 - > dmx ) ;
dvb_dmxdev_release ( & av7110 - > dmxdev1 ) ;
dvb_dmx_release ( & av7110 - > demux1 ) ;
}
dvb_net_release ( & av7110 - > dvb_net ) ;
dvbdemux - > dmx . close ( & dvbdemux - > dmx ) ;
dvbdemux - > dmx . remove_frontend ( & dvbdemux - > dmx , & av7110 - > hw_frontend ) ;
dvbdemux - > dmx . remove_frontend ( & dvbdemux - > dmx , & av7110 - > mem_frontend ) ;
dvb_dmxdev_release ( & av7110 - > dmxdev ) ;
dvb_dmx_release ( & av7110 - > demux ) ;
2006-08-08 16:10:08 +04:00
if ( av7110 - > fe ! = NULL ) {
2005-04-17 02:20:36 +04:00
dvb_unregister_frontend ( av7110 - > fe ) ;
2006-08-08 16:10:09 +04:00
dvb_frontend_detach ( av7110 - > fe ) ;
2006-08-08 16:10:08 +04:00
}
2005-04-17 02:20:36 +04:00
dvb_unregister_device ( av7110 - > osd_dev ) ;
av7110_av_unregister ( av7110 ) ;
av7110_ca_unregister ( av7110 ) ;
}
/****************************************************************************
* I2C client commands
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int i2c_writereg ( struct av7110 * av7110 , 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 ( & av7110 - > i2c_adap , & msgs , 1 ) ;
}
#if 0
u8 i2c_readreg ( struct av7110 * av7110 , 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 ( & av7110 - > i2c_adap , msgs , 2 ) ;
return mm2 [ 0 ] ;
}
# endif
/****************************************************************************
* INITIALIZATION
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int check_firmware ( struct av7110 * av7110 )
{
u32 crc = 0 , len = 0 ;
unsigned char * ptr ;
/* check for firmware magic */
ptr = av7110 - > bin_fw ;
if ( ptr [ 0 ] ! = ' A ' | | ptr [ 1 ] ! = ' V ' | |
ptr [ 2 ] ! = ' F ' | | ptr [ 3 ] ! = ' W ' ) {
printk ( " dvb-ttpci: this is not an av7110 firmware \n " ) ;
return - EINVAL ;
}
ptr + = 4 ;
/* check dpram file */
crc = ntohl ( * ( u32 * ) ptr ) ;
ptr + = 4 ;
len = ntohl ( * ( u32 * ) ptr ) ;
ptr + = 4 ;
if ( len > = 512 ) {
2006-03-08 04:20:23 +03:00
printk ( " dvb-ttpci: dpram file is way too big. \n " ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
if ( crc ! = crc32_le ( 0 , ptr , len ) ) {
printk ( " dvb-ttpci: crc32 of dpram file does not match. \n " ) ;
return - EINVAL ;
}
av7110 - > bin_dpram = ptr ;
av7110 - > size_dpram = len ;
ptr + = len ;
/* check root file */
crc = ntohl ( * ( u32 * ) ptr ) ;
ptr + = 4 ;
len = ntohl ( * ( u32 * ) ptr ) ;
ptr + = 4 ;
if ( len < = 200000 | | len > = 300000 | |
len > ( ( av7110 - > bin_fw + av7110 - > size_fw ) - ptr ) ) {
printk ( " dvb-ttpci: root file has strange size (%d). aborting. \n " , len ) ;
return - EINVAL ;
}
if ( crc ! = crc32_le ( 0 , ptr , len ) ) {
printk ( " dvb-ttpci: crc32 of root file does not match. \n " ) ;
return - EINVAL ;
}
av7110 - > bin_root = ptr ;
av7110 - > size_root = len ;
return 0 ;
}
# ifdef CONFIG_DVB_AV7110_FIRMWARE_FILE
# include "av7110_firm.h"
static void put_firmware ( struct av7110 * av7110 )
{
av7110 - > bin_fw = NULL ;
}
static inline int get_firmware ( struct av7110 * av7110 )
{
av7110 - > bin_fw = dvb_ttpci_fw ;
av7110 - > size_fw = sizeof ( dvb_ttpci_fw ) ;
return check_firmware ( av7110 ) ;
}
# else
static void put_firmware ( struct av7110 * av7110 )
{
vfree ( av7110 - > bin_fw ) ;
}
static int get_firmware ( struct av7110 * av7110 )
{
int ret ;
const struct firmware * fw ;
/* request the av7110 firmware, this will block until someone uploads it */
ret = request_firmware ( & fw , " dvb-ttpci-01.fw " , & av7110 - > dev - > pci - > dev ) ;
if ( ret ) {
if ( ret = = - ENOENT ) {
printk ( KERN_ERR " dvb-ttpci: could not load firmware, "
" file not found: dvb-ttpci-01.fw \n " ) ;
2006-01-09 20:25:38 +03:00
printk ( KERN_ERR " dvb-ttpci: usually this should be in "
" /usr/lib/hotplug/firmware or /lib/firmware \n " ) ;
printk ( KERN_ERR " dvb-ttpci: and can be downloaded from "
2005-04-17 02:20:36 +04:00
" http://www.linuxtv.org/download/dvb/firmware/ \n " ) ;
} else
printk ( KERN_ERR " dvb-ttpci: cannot request firmware "
" (error %i) \n " , ret ) ;
return - EINVAL ;
}
if ( fw - > size < = 200000 ) {
printk ( " dvb-ttpci: this firmware is way too small. \n " ) ;
release_firmware ( fw ) ;
return - EINVAL ;
}
/* check if the firmware is available */
2007-08-25 18:23:54 +04:00
av7110 - > bin_fw = vmalloc ( fw - > size ) ;
2005-04-17 02:20:36 +04:00
if ( NULL = = av7110 - > bin_fw ) {
dprintk ( 1 , " out of memory \n " ) ;
release_firmware ( fw ) ;
return - ENOMEM ;
}
memcpy ( av7110 - > bin_fw , fw - > data , fw - > size ) ;
av7110 - > size_fw = fw - > size ;
if ( ( ret = check_firmware ( av7110 ) ) )
vfree ( av7110 - > bin_fw ) ;
release_firmware ( fw ) ;
return ret ;
}
# endif
2006-04-19 00:47:11 +04:00
static int alps_bsrv2_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-04-17 02:20:36 +04:00
u8 pwr = 0 ;
u8 buf [ 4 ] ;
struct i2c_msg msg = { . addr = 0x61 , . flags = 0 , . buf = buf , . len = sizeof ( buf ) } ;
u32 div = ( params - > frequency + 479500 ) / 125 ;
if ( params - > frequency > 2000000 ) pwr = 3 ;
else if ( params - > frequency > 1800000 ) pwr = 2 ;
else if ( params - > frequency > 1600000 ) pwr = 1 ;
else if ( params - > frequency > 1200000 ) pwr = 0 ;
else if ( params - > frequency > = 1100000 ) pwr = 1 ;
else pwr = 2 ;
buf [ 0 ] = ( div > > 8 ) & 0x7f ;
buf [ 1 ] = div & 0xff ;
buf [ 2 ] = ( ( div & 0x18000 ) > > 10 ) | 0x95 ;
buf [ 3 ] = ( pwr < < 6 ) | 0x30 ;
2005-12-12 11:37:24 +03:00
// NOTE: since we're using a prescaler of 2, we set the
2005-04-17 02:20:36 +04:00
// divisor frequency to 62.5kHz and divide by 125 above
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & msg , 1 ) ! = 1 )
return - EIO ;
return 0 ;
}
static struct ves1x93_config alps_bsrv2_config = {
. demod_address = 0x08 ,
. xin = 90100000UL ,
. invert_pwm = 0 ,
} ;
2006-04-19 00:47:11 +04:00
static int alps_tdbe2_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
struct av7110 * av7110 = fe - > dvb - > priv ;
u32 div ;
u8 data [ 4 ] ;
struct i2c_msg msg = { . addr = 0x62 , . flags = 0 , . buf = data , . len = sizeof ( data ) } ;
div = ( params - > frequency + 35937500 + 31250 ) / 62500 ;
data [ 0 ] = ( div > > 8 ) & 0x7f ;
data [ 1 ] = div & 0xff ;
data [ 2 ] = 0x85 | ( ( div > > 10 ) & 0x60 ) ;
data [ 3 ] = ( params - > frequency < 174000000 ? 0x88 : params - > frequency < 470000000 ? 0x84 : 0x81 ) ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & msg , 1 ) ! = 1 )
return - EIO ;
return 0 ;
}
static struct ves1820_config alps_tdbe2_config = {
. demod_address = 0x09 ,
. xin = 57840000UL ,
. invert = 1 ,
. selagc = VES1820_SELAGC_SIGNAMPERR ,
} ;
2006-04-19 00:47:11 +04:00
static int grundig_29504_451_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
struct av7110 * av7110 = fe - > dvb - > priv ;
u32 div ;
u8 data [ 4 ] ;
struct i2c_msg msg = { . addr = 0x61 , . flags = 0 , . buf = data , . len = sizeof ( data ) } ;
div = params - > frequency / 125 ;
data [ 0 ] = ( div > > 8 ) & 0x7f ;
data [ 1 ] = div & 0xff ;
data [ 2 ] = 0x8e ;
data [ 3 ] = 0x00 ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & msg , 1 ) ! = 1 )
return - EIO ;
return 0 ;
}
static struct tda8083_config grundig_29504_451_config = {
. demod_address = 0x68 ,
} ;
2006-04-19 00:47:11 +04:00
static int philips_cd1516_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
2005-12-12 11:37:24 +03:00
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-04-17 02:20:36 +04:00
u32 div ;
u32 f = params - > frequency ;
u8 data [ 4 ] ;
struct i2c_msg msg = { . addr = 0x61 , . flags = 0 , . buf = data , . len = sizeof ( data ) } ;
div = ( f + 36125000 + 31250 ) / 62500 ;
data [ 0 ] = ( div > > 8 ) & 0x7f ;
data [ 1 ] = div & 0xff ;
data [ 2 ] = 0x8e ;
data [ 3 ] = ( f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34 ) ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & msg , 1 ) ! = 1 )
return - EIO ;
return 0 ;
}
static struct ves1820_config philips_cd1516_config = {
. demod_address = 0x09 ,
. xin = 57840000UL ,
. invert = 1 ,
. selagc = VES1820_SELAGC_SIGNAMPERR ,
} ;
2006-04-19 00:47:11 +04:00
static int alps_tdlb7_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
struct av7110 * av7110 = fe - > dvb - > priv ;
u32 div , pwr ;
u8 data [ 4 ] ;
struct i2c_msg msg = { . addr = 0x60 , . flags = 0 , . buf = data , . len = sizeof ( data ) } ;
div = ( params - > frequency + 36200000 ) / 166666 ;
if ( params - > frequency < = 782000000 )
pwr = 1 ;
else
pwr = 2 ;
data [ 0 ] = ( div > > 8 ) & 0x7f ;
data [ 1 ] = div & 0xff ;
data [ 2 ] = 0x85 ;
data [ 3 ] = pwr < < 6 ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & msg , 1 ) ! = 1 )
return - EIO ;
return 0 ;
}
static int alps_tdlb7_request_firmware ( struct dvb_frontend * fe , const struct firmware * * fw , char * name )
{
2006-09-14 07:15:13 +04:00
# if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-04-17 02:20:36 +04:00
return request_firmware ( fw , name , & av7110 - > dev - > pci - > dev ) ;
2006-09-14 07:15:13 +04:00
# else
return - EINVAL ;
# endif
2005-04-17 02:20:36 +04:00
}
static struct sp8870_config alps_tdlb7_config = {
. demod_address = 0x71 ,
. request_firmware = alps_tdlb7_request_firmware ,
} ;
2005-09-10 00:03:07 +04:00
static u8 nexusca_stv0297_inittab [ ] = {
0x80 , 0x01 ,
0x80 , 0x00 ,
0x81 , 0x01 ,
0x81 , 0x00 ,
0x00 , 0x09 ,
0x01 , 0x69 ,
0x03 , 0x00 ,
0x04 , 0x00 ,
0x07 , 0x00 ,
0x08 , 0x00 ,
0x20 , 0x00 ,
0x21 , 0x40 ,
0x22 , 0x00 ,
0x23 , 0x00 ,
0x24 , 0x40 ,
0x25 , 0x88 ,
0x30 , 0xff ,
0x31 , 0x00 ,
0x32 , 0xff ,
0x33 , 0x00 ,
0x34 , 0x50 ,
0x35 , 0x7f ,
0x36 , 0x00 ,
0x37 , 0x20 ,
0x38 , 0x00 ,
0x40 , 0x1c ,
0x41 , 0xff ,
0x42 , 0x29 ,
0x43 , 0x00 ,
0x44 , 0xff ,
0x45 , 0x00 ,
0x46 , 0x00 ,
0x49 , 0x04 ,
0x4a , 0x00 ,
0x4b , 0x7b ,
0x52 , 0x30 ,
0x55 , 0xae ,
0x56 , 0x47 ,
0x57 , 0xe1 ,
0x58 , 0x3a ,
0x5a , 0x1e ,
0x5b , 0x34 ,
0x60 , 0x00 ,
0x63 , 0x00 ,
0x64 , 0x00 ,
0x65 , 0x00 ,
0x66 , 0x00 ,
0x67 , 0x00 ,
0x68 , 0x00 ,
0x69 , 0x00 ,
0x6a , 0x02 ,
0x6b , 0x00 ,
0x70 , 0xff ,
0x71 , 0x00 ,
0x72 , 0x00 ,
0x73 , 0x00 ,
0x74 , 0x0c ,
0x80 , 0x00 ,
0x81 , 0x00 ,
0x82 , 0x00 ,
0x83 , 0x00 ,
0x84 , 0x04 ,
0x85 , 0x80 ,
0x86 , 0x24 ,
0x87 , 0x78 ,
0x88 , 0x10 ,
0x89 , 0x00 ,
0x90 , 0x01 ,
0x91 , 0x01 ,
0xa0 , 0x04 ,
0xa1 , 0x00 ,
0xa2 , 0x00 ,
0xb0 , 0x91 ,
0xb1 , 0x0b ,
0xc0 , 0x53 ,
0xc1 , 0x70 ,
0xc2 , 0x12 ,
0xd0 , 0x00 ,
0xd1 , 0x00 ,
0xd2 , 0x00 ,
0xd3 , 0x00 ,
0xd4 , 0x00 ,
0xd5 , 0x00 ,
0xde , 0x00 ,
0xdf , 0x00 ,
0x61 , 0x49 ,
0x62 , 0x0b ,
0x53 , 0x08 ,
0x59 , 0x08 ,
0xff , 0xff ,
} ;
2005-04-17 02:20:36 +04:00
2006-04-19 00:47:11 +04:00
static int nexusca_stv0297_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
struct av7110 * av7110 = fe - > dvb - > priv ;
u32 div ;
u8 data [ 4 ] ;
struct i2c_msg msg = { . addr = 0x63 , . flags = 0 , . buf = data , . len = sizeof ( data ) } ;
struct i2c_msg readmsg = { . addr = 0x63 , . flags = I2C_M_RD , . buf = data , . len = 1 } ;
int i ;
div = ( params - > frequency + 36150000 + 31250 ) / 62500 ;
data [ 0 ] = ( div > > 8 ) & 0x7f ;
data [ 1 ] = div & 0xff ;
data [ 2 ] = 0xce ;
if ( params - > frequency < 45000000 )
return - EINVAL ;
else if ( params - > frequency < 137000000 )
data [ 3 ] = 0x01 ;
else if ( params - > frequency < 403000000 )
data [ 3 ] = 0x02 ;
else if ( params - > frequency < 860000000 )
data [ 3 ] = 0x04 ;
else
return - EINVAL ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & msg , 1 ) ! = 1 ) {
printk ( " nexusca: pll transfer failed! \n " ) ;
return - EIO ;
}
// wait for PLL lock
for ( i = 0 ; i < 20 ; i + + ) {
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & readmsg , 1 ) = = 1 )
if ( data [ 0 ] & 0x40 ) break ;
msleep ( 10 ) ;
}
return 0 ;
}
static struct stv0297_config nexusca_stv0297_config = {
. demod_address = 0x1C ,
2005-09-10 00:03:07 +04:00
. inittab = nexusca_stv0297_inittab ,
2005-04-17 02:20:36 +04:00
. invert = 1 ,
2006-04-28 04:45:20 +04:00
. stop_during_read = 1 ,
2005-04-17 02:20:36 +04:00
} ;
2006-04-19 00:47:11 +04:00
static int grundig_29504_401_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
2006-12-26 13:33:48 +03:00
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-04-17 02:20:36 +04:00
u32 div ;
u8 cfg , cpump , band_select ;
u8 data [ 4 ] ;
struct i2c_msg msg = { . addr = 0x61 , . flags = 0 , . buf = data , . len = sizeof ( data ) } ;
div = ( 36125000 + params - > frequency ) / 166666 ;
cfg = 0x88 ;
if ( params - > frequency < 175000000 ) cpump = 2 ;
else if ( params - > frequency < 390000000 ) cpump = 1 ;
else if ( params - > frequency < 470000000 ) cpump = 2 ;
else if ( params - > frequency < 750000000 ) cpump = 1 ;
else cpump = 3 ;
if ( params - > frequency < 175000000 ) band_select = 0x0e ;
else if ( params - > frequency < 470000000 ) band_select = 0x05 ;
else band_select = 0x03 ;
data [ 0 ] = ( div > > 8 ) & 0x7f ;
data [ 1 ] = div & 0xff ;
data [ 2 ] = ( ( div > > 10 ) & 0x60 ) | cfg ;
data [ 3 ] = ( cpump < < 6 ) | band_select ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-04-17 02:20:36 +04:00
if ( i2c_transfer ( & av7110 - > i2c_adap , & msg , 1 ) ! = 1 ) return - EIO ;
return 0 ;
}
static struct l64781_config grundig_29504_401_config = {
. demod_address = 0x55 ,
} ;
2005-07-08 04:57:59 +04:00
static int av7110_fe_lock_fix ( struct av7110 * av7110 , fe_status_t status )
2005-04-17 02:20:36 +04:00
{
2005-07-08 04:57:59 +04:00
int ret = 0 ;
2005-04-17 02:20:36 +04:00
int synced = ( status & FE_HAS_LOCK ) ? 1 : 0 ;
av7110 - > fe_status = status ;
if ( av7110 - > fe_synced = = synced )
2005-07-08 04:57:59 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2007-03-03 20:45:48 +03:00
if ( av7110 - > playing ) {
av7110 - > fe_synced = synced ;
2005-07-08 04:57:59 +04:00
return 0 ;
2007-03-03 20:45:48 +03:00
}
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > pid_mutex ) )
2005-07-08 04:57:59 +04:00
return - ERESTARTSYS ;
2005-04-17 02:20:36 +04:00
2005-07-08 04:58:02 +04:00
if ( synced ) {
2005-07-08 04:57:59 +04:00
ret = SetPIDs ( av7110 , av7110 - > pids [ DMX_PES_VIDEO ] ,
2005-04-17 02:20:36 +04:00
av7110 - > pids [ DMX_PES_AUDIO ] ,
av7110 - > pids [ DMX_PES_TELETEXT ] , 0 ,
av7110 - > pids [ DMX_PES_PCR ] ) ;
2005-07-08 04:57:59 +04:00
if ( ! ret )
ret = av7110_fw_cmd ( av7110 , COMTYPE_PIDFILTER , Scan , 0 ) ;
2005-04-17 02:20:36 +04:00
} else {
2005-07-08 04:57:59 +04:00
ret = SetPIDs ( av7110 , 0 , 0 , 0 , 0 , 0 ) ;
if ( ! ret ) {
ret = av7110_fw_cmd ( av7110 , COMTYPE_PID_FILTER , FlushTSQueue , 0 ) ;
if ( ! ret )
ret = av7110_wait_msgstate ( av7110 , GPMQBusy ) ;
}
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:58:02 +04:00
if ( ! ret )
av7110 - > fe_synced = synced ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > pid_mutex ) ;
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_set_frontend ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
2006-01-09 20:32:42 +03:00
if ( ! ret ) {
av7110 - > saved_fe_params = * params ;
2005-07-08 04:57:59 +04:00
ret = av7110 - > fe_set_frontend ( fe , params ) ;
2006-01-09 20:32:42 +03:00
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_init ( struct dvb_frontend * fe )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
if ( ! ret )
ret = av7110 - > fe_init ( fe ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_read_status ( struct dvb_frontend * fe , fe_status_t * status )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
/* call the real implementation */
2005-07-08 04:57:59 +04:00
int ret = av7110 - > fe_read_status ( fe , status ) ;
if ( ! ret )
if ( ( ( * status ^ av7110 - > fe_status ) & FE_HAS_LOCK ) & & ( * status & FE_HAS_LOCK ) )
ret = av7110_fe_lock_fix ( av7110 , * status ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_diseqc_reset_overload ( struct dvb_frontend * fe )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
if ( ! ret )
ret = av7110 - > fe_diseqc_reset_overload ( fe ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_diseqc_send_master_cmd ( struct dvb_frontend * fe ,
struct dvb_diseqc_master_cmd * cmd )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
2006-01-09 20:32:42 +03:00
if ( ! ret ) {
av7110 - > saved_master_cmd = * cmd ;
2005-07-08 04:57:59 +04:00
ret = av7110 - > fe_diseqc_send_master_cmd ( fe , cmd ) ;
2006-01-09 20:32:42 +03:00
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_diseqc_send_burst ( struct dvb_frontend * fe , fe_sec_mini_cmd_t minicmd )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
2006-01-09 20:32:42 +03:00
if ( ! ret ) {
av7110 - > saved_minicmd = minicmd ;
2005-07-08 04:57:59 +04:00
ret = av7110 - > fe_diseqc_send_burst ( fe , minicmd ) ;
2006-01-09 20:32:42 +03:00
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_set_tone ( struct dvb_frontend * fe , fe_sec_tone_mode_t tone )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
2006-01-09 20:32:42 +03:00
if ( ! ret ) {
av7110 - > saved_tone = tone ;
2005-07-08 04:57:59 +04:00
ret = av7110 - > fe_set_tone ( fe , tone ) ;
2006-01-09 20:32:42 +03:00
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
static int av7110_fe_set_voltage ( struct dvb_frontend * fe , fe_sec_voltage_t voltage )
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
2006-01-09 20:32:42 +03:00
if ( ! ret ) {
av7110 - > saved_voltage = voltage ;
2005-07-08 04:57:59 +04:00
ret = av7110 - > fe_set_voltage ( fe , voltage ) ;
2006-01-09 20:32:42 +03:00
}
2005-07-08 04:57:59 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2006-01-09 20:32:43 +03:00
static int av7110_fe_dishnetwork_send_legacy_command ( struct dvb_frontend * fe , unsigned long cmd )
2005-04-17 02:20:36 +04:00
{
struct av7110 * av7110 = fe - > dvb - > priv ;
2005-07-08 04:57:59 +04:00
int ret = av7110_fe_lock_fix ( av7110 , 0 ) ;
if ( ! ret )
ret = av7110 - > fe_dishnetwork_send_legacy_command ( fe , cmd ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2006-01-09 20:32:42 +03:00
static void dvb_s_recover ( struct av7110 * av7110 )
{
av7110_fe_init ( av7110 - > fe ) ;
av7110_fe_set_voltage ( av7110 - > fe , av7110 - > saved_voltage ) ;
if ( av7110 - > saved_master_cmd . msg_len ) {
msleep ( 20 ) ;
av7110_fe_diseqc_send_master_cmd ( av7110 - > fe , & av7110 - > saved_master_cmd ) ;
}
msleep ( 20 ) ;
av7110_fe_diseqc_send_burst ( av7110 - > fe , av7110 - > saved_minicmd ) ;
msleep ( 20 ) ;
av7110_fe_set_tone ( av7110 - > fe , av7110 - > saved_tone ) ;
av7110_fe_set_frontend ( av7110 - > fe , & av7110 - > saved_fe_params ) ;
}
2005-04-17 02:20:36 +04:00
static u8 read_pwm ( struct av7110 * av7110 )
{
u8 b = 0xff ;
u8 pwm ;
struct i2c_msg msg [ ] = { { . addr = 0x50 , . flags = 0 , . buf = & b , . len = 1 } ,
{ . addr = 0x50 , . flags = I2C_M_RD , . buf = & pwm , . len = 1 } } ;
2005-12-12 11:37:24 +03:00
if ( ( i2c_transfer ( & av7110 - > i2c_adap , msg , 2 ) ! = 2 ) | | ( pwm = = 0xff ) )
2005-04-17 02:20:36 +04:00
pwm = 0x48 ;
return pwm ;
}
static int frontend_init ( struct av7110 * av7110 )
{
int ret ;
if ( av7110 - > dev - > pci - > subsystem_vendor = = 0x110a ) {
switch ( av7110 - > dev - > pci - > subsystem_device ) {
case 0x0000 : // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( ves1820_attach , & philips_cd1516_config ,
2005-04-17 02:20:36 +04:00
& av7110 - > i2c_adap , read_pwm ( av7110 ) ) ;
2006-04-20 19:01:47 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = philips_cd1516_tuner_set_params ;
2006-04-20 19:01:47 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
}
} else if ( av7110 - > dev - > pci - > subsystem_vendor = = 0x13c2 ) {
switch ( av7110 - > dev - > pci - > subsystem_device ) {
case 0x0000 : // Hauppauge/TT WinTV DVB-S rev1.X
case 0x0003 : // Hauppauge/TT WinTV Nexus-S Rev 2.X
case 0x1002 : // Hauppauge/TT WinTV DVB-S rev1.3SE
// try the ALPS BSRV2 first of all
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( ves1x93_attach , & alps_bsrv2_config , & av7110 - > i2c_adap ) ;
2005-04-17 02:20:36 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = alps_bsrv2_tuner_set_params ;
av7110 - > fe - > ops . diseqc_send_master_cmd = av7110_diseqc_send_master_cmd ;
av7110 - > fe - > ops . diseqc_send_burst = av7110_diseqc_send_burst ;
av7110 - > fe - > ops . set_tone = av7110_set_tone ;
2006-01-09 20:32:42 +03:00
av7110 - > recover = dvb_s_recover ;
2005-04-17 02:20:36 +04:00
break ;
}
// try the ALPS BSRU6 now
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( stv0299_attach , & alps_bsru6_config , & av7110 - > i2c_adap ) ;
2005-04-17 02:20:36 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = alps_bsru6_tuner_set_params ;
2006-04-19 00:47:11 +04:00
av7110 - > fe - > tuner_priv = & av7110 - > i2c_adap ;
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . diseqc_send_master_cmd = av7110_diseqc_send_master_cmd ;
av7110 - > fe - > ops . diseqc_send_burst = av7110_diseqc_send_burst ;
av7110 - > fe - > ops . set_tone = av7110_set_tone ;
2006-01-09 20:32:42 +03:00
av7110 - > recover = dvb_s_recover ;
2005-04-17 02:20:36 +04:00
break ;
}
// Try the grundig 29504-451
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( tda8083_attach , & grundig_29504_451_config , & av7110 - > i2c_adap ) ;
2005-04-17 02:20:36 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = grundig_29504_451_tuner_set_params ;
av7110 - > fe - > ops . diseqc_send_master_cmd = av7110_diseqc_send_master_cmd ;
av7110 - > fe - > ops . diseqc_send_burst = av7110_diseqc_send_burst ;
av7110 - > fe - > ops . set_tone = av7110_set_tone ;
2006-01-09 20:32:42 +03:00
av7110 - > recover = dvb_s_recover ;
2005-04-17 02:20:36 +04:00
break ;
}
/* Try DVB-C cards */
switch ( av7110 - > dev - > pci - > subsystem_device ) {
case 0x0000 :
/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( ves1820_attach , & philips_cd1516_config , & av7110 - > i2c_adap ,
2005-04-17 02:20:36 +04:00
read_pwm ( av7110 ) ) ;
2006-04-20 19:01:47 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = philips_cd1516_tuner_set_params ;
2006-04-20 19:01:47 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
case 0x0003 :
2006-03-30 05:46:12 +04:00
/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( ves1820_attach , & alps_tdbe2_config , & av7110 - > i2c_adap ,
2005-04-17 02:20:36 +04:00
read_pwm ( av7110 ) ) ;
2006-04-20 19:01:47 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = alps_tdbe2_tuner_set_params ;
2006-04-20 19:01:47 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
}
break ;
case 0x0001 : // Hauppauge/TT Nexus-T premium rev1.X
2006-08-07 09:04:26 +04:00
// try ALPS TDLB7 first, then Grundig 29504-401
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( sp8870_attach , & alps_tdlb7_config , & av7110 - > i2c_adap ) ;
2006-04-20 19:01:47 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = alps_tdlb7_tuner_set_params ;
2006-08-07 09:04:26 +04:00
break ;
2006-04-20 19:01:47 +04:00
}
2006-08-07 09:04:26 +04:00
/* fall-thru */
case 0x0008 : // Hauppauge/TT DVB-T
// Grundig 29504-401
av7110 - > fe = dvb_attach ( l64781_attach , & grundig_29504_401_config , & av7110 - > i2c_adap ) ;
if ( av7110 - > fe )
av7110 - > fe - > ops . tuner_ops . set_params = grundig_29504_401_tuner_set_params ;
2005-04-17 02:20:36 +04:00
break ;
case 0x0002 : // Hauppauge/TT DVB-C premium rev2.X
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( ves1820_attach , & alps_tdbe2_config , & av7110 - > i2c_adap , read_pwm ( av7110 ) ) ;
2006-04-20 19:01:47 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = alps_tdbe2_tuner_set_params ;
2006-04-20 19:01:47 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
2006-02-07 11:49:11 +03:00
case 0x0004 : // Galaxis DVB-S rev1.3
/* ALPS BSRV2 */
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( ves1x93_attach , & alps_bsrv2_config , & av7110 - > i2c_adap ) ;
2006-02-07 11:49:11 +03:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = alps_bsrv2_tuner_set_params ;
av7110 - > fe - > ops . diseqc_send_master_cmd = av7110_diseqc_send_master_cmd ;
av7110 - > fe - > ops . diseqc_send_burst = av7110_diseqc_send_burst ;
av7110 - > fe - > ops . set_tone = av7110_set_tone ;
2006-02-07 11:49:11 +03:00
av7110 - > recover = dvb_s_recover ;
}
break ;
2005-04-17 02:20:36 +04:00
case 0x0006 : /* Fujitsu-Siemens DVB-S rev 1.6 */
/* Grundig 29504-451 */
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( tda8083_attach , & grundig_29504_451_config , & av7110 - > i2c_adap ) ;
2005-04-17 02:20:36 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = grundig_29504_451_tuner_set_params ;
av7110 - > fe - > ops . diseqc_send_master_cmd = av7110_diseqc_send_master_cmd ;
av7110 - > fe - > ops . diseqc_send_burst = av7110_diseqc_send_burst ;
av7110 - > fe - > ops . set_tone = av7110_set_tone ;
2006-01-09 20:32:42 +03:00
av7110 - > recover = dvb_s_recover ;
2005-04-17 02:20:36 +04:00
}
break ;
case 0x000A : // Hauppauge/TT Nexus-CA rev1.X
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( stv0297_attach , & nexusca_stv0297_config , & av7110 - > i2c_adap ) ;
2005-04-17 02:20:36 +04:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = nexusca_stv0297_tuner_set_params ;
2006-04-19 00:47:11 +04:00
2005-04-17 02:20:36 +04:00
/* set TDA9819 into DVB mode */
2006-07-10 10:34:16 +04:00
saa7146_setgpio ( av7110 - > dev , 1 , SAA7146_GPIO_OUTLO ) ; // TDA9819 pin9(STD)
saa7146_setgpio ( av7110 - > dev , 3 , SAA7146_GPIO_OUTLO ) ; // TDA9819 pin30(VIF)
2005-04-17 02:20:36 +04:00
/* tuner on this needs a slower i2c bus speed */
av7110 - > dev - > i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240 ;
break ;
}
2005-05-17 08:54:19 +04:00
break ;
case 0x000E : /* Hauppauge/TT Nexus-S rev 2.3 */
/* ALPS BSBE1 */
2006-08-08 16:10:08 +04:00
av7110 - > fe = dvb_attach ( stv0299_attach , & alps_bsbe1_config , & av7110 - > i2c_adap ) ;
2006-01-09 20:25:05 +03:00
if ( av7110 - > fe ) {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . tuner_ops . set_params = alps_bsbe1_tuner_set_params ;
2006-04-19 00:47:11 +04:00
av7110 - > fe - > tuner_priv = & av7110 - > i2c_adap ;
2006-08-08 16:10:08 +04:00
if ( dvb_attach ( lnbp21_attach , av7110 - > fe , & av7110 - > i2c_adap , 0 , 0 ) = = NULL ) {
2006-02-28 16:32:25 +03:00
printk ( " dvb-ttpci: LNBP21 not found! \n " ) ;
2006-05-14 12:01:31 +04:00
if ( av7110 - > fe - > ops . release )
av7110 - > fe - > ops . release ( av7110 - > fe ) ;
2006-02-28 16:32:25 +03:00
av7110 - > fe = NULL ;
} else {
2006-05-14 12:01:31 +04:00
av7110 - > fe - > ops . dishnetwork_send_legacy_command = NULL ;
2006-02-28 16:32:25 +03:00
av7110 - > recover = dvb_s_recover ;
}
2006-01-09 20:25:05 +03:00
}
2005-05-17 08:54:19 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
}
if ( ! av7110 - > fe ) {
/* FIXME: propagate the failure code from the lower layers */
ret = - ENOMEM ;
printk ( " dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x \n " ,
av7110 - > dev - > pci - > vendor ,
av7110 - > dev - > pci - > device ,
av7110 - > dev - > pci - > subsystem_vendor ,
av7110 - > dev - > pci - > subsystem_device ) ;
} else {
2006-05-14 12:01:31 +04:00
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . init , av7110 - > fe_init , av7110_fe_init ) ;
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . read_status , av7110 - > fe_read_status , av7110_fe_read_status ) ;
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . diseqc_reset_overload , av7110 - > fe_diseqc_reset_overload , av7110_fe_diseqc_reset_overload ) ;
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . diseqc_send_master_cmd , av7110 - > fe_diseqc_send_master_cmd , av7110_fe_diseqc_send_master_cmd ) ;
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . diseqc_send_burst , av7110 - > fe_diseqc_send_burst , av7110_fe_diseqc_send_burst ) ;
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . set_tone , av7110 - > fe_set_tone , av7110_fe_set_tone ) ;
2007-07-16 23:54:49 +04:00
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . set_voltage , av7110 - > fe_set_voltage , av7110_fe_set_voltage ) ;
2006-05-14 12:01:31 +04:00
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . dishnetwork_send_legacy_command , av7110 - > fe_dishnetwork_send_legacy_command , av7110_fe_dishnetwork_send_legacy_command ) ;
FE_FUNC_OVERRIDE ( av7110 - > fe - > ops . set_frontend , av7110 - > fe_set_frontend , av7110_fe_set_frontend ) ;
2005-04-17 02:20:36 +04:00
2005-05-17 08:54:39 +04:00
ret = dvb_register_frontend ( & av7110 - > dvb_adapter , av7110 - > fe ) ;
2005-04-17 02:20:36 +04:00
if ( ret < 0 ) {
printk ( " av7110: Frontend registration failed! \n " ) ;
2006-08-08 16:10:09 +04:00
dvb_frontend_detach ( av7110 - > fe ) ;
2005-04-17 02:20:36 +04:00
av7110 - > fe = NULL ;
}
}
return ret ;
}
/* Budgetpatch note:
* Original hardware design by Roberto Deza :
* There is a DVB_Wiki at
* http : //212.227.36.83/linuxtv/wiki/index.php/Main_Page
* where is described this ' DVB TT Budget Patch ' , on Card Modding :
* http : //212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch
* On the short description there is also a link to a external file ,
* with more details :
* http : //perso.wanadoo.es/jesussolano/Ttf_tsc1.zip
*
* New software triggering design by Emard that works on
* original Roberto Deza ' s hardware :
*
* rps1 code for budgetpatch will copy internal HS event to GPIO3 pin .
* GPIO3 is in budget - patch hardware connectd to port B VSYNC
* HS is an internal event of 7146 , accessible with RPS
* and temporarily raised high every n lines
* ( n in defined in the RPS_THRESH1 counter threshold )
* I think HS is raised high on the beginning of the n - th line
* and remains high until this n - th line that triggered
* it is completely received . When the receiption of n - th line
* ends , HS is lowered .
*
* To transmit data over DMA , 7146 needs changing state at
* port B VSYNC pin . Any changing of port B VSYNC will
* cause some DMA data transfer , with more or less packets loss .
* It depends on the phase and frequency of VSYNC and
* the way of 7146 is instructed to trigger on port B ( defined
* in DD1_INIT register , 3 rd nibble from the right valid
* numbers are 0 - 7 , see datasheet )
*
* The correct triggering can minimize packet loss ,
* dvbtraffic should give this stable bandwidths :
* 22 k transponder = 33814 kbit / s
* 27.5 k transponder = 38045 kbit / s
* by experiment it is found that the best results
* ( stable bandwidths and almost no packet loss )
* are obtained using DD1_INIT triggering number 2
* ( Va at rising edge of VS Fa = HS x VS - failing forced toggle )
* and a VSYNC phase that occurs in the middle of DMA transfer
* ( about byte 188 * 512 = 96256 in the DMA window ) .
*
* Phase of HS is still not clear to me how to control ,
* It just happens to be so . It can be seen if one enables
* RPS_IRQ and print Event Counter 1 in vpeirq ( ) . Every
* time RPS_INTERRUPT is called , the Event Counter 1 will
* increment . That ' s how the 7146 is programmed to do event
* counting in this budget - patch . c
* I * think * HPS setting has something to do with the phase
* of HS but I cant be 100 % sure in that .
*
* hardware debug note : a working budget card ( including budget patch )
* with vpeirq ( ) interrupt setup in mode " 0x90 " ( every 64 K ) will
* generate 3 interrupts per 25 - Hz DMA frame of 2 * 188 * 512 bytes
* and that means 3 * 25 = 75 Hz of interrupt freqency , as seen by
* watch cat / proc / interrupts
*
* If this frequency is 3 x lower ( and data received in the DMA
* buffer don ' t start with 0x47 , but in the middle of packets ,
* whose lengths appear to be like 188 292 188 104 etc .
* this means VSYNC line is not connected in the hardware .
* ( check soldering pcb and pins )
* The same behaviour of missing VSYNC can be duplicated on budget
* cards , by seting DD1_INIT trigger mode 7 in 3 rd nibble .
*/
2006-02-27 06:09:20 +03:00
static int __devinit av7110_attach ( struct saa7146_dev * dev ,
struct saa7146_pci_extension_data * pci_ext )
2005-04-17 02:20:36 +04:00
{
const int length = TS_WIDTH * TS_HEIGHT ;
struct pci_dev * pdev = dev - > pci ;
struct av7110 * av7110 ;
2007-02-08 20:32:43 +03:00
struct task_struct * thread ;
2005-04-17 02:20:36 +04:00
int ret , count = 0 ;
dprintk ( 4 , " dev: %p \n " , dev ) ;
2005-12-12 11:37:24 +03:00
/* Set RPS_IRQ to 1 to track rps1 activity.
* Enabling this won ' t send any interrupt to PC CPU .
*/
2005-04-17 02:20:36 +04:00
# define RPS_IRQ 0
if ( budgetpatch = = 1 ) {
budgetpatch = 0 ;
/* autodetect the presence of budget patch
* this only works if saa7146 has been recently
* reset with with MASK_31 to MC1
*
* will wait for VBI_B event ( vertical blank at port B )
* and will reset GPIO3 after VBI_B is detected .
* ( GPIO3 should be raised high by CPU to
* test if GPIO3 will generate vertical blank signal
* in budget patch GPIO3 is connected to VSYNC_B
*/
/* RESET SAA7146 */
saa7146_write ( dev , MC1 , MASK_31 ) ;
/* autodetection success seems to be time-dependend after reset */
/* Fix VSYNC level */
saa7146_setgpio ( dev , 3 , SAA7146_GPIO_OUTLO ) ;
/* set vsync_b triggering */
saa7146_write ( dev , DD1_STREAM_B , 0 ) ;
/* port B VSYNC at rising edge */
saa7146_write ( dev , DD1_INIT , 0x00000200 ) ;
saa7146_write ( dev , BRS_CTRL , 0x00000000 ) ; // VBI
saa7146_write ( dev , MC2 ,
1 * ( MASK_08 | MASK_24 ) | // BRS control
0 * ( MASK_09 | MASK_25 ) | // a
1 * ( MASK_10 | MASK_26 ) | // b
0 * ( MASK_06 | MASK_22 ) | // HPS_CTRL1
0 * ( MASK_05 | MASK_21 ) | // HPS_CTRL2
0 * ( MASK_01 | MASK_15 ) // DEBI
) ;
/* start writing RPS1 code from beginning */
count = 0 ;
/* Disable RPS1 */
saa7146_write ( dev , MC1 , MASK_29 ) ;
/* RPS1 timeout disable */
saa7146_write ( dev , RPS_TOV1 , 0 ) ;
WRITE_RPS1 ( cpu_to_le32 ( CMD_PAUSE | EVT_VBI_B ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( CMD_WR_REG_MASK | ( GPIO_CTRL > > 2 ) ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( GPIO3_MSK ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( SAA7146_GPIO_OUTLO < < 24 ) ) ;
# if RPS_IRQ
/* issue RPS1 interrupt to increment counter */
WRITE_RPS1 ( cpu_to_le32 ( CMD_INTERRUPT ) ) ;
# endif
WRITE_RPS1 ( cpu_to_le32 ( CMD_STOP ) ) ;
/* Jump to begin of RPS program as safety measure (p37) */
WRITE_RPS1 ( cpu_to_le32 ( CMD_JUMP ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( dev - > d_rps1 . dma_handle ) ) ;
# if RPS_IRQ
/* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
* use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq ( ) is called
*/
saa7146_write ( dev , EC1SSR , ( 0x03 < < 2 ) | 3 ) ;
/* set event counter 1 treshold to maximum allowed value (rEC p55) */
saa7146_write ( dev , ECT1R , 0x3fff ) ;
# endif
/* Set RPS1 Address register to point to RPS code (r108 p42) */
saa7146_write ( dev , RPS_ADDR1 , dev - > d_rps1 . dma_handle ) ;
/* Enable RPS1, (rFC p33) */
saa7146_write ( dev , MC1 , ( MASK_13 | MASK_29 ) ) ;
mdelay ( 10 ) ;
/* now send VSYNC_B to rps1 by rising GPIO3 */
saa7146_setgpio ( dev , 3 , SAA7146_GPIO_OUTHI ) ;
mdelay ( 10 ) ;
/* if rps1 responded by lowering the GPIO3,
* then we have budgetpatch hardware
*/
if ( ( saa7146_read ( dev , GPIO_CTRL ) & 0x10000000 ) = = 0 ) {
budgetpatch = 1 ;
printk ( " dvb-ttpci: BUDGET-PATCH DETECTED. \n " ) ;
}
/* Disable RPS1 */
saa7146_write ( dev , MC1 , ( MASK_29 ) ) ;
# if RPS_IRQ
printk ( " dvb-ttpci: Event Counter 1 0x%04x \n " , saa7146_read ( dev , EC1R ) & 0x3fff ) ;
# endif
}
/* prepare the av7110 device struct */
2006-01-12 00:40:56 +03:00
av7110 = kzalloc ( sizeof ( struct av7110 ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! av7110 ) {
dprintk ( 1 , " out of memory \n " ) ;
return - ENOMEM ;
}
av7110 - > card_name = ( char * ) pci_ext - > ext_priv ;
av7110 - > dev = dev ;
dev - > ext_priv = av7110 ;
ret = get_firmware ( av7110 ) ;
if ( ret < 0 )
goto err_kfree_0 ;
ret = dvb_register_adapter ( & av7110 - > dvb_adapter , av7110 - > card_name ,
2008-04-10 02:13:13 +04:00
THIS_MODULE , & dev - > pci - > dev , adapter_nr ) ;
2005-04-17 02:20:36 +04:00
if ( ret < 0 )
goto err_put_firmware_1 ;
/* the Siemens DVB needs this if you want to have the i2c chips
get recognized before the main driver is fully loaded */
saa7146_write ( dev , GPIO_CTRL , 0x500000 ) ;
# ifdef I2C_ADAP_CLASS_TV_DIGITAL
av7110 - > i2c_adap . class = I2C_ADAP_CLASS_TV_DIGITAL ;
# else
av7110 - > i2c_adap . class = I2C_CLASS_TV_DIGITAL ;
# endif
strlcpy ( av7110 - > i2c_adap . name , pci_ext - > ext_priv , sizeof ( av7110 - > i2c_adap . name ) ) ;
saa7146_i2c_adapter_prepare ( dev , & av7110 - > i2c_adap , SAA7146_I2C_BUS_BIT_RATE_120 ) ; /* 275 kHz */
ret = i2c_add_adapter ( & av7110 - > i2c_adap ) ;
if ( ret < 0 )
goto err_dvb_unregister_adapter_2 ;
ttpci_eeprom_parse_mac ( & av7110 - > i2c_adap ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . proposed_mac ) ;
2005-04-17 02:20:36 +04:00
ret = - ENOMEM ;
if ( budgetpatch ) {
spin_lock_init ( & av7110 - > feedlock1 ) ;
av7110 - > grabbing = saa7146_vmalloc_build_pgtable ( pdev , length ,
& av7110 - > pt ) ;
if ( ! av7110 - > grabbing )
goto err_i2c_del_3 ;
saa7146_write ( dev , PCI_BT_V1 , 0x1c1f101f ) ;
saa7146_write ( dev , BCS_CTRL , 0x80400040 ) ;
/* set dd1 stream a & b */
saa7146_write ( dev , DD1_STREAM_B , 0x00000000 ) ;
saa7146_write ( dev , DD1_INIT , 0x03000200 ) ;
saa7146_write ( dev , MC2 , ( MASK_09 | MASK_25 | MASK_10 | MASK_26 ) ) ;
saa7146_write ( dev , BRS_CTRL , 0x60000000 ) ;
saa7146_write ( dev , BASE_ODD3 , 0 ) ;
saa7146_write ( dev , BASE_EVEN3 , 0 ) ;
saa7146_write ( dev , PROT_ADDR3 , TS_WIDTH * TS_HEIGHT ) ;
saa7146_write ( dev , BASE_PAGE3 , av7110 - > pt . dma | ME1 | 0x90 ) ;
saa7146_write ( dev , PITCH3 , TS_WIDTH ) ;
saa7146_write ( dev , NUM_LINE_BYTE3 , ( TS_HEIGHT < < 16 ) | TS_WIDTH ) ;
/* upload all */
saa7146_write ( dev , MC2 , 0x077c077c ) ;
saa7146_write ( dev , GPIO_CTRL , 0x000000 ) ;
# if RPS_IRQ
/* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
* use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq ( ) is called
*/
saa7146_write ( dev , EC1SSR , ( 0x03 < < 2 ) | 3 ) ;
/* set event counter 1 treshold to maximum allowed value (rEC p55) */
saa7146_write ( dev , ECT1R , 0x3fff ) ;
# endif
/* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */
count = 0 ;
/* Wait Source Line Counter Threshold (p36) */
WRITE_RPS1 ( cpu_to_le32 ( CMD_PAUSE | EVT_HS ) ) ;
/* Set GPIO3=1 (p42) */
WRITE_RPS1 ( cpu_to_le32 ( CMD_WR_REG_MASK | ( GPIO_CTRL > > 2 ) ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( GPIO3_MSK ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( SAA7146_GPIO_OUTHI < < 24 ) ) ;
# if RPS_IRQ
/* issue RPS1 interrupt */
WRITE_RPS1 ( cpu_to_le32 ( CMD_INTERRUPT ) ) ;
# endif
/* Wait reset Source Line Counter Threshold (p36) */
WRITE_RPS1 ( cpu_to_le32 ( CMD_PAUSE | RPS_INV | EVT_HS ) ) ;
/* Set GPIO3=0 (p42) */
WRITE_RPS1 ( cpu_to_le32 ( CMD_WR_REG_MASK | ( GPIO_CTRL > > 2 ) ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( GPIO3_MSK ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( SAA7146_GPIO_OUTLO < < 24 ) ) ;
# if RPS_IRQ
/* issue RPS1 interrupt */
WRITE_RPS1 ( cpu_to_le32 ( CMD_INTERRUPT ) ) ;
# endif
/* Jump to begin of RPS program (p37) */
WRITE_RPS1 ( cpu_to_le32 ( CMD_JUMP ) ) ;
WRITE_RPS1 ( cpu_to_le32 ( dev - > d_rps1 . dma_handle ) ) ;
/* Fix VSYNC level */
saa7146_setgpio ( dev , 3 , SAA7146_GPIO_OUTLO ) ;
/* Set RPS1 Address register to point to RPS code (r108 p42) */
saa7146_write ( dev , RPS_ADDR1 , dev - > d_rps1 . dma_handle ) ;
/* Set Source Line Counter Threshold, using BRS (rCC p43)
* It generates HS event every TS_HEIGHT lines
* this is related to TS_WIDTH set in register
* NUM_LINE_BYTE3 . If NUM_LINE_BYTE low 16 bits
* are set to TS_WIDTH bytes ( TS_WIDTH = 2 * 188 ) ,
* then RPS_THRESH1 should be set to trigger
* every TS_HEIGHT ( 512 ) lines .
*/
saa7146_write ( dev , RPS_THRESH1 , ( TS_HEIGHT * 1 ) | MASK_12 ) ;
/* Enable RPS1 (rFC p33) */
saa7146_write ( dev , MC1 , ( MASK_13 | MASK_29 ) ) ;
/* end of budgetpatch register initialization */
tasklet_init ( & av7110 - > vpe_tasklet , vpeirq , ( unsigned long ) av7110 ) ;
} else {
saa7146_write ( dev , PCI_BT_V1 , 0x1c00101f ) ;
saa7146_write ( dev , BCS_CTRL , 0x80400040 ) ;
/* set dd1 stream a & b */
saa7146_write ( dev , DD1_STREAM_B , 0x00000000 ) ;
saa7146_write ( dev , DD1_INIT , 0x03000000 ) ;
saa7146_write ( dev , MC2 , ( MASK_09 | MASK_25 | MASK_10 | MASK_26 ) ) ;
/* upload all */
saa7146_write ( dev , MC2 , 0x077c077c ) ;
saa7146_write ( dev , GPIO_CTRL , 0x000000 ) ;
}
tasklet_init ( & av7110 - > debi_tasklet , debiirq , ( unsigned long ) av7110 ) ;
tasklet_init ( & av7110 - > gpio_tasklet , gpioirq , ( unsigned long ) av7110 ) ;
2006-02-07 11:49:14 +03:00
mutex_init ( & av7110 - > pid_mutex ) ;
2005-04-17 02:20:36 +04:00
/* locks for data transfers from/to AV7110 */
spin_lock_init ( & av7110 - > debilock ) ;
2006-02-07 11:49:14 +03:00
mutex_init ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
av7110 - > debitype = - 1 ;
/* default OSD window */
av7110 - > osdwin = 1 ;
2006-02-07 11:49:14 +03:00
mutex_init ( & av7110 - > osd_mutex ) ;
2005-04-17 02:20:36 +04:00
2006-03-30 11:31:48 +04:00
/* TV standard */
2007-10-31 07:20:42 +03:00
av7110 - > vidmode = tv_standard = = 1 ? AV7110_VIDEO_MODE_NTSC
: AV7110_VIDEO_MODE_PAL ;
2006-03-30 11:31:48 +04:00
2005-04-17 02:20:36 +04:00
/* ARM "watchdog" */
init_waitqueue_head ( & av7110 - > arm_wait ) ;
av7110 - > arm_thread = NULL ;
/* allocate and init buffers */
av7110 - > debi_virt = pci_alloc_consistent ( pdev , 8192 , & av7110 - > debi_bus ) ;
if ( ! av7110 - > debi_virt )
goto err_saa71466_vfree_4 ;
av7110 - > iobuf = vmalloc ( AVOUTLEN + AOUTLEN + BMPLEN + 4 * IPACKS ) ;
if ( ! av7110 - > iobuf )
goto err_pci_free_5 ;
ret = av7110_av_init ( av7110 ) ;
if ( ret < 0 )
goto err_iobuf_vfree_6 ;
/* init BMP buffer */
av7110 - > bmpbuf = av7110 - > iobuf + AVOUTLEN + AOUTLEN ;
init_waitqueue_head ( & av7110 - > bmpq ) ;
ret = av7110_ca_init ( av7110 ) ;
if ( ret < 0 )
goto err_av7110_av_exit_7 ;
/* load firmware into AV7110 cards */
ret = av7110_bootarm ( av7110 ) ;
if ( ret < 0 )
goto err_av7110_ca_exit_8 ;
ret = av7110_firmversion ( av7110 ) ;
if ( ret < 0 )
goto err_stop_arm_9 ;
if ( FW_VERSION ( av7110 - > arm_app ) < 0x2501 )
printk ( " dvb-ttpci: Warning, firmware version 0x%04x is too old. "
" System might be unstable! \n " , FW_VERSION ( av7110 - > arm_app ) ) ;
2007-02-08 20:32:43 +03:00
thread = kthread_run ( arm_thread , ( void * ) av7110 , " arm_mon " ) ;
if ( IS_ERR ( thread ) ) {
ret = PTR_ERR ( thread ) ;
2005-04-17 02:20:36 +04:00
goto err_stop_arm_9 ;
2007-02-08 20:32:43 +03:00
}
av7110 - > arm_thread = thread ;
2005-04-17 02:20:36 +04:00
/* set initial volume in mixer struct */
av7110 - > mixer . volume_left = volume ;
av7110 - > mixer . volume_right = volume ;
ret = av7110_register ( av7110 ) ;
if ( ret < 0 )
goto err_arm_thread_stop_10 ;
2007-07-13 06:08:07 +04:00
init_av7110_av ( av7110 ) ;
2005-04-17 02:20:36 +04:00
/* special case DVB-C: these cards have an analog tuner
plus need some special handling , so we have separate
saa7146_ext_vv data for these . . . */
ret = av7110_init_v4l ( av7110 ) ;
if ( ret < 0 )
goto err_av7110_unregister_11 ;
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . priv = av7110 ;
2005-04-17 02:20:36 +04:00
ret = frontend_init ( av7110 ) ;
if ( ret < 0 )
goto err_av7110_exit_v4l_12 ;
# if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
2005-09-10 00:03:12 +04:00
av7110_ir_init ( av7110 ) ;
2005-04-17 02:20:36 +04:00
# endif
printk ( KERN_INFO " dvb-ttpci: found av7110-%d. \n " , av7110_num ) ;
av7110_num + + ;
out :
return ret ;
err_av7110_exit_v4l_12 :
av7110_exit_v4l ( av7110 ) ;
err_av7110_unregister_11 :
dvb_unregister ( av7110 ) ;
err_arm_thread_stop_10 :
av7110_arm_sync ( av7110 ) ;
err_stop_arm_9 :
/* Nothing to do. Rejoice. */
err_av7110_ca_exit_8 :
av7110_ca_exit ( av7110 ) ;
err_av7110_av_exit_7 :
av7110_av_exit ( av7110 ) ;
err_iobuf_vfree_6 :
vfree ( av7110 - > iobuf ) ;
err_pci_free_5 :
pci_free_consistent ( pdev , 8192 , av7110 - > debi_virt , av7110 - > debi_bus ) ;
err_saa71466_vfree_4 :
2007-05-03 19:23:44 +04:00
if ( av7110 - > grabbing )
saa7146_vfree_destroy_pgtable ( pdev , av7110 - > grabbing , & av7110 - > pt ) ;
2005-04-17 02:20:36 +04:00
err_i2c_del_3 :
i2c_del_adapter ( & av7110 - > i2c_adap ) ;
err_dvb_unregister_adapter_2 :
2005-05-17 08:54:39 +04:00
dvb_unregister_adapter ( & av7110 - > dvb_adapter ) ;
2005-04-17 02:20:36 +04:00
err_put_firmware_1 :
put_firmware ( av7110 ) ;
err_kfree_0 :
kfree ( av7110 ) ;
goto out ;
}
2006-02-27 06:09:20 +03:00
static int __devexit av7110_detach ( struct saa7146_dev * saa )
2005-04-17 02:20:36 +04:00
{
struct av7110 * av7110 = saa - > ext_priv ;
dprintk ( 4 , " %p \n " , av7110 ) ;
2005-09-10 00:03:12 +04:00
# if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
av7110_ir_exit ( av7110 ) ;
# endif
2005-04-17 02:20:36 +04:00
if ( budgetpatch ) {
/* Disable RPS1 */
saa7146_write ( saa , MC1 , MASK_29 ) ;
/* VSYNC LOW (inactive) */
saa7146_setgpio ( saa , 3 , SAA7146_GPIO_OUTLO ) ;
saa7146_write ( saa , MC1 , MASK_20 ) ; /* DMA3 off */
SAA7146_IER_DISABLE ( saa , MASK_10 ) ;
SAA7146_ISR_CLEAR ( saa , MASK_10 ) ;
msleep ( 50 ) ;
tasklet_kill ( & av7110 - > vpe_tasklet ) ;
2007-05-03 19:23:44 +04:00
saa7146_vfree_destroy_pgtable ( saa - > pci , av7110 - > grabbing , & av7110 - > pt ) ;
2005-04-17 02:20:36 +04:00
}
av7110_exit_v4l ( av7110 ) ;
av7110_arm_sync ( av7110 ) ;
tasklet_kill ( & av7110 - > debi_tasklet ) ;
tasklet_kill ( & av7110 - > gpio_tasklet ) ;
dvb_unregister ( av7110 ) ;
SAA7146_IER_DISABLE ( saa , MASK_19 | MASK_03 ) ;
SAA7146_ISR_CLEAR ( saa , MASK_19 | MASK_03 ) ;
av7110_ca_exit ( av7110 ) ;
av7110_av_exit ( av7110 ) ;
vfree ( av7110 - > iobuf ) ;
pci_free_consistent ( saa - > pci , 8192 , av7110 - > debi_virt ,
av7110 - > debi_bus ) ;
i2c_del_adapter ( & av7110 - > i2c_adap ) ;
2005-05-17 08:54:39 +04:00
dvb_unregister_adapter ( & av7110 - > dvb_adapter ) ;
2005-04-17 02:20:36 +04:00
av7110_num - - ;
put_firmware ( av7110 ) ;
kfree ( av7110 ) ;
saa - > ext_priv = NULL ;
return 0 ;
}
static void av7110_irq ( struct saa7146_dev * dev , u32 * isr )
{
struct av7110 * av7110 = dev - > ext_priv ;
//print_time("av7110_irq");
/* Note: Don't try to handle the DEBI error irq (MASK_18), in
* intel mode the timeout is asserted all the time . . .
*/
if ( * isr & MASK_19 ) {
//printk("av7110_irq: DEBI\n");
/* Note 1: The DEBI irq is level triggered: We must enable it
* only after we started a DMA xfer , and disable it here
* immediately , or it will be signalled all the time while
* DEBI is idle .
* Note 2 : You would think that an irq which is masked is
* not signalled by the hardware . Not so for the SAA7146 :
* An irq is signalled as long as the corresponding bit
* in the ISR is set , and disabling irqs just prevents the
* hardware from setting the ISR bit . This means a ) that we
* must clear the ISR * after * disabling the irq ( which is why
* we must do it here even though saa7146_core did it already ) ,
* and b ) that if we were to disable an edge triggered irq
* ( like the gpio irqs sadly are ) temporarily we would likely
* loose some . This sucks : - (
*/
SAA7146_IER_DISABLE ( av7110 - > dev , MASK_19 ) ;
SAA7146_ISR_CLEAR ( av7110 - > dev , MASK_19 ) ;
tasklet_schedule ( & av7110 - > debi_tasklet ) ;
}
if ( * isr & MASK_03 ) {
//printk("av7110_irq: GPIO\n");
tasklet_schedule ( & av7110 - > gpio_tasklet ) ;
}
if ( ( * isr & MASK_10 ) & & budgetpatch )
tasklet_schedule ( & av7110 - > vpe_tasklet ) ;
}
2008-01-11 01:31:47 +03:00
static struct saa7146_extension av7110_extension_driver ;
2005-04-17 02:20:36 +04:00
# define MAKE_AV7110_INFO(x_var,x_name) \
static struct saa7146_pci_extension_data x_var = { \
. ext_priv = x_name , \
2008-01-11 01:31:47 +03:00
. ext = & av7110_extension_driver }
2005-04-17 02:20:36 +04:00
2005-09-10 00:03:13 +04:00
MAKE_AV7110_INFO ( tts_1_X_fsc , " Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C " ) ;
2005-04-17 02:20:36 +04:00
MAKE_AV7110_INFO ( ttt_1_X , " Technotrend/Hauppauge WinTV DVB-T rev1.X " ) ;
MAKE_AV7110_INFO ( ttc_1_X , " Technotrend/Hauppauge WinTV Nexus-CA rev1.X " ) ;
MAKE_AV7110_INFO ( ttc_2_X , " Technotrend/Hauppauge WinTV DVB-C rev2.X " ) ;
MAKE_AV7110_INFO ( tts_2_X , " Technotrend/Hauppauge WinTV Nexus-S rev2.X " ) ;
2005-05-17 08:54:19 +04:00
MAKE_AV7110_INFO ( tts_2_3 , " Technotrend/Hauppauge WinTV Nexus-S rev2.3 " ) ;
2005-04-17 02:20:36 +04:00
MAKE_AV7110_INFO ( tts_1_3se , " Technotrend/Hauppauge WinTV DVB-S rev1.3 SE " ) ;
MAKE_AV7110_INFO ( ttt , " Technotrend/Hauppauge DVB-T " ) ;
MAKE_AV7110_INFO ( fsc , " Fujitsu Siemens DVB-C " ) ;
MAKE_AV7110_INFO ( fss , " Fujitsu Siemens DVB-S rev1.6 " ) ;
2006-02-07 11:49:11 +03:00
MAKE_AV7110_INFO ( gxs_1_3 , " Galaxis DVB-S rev1.3 " ) ;
2005-04-17 02:20:36 +04:00
static struct pci_device_id pci_tbl [ ] = {
2005-09-10 00:03:13 +04:00
MAKE_EXTENSION_PCI ( fsc , 0x110a , 0x0000 ) ,
MAKE_EXTENSION_PCI ( tts_1_X_fsc , 0x13c2 , 0x0000 ) ,
MAKE_EXTENSION_PCI ( ttt_1_X , 0x13c2 , 0x0001 ) ,
MAKE_EXTENSION_PCI ( ttc_2_X , 0x13c2 , 0x0002 ) ,
MAKE_EXTENSION_PCI ( tts_2_X , 0x13c2 , 0x0003 ) ,
2006-02-07 11:49:11 +03:00
MAKE_EXTENSION_PCI ( gxs_1_3 , 0x13c2 , 0x0004 ) ,
2005-09-10 00:03:13 +04:00
MAKE_EXTENSION_PCI ( fss , 0x13c2 , 0x0006 ) ,
MAKE_EXTENSION_PCI ( ttt , 0x13c2 , 0x0008 ) ,
MAKE_EXTENSION_PCI ( ttc_1_X , 0x13c2 , 0x000a ) ,
MAKE_EXTENSION_PCI ( tts_2_3 , 0x13c2 , 0x000e ) ,
MAKE_EXTENSION_PCI ( tts_1_3se , 0x13c2 , 0x1002 ) ,
2005-04-17 02:20:36 +04:00
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
{
. vendor = 0 ,
}
} ;
MODULE_DEVICE_TABLE ( pci , pci_tbl ) ;
2008-01-11 01:31:47 +03:00
static struct saa7146_extension av7110_extension_driver = {
2006-08-07 20:18:56 +04:00
. name = " dvb " ,
2006-11-01 19:09:51 +03:00
. flags = SAA7146_USE_I2C_IRQ ,
2005-04-17 02:20:36 +04:00
. module = THIS_MODULE ,
. pci_tbl = & pci_tbl [ 0 ] ,
. attach = av7110_attach ,
2006-02-27 06:09:20 +03:00
. detach = __devexit_p ( av7110_detach ) ,
2005-04-17 02:20:36 +04:00
. irq_mask = MASK_19 | MASK_03 | MASK_10 ,
. irq_func = av7110_irq ,
} ;
static int __init av7110_init ( void )
{
int retval ;
2008-01-11 01:31:47 +03:00
retval = saa7146_register_extension ( & av7110_extension_driver ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
static void __exit av7110_exit ( void )
{
2008-01-11 01:31:47 +03:00
saa7146_unregister_extension ( & av7110_extension_driver ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( av7110_init ) ;
module_exit ( av7110_exit ) ;
MODULE_DESCRIPTION ( " driver for the SAA7146 based AV110 PCI DVB cards by "
" Siemens, Technotrend, Hauppauge " ) ;
MODULE_AUTHOR ( " Ralph Metzler, Marcus Metzler, others " ) ;
MODULE_LICENSE ( " GPL " ) ;