2007-08-21 17:37:22 -03:00
/*
2010-10-20 06:35:54 -03:00
* tm6000 - dvb . c - dvb - t support for TM5600 / TM6000 / TM6010 USB video capture devices
*
* Copyright ( C ) 2007 Michel Ludwig < michel . ludwig @ gmail . com >
*
* 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 version 2
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2007-08-21 17:37:22 -03:00
*/
2010-02-05 20:06:52 -03:00
# include <linux/kernel.h>
2010-03-30 02:52:33 +09:00
# include <linux/slab.h>
2007-08-21 17:37:22 -03:00
# include <linux/usb.h>
# include "tm6000.h"
# include "tm6000-regs.h"
# include "zl10353.h"
# include <media/tuner.h>
2007-11-16 13:16:59 -03:00
# include "tuner-xc2028.h"
2010-05-23 15:31:44 -03:00
# include "xc5000.h"
2007-11-16 13:16:59 -03:00
2010-05-30 09:19:04 -03:00
MODULE_DESCRIPTION ( " DVB driver extension module for tm5600/6000/6010 based TV cards " ) ;
MODULE_AUTHOR ( " Mauro Carvalho Chehab <mchehab@redhat.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_SUPPORTED_DEVICE ( " {{Trident, tm5600}, "
" {{Trident, tm6000}, "
" {{Trident, tm6010} " ) ;
static int debug ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " enable debug message " ) ;
2010-05-29 13:52:46 -03:00
static inline void print_err_status ( struct tm6000_core * dev ,
int packet , int status )
2010-02-05 20:06:52 -03:00
{
char * errmsg = " Unknown " ;
2010-05-29 13:52:46 -03:00
switch ( status ) {
2010-02-05 20:06:52 -03:00
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 ;
}
2010-05-29 13:52:46 -03:00
if ( packet < 0 ) {
2010-02-05 20:06:52 -03:00
dprintk ( dev , 1 , " URB status %d [%s]. \n " ,
status , errmsg ) ;
} else {
dprintk ( dev , 1 , " URB packet %d, status %d [%s]. \n " ,
packet , status , errmsg ) ;
}
}
2007-08-21 17:37:22 -03:00
static void tm6000_urb_received ( struct urb * urb )
{
int ret ;
2010-05-29 13:52:46 -03:00
struct tm6000_core * dev = urb - > context ;
2007-08-21 17:37:22 -03:00
2011-11-28 15:46:19 -03:00
switch ( urb - > status ) {
case 0 :
case - ETIMEDOUT :
break ;
case - ENOENT :
case - ECONNRESET :
case - ESHUTDOWN :
return ;
default :
2010-05-29 13:52:46 -03:00
print_err_status ( dev , 0 , urb - > status ) ;
2011-11-28 15:46:19 -03:00
}
if ( urb - > actual_length > 0 )
2007-08-21 17:37:22 -03:00
dvb_dmx_swfilter ( & dev - > dvb - > demux , urb - > transfer_buffer ,
urb - > actual_length ) ;
2010-05-29 13:52:46 -03:00
if ( dev - > dvb - > streams > 0 ) {
2007-08-21 17:37:22 -03:00
ret = usb_submit_urb ( urb , GFP_ATOMIC ) ;
2010-05-29 13:52:46 -03:00
if ( ret < 0 ) {
2011-06-02 20:33:31 -04:00
printk ( KERN_ERR " tm6000: error %s \n " , __func__ ) ;
2007-08-21 17:37:22 -03:00
kfree ( urb - > transfer_buffer ) ;
usb_free_urb ( urb ) ;
}
}
}
2011-08-04 04:14:01 -03:00
static int tm6000_start_stream ( struct tm6000_core * dev )
2007-08-21 17:37:22 -03:00
{
int ret ;
2010-02-05 20:06:52 -03:00
unsigned int pipe , size ;
2007-08-21 17:37:22 -03:00
struct tm6000_dvb * dvb = dev - > dvb ;
2011-06-02 20:33:31 -04:00
printk ( KERN_INFO " tm6000: got start stream request %s \n " , __func__ ) ;
2007-08-21 17:37:22 -03:00
2010-05-23 15:29:26 -03:00
if ( dev - > mode ! = TM6000_MODE_DIGITAL ) {
tm6000_init_digital_mode ( dev ) ;
dev - > mode = TM6000_MODE_DIGITAL ;
}
2007-08-21 17:37:22 -03:00
dvb - > bulk_urb = usb_alloc_urb ( 0 , GFP_KERNEL ) ;
2010-05-29 13:52:46 -03:00
if ( dvb - > bulk_urb = = NULL ) {
2007-08-21 17:37:22 -03:00
printk ( KERN_ERR " tm6000: couldn't allocate urb \n " ) ;
return - ENOMEM ;
}
2010-04-26 11:24:18 -03:00
pipe = usb_rcvbulkpipe ( dev - > udev , dev - > bulk_in . endp - > desc . bEndpointAddress
2010-02-05 20:06:52 -03:00
& USB_ENDPOINT_NUMBER_MASK ) ;
size = usb_maxpacket ( dev - > udev , pipe , usb_pipeout ( pipe ) ) ;
size = size * 15 ; /* 512 x 8 or 12 or 15 */
2007-08-21 17:37:22 -03:00
2010-02-05 20:06:52 -03:00
dvb - > bulk_urb - > transfer_buffer = kzalloc ( size , GFP_KERNEL ) ;
2010-05-29 13:52:46 -03:00
if ( dvb - > bulk_urb - > transfer_buffer = = NULL ) {
2007-08-21 17:37:22 -03:00
usb_free_urb ( dvb - > bulk_urb ) ;
printk ( KERN_ERR " tm6000: couldn't allocate transfer buffer! \n " ) ;
return - ENOMEM ;
}
usb_fill_bulk_urb ( dvb - > bulk_urb , dev - > udev , pipe ,
dvb - > bulk_urb - > transfer_buffer ,
2010-02-05 20:06:52 -03:00
size ,
2007-08-21 17:37:22 -03:00
tm6000_urb_received , dev ) ;
2007-09-24 17:01:49 -03:00
2007-08-21 17:37:22 -03:00
ret = usb_clear_halt ( dev - > udev , pipe ) ;
2010-05-29 13:52:46 -03:00
if ( ret < 0 ) {
printk ( KERN_ERR " tm6000: error %i in %s during pipe reset \n " ,
2011-06-02 20:33:31 -04:00
ret , __func__ ) ;
2007-09-24 17:01:49 -03:00
return ret ;
2010-05-29 13:52:46 -03:00
} else
2007-08-21 17:37:22 -03:00
printk ( KERN_ERR " tm6000: pipe resetted \n " ) ;
2010-02-05 20:06:52 -03:00
/* mutex_lock(&tm6000_driver.open_close_mutex); */
2011-11-28 15:46:19 -03:00
ret = usb_submit_urb ( dvb - > bulk_urb , GFP_ATOMIC ) ;
2007-08-21 17:37:22 -03:00
2010-02-05 20:06:52 -03:00
/* mutex_unlock(&tm6000_driver.open_close_mutex); */
2007-08-21 17:37:22 -03:00
if ( ret ) {
2010-05-29 13:52:46 -03:00
printk ( KERN_ERR " tm6000: submit of urb failed (error=%i) \n " ,
ret ) ;
2007-08-21 17:37:22 -03:00
kfree ( dvb - > bulk_urb - > transfer_buffer ) ;
usb_free_urb ( dvb - > bulk_urb ) ;
return ret ;
}
return 0 ;
}
2011-08-04 04:14:01 -03:00
static void tm6000_stop_stream ( struct tm6000_core * dev )
2007-08-21 17:37:22 -03:00
{
struct tm6000_dvb * dvb = dev - > dvb ;
2010-05-29 13:52:46 -03:00
if ( dvb - > bulk_urb ) {
printk ( KERN_INFO " urb killing \n " ) ;
2007-08-21 17:37:22 -03:00
usb_kill_urb ( dvb - > bulk_urb ) ;
2010-05-29 13:52:46 -03:00
printk ( KERN_INFO " urb buffer free \n " ) ;
2007-08-21 17:37:22 -03:00
kfree ( dvb - > bulk_urb - > transfer_buffer ) ;
usb_free_urb ( dvb - > bulk_urb ) ;
dvb - > bulk_urb = NULL ;
}
}
2011-08-04 04:14:01 -03:00
static int tm6000_start_feed ( struct dvb_demux_feed * feed )
2007-08-21 17:37:22 -03:00
{
struct dvb_demux * demux = feed - > demux ;
struct tm6000_core * dev = demux - > priv ;
struct tm6000_dvb * dvb = dev - > dvb ;
2011-06-02 20:33:31 -04:00
printk ( KERN_INFO " tm6000: got start feed request %s \n " , __func__ ) ;
2007-08-21 17:37:22 -03:00
mutex_lock ( & dvb - > mutex ) ;
2010-05-29 13:52:46 -03:00
if ( dvb - > streams = = 0 ) {
2007-08-21 17:37:22 -03:00
dvb - > streams = 1 ;
2010-02-05 20:06:52 -03:00
/* mutex_init(&tm6000_dev->streming_mutex); */
2007-08-21 17:37:22 -03:00
tm6000_start_stream ( dev ) ;
2010-05-29 13:52:46 -03:00
} else
2007-08-21 17:37:22 -03:00
+ + ( dvb - > streams ) ;
mutex_unlock ( & dvb - > mutex ) ;
return 0 ;
}
2011-08-04 04:14:01 -03:00
static int tm6000_stop_feed ( struct dvb_demux_feed * feed )
2010-05-29 13:52:46 -03:00
{
2007-08-21 17:37:22 -03:00
struct dvb_demux * demux = feed - > demux ;
struct tm6000_core * dev = demux - > priv ;
struct tm6000_dvb * dvb = dev - > dvb ;
2011-06-02 20:33:31 -04:00
printk ( KERN_INFO " tm6000: got stop feed request %s \n " , __func__ ) ;
2007-08-21 17:37:22 -03:00
mutex_lock ( & dvb - > mutex ) ;
2010-05-29 13:52:46 -03:00
printk ( KERN_INFO " stream %#x \n " , dvb - > streams ) ;
2010-02-05 20:06:52 -03:00
- - ( dvb - > streams ) ;
2010-05-29 13:52:46 -03:00
if ( dvb - > streams = = 0 ) {
printk ( KERN_INFO " stop stream \n " ) ;
2007-08-21 17:37:22 -03:00
tm6000_stop_stream ( dev ) ;
2010-02-05 20:06:52 -03:00
/* mutex_destroy(&tm6000_dev->streaming_mutex); */
2007-08-21 17:37:22 -03:00
}
mutex_unlock ( & dvb - > mutex ) ;
2010-02-05 20:06:52 -03:00
/* mutex_destroy(&tm6000_dev->streaming_mutex); */
2007-08-21 17:37:22 -03:00
return 0 ;
}
2011-08-04 04:14:01 -03:00
static int tm6000_dvb_attach_frontend ( struct tm6000_core * dev )
2007-08-21 17:37:22 -03:00
{
struct tm6000_dvb * dvb = dev - > dvb ;
2010-05-29 13:52:46 -03:00
if ( dev - > caps . has_zl10353 ) {
struct zl10353_config config = {
. demod_address = dev - > demod_addr ,
2007-08-21 17:37:22 -03:00
. no_tuner = 1 ,
2010-02-05 20:06:52 -03:00
. parallel_ts = 1 ,
. if2 = 45700 ,
. disable_i2c_gate_ctrl = 1 ,
2007-08-21 17:37:22 -03:00
} ;
2010-02-15 14:37:23 -03:00
dvb - > frontend = dvb_attach ( zl10353_attach , & config ,
2007-08-21 17:37:22 -03:00
& dev - > i2c_adap ) ;
2010-05-29 13:52:46 -03:00
} else {
2007-08-21 17:37:22 -03:00
printk ( KERN_ERR " tm6000: no frontend defined for the device! \n " ) ;
return - 1 ;
}
2007-11-19 06:10:54 -03:00
return ( ! dvb - > frontend ) ? - 1 : 0 ;
2007-08-21 17:37:22 -03:00
}
2008-04-28 19:20:26 -03:00
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2011-08-04 04:14:01 -03:00
static int register_dvb ( struct tm6000_core * dev )
2007-08-21 17:37:22 -03:00
{
int ret = - 1 ;
struct tm6000_dvb * dvb = dev - > dvb ;
mutex_init ( & dvb - > mutex ) ;
dvb - > streams = 0 ;
/* attach the frontend */
ret = tm6000_dvb_attach_frontend ( dev ) ;
2010-05-29 13:52:46 -03:00
if ( ret < 0 ) {
2007-08-21 17:37:22 -03:00
printk ( KERN_ERR " tm6000: couldn't attach the frontend! \n " ) ;
2007-11-19 06:10:54 -03:00
goto err ;
2007-08-21 17:37:22 -03:00
}
ret = dvb_register_adapter ( & dvb - > adapter , " Trident TVMaster 6000 DVB-T " ,
2010-05-29 13:52:46 -03:00
THIS_MODULE , & dev - > udev - > dev , adapter_nr ) ;
2007-08-21 17:37:22 -03:00
dvb - > adapter . priv = dev ;
2007-11-16 13:16:59 -03:00
if ( dvb - > frontend ) {
2010-05-23 15:31:44 -03:00
switch ( dev - > tuner_type ) {
case TUNER_XC2028 : {
struct xc2028_config cfg = {
. i2c_adap = & dev - > i2c_adap ,
. i2c_addr = dev - > tuner_addr ,
} ;
dvb - > frontend - > callback = tm6000_tuner_callback ;
ret = dvb_register_frontend ( & dvb - > adapter , dvb - > frontend ) ;
if ( ret < 0 ) {
printk ( KERN_ERR
" tm6000: couldn't register frontend \n " ) ;
goto adapter_err ;
}
if ( ! dvb_attach ( xc2028_attach , dvb - > frontend , & cfg ) ) {
printk ( KERN_ERR " tm6000: couldn't register "
" frontend (xc3028) \n " ) ;
ret = - EINVAL ;
goto frontend_err ;
}
printk ( KERN_INFO " tm6000: XC2028/3028 asked to be "
" attached to frontend! \n " ) ;
break ;
}
case TUNER_XC5000 : {
struct xc5000_config cfg = {
. i2c_address = dev - > tuner_addr ,
} ;
dvb - > frontend - > callback = tm6000_xc5000_callback ;
ret = dvb_register_frontend ( & dvb - > adapter , dvb - > frontend ) ;
if ( ret < 0 ) {
printk ( KERN_ERR
" tm6000: couldn't register frontend \n " ) ;
goto adapter_err ;
}
if ( ! dvb_attach ( xc5000_attach , dvb - > frontend , & dev - > i2c_adap , & cfg ) ) {
printk ( KERN_ERR " tm6000: couldn't register "
" frontend (xc5000) \n " ) ;
ret = - EINVAL ;
goto frontend_err ;
}
printk ( KERN_INFO " tm6000: XC5000 asked to be "
" attached to frontend! \n " ) ;
break ;
}
2007-08-21 17:37:22 -03:00
}
2010-05-29 13:52:46 -03:00
} else
2007-11-16 13:16:59 -03:00
printk ( KERN_ERR " tm6000: no frontend found \n " ) ;
2007-08-21 17:37:22 -03:00
dvb - > demux . dmx . capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING
| DMX_MEMORY_BASED_FILTERING ;
dvb - > demux . priv = dev ;
2010-02-15 14:37:19 -03:00
dvb - > demux . filternum = 8 ;
dvb - > demux . feednum = 8 ;
2007-08-21 17:37:22 -03:00
dvb - > demux . start_feed = tm6000_start_feed ;
dvb - > demux . stop_feed = tm6000_stop_feed ;
dvb - > demux . write_to_decoder = NULL ;
ret = dvb_dmx_init ( & dvb - > demux ) ;
2010-05-29 13:52:46 -03:00
if ( ret < 0 ) {
2011-09-23 09:26:22 -03:00
printk ( KERN_ERR " tm6000: dvb_dmx_init failed (errno = %d) \n " , ret ) ;
2007-08-21 17:37:22 -03:00
goto frontend_err ;
}
dvb - > dmxdev . filternum = dev - > dvb - > demux . filternum ;
dvb - > dmxdev . demux = & dev - > dvb - > demux . dmx ;
dvb - > dmxdev . capabilities = 0 ;
ret = dvb_dmxdev_init ( & dvb - > dmxdev , & dvb - > adapter ) ;
2010-05-29 13:52:46 -03:00
if ( ret < 0 ) {
2011-09-23 09:26:22 -03:00
printk ( KERN_ERR " tm6000: dvb_dmxdev_init failed (errno = %d) \n " , ret ) ;
2007-08-21 17:37:22 -03:00
goto dvb_dmx_err ;
}
return 0 ;
dvb_dmx_err :
dvb_dmx_release ( & dvb - > demux ) ;
frontend_err :
2010-05-29 13:52:46 -03:00
if ( dvb - > frontend ) {
2007-11-19 06:10:54 -03:00
dvb_frontend_detach ( dvb - > frontend ) ;
2007-08-21 17:37:22 -03:00
dvb_unregister_frontend ( dvb - > frontend ) ;
}
adapter_err :
dvb_unregister_adapter ( & dvb - > adapter ) ;
err :
return ret ;
}
2011-08-04 04:14:01 -03:00
static void unregister_dvb ( struct tm6000_core * dev )
2007-08-21 17:37:22 -03:00
{
struct tm6000_dvb * dvb = dev - > dvb ;
2010-05-29 13:52:46 -03:00
if ( dvb - > bulk_urb ! = NULL ) {
2007-08-21 17:37:22 -03:00
struct urb * bulk_urb = dvb - > bulk_urb ;
kfree ( bulk_urb - > transfer_buffer ) ;
bulk_urb - > transfer_buffer = NULL ;
usb_unlink_urb ( bulk_urb ) ;
usb_free_urb ( bulk_urb ) ;
}
2010-02-05 20:06:52 -03:00
/* mutex_lock(&tm6000_driver.open_close_mutex); */
2010-05-29 13:52:46 -03:00
if ( dvb - > frontend ) {
2007-11-19 06:10:54 -03:00
dvb_frontend_detach ( dvb - > frontend ) ;
2007-08-21 17:37:22 -03:00
dvb_unregister_frontend ( dvb - > frontend ) ;
}
dvb_dmxdev_release ( & dvb - > dmxdev ) ;
dvb_dmx_release ( & dvb - > demux ) ;
dvb_unregister_adapter ( & dvb - > adapter ) ;
mutex_destroy ( & dvb - > mutex ) ;
2010-02-05 20:06:52 -03:00
/* mutex_unlock(&tm6000_driver.open_close_mutex); */
2007-08-21 17:37:22 -03:00
}
2010-05-30 09:19:04 -03:00
static int dvb_init ( struct tm6000_core * dev )
{
struct tm6000_dvb * dvb ;
int rc ;
if ( ! dev )
return 0 ;
if ( ! dev - > caps . has_dvb )
return 0 ;
2011-12-16 15:34:12 -03:00
if ( dev - > udev - > speed = = USB_SPEED_FULL ) {
printk ( KERN_INFO " This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter) \n " ) ;
return 0 ;
}
2010-05-30 09:19:04 -03:00
dvb = kzalloc ( sizeof ( struct tm6000_dvb ) , GFP_KERNEL ) ;
if ( ! dvb ) {
printk ( KERN_INFO " Cannot allocate memory \n " ) ;
return - ENOMEM ;
}
dev - > dvb = dvb ;
rc = register_dvb ( dev ) ;
if ( rc < 0 ) {
kfree ( dvb ) ;
dev - > dvb = NULL ;
return 0 ;
}
return 0 ;
}
static int dvb_fini ( struct tm6000_core * dev )
{
if ( ! dev )
return 0 ;
if ( ! dev - > caps . has_dvb )
return 0 ;
if ( dev - > dvb ) {
unregister_dvb ( dev ) ;
kfree ( dev - > dvb ) ;
dev - > dvb = NULL ;
}
return 0 ;
}
static struct tm6000_ops dvb_ops = {
2010-06-03 16:31:20 -03:00
. type = TM6000_DVB ,
2010-05-30 09:19:04 -03:00
. name = " TM6000 dvb Extension " ,
. init = dvb_init ,
. fini = dvb_fini ,
} ;
static int __init tm6000_dvb_register ( void )
{
return tm6000_register_extension ( & dvb_ops ) ;
}
static void __exit tm6000_dvb_unregister ( void )
{
tm6000_unregister_extension ( & dvb_ops ) ;
}
module_init ( tm6000_dvb_register ) ;
module_exit ( tm6000_dvb_unregister ) ;