18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * altera-ci.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2010,2011 NetUP Inc. 88c2ecf20Sopenharmony_ci * Copyright (C) 2010,2011 Igor M. Liplianin <liplianin@netup.ru> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * currently cx23885 GPIO's used. 138c2ecf20Sopenharmony_ci * GPIO-0 ~INT in 148c2ecf20Sopenharmony_ci * GPIO-1 TMS out 158c2ecf20Sopenharmony_ci * GPIO-2 ~reset chips out 168c2ecf20Sopenharmony_ci * GPIO-3 to GPIO-10 data/addr for CA in/out 178c2ecf20Sopenharmony_ci * GPIO-11 ~CS out 188c2ecf20Sopenharmony_ci * GPIO-12 AD_RG out 198c2ecf20Sopenharmony_ci * GPIO-13 ~WR out 208c2ecf20Sopenharmony_ci * GPIO-14 ~RD out 218c2ecf20Sopenharmony_ci * GPIO-15 ~RDY in 228c2ecf20Sopenharmony_ci * GPIO-16 TCK out 238c2ecf20Sopenharmony_ci * GPIO-17 TDO in 248c2ecf20Sopenharmony_ci * GPIO-18 TDI out 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Bit definitions for MC417_RWD and MC417_OEN registers 288c2ecf20Sopenharmony_ci * bits 31-16 298c2ecf20Sopenharmony_ci * +-----------+ 308c2ecf20Sopenharmony_ci * | Reserved | 318c2ecf20Sopenharmony_ci * +-----------+ 328c2ecf20Sopenharmony_ci * bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 338c2ecf20Sopenharmony_ci * +-------+-------+-------+-------+-------+-------+-------+-------+ 348c2ecf20Sopenharmony_ci * | TDI | TDO | TCK | RDY# | #RD | #WR | AD_RG | #CS | 358c2ecf20Sopenharmony_ci * +-------+-------+-------+-------+-------+-------+-------+-------+ 368c2ecf20Sopenharmony_ci * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 378c2ecf20Sopenharmony_ci * +-------+-------+-------+-------+-------+-------+-------+-------+ 388c2ecf20Sopenharmony_ci * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| 398c2ecf20Sopenharmony_ci * +-------+-------+-------+-------+-------+-------+-------+-------+ 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <media/dvb_demux.h> 458c2ecf20Sopenharmony_ci#include <media/dvb_frontend.h> 468c2ecf20Sopenharmony_ci#include "altera-ci.h" 478c2ecf20Sopenharmony_ci#include <media/dvb_ca_en50221.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* FPGA regs */ 508c2ecf20Sopenharmony_ci#define NETUP_CI_INT_CTRL 0x00 518c2ecf20Sopenharmony_ci#define NETUP_CI_BUSCTRL2 0x01 528c2ecf20Sopenharmony_ci#define NETUP_CI_ADDR0 0x04 538c2ecf20Sopenharmony_ci#define NETUP_CI_ADDR1 0x05 548c2ecf20Sopenharmony_ci#define NETUP_CI_DATA 0x06 558c2ecf20Sopenharmony_ci#define NETUP_CI_BUSCTRL 0x07 568c2ecf20Sopenharmony_ci#define NETUP_CI_PID_ADDR0 0x08 578c2ecf20Sopenharmony_ci#define NETUP_CI_PID_ADDR1 0x09 588c2ecf20Sopenharmony_ci#define NETUP_CI_PID_DATA 0x0a 598c2ecf20Sopenharmony_ci#define NETUP_CI_TSA_DIV 0x0c 608c2ecf20Sopenharmony_ci#define NETUP_CI_TSB_DIV 0x0d 618c2ecf20Sopenharmony_ci#define NETUP_CI_REVISION 0x0f 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* const for ci op */ 648c2ecf20Sopenharmony_ci#define NETUP_CI_FLG_CTL 1 658c2ecf20Sopenharmony_ci#define NETUP_CI_FLG_RD 1 668c2ecf20Sopenharmony_ci#define NETUP_CI_FLG_AD 1 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic unsigned int ci_dbg; 698c2ecf20Sopenharmony_cimodule_param(ci_dbg, int, 0644); 708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic unsigned int pid_dbg; 738c2ecf20Sopenharmony_cimodule_param(pid_dbg, int, 0644); 748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("altera FPGA CI module"); 778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Igor M. Liplianin <liplianin@netup.ru>"); 788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define ci_dbg_print(fmt, args...) \ 818c2ecf20Sopenharmony_ci do { \ 828c2ecf20Sopenharmony_ci if (ci_dbg) \ 838c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 848c2ecf20Sopenharmony_ci __func__, ##args); \ 858c2ecf20Sopenharmony_ci } while (0) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define pid_dbg_print(fmt, args...) \ 888c2ecf20Sopenharmony_ci do { \ 898c2ecf20Sopenharmony_ci if (pid_dbg) \ 908c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 918c2ecf20Sopenharmony_ci __func__, ##args); \ 928c2ecf20Sopenharmony_ci } while (0) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct altera_ci_state; 958c2ecf20Sopenharmony_cistruct netup_hw_pid_filter; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistruct fpga_internal { 988c2ecf20Sopenharmony_ci void *dev; 998c2ecf20Sopenharmony_ci struct mutex fpga_mutex;/* two CI's on the same fpga */ 1008c2ecf20Sopenharmony_ci struct netup_hw_pid_filter *pid_filt[2]; 1018c2ecf20Sopenharmony_ci struct altera_ci_state *state[2]; 1028c2ecf20Sopenharmony_ci struct work_struct work; 1038c2ecf20Sopenharmony_ci int (*fpga_rw) (void *dev, int flag, int data, int rw); 1048c2ecf20Sopenharmony_ci int cis_used; 1058c2ecf20Sopenharmony_ci int filts_used; 1068c2ecf20Sopenharmony_ci int strt_wrk; 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* stores all private variables for communication with CI */ 1108c2ecf20Sopenharmony_cistruct altera_ci_state { 1118c2ecf20Sopenharmony_ci struct fpga_internal *internal; 1128c2ecf20Sopenharmony_ci struct dvb_ca_en50221 ca; 1138c2ecf20Sopenharmony_ci int status; 1148c2ecf20Sopenharmony_ci int nr; 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* stores all private variables for hardware pid filtering */ 1188c2ecf20Sopenharmony_cistruct netup_hw_pid_filter { 1198c2ecf20Sopenharmony_ci struct fpga_internal *internal; 1208c2ecf20Sopenharmony_ci struct dvb_demux *demux; 1218c2ecf20Sopenharmony_ci /* save old functions */ 1228c2ecf20Sopenharmony_ci int (*start_feed)(struct dvb_demux_feed *feed); 1238c2ecf20Sopenharmony_ci int (*stop_feed)(struct dvb_demux_feed *feed); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci int status; 1268c2ecf20Sopenharmony_ci int nr; 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* internal params node */ 1308c2ecf20Sopenharmony_cistruct fpga_inode { 1318c2ecf20Sopenharmony_ci /* pointer for internal params, one for each pair of CI's */ 1328c2ecf20Sopenharmony_ci struct fpga_internal *internal; 1338c2ecf20Sopenharmony_ci struct fpga_inode *next_inode; 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* first internal params */ 1378c2ecf20Sopenharmony_cistatic struct fpga_inode *fpga_first_inode; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* find chip by dev */ 1408c2ecf20Sopenharmony_cistatic struct fpga_inode *find_inode(void *dev) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct fpga_inode *temp_chip = fpga_first_inode; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (temp_chip == NULL) 1458c2ecf20Sopenharmony_ci return temp_chip; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* 1488c2ecf20Sopenharmony_ci Search for the last fpga CI chip or 1498c2ecf20Sopenharmony_ci find it by dev */ 1508c2ecf20Sopenharmony_ci while ((temp_chip != NULL) && 1518c2ecf20Sopenharmony_ci (temp_chip->internal->dev != dev)) 1528c2ecf20Sopenharmony_ci temp_chip = temp_chip->next_inode; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return temp_chip; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci/* check demux */ 1578c2ecf20Sopenharmony_cistatic struct fpga_internal *check_filter(struct fpga_internal *temp_int, 1588c2ecf20Sopenharmony_ci void *demux_dev, int filt_nr) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci if (temp_int == NULL) 1618c2ecf20Sopenharmony_ci return NULL; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if ((temp_int->pid_filt[filt_nr]) == NULL) 1648c2ecf20Sopenharmony_ci return NULL; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (temp_int->pid_filt[filt_nr]->demux == demux_dev) 1678c2ecf20Sopenharmony_ci return temp_int; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return NULL; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* find chip by demux */ 1738c2ecf20Sopenharmony_cistatic struct fpga_inode *find_dinode(void *demux_dev) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct fpga_inode *temp_chip = fpga_first_inode; 1768c2ecf20Sopenharmony_ci struct fpga_internal *temp_int; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* 1798c2ecf20Sopenharmony_ci * Search of the last fpga CI chip or 1808c2ecf20Sopenharmony_ci * find it by demux 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci while (temp_chip != NULL) { 1838c2ecf20Sopenharmony_ci if (temp_chip->internal != NULL) { 1848c2ecf20Sopenharmony_ci temp_int = temp_chip->internal; 1858c2ecf20Sopenharmony_ci if (check_filter(temp_int, demux_dev, 0)) 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci if (check_filter(temp_int, demux_dev, 1)) 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci temp_chip = temp_chip->next_inode; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return temp_chip; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* deallocating chip */ 1988c2ecf20Sopenharmony_cistatic void remove_inode(struct fpga_internal *internal) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct fpga_inode *prev_node = fpga_first_inode; 2018c2ecf20Sopenharmony_ci struct fpga_inode *del_node = find_inode(internal->dev); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (del_node != NULL) { 2048c2ecf20Sopenharmony_ci if (del_node == fpga_first_inode) { 2058c2ecf20Sopenharmony_ci fpga_first_inode = del_node->next_inode; 2068c2ecf20Sopenharmony_ci } else { 2078c2ecf20Sopenharmony_ci while (prev_node->next_inode != del_node) 2088c2ecf20Sopenharmony_ci prev_node = prev_node->next_inode; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (del_node->next_inode == NULL) 2118c2ecf20Sopenharmony_ci prev_node->next_inode = NULL; 2128c2ecf20Sopenharmony_ci else 2138c2ecf20Sopenharmony_ci prev_node->next_inode = 2148c2ecf20Sopenharmony_ci prev_node->next_inode->next_inode; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci kfree(del_node); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* allocating new chip */ 2228c2ecf20Sopenharmony_cistatic struct fpga_inode *append_internal(struct fpga_internal *internal) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct fpga_inode *new_node = fpga_first_inode; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (new_node == NULL) { 2278c2ecf20Sopenharmony_ci new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); 2288c2ecf20Sopenharmony_ci fpga_first_inode = new_node; 2298c2ecf20Sopenharmony_ci } else { 2308c2ecf20Sopenharmony_ci while (new_node->next_inode != NULL) 2318c2ecf20Sopenharmony_ci new_node = new_node->next_inode; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci new_node->next_inode = 2348c2ecf20Sopenharmony_ci kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); 2358c2ecf20Sopenharmony_ci if (new_node->next_inode != NULL) 2368c2ecf20Sopenharmony_ci new_node = new_node->next_inode; 2378c2ecf20Sopenharmony_ci else 2388c2ecf20Sopenharmony_ci new_node = NULL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (new_node != NULL) { 2428c2ecf20Sopenharmony_ci new_node->internal = internal; 2438c2ecf20Sopenharmony_ci new_node->next_inode = NULL; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return new_node; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int netup_fpga_op_rw(struct fpga_internal *inter, int addr, 2508c2ecf20Sopenharmony_ci u8 val, u8 read) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0); 2538c2ecf20Sopenharmony_ci return inter->fpga_rw(inter->dev, 0, val, read); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/* flag - mem/io, read - read/write */ 2578c2ecf20Sopenharmony_cistatic int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, 2588c2ecf20Sopenharmony_ci u8 flag, u8 read, int addr, u8 val) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci struct altera_ci_state *state = en50221->data; 2628c2ecf20Sopenharmony_ci struct fpga_internal *inter = state->internal; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci u8 store; 2658c2ecf20Sopenharmony_ci int mem = 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (0 != slot) 2688c2ecf20Sopenharmony_ci return -EINVAL; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0); 2738c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0); 2748c2ecf20Sopenharmony_ci store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci store &= 0x0f; 2778c2ecf20Sopenharmony_ci store |= ((state->nr << 7) | (flag << 6)); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0); 2808c2ecf20Sopenharmony_ci mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__, 2858c2ecf20Sopenharmony_ci (read) ? "read" : "write", addr, 2868c2ecf20Sopenharmony_ci (flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem", 2878c2ecf20Sopenharmony_ci (read) ? mem : val); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return mem; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, 2938c2ecf20Sopenharmony_ci int slot, int addr) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, 2998c2ecf20Sopenharmony_ci int slot, int addr, u8 data) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci return altera_ci_op_cam(en50221, slot, 0, 0, addr, data); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, 3058c2ecf20Sopenharmony_ci int slot, u8 addr) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 3088c2ecf20Sopenharmony_ci NETUP_CI_FLG_RD, addr, 0); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, 3128c2ecf20Sopenharmony_ci u8 addr, u8 data) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct altera_ci_state *state = en50221->data; 3208c2ecf20Sopenharmony_ci struct fpga_internal *inter = state->internal; 3218c2ecf20Sopenharmony_ci /* reasonable timeout for CI reset is 10 seconds */ 3228c2ecf20Sopenharmony_ci unsigned long t_out = jiffies + msecs_to_jiffies(9999); 3238c2ecf20Sopenharmony_ci int ret; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (0 != slot) 3288c2ecf20Sopenharmony_ci return -EINVAL; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); 3338c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 3348c2ecf20Sopenharmony_ci (ret & 0xcf) | (1 << (5 - state->nr)), 0); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci for (;;) { 3398c2ecf20Sopenharmony_ci msleep(50); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 3448c2ecf20Sopenharmony_ci 0, NETUP_CI_FLG_RD); 3458c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if ((ret & (1 << (5 - state->nr))) == 0) 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci if (time_after(jiffies, t_out)) 3508c2ecf20Sopenharmony_ci break; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ci_dbg_print("%s: %d msecs\n", __func__, 3558c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out)); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci /* not implemented */ 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct altera_ci_state *state = en50221->data; 3698c2ecf20Sopenharmony_ci struct fpga_internal *inter = state->internal; 3708c2ecf20Sopenharmony_ci int ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (0 != slot) 3758c2ecf20Sopenharmony_ci return -EINVAL; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); 3808c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 3818c2ecf20Sopenharmony_ci (ret & 0x0f) | (1 << (3 - state->nr)), 0); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/* work handler */ 3898c2ecf20Sopenharmony_cistatic void netup_read_ci_status(struct work_struct *work) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct fpga_internal *inter = 3928c2ecf20Sopenharmony_ci container_of(work, struct fpga_internal, work); 3938c2ecf20Sopenharmony_ci int ret; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 3988c2ecf20Sopenharmony_ci /* ack' irq */ 3998c2ecf20Sopenharmony_ci ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD); 4008c2ecf20Sopenharmony_ci ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (inter->state[1] != NULL) { 4058c2ecf20Sopenharmony_ci inter->state[1]->status = 4068c2ecf20Sopenharmony_ci ((ret & 1) == 0 ? 4078c2ecf20Sopenharmony_ci DVB_CA_EN50221_POLL_CAM_PRESENT | 4088c2ecf20Sopenharmony_ci DVB_CA_EN50221_POLL_CAM_READY : 0); 4098c2ecf20Sopenharmony_ci ci_dbg_print("%s: setting CI[1] status = 0x%x\n", 4108c2ecf20Sopenharmony_ci __func__, inter->state[1]->status); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (inter->state[0] != NULL) { 4148c2ecf20Sopenharmony_ci inter->state[0]->status = 4158c2ecf20Sopenharmony_ci ((ret & 2) == 0 ? 4168c2ecf20Sopenharmony_ci DVB_CA_EN50221_POLL_CAM_PRESENT | 4178c2ecf20Sopenharmony_ci DVB_CA_EN50221_POLL_CAM_READY : 0); 4188c2ecf20Sopenharmony_ci ci_dbg_print("%s: setting CI[0] status = 0x%x\n", 4198c2ecf20Sopenharmony_ci __func__, inter->state[0]->status); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* CI irq handler */ 4248c2ecf20Sopenharmony_ciint altera_ci_irq(void *dev) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct fpga_inode *temp_int = NULL; 4278c2ecf20Sopenharmony_ci struct fpga_internal *inter = NULL; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (dev != NULL) { 4328c2ecf20Sopenharmony_ci temp_int = find_inode(dev); 4338c2ecf20Sopenharmony_ci if (temp_int != NULL) { 4348c2ecf20Sopenharmony_ci inter = temp_int->internal; 4358c2ecf20Sopenharmony_ci schedule_work(&inter->work); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci return 1; 4408c2ecf20Sopenharmony_ci} 4418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(altera_ci_irq); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, 4448c2ecf20Sopenharmony_ci int slot, int open) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct altera_ci_state *state = en50221->data; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (0 != slot) 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci return state->status; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic void altera_hw_filt_release(void *main_dev, int filt_nr) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct fpga_inode *temp_int = find_inode(main_dev); 4578c2ecf20Sopenharmony_ci struct netup_hw_pid_filter *pid_filt = NULL; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (temp_int != NULL) { 4628c2ecf20Sopenharmony_ci pid_filt = temp_int->internal->pid_filt[filt_nr - 1]; 4638c2ecf20Sopenharmony_ci /* stored old feed controls */ 4648c2ecf20Sopenharmony_ci pid_filt->demux->start_feed = pid_filt->start_feed; 4658c2ecf20Sopenharmony_ci pid_filt->demux->stop_feed = pid_filt->stop_feed; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (((--(temp_int->internal->filts_used)) <= 0) && 4688c2ecf20Sopenharmony_ci ((temp_int->internal->cis_used) <= 0)) { 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ci_dbg_print("%s: Actually removing\n", __func__); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci remove_inode(temp_int->internal); 4738c2ecf20Sopenharmony_ci kfree(pid_filt->internal); 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci kfree(pid_filt); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_civoid altera_ci_release(void *dev, int ci_nr) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct fpga_inode *temp_int = find_inode(dev); 4858c2ecf20Sopenharmony_ci struct altera_ci_state *state = NULL; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (temp_int != NULL) { 4908c2ecf20Sopenharmony_ci state = temp_int->internal->state[ci_nr - 1]; 4918c2ecf20Sopenharmony_ci altera_hw_filt_release(dev, ci_nr); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (((temp_int->internal->filts_used) <= 0) && 4958c2ecf20Sopenharmony_ci ((--(temp_int->internal->cis_used)) <= 0)) { 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci ci_dbg_print("%s: Actually removing\n", __func__); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci remove_inode(temp_int->internal); 5008c2ecf20Sopenharmony_ci kfree(state->internal); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (state != NULL) { 5048c2ecf20Sopenharmony_ci if (state->ca.data != NULL) 5058c2ecf20Sopenharmony_ci dvb_ca_en50221_release(&state->ca); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci kfree(state); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(altera_ci_release); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void altera_pid_control(struct netup_hw_pid_filter *pid_filt, 5158c2ecf20Sopenharmony_ci u16 pid, int onoff) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct fpga_internal *inter = pid_filt->internal; 5188c2ecf20Sopenharmony_ci u8 store = 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* pid 0-0x1f always enabled, don't touch them */ 5218c2ecf20Sopenharmony_ci if ((pid == 0x2000) || (pid < 0x20)) 5228c2ecf20Sopenharmony_ci return; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0); 5278c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, 5288c2ecf20Sopenharmony_ci ((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (onoff)/* 0 - on, 1 - off */ 5338c2ecf20Sopenharmony_ci store |= (1 << (pid & 7)); 5348c2ecf20Sopenharmony_ci else 5358c2ecf20Sopenharmony_ci store &= ~(1 << (pid & 7)); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__, 5428c2ecf20Sopenharmony_ci pid_filt->nr, pid, pid, onoff ? "off" : "on"); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt, 5468c2ecf20Sopenharmony_ci int filt_nr, int onoff) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct fpga_internal *inter = pid_filt->internal; 5498c2ecf20Sopenharmony_ci u8 store = 0; 5508c2ecf20Sopenharmony_ci int i; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci pid_dbg_print("%s: pid_filt->nr[%d] now %s\n", __func__, pid_filt->nr, 5538c2ecf20Sopenharmony_ci onoff ? "off" : "on"); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (onoff)/* 0 - on, 1 - off */ 5568c2ecf20Sopenharmony_ci store = 0xff;/* ignore pid */ 5578c2ecf20Sopenharmony_ci else 5588c2ecf20Sopenharmony_ci store = 0;/* enable pid */ 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci for (i = 0; i < 1024; i++) { 5638c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, 5668c2ecf20Sopenharmony_ci ((i >> 8) & 0x03) | (pid_filt->nr << 2), 0); 5678c2ecf20Sopenharmony_ci /* pid 0-0x1f always enabled */ 5688c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 5698c2ecf20Sopenharmony_ci (i > 3 ? store : 0), 0); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int altera_pid_feed_control(void *demux_dev, int filt_nr, 5768c2ecf20Sopenharmony_ci struct dvb_demux_feed *feed, int onoff) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct fpga_inode *temp_int = find_dinode(demux_dev); 5798c2ecf20Sopenharmony_ci struct fpga_internal *inter = temp_int->internal; 5808c2ecf20Sopenharmony_ci struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1]; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1); 5838c2ecf20Sopenharmony_ci /* call old feed proc's */ 5848c2ecf20Sopenharmony_ci if (onoff) 5858c2ecf20Sopenharmony_ci pid_filt->start_feed(feed); 5868c2ecf20Sopenharmony_ci else 5878c2ecf20Sopenharmony_ci pid_filt->stop_feed(feed); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (feed->pid == 0x2000) 5908c2ecf20Sopenharmony_ci altera_toggle_fullts_streaming(pid_filt, filt_nr, 5918c2ecf20Sopenharmony_ci onoff ? 0 : 1); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci return 0; 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci altera_pid_feed_control(feed->demux, num, feed, 1); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return 0; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci altera_pid_feed_control(feed->demux, num, feed, 0); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int altera_ci_start_feed_1(struct dvb_demux_feed *feed) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci return altera_ci_start_feed(feed, 1); 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int altera_ci_stop_feed_1(struct dvb_demux_feed *feed) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci return altera_ci_stop_feed(feed, 1); 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic int altera_ci_start_feed_2(struct dvb_demux_feed *feed) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci return altera_ci_start_feed(feed, 2); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int altera_ci_stop_feed_2(struct dvb_demux_feed *feed) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci return altera_ci_stop_feed(feed, 2); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct netup_hw_pid_filter *pid_filt = NULL; 6338c2ecf20Sopenharmony_ci struct fpga_inode *temp_int = find_inode(config->dev); 6348c2ecf20Sopenharmony_ci struct fpga_internal *inter = NULL; 6358c2ecf20Sopenharmony_ci int ret = 0; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!pid_filt) { 6428c2ecf20Sopenharmony_ci ret = -ENOMEM; 6438c2ecf20Sopenharmony_ci goto err; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (temp_int != NULL) { 6478c2ecf20Sopenharmony_ci inter = temp_int->internal; 6488c2ecf20Sopenharmony_ci (inter->filts_used)++; 6498c2ecf20Sopenharmony_ci ci_dbg_print("%s: Find Internal Structure!\n", __func__); 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); 6528c2ecf20Sopenharmony_ci if (!inter) { 6538c2ecf20Sopenharmony_ci ret = -ENOMEM; 6548c2ecf20Sopenharmony_ci goto err; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci temp_int = append_internal(inter); 6588c2ecf20Sopenharmony_ci if (!temp_int) { 6598c2ecf20Sopenharmony_ci ret = -ENOMEM; 6608c2ecf20Sopenharmony_ci goto err; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci inter->filts_used = 1; 6638c2ecf20Sopenharmony_ci inter->dev = config->dev; 6648c2ecf20Sopenharmony_ci inter->fpga_rw = config->fpga_rw; 6658c2ecf20Sopenharmony_ci mutex_init(&inter->fpga_mutex); 6668c2ecf20Sopenharmony_ci inter->strt_wrk = 1; 6678c2ecf20Sopenharmony_ci ci_dbg_print("%s: Create New Internal Structure!\n", __func__); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__, 6718c2ecf20Sopenharmony_ci pid_filt, hw_filt_nr - 1); 6728c2ecf20Sopenharmony_ci inter->pid_filt[hw_filt_nr - 1] = pid_filt; 6738c2ecf20Sopenharmony_ci pid_filt->demux = config->demux; 6748c2ecf20Sopenharmony_ci pid_filt->internal = inter; 6758c2ecf20Sopenharmony_ci pid_filt->nr = hw_filt_nr - 1; 6768c2ecf20Sopenharmony_ci /* store old feed controls */ 6778c2ecf20Sopenharmony_ci pid_filt->start_feed = config->demux->start_feed; 6788c2ecf20Sopenharmony_ci pid_filt->stop_feed = config->demux->stop_feed; 6798c2ecf20Sopenharmony_ci /* replace with new feed controls */ 6808c2ecf20Sopenharmony_ci if (hw_filt_nr == 1) { 6818c2ecf20Sopenharmony_ci pid_filt->demux->start_feed = altera_ci_start_feed_1; 6828c2ecf20Sopenharmony_ci pid_filt->demux->stop_feed = altera_ci_stop_feed_1; 6838c2ecf20Sopenharmony_ci } else if (hw_filt_nr == 2) { 6848c2ecf20Sopenharmony_ci pid_filt->demux->start_feed = altera_ci_start_feed_2; 6858c2ecf20Sopenharmony_ci pid_filt->demux->stop_feed = altera_ci_stop_feed_2; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci altera_toggle_fullts_streaming(pid_filt, 0, 1); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_cierr: 6928c2ecf20Sopenharmony_ci ci_dbg_print("%s: Can't init hardware filter: Error %d\n", 6938c2ecf20Sopenharmony_ci __func__, ret); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci kfree(pid_filt); 6968c2ecf20Sopenharmony_ci kfree(inter); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci return ret; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ciint altera_ci_init(struct altera_ci_config *config, int ci_nr) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct altera_ci_state *state; 7048c2ecf20Sopenharmony_ci struct fpga_inode *temp_int = find_inode(config->dev); 7058c2ecf20Sopenharmony_ci struct fpga_internal *inter = NULL; 7068c2ecf20Sopenharmony_ci int ret = 0; 7078c2ecf20Sopenharmony_ci u8 store = 0; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (!state) { 7148c2ecf20Sopenharmony_ci ret = -ENOMEM; 7158c2ecf20Sopenharmony_ci goto err; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (temp_int != NULL) { 7198c2ecf20Sopenharmony_ci inter = temp_int->internal; 7208c2ecf20Sopenharmony_ci (inter->cis_used)++; 7218c2ecf20Sopenharmony_ci inter->fpga_rw = config->fpga_rw; 7228c2ecf20Sopenharmony_ci ci_dbg_print("%s: Find Internal Structure!\n", __func__); 7238c2ecf20Sopenharmony_ci } else { 7248c2ecf20Sopenharmony_ci inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); 7258c2ecf20Sopenharmony_ci if (!inter) { 7268c2ecf20Sopenharmony_ci ret = -ENOMEM; 7278c2ecf20Sopenharmony_ci goto err; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci temp_int = append_internal(inter); 7318c2ecf20Sopenharmony_ci if (!temp_int) { 7328c2ecf20Sopenharmony_ci ret = -ENOMEM; 7338c2ecf20Sopenharmony_ci goto err; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci inter->cis_used = 1; 7368c2ecf20Sopenharmony_ci inter->dev = config->dev; 7378c2ecf20Sopenharmony_ci inter->fpga_rw = config->fpga_rw; 7388c2ecf20Sopenharmony_ci mutex_init(&inter->fpga_mutex); 7398c2ecf20Sopenharmony_ci inter->strt_wrk = 1; 7408c2ecf20Sopenharmony_ci ci_dbg_print("%s: Create New Internal Structure!\n", __func__); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__, 7448c2ecf20Sopenharmony_ci state, ci_nr - 1); 7458c2ecf20Sopenharmony_ci state->internal = inter; 7468c2ecf20Sopenharmony_ci state->nr = ci_nr - 1; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci state->ca.owner = THIS_MODULE; 7498c2ecf20Sopenharmony_ci state->ca.read_attribute_mem = altera_ci_read_attribute_mem; 7508c2ecf20Sopenharmony_ci state->ca.write_attribute_mem = altera_ci_write_attribute_mem; 7518c2ecf20Sopenharmony_ci state->ca.read_cam_control = altera_ci_read_cam_ctl; 7528c2ecf20Sopenharmony_ci state->ca.write_cam_control = altera_ci_write_cam_ctl; 7538c2ecf20Sopenharmony_ci state->ca.slot_reset = altera_ci_slot_reset; 7548c2ecf20Sopenharmony_ci state->ca.slot_shutdown = altera_ci_slot_shutdown; 7558c2ecf20Sopenharmony_ci state->ca.slot_ts_enable = altera_ci_slot_ts_ctl; 7568c2ecf20Sopenharmony_ci state->ca.poll_slot_status = altera_poll_ci_slot_status; 7578c2ecf20Sopenharmony_ci state->ca.data = state; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci ret = dvb_ca_en50221_init(config->adapter, 7608c2ecf20Sopenharmony_ci &state->ca, 7618c2ecf20Sopenharmony_ci /* flags */ 0, 7628c2ecf20Sopenharmony_ci /* n_slots */ 1); 7638c2ecf20Sopenharmony_ci if (0 != ret) 7648c2ecf20Sopenharmony_ci goto err; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci inter->state[ci_nr - 1] = state; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci altera_hw_filt_init(config, ci_nr); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (inter->strt_wrk) { 7718c2ecf20Sopenharmony_ci INIT_WORK(&inter->work, netup_read_ci_status); 7728c2ecf20Sopenharmony_ci inter->strt_wrk = 0; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci ci_dbg_print("%s: CI initialized!\n", __func__); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci /* Enable div */ 7808c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0); 7818c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* enable TS out */ 7848c2ecf20Sopenharmony_ci store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); 7858c2ecf20Sopenharmony_ci store |= (3 << 4); 7868c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD); 7898c2ecf20Sopenharmony_ci /* enable irq */ 7908c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci schedule_work(&inter->work); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci return 0; 7998c2ecf20Sopenharmony_cierr: 8008c2ecf20Sopenharmony_ci ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci kfree(state); 8038c2ecf20Sopenharmony_ci kfree(inter); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return ret; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(altera_ci_init); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ciint altera_ci_tuner_reset(void *dev, int ci_nr) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct fpga_inode *temp_int = find_inode(dev); 8128c2ecf20Sopenharmony_ci struct fpga_internal *inter = NULL; 8138c2ecf20Sopenharmony_ci u8 store; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci ci_dbg_print("%s\n", __func__); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (temp_int == NULL) 8188c2ecf20Sopenharmony_ci return -1; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (temp_int->internal == NULL) 8218c2ecf20Sopenharmony_ci return -1; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci inter = temp_int->internal; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci mutex_lock(&inter->fpga_mutex); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); 8288c2ecf20Sopenharmony_ci store &= ~(4 << (2 - ci_nr)); 8298c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); 8308c2ecf20Sopenharmony_ci msleep(100); 8318c2ecf20Sopenharmony_ci store |= (4 << (2 - ci_nr)); 8328c2ecf20Sopenharmony_ci netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci mutex_unlock(&inter->fpga_mutex); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(altera_ci_tuner_reset); 839