2019-11-04 19:12:52 +01:00
// SPDX-License-Identifier: GPL-2.0
2015-08-05 17:22:42 +02:00
/*
* ddbridge - core . c : Digital Devices bridge core functions
*
2019-11-04 19:12:52 +01:00
* Copyright ( C ) 2010 - 2017 Digital Devices GmbH
2015-08-05 17:22:42 +02:00
* Marcus Metzler < mocm @ metzlerbros . de >
* Ralph Metzler < rjkm @ metzlerbros . de >
2016-03-24 12:10:20 +01:00
*
2015-08-05 17:22:42 +02:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 only , as published by the Free Software Foundation .
*
*
* 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
2019-11-04 19:12:52 +01:00
* along with this program . If not , see < https : //www.gnu.org/licenses/>.
2015-08-05 17:22:42 +02:00
*/
2017-08-02 17:40:24 +02:00
# include "ddbridge.h"
2017-08-02 20:22:52 +02:00
# include "ddbridge-i2c.h"
# include "ddbridge-io.h"
2021-03-18 12:39:41 +01:00
# include "ddbridge-ioctl.h"
2020-08-29 15:32:42 +02:00
# include <media/dvb_net.h>
2017-08-02 17:40:24 +02:00
struct workqueue_struct * ddb_wq ;
2015-08-05 17:22:42 +02:00
2017-12-11 16:20:24 +01:00
static DEFINE_MUTEX ( redirect_lock ) ; /* lock for redirect */
2017-07-24 01:03:40 +02:00
static int adapter_alloc ;
module_param ( adapter_alloc , int , 0444 ) ;
MODULE_PARM_DESC ( adapter_alloc ,
" 0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all " ) ;
2016-09-05 14:25:05 +02:00
static int ci_bitrate = 70000 ;
2015-08-05 17:22:42 +02:00
module_param ( ci_bitrate , int , 0444 ) ;
2016-06-27 23:01:21 +02:00
MODULE_PARM_DESC ( ci_bitrate , " Bitrate in KHz for output to CI. " ) ;
2015-08-05 17:22:42 +02:00
static int ts_loop = - 1 ;
module_param ( ts_loop , int , 0444 ) ;
MODULE_PARM_DESC ( ts_loop , " TS in/out test loop on port ts_loop " ) ;
2017-10-23 21:07:28 +02:00
static int dummy_tuner ;
module_param ( dummy_tuner , int , 0444 ) ;
MODULE_PARM_DESC ( dummy_tuner ,
" attach dummy tuner to port 0 of supported cards " ) ;
2015-08-05 17:22:42 +02:00
static int vlan ;
module_param ( vlan , int , 0444 ) ;
MODULE_PARM_DESC ( vlan , " VLAN and QoS IDs enabled " ) ;
2016-04-12 12:18:09 +02:00
static int xo2_speed = 2 ;
module_param ( xo2_speed , int , 0444 ) ;
MODULE_PARM_DESC ( xo2_speed , " default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards " ) ;
2020-08-29 14:57:02 +02:00
static int raw_stream ;
module_param ( raw_stream , int , 0444 ) ;
MODULE_PARM_DESC ( raw_stream , " send data as raw stream to DVB layer " ) ;
2016-05-02 16:27:32 +02:00
# ifdef __arm__
2016-04-15 22:45:55 +02:00
static int alt_dma = 1 ;
# else
static int alt_dma ;
# endif
2016-04-15 18:08:51 +02:00
module_param ( alt_dma , int , 0444 ) ;
MODULE_PARM_DESC ( alt_dma , " use alternative DMA buffer handling " ) ;
2016-04-15 22:45:55 +02:00
static int no_init ;
module_param ( no_init , int , 0444 ) ;
MODULE_PARM_DESC ( no_init , " do not initialize most devices " ) ;
2016-12-30 15:03:38 +01:00
static int stv0910_single ;
module_param ( stv0910_single , int , 0444 ) ;
2017-10-23 00:14:39 +02:00
MODULE_PARM_DESC ( stv0910_single , " use stv0910 cards as single demods " ) ;
static int dma_buf_num = 8 ;
module_param ( dma_buf_num , int , 0444 ) ;
MODULE_PARM_DESC ( dma_buf_num , " dma buffer number, possible values: 8-32 " ) ;
static int dma_buf_size = 21 ;
module_param ( dma_buf_size , int , 0444 ) ;
MODULE_PARM_DESC ( dma_buf_size ,
" dma buffer size as multiple of 128*47, possible values: 1-43 " ) ;
2016-12-30 15:03:38 +01:00
2015-08-05 17:22:42 +02:00
# define DDB_MAX_ADAPTER 64
static struct ddb * ddbs [ DDB_MAX_ADAPTER ] ;
DVB_DEFINE_MOD_OPT_ADAPTER_NR ( adapter_nr ) ;
2016-05-02 16:27:32 +02:00
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
2017-10-25 23:03:16 +02:00
struct ddb_irq * ddb_irq_set ( struct ddb * dev , u32 link , u32 nr ,
void ( * handler ) ( void * ) , void * data )
{
2017-12-11 16:12:23 +01:00
struct ddb_irq * irq = & dev - > link [ link ] . irq [ nr ] ;
2017-10-25 23:03:16 +02:00
irq - > handler = handler ;
irq - > data = data ;
return irq ;
}
2020-08-29 15:32:42 +02:00
EXPORT_SYMBOL ( ddb_irq_set ) ;
2017-10-25 23:03:16 +02:00
2016-05-02 16:27:32 +02:00
static void ddb_set_dma_table ( struct ddb_io * io )
2015-08-05 17:22:42 +02:00
{
2016-05-02 16:27:32 +02:00
struct ddb * dev = io - > port - > dev ;
struct ddb_dma * dma = io - > dma ;
u32 i ;
2015-08-05 17:22:42 +02:00
u64 mem ;
if ( ! dma )
return ;
for ( i = 0 ; i < dma - > num ; i + + ) {
mem = dma - > pbuf [ i ] ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , mem & 0xffffffff , dma - > bufregs + i * 8 ) ;
ddbwritel ( dev , mem > > 32 , dma - > bufregs + i * 8 + 4 ) ;
2015-08-05 17:22:42 +02:00
}
2017-02-21 17:12:35 +01:00
dma - > bufval = ( ( dma - > div & 0x0f ) < < 16 ) |
2015-08-05 17:22:42 +02:00
( ( dma - > num & 0x1f ) < < 11 ) |
( ( dma - > size > > 7 ) & 0x7ff ) ;
}
static void ddb_set_dma_tables ( struct ddb * dev )
{
u32 i ;
2017-04-16 21:20:52 +02:00
2016-05-02 16:27:32 +02:00
for ( i = 0 ; i < DDB_MAX_PORT ; i + + ) {
if ( dev - > port [ i ] . input [ 0 ] )
ddb_set_dma_table ( dev - > port [ i ] . input [ 0 ] ) ;
if ( dev - > port [ i ] . input [ 1 ] )
ddb_set_dma_table ( dev - > port [ i ] . input [ 1 ] ) ;
if ( dev - > port [ i ] . output )
ddb_set_dma_table ( dev - > port [ i ] . output ) ;
2017-04-16 21:20:52 +02:00
}
2015-08-05 17:22:42 +02:00
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void ddb_redirect_dma ( struct ddb * dev ,
struct ddb_dma * sdma ,
struct ddb_dma * ddma )
{
u32 i , base ;
u64 mem ;
2016-04-20 16:27:56 +02:00
sdma - > bufval = ddma - > bufval ;
2016-05-02 16:27:32 +02:00
base = sdma - > bufregs ;
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < ddma - > num ; i + + ) {
mem = ddma - > pbuf [ i ] ;
ddbwritel ( dev , mem & 0xffffffff , base + i * 8 ) ;
ddbwritel ( dev , mem > > 32 , base + i * 8 + 4 ) ;
}
}
static int ddb_unredirect ( struct ddb_port * port )
{
2017-12-11 16:20:24 +01:00
struct ddb_input * oredi , * iredi = NULL ;
struct ddb_output * iredo = NULL ;
2015-08-05 17:22:42 +02:00
mutex_lock ( & redirect_lock ) ;
if ( port - > output - > dma - > running ) {
mutex_unlock ( & redirect_lock ) ;
return - EBUSY ;
}
oredi = port - > output - > redi ;
if ( ! oredi )
goto done ;
if ( port - > input [ 0 ] ) {
iredi = port - > input [ 0 ] - > redi ;
iredo = port - > input [ 0 ] - > redo ;
if ( iredo ) {
iredo - > port - > output - > redi = oredi ;
if ( iredo - > port - > input [ 0 ] ) {
iredo - > port - > input [ 0 ] - > redi = iredi ;
ddb_redirect_dma ( oredi - > port - > dev ,
oredi - > dma , iredo - > dma ) ;
}
2017-12-11 16:20:24 +01:00
port - > input [ 0 ] - > redo = NULL ;
2016-05-02 16:27:32 +02:00
ddb_set_dma_table ( port - > input [ 0 ] ) ;
2015-08-05 17:22:42 +02:00
}
oredi - > redi = iredi ;
2017-12-11 16:20:24 +01:00
port - > input [ 0 ] - > redi = NULL ;
2015-08-05 17:22:42 +02:00
}
2017-12-11 16:20:24 +01:00
oredi - > redo = NULL ;
port - > output - > redi = NULL ;
2015-08-05 17:22:42 +02:00
2016-05-02 16:27:32 +02:00
ddb_set_dma_table ( oredi ) ;
2015-08-05 17:22:42 +02:00
done :
mutex_unlock ( & redirect_lock ) ;
return 0 ;
}
static int ddb_redirect ( u32 i , u32 p )
{
2016-05-31 16:53:04 +02:00
struct ddb * idev = ddbs [ ( i > > 4 ) & 0x3f ] ;
2015-08-05 17:22:42 +02:00
struct ddb_input * input , * input2 ;
2016-05-31 16:53:04 +02:00
struct ddb * pdev = ddbs [ ( p > > 4 ) & 0x3f ] ;
2015-08-05 17:22:42 +02:00
struct ddb_port * port ;
2017-07-11 20:20:39 +02:00
if ( ! pdev | | ! idev )
2015-08-05 17:22:42 +02:00
return - EINVAL ;
2017-07-11 20:20:39 +02:00
if ( ! pdev - > has_dma | | ! idev - > has_dma )
2015-08-05 17:22:42 +02:00
return - EINVAL ;
port = & pdev - > port [ p & 0x0f ] ;
if ( ! port - > output )
return - EINVAL ;
if ( ddb_unredirect ( port ) )
return - EBUSY ;
if ( i = = 8 )
return 0 ;
input = & idev - > input [ i & 7 ] ;
if ( ! input )
return - EINVAL ;
mutex_lock ( & redirect_lock ) ;
if ( port - > output - > dma - > running | | input - > dma - > running ) {
mutex_unlock ( & redirect_lock ) ;
return - EBUSY ;
}
input2 = port - > input [ 0 ] ;
if ( input2 ) {
if ( input - > redi ) {
input2 - > redi = input - > redi ;
2017-12-11 16:20:24 +01:00
input - > redi = NULL ;
2017-08-26 22:04:37 +02:00
} else {
2015-08-05 17:22:42 +02:00
input2 - > redi = input ;
2017-08-26 22:04:37 +02:00
}
2015-08-05 17:22:42 +02:00
}
input - > redo = port - > output ;
port - > output - > redi = input ;
ddb_redirect_dma ( input - > port - > dev , input - > dma , port - > output - > dma ) ;
mutex_unlock ( & redirect_lock ) ;
return 0 ;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void dma_free ( struct pci_dev * pdev , struct ddb_dma * dma , int dir )
{
int i ;
if ( ! dma )
return ;
for ( i = 0 ; i < dma - > num ; i + + ) {
if ( dma - > vbuf [ i ] ) {
2016-04-15 18:08:51 +02:00
if ( alt_dma ) {
dma_unmap_single ( & pdev - > dev , dma - > pbuf [ i ] ,
dma - > size ,
dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE ) ;
kfree ( dma - > vbuf [ i ] ) ;
2017-08-26 22:04:37 +02:00
} else {
2016-04-15 18:08:51 +02:00
dma_free_coherent ( & pdev - > dev , dma - > size ,
dma - > vbuf [ i ] ,
dma - > pbuf [ i ] ) ;
2017-08-26 22:04:37 +02:00
}
2015-08-05 17:22:42 +02:00
dma - > vbuf [ i ] = 0 ;
}
}
}
static int dma_alloc ( struct pci_dev * pdev , struct ddb_dma * dma , int dir )
{
int i ;
if ( ! dma )
return 0 ;
for ( i = 0 ; i < dma - > num ; i + + ) {
2016-04-15 18:08:51 +02:00
if ( alt_dma ) {
2017-09-25 19:20:17 +02:00
# if (KERNEL_VERSION(4, 13, 0) > LINUX_VERSION_CODE)
2021-03-01 12:57:20 +01:00
dma - > vbuf [ i ] = kzalloc ( dma - > size , __GFP_REPEAT ) ;
2017-08-24 23:48:14 +02:00
# else
2021-03-01 12:57:20 +01:00
dma - > vbuf [ i ] = kzalloc ( dma - > size , __GFP_RETRY_MAYFAIL ) ;
2017-08-24 23:48:14 +02:00
# endif
2016-04-15 18:08:51 +02:00
if ( ! dma - > vbuf [ i ] )
return - ENOMEM ;
dma - > pbuf [ i ] = dma_map_single ( & pdev - > dev ,
dma - > vbuf [ i ] ,
dma - > size ,
dir ? DMA_TO_DEVICE :
DMA_FROM_DEVICE ) ;
if ( dma_mapping_error ( & pdev - > dev , dma - > pbuf [ i ] ) ) {
kfree ( dma - > vbuf [ i ] ) ;
2016-04-15 23:53:20 +02:00
dma - > vbuf [ i ] = 0 ;
2016-04-15 18:08:51 +02:00
return - ENOMEM ;
}
} else {
dma - > vbuf [ i ] = dma_alloc_coherent ( & pdev - > dev ,
dma - > size ,
& dma - > pbuf [ i ] ,
2021-03-01 12:57:20 +01:00
GFP_KERNEL | __GFP_ZERO ) ;
2016-04-15 18:08:51 +02:00
if ( ! dma - > vbuf [ i ] )
return - ENOMEM ;
}
2021-03-01 12:57:45 +01:00
if ( ( ( u64 ) dma - > vbuf [ i ] & 0xfff ) )
dev_err ( & pdev - > dev , " DMA memory at %px not aligned! \n " , dma - > vbuf [ i ] ) ;
2015-08-05 17:22:42 +02:00
}
return 0 ;
}
static int ddb_buffers_alloc ( struct ddb * dev )
{
int i ;
struct ddb_port * port ;
2016-05-05 00:15:02 +02:00
for ( i = 0 ; i < dev - > port_num ; i + + ) {
2015-08-05 17:22:42 +02:00
port = & dev - > port [ i ] ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
if ( port - > input [ 0 ] - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > input [ 0 ] - > dma , 0 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
if ( port - > input [ 1 ] - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > input [ 1 ] - > dma , 0 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
break ;
case DDB_PORT_CI :
case DDB_PORT_LOOP :
if ( port - > input [ 0 ] - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > input [ 0 ] - > dma , 0 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
2020-01-15 12:32:34 +01:00
/* fallthrough */
2015-08-05 17:22:42 +02:00
case DDB_PORT_MOD :
if ( port - > output - > dma )
2016-03-24 12:10:20 +01:00
if ( dma_alloc ( dev - > pdev ,
port - > output - > dma , 1 ) < 0 )
2015-08-05 17:22:42 +02:00
return - 1 ;
break ;
default :
break ;
}
}
ddb_set_dma_tables ( dev ) ;
return 0 ;
}
2017-08-02 17:40:24 +02:00
void ddb_buffers_free ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i ;
struct ddb_port * port ;
2016-05-05 00:15:02 +02:00
for ( i = 0 ; i < dev - > port_num ; i + + ) {
2015-08-05 17:22:42 +02:00
port = & dev - > port [ i ] ;
if ( port - > input [ 0 ] & & port - > input [ 0 ] - > dma )
dma_free ( dev - > pdev , port - > input [ 0 ] - > dma , 0 ) ;
if ( port - > input [ 1 ] & & port - > input [ 1 ] - > dma )
dma_free ( dev - > pdev , port - > input [ 1 ] - > dma , 0 ) ;
if ( port - > output & & port - > output - > dma )
dma_free ( dev - > pdev , port - > output - > dma , 1 ) ;
}
}
2016-10-24 15:13:26 +02:00
/*
2017-04-16 21:20:52 +02:00
* Control :
*
* Bit 0 - Enable TS
* 1 - Reset
* 2 - clock enable
* 3 - clock phase
* 4 - gap enable
* 5 - send null packets on underrun
* 6 - enable clock gating
* 7 - set error bit on inserted null packets
* 8 - 10 - fine adjust clock delay
* 11 - HS ( high speed ) , if NCO mode = 0 : 0 = 72 MHz 1 = 96 Mhz
* 12 - enable NCO mode
*
* Control 2 :
*
* Bit 0 - 6 : gap_size , Gap = ( gap_size * 2 ) + 4
* 16 - 31 : HS = 0 : Speed = 72 * Value / 8192 MBit / s
* HS = 1 : Speed = 72 * 8 / ( Value + 1 ) MBit / s ( only bit 19 - 16 used )
*
*/
2016-10-24 15:13:26 +02:00
2016-06-27 23:01:21 +02:00
static void calc_con ( struct ddb_output * output , u32 * con , u32 * con2 , u32 flags )
2016-06-16 15:40:24 +02:00
{
struct ddb * dev = output - > port - > dev ;
2016-06-27 23:01:21 +02:00
u32 bitrate = output - > port - > obr , max_bitrate = 72000 ;
u32 gap = 4 , nco = 0 ;
2017-04-16 21:20:52 +02:00
* con = 0x1C ;
2016-06-27 23:01:21 +02:00
if ( output - > port - > gap ! = 0xffffffff ) {
flags | = 1 ;
gap = output - > port - > gap ;
2017-06-12 13:52:33 +02:00
max_bitrate = 0 ;
2016-06-27 23:01:21 +02:00
}
2016-06-16 15:40:24 +02:00
if ( dev - > link [ 0 ] . info - > type = = DDB_OCTOPUS_CI & & output - > port - > nr > 1 ) {
2016-06-27 23:01:21 +02:00
* con = 0x10c ;
if ( dev - > link [ 0 ] . ids . regmapid > = 0x10003 & & ! ( flags & 1 ) ) {
if ( ! ( flags & 2 ) ) {
/* NCO */
max_bitrate = 0 ;
2016-06-16 15:40:24 +02:00
gap = 0 ;
2016-06-27 23:01:21 +02:00
if ( bitrate ! = 72000 ) {
2017-08-26 22:04:37 +02:00
if ( bitrate > = 96000 ) {
2016-06-27 23:01:21 +02:00
* con | = 0x800 ;
2017-08-26 22:04:37 +02:00
} else {
2016-06-27 23:01:21 +02:00
* con | = 0x1000 ;
2017-04-16 21:20:52 +02:00
nco = ( bitrate *
8192 + 71999 ) / 72000 ;
2016-06-27 23:01:21 +02:00
}
2016-06-16 15:40:24 +02:00
}
} else {
2016-06-27 23:01:21 +02:00
/* Divider and gap */
* con | = 0x1810 ;
2016-06-16 15:40:24 +02:00
if ( bitrate < = 64000 ) {
2016-06-27 23:01:21 +02:00
max_bitrate = 64000 ;
nco = 8 ;
2017-04-16 21:20:52 +02:00
} else if ( bitrate < = 72000 ) {
2016-06-27 23:01:21 +02:00
max_bitrate = 72000 ;
nco = 7 ;
2016-06-16 15:40:24 +02:00
} else {
2016-06-27 23:01:21 +02:00
max_bitrate = 96000 ;
nco = 5 ;
2016-06-16 15:40:24 +02:00
}
}
} else {
if ( bitrate > 72000 ) {
2016-06-27 23:01:21 +02:00
* con | = 0x810 ; /* 96 MBit/s and gap */
max_bitrate = 96000 ;
2016-06-16 15:40:24 +02:00
}
2017-07-27 21:56:39 +02:00
* con | = 0x10 ; /* enable gap */
2016-06-16 15:40:24 +02:00
}
}
2016-06-27 23:01:21 +02:00
if ( max_bitrate > 0 ) {
if ( bitrate > max_bitrate )
bitrate = max_bitrate ;
2016-06-16 15:40:24 +02:00
if ( bitrate < 31000 )
bitrate = 31000 ;
2016-06-27 23:01:21 +02:00
gap = ( ( max_bitrate - bitrate ) * 94 ) / bitrate ;
2016-06-16 15:40:24 +02:00
if ( gap < 2 )
2016-06-27 23:01:21 +02:00
* con & = ~ 0x10 ; /* Disable gap */
2016-06-16 15:40:24 +02:00
else
gap - = 2 ;
if ( gap > 127 )
gap = 127 ;
}
2016-06-27 23:01:21 +02:00
* con2 = ( nco < < 16 ) | gap ;
2016-06-16 15:40:24 +02:00
}
2022-01-14 12:43:50 +01:00
static int ddb_output_start_unlocked ( struct ddb_output * output )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = output - > port - > dev ;
2016-06-27 23:01:21 +02:00
u32 con = 0x11c , con2 = 0 ;
2022-01-14 12:43:50 +01:00
int err = 0 ;
2015-08-05 17:22:42 +02:00
if ( output - > dma ) {
output - > dma - > cbuf = 0 ;
output - > dma - > coff = 0 ;
output - > dma - > stat = 0 ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
2017-08-26 22:04:37 +02:00
if ( output - > port - > class = = DDB_PORT_MOD ) {
2022-01-14 12:43:50 +01:00
err = ddbridge_mod_output_start ( output ) ;
2017-08-26 22:04:37 +02:00
} else {
2016-06-27 23:01:21 +02:00
if ( output - > port - > input [ 0 ] - > port - > class = = DDB_PORT_LOOP )
con = ( 1UL < < 13 ) | 0x14 ;
else
calc_con ( output , & con , & con2 , 0 ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , TS_CONTROL ( output ) ) ;
ddbwritel ( dev , 2 , TS_CONTROL ( output ) ) ;
ddbwritel ( dev , 0 , TS_CONTROL ( output ) ) ;
2016-06-27 23:01:21 +02:00
ddbwritel ( dev , con , TS_CONTROL ( output ) ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , con2 , TS_CONTROL2 ( output ) ) ;
2015-08-05 17:22:42 +02:00
}
if ( output - > dma ) {
2016-04-20 16:27:56 +02:00
ddbwritel ( dev , output - > dma - > bufval ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_SIZE ( output - > dma ) ) ;
ddbwritel ( dev , 0 , DMA_BUFFER_ACK ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 1 , DMA_BASE_READ ) ;
2017-05-04 09:09:34 +02:00
ddbwritel ( dev , 7 , DMA_BUFFER_CONTROL ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
2016-06-27 23:01:21 +02:00
if ( output - > port - > class ! = DDB_PORT_MOD )
ddbwritel ( dev , con | 1 , TS_CONTROL ( output ) ) ;
2020-08-29 15:32:42 +02:00
if ( output - > dma )
2015-08-05 17:22:42 +02:00
output - > dma - > running = 1 ;
2022-01-14 12:43:50 +01:00
return err ;
2018-05-28 16:41:11 +02:00
}
2022-01-14 12:43:50 +01:00
static int ddb_output_start ( struct ddb_output * output )
2018-05-28 16:41:11 +02:00
{
2022-01-14 12:43:50 +01:00
int err ;
2018-05-28 16:41:11 +02:00
if ( output - > dma ) {
spin_lock_irq ( & output - > dma - > lock ) ;
2022-01-14 12:43:50 +01:00
err = ddb_output_start_unlocked ( output ) ;
2015-08-05 17:22:42 +02:00
spin_unlock_irq ( & output - > dma - > lock ) ;
2018-05-28 16:41:11 +02:00
} else {
2022-01-14 12:43:50 +01:00
err = ddb_output_start_unlocked ( output ) ;
2015-08-05 17:22:42 +02:00
}
2022-01-14 12:43:50 +01:00
return err ;
2015-08-05 17:22:42 +02:00
}
2018-05-28 16:41:11 +02:00
static void ddb_output_stop_unlocked ( struct ddb_output * output )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = output - > port - > dev ;
if ( output - > port - > class = = DDB_PORT_MOD )
ddbridge_mod_output_stop ( output ) ;
else
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , TS_CONTROL ( output ) ) ;
2015-08-05 17:22:42 +02:00
if ( output - > dma ) {
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
output - > dma - > running = 0 ;
2018-05-28 16:41:11 +02:00
}
}
static void ddb_output_stop ( struct ddb_output * output )
{
if ( output - > dma ) {
spin_lock_irq ( & output - > dma - > lock ) ;
ddb_output_stop_unlocked ( output ) ;
2015-08-05 17:22:42 +02:00
spin_unlock_irq ( & output - > dma - > lock ) ;
2018-05-28 16:41:11 +02:00
} else {
ddb_output_stop_unlocked ( output ) ;
2015-08-05 17:22:42 +02:00
}
}
2021-02-24 20:24:14 +01:00
static void update_loss ( struct ddb_dma * dma )
{
struct ddb_input * input = ( struct ddb_input * ) dma - > io ;
u32 packet_loss = dma - > packet_loss ;
u32 cur_counter = ddbreadl ( input - > port - > dev , TS_STAT ( input ) ) & 0xffff ;
if ( cur_counter < ( packet_loss & 0xffff ) )
packet_loss + = 0x10000 ;
packet_loss = ( ( packet_loss & 0xffff0000 ) | cur_counter ) ;
dma - > packet_loss = packet_loss ;
}
2018-05-28 16:41:11 +02:00
static void ddb_input_stop_unlocked ( struct ddb_input * input )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = input - > port - > dev ;
u32 tag = DDB_LINK_TAG ( input - > port - > lnr ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , tag | TS_CONTROL ( input ) ) ;
2015-08-05 17:22:42 +02:00
if ( input - > dma ) {
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
input - > dma - > running = 0 ;
2020-03-31 16:43:18 +02:00
if ( input - > dma - > stall_count )
dev_warn ( input - > port - > dev - > dev ,
" DMA stalled %u times! \n " ,
input - > dma - > stall_count ) ;
2021-02-24 20:25:27 +01:00
update_loss ( input - > dma ) ;
if ( input - > dma - > packet_loss > 1 )
2020-03-31 16:43:18 +02:00
dev_warn ( input - > port - > dev - > dev ,
" %u packets lost due to low DMA performance! \n " ,
input - > dma - > packet_loss ) ;
2015-08-05 17:22:42 +02:00
}
}
2018-05-28 16:41:11 +02:00
static void ddb_input_stop ( struct ddb_input * input )
{
if ( input - > dma ) {
spin_lock_irq ( & input - > dma - > lock ) ;
ddb_input_stop_unlocked ( input ) ;
spin_unlock_irq ( & input - > dma - > lock ) ;
} else {
ddb_input_stop_unlocked ( input ) ;
}
}
static void ddb_input_start_unlocked ( struct ddb_input * input )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = input - > port - > dev ;
if ( input - > dma ) {
input - > dma - > cbuf = 0 ;
input - > dma - > coff = 0 ;
input - > dma - > stat = 0 ;
2020-03-31 16:43:18 +02:00
input - > dma - > stall_count = 0 ;
input - > dma - > packet_loss = 0 ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0 , TS_CONTROL ( input ) ) ;
ddbwritel ( dev , 2 , TS_CONTROL ( input ) ) ;
ddbwritel ( dev , 0 , TS_CONTROL ( input ) ) ;
2015-08-05 17:22:42 +02:00
if ( input - > dma ) {
2016-04-20 16:27:56 +02:00
ddbwritel ( dev , input - > dma - > bufval ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_SIZE ( input - > dma ) ) ;
ddbwritel ( dev , 0 , DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 1 , DMA_BASE_WRITE ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 3 , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
if ( dev - > link [ 0 ] . info - > type = = DDB_OCTONET )
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , 0x01 , TS_CONTROL ( input ) ) ;
2020-08-29 15:18:59 +02:00
else {
if ( raw_stream )
ddbwritel ( dev , 0x01 | ( ( raw_stream & 3 ) < < 8 ) , TS_CONTROL ( input ) ) ;
else
ddbwritel ( dev , 0x01 | input - > con , TS_CONTROL ( input ) ) ;
}
2017-10-23 21:07:28 +02:00
if ( input - > port - > type = = DDB_TUNER_DUMMY )
ddbwritel ( dev , 0x000fff01 , TS_CONTROL2 ( input ) ) ;
2020-08-29 15:18:59 +02:00
if ( input - > dma )
2015-08-05 17:22:42 +02:00
input - > dma - > running = 1 ;
2018-05-28 16:41:11 +02:00
}
static void ddb_input_start ( struct ddb_input * input )
{
if ( input - > dma ) {
spin_lock_irq ( & input - > dma - > lock ) ;
ddb_input_start_unlocked ( input ) ;
2015-08-05 17:22:42 +02:00
spin_unlock_irq ( & input - > dma - > lock ) ;
2018-05-28 16:41:11 +02:00
} else {
ddb_input_start_unlocked ( input ) ;
2015-08-05 17:22:42 +02:00
}
}
2017-08-02 17:40:24 +02:00
int ddb_dvb_ns_input_start ( struct ddb_input * input )
2015-08-05 17:22:42 +02:00
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( ! dvb - > users )
ddb_input_start ( input ) ;
return + + dvb - > users ;
}
2017-08-02 17:40:24 +02:00
int ddb_dvb_ns_input_stop ( struct ddb_input * input )
2015-08-05 17:22:42 +02:00
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( - - dvb - > users )
return dvb - > users ;
ddb_input_stop ( input ) ;
return 0 ;
}
static void ddb_input_start_all ( struct ddb_input * input )
{
struct ddb_input * i = input ;
struct ddb_output * o ;
mutex_lock ( & redirect_lock ) ;
while ( i & & ( o = i - > redo ) ) {
ddb_output_start ( o ) ;
i = o - > port - > input [ 0 ] ;
if ( i )
ddb_input_start ( i ) ;
}
ddb_input_start ( input ) ;
mutex_unlock ( & redirect_lock ) ;
}
static void ddb_input_stop_all ( struct ddb_input * input )
{
struct ddb_input * i = input ;
struct ddb_output * o ;
mutex_lock ( & redirect_lock ) ;
ddb_input_stop ( input ) ;
while ( i & & ( o = i - > redo ) ) {
ddb_output_stop ( o ) ;
i = o - > port - > input [ 0 ] ;
if ( i )
ddb_input_stop ( i ) ;
}
mutex_unlock ( & redirect_lock ) ;
}
static u32 ddb_output_free ( struct ddb_output * output )
{
u32 idx , off , stat = output - > dma - > stat ;
s32 diff ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
if ( output - > dma - > cbuf ! = idx ) {
if ( ( ( ( output - > dma - > cbuf + 1 ) % output - > dma - > num ) = = idx ) & &
2020-08-29 15:32:42 +02:00
( output - > dma - > size - output - > dma - > coff < = 2 * 188 ) )
2015-08-05 17:22:42 +02:00
return 0 ;
return 188 ;
}
diff = off - output - > dma - > coff ;
2018-01-21 11:54:09 +01:00
if ( diff < = 0 | | diff > 2 * 188 )
2015-08-05 17:22:42 +02:00
return 188 ;
return 0 ;
}
static ssize_t ddb_output_write ( struct ddb_output * output ,
2015-12-13 22:26:35 +01:00
const __user u8 * buf , size_t count )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = output - > port - > dev ;
u32 idx , off , stat = output - > dma - > stat ;
u32 left = count , len ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
while ( left ) {
len = output - > dma - > size - output - > dma - > coff ;
if ( ( ( ( output - > dma - > cbuf + 1 ) % output - > dma - > num ) = = idx ) & &
( off = = 0 ) ) {
if ( len < = 188 )
break ;
len - = 188 ;
}
if ( output - > dma - > cbuf = = idx ) {
if ( off > output - > dma - > coff ) {
len = off - output - > dma - > coff ;
len - = ( len % 188 ) ;
if ( len < = 188 )
break ;
len - = 188 ;
}
}
if ( len > left )
len = left ;
if ( copy_from_user ( output - > dma - > vbuf [ output - > dma - > cbuf ] +
output - > dma - > coff ,
buf , len ) )
return - EIO ;
2016-04-15 18:08:51 +02:00
if ( alt_dma )
dma_sync_single_for_device ( dev - > dev ,
output - > dma - > pbuf [
output - > dma - > cbuf ] ,
2017-04-16 21:20:52 +02:00
output - > dma - > size ,
DMA_TO_DEVICE ) ;
2015-08-05 17:22:42 +02:00
left - = len ;
buf + = len ;
output - > dma - > coff + = len ;
if ( output - > dma - > coff = = output - > dma - > size ) {
output - > dma - > coff = 0 ;
output - > dma - > cbuf = ( ( output - > dma - > cbuf + 1 ) %
output - > dma - > num ) ;
}
ddbwritel ( dev ,
( output - > dma - > cbuf < < 11 ) |
( output - > dma - > coff > > 7 ) ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_ACK ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
return count - left ;
}
static u32 ddb_input_avail ( struct ddb_input * input )
{
struct ddb * dev = input - > port - > dev ;
u32 idx , off , stat = input - > dma - > stat ;
2016-05-02 16:27:32 +02:00
u32 ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
if ( ctrl & 4 ) {
2017-08-25 23:30:58 +02:00
dev_err ( dev - > dev , " IA %d %d %08x \n " , idx , off , ctrl ) ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , stat , DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
if ( input - > dma - > cbuf ! = idx )
return 188 ;
return 0 ;
}
2016-03-24 12:10:20 +01:00
static size_t ddb_input_read ( struct ddb_input * input ,
__user u8 * buf , size_t count )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = input - > port - > dev ;
u32 left = count ;
u32 idx , off , free , stat = input - > dma - > stat ;
int ret ;
idx = ( stat > > 11 ) & 0x1f ;
off = ( stat & 0x7ff ) < < 7 ;
while ( left ) {
if ( input - > dma - > cbuf = = idx )
return count - left ;
free = input - > dma - > size - input - > dma - > coff ;
if ( free > left )
free = left ;
2016-04-15 18:08:51 +02:00
if ( alt_dma )
dma_sync_single_for_cpu ( dev - > dev ,
2017-04-16 21:20:52 +02:00
input - > dma - > pbuf [
input - > dma - > cbuf ] ,
input - > dma - > size ,
DMA_FROM_DEVICE ) ;
2015-08-05 17:22:42 +02:00
ret = copy_to_user ( buf , input - > dma - > vbuf [ input - > dma - > cbuf ] +
input - > dma - > coff , free ) ;
if ( ret )
return - EFAULT ;
input - > dma - > coff + = free ;
if ( input - > dma - > coff = = input - > dma - > size ) {
input - > dma - > coff = 0 ;
input - > dma - > cbuf = ( input - > dma - > cbuf + 1 ) %
input - > dma - > num ;
}
left - = free ;
2016-06-10 09:45:21 +02:00
buf + = free ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev ,
( input - > dma - > cbuf < < 11 ) | ( input - > dma - > coff > > 7 ) ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
return count ;
}
/****************************************************************************/
/****************************************************************************/
static ssize_t ts_write ( struct file * file , const char * buf ,
size_t count , loff_t * ppos )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb * dev = output - > port - > dev ;
size_t left = count ;
int stat ;
if ( ! dev - > has_dma )
return - EINVAL ;
while ( left ) {
if ( ddb_output_free ( output ) < 188 ) {
if ( file - > f_flags & O_NONBLOCK )
break ;
if ( wait_event_interruptible (
output - > dma - > wq ,
ddb_output_free ( output ) > = 188 ) < 0 )
break ;
}
stat = ddb_output_write ( output , buf , left ) ;
if ( stat < 0 )
return stat ;
buf + = stat ;
left - = stat ;
}
return ( left = = count ) ? - EAGAIN : ( count - left ) ;
}
2015-12-13 22:26:35 +01:00
static ssize_t ts_read ( struct file * file , __user char * buf ,
2015-08-05 17:22:42 +02:00
size_t count , loff_t * ppos )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
struct ddb * dev = output - > port - > dev ;
size_t left = count ;
int stat ;
if ( ! dev - > has_dma )
return - EINVAL ;
2017-09-06 17:51:30 +02:00
if ( ! input )
return - EINVAL ;
2015-08-05 17:22:42 +02:00
while ( left ) {
if ( ddb_input_avail ( input ) < 188 ) {
if ( file - > f_flags & O_NONBLOCK )
break ;
if ( wait_event_interruptible (
input - > dma - > wq ,
ddb_input_avail ( input ) > = 188 ) < 0 )
break ;
}
stat = ddb_input_read ( input , buf , left ) ;
if ( stat < 0 )
return stat ;
left - = stat ;
buf + = stat ;
}
return ( count & & ( left = = count ) ) ? - EAGAIN : ( count - left ) ;
}
static unsigned int ts_poll ( struct file * file , poll_table * wait )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
unsigned int mask = 0 ;
poll_wait ( file , & input - > dma - > wq , wait ) ;
poll_wait ( file , & output - > dma - > wq , wait ) ;
if ( ddb_input_avail ( input ) > = 188 )
mask | = POLLIN | POLLRDNORM ;
if ( ddb_output_free ( output ) > = 188 )
mask | = POLLOUT | POLLWRNORM ;
return mask ;
}
static int ts_release ( struct inode * inode , struct file * file )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY ) {
if ( ! input )
return - EINVAL ;
ddb_input_stop ( input ) ;
} else if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
ddb_output_stop ( output ) ;
}
return dvb_generic_release ( inode , file ) ;
}
static int ts_open ( struct inode * inode , struct file * file )
{
int err ;
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
struct ddb_input * input = output - > port - > input [ 0 ] ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY ) {
if ( ! input )
return - EINVAL ;
if ( input - > redo | | input - > redi )
return - EBUSY ;
} else if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
2017-08-26 22:04:37 +02:00
} else {
2015-09-24 23:29:09 +02:00
return - EINVAL ;
2017-08-26 22:04:37 +02:00
}
2015-08-05 17:22:42 +02:00
err = dvb_generic_open ( inode , file ) ;
if ( err < 0 )
return err ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY )
2022-01-14 12:43:50 +01:00
ddb_input_start ( input ) ;
2015-08-05 17:22:42 +02:00
else if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY )
2021-12-06 15:36:44 +01:00
err = ddb_output_start ( output ) ;
2015-08-05 17:22:42 +02:00
return err ;
}
static int mod_release ( struct inode * inode , struct file * file )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
ddb_output_stop ( output ) ;
}
return dvb_generic_release ( inode , file ) ;
}
static int mod_open ( struct inode * inode , struct file * file )
{
int err ;
struct dvb_device * dvbdev = file - > private_data ;
struct ddb_output * output = dvbdev - > priv ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
if ( ! output )
return - EINVAL ;
}
err = dvb_generic_open ( inode , file ) ;
if ( err < 0 )
return err ;
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY )
ddb_output_start ( output ) ;
return err ;
}
2017-08-26 22:04:37 +02:00
2015-08-05 17:22:42 +02:00
static const struct file_operations ci_fops = {
. owner = THIS_MODULE ,
. read = ts_read ,
. write = ts_write ,
. open = ts_open ,
. release = ts_release ,
. poll = ts_poll ,
2017-12-11 16:20:24 +01:00
. mmap = NULL ,
2015-08-05 17:22:42 +02:00
} ;
static struct dvb_device dvbdev_ci = {
2017-12-11 16:20:24 +01:00
. priv = NULL ,
2015-08-05 17:22:42 +02:00
. readers = 1 ,
. writers = 1 ,
. users = 2 ,
. fops = & ci_fops ,
} ;
/****************************************************************************/
/****************************************************************************/
static long mod_ioctl ( struct file * file ,
unsigned int cmd , unsigned long arg )
{
return dvb_usercopy ( file , cmd , arg , ddbridge_mod_do_ioctl ) ;
}
static const struct file_operations mod_fops = {
. owner = THIS_MODULE ,
. read = ts_read ,
. write = ts_write ,
. open = mod_open ,
. release = mod_release ,
. poll = ts_poll ,
2017-12-11 16:20:24 +01:00
. mmap = NULL ,
2015-08-05 17:22:42 +02:00
. unlocked_ioctl = mod_ioctl ,
} ;
static struct dvb_device dvbdev_mod = {
2017-12-11 16:20:24 +01:00
. priv = NULL ,
2015-08-05 17:22:42 +02:00
. readers = 1 ,
. writers = 1 ,
. users = 2 ,
. fops = & mod_fops ,
} ;
static int locked_gate_ctrl ( struct dvb_frontend * fe , int enable )
{
struct ddb_input * input = fe - > sec_priv ;
struct ddb_port * port = input - > port ;
struct ddb_dvb * dvb = & port - > dvb [ input - > nr & 1 ] ;
int status ;
if ( enable ) {
mutex_lock ( & port - > i2c_gate_lock ) ;
status = dvb - > i2c_gate_ctrl ( fe , 1 ) ;
} else {
status = dvb - > i2c_gate_ctrl ( fe , 0 ) ;
mutex_unlock ( & port - > i2c_gate_lock ) ;
}
return status ;
}
2017-10-23 21:07:28 +02:00
/****************************************************************************/
static int dummy_read_status ( struct dvb_frontend * fe , enum fe_status * status )
{
* status = 0x1f ;
return 0 ;
}
static void dummy_release ( struct dvb_frontend * fe )
{
kfree ( fe ) ;
}
static struct dvb_frontend_ops dummy_ops = {
2019-07-08 10:00:11 +02:00
. delsys = { SYS_DVBC_ANNEX_A , SYS_DVBS , SYS_DVBS2 } ,
2017-10-23 21:07:28 +02:00
. info = {
. name = " DUMMY DVB-C/C2 DVB-T/T2 " ,
2020-08-29 15:32:42 +02:00
. frequency_stepsize_hz = 166667 , /* DVB-T only */
. frequency_min_hz = 47000000 , /* DVB-T: 47125000 */
. frequency_max_hz = 865000000 , /* DVB-C: 862000000 */
2017-10-23 21:07:28 +02:00
. symbol_rate_min = 870000 ,
. symbol_rate_max = 11700000 ,
. caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
2020-08-29 15:32:42 +02:00
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
2017-10-23 21:07:28 +02:00
} ,
. release = dummy_release ,
. read_status = dummy_read_status ,
} ;
static struct dvb_frontend * dummy_attach ( void )
{
# if (KERNEL_VERSION(4, 13, 0) > LINUX_VERSION_CODE)
struct dvb_frontend * fe = kmalloc ( sizeof ( * fe ) , __GFP_REPEAT ) ;
# else
struct dvb_frontend * fe = kmalloc ( sizeof ( * fe ) , __GFP_RETRY_MAYFAIL ) ;
# endif
if ( fe )
fe - > ops = dummy_ops ;
return fe ;
}
static int demod_attach_dummy ( struct ddb_input * input )
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
2021-02-25 14:57:33 +01:00
#if 0
2017-10-23 21:07:28 +02:00
dvb - > fe = dvb_attach ( dummy_attach ) ;
2021-02-25 14:57:33 +01:00
# else
dvb - > fe = dummy_attach ( ) ;
# endif
2017-10-23 21:07:28 +02:00
return 0 ;
}
/****************************************************************************/
2015-08-05 17:22:42 +02:00
# ifdef CONFIG_DVB_DRXK
static int demod_attach_drxk ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
2017-08-26 22:04:37 +02:00
dvb - > fe = dvb_attach ( drxk_attach ,
i2c , 0x29 + ( input - > nr & 1 ) ,
& dvb - > fe2 ) ;
if ( ! dvb - > fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No DRXK found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
2017-08-26 22:04:37 +02:00
dvb - > fe - > sec_priv = input ;
dvb - > i2c_gate_ctrl = dvb - > fe - > ops . i2c_gate_ctrl ;
dvb - > fe - > ops . i2c_gate_ctrl = locked_gate_ctrl ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
# endif
2016-11-07 21:19:53 +01:00
static int demod_attach_cxd2843 ( struct ddb_input * input , int par , int osc24 )
2015-08-05 17:22:42 +02:00
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
2016-11-07 21:19:53 +01:00
struct cxd2843_cfg cfg ;
cfg . adr = ( input - > nr & 1 ) ? 0x6d : 0x6c ;
cfg . ts_clock = par ? 0 : 1 ;
cfg . parallel = par ? 1 : 0 ;
cfg . osc = osc24 ? 24000000 : 20500000 ;
2017-08-26 22:04:37 +02:00
dvb - > fe = dvb_attach ( cxd2843_attach , i2c , & cfg ) ;
2015-08-05 17:22:42 +02:00
if ( ! dvb - > fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No cxd2837/38/43/54 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
2017-08-26 22:04:37 +02:00
dvb - > fe - > sec_priv = input ;
dvb - > i2c_gate_ctrl = dvb - > fe - > ops . i2c_gate_ctrl ;
dvb - > fe - > ops . i2c_gate_ctrl = locked_gate_ctrl ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
static int demod_attach_stv0367dd ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct stv0367_cfg cfg = { . cont_clock = 0 } ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
cfg . adr = 0x1f - ( input - > nr & 1 ) ;
if ( input - > port - > dev - > link [ input - > port - > lnr ] . info - > con_clock )
cfg . cont_clock = 1 ;
2018-01-01 21:00:11 +01:00
dvb - > fe = dvb_attach ( stv0367_attach , i2c , & cfg ) ;
2015-08-05 17:22:42 +02:00
if ( ! dvb - > fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No stv0367 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
2017-08-26 22:04:37 +02:00
dvb - > fe - > sec_priv = input ;
dvb - > i2c_gate_ctrl = dvb - > fe - > ops . i2c_gate_ctrl ;
dvb - > fe - > ops . i2c_gate_ctrl = locked_gate_ctrl ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
static int tuner_attach_tda18271 ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
if ( dvb - > fe - > ops . i2c_gate_ctrl )
dvb - > fe - > ops . i2c_gate_ctrl ( dvb - > fe , 1 ) ;
fe = dvb_attach ( tda18271c2dd_attach , dvb - > fe , i2c , 0x60 ) ;
if ( dvb - > fe - > ops . i2c_gate_ctrl )
dvb - > fe - > ops . i2c_gate_ctrl ( dvb - > fe , 0 ) ;
if ( ! fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No TDA18271 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
static int tuner_attach_tda18212dd ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
fe = dvb_attach ( tda18212dd_attach , dvb - > fe , i2c ,
( input - > nr & 1 ) ? 0x63 : 0x60 ) ;
if ( ! fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No TDA18212 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
# ifdef CONFIG_DVB_TDA18212
struct tda18212_config tda18212_0 = {
. i2c_address = 0x60 ,
} ;
struct tda18212_config tda18212_1 = {
. i2c_address = 0x63 ,
} ;
static int tuner_attach_tda18212 ( struct ddb_input * input )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
struct tda18212_config * cfg ;
cfg = ( input - > nr & 1 ) ? & tda18212_1 : & tda18212_0 ;
fe = dvb_attach ( tda18212_attach , dvb - > fe , i2c , cfg ) ;
if ( ! fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No TDA18212 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
# endif
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static struct stv090x_config stv0900 = {
. device = STV0900 ,
. demod_mode = STV090x_DUAL ,
. clk_mode = STV090x_CLK_EXT ,
. xtal = 27000000 ,
. address = 0x69 ,
. ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts1_tei = 1 ,
. ts2_tei = 1 ,
. repeater_level = STV090x_RPTLEVEL_16 ,
. adc1_range = STV090x_ADC_1Vpp ,
. adc2_range = STV090x_ADC_1Vpp ,
. diseqc_envelope_mode = true ,
} ;
static struct stv090x_config stv0900_aa = {
. device = STV0900 ,
. demod_mode = STV090x_DUAL ,
. clk_mode = STV090x_CLK_EXT ,
. xtal = 27000000 ,
. address = 0x68 ,
. ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED ,
. ts1_tei = 1 ,
. ts2_tei = 1 ,
. repeater_level = STV090x_RPTLEVEL_16 ,
. adc1_range = STV090x_ADC_1Vpp ,
. adc2_range = STV090x_ADC_1Vpp ,
. diseqc_envelope_mode = true ,
} ;
static struct stv6110x_config stv6110a = {
. addr = 0x60 ,
. refclk = 27000000 ,
. clk_div = 1 ,
} ;
static struct stv6110x_config stv6110b = {
. addr = 0x63 ,
. refclk = 27000000 ,
. clk_div = 1 ,
} ;
static int demod_attach_stv0900 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct stv090x_config * feconf = type ? & stv0900_aa : & stv0900 ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
dvb - > fe = dvb_attach ( stv090x_attach , feconf , i2c ,
( input - > nr & 1 ) ? STV090x_DEMODULATOR_1
: STV090x_DEMODULATOR_0 ) ;
if ( ! dvb - > fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No STV0900 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
if ( ! dvb_attach ( lnbh24_attach , dvb - > fe , i2c , 0 ,
0 , ( input - > nr & 1 ) ?
( 0x09 - type ) : ( 0x0b - type ) ) ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No LNBH24 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
return 0 ;
}
static int tuner_attach_stv6110 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct stv090x_config * feconf = type ? & stv0900_aa : & stv0900 ;
struct stv6110x_config * tunerconf = ( input - > nr & 1 ) ?
& stv6110b : & stv6110a ;
2017-09-26 21:18:04 +02:00
const struct stv6110x_devctl * ctl ;
2015-08-05 17:22:42 +02:00
ctl = dvb_attach ( stv6110x_attach , dvb - > fe , tunerconf , i2c ) ;
if ( ! ctl ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No STV6110X found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
2017-08-25 23:30:58 +02:00
dev_info ( input - > port - > dev - > dev ,
" attach tuner input %d adr %02x \n " ,
input - > nr , tunerconf - > addr ) ;
2015-08-05 17:22:42 +02:00
feconf - > tuner_init = ctl - > tuner_init ;
feconf - > tuner_sleep = ctl - > tuner_sleep ;
feconf - > tuner_set_mode = ctl - > tuner_set_mode ;
feconf - > tuner_set_frequency = ctl - > tuner_set_frequency ;
feconf - > tuner_get_frequency = ctl - > tuner_get_frequency ;
feconf - > tuner_set_bandwidth = ctl - > tuner_set_bandwidth ;
feconf - > tuner_get_bandwidth = ctl - > tuner_get_bandwidth ;
feconf - > tuner_set_bbgain = ctl - > tuner_set_bbgain ;
feconf - > tuner_get_bbgain = ctl - > tuner_get_bbgain ;
feconf - > tuner_set_refclk = ctl - > tuner_set_refclk ;
feconf - > tuner_get_status = ctl - > tuner_get_status ;
return 0 ;
}
2015-12-10 18:26:45 +01:00
static struct stv0910_cfg stv0910_p = {
2015-08-05 17:22:42 +02:00
. adr = 0x68 ,
. parallel = 1 ,
. rptlvl = 4 ,
. clk = 30000000 ,
2019-03-14 12:42:52 +01:00
. tsspeed = 0x20 ,
2015-08-05 17:22:42 +02:00
} ;
2018-04-07 20:17:38 +02:00
static int has_lnbh25 ( struct i2c_adapter * i2c , u8 adr )
{
u8 val ;
return i2c_read_reg ( i2c , adr , 0 , & val ) ? 0 : 1 ;
}
2015-08-05 17:22:42 +02:00
static int demod_attach_stv0910 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
2015-12-10 18:26:45 +01:00
struct stv0910_cfg cfg = stv0910_p ;
2018-08-10 08:48:01 +02:00
struct ddb * dev = input - > port - > dev ;
2018-04-07 20:17:38 +02:00
u8 lnbh_adr = 0x08 ;
2015-08-05 17:22:42 +02:00
2016-12-30 15:03:38 +01:00
if ( stv0910_single )
cfg . single = 1 ;
2015-12-10 18:26:45 +01:00
if ( type )
cfg . parallel = 2 ;
2018-08-10 08:48:01 +02:00
if ( ( input - > port - > nr = = 0 ) & &
( ( dev - > link [ 0 ] . ids . hwid & 0xffffff ) <
dev - > link [ 0 ] . info - > hw_min ) )
cfg . tsspeed = 0x28 ;
2015-12-10 18:26:45 +01:00
dvb - > fe = dvb_attach ( stv0910_attach , i2c , & cfg , ( input - > nr & 1 ) ) ;
if ( ! dvb - > fe ) {
cfg . adr = 0x6c ;
2015-08-05 17:22:42 +02:00
dvb - > fe = dvb_attach ( stv0910_attach , i2c ,
2015-12-10 18:26:45 +01:00
& cfg , ( input - > nr & 1 ) ) ;
}
2015-08-05 17:22:42 +02:00
if ( ! dvb - > fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No STV0910 found! \n " ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
2018-04-07 20:17:38 +02:00
if ( has_lnbh25 ( i2c , 0x0d ) )
lnbh_adr = 0x0c ;
2015-08-05 17:22:42 +02:00
if ( ! dvb_attach ( lnbh25_attach , dvb - > fe , i2c ,
2018-04-07 20:17:38 +02:00
( input - > nr & 1 ) + lnbh_adr ) ) {
dev_err ( input - > port - > dev - > dev ,
" No LNBH25 found! \n " ) ;
return - ENODEV ;
2015-08-05 17:22:42 +02:00
}
return 0 ;
}
static int tuner_attach_stv6111 ( struct ddb_input * input , int type )
{
struct i2c_adapter * i2c = & input - > port - > i2c - > adap ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_frontend * fe ;
u8 adr = ( type ? 0 : 4 ) + ( ( input - > nr & 1 ) ? 0x63 : 0x60 ) ;
fe = dvb_attach ( stv6111_attach , dvb - > fe , i2c , adr ) ;
if ( ! fe ) {
fe = dvb_attach ( stv6111_attach , dvb - > fe , i2c , adr & ~ 4 ) ;
if ( ! fe ) {
2017-08-25 23:30:58 +02:00
dev_err ( input - > port - > dev - > dev ,
" No STV6111 found at 0x%02x! \n " , adr ) ;
2015-08-05 17:22:42 +02:00
return - ENODEV ;
}
}
return 0 ;
}
static int start_feed ( struct dvb_demux_feed * dvbdmxfeed )
{
struct dvb_demux * dvbdmx = dvbdmxfeed - > demux ;
struct ddb_input * input = dvbdmx - > priv ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( ! dvb - > users )
ddb_input_start_all ( input ) ;
return + + dvb - > users ;
}
static int stop_feed ( struct dvb_demux_feed * dvbdmxfeed )
{
struct dvb_demux * dvbdmx = dvbdmxfeed - > demux ;
struct ddb_input * input = dvbdmx - > priv ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
if ( - - dvb - > users )
return dvb - > users ;
ddb_input_stop_all ( input ) ;
return 0 ;
}
static void dvb_input_detach ( struct ddb_input * input )
{
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct dvb_demux * dvbdemux = & dvb - > demux ;
switch ( dvb - > attached ) {
2018-01-01 21:04:00 +01:00
case 0x41 :
2015-08-05 17:22:42 +02:00
if ( dvb - > fe2 )
dvb_unregister_frontend ( dvb - > fe2 ) ;
2019-03-14 12:44:21 +01:00
/* fallthrough */
2018-01-01 21:04:00 +01:00
case 0x40 :
2015-08-05 17:22:42 +02:00
if ( dvb - > fe )
dvb_unregister_frontend ( dvb - > fe ) ;
/* fallthrough */
case 0x30 :
dvb_frontend_detach ( dvb - > fe ) ;
2017-08-26 22:04:37 +02:00
dvb - > fe = NULL ;
dvb - > fe2 = NULL ;
2015-08-05 17:22:42 +02:00
/* fallthrough */
case 0x21 :
if ( input - > port - > dev - > ns_num )
dvb_netstream_release ( & dvb - > dvbns ) ;
/* fallthrough */
case 0x20 :
dvb_net_release ( & dvb - > dvbnet ) ;
/* fallthrough */
2017-04-07 22:21:06 +02:00
case 0x12 :
2015-08-05 17:22:42 +02:00
dvbdemux - > dmx . remove_frontend ( & dvbdemux - > dmx ,
& dvb - > hw_frontend ) ;
dvbdemux - > dmx . remove_frontend ( & dvbdemux - > dmx ,
& dvb - > mem_frontend ) ;
2017-04-07 22:21:06 +02:00
/* fallthrough */
case 0x11 :
2015-08-05 17:22:42 +02:00
dvb_dmxdev_release ( & dvb - > dmxdev ) ;
/* fallthrough */
case 0x10 :
dvb_dmx_release ( & dvb - > demux ) ;
/* fallthrough */
case 0x01 :
break ;
}
dvb - > attached = 0x00 ;
}
static int dvb_register_adapters ( struct ddb * dev )
{
2018-09-10 20:21:17 +02:00
int i , ret = 0 , l = 0 ;
2015-08-05 17:22:42 +02:00
struct ddb_port * port ;
2019-08-13 21:37:10 +02:00
struct dvb_adapter * adap = 0 ;
2015-08-05 17:22:42 +02:00
2018-09-10 20:21:17 +02:00
if ( adapter_alloc = = 4 ) {
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
if ( port - > lnr > = l ) {
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " , THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
l = port - > lnr + 1 ;
}
port - > dvb [ 0 ] . adap = adap ;
port - > dvb [ 1 ] . adap = adap ;
}
return 0 ;
}
if ( adapter_alloc > = 3 | | dev - > link [ 0 ] . info - > type = = DDB_MOD | |
2018-03-28 19:42:03 +02:00
dev - > link [ 0 ] . info - > type = = DDB_OCTONET | |
2020-08-29 15:32:42 +02:00
dev - > link [ 0 ] . info - > type = = DDB_OCTOPRO ) {
2015-08-05 17:22:42 +02:00
port = & dev - > port [ 0 ] ;
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " , THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
port - > dvb [ 0 ] . adap = adap ;
port - > dvb [ 1 ] . adap = adap ;
}
return 0 ;
}
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
if ( adapter_alloc > 0 ) {
port - > dvb [ 1 ] . adap = port - > dvb [ 0 ] . adap ;
break ;
}
adap = port - > dvb [ 1 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 1 ] . adap_registered = 1 ;
break ;
case DDB_PORT_CI :
case DDB_PORT_LOOP :
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
break ;
default :
if ( adapter_alloc < 2 )
break ;
adap = port - > dvb [ 0 ] . adap ;
ret = dvb_register_adapter ( adap , " DDBridge " ,
THIS_MODULE ,
port - > dev - > dev ,
adapter_nr ) ;
if ( ret < 0 )
return ret ;
port - > dvb [ 0 ] . adap_registered = 1 ;
break ;
}
}
return ret ;
}
static void dvb_unregister_adapters ( struct ddb * dev )
{
int i ;
struct ddb_port * port ;
struct ddb_dvb * dvb ;
2018-09-10 20:21:17 +02:00
for ( i = 0 ; i < dev - > port_num ; i + + ) {
2015-08-05 17:22:42 +02:00
port = & dev - > port [ i ] ;
dvb = & port - > dvb [ 0 ] ;
if ( dvb - > adap_registered )
dvb_unregister_adapter ( dvb - > adap ) ;
dvb - > adap_registered = 0 ;
dvb = & port - > dvb [ 1 ] ;
if ( dvb - > adap_registered )
dvb_unregister_adapter ( dvb - > adap ) ;
dvb - > adap_registered = 0 ;
}
}
static int dvb_input_attach ( struct ddb_input * input )
{
int ret = 0 ;
struct ddb_dvb * dvb = & input - > port - > dvb [ input - > nr & 1 ] ;
struct ddb_port * port = input - > port ;
struct dvb_adapter * adap = dvb - > adap ;
struct dvb_demux * dvbdemux = & dvb - > demux ;
2016-12-14 19:11:57 +01:00
int par = 0 , osc24 = 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
dvb - > attached = 0x01 ;
2017-04-07 22:21:06 +02:00
dvbdemux - > priv = input ;
dvbdemux - > dmx . capabilities = DMX_TS_FILTERING |
DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING ;
dvbdemux - > start_feed = start_feed ;
dvbdemux - > stop_feed = stop_feed ;
2017-08-26 22:04:37 +02:00
dvbdemux - > filternum = 256 ;
dvbdemux - > feednum = 256 ;
2017-04-07 22:21:06 +02:00
ret = dvb_dmx_init ( dvbdemux ) ;
2015-08-05 17:22:42 +02:00
if ( ret < 0 )
return ret ;
dvb - > attached = 0x10 ;
2017-04-07 22:21:06 +02:00
dvb - > dmxdev . filternum = 256 ;
dvb - > dmxdev . demux = & dvbdemux - > dmx ;
ret = dvb_dmxdev_init ( & dvb - > dmxdev , adap ) ;
2015-08-05 17:22:42 +02:00
if ( ret < 0 )
return ret ;
dvb - > attached = 0x11 ;
2017-04-07 22:21:06 +02:00
dvb - > mem_frontend . source = DMX_MEMORY_FE ;
dvb - > demux . dmx . add_frontend ( & dvb - > demux . dmx , & dvb - > mem_frontend ) ;
dvb - > hw_frontend . source = DMX_FRONTEND_0 ;
dvb - > demux . dmx . add_frontend ( & dvb - > demux . dmx , & dvb - > hw_frontend ) ;
ret = dvbdemux - > dmx . connect_frontend ( & dvbdemux - > dmx , & dvb - > hw_frontend ) ;
if ( ret < 0 )
return ret ;
dvb - > attached = 0x12 ;
2015-08-05 17:22:42 +02:00
ret = dvb_net_init ( adap , & dvb - > dvbnet , dvb - > dmxdev . demux ) ;
if ( ret < 0 )
return ret ;
dvb - > attached = 0x20 ;
if ( input - > port - > dev - > ns_num ) {
ret = netstream_init ( input ) ;
if ( ret < 0 )
return ret ;
dvb - > attached = 0x21 ;
}
2017-08-26 22:04:37 +02:00
dvb - > fe = NULL ;
dvb - > fe2 = NULL ;
2015-08-05 17:22:42 +02:00
switch ( port - > type ) {
case DDB_TUNER_MXL5XX :
2017-08-27 23:54:49 +02:00
if ( ddb_fe_attach_mxl5xx ( input ) < 0 )
2015-08-05 17:22:42 +02:00
return - ENODEV ;
break ;
case DDB_TUNER_DVBS_ST :
if ( demod_attach_stv0900 ( input , 0 ) < 0 )
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-08-05 17:22:42 +02:00
if ( tuner_attach_stv6110 ( input , 0 ) < 0 )
return - ENODEV ;
break ;
case DDB_TUNER_DVBS_ST_AA :
if ( demod_attach_stv0900 ( input , 1 ) < 0 )
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-08-05 17:22:42 +02:00
if ( tuner_attach_stv6110 ( input , 1 ) < 0 )
return - ENODEV ;
break ;
case DDB_TUNER_DVBS_STV0910 :
if ( demod_attach_stv0910 ( input , 0 ) < 0 )
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-08-05 17:22:42 +02:00
if ( tuner_attach_stv6111 ( input , 0 ) < 0 )
return - ENODEV ;
break ;
2015-12-10 18:26:45 +01:00
case DDB_TUNER_DVBS_STV0910_PR :
2015-08-05 17:22:42 +02:00
if ( demod_attach_stv0910 ( input , 1 ) < 0 )
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-08-05 17:22:42 +02:00
if ( tuner_attach_stv6111 ( input , 1 ) < 0 )
return - ENODEV ;
break ;
2015-12-10 18:26:45 +01:00
case DDB_TUNER_DVBS_STV0910_P :
if ( demod_attach_stv0910 ( input , 0 ) < 0 )
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-12-10 18:26:45 +01:00
if ( tuner_attach_stv6111 ( input , 1 ) < 0 )
return - ENODEV ;
break ;
2015-08-05 17:22:42 +02:00
# ifdef CONFIG_DVB_DRXK
case DDB_TUNER_DVBCT_TR :
if ( demod_attach_drxk ( input ) < 0 )
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-08-05 17:22:42 +02:00
if ( tuner_attach_tda18271 ( input ) < 0 )
return - ENODEV ;
break ;
# endif
case DDB_TUNER_DVBCT_ST :
if ( demod_attach_stv0367dd ( input ) < 0 )
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-08-05 17:22:42 +02:00
if ( tuner_attach_tda18212dd ( input ) < 0 )
return - ENODEV ;
break ;
2016-12-14 19:11:57 +01:00
case DDB_TUNER_DVBC2T2I_SONY_P :
if ( input - > port - > dev - > link [ input - > port - > lnr ] . info - > ts_quirks &
TS_QUIRK_ALT_OSC )
osc24 = 0 ;
else
osc24 = 1 ;
2020-01-15 12:32:34 +01:00
/* fallthrough */
2015-08-05 17:22:42 +02:00
case DDB_TUNER_DVBCT2_SONY_P :
case DDB_TUNER_DVBC2T2_SONY_P :
case DDB_TUNER_ISDBT_SONY_P :
2016-03-24 12:10:20 +01:00
if ( input - > port - > dev - > link [ input - > port - > lnr ] . info - > ts_quirks &
TS_QUIRK_SERIAL )
2015-12-10 18:26:45 +01:00
par = 0 ;
else
2015-09-17 18:54:25 +02:00
par = 1 ;
2016-12-14 19:11:57 +01:00
if ( demod_attach_cxd2843 ( input , par , osc24 ) < 0 )
2016-11-07 21:19:53 +01:00
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2016-11-07 21:19:53 +01:00
if ( tuner_attach_tda18212dd ( input ) < 0 )
return - ENODEV ;
break ;
case DDB_TUNER_DVBC2T2I_SONY :
2016-12-14 19:11:57 +01:00
osc24 = 1 ;
2020-01-15 12:32:34 +01:00
/* fallthrough */
2016-12-14 19:11:57 +01:00
case DDB_TUNER_DVBCT2_SONY :
case DDB_TUNER_DVBC2T2_SONY :
case DDB_TUNER_ISDBT_SONY :
if ( demod_attach_cxd2843 ( input , 0 , osc24 ) < 0 )
2015-08-05 17:22:42 +02:00
return - ENODEV ;
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x30 ;
2015-08-05 17:22:42 +02:00
if ( tuner_attach_tda18212dd ( input ) < 0 )
return - ENODEV ;
break ;
2017-10-23 21:07:28 +02:00
case DDB_TUNER_DUMMY :
if ( demod_attach_dummy ( input ) < 0 )
return - ENODEV ;
break ;
2018-05-15 23:01:39 +02:00
case DDB_TUNER_MCI_SX8 :
case DDB_TUNER_MCI_M4 :
if ( ddb_fe_attach_mci ( input , port - > type ) < 0 )
2017-12-05 19:59:23 +01:00
return - ENODEV ;
break ;
2015-08-05 17:22:42 +02:00
default :
return 0 ;
}
dvb - > attached = 0x30 ;
2017-04-07 22:21:06 +02:00
2015-08-05 17:22:42 +02:00
if ( dvb - > fe ) {
if ( dvb_register_frontend ( adap , dvb - > fe ) < 0 )
return - ENODEV ;
}
2018-01-01 21:04:00 +01:00
dvb - > attached = 0x40 ;
2015-08-05 17:22:42 +02:00
if ( dvb - > fe2 ) {
if ( dvb_register_frontend ( adap , dvb - > fe2 ) < 0 )
return - ENODEV ;
dvb - > fe2 - > tuner_priv = dvb - > fe - > tuner_priv ;
memcpy ( & dvb - > fe2 - > ops . tuner_ops ,
& dvb - > fe - > ops . tuner_ops ,
sizeof ( struct dvb_tuner_ops ) ) ;
2019-03-14 12:44:21 +01:00
dvb - > attached = 0x41 ;
2015-08-05 17:22:42 +02:00
}
return 0 ;
}
static int port_has_encti ( struct ddb_port * port )
{
u8 val ;
int ret = i2c_read_reg ( & port - > i2c - > adap , 0x20 , 0 , & val ) ;
if ( ! ret )
2017-08-25 23:30:58 +02:00
dev_info ( port - > dev - > dev ,
" [0x20]=0x%02x \n " , val ) ;
2015-08-05 17:22:42 +02:00
return ret ? 0 : 1 ;
}
static int port_has_cxd ( struct ddb_port * port , u8 * type )
{
u8 val ;
u8 probe [ 4 ] = { 0xe0 , 0x00 , 0x00 , 0x00 } , data [ 4 ] ;
struct i2c_msg msgs [ 2 ] = { { . addr = 0x40 , . flags = 0 ,
. buf = probe , . len = 4 } ,
{ . addr = 0x40 , . flags = I2C_M_RD ,
. buf = data , . len = 4 } } ;
val = i2c_transfer ( & port - > i2c - > adap , msgs , 2 ) ;
if ( val ! = 2 )
return 0 ;
if ( data [ 0 ] = = 0x02 & & data [ 1 ] = = 0x2b & & data [ 3 ] = = 0x43 )
* type = 2 ;
else
* type = 1 ;
return 1 ;
}
static int port_has_xo2 ( struct ddb_port * port , u8 * type , u8 * id )
{
u8 probe [ 1 ] = { 0x00 } , data [ 4 ] ;
if ( i2c_io ( & port - > i2c - > adap , 0x10 , probe , 1 , data , 4 ) )
return 0 ;
if ( data [ 0 ] = = ' D ' & & data [ 1 ] = = ' F ' ) {
* id = data [ 2 ] ;
* type = 1 ;
return 1 ;
}
if ( data [ 0 ] = = ' C ' & & data [ 1 ] = = ' I ' ) {
* id = data [ 2 ] ;
* type = 2 ;
return 1 ;
}
return 0 ;
}
static int port_has_stv0900 ( struct ddb_port * port )
{
u8 val ;
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x69 , 0xf100 , & val ) < 0 )
return 0 ;
return 1 ;
}
static int port_has_stv0900_aa ( struct ddb_port * port , u8 * id )
{
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x68 , 0xf100 , id ) < 0 )
return 0 ;
return 1 ;
}
static int port_has_drxks ( struct ddb_port * port )
{
u8 val ;
if ( i2c_read ( & port - > i2c - > adap , 0x29 , & val ) < 0 )
return 0 ;
if ( i2c_read ( & port - > i2c - > adap , 0x2a , & val ) < 0 )
return 0 ;
return 1 ;
}
static int port_has_stv0367 ( struct ddb_port * port )
{
u8 val ;
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x1e , 0xf000 , & val ) < 0 )
return 0 ;
if ( val ! = 0x60 )
return 0 ;
if ( i2c_read_reg16 ( & port - > i2c - > adap , 0x1f , 0xf000 , & val ) < 0 )
return 0 ;
if ( val ! = 0x60 )
return 0 ;
return 1 ;
}
static int init_xo2 ( struct ddb_port * port )
{
struct i2c_adapter * i2c = & port - > i2c - > adap ;
struct ddb * dev = port - > dev ;
u8 val , data [ 2 ] ;
int res ;
res = i2c_read_regs ( i2c , 0x10 , 0x04 , data , 2 ) ;
if ( res < 0 )
return res ;
if ( data [ 0 ] ! = 0x01 ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Port %d: invalid XO2 \n " , port - > nr ) ;
2015-08-05 17:22:42 +02:00
return - 1 ;
}
i2c_read_reg ( i2c , 0x10 , 0x08 , & val ) ;
if ( val ! = 0 ) {
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x00 ) ;
msleep ( 100 ) ;
}
/* Enable tuner power, disable pll, reset demods */
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x04 ) ;
usleep_range ( 2000 , 3000 ) ;
/* Release demod resets */
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x07 ) ;
/* speed: 0=55,1=75,2=90,3=104 MBit/s */
2016-04-12 12:18:09 +02:00
i2c_write_reg ( i2c , 0x10 , 0x09 , xo2_speed ) ;
2015-08-05 17:22:42 +02:00
if ( dev - > link [ port - > lnr ] . info - > con_clock ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Setting continuous clock for XO2 \n " ) ;
2015-08-05 17:22:42 +02:00
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x03 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x03 ) ;
} else {
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x01 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x01 ) ;
}
usleep_range ( 2000 , 3000 ) ;
2016-03-24 12:10:20 +01:00
/* Start XO2 PLL */
2015-08-05 17:22:42 +02:00
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x87 ) ;
return 0 ;
}
static int init_xo2_ci ( struct ddb_port * port )
{
struct i2c_adapter * i2c = & port - > i2c - > adap ;
struct ddb * dev = port - > dev ;
u8 val , data [ 2 ] ;
int res ;
res = i2c_read_regs ( i2c , 0x10 , 0x04 , data , 2 ) ;
if ( res < 0 )
return res ;
if ( data [ 0 ] > 1 ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Port %d: invalid XO2 CI %02x \n " ,
port - > nr , data [ 0 ] ) ;
2015-08-05 17:22:42 +02:00
return - 1 ;
}
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Port %d: DuoFlex CI %u.%u \n " ,
port - > nr , data [ 0 ] , data [ 1 ] ) ;
2015-08-05 17:22:42 +02:00
i2c_read_reg ( i2c , 0x10 , 0x08 , & val ) ;
if ( val ! = 0 ) {
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x00 ) ;
msleep ( 100 ) ;
}
/* Enable both CI */
i2c_write_reg ( i2c , 0x10 , 0x08 , 3 ) ;
usleep_range ( 2000 , 3000 ) ;
/* speed: 0=55,1=75,2=90,3=104 MBit/s */
i2c_write_reg ( i2c , 0x10 , 0x09 , 1 ) ;
i2c_write_reg ( i2c , 0x10 , 0x08 , 0x83 ) ;
usleep_range ( 2000 , 3000 ) ;
if ( dev - > link [ port - > lnr ] . info - > con_clock ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Setting continuous clock for DuoFLex CI \n " ) ;
2015-08-05 17:22:42 +02:00
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x03 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x03 ) ;
} else {
i2c_write_reg ( i2c , 0x10 , 0x0a , 0x01 ) ;
i2c_write_reg ( i2c , 0x10 , 0x0b , 0x01 ) ;
}
return 0 ;
}
static int port_has_cxd28xx ( struct ddb_port * port , u8 * id )
{
struct i2c_adapter * i2c = & port - > i2c - > adap ;
int status ;
status = i2c_write_reg ( & port - > i2c - > adap , 0x6e , 0 , 0 ) ;
if ( status )
return 0 ;
status = i2c_read_reg ( i2c , 0x6e , 0xfd , id ) ;
if ( status )
return 0 ;
return 1 ;
}
static char * xo2names [ ] = {
" DUAL DVB-S2 " , " DUAL DVB-C/T/T2 " ,
" DUAL DVB-ISDBT " , " DUAL DVB-C/C2/T/T2 " ,
2016-11-07 21:19:53 +01:00
" DUAL ATSC " , " DUAL DVB-C/C2/T/T2,ISDB-T " ,
2015-08-05 17:22:42 +02:00
" " , " "
} ;
2015-10-22 14:51:36 +02:00
static char * xo2types [ ] = {
" DVBS_ST " , " DVBCT2_SONY " ,
" ISDBT_SONY " , " DVBC2T2_SONY " ,
2016-11-07 21:19:53 +01:00
" ATSC_ST " , " DVBC2T2I_SONY "
2015-10-22 14:51:36 +02:00
} ;
2015-08-05 17:22:42 +02:00
static void ddb_port_probe ( struct ddb_port * port )
{
struct ddb * dev = port - > dev ;
u32 l = port - > lnr ;
2018-05-14 04:26:51 +02:00
struct ddb_link * link = & dev - > link [ l ] ;
2015-08-05 17:22:42 +02:00
u8 id , type ;
port - > name = " NO MODULE " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " NONE " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_NONE ;
2015-10-22 14:51:36 +02:00
2015-08-05 17:22:42 +02:00
/* Handle missing ports and ports without I2C */
2016-03-24 12:10:20 +01:00
2017-10-23 21:07:28 +02:00
if ( dummy_tuner & & ! port - > nr & &
2019-07-08 10:00:11 +02:00
( link - > ids . device = = 0x0005 | |
link - > ids . device = = 0x000a ) ) {
2017-10-23 21:07:28 +02:00
port - > name = " DUMMY " ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_DUMMY ;
port - > type_name = " DUMMY " ;
return ;
}
2015-08-05 17:22:42 +02:00
if ( port - > nr = = ts_loop ) {
port - > name = " TS LOOP " ;
port - > class = DDB_PORT_LOOP ;
return ;
}
2016-03-24 12:10:20 +01:00
2021-12-06 15:37:10 +01:00
if ( port - > nr = = 1 & & link - > info - > type = = DDB_OCTOPUS_CI & &
2018-05-14 04:26:51 +02:00
link - > info - > i2c_mask = = 1 ) {
2015-08-05 17:22:42 +02:00
port - > name = " NO TAB " ;
port - > class = DDB_PORT_NONE ;
return ;
}
2021-12-06 15:37:10 +01:00
if ( link - > info - > type = = DDB_MOD ) {
2015-08-05 17:22:42 +02:00
port - > name = " MOD " ;
port - > class = DDB_PORT_MOD ;
return ;
}
2018-05-14 04:26:51 +02:00
if ( link - > info - > type = = DDB_OCTOPUS_MAX ) {
2015-08-05 17:22:42 +02:00
port - > name = " DUAL DVB-S2 MAX " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " MXL5XX " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_MXL5XX ;
if ( port - > i2c )
ddbwritel ( dev , I2C_SPEED_400 ,
port - > i2c - > regs + I2C_TIMING ) ;
return ;
}
2021-12-06 15:37:10 +01:00
if ( ( link - > info - > type = = DDB_OCTOPUS_MCI ) & &
( port - > nr < link - > info - > mci_ports ) ) {
2017-12-05 19:59:23 +01:00
port - > name = " DUAL MCI " ;
port - > type_name = " MCI " ;
port - > class = DDB_PORT_TUNER ;
2018-05-15 23:01:39 +02:00
port - > type = DDB_TUNER_MCI + link - > info - > mci_type ;
2017-12-05 19:59:23 +01:00
return ;
}
2018-05-14 04:26:51 +02:00
if ( port - > nr > 1 & & link - > info - > type = = DDB_OCTOPUS_CI ) {
2015-08-05 17:22:42 +02:00
port - > name = " CI internal " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " INTERNAL " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_INTERNAL ;
}
if ( ! port - > i2c )
return ;
/* Probe ports with I2C */
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( port_has_cxd ( port , & id ) ) {
if ( id = = 1 ) {
port - > name = " CI " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " CXD2099 " ;
2015-08-05 17:22:42 +02:00
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_EXTERNAL_SONY ;
ddbwritel ( dev , I2C_SPEED_400 ,
port - > i2c - > regs + I2C_TIMING ) ;
} else {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Port %d: Uninitialized DuoFlex \n " ,
port - > nr ) ;
2015-08-05 17:22:42 +02:00
return ;
}
} else if ( port_has_xo2 ( port , & type , & id ) ) {
ddbwritel ( dev , I2C_SPEED_400 , port - > i2c - > regs + I2C_TIMING ) ;
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " XO2 ID %02x \n " , id ) ;
2015-08-05 17:22:42 +02:00
if ( type = = 2 ) {
port - > name = " DuoFlex CI " ;
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_EXTERNAL_XO2 ;
2015-10-22 14:51:36 +02:00
port - > type_name = " CI_XO2 " ;
2015-08-05 17:22:42 +02:00
init_xo2_ci ( port ) ;
return ;
}
id > > = 2 ;
if ( id > 5 ) {
port - > name = " unknown XO2 DuoFlex " ;
2015-10-22 14:51:36 +02:00
port - > type_name = " UNKNOWN " ;
2015-08-05 17:22:42 +02:00
} else {
port - > name = xo2names [ id ] ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_XO2 + id ;
2015-10-22 14:51:36 +02:00
port - > type_name = xo2types [ id ] ;
2015-08-05 17:22:42 +02:00
init_xo2 ( port ) ;
}
} else if ( port_has_cxd28xx ( port , & id ) ) {
switch ( id ) {
case 0xa4 :
2015-10-22 14:51:36 +02:00
port - > name = " DUAL DVB-C2T2 CXD2843 " ;
2015-08-05 17:22:42 +02:00
port - > type = DDB_TUNER_DVBC2T2_SONY_P ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBC2T2_SONY " ;
2015-08-05 17:22:42 +02:00
break ;
case 0xb1 :
port - > name = " DUAL DVB-CT2 CXD2837 " ;
port - > type = DDB_TUNER_DVBCT2_SONY_P ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBCT2_SONY " ;
2015-08-05 17:22:42 +02:00
break ;
case 0xb0 :
port - > name = " DUAL ISDB-T CXD2838 " ;
port - > type = DDB_TUNER_ISDBT_SONY_P ;
2015-10-22 14:51:36 +02:00
port - > type_name = " ISDBT_SONY " ;
2015-08-05 17:22:42 +02:00
break ;
2016-08-29 18:44:53 +02:00
case 0xc1 :
port - > name = " DUAL DVB-C2T2 ISDB-T CXD2854 " ;
2017-04-09 13:20:22 +02:00
port - > type = DDB_TUNER_DVBC2T2I_SONY_P ;
port - > type_name = " DVBC2T2I_ISDBT_SONY " ;
2016-08-29 18:44:53 +02:00
break ;
2015-08-05 17:22:42 +02:00
default :
return ;
}
port - > class = DDB_PORT_TUNER ;
ddbwritel ( dev , I2C_SPEED_400 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_stv0900 ( port ) ) {
port - > name = " DUAL DVB-S2 " ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_DVBS_ST ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBS_ST " ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_100 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_stv0900_aa ( port , & id ) ) {
port - > name = " DUAL DVB-S2 " ;
port - > class = DDB_PORT_TUNER ;
2015-12-10 18:26:45 +01:00
if ( id = = 0x51 ) {
if ( port - > nr = = 0 & &
2018-05-14 04:26:51 +02:00
link - > info - > ts_quirks & TS_QUIRK_REVERSED )
2015-12-10 18:26:45 +01:00
port - > type = DDB_TUNER_DVBS_STV0910_PR ;
else
port - > type = DDB_TUNER_DVBS_STV0910_P ;
port - > type_name = " DVBS_ST_0910 " ;
} else {
2015-08-05 17:22:42 +02:00
port - > type = DDB_TUNER_DVBS_ST_AA ;
2015-12-10 18:26:45 +01:00
port - > type_name = " DVBS_ST_AA " ;
}
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_100 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_drxks ( port ) ) {
port - > name = " DUAL DVB-C/T " ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_DVBCT_TR ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBCT_TR " ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_400 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_stv0367 ( port ) ) {
port - > name = " DUAL DVB-C/T " ;
port - > class = DDB_PORT_TUNER ;
port - > type = DDB_TUNER_DVBCT_ST ;
2015-10-22 14:51:36 +02:00
port - > type_name = " DVBCT_ST " ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , I2C_SPEED_100 , port - > i2c - > regs + I2C_TIMING ) ;
} else if ( port_has_encti ( port ) ) {
port - > name = " ENCTI " ;
port - > class = DDB_PORT_LOOP ;
2016-03-24 12:10:20 +01:00
}
2015-08-05 17:22:42 +02:00
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static int ddb_port_attach ( struct ddb_port * port )
{
int ret = 0 ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
ret = dvb_input_attach ( port - > input [ 0 ] ) ;
if ( ret < 0 )
break ;
ret = dvb_input_attach ( port - > input [ 1 ] ) ;
if ( ret < 0 )
break ;
port - > input [ 0 ] - > redi = port - > input [ 0 ] ;
port - > input [ 1 ] - > redi = port - > input [ 1 ] ;
break ;
case DDB_PORT_CI :
2017-08-27 22:09:43 +02:00
ret = ddb_ci_attach ( port , ci_bitrate ) ;
2015-08-05 17:22:42 +02:00
if ( ret < 0 )
break ;
2020-01-15 12:32:34 +01:00
/* fallthrough */
2020-08-29 15:32:42 +02:00
case DDB_PORT_LOOP :
2015-08-05 17:22:42 +02:00
ret = dvb_register_device ( port - > dvb [ 0 ] . adap ,
& port - > dvb [ 0 ] . dev ,
2017-08-26 22:04:37 +02:00
& dvbdev_ci , ( void * ) port - > output ,
2017-09-26 21:18:04 +02:00
DVB_DEVICE_CI , 1 ) ;
2015-08-05 17:22:42 +02:00
break ;
case DDB_PORT_MOD :
ret = dvb_register_device ( port - > dvb [ 0 ] . adap ,
& port - > dvb [ 0 ] . dev ,
2017-08-26 22:04:37 +02:00
& dvbdev_mod , ( void * ) port - > output ,
2017-09-26 21:18:04 +02:00
DVB_DEVICE_MOD , 1 ) ;
2015-08-05 17:22:42 +02:00
break ;
default :
break ;
}
if ( ret < 0 )
2017-08-26 10:32:53 +02:00
dev_err ( port - > dev - > dev ,
" port_attach on port %d failed \n " , port - > nr ) ;
2015-08-05 17:22:42 +02:00
return ret ;
}
static int ddb_ports_attach ( struct ddb * dev )
{
int i , ret = 0 ;
struct ddb_port * port ;
dev - > ns_num = dev - > link [ 0 ] . info - > ns_num ;
for ( i = 0 ; i < dev - > ns_num ; i + + )
dev - > ns [ i ] . nr = i ;
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " %d netstream channels \n " , dev - > ns_num ) ;
2015-08-05 17:22:42 +02:00
if ( dev - > port_num ) {
ret = dvb_register_adapters ( dev ) ;
if ( ret < 0 ) {
2017-08-25 23:30:58 +02:00
dev_err ( dev - > dev , " Registering adapters failed. Check DVB_MAX_ADAPTERS in config. \n " ) ;
2015-08-05 17:22:42 +02:00
return ret ;
}
}
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
ret = ddb_port_attach ( port ) ;
if ( ret < 0 )
break ;
}
return ret ;
}
2017-08-02 17:40:24 +02:00
void ddb_ports_detach ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i ;
struct ddb_port * port ;
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
switch ( port - > class ) {
case DDB_PORT_TUNER :
dvb_input_detach ( port - > input [ 0 ] ) ;
dvb_input_detach ( port - > input [ 1 ] ) ;
break ;
case DDB_PORT_CI :
case DDB_PORT_LOOP :
if ( port - > dvb [ 0 ] . dev )
dvb_unregister_device ( port - > dvb [ 0 ] . dev ) ;
if ( port - > en ) {
dvb_ca_en50221_release ( port - > en ) ;
2018-01-16 23:54:15 +01:00
kfree ( port - > en - > data ) ;
2015-12-13 22:26:35 +01:00
port - > en = NULL ;
2015-08-05 17:22:42 +02:00
}
break ;
case DDB_PORT_MOD :
if ( port - > dvb [ 0 ] . dev )
dvb_unregister_device ( port - > dvb [ 0 ] . dev ) ;
break ;
}
}
dvb_unregister_adapters ( dev ) ;
}
/* Copy input DMA pointers to output DMA and ACK. */
static void input_write_output ( struct ddb_input * input ,
struct ddb_output * output )
{
ddbwritel ( output - > port - > dev ,
2016-05-02 16:27:32 +02:00
input - > dma - > stat , DMA_BUFFER_ACK ( output - > dma ) ) ;
2015-08-05 17:22:42 +02:00
output - > dma - > cbuf = ( input - > dma - > stat > > 11 ) & 0x1f ;
output - > dma - > coff = ( input - > dma - > stat & 0x7ff ) < < 7 ;
}
static void output_ack_input ( struct ddb_output * output ,
struct ddb_input * input )
{
ddbwritel ( input - > port - > dev ,
2016-05-02 16:27:32 +02:00
output - > dma - > stat , DMA_BUFFER_ACK ( input - > dma ) ) ;
2015-08-05 17:22:42 +02:00
}
static void input_write_dvb ( struct ddb_input * input ,
struct ddb_input * input2 )
{
struct ddb_dvb * dvb = & input2 - > port - > dvb [ input2 - > nr & 1 ] ;
struct ddb_dma * dma , * dma2 ;
struct ddb * dev = input - > port - > dev ;
int ack = 1 ;
2017-08-26 22:04:37 +02:00
dma = input - > dma ;
dma2 = input - > dma ;
2015-08-05 17:22:42 +02:00
/* if there also is an output connected, do not ACK.
2017-04-16 21:20:52 +02:00
* input_write_output will ACK .
*/
2015-08-05 17:22:42 +02:00
if ( input - > redo ) {
dma2 = input - > redo - > dma ;
ack = 0 ;
}
2017-08-26 22:04:37 +02:00
while ( dma - > cbuf ! = ( ( dma - > stat > > 11 ) & 0x1f ) | | ( 4 & dma - > ctrl ) ) {
2015-08-05 17:22:42 +02:00
if ( 4 & dma - > ctrl ) {
2021-02-24 20:30:45 +01:00
dev_warn ( dev - > dev , " Overflow dma input %u \n " , input - > nr ) ;
2015-08-05 17:22:42 +02:00
ack = 1 ;
}
2016-04-15 18:08:51 +02:00
if ( alt_dma )
dma_sync_single_for_cpu ( dev - > dev , dma2 - > pbuf [ dma - > cbuf ] ,
dma2 - > size , DMA_FROM_DEVICE ) ;
2021-02-25 14:58:42 +01:00
if ( raw_stream | | input - > con ) {
2020-08-29 14:57:02 +02:00
dvb_dmx_swfilter_raw ( & dvb - > demux ,
dma2 - > vbuf [ dma - > cbuf ] ,
dma2 - > size ) ;
2021-02-25 14:58:42 +01:00
} else {
2021-03-01 12:58:21 +01:00
if ( dma2 - > unaligned | | ( dma2 - > vbuf [ dma - > cbuf ] [ 0 ] ! = 0x47 ) ) {
2021-02-25 14:58:42 +01:00
if ( ! dma2 - > unaligned ) {
dma2 - > unaligned + + ;
dev_warn ( dev - > dev , " Input %u dma buffer unaligned, "
" switching to unaligned processing. \n " ,
input - > nr ) ;
print_hex_dump ( KERN_INFO , " TS: " , DUMP_PREFIX_OFFSET , 32 , 1 ,
dma2 - > vbuf [ dma - > cbuf ] ,
2021-03-01 12:58:54 +01:00
512 , false ) ;
2021-02-25 14:58:42 +01:00
}
dvb_dmx_swfilter ( & dvb - > demux ,
2020-08-29 14:57:02 +02:00
dma2 - > vbuf [ dma - > cbuf ] ,
2021-02-25 14:58:42 +01:00
dma2 - > size ) ;
} else
dvb_dmx_swfilter_packets ( & dvb - > demux ,
dma2 - > vbuf [ dma - > cbuf ] ,
dma2 - > size / 188 ) ;
}
2015-08-05 17:22:42 +02:00
dma - > cbuf = ( dma - > cbuf + 1 ) % dma2 - > num ;
if ( ack )
ddbwritel ( dev , ( dma - > cbuf < < 11 ) ,
2016-05-02 16:27:32 +02:00
DMA_BUFFER_ACK ( dma ) ) ;
dma - > stat = ddbreadl ( dev , DMA_BUFFER_CURRENT ( dma ) ) ;
dma - > ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( dma ) ) ;
2015-08-05 17:22:42 +02:00
}
}
static void input_tasklet ( unsigned long data )
{
2017-10-25 23:03:16 +02:00
struct ddb_dma * dma = ( struct ddb_dma * ) data ;
struct ddb_input * input = ( struct ddb_input * ) dma - > io ;
2015-08-05 17:22:42 +02:00
struct ddb * dev = input - > port - > dev ;
unsigned long flags ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
spin_lock_irqsave ( & dma - > lock , flags ) ;
if ( ! dma - > running ) {
spin_unlock_irqrestore ( & dma - > lock , flags ) ;
return ;
}
2016-05-02 16:27:32 +02:00
dma - > stat = ddbreadl ( dev , DMA_BUFFER_CURRENT ( dma ) ) ;
dma - > ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( dma ) ) ;
2021-02-24 20:25:27 +01:00
update_loss ( dma ) ;
2020-03-31 16:43:18 +02:00
if ( 4 & dma - > ctrl )
dma - > stall_count + + ;
2015-08-05 17:22:42 +02:00
if ( input - > redi )
input_write_dvb ( input , input - > redi ) ;
if ( input - > redo )
input_write_output ( input , input - > redo ) ;
wake_up ( & dma - > wq ) ;
spin_unlock_irqrestore ( & dma - > lock , flags ) ;
}
2020-08-29 15:32:42 +02:00
# ifdef OPTIMIZE_TASKLETS
2017-12-05 19:33:16 +01:00
static void input_handler ( unsigned long data )
{
struct ddb_input * input = ( struct ddb_input * ) data ;
struct ddb_dma * dma = input - > dma ;
/* If there is no input connected, input_tasklet() will
* just copy pointers and ACK . So , there is no need to go
* through the tasklet scheduler .
*/
if ( input - > redi )
tasklet_schedule ( & dma - > tasklet ) ;
else
input_tasklet ( data ) ;
}
# else
2017-10-25 23:03:16 +02:00
static void input_handler ( void * data )
2015-08-05 17:22:42 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb_input * input = ( struct ddb_input * ) data ;
2015-08-05 17:22:42 +02:00
struct ddb_dma * dma = input - > dma ;
2018-01-21 11:53:16 +01:00
input_tasklet ( ( unsigned long ) dma ) ;
2015-08-05 17:22:42 +02:00
}
2017-12-05 19:33:16 +01:00
# endif
2015-08-05 17:22:42 +02:00
2017-10-25 23:03:16 +02:00
static void output_tasklet ( unsigned long data )
{
2018-01-21 11:53:16 +01:00
struct ddb_dma * dma = ( struct ddb_dma * ) data ;
2017-10-25 23:03:16 +02:00
struct ddb_output * output = ( struct ddb_output * ) dma - > io ;
2015-08-05 17:22:42 +02:00
struct ddb * dev = output - > port - > dev ;
2018-01-21 11:53:16 +01:00
unsigned long flags ;
2015-08-05 17:22:42 +02:00
2018-01-21 11:53:16 +01:00
spin_lock_irqsave ( & dma - > lock , flags ) ;
if ( ! dma - > running )
goto unlock_exit ;
2016-05-02 16:27:32 +02:00
dma - > stat = ddbreadl ( dev , DMA_BUFFER_CURRENT ( dma ) ) ;
dma - > ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( dma ) ) ;
2015-08-05 17:22:42 +02:00
if ( output - > redi )
output_ack_input ( output , output - > redi ) ;
wake_up ( & dma - > wq ) ;
2018-01-21 11:53:16 +01:00
unlock_exit :
spin_unlock_irqrestore ( & dma - > lock , flags ) ;
2015-08-05 17:22:42 +02:00
}
2020-08-29 15:32:42 +02:00
# ifdef OPTIMIZE_TASKLETS
2018-01-21 11:53:16 +01:00
static void output_handler ( void * data )
2017-12-05 19:33:16 +01:00
{
struct ddb_output * output = ( struct ddb_output * ) data ;
struct ddb_dma * dma = output - > dma ;
struct ddb * dev = output - > port - > dev ;
spin_lock ( & dma - > lock ) ;
if ( ! dma - > running ) {
spin_unlock ( & dma - > lock ) ;
return ;
}
dma - > stat = ddbreadl ( dev , DMA_BUFFER_CURRENT ( dma ) ) ;
dma - > ctrl = ddbreadl ( dev , DMA_BUFFER_CONTROL ( dma ) ) ;
if ( output - > redi )
output_ack_input ( output , output - > redi ) ;
wake_up ( & dma - > wq ) ;
spin_unlock ( & dma - > lock ) ;
}
# else
2017-10-25 23:03:16 +02:00
static void output_handler ( void * data )
{
struct ddb_output * output = ( struct ddb_output * ) data ;
struct ddb_dma * dma = output - > dma ;
tasklet_schedule ( & dma - > tasklet ) ;
}
2017-12-05 19:33:16 +01:00
# endif
2017-10-25 23:03:16 +02:00
2015-08-05 17:22:42 +02:00
/****************************************************************************/
/****************************************************************************/
2017-09-08 14:47:14 +02:00
static const struct ddb_regmap * io_regmap ( struct ddb_io * io , int link )
2015-08-05 17:22:42 +02:00
{
2017-09-08 14:47:14 +02:00
const struct ddb_info * info ;
2016-05-02 16:27:32 +02:00
if ( link )
info = io - > port - > dev - > link [ io - > port - > lnr ] . info ;
else
info = io - > port - > dev - > link [ 0 ] . info ;
if ( ! info )
return NULL ;
return info - > regmap ;
}
2017-10-25 23:03:16 +02:00
static void ddb_dma_init ( struct ddb_io * io , int nr , int out , int irq_nr )
2016-05-02 16:27:32 +02:00
{
struct ddb_dma * dma ;
2017-09-08 14:47:14 +02:00
const struct ddb_regmap * rm = io_regmap ( io , 0 ) ;
2017-04-16 21:20:52 +02:00
2016-05-02 16:27:32 +02:00
dma = out ? & io - > port - > dev - > odma [ nr ] : & io - > port - > dev - > idma [ nr ] ;
io - > dma = dma ;
2015-08-05 17:22:42 +02:00
dma - > io = io ;
spin_lock_init ( & dma - > lock ) ;
init_waitqueue_head ( & dma - > wq ) ;
if ( out ) {
2017-10-25 23:03:16 +02:00
tasklet_init ( & dma - > tasklet , output_tasklet , ( unsigned long ) dma ) ;
2016-05-02 16:27:32 +02:00
dma - > regs = rm - > odma - > base + rm - > odma - > size * nr ;
dma - > bufregs = rm - > odma_buf - > base + rm - > odma_buf - > size * nr ;
2017-02-21 17:12:35 +01:00
if ( io - > port - > dev - > link [ 0 ] . info - > type = = DDB_MOD & &
2019-03-14 12:44:46 +01:00
io - > port - > dev - > link [ 0 ] . info - > version > = 16 ) {
2017-02-21 17:12:35 +01:00
dma - > num = OUTPUT_DMA_BUFS_SDR ;
dma - > size = OUTPUT_DMA_SIZE_SDR ;
2017-10-23 00:14:39 +02:00
dma - > div = 1 ;
2017-02-21 17:12:35 +01:00
} else {
2017-10-23 00:14:39 +02:00
dma - > num = dma_buf_num ;
dma - > size = dma_buf_size * 128 * 47 ;
dma - > div = 1 ;
2017-02-21 17:12:35 +01:00
}
2015-08-05 17:22:42 +02:00
} else {
2017-10-25 23:03:16 +02:00
tasklet_init ( & dma - > tasklet , input_tasklet , ( unsigned long ) dma ) ;
2016-05-02 16:27:32 +02:00
dma - > regs = rm - > idma - > base + rm - > idma - > size * nr ;
dma - > bufregs = rm - > idma_buf - > base + rm - > idma_buf - > size * nr ;
2017-10-23 00:14:39 +02:00
dma - > num = dma_buf_num ;
dma - > size = dma_buf_size * 128 * 47 ;
dma - > div = 1 ;
2015-08-05 17:22:42 +02:00
}
2016-05-02 16:27:32 +02:00
ddbwritel ( io - > port - > dev , 0 , DMA_BUFFER_ACK ( dma ) ) ;
2015-08-05 17:22:42 +02:00
}
2016-05-02 16:27:32 +02:00
static void ddb_input_init ( struct ddb_port * port , int nr , int pnr , int anr )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = port - > dev ;
struct ddb_input * input = & dev - > input [ anr ] ;
2017-09-08 14:47:14 +02:00
const struct ddb_regmap * rm ;
2015-08-05 17:22:42 +02:00
port - > input [ pnr ] = input ;
input - > nr = nr ;
input - > port = port ;
2016-05-02 16:27:32 +02:00
rm = io_regmap ( input , 1 ) ;
input - > regs = DDB_LINK_TAG ( port - > lnr ) |
( rm - > input - > base + rm - > input - > size * nr ) ;
2020-12-01 15:58:35 +01:00
#if 0
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " init link %u, input %u, regs %08x \n " ,
2017-04-16 21:20:52 +02:00
port - > lnr , nr , input - > regs ) ;
2020-12-01 15:58:35 +01:00
# endif
2015-08-05 17:22:42 +02:00
if ( dev - > has_dma ) {
2017-09-08 14:47:14 +02:00
const struct ddb_regmap * rm0 = io_regmap ( input , 0 ) ;
2016-05-06 12:32:25 +02:00
u32 base = rm0 - > irq_base_idma ;
2016-05-02 16:27:32 +02:00
u32 dma_nr = nr ;
if ( port - > lnr )
dma_nr + = 32 + ( port - > lnr - 1 ) * 8 ;
2017-04-16 21:20:52 +02:00
2017-10-25 23:03:16 +02:00
ddb_irq_set ( dev , 0 , dma_nr + base , & input_handler , input ) ;
ddb_dma_init ( input , dma_nr , 0 , dma_nr + base ) ;
2015-08-05 17:22:42 +02:00
}
}
2016-05-02 16:27:32 +02:00
static void ddb_output_init ( struct ddb_port * port , int nr )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = port - > dev ;
struct ddb_output * output = & dev - > output [ nr ] ;
2017-09-08 14:47:14 +02:00
const struct ddb_regmap * rm ;
2015-08-05 17:22:42 +02:00
port - > output = output ;
output - > nr = nr ;
output - > port = port ;
2016-05-02 16:27:32 +02:00
rm = io_regmap ( output , 1 ) ;
output - > regs = DDB_LINK_TAG ( port - > lnr ) |
( rm - > output - > base + rm - > output - > size * nr ) ;
2015-08-05 17:22:42 +02:00
if ( dev - > has_dma ) {
2017-09-08 14:47:14 +02:00
const struct ddb_regmap * rm0 = io_regmap ( output , 0 ) ;
2016-05-06 12:32:25 +02:00
u32 base = rm0 - > irq_base_odma ;
2017-08-26 10:32:53 +02:00
2017-10-25 23:03:16 +02:00
ddb_irq_set ( dev , 0 , nr + base , & output_handler , output ) ;
ddb_dma_init ( output , nr , 1 , nr + base ) ;
2015-08-05 17:22:42 +02:00
}
}
static int ddb_port_match_i2c ( struct ddb_port * port )
{
struct ddb * dev = port - > dev ;
u32 i ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < dev - > i2c_num ; i + + ) {
if ( dev - > i2c [ i ] . link = = port - > lnr & &
dev - > i2c [ i ] . nr = = port - > nr ) {
port - > i2c = & dev - > i2c [ i ] ;
return 1 ;
}
}
return 0 ;
}
2016-05-02 16:27:32 +02:00
static int ddb_port_match_link_i2c ( struct ddb_port * port )
{
struct ddb * dev = port - > dev ;
u32 i ;
for ( i = 0 ; i < dev - > i2c_num ; i + + ) {
if ( dev - > i2c [ i ] . link = = port - > lnr ) {
port - > i2c = & dev - > i2c [ i ] ;
return 1 ;
}
}
return 0 ;
}
2015-08-05 17:22:42 +02:00
static void ddb_ports_init ( struct ddb * dev )
{
2021-06-23 11:18:35 +02:00
u32 i , l , p , ports ;
2015-08-05 17:22:42 +02:00
struct ddb_port * port ;
2017-09-08 14:47:14 +02:00
const struct ddb_info * info ;
const struct ddb_regmap * rm ;
2015-08-05 17:22:42 +02:00
for ( p = l = 0 ; l < DDB_MAX_LINK ; l + + ) {
info = dev - > link [ l ] . info ;
if ( ! info )
continue ;
rm = info - > regmap ;
if ( ! rm )
continue ;
2021-06-23 11:18:35 +02:00
ports = info - > port_num ;
2021-12-06 15:37:10 +01:00
if ( ( l = = 0 ) & & ( info - > type = = DDB_MOD ) & &
2021-06-23 11:18:35 +02:00
( dev - > link [ 0 ] . ids . revision = = 1 ) ) {
ports = ddbreadl ( dev , 0x260 ) > > 24 ;
}
for ( i = 0 ; i < ports ; i + + , p + + ) {
2015-08-05 17:22:42 +02:00
port = & dev - > port [ p ] ;
port - > dev = dev ;
port - > nr = i ;
port - > lnr = l ;
port - > pnr = p ;
2016-06-27 23:01:21 +02:00
port - > gap = 0xffffffff ;
2015-08-05 17:22:42 +02:00
port - > obr = ci_bitrate ;
mutex_init ( & port - > i2c_gate_lock ) ;
2016-05-02 16:27:32 +02:00
if ( ! ddb_port_match_i2c ( port ) )
2015-08-05 17:22:42 +02:00
if ( info - > type = = DDB_OCTOPUS_MAX )
2016-05-02 16:27:32 +02:00
ddb_port_match_link_i2c ( port ) ;
2015-08-05 17:22:42 +02:00
ddb_port_probe ( port ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
port - > dvb [ 0 ] . adap = & dev - > adap [ 2 * p ] ;
port - > dvb [ 1 ] . adap = & dev - > adap [ 2 * p + 1 ] ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ( port - > class = = DDB_PORT_NONE ) & & i & &
dev - > port [ p - 1 ] . type = = DDB_CI_EXTERNAL_XO2 ) {
port - > class = DDB_PORT_CI ;
port - > type = DDB_CI_EXTERNAL_XO2_B ;
port - > name = " DuoFlex CI_B " ;
port - > i2c = dev - > port [ p - 1 ] . i2c ;
}
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Port %u: Link %u, Link Port %u (TAB %u): %s \n " ,
port - > pnr , port - > lnr , port - > nr ,
port - > nr + 1 , port - > name ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( port - > class = = DDB_PORT_CI & &
port - > type = = DDB_CI_EXTERNAL_XO2 ) {
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i , 0 , 2 * i ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
continue ;
}
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( port - > class = = DDB_PORT_CI & &
port - > type = = DDB_CI_EXTERNAL_XO2_B ) {
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i - 1 , 0 , 2 * i - 1 ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
continue ;
}
2016-05-02 16:27:32 +02:00
if ( port - > class = = DDB_PORT_NONE )
continue ;
2021-12-06 15:37:10 +01:00
switch ( info - > type ) {
2015-08-05 17:22:42 +02:00
case DDB_OCTOPUS_CI :
if ( i > = 2 ) {
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 + i , 0 , 2 + i ) ;
ddb_input_init ( port , 4 + i , 1 , 4 + i ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
break ;
} /* fallthrough */
case DDB_OCTONET :
case DDB_OCTOPUS :
2016-04-15 23:53:20 +02:00
case DDB_OCTOPRO :
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i , 0 , 2 * i ) ;
ddb_input_init ( port , 2 * i + 1 , 1 , 2 * i + 1 ) ;
ddb_output_init ( port , i ) ;
2015-08-05 17:22:42 +02:00
break ;
case DDB_OCTOPUS_MAX :
2015-09-17 18:54:25 +02:00
case DDB_OCTOPUS_MAX_CT :
2017-12-05 19:59:23 +01:00
case DDB_OCTOPUS_MCI :
2016-05-02 16:27:32 +02:00
ddb_input_init ( port , 2 * i , 0 , 2 * p ) ;
ddb_input_init ( port , 2 * i + 1 , 1 , 2 * p + 1 ) ;
2015-08-05 17:22:42 +02:00
break ;
case DDB_MOD :
2016-05-02 16:27:32 +02:00
ddb_output_init ( port , i ) ;
2017-10-25 23:03:16 +02:00
ddb_irq_set ( dev , 0 , i + rm - > irq_base_rate ,
& ddbridge_mod_rate_handler ,
& dev - > output [ i ] ) ;
2015-08-05 17:22:42 +02:00
break ;
default :
break ;
}
}
}
dev - > port_num = p ;
}
2017-08-02 17:40:24 +02:00
void ddb_ports_release ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
int i ;
struct ddb_port * port ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < dev - > port_num ; i + + ) {
port = & dev - > port [ i ] ;
if ( port - > input [ 0 ] & & port - > input [ 0 ] - > dma )
tasklet_kill ( & port - > input [ 0 ] - > dma - > tasklet ) ;
if ( port - > input [ 1 ] & & port - > input [ 1 ] - > dma )
tasklet_kill ( & port - > input [ 1 ] - > dma - > tasklet ) ;
if ( port - > output & & port - > output - > dma )
tasklet_kill ( & port - > output - > dma - > tasklet ) ;
}
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
2017-08-26 22:04:37 +02:00
# define IRQ_HANDLE(_n) \
2017-10-25 23:03:16 +02:00
do { if ( ( s & ( 1UL < < ( ( _n ) & 0x1f ) ) ) & & dev - > link [ 0 ] . irq [ _n ] . handler ) \
dev - > link [ 0 ] . irq [ _n ] . handler ( dev - > link [ 0 ] . irq [ _n ] . data ) ; } \
2015-08-05 17:22:42 +02:00
while ( 0 )
2017-12-05 19:37:29 +01:00
# define IRQ_HANDLE_NIBBLE(_shift) { \
if ( s & ( 0x0000000f < < ( ( _shift ) & 0x1f ) ) ) { \
IRQ_HANDLE ( 0 + ( _shift ) ) ; \
IRQ_HANDLE ( 1 + ( _shift ) ) ; \
IRQ_HANDLE ( 2 + ( _shift ) ) ; \
IRQ_HANDLE ( 3 + ( _shift ) ) ; \
} \
}
# define IRQ_HANDLE_BYTE(_shift) { \
2017-08-26 22:04:37 +02:00
if ( s & ( 0x000000ff < < ( ( _shift ) & 0x1f ) ) ) { \
IRQ_HANDLE ( 0 + ( _shift ) ) ; \
IRQ_HANDLE ( 1 + ( _shift ) ) ; \
IRQ_HANDLE ( 2 + ( _shift ) ) ; \
IRQ_HANDLE ( 3 + ( _shift ) ) ; \
IRQ_HANDLE ( 4 + ( _shift ) ) ; \
IRQ_HANDLE ( 5 + ( _shift ) ) ; \
IRQ_HANDLE ( 6 + ( _shift ) ) ; \
IRQ_HANDLE ( 7 + ( _shift ) ) ; \
2017-04-16 21:20:52 +02:00
} \
2016-04-15 22:45:55 +02:00
}
2015-08-05 17:22:42 +02:00
static void irq_handle_msg ( struct ddb * dev , u32 s )
{
dev - > i2c_irq + + ;
2017-12-05 19:37:29 +01:00
IRQ_HANDLE_NIBBLE ( 0 ) ;
2015-08-05 17:22:42 +02:00
}
static void irq_handle_io ( struct ddb * dev , u32 s )
{
dev - > ts_irq + + ;
2017-12-05 19:37:29 +01:00
IRQ_HANDLE_NIBBLE ( 4 ) ;
IRQ_HANDLE_BYTE ( 8 ) ;
IRQ_HANDLE_BYTE ( 16 ) ;
IRQ_HANDLE_BYTE ( 24 ) ;
2015-08-05 17:22:42 +02:00
}
2017-08-27 21:42:02 +02:00
irqreturn_t ddb_irq_handler0 ( int irq , void * dev_id )
2015-08-05 17:22:42 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb * dev = ( struct ddb * ) dev_id ;
2018-03-04 23:43:39 +01:00
u32 mask = 0x8fffff00 ;
u32 s = mask & ddbreadl ( dev , INTERRUPT_STATUS ) ;
2015-08-05 17:22:42 +02:00
2018-03-04 23:43:39 +01:00
if ( ! s )
return IRQ_NONE ;
2015-08-05 17:22:42 +02:00
do {
2016-04-13 11:31:30 +02:00
if ( s & 0x80000000 )
2015-08-05 17:22:42 +02:00
return IRQ_NONE ;
2018-03-04 23:43:39 +01:00
ddbwritel ( dev , s , INTERRUPT_ACK ) ;
2015-08-05 17:22:42 +02:00
irq_handle_io ( dev , s ) ;
2018-03-04 23:43:39 +01:00
} while ( ( s = mask & ddbreadl ( dev , INTERRUPT_STATUS ) ) ) ;
2015-08-05 17:22:42 +02:00
return IRQ_HANDLED ;
}
2017-08-27 21:42:02 +02:00
irqreturn_t ddb_irq_handler1 ( int irq , void * dev_id )
2015-08-05 17:22:42 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb * dev = ( struct ddb * ) dev_id ;
2018-03-04 23:43:39 +01:00
u32 mask = 0x8000000f ;
u32 s = mask & ddbreadl ( dev , INTERRUPT_STATUS ) ;
2015-08-05 17:22:42 +02:00
2018-03-04 23:43:39 +01:00
if ( ! s )
return IRQ_NONE ;
2015-08-05 17:22:42 +02:00
do {
if ( s & 0x80000000 )
return IRQ_NONE ;
2018-03-04 23:43:39 +01:00
ddbwritel ( dev , s , INTERRUPT_ACK ) ;
2015-08-05 17:22:42 +02:00
irq_handle_msg ( dev , s ) ;
2018-03-04 23:43:39 +01:00
} while ( ( s = mask & ddbreadl ( dev , INTERRUPT_STATUS ) ) ) ;
2015-08-05 17:22:42 +02:00
return IRQ_HANDLED ;
}
2017-08-27 21:42:02 +02:00
irqreturn_t ddb_irq_handler ( int irq , void * dev_id )
2015-08-05 17:22:42 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb * dev = ( struct ddb * ) dev_id ;
2015-08-05 17:22:42 +02:00
u32 s = ddbreadl ( dev , INTERRUPT_STATUS ) ;
int ret = IRQ_HANDLED ;
if ( ! s )
return IRQ_NONE ;
do {
if ( s & 0x80000000 )
return IRQ_NONE ;
ddbwritel ( dev , s , INTERRUPT_ACK ) ;
if ( s & 0x0000000f )
irq_handle_msg ( dev , s ) ;
if ( s & 0x0fffff00 ) {
irq_handle_io ( dev , s ) ;
}
} while ( ( s = ddbreadl ( dev , INTERRUPT_STATUS ) ) ) ;
return ret ;
}
2016-04-15 18:08:51 +02:00
static irqreturn_t irq_handle_v2_n ( struct ddb * dev , u32 n )
{
2016-05-02 16:27:32 +02:00
u32 reg = INTERRUPT_V2_STATUS + 4 * n ;
2016-04-15 18:08:51 +02:00
u32 s = ddbreadl ( dev , reg ) ;
u32 off = n * 32 ;
2016-04-15 23:53:20 +02:00
2016-04-15 18:08:51 +02:00
if ( ! s )
return IRQ_NONE ;
ddbwritel ( dev , s , reg ) ;
2017-04-16 21:20:52 +02:00
2017-12-05 19:37:29 +01:00
IRQ_HANDLE_BYTE ( 0 + off ) ;
IRQ_HANDLE_BYTE ( 8 + off ) ;
IRQ_HANDLE_BYTE ( 16 + off ) ;
IRQ_HANDLE_BYTE ( 24 + off ) ;
2016-04-15 22:45:55 +02:00
return IRQ_HANDLED ;
2016-04-15 18:08:51 +02:00
}
2017-08-27 21:42:02 +02:00
irqreturn_t ddb_irq_handler_v2 ( int irq , void * dev_id )
2016-04-15 18:08:51 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb * dev = ( struct ddb * ) dev_id ;
2016-04-15 23:53:20 +02:00
u32 s = 0xffff & ddbreadl ( dev , INTERRUPT_V2_STATUS ) ;
2016-04-15 18:08:51 +02:00
int ret = IRQ_HANDLED ;
if ( ! s )
return IRQ_NONE ;
do {
2016-05-02 16:27:32 +02:00
if ( s & 0x80 )
2016-04-15 18:08:51 +02:00
return IRQ_NONE ;
2016-05-02 16:27:32 +02:00
ddbwritel ( dev , s , INTERRUPT_V2_STATUS ) ;
2016-04-15 18:08:51 +02:00
if ( s & 0x00000001 )
2016-05-02 16:27:32 +02:00
irq_handle_v2_n ( dev , 1 ) ;
2016-05-05 00:15:02 +02:00
if ( s & 0x00000002 )
2016-05-02 16:27:32 +02:00
irq_handle_v2_n ( dev , 2 ) ;
if ( s & 0x00000004 )
irq_handle_v2_n ( dev , 3 ) ;
2017-12-05 19:37:29 +01:00
IRQ_HANDLE_NIBBLE ( 8 ) ;
2016-04-15 23:53:20 +02:00
} while ( ( s = 0xffff & ddbreadl ( dev , INTERRUPT_V2_STATUS ) ) ) ;
2016-04-15 18:08:51 +02:00
return ret ;
}
2015-08-05 17:22:42 +02:00
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static ssize_t nsd_read ( struct file * file , char * buf ,
size_t count , loff_t * ppos )
{
return 0 ;
}
static unsigned int nsd_poll ( struct file * file , poll_table * wait )
{
return 0 ;
}
static int nsd_release ( struct inode * inode , struct file * file )
{
return dvb_generic_release ( inode , file ) ;
}
static int nsd_open ( struct inode * inode , struct file * file )
{
return dvb_generic_open ( inode , file ) ;
}
static struct ddb_input * plugtoinput ( struct ddb * dev , u8 plug )
{
int i , j ;
for ( i = j = 0 ; i < dev - > port_num ; i + + ) {
if ( dev - > port [ i ] . class = = DDB_PORT_TUNER ) {
if ( j = = plug )
return dev - > port [ i ] . input [ 0 ] ;
if ( j + 1 = = plug )
return dev - > port [ i ] . input [ 1 ] ;
j + = 2 ;
}
}
return 0 ;
}
static int nsd_do_ioctl ( struct file * file , unsigned int cmd , void * parg )
{
struct dvb_device * dvbdev = file - > private_data ;
struct ddb * dev = dvbdev - > priv ;
2017-08-26 22:04:37 +02:00
/* unsigned long arg = (unsigned long)parg; */
2015-08-05 17:22:42 +02:00
int ret = 0 ;
switch ( cmd ) {
case NSD_START_GET_TS :
{
struct dvb_nsd_ts * ts = parg ;
struct ddb_input * input = plugtoinput ( dev , ts - > input ) ;
u32 ctrl ;
u32 to ;
if ( ! input )
return - EINVAL ;
ctrl = ( input - > port - > lnr < < 16 ) | ( ( input - > nr & 7 ) < < 8 ) |
( ( ts - > filter_mask & 3 ) < < 2 ) ;
2017-04-16 21:20:52 +02:00
2015-08-05 17:22:42 +02:00
if ( ddbreadl ( dev , TS_CAPTURE_CONTROL ) & 1 ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " ts capture busy \n " ) ;
2015-08-05 17:22:42 +02:00
return - EBUSY ;
}
ddb_dvb_ns_input_start ( input ) ;
ddbwritel ( dev , ctrl , TS_CAPTURE_CONTROL ) ;
ddbwritel ( dev , ts - > pid , TS_CAPTURE_PID ) ;
ddbwritel ( dev , ( ts - > section_id < < 16 ) |
( ts - > table < < 8 ) | ts - > section ,
TS_CAPTURE_TABLESECTION ) ;
/* 1024 ms default timeout if timeout set to 0 */
if ( ts - > timeout )
to = ts - > timeout ;
else
to = 1024 ;
/* 21 packets default if num set to 0 */
if ( ts - > num )
2017-08-26 22:04:37 +02:00
to | = ( ( u32 ) ts - > num < < 16 ) ;
2015-08-05 17:22:42 +02:00
else
to | = ( 21 < < 16 ) ;
ddbwritel ( dev , to , TS_CAPTURE_TIMEOUT ) ;
if ( ts - > mode )
ctrl | = 2 ;
ddbwritel ( dev , ctrl | 1 , TS_CAPTURE_CONTROL ) ;
break ;
}
case NSD_POLL_GET_TS :
{
struct dvb_nsd_ts * ts = parg ;
u32 ctrl = ddbreadl ( dev , TS_CAPTURE_CONTROL ) ;
if ( ctrl & 1 )
return - EBUSY ;
2017-08-25 23:30:58 +02:00
if ( ctrl & ( 1 < < 14 ) )
2015-08-05 17:22:42 +02:00
return - EAGAIN ;
ddbcpyfrom ( dev , dev - > tsbuf , TS_CAPTURE_MEMORY ,
TS_CAPTURE_LEN ) ;
ts - > len = ddbreadl ( dev , TS_CAPTURE_RECEIVED ) & 0x1fff ;
if ( copy_to_user ( ts - > ts , dev - > tsbuf , ts - > len ) )
return - EIO ;
break ;
}
case NSD_CANCEL_GET_TS :
{
u32 ctrl = 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , ctrl , TS_CAPTURE_CONTROL ) ;
ctrl = ddbreadl ( dev , TS_CAPTURE_CONTROL ) ;
break ;
}
case NSD_STOP_GET_TS :
{
struct dvb_nsd_ts * ts = parg ;
struct ddb_input * input = plugtoinput ( dev , ts - > input ) ;
u32 ctrl = ddbreadl ( dev , TS_CAPTURE_CONTROL ) ;
if ( ! input )
return - EINVAL ;
if ( ctrl & 1 ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev ,
" cannot stop ts capture, while it was neither finished nor canceled \n " ) ;
2015-08-05 17:22:42 +02:00
return - EBUSY ;
}
ddb_dvb_ns_input_stop ( input ) ;
break ;
}
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
static long nsd_ioctl ( struct file * file ,
unsigned int cmd , unsigned long arg )
{
return dvb_usercopy ( file , cmd , arg , nsd_do_ioctl ) ;
}
static const struct file_operations nsd_fops = {
. owner = THIS_MODULE ,
. read = nsd_read ,
. open = nsd_open ,
. release = nsd_release ,
. poll = nsd_poll ,
. unlocked_ioctl = nsd_ioctl ,
} ;
static struct dvb_device dvbdev_nsd = {
. priv = 0 ,
. readers = 1 ,
. writers = 1 ,
. users = 1 ,
. fops = & nsd_fops ,
} ;
static int ddb_nsd_attach ( struct ddb * dev )
{
int ret ;
if ( ! dev - > link [ 0 ] . info - > ns_num )
return 0 ;
ret = dvb_register_device ( & dev - > adap [ 0 ] ,
& dev - > nsd_dev ,
2017-08-26 22:04:37 +02:00
& dvbdev_nsd , ( void * ) dev ,
2017-09-26 21:18:04 +02:00
DVB_DEVICE_NSD , 0 ) ;
2015-08-05 17:22:42 +02:00
return ret ;
}
2017-08-02 17:40:24 +02:00
void ddb_nsd_detach ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
if ( ! dev - > link [ 0 ] . info - > ns_num )
return ;
if ( dev - > nsd_dev - > users > 2 ) {
wait_event ( dev - > nsd_dev - > wait_queue ,
dev - > nsd_dev - > users = = 2 ) ;
}
dvb_unregister_device ( dev - > nsd_dev ) ;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static int reg_wait ( struct ddb * dev , u32 reg , u32 bit )
{
u32 count = 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
while ( ddbreadl ( dev , reg ) & bit ) {
ndelay ( 10 ) ;
if ( + + count = = 100 )
return - 1 ;
}
return 0 ;
}
2016-03-24 12:10:20 +01:00
static int flashio ( struct ddb * dev , u32 lnr ,
u8 * wbuf , u32 wlen , u8 * rbuf , u32 rlen )
2015-08-05 17:22:42 +02:00
{
u32 data , shift ;
u32 tag = DDB_LINK_TAG ( lnr ) ;
struct ddb_link * link = & dev - > link [ lnr ] ;
mutex_lock ( & link - > flash_mutex ) ;
if ( wlen > 4 )
ddbwritel ( dev , 1 , tag | SPI_CONTROL ) ;
while ( wlen > 4 ) {
/* FIXME: check for big-endian */
2017-08-26 22:04:37 +02:00
data = swab32 ( * ( u32 * ) wbuf ) ;
2015-08-05 17:22:42 +02:00
wbuf + = 4 ;
wlen - = 4 ;
ddbwritel ( dev , data , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
}
if ( rlen )
ddbwritel ( dev , 0x0001 | ( ( wlen < < ( 8 + 3 ) ) & 0x1f00 ) ,
tag | SPI_CONTROL ) ;
else
ddbwritel ( dev , 0x0003 | ( ( wlen < < ( 8 + 3 ) ) & 0x1f00 ) ,
tag | SPI_CONTROL ) ;
data = 0 ;
shift = ( ( 4 - wlen ) * 8 ) ;
while ( wlen ) {
data < < = 8 ;
data | = * wbuf ;
wlen - - ;
wbuf + + ;
}
if ( shift )
data < < = shift ;
ddbwritel ( dev , data , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ! rlen ) {
ddbwritel ( dev , 0 , tag | SPI_CONTROL ) ;
goto exit ;
}
if ( rlen > 4 )
ddbwritel ( dev , 1 , tag | SPI_CONTROL ) ;
while ( rlen > 4 ) {
ddbwritel ( dev , 0xffffffff , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
data = ddbreadl ( dev , tag | SPI_DATA ) ;
2017-08-26 22:04:37 +02:00
* ( u32 * ) rbuf = swab32 ( data ) ;
2015-08-05 17:22:42 +02:00
rbuf + = 4 ;
rlen - = 4 ;
}
2016-03-24 12:10:20 +01:00
ddbwritel ( dev , 0x0003 | ( ( rlen < < ( 8 + 3 ) ) & 0x1F00 ) ,
tag | SPI_CONTROL ) ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 0xffffffff , tag | SPI_DATA ) ;
if ( reg_wait ( dev , tag | SPI_CONTROL , 4 ) )
goto fail ;
data = ddbreadl ( dev , tag | SPI_DATA ) ;
ddbwritel ( dev , 0 , tag | SPI_CONTROL ) ;
if ( rlen < 4 )
data < < = ( ( 4 - rlen ) * 8 ) ;
while ( rlen > 0 ) {
* rbuf = ( ( data > > 24 ) & 0xff ) ;
data < < = 8 ;
rbuf + + ;
rlen - - ;
}
exit :
mutex_unlock ( & link - > flash_mutex ) ;
return 0 ;
fail :
mutex_unlock ( & link - > flash_mutex ) ;
return - 1 ;
}
int ddbridge_flashread ( struct ddb * dev , u32 link , u8 * buf , u32 addr , u32 len )
{
u8 cmd [ 4 ] = { 0x03 , ( addr > > 16 ) & 0xff ,
( addr > > 8 ) & 0xff , addr & 0xff } ;
return flashio ( dev , link , cmd , 4 , buf , len ) ;
}
2018-04-11 21:20:25 +02:00
static int mdio_write ( struct ddb * dev , u8 adr , u8 reg , u16 val , u32 mdio_base )
2015-08-05 17:22:42 +02:00
{
2018-04-11 21:20:25 +02:00
ddbwritel ( dev , adr , MDIO_ADR_OFF + mdio_base ) ;
ddbwritel ( dev , reg , MDIO_REG_OFF + mdio_base ) ;
ddbwritel ( dev , val , MDIO_VAL_OFF + mdio_base ) ;
ddbwritel ( dev , 0x03 , MDIO_CTRL_OFF + mdio_base ) ;
while ( ddbreadl ( dev , MDIO_CTRL_OFF + mdio_base ) & 0x02 )
2015-08-05 17:22:42 +02:00
ndelay ( 500 ) ;
return 0 ;
}
2018-04-11 21:20:25 +02:00
static u16 mdio_read ( struct ddb * dev , u8 adr , u8 reg , u32 mdio_base )
2015-08-05 17:22:42 +02:00
{
2018-04-11 21:20:25 +02:00
ddbwritel ( dev , adr , MDIO_ADR_OFF + mdio_base ) ;
ddbwritel ( dev , reg , MDIO_REG_OFF + mdio_base ) ;
ddbwritel ( dev , 0x07 , MDIO_CTRL_OFF + mdio_base ) ;
while ( ddbreadl ( dev , MDIO_CTRL_OFF + mdio_base ) & 0x02 )
2015-08-05 17:22:42 +02:00
ndelay ( 500 ) ;
2018-04-11 21:20:25 +02:00
return ddbreadl ( dev , MDIO_VAL_OFF + mdio_base ) ;
2015-08-05 17:22:42 +02:00
}
# define DDB_NAME "ddbridge"
static u32 ddb_num ;
static int ddb_major ;
static DEFINE_MUTEX ( ddb_mutex ) ;
static int ddb_release ( struct inode * inode , struct file * file )
{
struct ddb * dev = file - > private_data ;
2020-01-16 10:57:53 +01:00
atomic_inc ( & dev - > ddb_dev_users ) ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
static int ddb_open ( struct inode * inode , struct file * file )
{
struct ddb * dev = ddbs [ iminor ( inode ) ] ;
2020-01-16 10:57:53 +01:00
if ( ! atomic_dec_and_test ( & dev - > ddb_dev_users ) ) {
atomic_inc ( & dev - > ddb_dev_users ) ;
2015-08-05 17:22:42 +02:00
return - EBUSY ;
2020-01-16 10:57:53 +01:00
}
2015-08-05 17:22:42 +02:00
file - > private_data = dev ;
return 0 ;
}
static long ddb_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
{
struct ddb * dev = file - > private_data ;
void * parg = ( void * ) arg ;
int res ;
switch ( cmd ) {
case IOCTL_DDB_FLASHIO :
{
struct ddb_flashio fio ;
u8 * rbuf , * wbuf ;
if ( copy_from_user ( & fio , parg , sizeof ( fio ) ) )
return - EFAULT ;
if ( fio . write_len > 1028 | | fio . read_len > 1028 )
return - EINVAL ;
if ( fio . write_len + fio . read_len > 1028 )
return - EINVAL ;
if ( fio . link > 3 )
return - EINVAL ;
wbuf = & dev - > iobuf [ 0 ] ;
rbuf = wbuf + fio . write_len ;
if ( copy_from_user ( wbuf , fio . write_buf , fio . write_len ) )
return - EFAULT ;
2016-03-24 12:10:20 +01:00
res = flashio ( dev , fio . link , wbuf ,
fio . write_len , rbuf , fio . read_len ) ;
2015-08-05 17:22:42 +02:00
if ( res )
return res ;
if ( copy_to_user ( fio . read_buf , rbuf , fio . read_len ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_GPIO_OUT :
{
struct ddb_gpio gpio ;
if ( copy_from_user ( & gpio , parg , sizeof ( gpio ) ) )
return - EFAULT ;
ddbwritel ( dev , gpio . mask , GPIO_DIRECTION ) ;
ddbwritel ( dev , gpio . data , GPIO_OUTPUT ) ;
break ;
}
case IOCTL_DDB_ID :
{
struct ddb_id ddbid ;
2015-09-06 19:08:57 +02:00
ddbid . vendor = dev - > link [ 0 ] . ids . vendor ;
ddbid . device = dev - > link [ 0 ] . ids . device ;
ddbid . subvendor = dev - > link [ 0 ] . ids . subvendor ;
ddbid . subdevice = dev - > link [ 0 ] . ids . subdevice ;
2021-06-23 11:18:35 +02:00
ddbid . hw = dev - > link [ 0 ] . ids . hwid ;
ddbid . regmap = dev - > link [ 0 ] . ids . regmapid ;
2015-08-05 17:22:42 +02:00
if ( copy_to_user ( parg , & ddbid , sizeof ( ddbid ) ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_READ_REG :
{
struct ddb_reg reg ;
if ( copy_from_user ( & reg , parg , sizeof ( reg ) ) )
return - EFAULT ;
if ( ( reg . reg & 0xfffffff ) > = dev - > regs_len )
return - EINVAL ;
reg . val = ddbreadl ( dev , reg . reg ) ;
if ( copy_to_user ( parg , & reg , sizeof ( reg ) ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_REG :
{
struct ddb_reg reg ;
if ( copy_from_user ( & reg , parg , sizeof ( reg ) ) )
return - EFAULT ;
if ( ( reg . reg & 0xfffffff ) > = dev - > regs_len )
return - EINVAL ;
ddbwritel ( dev , reg . val , reg . reg ) ;
break ;
}
case IOCTL_DDB_READ_MDIO :
{
struct ddb_mdio mdio ;
2018-04-11 21:20:25 +02:00
u32 mdio_base = dev - > link [ 0 ] . info - > mdio_base ;
2015-08-05 17:22:42 +02:00
2018-04-11 21:20:25 +02:00
if ( ! mdio_base )
2015-08-05 17:22:42 +02:00
return - EIO ;
if ( copy_from_user ( & mdio , parg , sizeof ( mdio ) ) )
return - EFAULT ;
2018-04-11 21:20:25 +02:00
mdio . val = mdio_read ( dev , mdio . adr , mdio . reg , mdio_base ) ;
2015-08-05 17:22:42 +02:00
if ( copy_to_user ( parg , & mdio , sizeof ( mdio ) ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_MDIO :
{
struct ddb_mdio mdio ;
2018-04-11 21:20:25 +02:00
u32 mdio_base = dev - > link [ 0 ] . info - > mdio_base ;
2015-08-05 17:22:42 +02:00
2018-04-11 21:20:25 +02:00
if ( ! mdio_base )
2015-08-05 17:22:42 +02:00
return - EIO ;
if ( copy_from_user ( & mdio , parg , sizeof ( mdio ) ) )
return - EFAULT ;
2018-04-11 21:20:25 +02:00
mdio_write ( dev , mdio . adr , mdio . reg , mdio . val , mdio_base ) ;
2015-08-05 17:22:42 +02:00
break ;
}
case IOCTL_DDB_READ_MEM :
{
struct ddb_mem mem ;
u8 * buf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & mem , parg , sizeof ( mem ) ) )
return - EFAULT ;
if ( ( ( ( mem . len + mem . off ) & 0xfffffff ) > dev - > regs_len ) | |
mem . len > 1024 )
return - EINVAL ;
ddbcpyfrom ( dev , buf , mem . off , mem . len ) ;
if ( copy_to_user ( mem . buf , buf , mem . len ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_MEM :
{
struct ddb_mem mem ;
u8 * buf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & mem , parg , sizeof ( mem ) ) )
return - EFAULT ;
if ( ( ( ( mem . len + mem . off ) & 0xfffffff ) > dev - > regs_len ) | |
mem . len > 1024 )
return - EINVAL ;
if ( copy_from_user ( buf , mem . buf , mem . len ) )
return - EFAULT ;
ddbcpyto ( dev , mem . off , buf , mem . len ) ;
break ;
}
case IOCTL_DDB_READ_I2C :
{
struct ddb_i2c_msg i2c ;
struct i2c_adapter * adap ;
u8 * mbuf , * hbuf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & i2c , parg , sizeof ( i2c ) ) )
return - EFAULT ;
2019-04-12 20:11:27 +02:00
if ( i2c . bus > dev - > i2c_num )
2015-08-05 17:22:42 +02:00
return - EINVAL ;
if ( i2c . mlen + i2c . hlen > 512 )
return - EINVAL ;
adap = & dev - > i2c [ i2c . bus ] . adap ;
mbuf = hbuf + i2c . hlen ;
if ( copy_from_user ( hbuf , i2c . hdr , i2c . hlen ) )
return - EFAULT ;
if ( i2c_io ( adap , i2c . adr , hbuf , i2c . hlen , mbuf , i2c . mlen ) < 0 )
return - EIO ;
if ( copy_to_user ( i2c . msg , mbuf , i2c . mlen ) )
return - EFAULT ;
break ;
}
case IOCTL_DDB_WRITE_I2C :
{
struct ddb_i2c_msg i2c ;
struct i2c_adapter * adap ;
u8 * buf = & dev - > iobuf [ 0 ] ;
if ( copy_from_user ( & i2c , parg , sizeof ( i2c ) ) )
return - EFAULT ;
2019-04-12 20:11:27 +02:00
if ( i2c . bus > dev - > i2c_num )
2015-08-05 17:22:42 +02:00
return - EINVAL ;
if ( i2c . mlen + i2c . hlen > 250 )
return - EINVAL ;
adap = & dev - > i2c [ i2c . bus ] . adap ;
if ( copy_from_user ( buf , i2c . hdr , i2c . hlen ) )
return - EFAULT ;
if ( copy_from_user ( buf + i2c . hlen , i2c . msg , i2c . mlen ) )
return - EFAULT ;
if ( i2c_write ( adap , i2c . adr , buf , i2c . hlen + i2c . mlen ) < 0 )
return - EIO ;
break ;
}
2020-12-01 15:58:35 +01:00
case IOCTL_DDB_MCI_CMD :
{
struct ddb_mci_msg msg ;
struct ddb_link * link ;
int res ;
if ( copy_from_user ( & msg , parg , sizeof ( msg ) ) )
return - EFAULT ;
if ( msg . link > 3 )
return - EFAULT ;
link = & dev - > link [ msg . link ] ;
res = ddb_mci_cmd_link ( link , & msg . cmd , & msg . res ) ;
if ( copy_to_user ( parg , & msg , sizeof ( msg ) ) )
return - EFAULT ;
return res ;
}
2015-08-05 17:22:42 +02:00
default :
return - ENOTTY ;
}
return 0 ;
}
static const struct file_operations ddb_fops = {
. unlocked_ioctl = ddb_ioctl ,
. open = ddb_open ,
. release = ddb_release ,
} ;
2017-09-25 19:20:17 +02:00
# if (KERNEL_VERSION(3, 4, 0) > LINUX_VERSION_CODE)
2015-08-05 17:22:42 +02:00
static char * ddb_devnode ( struct device * device , mode_t * mode )
# else
static char * ddb_devnode ( struct device * device , umode_t * mode )
# endif
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return kasprintf ( GFP_KERNEL , " ddbridge/card%d " , dev - > nr ) ;
}
# define __ATTR_MRO(_name, _show) { \
. attr = { . name = __stringify ( _name ) , . mode = 0444 } , \
. show = _show , \
}
# define __ATTR_MWO(_name, _store) { \
. attr = { . name = __stringify ( _name ) , . mode = 0222 } , \
. store = _store , \
}
static ssize_t ports_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-05-05 00:15:02 +02:00
return sprintf ( buf , " %d \n " , dev - > port_num ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t ts_irq_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return sprintf ( buf , " %d \n " , dev - > ts_irq ) ;
}
static ssize_t i2c_irq_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return sprintf ( buf , " %d \n " , dev - > i2c_irq ) ;
}
static char * class_name [ ] = {
" NONE " , " CI " , " TUNER " , " LOOP " , " MOD "
} ;
static ssize_t fan_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
u32 val ;
val = ddbreadl ( dev , GPIO_OUTPUT ) & 1 ;
return sprintf ( buf , " %d \n " , val ) ;
}
static ssize_t fan_store ( struct device * device , struct device_attribute * d ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2017-04-16 21:20:52 +02:00
u32 val ;
2015-08-05 17:22:42 +02:00
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
ddbwritel ( dev , 1 , GPIO_DIRECTION ) ;
ddbwritel ( dev , val & 1 , GPIO_OUTPUT ) ;
return count ;
}
2016-08-29 18:44:53 +02:00
static ssize_t fanspeed_show ( struct device * device ,
2017-08-26 22:04:37 +02:00
struct device_attribute * attr , char * buf )
2016-08-29 18:44:53 +02:00
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 8 ] - 0x30 ;
struct ddb_link * link = & dev - > link [ num ] ;
u32 spd ;
spd = ddblreadl ( link , TEMPMON_FANCONTROL ) & 0xff ;
return sprintf ( buf , " %u \n " , spd * 100 ) ;
}
2015-08-05 17:22:42 +02:00
static ssize_t temp_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2018-05-25 23:05:26 +02:00
struct ddb_link * link ;
2015-08-05 17:22:42 +02:00
struct i2c_adapter * adap ;
2016-08-02 21:22:18 +02:00
s32 temp , temp2 , temp3 ;
int i ;
2015-08-05 17:22:42 +02:00
u8 tmp [ 2 ] ;
2018-05-25 23:05:26 +02:00
int l = 0 ;
if ( attr - > attr . name [ 4 ] = = ' l ' )
l = attr - > attr . name [ 5 ] - 0x30 ;
link = & dev - > link [ l ] ;
2017-04-16 21:20:52 +02:00
2020-08-29 15:32:42 +02:00
if ( link - > info - > type = = DDB_MOD ) {
2017-02-09 10:12:43 +01:00
if ( link - > info - > version > = 2 ) {
2016-12-14 19:24:58 +01:00
temp = 0xffff & ddbreadl ( dev , TEMPMON2_BOARD ) ;
2016-08-02 21:22:18 +02:00
temp = ( temp * 1000 ) > > 8 ;
2016-12-14 19:24:58 +01:00
temp2 = 0xffff & ddbreadl ( dev , TEMPMON2_FPGACORE ) ;
2016-08-02 21:22:18 +02:00
temp2 = ( temp2 * 1000 ) > > 8 ;
2016-12-14 19:24:58 +01:00
temp3 = 0xffff & ddbreadl ( dev , TEMPMON2_QAMCORE ) ;
2016-08-02 21:22:18 +02:00
temp3 = ( temp3 * 1000 ) > > 8 ;
2017-04-16 21:20:52 +02:00
2016-08-02 21:22:18 +02:00
return sprintf ( buf , " %d %d %d \n " , temp , temp2 , temp3 ) ;
}
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 1 , TEMPMON_CONTROL ) ;
for ( i = 0 ; i < 10 ; i + + ) {
if ( 0 = = ( 1 & ddbreadl ( dev , TEMPMON_CONTROL ) ) )
break ;
usleep_range ( 1000 , 2000 ) ;
}
temp = ddbreadl ( dev , TEMPMON_SENSOR1 ) ;
temp2 = ddbreadl ( dev , TEMPMON_SENSOR2 ) ;
temp = ( temp * 1000 ) > > 8 ;
temp2 = ( temp2 * 1000 ) > > 8 ;
if ( ddbreadl ( dev , TEMPMON_CONTROL ) & 0x8000 ) {
temp3 = ddbreadl ( dev , TEMPMON_CORE ) ;
temp3 = ( temp3 * 1000 ) > > 8 ;
return sprintf ( buf , " %d %d %d \n " , temp , temp2 , temp3 ) ;
}
return sprintf ( buf , " %d %d \n " , temp , temp2 ) ;
}
2018-05-25 23:05:26 +02:00
if ( link - > info - > type = = DDB_OCTOPUS_MCI ) {
temp = 0xffff & ddblreadl ( link , TEMPMON_SENSOR0 ) ;
2018-05-25 00:12:31 +02:00
temp = ( temp * 1000 ) > > 8 ;
return sprintf ( buf , " %d \n " , temp ) ;
}
2017-02-09 10:12:43 +01:00
if ( ! link - > info - > temp_num )
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " no sensor \n " ) ;
2017-02-09 10:12:43 +01:00
adap = & dev - > i2c [ link - > info - > temp_bus ] . adap ;
2015-08-05 17:22:42 +02:00
if ( i2c_read_regs ( adap , 0x48 , 0 , tmp , 2 ) < 0 )
return sprintf ( buf , " read_error \n " ) ;
temp = ( tmp [ 0 ] < < 3 ) | ( tmp [ 1 ] > > 5 ) ;
temp * = 125 ;
2017-02-09 10:12:43 +01:00
if ( link - > info - > temp_num = = 2 ) {
2015-08-05 17:22:42 +02:00
if ( i2c_read_regs ( adap , 0x49 , 0 , tmp , 2 ) < 0 )
return sprintf ( buf , " read_error \n " ) ;
temp2 = ( tmp [ 0 ] < < 3 ) | ( tmp [ 1 ] > > 5 ) ;
temp2 * = 125 ;
return sprintf ( buf , " %d %d \n " , temp , temp2 ) ;
}
return sprintf ( buf , " %d \n " , temp ) ;
}
static ssize_t ctemp_show ( struct device * device ,
2017-08-26 22:04:37 +02:00
struct device_attribute * attr , char * buf )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = dev_get_drvdata ( device ) ;
struct i2c_adapter * adap ;
int temp ;
u8 tmp [ 2 ] ;
int num = attr - > attr . name [ 4 ] - 0x30 ;
adap = & dev - > i2c [ num ] . adap ;
if ( ! adap )
return 0 ;
if ( i2c_read_regs ( adap , 0x49 , 0 , tmp , 2 ) < 0 )
if ( i2c_read_regs ( adap , 0x4d , 0 , tmp , 2 ) < 0 )
return sprintf ( buf , " no sensor \n " ) ;
temp = tmp [ 0 ] * 1000 ;
return sprintf ( buf , " %d \n " , temp ) ;
}
static ssize_t mod_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
return sprintf ( buf , " %s:%s \n " ,
class_name [ dev - > port [ num ] . class ] ,
2015-10-22 14:51:36 +02:00
dev - > port [ num ] . type_name ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t led_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
return sprintf ( buf , " %d \n " , dev - > leds & ( 1 < < num ) ? 1 : 0 ) ;
}
static void ddb_set_led ( struct ddb * dev , int num , int val )
{
if ( ! dev - > link [ 0 ] . info - > led_num )
return ;
switch ( dev - > port [ num ] . class ) {
case DDB_PORT_TUNER :
switch ( dev - > port [ num ] . type ) {
case DDB_TUNER_DVBS_ST :
i2c_write_reg16 ( & dev - > i2c [ num ] . adap ,
0x69 , 0xf14c , val ? 2 : 0 ) ;
break ;
case DDB_TUNER_DVBCT_ST :
i2c_write_reg16 ( & dev - > i2c [ num ] . adap ,
0x1f , 0xf00e , 0 ) ;
i2c_write_reg16 ( & dev - > i2c [ num ] . adap ,
0x1f , 0xf00f , val ? 1 : 0 ) ;
break ;
2016-11-07 21:19:53 +01:00
case DDB_TUNER_XO2 . . . DDB_TUNER_DVBC2T2I_SONY :
2015-08-05 17:22:42 +02:00
{
u8 v ;
i2c_read_reg ( & dev - > i2c [ num ] . adap , 0x10 , 0x08 , & v ) ;
v = ( v & ~ 0x10 ) | ( val ? 0x10 : 0 ) ;
i2c_write_reg ( & dev - > i2c [ num ] . adap , 0x10 , 0x08 , v ) ;
break ;
}
default :
break ;
}
break ;
}
}
static ssize_t led_store ( struct device * device ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
2017-04-16 21:20:52 +02:00
u32 val ;
2015-08-05 17:22:42 +02:00
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val )
dev - > leds | = ( 1 < < num ) ;
else
dev - > leds & = ~ ( 1 < < num ) ;
ddb_set_led ( dev , num , val ) ;
return count ;
}
static ssize_t snr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
char snr [ 32 ] ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
if ( dev - > port [ num ] . type > = DDB_TUNER_XO2 ) {
if ( i2c_read_regs ( & dev - > i2c [ num ] . adap , 0x10 , 0x10 , snr , 16 ) < 0 )
return sprintf ( buf , " NO SNR \n " ) ;
snr [ 16 ] = 0 ;
} else {
/* serial number at 0x100-0x11f */
if ( i2c_read_regs16 ( & dev - > i2c [ num ] . adap ,
0x57 , 0x100 , snr , 32 ) < 0 )
if ( i2c_read_regs16 ( & dev - > i2c [ num ] . adap ,
0x50 , 0x100 , snr , 32 ) < 0 )
return sprintf ( buf , " NO SNR \n " ) ;
snr [ 31 ] = 0 ; /* in case it is not terminated on EEPROM */
}
return sprintf ( buf , " %s \n " , snr ) ;
}
static ssize_t snr_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
u8 snr [ 34 ] = { 0x01 , 0x00 } ;
return 0 ; /* NOE: remove completely? */
if ( count > 31 )
return - EINVAL ;
if ( dev - > port [ num ] . type > = DDB_TUNER_XO2 )
return - EINVAL ;
memcpy ( snr + 2 , buf , count ) ;
i2c_write ( & dev - > i2c [ num ] . adap , 0x57 , snr , 34 ) ;
i2c_write ( & dev - > i2c [ num ] . adap , 0x50 , snr , 34 ) ;
return count ;
}
static ssize_t bsnr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
char snr [ 16 ] ;
ddbridge_flashread ( dev , 0 , snr , 0x10 , 15 ) ;
snr [ 15 ] = 0 ; /* in case it is not terminated on EEPROM */
return sprintf ( buf , " %s \n " , snr ) ;
}
static ssize_t bpsnr_show ( struct device * device ,
2017-08-26 22:04:37 +02:00
struct device_attribute * attr , char * buf )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2017-07-11 20:27:42 +02:00
unsigned char snr [ 32 ] ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ! dev - > i2c_num )
return 0 ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( i2c_read_regs16 ( & dev - > i2c [ 0 ] . adap ,
0x50 , 0x0000 , snr , 32 ) < 0 | |
2016-03-24 12:10:20 +01:00
snr [ 0 ] = = 0xff )
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " NO SNR \n " ) ;
snr [ 31 ] = 0 ; /* in case it is not terminated on EEPROM */
return sprintf ( buf , " %s \n " , snr ) ;
}
2019-03-14 12:47:48 +01:00
static ssize_t gtl_snr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 6 ] - 0x30 ;
char snr [ 16 ] ;
ddbridge_flashread ( dev , num , snr , 0x10 , 15 ) ;
snr [ 15 ] = 0 ; /* in case it is not terminated on EEPROM */
return sprintf ( buf , " %s \n " , snr ) ;
}
static ssize_t gtl_snr_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
return 0 ;
}
2015-08-05 17:22:42 +02:00
static ssize_t redirect_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
return 0 ;
}
static ssize_t redirect_store ( struct device * device ,
struct device_attribute * attr ,
2016-05-31 16:53:04 +02:00
const char * buf , size_t count )
{
unsigned int i , p ;
int res ;
if ( sscanf ( buf , " %x %x \n " , & i , & p ) ! = 2 )
return - EINVAL ;
res = ddb_redirect ( i , p ) ;
if ( res < 0 )
return res ;
2017-08-25 23:30:58 +02:00
dev_info ( device , " redirect: %02x, %02x \n " , i , p ) ;
2016-05-31 16:53:04 +02:00
return count ;
}
2015-08-05 17:22:42 +02:00
static ssize_t gap_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
return sprintf ( buf , " %d \n " , dev - > port [ num ] . gap ) ;
}
static ssize_t gap_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
unsigned int val ;
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
2017-07-27 21:56:39 +02:00
if ( val > 128 )
2015-08-05 17:22:42 +02:00
return - EINVAL ;
2017-07-27 21:56:39 +02:00
if ( val = = 128 )
val = 0xffffffff ;
2015-08-05 17:22:42 +02:00
dev - > port [ num ] . gap = val ;
return count ;
}
2016-06-27 23:01:21 +02:00
static ssize_t obr_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
2017-04-16 21:20:52 +02:00
2016-06-27 23:01:21 +02:00
return sprintf ( buf , " %d \n " , dev - > port [ num ] . obr ) ;
}
static ssize_t obr_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 3 ] - 0x30 ;
unsigned int val ;
2017-04-16 21:20:52 +02:00
2016-06-27 23:01:21 +02:00
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val > 96000 )
return - EINVAL ;
dev - > port [ num ] . obr = val ;
return count ;
}
2015-08-05 17:22:42 +02:00
static ssize_t version_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
return sprintf ( buf , " %08x %08x \n " ,
2015-09-06 19:08:57 +02:00
dev - > link [ 0 ] . ids . hwid , dev - > link [ 0 ] . ids . regmapid ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t hwid_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2015-09-06 19:08:57 +02:00
return sprintf ( buf , " 0x%08X \n " , dev - > link [ 0 ] . ids . hwid ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t regmap_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2015-09-06 19:08:57 +02:00
return sprintf ( buf , " 0x%08X \n " , dev - > link [ 0 ] . ids . regmapid ) ;
2015-08-05 17:22:42 +02:00
}
static ssize_t vlan_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " %u \n " , dev - > vlan ) ;
}
static ssize_t vlan_store ( struct device * device , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ddb * dev = dev_get_drvdata ( device ) ;
unsigned int val ;
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
if ( val > 1 )
return - EINVAL ;
if ( ! dev - > link [ 0 ] . info - > ns_num )
return - EINVAL ;
ddbwritel ( dev , 14 + ( val ? 4 : 0 ) , ETHER_LENGTH ) ;
dev - > vlan = val ;
return count ;
}
static ssize_t fmode_show ( struct device * device ,
2017-08-26 22:04:37 +02:00
struct device_attribute * attr , char * buf )
2015-08-05 17:22:42 +02:00
{
int num = attr - > attr . name [ 5 ] - 0x30 ;
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
return sprintf ( buf , " %u \n " , dev - > link [ num ] . lnb . fmode ) ;
}
2015-09-06 19:08:57 +02:00
static ssize_t devid_show ( struct device * device ,
struct device_attribute * attr , char * buf )
{
int num = attr - > attr . name [ 5 ] - 0x30 ;
struct ddb * dev = dev_get_drvdata ( device ) ;
2016-03-24 12:10:20 +01:00
2015-09-06 19:08:57 +02:00
return sprintf ( buf , " %08x \n " , dev - > link [ num ] . ids . devid ) ;
}
2015-08-05 17:22:42 +02:00
static ssize_t fmode_store ( struct device * device , struct device_attribute * attr ,
2017-08-26 22:04:37 +02:00
const char * buf , size_t count )
2015-08-05 17:22:42 +02:00
{
struct ddb * dev = dev_get_drvdata ( device ) ;
int num = attr - > attr . name [ 5 ] - 0x30 ;
unsigned int val ;
if ( sscanf ( buf , " %u \n " , & val ) ! = 1 )
return - EINVAL ;
2018-06-23 16:44:16 +02:00
if ( val > 4 )
2015-08-05 17:22:42 +02:00
return - EINVAL ;
2017-08-27 23:54:49 +02:00
ddb_lnb_init_fmode ( dev , & dev - > link [ num ] , val ) ;
2015-08-05 17:22:42 +02:00
return count ;
}
static struct device_attribute ddb_attrs [ ] = {
__ATTR_RO ( version ) ,
__ATTR_RO ( ports ) ,
__ATTR_RO ( ts_irq ) ,
__ATTR_RO ( i2c_irq ) ,
__ATTR ( gap0 , 0664 , gap_show , gap_store ) ,
__ATTR ( gap1 , 0664 , gap_show , gap_store ) ,
__ATTR ( gap2 , 0664 , gap_show , gap_store ) ,
__ATTR ( gap3 , 0664 , gap_show , gap_store ) ,
2016-06-27 23:01:21 +02:00
__ATTR ( obr0 , 0664 , obr_show , obr_store ) ,
__ATTR ( obr1 , 0664 , obr_show , obr_store ) ,
__ATTR ( obr2 , 0664 , obr_show , obr_store ) ,
__ATTR ( obr3 , 0664 , obr_show , obr_store ) ,
2015-08-05 17:22:42 +02:00
__ATTR ( vlan , 0664 , vlan_show , vlan_store ) ,
__ATTR ( fmode0 , 0664 , fmode_show , fmode_store ) ,
__ATTR ( fmode1 , 0664 , fmode_show , fmode_store ) ,
__ATTR ( fmode2 , 0664 , fmode_show , fmode_store ) ,
__ATTR ( fmode3 , 0664 , fmode_show , fmode_store ) ,
2015-09-06 19:08:57 +02:00
__ATTR_MRO ( devid0 , devid_show ) ,
__ATTR_MRO ( devid1 , devid_show ) ,
__ATTR_MRO ( devid2 , devid_show ) ,
__ATTR_MRO ( devid3 , devid_show ) ,
2015-08-05 17:22:42 +02:00
__ATTR_RO ( hwid ) ,
__ATTR_RO ( regmap ) ,
__ATTR ( redirect , 0664 , redirect_show , redirect_store ) ,
__ATTR_MRO ( snr , bsnr_show ) ,
__ATTR_RO ( bpsnr ) ,
__ATTR_NULL ,
} ;
static struct device_attribute ddb_attrs_temp [ ] = {
2018-05-25 23:05:26 +02:00
__ATTR_MRO ( temp , temp_show ) ,
__ATTR_MRO ( templ1 , temp_show ) ,
__ATTR_MRO ( templ2 , temp_show ) ,
__ATTR_MRO ( templ3 , temp_show ) ,
2015-08-05 17:22:42 +02:00
} ;
static struct device_attribute ddb_attrs_mod [ ] = {
__ATTR_MRO ( mod0 , mod_show ) ,
__ATTR_MRO ( mod1 , mod_show ) ,
__ATTR_MRO ( mod2 , mod_show ) ,
__ATTR_MRO ( mod3 , mod_show ) ,
__ATTR_MRO ( mod4 , mod_show ) ,
__ATTR_MRO ( mod5 , mod_show ) ,
__ATTR_MRO ( mod6 , mod_show ) ,
__ATTR_MRO ( mod7 , mod_show ) ,
__ATTR_MRO ( mod8 , mod_show ) ,
__ATTR_MRO ( mod9 , mod_show ) ,
} ;
static struct device_attribute ddb_attrs_fan [ ] = {
__ATTR ( fan , 0664 , fan_show , fan_store ) ,
} ;
static struct device_attribute ddb_attrs_snr [ ] = {
__ATTR ( snr0 , 0664 , snr_show , snr_store ) ,
__ATTR ( snr1 , 0664 , snr_show , snr_store ) ,
__ATTR ( snr2 , 0664 , snr_show , snr_store ) ,
__ATTR ( snr3 , 0664 , snr_show , snr_store ) ,
} ;
2019-03-14 12:47:48 +01:00
static struct device_attribute ddb_attrs_gtl_snr [ ] = {
__ATTR ( gtlsnr1 , 0664 , gtl_snr_show , gtl_snr_store ) ,
__ATTR ( gtlsnr2 , 0664 , gtl_snr_show , gtl_snr_store ) ,
__ATTR ( gtlsnr3 , 0664 , gtl_snr_show , gtl_snr_store ) ,
} ;
2015-08-05 17:22:42 +02:00
static struct device_attribute ddb_attrs_ctemp [ ] = {
__ATTR_MRO ( temp0 , ctemp_show ) ,
__ATTR_MRO ( temp1 , ctemp_show ) ,
__ATTR_MRO ( temp2 , ctemp_show ) ,
__ATTR_MRO ( temp3 , ctemp_show ) ,
} ;
static struct device_attribute ddb_attrs_led [ ] = {
__ATTR ( led0 , 0664 , led_show , led_store ) ,
__ATTR ( led1 , 0664 , led_show , led_store ) ,
__ATTR ( led2 , 0664 , led_show , led_store ) ,
__ATTR ( led3 , 0664 , led_show , led_store ) ,
} ;
2016-08-29 18:44:53 +02:00
static struct device_attribute ddb_attrs_fanspeed [ ] = {
__ATTR_MRO ( fanspeed0 , fanspeed_show ) ,
__ATTR_MRO ( fanspeed1 , fanspeed_show ) ,
__ATTR_MRO ( fanspeed2 , fanspeed_show ) ,
__ATTR_MRO ( fanspeed3 , fanspeed_show ) ,
} ;
2015-08-05 17:22:42 +02:00
static struct class ddb_class = {
. name = " ddbridge " ,
. owner = THIS_MODULE ,
. devnode = ddb_devnode ,
} ;
2017-08-02 17:40:24 +02:00
int ddb_class_create ( void )
2015-08-05 17:22:42 +02:00
{
ddb_major = register_chrdev ( 0 , DDB_NAME , & ddb_fops ) ;
if ( ddb_major < 0 )
return ddb_major ;
if ( class_register ( & ddb_class ) < 0 )
return - 1 ;
return 0 ;
}
2017-08-02 17:40:24 +02:00
void ddb_class_destroy ( void )
2015-08-05 17:22:42 +02:00
{
class_unregister ( & ddb_class ) ;
unregister_chrdev ( ddb_major , DDB_NAME ) ;
}
static void ddb_device_attrs_del ( struct ddb * dev )
{
int i ;
2016-08-29 18:44:53 +02:00
for ( i = 0 ; i < 4 ; i + + )
2016-08-29 21:13:48 +02:00
if ( dev - > link [ i ] . info & &
dev - > link [ i ] . info - > tempmon_irq )
2017-04-16 21:20:52 +02:00
device_remove_file ( dev - > ddb_dev ,
& ddb_attrs_fanspeed [ i ] ) ;
2018-05-25 23:05:26 +02:00
for ( i = 0 ; i < 4 ; i + + )
if ( dev - > link [ i ] . info & &
dev - > link [ i ] . info - > temp_num )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_temp [ i ] ) ;
2015-08-05 17:22:42 +02:00
for ( i = 0 ; i < dev - > link [ 0 ] . info - > port_num ; i + + )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_mod [ i ] ) ;
for ( i = 0 ; i < dev - > link [ 0 ] . info - > fan_num ; i + + )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_fan [ i ] ) ;
for ( i = 0 ; i < dev - > i2c_num & & i < 4 ; i + + ) {
if ( dev - > link [ 0 ] . info - > led_num )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_led [ i ] ) ;
device_remove_file ( dev - > ddb_dev , & ddb_attrs_snr [ i ] ) ;
device_remove_file ( dev - > ddb_dev , & ddb_attrs_ctemp [ i ] ) ;
}
2019-03-14 12:47:48 +01:00
if ( dev - > link [ 0 ] . info - > regmap - > gtl )
for ( i = 0 ; i < dev - > link [ 0 ] . info - > regmap - > gtl - > num ; i + + )
device_remove_file ( dev - > ddb_dev , & ddb_attrs_gtl_snr [ i ] ) ;
2017-08-26 22:04:37 +02:00
for ( i = 0 ; ddb_attrs [ i ] . attr . name ; i + + )
2015-08-05 17:22:42 +02:00
device_remove_file ( dev - > ddb_dev , & ddb_attrs [ i ] ) ;
}
static int ddb_device_attrs_add ( struct ddb * dev )
{
int i ;
2017-08-26 22:04:37 +02:00
for ( i = 0 ; ddb_attrs [ i ] . attr . name ; i + + )
2015-08-05 17:22:42 +02:00
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs [ i ] ) )
goto fail ;
2018-05-25 23:05:26 +02:00
for ( i = 0 ; i < 4 ; i + + )
if ( dev - > link [ i ] . info & &
dev - > link [ i ] . info - > temp_num )
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_temp [ i ] ) )
goto fail ;
2016-07-31 21:41:03 +02:00
for ( i = 0 ; ( i < dev - > link [ 0 ] . info - > port_num ) & & ( i < 10 ) ; i + + )
2015-08-05 17:22:42 +02:00
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_mod [ i ] ) )
goto fail ;
for ( i = 0 ; i < dev - > link [ 0 ] . info - > fan_num ; i + + )
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_fan [ i ] ) )
goto fail ;
2016-07-31 21:41:03 +02:00
for ( i = 0 ; ( i < dev - > i2c_num ) & & ( i < 4 ) ; i + + ) {
2015-08-05 17:22:42 +02:00
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_snr [ i ] ) )
goto fail ;
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_ctemp [ i ] ) )
goto fail ;
if ( dev - > link [ 0 ] . info - > led_num )
if ( device_create_file ( dev - > ddb_dev ,
& ddb_attrs_led [ i ] ) )
goto fail ;
}
2019-03-14 12:47:48 +01:00
if ( dev - > link [ 0 ] . info - > regmap - > gtl )
for ( i = 0 ; i < dev - > link [ 0 ] . info - > regmap - > gtl - > num ; i + + )
if ( device_create_file ( dev - > ddb_dev , & ddb_attrs_gtl_snr [ i ] ) )
goto fail ;
2016-08-29 18:44:53 +02:00
for ( i = 0 ; i < 4 ; i + + )
if ( dev - > link [ i ] . info & &
dev - > link [ i ] . info - > tempmon_irq )
if ( device_create_file ( dev - > ddb_dev ,
& ddb_attrs_fanspeed [ i ] ) )
goto fail ;
2015-08-05 17:22:42 +02:00
return 0 ;
fail :
return - 1 ;
}
static int ddb_device_create ( struct ddb * dev )
{
int res = 0 ;
if ( ddb_num = = DDB_MAX_ADAPTER )
return - ENOMEM ;
mutex_lock ( & ddb_mutex ) ;
dev - > nr = ddb_num ;
2020-01-16 10:57:53 +01:00
atomic_set ( & dev - > ddb_dev_users , 1 ) ;
2015-08-05 17:22:42 +02:00
ddbs [ dev - > nr ] = dev ;
dev - > ddb_dev = device_create ( & ddb_class , dev - > dev ,
MKDEV ( ddb_major , dev - > nr ) ,
dev , " ddbridge%d " , dev - > nr ) ;
if ( IS_ERR ( dev - > ddb_dev ) ) {
res = PTR_ERR ( dev - > ddb_dev ) ;
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Could not create ddbridge%d \n " , dev - > nr ) ;
2015-08-05 17:22:42 +02:00
goto fail ;
}
res = ddb_device_attrs_add ( dev ) ;
if ( res ) {
ddb_device_attrs_del ( dev ) ;
device_destroy ( & ddb_class , MKDEV ( ddb_major , dev - > nr ) ) ;
2017-12-11 16:20:24 +01:00
ddbs [ dev - > nr ] = NULL ;
2015-08-05 17:22:42 +02:00
dev - > ddb_dev = ERR_PTR ( - ENODEV ) ;
2017-08-26 22:04:37 +02:00
} else {
2015-08-05 17:22:42 +02:00
ddb_num + + ;
2017-08-26 22:04:37 +02:00
}
2015-08-05 17:22:42 +02:00
fail :
mutex_unlock ( & ddb_mutex ) ;
return res ;
}
2017-08-02 17:40:24 +02:00
void ddb_device_destroy ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
if ( IS_ERR ( dev - > ddb_dev ) )
return ;
ddb_device_attrs_del ( dev ) ;
device_destroy ( & ddb_class , MKDEV ( ddb_major , dev - > nr ) ) ;
}
2016-04-15 18:08:51 +02:00
# define LINK_IRQ_HANDLE(_l, _nr) \
2017-10-25 23:03:16 +02:00
do { if ( ( s & ( 1UL < < ( _nr ) ) ) & & dev - > link [ _l ] . irq [ _nr ] . handler ) \
dev - > link [ _l ] . irq [ _nr ] . handler ( dev - > link [ _l ] . irq [ _nr ] . data ) ; } \
2015-08-05 17:22:42 +02:00
while ( 0 )
2017-10-25 23:03:16 +02:00
static void gtl_link_handler ( void * priv )
2015-08-05 17:22:42 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb * dev = ( struct ddb * ) priv ;
2015-08-31 20:53:22 +02:00
u32 regs = dev - > link [ 0 ] . info - > regmap - > gtl - > base ;
2017-08-26 10:32:53 +02:00
2020-01-16 10:55:25 +01:00
dev_info ( dev - > dev , " GT link changed to %u \n " ,
2017-08-25 23:30:58 +02:00
( 1 & ddbreadl ( dev , regs ) ) ) ;
2015-08-05 17:22:42 +02:00
}
static void link_tasklet ( unsigned long data )
{
2017-08-26 22:04:37 +02:00
struct ddb_link * link = ( struct ddb_link * ) data ;
2015-08-05 17:22:42 +02:00
struct ddb * dev = link - > dev ;
2016-04-15 18:08:51 +02:00
u32 s , tag = DDB_LINK_TAG ( link - > nr ) ;
u32 l = link - > nr ;
2017-04-16 21:20:52 +02:00
2015-08-05 17:22:42 +02:00
s = ddbreadl ( dev , tag | INTERRUPT_STATUS ) ;
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " gtl_irq %08x = %08x \n " , tag | INTERRUPT_STATUS , s ) ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
if ( ! s )
return ;
ddbwritel ( dev , s , tag | INTERRUPT_ACK ) ;
2016-04-15 18:08:51 +02:00
LINK_IRQ_HANDLE ( l , 0 ) ;
LINK_IRQ_HANDLE ( l , 1 ) ;
LINK_IRQ_HANDLE ( l , 2 ) ;
LINK_IRQ_HANDLE ( l , 3 ) ;
2016-08-29 18:44:53 +02:00
LINK_IRQ_HANDLE ( l , 24 ) ;
2015-08-05 17:22:42 +02:00
}
2017-10-25 23:03:16 +02:00
static void gtl_irq_handler ( void * priv )
2015-08-05 17:22:42 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb_link * link = ( struct ddb_link * ) priv ;
2020-08-29 15:32:42 +02:00
# ifdef USE_LINK_TASKLET
tasklet_schedule ( & link - > tasklet ) ;
# else
2015-08-05 17:22:42 +02:00
struct ddb * dev = link - > dev ;
2016-04-15 18:08:51 +02:00
u32 s , l = link - > nr , tag = DDB_LINK_TAG ( link - > nr ) ;
2016-03-24 12:10:20 +01:00
2015-09-20 01:45:11 +02:00
while ( ( s = ddbreadl ( dev , tag | INTERRUPT_STATUS ) ) ) {
ddbwritel ( dev , s , tag | INTERRUPT_ACK ) ;
2016-04-15 18:08:51 +02:00
LINK_IRQ_HANDLE ( l , 0 ) ;
LINK_IRQ_HANDLE ( l , 1 ) ;
LINK_IRQ_HANDLE ( l , 2 ) ;
LINK_IRQ_HANDLE ( l , 3 ) ;
2016-08-29 18:44:53 +02:00
LINK_IRQ_HANDLE ( l , 24 ) ;
2015-09-20 01:45:11 +02:00
}
2015-08-05 17:22:42 +02:00
# endif
}
static int ddb_gtl_init_link ( struct ddb * dev , u32 l )
{
struct ddb_link * link = & dev - > link [ l ] ;
u32 regs = dev - > link [ 0 ] . info - > regmap - > gtl - > base +
( l - 1 ) * dev - > link [ 0 ] . info - > regmap - > gtl - > size ;
2016-10-10 00:19:16 +02:00
u32 id , subid , base = dev - > link [ 0 ] . info - > regmap - > irq_base_gtl ;
2016-03-24 12:10:20 +01:00
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Checking GT link %u: regs = %08x \n " , l , regs ) ;
2017-08-26 10:32:53 +02:00
2015-08-05 17:22:42 +02:00
spin_lock_init ( & link - > lock ) ;
mutex_init ( & link - > lnb . lock ) ;
2015-08-31 20:53:22 +02:00
link - > lnb . fmode = 0xffffffff ;
2015-08-05 17:22:42 +02:00
mutex_init ( & link - > flash_mutex ) ;
2016-05-03 22:05:29 +02:00
link - > nr = l ;
link - > dev = dev ;
link - > regs = regs ;
2015-08-05 17:22:42 +02:00
if ( ! ( 1 & ddbreadl ( dev , regs ) ) ) {
u32 c ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( c = 0 ; c < 5 ; c + + ) {
ddbwritel ( dev , 2 , regs ) ;
msleep ( 20 ) ;
ddbwritel ( dev , 0 , regs ) ;
msleep ( 200 ) ;
if ( 1 & ddbreadl ( dev , regs ) )
break ;
}
2018-08-13 15:05:43 +02:00
if ( c = = 5 ) {
ddbwritel ( dev , 8 , regs ) ;
2015-08-05 17:22:42 +02:00
return - 1 ;
2018-08-13 15:05:43 +02:00
}
2015-08-05 17:22:42 +02:00
}
id = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 8 ) ;
2016-10-10 00:19:16 +02:00
subid = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 12 ) ;
2017-07-24 22:24:47 +02:00
link - > info = get_ddb_info ( id & 0xffff , id > > 16 ,
subid & 0xffff , subid > > 16 ) ;
if ( link - > info - > type ! = DDB_OCTOPUS_MAX_CT & &
2017-12-05 19:59:23 +01:00
link - > info - > type ! = DDB_OCTOPUS_MAX & &
2020-08-29 15:32:42 +02:00
link - > info - > type ! = DDB_OCTOPUS_MCI ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev ,
" Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first. " ,
2017-10-25 23:03:16 +02:00
id ) ;
2015-08-05 17:22:42 +02:00
return - 1 ;
}
2015-09-06 19:08:57 +02:00
link - > ids . devid = id ;
2016-03-24 12:10:20 +01:00
2016-05-06 00:55:41 +02:00
ddbwritel ( dev , 1 , regs + 0x20 ) ;
2017-10-25 23:03:16 +02:00
ddb_irq_set ( dev , 0 , base + l , gtl_irq_handler , link ) ;
2016-08-29 18:44:53 +02:00
dev - > link [ l ] . ids . hwid = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 0 ) ;
dev - > link [ l ] . ids . regmapid = ddbreadl ( dev , DDB_LINK_TAG ( l ) | 4 ) ;
2016-10-10 00:19:16 +02:00
dev - > link [ l ] . ids . vendor = id & 0xffff ;
dev - > link [ l ] . ids . device = id > > 16 ;
dev - > link [ l ] . ids . subvendor = subid & 0xffff ;
dev - > link [ l ] . ids . subdevice = subid > > 16 ;
2016-08-29 18:44:53 +02:00
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " GTL %s \n " , dev - > link [ l ] . info - > name ) ;
2016-08-29 18:44:53 +02:00
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " GTL HW %08x REGMAP %08x \n " ,
dev - > link [ l ] . ids . hwid ,
dev - > link [ l ] . ids . regmapid ) ;
dev_info ( dev - > dev , " GTL ID %08x \n " ,
ddbreadl ( dev , DDB_LINK_TAG ( l ) | 8 ) ) ;
2016-03-24 12:10:20 +01:00
2017-08-26 22:04:37 +02:00
tasklet_init ( & link - > tasklet , link_tasklet , ( unsigned long ) link ) ;
2015-08-05 17:22:42 +02:00
ddbwritel ( dev , 0xffffffff , DDB_LINK_TAG ( l ) | INTERRUPT_ACK ) ;
2016-08-29 18:44:53 +02:00
ddbwritel ( dev , 0x0100000f , DDB_LINK_TAG ( l ) | INTERRUPT_ENABLE ) ;
2015-08-05 17:22:42 +02:00
return 0 ;
}
static int ddb_gtl_init ( struct ddb * dev )
{
2016-05-02 16:27:32 +02:00
u32 l , base = dev - > link [ 0 ] . info - > regmap - > irq_base_gtl ;
2015-08-05 17:22:42 +02:00
2017-10-25 23:03:16 +02:00
ddb_irq_set ( dev , 0 , base , gtl_link_handler , dev ) ;
2016-03-24 12:10:20 +01:00
for ( l = 1 ; l < dev - > link [ 0 ] . info - > regmap - > gtl - > num + 1 ; l + + )
2015-08-05 17:22:42 +02:00
ddb_gtl_init_link ( dev , l ) ;
return 0 ;
}
2016-08-29 18:44:53 +02:00
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void tempmon_setfan ( struct ddb_link * link )
{
u32 temp , temp2 , pwm ;
2017-04-16 21:20:52 +02:00
if ( ( ddblreadl ( link , TEMPMON_CONTROL ) &
TEMPMON_CONTROL_OVERTEMP ) ! = 0 ) {
2017-08-25 23:30:58 +02:00
dev_info ( link - > dev - > dev , " Over temperature condition \n " ) ;
2017-08-26 22:04:37 +02:00
link - > over_temperature_error = 1 ;
2016-08-29 18:44:53 +02:00
}
temp = ( ddblreadl ( link , TEMPMON_SENSOR0 ) > > 8 ) & 0xFF ;
if ( temp & 0x80 )
temp = 0 ;
temp2 = ( ddblreadl ( link , TEMPMON_SENSOR1 ) > > 8 ) & 0xFF ;
if ( temp2 & 0x80 )
temp2 = 0 ;
if ( temp2 > temp )
temp = temp2 ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
pwm = ( ddblreadl ( link , TEMPMON_FANCONTROL ) > > 8 ) & 0x0F ;
if ( pwm > 10 )
2017-04-16 21:20:52 +02:00
pwm = 10 ;
2016-08-29 18:44:53 +02:00
if ( temp > = link - > temp_tab [ pwm ] ) {
2017-04-16 21:20:52 +02:00
while ( pwm < 10 & & temp > = link - > temp_tab [ pwm + 1 ] )
2016-08-29 18:44:53 +02:00
pwm + = 1 ;
} else {
2019-08-05 16:01:12 +02:00
while ( pwm > 1 & & temp < ( link - > temp_tab [ pwm ] - 2 ) )
2016-08-29 18:44:53 +02:00
pwm - = 1 ;
}
ddblwritel ( link , ( pwm < < 8 ) , TEMPMON_FANCONTROL ) ;
2017-01-19 16:37:50 +01:00
}
2016-08-29 18:44:53 +02:00
2017-10-25 23:03:16 +02:00
static void temp_handler ( void * data )
2016-08-29 18:44:53 +02:00
{
2017-08-26 22:04:37 +02:00
struct ddb_link * link = ( struct ddb_link * ) data ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
spin_lock ( & link - > temp_lock ) ;
tempmon_setfan ( link ) ;
spin_unlock ( & link - > temp_lock ) ;
}
2017-08-26 22:04:37 +02:00
static int tempmon_init ( struct ddb_link * link , int first_time )
2016-08-29 18:44:53 +02:00
{
struct ddb * dev = link - > dev ;
int status = 0 ;
u32 l = link - > nr ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
spin_lock_irq ( & link - > temp_lock ) ;
2017-08-26 22:04:37 +02:00
if ( first_time ) {
2017-08-26 10:32:53 +02:00
static u8 temperature_table [ 11 ] = {
2017-04-16 21:20:52 +02:00
30 , 35 , 40 , 45 , 50 , 55 , 60 , 65 , 70 , 75 , 80 } ;
2017-08-26 10:32:53 +02:00
memcpy ( link - > temp_tab , temperature_table ,
sizeof ( temperature_table ) ) ;
2016-08-29 18:44:53 +02:00
}
2017-10-25 23:03:16 +02:00
ddb_irq_set ( dev , l , link - > info - > tempmon_irq , temp_handler , link ) ;
2016-08-29 18:44:53 +02:00
ddblwritel ( link , ( TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN |
TEMPMON_CONTROL_INTENABLE ) ,
TEMPMON_CONTROL ) ;
ddblwritel ( link , ( 3 < < 8 ) , TEMPMON_FANCONTROL ) ;
2017-04-16 21:20:52 +02:00
2017-08-26 22:04:37 +02:00
link - > over_temperature_error =
2017-04-16 21:20:52 +02:00
( ( ddblreadl ( link , TEMPMON_CONTROL ) &
TEMPMON_CONTROL_OVERTEMP ) ! = 0 ) ;
2017-08-26 22:04:37 +02:00
if ( link - > over_temperature_error ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev , " Over temperature condition \n " ) ;
2016-08-29 18:44:53 +02:00
status = - 1 ;
}
tempmon_setfan ( link ) ;
spin_unlock_irq ( & link - > temp_lock ) ;
return status ;
}
static int ddb_init_tempmon ( struct ddb_link * link )
{
2017-09-08 14:47:14 +02:00
const struct ddb_info * info = link - > info ;
2017-04-16 21:20:52 +02:00
2016-08-29 18:44:53 +02:00
if ( ! info - > tempmon_irq )
2017-02-09 10:12:43 +01:00
return 0 ;
2016-08-29 18:44:53 +02:00
if ( info - > type = = DDB_OCTOPUS_MAX | |
2017-08-26 10:32:53 +02:00
info - > type = = DDB_OCTOPUS_MAX_CT )
2016-08-29 18:44:53 +02:00
if ( link - > ids . regmapid < 0x00010002 )
2017-02-09 10:12:43 +01:00
return 0 ;
2016-08-29 18:44:53 +02:00
spin_lock_init ( & link - > temp_lock ) ;
2017-02-09 10:12:43 +01:00
return tempmon_init ( link , 1 ) ;
2016-08-29 18:44:53 +02:00
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
2015-08-05 17:22:42 +02:00
static int ddb_init_boards ( struct ddb * dev )
{
2017-09-08 14:47:14 +02:00
const struct ddb_info * info ;
2016-08-29 18:44:53 +02:00
struct ddb_link * link ;
2015-08-05 17:22:42 +02:00
u32 l ;
2016-03-24 12:10:20 +01:00
2015-08-05 17:22:42 +02:00
for ( l = 0 ; l < DDB_MAX_LINK ; l + + ) {
2016-08-29 18:44:53 +02:00
link = & dev - > link [ l ] ;
info = link - > info ;
2015-08-05 17:22:42 +02:00
if ( ! info )
continue ;
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev ,
" link %u vendor %04x device %04x subvendor %04x subdevice %04x \n " ,
l ,
2017-08-26 10:32:53 +02:00
dev - > link [ l ] . ids . vendor ,
dev - > link [ l ] . ids . device ,
dev - > link [ l ] . ids . subvendor ,
dev - > link [ l ] . ids . subdevice ) ;
2015-08-05 17:22:42 +02:00
if ( info - > board_control ) {
ddbwritel ( dev , 0 , DDB_LINK_TAG ( l ) | BOARD_CONTROL ) ;
msleep ( 100 ) ;
2016-03-24 12:10:20 +01:00
ddbwritel ( dev , info - > board_control_2 ,
DDB_LINK_TAG ( l ) | BOARD_CONTROL ) ;
2015-08-05 17:22:42 +02:00
usleep_range ( 2000 , 3000 ) ;
2016-03-24 12:10:20 +01:00
ddbwritel ( dev , info - > board_control_2 |
info - > board_control ,
2015-08-05 17:22:42 +02:00
DDB_LINK_TAG ( l ) | BOARD_CONTROL ) ;
usleep_range ( 2000 , 3000 ) ;
}
2016-08-29 18:44:53 +02:00
ddb_init_tempmon ( link ) ;
2020-12-01 15:58:35 +01:00
if ( info - > regmap - > mci ) {
if ( link - > info - > type = = DDB_OCTOPUS_MCI | |
( ( link - > info - > type = = DDB_MOD ) & &
( link - > ids . regmapid & 0xfff0 ) ) )
mci_init ( link ) ;
}
2015-08-05 17:22:42 +02:00
}
return 0 ;
}
2017-08-02 17:40:24 +02:00
int ddb_init ( struct ddb * dev )
2015-08-05 17:22:42 +02:00
{
2016-04-15 22:45:55 +02:00
mutex_init ( & dev - > link [ 0 ] . flash_mutex ) ;
2017-10-17 23:49:31 +02:00
mutex_init ( & dev - > ioctl_mutex ) ;
2016-04-15 22:45:55 +02:00
if ( no_init ) {
ddb_device_create ( dev ) ;
2017-04-16 21:20:52 +02:00
return 0 ;
2016-04-15 22:45:55 +02:00
}
2015-08-05 17:22:42 +02:00
if ( dev - > link [ 0 ] . info - > ns_num ) {
ddbwritel ( dev , 1 , ETHER_CONTROL ) ;
dev - > vlan = vlan ;
ddbwritel ( dev , 14 + ( dev - > vlan ? 4 : 0 ) , ETHER_LENGTH ) ;
}
mutex_init ( & dev - > link [ 0 ] . lnb . lock ) ;
2017-04-16 21:20:52 +02:00
2015-08-05 17:22:42 +02:00
if ( dev - > link [ 0 ] . info - > regmap - > gtl )
ddb_gtl_init ( dev ) ;
ddb_init_boards ( dev ) ;
if ( ddb_i2c_init ( dev ) < 0 )
goto fail ;
ddb_ports_init ( dev ) ;
2017-09-09 00:21:11 +02:00
if ( dev - > link [ 0 ] . info - > type = = DDB_MOD )
ddbridge_mod_init ( dev ) ;
2015-08-05 17:22:42 +02:00
if ( ddb_buffers_alloc ( dev ) < 0 ) {
2017-08-25 23:30:58 +02:00
dev_info ( dev - > dev ,
" Could not allocate buffer memory \n " ) ;
2015-08-05 17:22:42 +02:00
goto fail2 ;
}
if ( ddb_ports_attach ( dev ) < 0 )
goto fail3 ;
ddb_nsd_attach ( dev ) ;
ddb_device_create ( dev ) ;
if ( dev - > link [ 0 ] . info - > fan_num ) {
ddbwritel ( dev , 1 , GPIO_DIRECTION ) ;
ddbwritel ( dev , 1 , GPIO_OUTPUT ) ;
}
return 0 ;
fail3 :
ddb_ports_detach ( dev ) ;
2017-08-25 23:30:58 +02:00
dev_err ( dev - > dev , " fail3 \n " ) ;
2015-08-05 17:22:42 +02:00
ddb_ports_release ( dev ) ;
fail2 :
2017-08-25 23:30:58 +02:00
dev_err ( dev - > dev , " fail2 \n " ) ;
2015-08-05 17:22:42 +02:00
ddb_buffers_free ( dev ) ;
ddb_i2c_release ( dev ) ;
fail :
2017-08-25 23:30:58 +02:00
dev_err ( dev - > dev , " fail1 \n " ) ;
2015-08-05 17:22:42 +02:00
return - 1 ;
}
2016-05-02 16:27:32 +02:00
static void ddb_reset_io ( struct ddb * dev , u32 reg )
{
ddbwritel ( dev , 0x00 , reg ) ;
ddbwritel ( dev , 0x02 , reg ) ;
ddbwritel ( dev , 0x00 , reg ) ;
}
2017-08-02 17:40:24 +02:00
void ddb_reset_ios ( struct ddb * dev )
2016-05-02 16:27:32 +02:00
{
u32 i ;
2017-09-08 14:47:14 +02:00
const struct ddb_regmap * rm = dev - > link [ 0 ] . info - > regmap ;
2017-04-16 21:20:52 +02:00
2016-05-02 16:27:32 +02:00
if ( rm - > input )
for ( i = 0 ; i < rm - > input - > num ; i + + )
2017-04-16 21:20:52 +02:00
ddb_reset_io ( dev ,
rm - > input - > base + i * rm - > input - > size ) ;
2016-05-02 16:27:32 +02:00
if ( rm - > output )
for ( i = 0 ; i < rm - > output - > num ; i + + )
2017-04-16 21:20:52 +02:00
ddb_reset_io ( dev ,
rm - > output - > base + i * rm - > output - > size ) ;
2016-05-02 16:27:32 +02:00
usleep_range ( 5000 , 6000 ) ;
}
2017-07-24 01:03:40 +02:00
2017-08-02 17:40:24 +02:00
void ddb_unmap ( struct ddb * dev )
2017-07-24 01:03:40 +02:00
{
if ( dev - > regs )
iounmap ( dev - > regs ) ;
vfree ( dev ) ;
}
2017-10-22 20:58:58 +02:00
int ddb_exit_ddbridge ( int stage , int error )
{
switch ( stage ) {
default :
case 2 :
destroy_workqueue ( ddb_wq ) ;
2020-01-15 12:32:34 +01:00
/* fallthrough */
2017-10-22 20:58:58 +02:00
case 1 :
ddb_class_destroy ( ) ;
}
return error ;
}
int ddb_init_ddbridge ( void )
{
2017-10-23 00:14:39 +02:00
if ( dma_buf_num < 8 )
dma_buf_num = 8 ;
if ( dma_buf_num > 32 )
dma_buf_num = 32 ;
if ( dma_buf_size < 1 )
dma_buf_size = 1 ;
if ( dma_buf_size > 43 )
dma_buf_size = 43 ;
2018-01-01 21:03:27 +01:00
2017-10-22 20:58:58 +02:00
if ( ddb_class_create ( ) < 0 )
return - 1 ;
ddb_wq = alloc_workqueue ( " ddbridge " , 0 , 0 ) ;
if ( ! ddb_wq )
return ddb_exit_ddbridge ( 1 , - 1 ) ;
return 0 ;
}