2008-04-18 04:36:41 +04:00
/*
DVB device driver for em28xx
( c ) 2008 Mauro Carvalho Chehab < mchehab @ infradead . org >
2008-04-18 04:38:27 +04:00
( c ) 2008 Devin Heitmueller < devin . heitmueller @ gmail . com >
- Fixes for the driver to properly work with HVR - 950
2008-06-04 20:43:46 +04:00
- Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
2008-07-26 18:04:33 +04:00
- Fixes for the driver to properly work with AMD ATI TV Wonder HD 600
2008-04-18 04:38:27 +04:00
2008-04-18 04:40:36 +04:00
( c ) 2008 Aidan Thornton < makosoft @ googlemail . com >
Based on cx88 - dvb , saa7134 - dvb and videobuf - dvb originally written by :
2008-04-18 04:36:41 +04:00
( c ) 2004 , 2005 Chris Pascoe < c . pascoe @ itee . uq . edu . au >
( c ) 2004 Gerd Knorr < kraxel @ bytesex . org > [ SuSE Labs ]
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 .
*/
# include <linux/kernel.h>
# include <linux/usb.h>
# include "em28xx.h"
# include <media/v4l2-common.h>
# include <media/videobuf-vmalloc.h>
2009-06-07 00:05:02 +04:00
# include <media/tuner.h>
# include "tuner-simple.h"
2008-04-18 04:36:41 +04:00
# include "lgdt330x.h"
2008-04-18 04:40:03 +04:00
# include "zl10353.h"
2009-01-19 03:59:34 +03:00
# include "s5h1409.h"
2009-07-13 00:51:12 +04:00
# include "mt352.h"
# include "mt352_priv.h" /* FIXME */
2008-04-18 04:36:41 +04:00
MODULE_DESCRIPTION ( " driver for em28xx based DVB cards " ) ;
MODULE_AUTHOR ( " Mauro Carvalho Chehab <mchehab@infradead.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
static unsigned int debug ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " enable debug messages [dvb] " ) ;
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
# define dprintk(level, fmt, arg...) do { \
if ( debug > = level ) \
2008-04-18 04:40:36 +04:00
printk ( KERN_DEBUG " %s/2-dvb: " fmt , dev - > name , # # arg ) ; \
2008-04-18 04:36:41 +04:00
} while ( 0 )
2008-04-18 04:40:36 +04:00
# define EM28XX_DVB_NUM_BUFS 5
# define EM28XX_DVB_MAX_PACKETS 64
struct em28xx_dvb {
struct dvb_frontend * frontend ;
/* feed count management */
struct mutex lock ;
int nfeeds ;
/* general boilerplate stuff */
struct dvb_adapter adapter ;
struct dvb_demux demux ;
struct dmxdev dmxdev ;
struct dmx_frontend fe_hw ;
struct dmx_frontend fe_mem ;
struct dvb_net net ;
} ;
static inline void print_err_status ( struct em28xx * dev ,
int packet , int status )
2008-04-18 04:36:41 +04:00
{
2008-04-18 04:40:36 +04:00
char * errmsg = " Unknown " ;
2008-04-18 04:36:41 +04:00
2008-04-18 04:40:36 +04:00
switch ( status ) {
case - ENOENT :
errmsg = " unlinked synchronuously " ;
break ;
case - ECONNRESET :
errmsg = " unlinked asynchronuously " ;
break ;
case - ENOSR :
errmsg = " Buffer error (overrun) " ;
break ;
case - EPIPE :
errmsg = " Stalled (device not responding) " ;
break ;
case - EOVERFLOW :
errmsg = " Babble (bad cable?) " ;
break ;
case - EPROTO :
errmsg = " Bit-stuff error (bad cable?) " ;
break ;
case - EILSEQ :
errmsg = " CRC/Timeout (could be anything) " ;
break ;
case - ETIME :
errmsg = " Device does not respond " ;
break ;
}
if ( packet < 0 ) {
dprintk ( 1 , " URB status %d [%s]. \n " , status , errmsg ) ;
} else {
2008-04-18 04:41:10 +04:00
dprintk ( 1 , " URB packet %d, status %d [%s]. \n " ,
packet , status , errmsg ) ;
2008-04-18 04:40:36 +04:00
}
}
2008-04-18 04:36:41 +04:00
2008-04-18 04:40:36 +04:00
static inline int dvb_isoc_copy ( struct em28xx * dev , struct urb * urb )
{
int i ;
2008-04-18 04:36:41 +04:00
2008-04-18 04:40:36 +04:00
if ( ! dev )
return 0 ;
2008-04-18 04:36:41 +04:00
2008-04-18 04:40:36 +04:00
if ( ( dev - > state & DEV_DISCONNECTED ) | | ( dev - > state & DEV_MISCONFIGURED ) )
return 0 ;
if ( urb - > status < 0 ) {
print_err_status ( dev , - 1 , urb - > status ) ;
if ( urb - > status = = - ENOENT )
return 0 ;
}
for ( i = 0 ; i < urb - > number_of_packets ; i + + ) {
int status = urb - > iso_frame_desc [ i ] . status ;
if ( status < 0 ) {
print_err_status ( dev , i , status ) ;
if ( urb - > iso_frame_desc [ i ] . status ! = - EPROTO )
continue ;
}
dvb_dmx_swfilter ( & dev - > dvb - > demux , urb - > transfer_buffer +
urb - > iso_frame_desc [ i ] . offset ,
urb - > iso_frame_desc [ i ] . actual_length ) ;
}
return 0 ;
}
2008-04-18 04:41:10 +04:00
static int start_streaming ( struct em28xx_dvb * dvb )
{
2008-04-18 04:48:00 +04:00
int rc ;
2008-04-18 04:40:36 +04:00
struct em28xx * dev = dvb - > adapter . priv ;
2009-05-17 00:09:28 +04:00
int max_dvb_packet_size ;
2008-04-18 04:40:36 +04:00
usb_set_interface ( dev - > udev , 0 , 1 ) ;
2008-04-18 04:48:00 +04:00
rc = em28xx_set_mode ( dev , EM28XX_DIGITAL_MODE ) ;
if ( rc < 0 )
return rc ;
2008-04-18 04:40:36 +04:00
2009-05-17 00:09:28 +04:00
max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize ( dev ) ;
2008-04-18 04:40:36 +04:00
return em28xx_init_isoc ( dev , EM28XX_DVB_MAX_PACKETS ,
2009-05-17 00:09:28 +04:00
EM28XX_DVB_NUM_BUFS , max_dvb_packet_size ,
2008-04-18 04:48:00 +04:00
dvb_isoc_copy ) ;
2008-04-18 04:40:36 +04:00
}
2008-04-18 04:41:10 +04:00
static int stop_streaming ( struct em28xx_dvb * dvb )
{
2008-04-18 04:40:36 +04:00
struct em28xx * dev = dvb - > adapter . priv ;
em28xx_uninit_isoc ( dev ) ;
2008-04-18 04:48:00 +04:00
2008-11-27 15:10:40 +03:00
em28xx_set_mode ( dev , EM28XX_SUSPEND ) ;
2008-04-18 04:48:00 +04:00
2008-04-18 04:36:41 +04:00
return 0 ;
}
2008-04-18 04:40:36 +04:00
static int start_feed ( struct dvb_demux_feed * feed )
{
struct dvb_demux * demux = feed - > demux ;
struct em28xx_dvb * dvb = demux - > priv ;
int rc , ret ;
if ( ! demux - > dmx . frontend )
return - EINVAL ;
mutex_lock ( & dvb - > lock ) ;
dvb - > nfeeds + + ;
rc = dvb - > nfeeds ;
if ( dvb - > nfeeds = = 1 ) {
ret = start_streaming ( dvb ) ;
2008-04-18 04:41:10 +04:00
if ( ret < 0 )
rc = ret ;
2008-04-18 04:40:36 +04:00
}
mutex_unlock ( & dvb - > lock ) ;
return rc ;
}
static int stop_feed ( struct dvb_demux_feed * feed )
{
struct dvb_demux * demux = feed - > demux ;
struct em28xx_dvb * dvb = demux - > priv ;
int err = 0 ;
mutex_lock ( & dvb - > lock ) ;
dvb - > nfeeds - - ;
2008-04-18 04:41:10 +04:00
if ( 0 = = dvb - > nfeeds )
2008-04-18 04:40:36 +04:00
err = stop_streaming ( dvb ) ;
2008-04-18 04:41:10 +04:00
2008-04-18 04:40:36 +04:00
mutex_unlock ( & dvb - > lock ) ;
return err ;
}
2008-04-18 04:49:20 +04:00
/* ------------------------------------------------------------------ */
static int em28xx_dvb_bus_ctrl ( struct dvb_frontend * fe , int acquire )
{
struct em28xx * dev = fe - > dvb - > priv ;
if ( acquire )
return em28xx_set_mode ( dev , EM28XX_DIGITAL_MODE ) ;
else
2008-11-27 15:10:40 +03:00
return em28xx_set_mode ( dev , EM28XX_SUSPEND ) ;
2008-04-18 04:49:20 +04:00
}
2008-04-18 04:36:41 +04:00
/* ------------------------------------------------------------------ */
2008-04-18 04:37:40 +04:00
static struct lgdt330x_config em2880_lgdt3303_dev = {
. demod_address = 0x0e ,
. demod_chip = LGDT3303 ,
} ;
2008-04-18 04:36:41 +04:00
2008-04-18 04:40:03 +04:00
static struct zl10353_config em28xx_zl10353_with_xc3028 = {
. demod_address = ( 0x1e > > 1 ) ,
. no_tuner = 1 ,
. parallel_ts = 1 ,
. if2 = 45600 ,
} ;
2009-01-19 03:59:34 +03:00
static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
. demod_address = 0x32 > > 1 ,
. output_mode = S5H1409_PARALLEL_OUTPUT ,
. gpio = S5H1409_GPIO_OFF ,
. inversion = S5H1409_INVERSION_OFF ,
. status_mode = S5H1409_DEMODLOCKING ,
. mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
} ;
2009-06-23 05:32:32 +04:00
static struct zl10353_config em28xx_terratec_xs_zl10353_xc3028 = {
. demod_address = ( 0x1e > > 1 ) ,
. no_tuner = 1 ,
. disable_i2c_gate_ctrl = 1 ,
. parallel_ts = 1 ,
. if2 = 45600 ,
} ;
2008-06-08 17:22:03 +04:00
# ifdef EM28XX_DRX397XD_SUPPORT
/* [TODO] djh - not sure yet what the device config needs to contain */
static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
. demod_address = ( 0xe0 > > 1 ) ,
} ;
# endif
2009-07-13 00:51:12 +04:00
static int mt352_terratec_xs_init ( struct dvb_frontend * fe )
{
/* Values extracted from a USB trace of the Terratec Windows driver */
static u8 clock_config [ ] = { CLOCK_CTL , 0x38 , 0x2c } ;
static u8 reset [ ] = { RESET , 0x80 } ;
static u8 adc_ctl_1_cfg [ ] = { ADC_CTL_1 , 0x40 } ;
static u8 agc_cfg [ ] = { AGC_TARGET , 0x28 , 0xa0 } ;
static u8 input_freq_cfg [ ] = { INPUT_FREQ_1 , 0x31 , 0xb8 } ;
static u8 rs_err_cfg [ ] = { RS_ERR_PER_1 , 0x00 , 0x4d } ;
static u8 capt_range_cfg [ ] = { CAPT_RANGE , 0x32 } ;
static u8 trl_nom_cfg [ ] = { TRL_NOMINAL_RATE_1 , 0x64 , 0x00 } ;
static u8 tps_given_cfg [ ] = { TPS_GIVEN_1 , 0x40 , 0x80 , 0x50 } ;
2009-07-13 01:44:19 +04:00
static u8 tuner_go [ ] = { TUNER_GO , 0x01 } ;
2009-07-13 00:51:12 +04:00
mt352_write ( fe , clock_config , sizeof ( clock_config ) ) ;
udelay ( 200 ) ;
mt352_write ( fe , reset , sizeof ( reset ) ) ;
mt352_write ( fe , adc_ctl_1_cfg , sizeof ( adc_ctl_1_cfg ) ) ;
mt352_write ( fe , agc_cfg , sizeof ( agc_cfg ) ) ;
mt352_write ( fe , input_freq_cfg , sizeof ( input_freq_cfg ) ) ;
mt352_write ( fe , rs_err_cfg , sizeof ( rs_err_cfg ) ) ;
mt352_write ( fe , capt_range_cfg , sizeof ( capt_range_cfg ) ) ;
mt352_write ( fe , trl_nom_cfg , sizeof ( trl_nom_cfg ) ) ;
mt352_write ( fe , tps_given_cfg , sizeof ( tps_given_cfg ) ) ;
mt352_write ( fe , tuner_go , sizeof ( tuner_go ) ) ;
return 0 ;
}
static struct mt352_config terratec_xs_mt352_cfg = {
. demod_address = ( 0x1e > > 1 ) ,
. no_tuner = 1 ,
. if2 = 45600 ,
. demod_init = mt352_terratec_xs_init ,
} ;
2008-04-18 04:36:41 +04:00
/* ------------------------------------------------------------------ */
static int attach_xc3028 ( u8 addr , struct em28xx * dev )
{
struct dvb_frontend * fe ;
2008-04-18 04:37:53 +04:00
struct xc2028_config cfg ;
2008-04-18 04:41:10 +04:00
memset ( & cfg , 0 , sizeof ( cfg ) ) ;
2008-04-18 04:37:53 +04:00
cfg . i2c_adap = & dev - > i2c_adap ;
cfg . i2c_addr = addr ;
2008-04-18 04:40:36 +04:00
if ( ! dev - > dvb - > frontend ) {
2008-04-18 04:36:41 +04:00
printk ( KERN_ERR " %s/2: dvb frontend not attached. "
" Can't attach xc3028 \n " ,
dev - > name ) ;
return - EINVAL ;
}
2008-04-18 04:40:36 +04:00
fe = dvb_attach ( xc2028_attach , dev - > dvb - > frontend , & cfg ) ;
2008-04-18 04:36:41 +04:00
if ( ! fe ) {
printk ( KERN_ERR " %s/2: xc3028 attach failed \n " ,
dev - > name ) ;
2008-04-18 04:40:36 +04:00
dvb_frontend_detach ( dev - > dvb - > frontend ) ;
dev - > dvb - > frontend = NULL ;
2008-04-18 04:36:41 +04:00
return - EINVAL ;
}
printk ( KERN_INFO " %s/2: xc3028 attached \n " , dev - > name ) ;
return 0 ;
}
2008-04-18 04:40:36 +04:00
/* ------------------------------------------------------------------ */
2008-09-04 10:33:43 +04:00
static int register_dvb ( struct em28xx_dvb * dvb ,
2008-04-18 04:40:36 +04:00
struct module * module ,
struct em28xx * dev ,
struct device * device )
2008-04-18 04:36:41 +04:00
{
2008-04-18 04:40:36 +04:00
int result ;
2008-04-18 04:36:41 +04:00
2008-04-18 04:40:36 +04:00
mutex_init ( & dvb - > lock ) ;
2008-04-18 04:36:41 +04:00
2008-04-18 04:40:36 +04:00
/* register adapter */
result = dvb_register_adapter ( & dvb - > adapter , dev - > name , module , device ,
adapter_nr ) ;
if ( result < 0 ) {
printk ( KERN_WARNING " %s: dvb_register_adapter failed (errno = %d) \n " ,
dev - > name , result ) ;
goto fail_adapter ;
}
2008-04-18 04:49:20 +04:00
/* Ensure all frontends negotiate bus access */
dvb - > frontend - > ops . ts_bus_ctrl = em28xx_dvb_bus_ctrl ;
2008-04-18 04:40:36 +04:00
dvb - > adapter . priv = dev ;
/* register frontend */
result = dvb_register_frontend ( & dvb - > adapter , dvb - > frontend ) ;
if ( result < 0 ) {
printk ( KERN_WARNING " %s: dvb_register_frontend failed (errno = %d) \n " ,
dev - > name , result ) ;
goto fail_frontend ;
}
/* register demux stuff */
dvb - > demux . dmx . capabilities =
DMX_TS_FILTERING | DMX_SECTION_FILTERING |
DMX_MEMORY_BASED_FILTERING ;
dvb - > demux . priv = dvb ;
dvb - > demux . filternum = 256 ;
dvb - > demux . feednum = 256 ;
dvb - > demux . start_feed = start_feed ;
dvb - > demux . stop_feed = stop_feed ;
2008-04-18 04:49:20 +04:00
2008-04-18 04:40:36 +04:00
result = dvb_dmx_init ( & dvb - > demux ) ;
if ( result < 0 ) {
printk ( KERN_WARNING " %s: dvb_dmx_init failed (errno = %d) \n " ,
dev - > name , result ) ;
goto fail_dmx ;
}
dvb - > dmxdev . filternum = 256 ;
dvb - > dmxdev . demux = & dvb - > demux . dmx ;
dvb - > dmxdev . capabilities = 0 ;
result = dvb_dmxdev_init ( & dvb - > dmxdev , & dvb - > adapter ) ;
if ( result < 0 ) {
printk ( KERN_WARNING " %s: dvb_dmxdev_init failed (errno = %d) \n " ,
dev - > name , result ) ;
goto fail_dmxdev ;
}
2008-04-18 04:38:38 +04:00
2008-04-18 04:40:36 +04:00
dvb - > fe_hw . source = DMX_FRONTEND_0 ;
result = dvb - > demux . dmx . add_frontend ( & dvb - > demux . dmx , & dvb - > fe_hw ) ;
if ( result < 0 ) {
printk ( KERN_WARNING " %s: add_frontend failed (DMX_FRONTEND_0, errno = %d) \n " ,
dev - > name , result ) ;
goto fail_fe_hw ;
}
dvb - > fe_mem . source = DMX_MEMORY_FE ;
result = dvb - > demux . dmx . add_frontend ( & dvb - > demux . dmx , & dvb - > fe_mem ) ;
if ( result < 0 ) {
printk ( KERN_WARNING " %s: add_frontend failed (DMX_MEMORY_FE, errno = %d) \n " ,
dev - > name , result ) ;
goto fail_fe_mem ;
}
result = dvb - > demux . dmx . connect_frontend ( & dvb - > demux . dmx , & dvb - > fe_hw ) ;
if ( result < 0 ) {
printk ( KERN_WARNING " %s: connect_frontend failed (errno = %d) \n " ,
dev - > name , result ) ;
goto fail_fe_conn ;
}
/* register network adapter */
dvb_net_init ( & dvb - > adapter , & dvb - > net , & dvb - > demux . dmx ) ;
return 0 ;
fail_fe_conn :
dvb - > demux . dmx . remove_frontend ( & dvb - > demux . dmx , & dvb - > fe_mem ) ;
fail_fe_mem :
dvb - > demux . dmx . remove_frontend ( & dvb - > demux . dmx , & dvb - > fe_hw ) ;
fail_fe_hw :
dvb_dmxdev_release ( & dvb - > dmxdev ) ;
fail_dmxdev :
dvb_dmx_release ( & dvb - > demux ) ;
fail_dmx :
dvb_unregister_frontend ( dvb - > frontend ) ;
fail_frontend :
dvb_frontend_detach ( dvb - > frontend ) ;
dvb_unregister_adapter ( & dvb - > adapter ) ;
fail_adapter :
return result ;
}
static void unregister_dvb ( struct em28xx_dvb * dvb )
{
dvb_net_release ( & dvb - > net ) ;
dvb - > demux . dmx . remove_frontend ( & dvb - > demux . dmx , & dvb - > fe_mem ) ;
dvb - > demux . dmx . remove_frontend ( & dvb - > demux . dmx , & dvb - > fe_hw ) ;
dvb_dmxdev_release ( & dvb - > dmxdev ) ;
dvb_dmx_release ( & dvb - > demux ) ;
dvb_unregister_frontend ( dvb - > frontend ) ;
dvb_frontend_detach ( dvb - > frontend ) ;
dvb_unregister_adapter ( & dvb - > adapter ) ;
}
static int dvb_init ( struct em28xx * dev )
{
int result = 0 ;
struct em28xx_dvb * dvb ;
2008-11-25 15:39:50 +03:00
if ( ! dev - > board . has_dvb ) {
2008-06-10 19:34:35 +04:00
/* This device does not support the extension */
return 0 ;
}
2008-04-18 04:40:36 +04:00
dvb = kzalloc ( sizeof ( struct em28xx_dvb ) , GFP_KERNEL ) ;
2008-04-18 04:41:10 +04:00
if ( dvb = = NULL ) {
printk ( KERN_INFO " em28xx_dvb: memory allocation failed \n " ) ;
2008-04-18 04:40:36 +04:00
return - ENOMEM ;
}
dev - > dvb = dvb ;
2008-04-18 04:36:41 +04:00
2008-04-18 04:48:00 +04:00
em28xx_set_mode ( dev , EM28XX_DIGITAL_MODE ) ;
2008-04-18 04:36:41 +04:00
/* init frontend */
switch ( dev - > model ) {
2008-12-02 03:01:04 +03:00
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 :
2008-07-27 21:58:58 +04:00
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 :
2008-06-04 20:43:46 +04:00
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO :
2008-07-26 18:04:33 +04:00
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 :
2008-04-18 04:40:36 +04:00
dvb - > frontend = dvb_attach ( lgdt330x_attach ,
& em2880_lgdt3303_dev ,
& dev - > i2c_adap ) ;
if ( attach_xc3028 ( 0x61 , dev ) < 0 ) {
result = - EINVAL ;
goto out_free ;
}
2008-04-18 04:37:40 +04:00
break ;
2008-04-18 04:40:03 +04:00
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 :
2008-10-11 23:56:13 +04:00
case EM2880_BOARD_KWORLD_DVB_310U :
2009-04-10 01:24:34 +04:00
case EM2880_BOARD_EMPIRE_DUAL_TV :
2008-04-18 04:40:36 +04:00
dvb - > frontend = dvb_attach ( zl10353_attach ,
& em28xx_zl10353_with_xc3028 ,
& dev - > i2c_adap ) ;
if ( attach_xc3028 ( 0x61 , dev ) < 0 ) {
result = - EINVAL ;
goto out_free ;
}
2008-04-18 04:40:03 +04:00
break ;
2009-06-23 05:32:32 +04:00
case EM2880_BOARD_TERRATEC_HYBRID_XS :
dvb - > frontend = dvb_attach ( zl10353_attach ,
& em28xx_terratec_xs_zl10353_xc3028 ,
& dev - > i2c_adap ) ;
if ( dvb - > frontend = = NULL ) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn ' t for zl10353 , try mt352 */
2009-07-13 00:51:12 +04:00
dvb - > frontend = dvb_attach ( mt352_attach ,
& terratec_xs_mt352_cfg ,
& dev - > i2c_adap ) ;
2009-06-23 05:32:32 +04:00
}
2009-07-13 00:51:12 +04:00
2009-06-23 05:32:32 +04:00
if ( attach_xc3028 ( 0x61 , dev ) < 0 ) {
result = - EINVAL ;
goto out_free ;
}
break ;
2009-01-19 03:59:34 +03:00
case EM2883_BOARD_KWORLD_HYBRID_330U :
2009-06-19 07:33:54 +04:00
case EM2882_BOARD_EVGA_INDTUBE :
2009-01-19 03:59:34 +03:00
dvb - > frontend = dvb_attach ( s5h1409_attach ,
& em28xx_s5h1409_with_xc3028 ,
& dev - > i2c_adap ) ;
if ( attach_xc3028 ( 0x61 , dev ) < 0 ) {
result = - EINVAL ;
goto out_free ;
}
break ;
2009-06-07 00:05:02 +04:00
case EM2882_BOARD_KWORLD_ATSC_315U :
dvb - > frontend = dvb_attach ( lgdt330x_attach ,
& em2880_lgdt3303_dev ,
& dev - > i2c_adap ) ;
if ( dvb - > frontend ! = NULL ) {
if ( ! dvb_attach ( simple_tuner_attach , dvb - > frontend ,
& dev - > i2c_adap , 0x61 , TUNER_THOMSON_DTT761X ) ) {
result = - EINVAL ;
goto out_free ;
}
}
break ;
2008-06-08 17:22:03 +04:00
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 :
# ifdef EM28XX_DRX397XD_SUPPORT
/* We don't have the config structure properly populated, so
this is commented out for now */
dvb - > frontend = dvb_attach ( drx397xD_attach ,
& em28xx_drx397xD_with_xc3028 ,
& dev - > i2c_adap ) ;
if ( attach_xc3028 ( 0x61 , dev ) < 0 ) {
result = - EINVAL ;
goto out_free ;
}
break ;
# endif
2008-04-18 04:36:41 +04:00
default :
printk ( KERN_ERR " %s/2: The frontend of your DVB/ATSC card "
" isn't supported yet \n " ,
dev - > name ) ;
break ;
}
2008-04-18 04:40:36 +04:00
if ( NULL = = dvb - > frontend ) {
2008-04-18 04:36:41 +04:00
printk ( KERN_ERR
" %s/2: frontend initialization failed \n " ,
dev - > name ) ;
2008-04-18 04:40:36 +04:00
result = - EINVAL ;
goto out_free ;
2008-04-18 04:36:41 +04:00
}
2008-09-12 20:31:45 +04:00
/* define general-purpose callback pointer */
dvb - > frontend - > callback = em28xx_tuner_callback ;
2008-04-18 04:36:41 +04:00
/* register everything */
2008-04-18 04:40:36 +04:00
result = register_dvb ( dvb , THIS_MODULE , dev , & dev - > udev - > dev ) ;
2008-04-18 04:41:10 +04:00
if ( result < 0 )
2008-04-18 04:40:36 +04:00
goto out_free ;
2008-11-27 15:10:40 +03:00
em28xx_set_mode ( dev , EM28XX_SUSPEND ) ;
2008-04-18 04:40:45 +04:00
printk ( KERN_INFO " Successfully loaded em28xx-dvb \n " ) ;
2008-04-18 04:40:36 +04:00
return 0 ;
out_free :
2008-11-27 15:10:40 +03:00
em28xx_set_mode ( dev , EM28XX_SUSPEND ) ;
2008-04-18 04:40:36 +04:00
kfree ( dvb ) ;
dev - > dvb = NULL ;
return result ;
2008-04-18 04:36:41 +04:00
}
static int dvb_fini ( struct em28xx * dev )
{
2008-11-25 15:39:50 +03:00
if ( ! dev - > board . has_dvb ) {
2008-06-10 19:34:35 +04:00
/* This device does not support the extension */
return 0 ;
}
2008-04-18 04:40:36 +04:00
if ( dev - > dvb ) {
unregister_dvb ( dev - > dvb ) ;
dev - > dvb = NULL ;
}
2008-04-18 04:36:41 +04:00
return 0 ;
}
static struct em28xx_ops dvb_ops = {
. id = EM28XX_DVB ,
. name = " Em28xx dvb Extension " ,
. init = dvb_init ,
. fini = dvb_fini ,
} ;
static int __init em28xx_dvb_register ( void )
{
return em28xx_register_extension ( & dvb_ops ) ;
}
static void __exit em28xx_dvb_unregister ( void )
{
em28xx_unregister_extension ( & dvb_ops ) ;
}
module_init ( em28xx_dvb_register ) ;
module_exit ( em28xx_dvb_unregister ) ;