2005-04-17 02:20:36 +04:00
/*
* budget - ci . c : driver for the SAA7146 based Budget DVB cards
*
* Compiled from various sources by Michael Hunold < michael @ mihu . de >
*
* msp430 IR support contributed by Jack Thomasson < jkt @ Helius . COM >
* partially based on the Siemens DVB driver by Ralph + Marcus Metzler
*
* CI interface support ( c ) 2004 Andrew de Quincey < adq_dvb @ lidskialf . net >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
* Or , point your browser to http : //www.gnu.org/copyleft/gpl.html
*
*
* the project ' s page is at http : //www.linuxtv.org/dvb/
*/
# include "budget.h"
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/input.h>
# include <linux/spinlock.h>
# include "dvb_ca_en50221.h"
# include "stv0299.h"
2005-09-10 00:03:07 +04:00
# include "stv0297.h"
2005-04-17 02:20:36 +04:00
# include "tda1004x.h"
2006-02-28 15:52:44 +03:00
# include "lnbp21.h"
# include "bsbe1.h"
2006-03-16 17:22:47 +03:00
# include "bsru6.h"
2005-04-17 02:20:36 +04:00
# define DEBIADDR_IR 0x1234
# define DEBIADDR_CICONTROL 0x0000
# define DEBIADDR_CIVERSION 0x4000
# define DEBIADDR_IO 0x1000
# define DEBIADDR_ATTR 0x3000
# define CICONTROL_RESET 0x01
# define CICONTROL_ENABLETS 0x02
# define CICONTROL_CAMDETECT 0x08
# define DEBICICTL 0x00420000
# define DEBICICAM 0x02420000
# define SLOTSTATUS_NONE 1
# define SLOTSTATUS_PRESENT 2
# define SLOTSTATUS_RESET 4
# define SLOTSTATUS_READY 8
# define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
struct budget_ci {
struct budget budget ;
2005-09-15 11:01:53 +04:00
struct input_dev * input_dev ;
2005-04-17 02:20:36 +04:00
struct tasklet_struct msp430_irq_tasklet ;
struct tasklet_struct ciintf_irq_tasklet ;
int slot_status ;
2006-04-05 21:09:45 +04:00
int ci_irq ;
2005-04-17 02:20:36 +04:00
struct dvb_ca_en50221 ca ;
char ir_dev_name [ 50 ] ;
2005-07-08 04:57:54 +04:00
u8 tuner_pll_address ; /* used for philips_tdm1316l configs */
2005-04-17 02:20:36 +04:00
} ;
/* from reading the following remotes:
Zenith Universal 7 / TV Mode 807 / VCR Mode 837
Hauppauge ( from NOVA - CI - s box product )
i ' ve taken a " middle of the road " approach and note the differences
*/
static u16 key_map [ 64 ] = {
/* 0x0X */
KEY_0 , KEY_1 , KEY_2 , KEY_3 , KEY_4 , KEY_5 , KEY_6 , KEY_7 , KEY_8 ,
KEY_9 ,
KEY_ENTER ,
KEY_RED ,
KEY_POWER , /* RADIO on Hauppauge */
KEY_MUTE ,
0 ,
KEY_A , /* TV on Hauppauge */
/* 0x1X */
KEY_VOLUMEUP , KEY_VOLUMEDOWN ,
0 , 0 ,
KEY_B ,
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
KEY_UP , KEY_DOWN ,
KEY_OPTION , /* RESERVED on Hauppauge */
KEY_BREAK ,
/* 0x2X */
KEY_CHANNELUP , KEY_CHANNELDOWN ,
KEY_PREVIOUS , /* Prev. Ch on Zenith, SOURCE on Hauppauge */
0 , KEY_RESTART , KEY_OK ,
KEY_CYCLEWINDOWS , /* MINIMIZE on Hauppauge */
0 ,
KEY_ENTER , /* VCR mode on Zenith */
KEY_PAUSE ,
0 ,
KEY_RIGHT , KEY_LEFT ,
0 ,
KEY_MENU , /* FULL SCREEN on Hauppauge */
0 ,
/* 0x3X */
KEY_SLOW ,
KEY_PREVIOUS , /* VCR mode on Zenith */
KEY_REWIND ,
0 ,
KEY_FASTFORWARD ,
KEY_PLAY , KEY_STOP ,
KEY_RECORD ,
KEY_TUNER , /* TV/VCR on Zenith */
0 ,
KEY_C ,
0 ,
KEY_EXIT ,
KEY_POWER2 ,
KEY_TUNER , /* VCR mode on Zenith */
0 ,
} ;
static void msp430_ir_debounce ( unsigned long data )
{
struct input_dev * dev = ( struct input_dev * ) data ;
if ( dev - > rep [ 0 ] = = 0 | | dev - > rep [ 0 ] = = ~ 0 ) {
input_event ( dev , EV_KEY , key_map [ dev - > repeat_key ] , ! ! 0 ) ;
return ;
}
dev - > rep [ 0 ] = 0 ;
dev - > timer . expires = jiffies + HZ * 350 / 1000 ;
add_timer ( & dev - > timer ) ;
input_event ( dev , EV_KEY , key_map [ dev - > repeat_key ] , 2 ) ; /* REPEAT */
}
static void msp430_ir_interrupt ( unsigned long data )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) data ;
2005-09-15 11:01:53 +04:00
struct input_dev * dev = budget_ci - > input_dev ;
2005-04-17 02:20:36 +04:00
unsigned int code =
ttpci_budget_debiread ( & budget_ci - > budget , DEBINOSWAP , DEBIADDR_IR , 2 , 1 , 0 ) > > 8 ;
if ( code & 0x40 ) {
code & = 0x3f ;
if ( timer_pending ( & dev - > timer ) ) {
if ( code = = dev - > repeat_key ) {
+ + dev - > rep [ 0 ] ;
return ;
}
del_timer ( & dev - > timer ) ;
input_event ( dev , EV_KEY , key_map [ dev - > repeat_key ] , ! ! 0 ) ;
}
if ( ! key_map [ code ] ) {
printk ( " DVB (%s): no key for %02x! \n " , __FUNCTION__ , code ) ;
return ;
}
/* initialize debounce and repeat */
dev - > repeat_key = code ;
/* Zenith remote _always_ sends 2 sequences */
dev - > rep [ 0 ] = ~ 0 ;
/* 350 milliseconds */
dev - > timer . expires = jiffies + HZ * 350 / 1000 ;
/* MAKE */
input_event ( dev , EV_KEY , key_map [ code ] , ! 0 ) ;
add_timer ( & dev - > timer ) ;
}
}
static int msp430_ir_init ( struct budget_ci * budget_ci )
{
struct saa7146_dev * saa = budget_ci - > budget . dev ;
2005-09-15 11:01:53 +04:00
struct input_dev * input_dev ;
2005-04-17 02:20:36 +04:00
int i ;
2005-09-15 11:01:53 +04:00
budget_ci - > input_dev = input_dev = input_allocate_device ( ) ;
if ( ! input_dev )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
sprintf ( budget_ci - > ir_dev_name , " Budget-CI dvb ir receiver %s " , saa - > name ) ;
2005-09-15 11:01:53 +04:00
input_dev - > name = budget_ci - > ir_dev_name ;
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:53 +04:00
set_bit ( EV_KEY , input_dev - > evbit ) ;
for ( i = 0 ; i < ARRAY_SIZE ( key_map ) ; i + + )
2005-04-17 02:20:36 +04:00
if ( key_map [ i ] )
2005-09-15 11:01:53 +04:00
set_bit ( key_map [ i ] , input_dev - > keybit ) ;
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:53 +04:00
input_register_device ( budget_ci - > input_dev ) ;
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:53 +04:00
input_dev - > timer . function = msp430_ir_debounce ;
2005-04-17 02:20:36 +04:00
saa7146_write ( saa , IER , saa7146_read ( saa , IER ) | MASK_06 ) ;
saa7146_setgpio ( saa , 3 , SAA7146_GPIO_IRQHI ) ;
return 0 ;
}
static void msp430_ir_deinit ( struct budget_ci * budget_ci )
{
struct saa7146_dev * saa = budget_ci - > budget . dev ;
2005-09-15 11:01:53 +04:00
struct input_dev * dev = budget_ci - > input_dev ;
2005-04-17 02:20:36 +04:00
saa7146_write ( saa , IER , saa7146_read ( saa , IER ) & ~ MASK_06 ) ;
saa7146_setgpio ( saa , 3 , SAA7146_GPIO_INPUT ) ;
if ( del_timer ( & dev - > timer ) )
input_event ( dev , EV_KEY , key_map [ dev - > repeat_key ] , ! ! 0 ) ;
input_unregister_device ( dev ) ;
}
static int ciintf_read_attribute_mem ( struct dvb_ca_en50221 * ca , int slot , int address )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
if ( slot ! = 0 )
return - EINVAL ;
return ttpci_budget_debiread ( & budget_ci - > budget , DEBICICAM ,
DEBIADDR_ATTR | ( address & 0xfff ) , 1 , 1 , 0 ) ;
}
static int ciintf_write_attribute_mem ( struct dvb_ca_en50221 * ca , int slot , int address , u8 value )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
if ( slot ! = 0 )
return - EINVAL ;
return ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICAM ,
DEBIADDR_ATTR | ( address & 0xfff ) , 1 , value , 1 , 0 ) ;
}
static int ciintf_read_cam_control ( struct dvb_ca_en50221 * ca , int slot , u8 address )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
if ( slot ! = 0 )
return - EINVAL ;
return ttpci_budget_debiread ( & budget_ci - > budget , DEBICICAM ,
DEBIADDR_IO | ( address & 3 ) , 1 , 1 , 0 ) ;
}
static int ciintf_write_cam_control ( struct dvb_ca_en50221 * ca , int slot , u8 address , u8 value )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
if ( slot ! = 0 )
return - EINVAL ;
return ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICAM ,
DEBIADDR_IO | ( address & 3 ) , 1 , value , 1 , 0 ) ;
}
static int ciintf_slot_reset ( struct dvb_ca_en50221 * ca , int slot )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
struct saa7146_dev * saa = budget_ci - > budget . dev ;
if ( slot ! = 0 )
return - EINVAL ;
2006-04-05 21:09:45 +04:00
if ( budget_ci - > ci_irq ) {
// trigger on RISING edge during reset so we know when READY is re-asserted
saa7146_setgpio ( saa , 0 , SAA7146_GPIO_IRQHI ) ;
}
2005-04-17 02:20:36 +04:00
budget_ci - > slot_status = SLOTSTATUS_RESET ;
ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 , 0 , 1 , 0 ) ;
msleep ( 1 ) ;
ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 ,
CICONTROL_RESET , 1 , 0 ) ;
saa7146_setgpio ( saa , 1 , SAA7146_GPIO_OUTHI ) ;
ttpci_budget_set_video_port ( saa , BUDGET_VIDEO_PORTB ) ;
return 0 ;
}
static int ciintf_slot_shutdown ( struct dvb_ca_en50221 * ca , int slot )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
struct saa7146_dev * saa = budget_ci - > budget . dev ;
if ( slot ! = 0 )
return - EINVAL ;
saa7146_setgpio ( saa , 1 , SAA7146_GPIO_OUTHI ) ;
ttpci_budget_set_video_port ( saa , BUDGET_VIDEO_PORTB ) ;
return 0 ;
}
static int ciintf_slot_ts_enable ( struct dvb_ca_en50221 * ca , int slot )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
struct saa7146_dev * saa = budget_ci - > budget . dev ;
int tmp ;
if ( slot ! = 0 )
return - EINVAL ;
saa7146_setgpio ( saa , 1 , SAA7146_GPIO_OUTLO ) ;
tmp = ttpci_budget_debiread ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 , 1 , 0 ) ;
ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 ,
tmp | CICONTROL_ENABLETS , 1 , 0 ) ;
ttpci_budget_set_video_port ( saa , BUDGET_VIDEO_PORTA ) ;
return 0 ;
}
static void ciintf_interrupt ( unsigned long data )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) data ;
struct saa7146_dev * saa = budget_ci - > budget . dev ;
unsigned int flags ;
// ensure we don't get spurious IRQs during initialisation
if ( ! budget_ci - > budget . ci_present )
return ;
// read the CAM status
flags = ttpci_budget_debiread ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 , 1 , 0 ) ;
if ( flags & CICONTROL_CAMDETECT ) {
// GPIO should be set to trigger on falling edge if a CAM is present
saa7146_setgpio ( saa , 0 , SAA7146_GPIO_IRQLO ) ;
if ( budget_ci - > slot_status & SLOTSTATUS_NONE ) {
// CAM insertion IRQ
budget_ci - > slot_status = SLOTSTATUS_PRESENT ;
dvb_ca_en50221_camchange_irq ( & budget_ci - > ca , 0 ,
DVB_CA_EN50221_CAMCHANGE_INSERTED ) ;
} else if ( budget_ci - > slot_status & SLOTSTATUS_RESET ) {
// CAM ready (reset completed)
budget_ci - > slot_status = SLOTSTATUS_READY ;
dvb_ca_en50221_camready_irq ( & budget_ci - > ca , 0 ) ;
} else if ( budget_ci - > slot_status & SLOTSTATUS_READY ) {
// FR/DA IRQ
dvb_ca_en50221_frda_irq ( & budget_ci - > ca , 0 ) ;
}
} else {
// trigger on rising edge if a CAM is not present - when a CAM is inserted, we
// only want to get the IRQ when it sets READY. If we trigger on the falling edge,
// the CAM might not actually be ready yet.
saa7146_setgpio ( saa , 0 , SAA7146_GPIO_IRQHI ) ;
// generate a CAM removal IRQ if we haven't already
if ( budget_ci - > slot_status & SLOTSTATUS_OCCUPIED ) {
// CAM removal IRQ
budget_ci - > slot_status = SLOTSTATUS_NONE ;
dvb_ca_en50221_camchange_irq ( & budget_ci - > ca , 0 ,
DVB_CA_EN50221_CAMCHANGE_REMOVED ) ;
}
}
}
2006-04-05 21:09:45 +04:00
static int ciintf_poll_slot_status ( struct dvb_ca_en50221 * ca , int slot , int open )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) ca - > data ;
unsigned int flags ;
// ensure we don't get spurious IRQs during initialisation
if ( ! budget_ci - > budget . ci_present )
return - EINVAL ;
// read the CAM status
flags = ttpci_budget_debiread ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 , 1 , 0 ) ;
if ( flags & CICONTROL_CAMDETECT ) {
// mark it as present if it wasn't before
if ( budget_ci - > slot_status & SLOTSTATUS_NONE ) {
budget_ci - > slot_status = SLOTSTATUS_PRESENT ;
}
// during a RESET, we check if we can read from IO memory to see when CAM is ready
if ( budget_ci - > slot_status & SLOTSTATUS_RESET ) {
if ( ciintf_read_attribute_mem ( ca , slot , 0 ) = = 0x1d ) {
budget_ci - > slot_status = SLOTSTATUS_READY ;
}
}
} else {
budget_ci - > slot_status = SLOTSTATUS_NONE ;
}
if ( budget_ci - > slot_status ! = SLOTSTATUS_NONE ) {
if ( budget_ci - > slot_status & SLOTSTATUS_READY ) {
return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY ;
}
return DVB_CA_EN50221_POLL_CAM_PRESENT ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
static int ciintf_init ( struct budget_ci * budget_ci )
{
struct saa7146_dev * saa = budget_ci - > budget . dev ;
int flags ;
int result ;
2006-04-05 21:09:45 +04:00
int ci_version ;
int ca_flags ;
2005-04-17 02:20:36 +04:00
memset ( & budget_ci - > ca , 0 , sizeof ( struct dvb_ca_en50221 ) ) ;
// enable DEBI pins
saa7146_write ( saa , MC1 , saa7146_read ( saa , MC1 ) | ( 0x800 < < 16 ) | 0x800 ) ;
// test if it is there
2006-04-05 21:09:45 +04:00
ci_version = ttpci_budget_debiread ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CIVERSION , 1 , 1 , 0 ) ;
if ( ( ci_version & 0xa0 ) ! = 0xa0 ) {
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
goto error ;
}
2006-04-05 21:09:45 +04:00
2005-04-17 02:20:36 +04:00
// determine whether a CAM is present or not
flags = ttpci_budget_debiread ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 , 1 , 0 ) ;
budget_ci - > slot_status = SLOTSTATUS_NONE ;
if ( flags & CICONTROL_CAMDETECT )
budget_ci - > slot_status = SLOTSTATUS_PRESENT ;
2006-04-05 21:09:45 +04:00
// version 0xa2 of the CI firmware doesn't generate interrupts
if ( ci_version = = 0xa2 ) {
ca_flags = 0 ;
budget_ci - > ci_irq = 0 ;
} else {
ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
DVB_CA_EN50221_FLAG_IRQ_FR |
DVB_CA_EN50221_FLAG_IRQ_DA ;
budget_ci - > ci_irq = 1 ;
}
2005-04-17 02:20:36 +04:00
// register CI interface
budget_ci - > ca . owner = THIS_MODULE ;
budget_ci - > ca . read_attribute_mem = ciintf_read_attribute_mem ;
budget_ci - > ca . write_attribute_mem = ciintf_write_attribute_mem ;
budget_ci - > ca . read_cam_control = ciintf_read_cam_control ;
budget_ci - > ca . write_cam_control = ciintf_write_cam_control ;
budget_ci - > ca . slot_reset = ciintf_slot_reset ;
budget_ci - > ca . slot_shutdown = ciintf_slot_shutdown ;
budget_ci - > ca . slot_ts_enable = ciintf_slot_ts_enable ;
2006-04-05 21:09:45 +04:00
budget_ci - > ca . poll_slot_status = ciintf_poll_slot_status ;
2005-04-17 02:20:36 +04:00
budget_ci - > ca . data = budget_ci ;
2005-05-17 08:54:39 +04:00
if ( ( result = dvb_ca_en50221_init ( & budget_ci - > budget . dvb_adapter ,
2005-04-17 02:20:36 +04:00
& budget_ci - > ca ,
2006-04-05 21:09:45 +04:00
ca_flags , 1 ) ) ! = 0 ) {
2005-04-17 02:20:36 +04:00
printk ( " budget_ci: CI interface detected, but initialisation failed. \n " ) ;
goto error ;
}
2006-04-05 21:09:45 +04:00
2005-04-17 02:20:36 +04:00
// Setup CI slot IRQ
2006-04-05 21:09:45 +04:00
if ( budget_ci - > ci_irq ) {
tasklet_init ( & budget_ci - > ciintf_irq_tasklet , ciintf_interrupt , ( unsigned long ) budget_ci ) ;
if ( budget_ci - > slot_status ! = SLOTSTATUS_NONE ) {
saa7146_setgpio ( saa , 0 , SAA7146_GPIO_IRQLO ) ;
} else {
saa7146_setgpio ( saa , 0 , SAA7146_GPIO_IRQHI ) ;
}
saa7146_write ( saa , IER , saa7146_read ( saa , IER ) | MASK_03 ) ;
2005-04-17 02:20:36 +04:00
}
2006-04-05 21:09:45 +04:00
// enable interface
2005-04-17 02:20:36 +04:00
ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 ,
CICONTROL_RESET , 1 , 0 ) ;
// success!
printk ( " budget_ci: CI interface initialised \n " ) ;
budget_ci - > budget . ci_present = 1 ;
// forge a fake CI IRQ so the CAM state is setup correctly
2006-04-05 21:09:45 +04:00
if ( budget_ci - > ci_irq ) {
flags = DVB_CA_EN50221_CAMCHANGE_REMOVED ;
if ( budget_ci - > slot_status ! = SLOTSTATUS_NONE )
flags = DVB_CA_EN50221_CAMCHANGE_INSERTED ;
dvb_ca_en50221_camchange_irq ( & budget_ci - > ca , 0 , flags ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
error :
saa7146_write ( saa , MC1 , saa7146_read ( saa , MC1 ) | ( 0x800 < < 16 ) ) ;
return result ;
}
static void ciintf_deinit ( struct budget_ci * budget_ci )
{
struct saa7146_dev * saa = budget_ci - > budget . dev ;
// disable CI interrupts
2006-04-05 21:09:45 +04:00
if ( budget_ci - > ci_irq ) {
saa7146_write ( saa , IER , saa7146_read ( saa , IER ) & ~ MASK_03 ) ;
saa7146_setgpio ( saa , 0 , SAA7146_GPIO_INPUT ) ;
tasklet_kill ( & budget_ci - > ciintf_irq_tasklet ) ;
}
// reset interface
2005-04-17 02:20:36 +04:00
ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 , 0 , 1 , 0 ) ;
msleep ( 1 ) ;
ttpci_budget_debiwrite ( & budget_ci - > budget , DEBICICTL , DEBIADDR_CICONTROL , 1 ,
CICONTROL_RESET , 1 , 0 ) ;
// disable TS data stream to CI interface
saa7146_setgpio ( saa , 1 , SAA7146_GPIO_INPUT ) ;
// release the CA device
dvb_ca_en50221_release ( & budget_ci - > ca ) ;
// disable DEBI pins
saa7146_write ( saa , MC1 , saa7146_read ( saa , MC1 ) | ( 0x800 < < 16 ) ) ;
}
static void budget_ci_irq ( struct saa7146_dev * dev , u32 * isr )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) dev - > ext_priv ;
dprintk ( 8 , " dev: %p, budget_ci: %p \n " , dev , budget_ci ) ;
if ( * isr & MASK_06 )
tasklet_schedule ( & budget_ci - > msp430_irq_tasklet ) ;
if ( * isr & MASK_10 )
ttpci_budget_irq10_handler ( dev , isr ) ;
2006-04-05 21:09:45 +04:00
if ( ( * isr & MASK_03 ) & & ( budget_ci - > budget . ci_present ) & & ( budget_ci - > ci_irq ) )
2005-04-17 02:20:36 +04:00
tasklet_schedule ( & budget_ci - > ciintf_irq_tasklet ) ;
}
static u8 philips_su1278_tt_inittab [ ] = {
0x01 , 0x0f ,
0x02 , 0x30 ,
0x03 , 0x00 ,
0x04 , 0x5b ,
0x05 , 0x85 ,
0x06 , 0x02 ,
0x07 , 0x00 ,
0x08 , 0x02 ,
0x09 , 0x00 ,
0x0C , 0x01 ,
0x0D , 0x81 ,
0x0E , 0x44 ,
0x0f , 0x14 ,
0x10 , 0x3c ,
0x11 , 0x84 ,
0x12 , 0xda ,
0x13 , 0x97 ,
0x14 , 0x95 ,
0x15 , 0xc9 ,
0x16 , 0x19 ,
0x17 , 0x8c ,
0x18 , 0x59 ,
0x19 , 0xf8 ,
0x1a , 0xfe ,
0x1c , 0x7f ,
0x1d , 0x00 ,
0x1e , 0x00 ,
0x1f , 0x50 ,
0x20 , 0x00 ,
0x21 , 0x00 ,
0x22 , 0x00 ,
0x23 , 0x00 ,
0x28 , 0x00 ,
0x29 , 0x28 ,
0x2a , 0x14 ,
0x2b , 0x0f ,
0x2c , 0x09 ,
0x2d , 0x09 ,
0x31 , 0x1f ,
0x32 , 0x19 ,
0x33 , 0xfc ,
0x34 , 0x93 ,
0xff , 0xff
} ;
static int philips_su1278_tt_set_symbol_rate ( struct dvb_frontend * fe , u32 srate , u32 ratio )
{
stv0299_writereg ( fe , 0x0e , 0x44 ) ;
if ( srate > = 10000000 ) {
stv0299_writereg ( fe , 0x13 , 0x97 ) ;
stv0299_writereg ( fe , 0x14 , 0x95 ) ;
stv0299_writereg ( fe , 0x15 , 0xc9 ) ;
stv0299_writereg ( fe , 0x17 , 0x8c ) ;
stv0299_writereg ( fe , 0x1a , 0xfe ) ;
stv0299_writereg ( fe , 0x1c , 0x7f ) ;
stv0299_writereg ( fe , 0x2d , 0x09 ) ;
} else {
stv0299_writereg ( fe , 0x13 , 0x99 ) ;
stv0299_writereg ( fe , 0x14 , 0x8d ) ;
stv0299_writereg ( fe , 0x15 , 0xce ) ;
stv0299_writereg ( fe , 0x17 , 0x43 ) ;
stv0299_writereg ( fe , 0x1a , 0x1d ) ;
stv0299_writereg ( fe , 0x1c , 0x12 ) ;
stv0299_writereg ( fe , 0x2d , 0x05 ) ;
}
stv0299_writereg ( fe , 0x0e , 0x23 ) ;
stv0299_writereg ( fe , 0x0f , 0x94 ) ;
stv0299_writereg ( fe , 0x10 , 0x39 ) ;
stv0299_writereg ( fe , 0x15 , 0xc9 ) ;
stv0299_writereg ( fe , 0x1f , ( ratio > > 16 ) & 0xff ) ;
stv0299_writereg ( fe , 0x20 , ( ratio > > 8 ) & 0xff ) ;
stv0299_writereg ( fe , 0x21 , ( ratio ) & 0xf0 ) ;
return 0 ;
}
2006-04-19 00:47:11 +04:00
static int philips_su1278_tt_tuner_set_params ( struct dvb_frontend * fe ,
struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
2006-04-19 00:47:11 +04:00
struct budget_ci * budget_ci = ( struct budget_ci * ) fe - > dvb - > priv ;
2005-04-17 02:20:36 +04:00
u32 div ;
u8 buf [ 4 ] ;
struct i2c_msg msg = { . addr = 0x60 , . flags = 0 , . buf = buf , . len = sizeof ( buf ) } ;
if ( ( params - > frequency < 950000 ) | | ( params - > frequency > 2150000 ) )
return - EINVAL ;
div = ( params - > frequency + ( 500 - 1 ) ) / 500 ; // round correctly
buf [ 0 ] = ( div > > 8 ) & 0x7f ;
buf [ 1 ] = div & 0xff ;
buf [ 2 ] = 0x80 | ( ( div & 0x18000 ) > > 10 ) | 2 ;
buf [ 3 ] = 0x20 ;
if ( params - > u . qpsk . symbol_rate < 4000000 )
buf [ 3 ] | = 1 ;
if ( params - > frequency < 1250000 )
buf [ 3 ] | = 0 ;
else if ( params - > frequency < 1550000 )
buf [ 3 ] | = 0x40 ;
else if ( params - > frequency < 2050000 )
buf [ 3 ] | = 0x80 ;
else if ( params - > frequency < 2150000 )
buf [ 3 ] | = 0xC0 ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2006-04-19 00:47:11 +04:00
if ( i2c_transfer ( & budget_ci - > budget . i2c_adap , & msg , 1 ) ! = 1 )
2005-04-17 02:20:36 +04:00
return - EIO ;
return 0 ;
}
static struct stv0299_config philips_su1278_tt_config = {
. demod_address = 0x68 ,
. inittab = philips_su1278_tt_inittab ,
. mclk = 64000000UL ,
. invert = 0 ,
. skip_reinit = 1 ,
. lock_output = STV0229_LOCKOUTPUT_1 ,
. volt13_op0_op1 = STV0299_VOLT13_OP1 ,
. min_delay_ms = 50 ,
. set_symbol_rate = philips_su1278_tt_set_symbol_rate ,
} ;
2006-04-19 00:47:11 +04:00
static int philips_tdm1316l_tuner_init ( struct dvb_frontend * fe )
2005-04-17 02:20:36 +04:00
{
struct budget_ci * budget_ci = ( struct budget_ci * ) fe - > dvb - > priv ;
static u8 td1316_init [ ] = { 0x0b , 0xf5 , 0x85 , 0xab } ;
static u8 disable_mc44BC374c [ ] = { 0x1d , 0x74 , 0xa0 , 0x68 } ;
2005-07-08 04:57:54 +04:00
struct i2c_msg tuner_msg = { . addr = budget_ci - > tuner_pll_address , . flags = 0 , . buf = td1316_init , . len =
2005-04-17 02:20:36 +04:00
sizeof ( td1316_init ) } ;
// setup PLL configuration
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 ( & budget_ci - > budget . i2c_adap , & tuner_msg , 1 ) ! = 1 )
return - EIO ;
msleep ( 1 ) ;
// disable the mc44BC374c (do not check for errors)
tuner_msg . addr = 0x65 ;
tuner_msg . buf = disable_mc44BC374c ;
tuner_msg . len = sizeof ( disable_mc44BC374c ) ;
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 ( & budget_ci - > budget . i2c_adap , & tuner_msg , 1 ) ! = 1 ) {
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
i2c_transfer ( & budget_ci - > budget . i2c_adap , & tuner_msg , 1 ) ;
}
return 0 ;
}
2006-04-19 00:47:11 +04:00
static int philips_tdm1316l_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-04-17 02:20:36 +04:00
{
struct budget_ci * budget_ci = ( struct budget_ci * ) fe - > dvb - > priv ;
u8 tuner_buf [ 4 ] ;
2005-07-08 04:57:54 +04:00
struct i2c_msg tuner_msg = { . addr = budget_ci - > tuner_pll_address , . flags = 0 , . buf = tuner_buf , . len = sizeof ( tuner_buf ) } ;
2005-04-17 02:20:36 +04:00
int tuner_frequency = 0 ;
u8 band , cp , filter ;
// determine charge pump
tuner_frequency = params - > frequency + 36130000 ;
if ( tuner_frequency < 87000000 )
return - EINVAL ;
else if ( tuner_frequency < 130000000 )
cp = 3 ;
else if ( tuner_frequency < 160000000 )
cp = 5 ;
else if ( tuner_frequency < 200000000 )
cp = 6 ;
else if ( tuner_frequency < 290000000 )
cp = 3 ;
else if ( tuner_frequency < 420000000 )
cp = 5 ;
else if ( tuner_frequency < 480000000 )
cp = 6 ;
else if ( tuner_frequency < 620000000 )
cp = 3 ;
else if ( tuner_frequency < 830000000 )
cp = 5 ;
else if ( tuner_frequency < 895000000 )
cp = 7 ;
else
return - EINVAL ;
// determine band
if ( params - > frequency < 49000000 )
return - EINVAL ;
else if ( params - > frequency < 159000000 )
band = 1 ;
else if ( params - > frequency < 444000000 )
band = 2 ;
else if ( params - > frequency < 861000000 )
band = 4 ;
else
return - EINVAL ;
// setup PLL filter and TDA9889
switch ( params - > u . ofdm . bandwidth ) {
case BANDWIDTH_6_MHZ :
2006-08-08 16:10:08 +04:00
tda1004x_writereg ( fe , 0x0C , 0x14 ) ;
2005-04-17 02:20:36 +04:00
filter = 0 ;
break ;
case BANDWIDTH_7_MHZ :
2006-08-08 16:10:08 +04:00
tda1004x_writereg ( fe , 0x0C , 0x80 ) ;
2005-04-17 02:20:36 +04:00
filter = 0 ;
break ;
case BANDWIDTH_8_MHZ :
2006-08-08 16:10:08 +04:00
tda1004x_writereg ( fe , 0x0C , 0x14 ) ;
2005-04-17 02:20:36 +04:00
filter = 1 ;
break ;
default :
return - EINVAL ;
}
// calculate divisor
// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
tuner_frequency = ( ( ( params - > frequency / 1000 ) * 6 ) + 217280 ) / 1000 ;
// setup tuner buffer
tuner_buf [ 0 ] = tuner_frequency > > 8 ;
tuner_buf [ 1 ] = tuner_frequency & 0xff ;
tuner_buf [ 2 ] = 0xca ;
tuner_buf [ 3 ] = ( cp < < 5 ) | ( filter < < 3 ) | band ;
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 ( & budget_ci - > budget . i2c_adap , & tuner_msg , 1 ) ! = 1 )
return - EIO ;
msleep ( 1 ) ;
return 0 ;
}
static int philips_tdm1316l_request_firmware ( struct dvb_frontend * fe ,
const struct firmware * * fw , char * name )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) fe - > dvb - > priv ;
return request_firmware ( fw , name , & budget_ci - > budget . dev - > pci - > dev ) ;
}
static struct tda1004x_config philips_tdm1316l_config = {
. demod_address = 0x8 ,
. invert = 0 ,
. invert_oclk = 0 ,
2005-07-08 04:57:40 +04:00
. xtal_freq = TDA10046_XTAL_4M ,
. agc_config = TDA10046_AGC_DEFAULT ,
. if_freq = TDA10046_FREQ_3617 ,
2005-04-17 02:20:36 +04:00
. request_firmware = philips_tdm1316l_request_firmware ,
} ;
2006-04-19 00:47:11 +04:00
static int dvbc_philips_tdm1316l_tuner_set_params ( struct dvb_frontend * fe , struct dvb_frontend_parameters * params )
2005-09-10 00:03:07 +04:00
{
struct budget_ci * budget_ci = ( struct budget_ci * ) fe - > dvb - > priv ;
u8 tuner_buf [ 5 ] ;
struct i2c_msg tuner_msg = { . addr = budget_ci - > tuner_pll_address ,
. flags = 0 ,
. buf = tuner_buf ,
. len = sizeof ( tuner_buf ) } ;
int tuner_frequency = 0 ;
u8 band , cp , filter ;
// determine charge pump
tuner_frequency = params - > frequency + 36125000 ;
if ( tuner_frequency < 87000000 )
return - EINVAL ;
else if ( tuner_frequency < 130000000 ) {
cp = 3 ;
band = 1 ;
} else if ( tuner_frequency < 160000000 ) {
cp = 5 ;
band = 1 ;
} else if ( tuner_frequency < 200000000 ) {
cp = 6 ;
band = 1 ;
} else if ( tuner_frequency < 290000000 ) {
cp = 3 ;
band = 2 ;
} else if ( tuner_frequency < 420000000 ) {
cp = 5 ;
band = 2 ;
} else if ( tuner_frequency < 480000000 ) {
cp = 6 ;
band = 2 ;
} else if ( tuner_frequency < 620000000 ) {
cp = 3 ;
band = 4 ;
} else if ( tuner_frequency < 830000000 ) {
cp = 5 ;
band = 4 ;
} else if ( tuner_frequency < 895000000 ) {
cp = 7 ;
band = 4 ;
} else
return - EINVAL ;
// assume PLL filter should always be 8MHz for the moment.
filter = 1 ;
// calculate divisor
tuner_frequency = ( params - > frequency + 36125000 + ( 62500 / 2 ) ) / 62500 ;
// setup tuner buffer
tuner_buf [ 0 ] = tuner_frequency > > 8 ;
tuner_buf [ 1 ] = tuner_frequency & 0xff ;
tuner_buf [ 2 ] = 0xc8 ;
tuner_buf [ 3 ] = ( cp < < 5 ) | ( filter < < 3 ) | band ;
tuner_buf [ 4 ] = 0x80 ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-09-10 00:03:07 +04:00
if ( i2c_transfer ( & budget_ci - > budget . i2c_adap , & tuner_msg , 1 ) ! = 1 )
return - EIO ;
msleep ( 50 ) ;
2006-05-14 12:01:31 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2005-09-10 00:03:07 +04:00
if ( i2c_transfer ( & budget_ci - > budget . i2c_adap , & tuner_msg , 1 ) ! = 1 )
return - EIO ;
msleep ( 1 ) ;
return 0 ;
}
static u8 dvbc_philips_tdm1316l_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 , 0x20 ,
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 , 0x38 ,
0x62 , 0x0a ,
0x53 , 0x13 ,
0x59 , 0x08 ,
0xff , 0xff ,
} ;
static struct stv0297_config dvbc_philips_tdm1316l_config = {
. demod_address = 0x1c ,
. inittab = dvbc_philips_tdm1316l_inittab ,
. invert = 0 ,
2006-04-28 04:45:20 +04:00
. stop_during_read = 1 ,
2005-09-10 00:03:07 +04:00
} ;
2005-04-17 02:20:36 +04:00
static void frontend_init ( struct budget_ci * budget_ci )
{
switch ( budget_ci - > budget . dev - > pci - > subsystem_device ) {
case 0x100c : // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
budget_ci - > budget . dvb_frontend =
stv0299_attach ( & alps_bsru6_config , & budget_ci - > budget . i2c_adap ) ;
if ( budget_ci - > budget . dvb_frontend ) {
2006-05-14 12:01:31 +04:00
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . set_params = alps_bsru6_tuner_set_params ;
2006-04-19 00:47:11 +04:00
budget_ci - > budget . dvb_frontend - > tuner_priv = & budget_ci - > budget . i2c_adap ;
2005-04-17 02:20:36 +04:00
break ;
}
break ;
case 0x100f : // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
budget_ci - > budget . dvb_frontend =
stv0299_attach ( & philips_su1278_tt_config , & budget_ci - > budget . i2c_adap ) ;
if ( budget_ci - > budget . dvb_frontend ) {
2006-05-14 12:01:31 +04:00
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . set_params = philips_su1278_tt_tuner_set_params ;
2005-04-17 02:20:36 +04:00
break ;
}
break ;
2005-09-10 00:03:07 +04:00
case 0x1010 : // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
budget_ci - > tuner_pll_address = 0x61 ;
budget_ci - > budget . dvb_frontend =
stv0297_attach ( & dvbc_philips_tdm1316l_config , & budget_ci - > budget . i2c_adap ) ;
if ( budget_ci - > budget . dvb_frontend ) {
2006-05-14 12:01:31 +04:00
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . set_params = dvbc_philips_tdm1316l_tuner_set_params ;
2005-09-10 00:03:07 +04:00
break ;
}
break ;
2005-04-17 02:20:36 +04:00
case 0x1011 : // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
2005-07-08 04:57:54 +04:00
budget_ci - > tuner_pll_address = 0x63 ;
2005-04-17 02:20:36 +04:00
budget_ci - > budget . dvb_frontend =
tda10045_attach ( & philips_tdm1316l_config , & budget_ci - > budget . i2c_adap ) ;
if ( budget_ci - > budget . dvb_frontend ) {
2006-05-14 12:01:31 +04:00
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . init = philips_tdm1316l_tuner_init ;
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . set_params = philips_tdm1316l_tuner_set_params ;
2005-04-17 02:20:36 +04:00
break ;
}
break ;
2005-07-08 04:57:54 +04:00
2005-09-10 00:03:07 +04:00
case 0x1012 : // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
2005-07-08 04:57:54 +04:00
budget_ci - > tuner_pll_address = 0x60 ;
budget_ci - > budget . dvb_frontend =
tda10046_attach ( & philips_tdm1316l_config , & budget_ci - > budget . i2c_adap ) ;
if ( budget_ci - > budget . dvb_frontend ) {
2006-05-14 12:01:31 +04:00
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . init = philips_tdm1316l_tuner_init ;
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . set_params = philips_tdm1316l_tuner_set_params ;
2005-07-08 04:57:54 +04:00
break ;
}
break ;
2006-02-28 15:52:44 +03:00
case 0x1017 : // TT S-1500 PCI
budget_ci - > budget . dvb_frontend = stv0299_attach ( & alps_bsbe1_config , & budget_ci - > budget . i2c_adap ) ;
if ( budget_ci - > budget . dvb_frontend ) {
2006-05-14 12:01:31 +04:00
budget_ci - > budget . dvb_frontend - > ops . tuner_ops . set_params = alps_bsbe1_tuner_set_params ;
2006-04-19 00:47:11 +04:00
budget_ci - > budget . dvb_frontend - > tuner_priv = & budget_ci - > budget . i2c_adap ;
2006-05-14 12:01:31 +04:00
budget_ci - > budget . dvb_frontend - > ops . dishnetwork_send_legacy_command = NULL ;
2006-08-08 16:10:08 +04:00
if ( lnbp21_attach ( budget_ci - > budget . dvb_frontend , & budget_ci - > budget . i2c_adap , LNBP21_LLC , 0 ) = = NULL ) {
2006-02-28 15:52:44 +03:00
printk ( " %s: No LNBP21 found! \n " , __FUNCTION__ ) ;
2006-05-14 12:01:31 +04:00
if ( budget_ci - > budget . dvb_frontend - > ops . release )
budget_ci - > budget . dvb_frontend - > ops . release ( budget_ci - > budget . dvb_frontend ) ;
2006-02-28 15:52:44 +03:00
budget_ci - > budget . dvb_frontend = NULL ;
}
}
break ;
2005-04-17 02:20:36 +04:00
}
if ( budget_ci - > budget . dvb_frontend = = NULL ) {
printk ( " budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x \n " ,
budget_ci - > budget . dev - > pci - > vendor ,
budget_ci - > budget . dev - > pci - > device ,
budget_ci - > budget . dev - > pci - > subsystem_vendor ,
budget_ci - > budget . dev - > pci - > subsystem_device ) ;
} else {
if ( dvb_register_frontend
2005-05-17 08:54:39 +04:00
( & budget_ci - > budget . dvb_adapter , budget_ci - > budget . dvb_frontend ) ) {
2005-04-17 02:20:36 +04:00
printk ( " budget-ci: Frontend registration failed! \n " ) ;
2006-05-14 12:01:31 +04:00
if ( budget_ci - > budget . dvb_frontend - > ops . release )
budget_ci - > budget . dvb_frontend - > ops . release ( budget_ci - > budget . dvb_frontend ) ;
2005-04-17 02:20:36 +04:00
budget_ci - > budget . dvb_frontend = NULL ;
}
}
}
static int budget_ci_attach ( struct saa7146_dev * dev , struct saa7146_pci_extension_data * info )
{
struct budget_ci * budget_ci ;
int err ;
if ( ! ( budget_ci = kmalloc ( sizeof ( struct budget_ci ) , GFP_KERNEL ) ) )
return - ENOMEM ;
dprintk ( 2 , " budget_ci: %p \n " , budget_ci ) ;
budget_ci - > budget . ci_present = 0 ;
dev - > ext_priv = budget_ci ;
if ( ( err = ttpci_budget_init ( & budget_ci - > budget , dev , info , THIS_MODULE ) ) ) {
kfree ( budget_ci ) ;
return err ;
}
tasklet_init ( & budget_ci - > msp430_irq_tasklet , msp430_ir_interrupt ,
( unsigned long ) budget_ci ) ;
msp430_ir_init ( budget_ci ) ;
ciintf_init ( budget_ci ) ;
2005-05-17 08:54:39 +04:00
budget_ci - > budget . dvb_adapter . priv = budget_ci ;
2005-04-17 02:20:36 +04:00
frontend_init ( budget_ci ) ;
2006-07-19 05:55:23 +04:00
ttpci_budget_init_hooks ( & budget_ci - > budget ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int budget_ci_detach ( struct saa7146_dev * dev )
{
struct budget_ci * budget_ci = ( struct budget_ci * ) dev - > ext_priv ;
struct saa7146_dev * saa = budget_ci - > budget . dev ;
int err ;
if ( budget_ci - > budget . ci_present )
ciintf_deinit ( budget_ci ) ;
if ( budget_ci - > budget . dvb_frontend )
dvb_unregister_frontend ( budget_ci - > budget . dvb_frontend ) ;
err = ttpci_budget_deinit ( & budget_ci - > budget ) ;
tasklet_kill ( & budget_ci - > msp430_irq_tasklet ) ;
msp430_ir_deinit ( budget_ci ) ;
// disable frontend and CI interface
saa7146_setgpio ( saa , 2 , SAA7146_GPIO_INPUT ) ;
kfree ( budget_ci ) ;
return err ;
}
static struct saa7146_extension budget_extension ;
2006-02-28 15:52:44 +03:00
MAKE_BUDGET_INFO ( ttbs2 , " TT-Budget/S-1500 PCI " , BUDGET_TT ) ;
2005-04-17 02:20:36 +04:00
MAKE_BUDGET_INFO ( ttbci , " TT-Budget/WinTV-NOVA-CI PCI " , BUDGET_TT_HW_DISEQC ) ;
MAKE_BUDGET_INFO ( ttbt2 , " TT-Budget/WinTV-NOVA-T PCI " , BUDGET_TT ) ;
2005-07-08 04:57:54 +04:00
MAKE_BUDGET_INFO ( ttbtci , " TT-Budget-T-CI PCI " , BUDGET_TT ) ;
2005-09-10 00:03:07 +04:00
MAKE_BUDGET_INFO ( ttbcci , " TT-Budget-C-CI PCI " , BUDGET_TT ) ;
2005-04-17 02:20:36 +04:00
static struct pci_device_id pci_tbl [ ] = {
MAKE_EXTENSION_PCI ( ttbci , 0x13c2 , 0x100c ) ,
MAKE_EXTENSION_PCI ( ttbci , 0x13c2 , 0x100f ) ,
2005-09-10 00:03:07 +04:00
MAKE_EXTENSION_PCI ( ttbcci , 0x13c2 , 0x1010 ) ,
2005-04-17 02:20:36 +04:00
MAKE_EXTENSION_PCI ( ttbt2 , 0x13c2 , 0x1011 ) ,
2005-07-08 04:57:54 +04:00
MAKE_EXTENSION_PCI ( ttbtci , 0x13c2 , 0x1012 ) ,
2006-02-28 15:52:44 +03:00
MAKE_EXTENSION_PCI ( ttbs2 , 0x13c2 , 0x1017 ) ,
2005-04-17 02:20:36 +04:00
{
. vendor = 0 ,
}
} ;
MODULE_DEVICE_TABLE ( pci , pci_tbl ) ;
static struct saa7146_extension budget_extension = {
. name = " budget_ci dvb \0 " ,
2005-12-01 11:51:48 +03:00
. flags = SAA7146_I2C_SHORT_DELAY ,
2005-04-17 02:20:36 +04:00
. module = THIS_MODULE ,
. pci_tbl = & pci_tbl [ 0 ] ,
. attach = budget_ci_attach ,
. detach = budget_ci_detach ,
. irq_mask = MASK_03 | MASK_06 | MASK_10 ,
. irq_func = budget_ci_irq ,
} ;
static int __init budget_ci_init ( void )
{
return saa7146_register_extension ( & budget_extension ) ;
}
static void __exit budget_ci_exit ( void )
{
saa7146_unregister_extension ( & budget_extension ) ;
}
module_init ( budget_ci_init ) ;
module_exit ( budget_ci_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Michael Hunold, Jack Thomasson, Andrew de Quincey, others " ) ;
MODULE_DESCRIPTION ( " driver for the SAA7146 based so-called "
" budget PCI DVB cards w/ CI-module produced by "
" Siemens, Technotrend, Hauppauge " ) ;