cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

flexcop.c (8390B)


      1// SPDX-License-Identifier: LGPL-2.1-or-later
      2/*
      3 * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
      4 * flexcop.c - main module part
      5 * Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@posteo.de>
      6 * based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
      7 *
      8 * Acknowledgements:
      9 *   John Jurrius from BBTI, Inc. for extensive support
     10 *                    with code examples and data books
     11 *   Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
     12 *
     13 * Contributions to the skystar2-driver have been done by
     14 *   Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
     15 *   Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
     16 *   Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
     17 *   Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
     18 *               filtering)
     19 */
     20
     21#include "flexcop.h"
     22
     23#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
     24#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@posteo.de"
     25
     26#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
     27#define DEBSTATUS ""
     28#else
     29#define DEBSTATUS " (debugging is not enabled)"
     30#endif
     31
     32int b2c2_flexcop_debug;
     33EXPORT_SYMBOL_GPL(b2c2_flexcop_debug);
     34module_param_named(debug, b2c2_flexcop_debug,  int, 0644);
     35MODULE_PARM_DESC(debug,
     36		"set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg,64=i2cdump (|-able))."
     37		DEBSTATUS);
     38#undef DEBSTATUS
     39
     40DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
     41
     42/* global zero for ibi values */
     43flexcop_ibi_value ibi_zero;
     44
     45static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
     46{
     47	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
     48	return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
     49}
     50
     51static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
     52{
     53	struct flexcop_device *fc = dvbdmxfeed->demux->priv;
     54	return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
     55}
     56
     57static int flexcop_dvb_init(struct flexcop_device *fc)
     58{
     59	int ret = dvb_register_adapter(&fc->dvb_adapter,
     60			"FlexCop Digital TV device", fc->owner,
     61			fc->dev, adapter_nr);
     62	if (ret < 0) {
     63		err("error registering DVB adapter");
     64		return ret;
     65	}
     66	fc->dvb_adapter.priv = fc;
     67
     68	fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
     69			| DMX_MEMORY_BASED_FILTERING);
     70	fc->demux.priv = fc;
     71	fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
     72	fc->demux.start_feed = flexcop_dvb_start_feed;
     73	fc->demux.stop_feed = flexcop_dvb_stop_feed;
     74	fc->demux.write_to_decoder = NULL;
     75
     76	ret = dvb_dmx_init(&fc->demux);
     77	if (ret < 0) {
     78		err("dvb_dmx failed: error %d", ret);
     79		goto err_dmx;
     80	}
     81
     82	fc->hw_frontend.source = DMX_FRONTEND_0;
     83
     84	fc->dmxdev.filternum = fc->demux.feednum;
     85	fc->dmxdev.demux = &fc->demux.dmx;
     86	fc->dmxdev.capabilities = 0;
     87	ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
     88	if (ret < 0) {
     89		err("dvb_dmxdev_init failed: error %d", ret);
     90		goto err_dmx_dev;
     91	}
     92
     93	ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
     94	if (ret < 0) {
     95		err("adding hw_frontend to dmx failed: error %d", ret);
     96		goto err_dmx_add_hw_frontend;
     97	}
     98
     99	fc->mem_frontend.source = DMX_MEMORY_FE;
    100	ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
    101	if (ret < 0) {
    102		err("adding mem_frontend to dmx failed: error %d", ret);
    103		goto err_dmx_add_mem_frontend;
    104	}
    105
    106	ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
    107	if (ret < 0) {
    108		err("connect frontend failed: error %d", ret);
    109		goto err_connect_frontend;
    110	}
    111
    112	ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
    113	if (ret < 0) {
    114		err("dvb_net_init failed: error %d", ret);
    115		goto err_net;
    116	}
    117
    118	fc->init_state |= FC_STATE_DVB_INIT;
    119	return 0;
    120
    121err_net:
    122	fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
    123err_connect_frontend:
    124	fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
    125err_dmx_add_mem_frontend:
    126	fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
    127err_dmx_add_hw_frontend:
    128	dvb_dmxdev_release(&fc->dmxdev);
    129err_dmx_dev:
    130	dvb_dmx_release(&fc->demux);
    131err_dmx:
    132	dvb_unregister_adapter(&fc->dvb_adapter);
    133	return ret;
    134}
    135
    136static void flexcop_dvb_exit(struct flexcop_device *fc)
    137{
    138	if (fc->init_state & FC_STATE_DVB_INIT) {
    139		dvb_net_release(&fc->dvbnet);
    140
    141		fc->demux.dmx.close(&fc->demux.dmx);
    142		fc->demux.dmx.remove_frontend(&fc->demux.dmx,
    143			&fc->mem_frontend);
    144		fc->demux.dmx.remove_frontend(&fc->demux.dmx,
    145			&fc->hw_frontend);
    146		dvb_dmxdev_release(&fc->dmxdev);
    147		dvb_dmx_release(&fc->demux);
    148		dvb_unregister_adapter(&fc->dvb_adapter);
    149		deb_info("deinitialized dvb stuff\n");
    150	}
    151	fc->init_state &= ~FC_STATE_DVB_INIT;
    152}
    153
    154/* these methods are necessary to achieve the long-term-goal of hiding the
    155 * struct flexcop_device from the bus-parts */
    156void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
    157{
    158	dvb_dmx_swfilter(&fc->demux, buf, len);
    159}
    160EXPORT_SYMBOL(flexcop_pass_dmx_data);
    161
    162void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
    163{
    164	dvb_dmx_swfilter_packets(&fc->demux, buf, no);
    165}
    166EXPORT_SYMBOL(flexcop_pass_dmx_packets);
    167
    168static void flexcop_reset(struct flexcop_device *fc)
    169{
    170	flexcop_ibi_value v210, v204;
    171
    172	/* reset the flexcop itself */
    173	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
    174
    175	v210.raw = 0;
    176	v210.sw_reset_210.reset_block_000 = 1;
    177	v210.sw_reset_210.reset_block_100 = 1;
    178	v210.sw_reset_210.reset_block_200 = 1;
    179	v210.sw_reset_210.reset_block_300 = 1;
    180	v210.sw_reset_210.reset_block_400 = 1;
    181	v210.sw_reset_210.reset_block_500 = 1;
    182	v210.sw_reset_210.reset_block_600 = 1;
    183	v210.sw_reset_210.reset_block_700 = 1;
    184	v210.sw_reset_210.Block_reset_enable = 0xb2;
    185	v210.sw_reset_210.Special_controls = 0xc259;
    186	fc->write_ibi_reg(fc,sw_reset_210,v210);
    187	msleep(1);
    188
    189	/* reset the periphical devices */
    190
    191	v204 = fc->read_ibi_reg(fc,misc_204);
    192	v204.misc_204.Per_reset_sig = 0;
    193	fc->write_ibi_reg(fc,misc_204,v204);
    194	msleep(1);
    195	v204.misc_204.Per_reset_sig = 1;
    196	fc->write_ibi_reg(fc,misc_204,v204);
    197}
    198
    199void flexcop_reset_block_300(struct flexcop_device *fc)
    200{
    201	flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
    202			  v210 = fc->read_ibi_reg(fc, sw_reset_210);
    203
    204	deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
    205	fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
    206
    207	v210.sw_reset_210.reset_block_300 = 1;
    208	v210.sw_reset_210.Block_reset_enable = 0xb2;
    209
    210	fc->write_ibi_reg(fc,sw_reset_210,v210);
    211	fc->write_ibi_reg(fc,ctrl_208,v208_save);
    212}
    213
    214struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
    215{
    216	void *bus;
    217	struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
    218				GFP_KERNEL);
    219	if (!fc) {
    220		err("no memory");
    221		return NULL;
    222	}
    223
    224	bus = kzalloc(bus_specific_len, GFP_KERNEL);
    225	if (!bus) {
    226		err("no memory");
    227		kfree(fc);
    228		return NULL;
    229	}
    230
    231	fc->bus_specific = bus;
    232
    233	return fc;
    234}
    235EXPORT_SYMBOL(flexcop_device_kmalloc);
    236
    237void flexcop_device_kfree(struct flexcop_device *fc)
    238{
    239	kfree(fc->bus_specific);
    240	kfree(fc);
    241}
    242EXPORT_SYMBOL(flexcop_device_kfree);
    243
    244int flexcop_device_initialize(struct flexcop_device *fc)
    245{
    246	int ret;
    247	ibi_zero.raw = 0;
    248
    249	flexcop_reset(fc);
    250	flexcop_determine_revision(fc);
    251	flexcop_sram_init(fc);
    252	flexcop_hw_filter_init(fc);
    253	flexcop_smc_ctrl(fc, 0);
    254
    255	ret = flexcop_dvb_init(fc);
    256	if (ret)
    257		goto error;
    258
    259	/* i2c has to be done before doing EEProm stuff -
    260	 * because the EEProm is accessed via i2c */
    261	ret = flexcop_i2c_init(fc);
    262	if (ret)
    263		goto error;
    264
    265	/* do the MAC address reading after initializing the dvb_adapter */
    266	if (fc->get_mac_addr(fc, 0) == 0) {
    267		u8 *b = fc->dvb_adapter.proposed_mac;
    268		info("MAC address = %pM", b);
    269		flexcop_set_mac_filter(fc,b);
    270		flexcop_mac_filter_ctrl(fc,1);
    271	} else
    272		warn("reading of MAC address failed.\n");
    273
    274	ret = flexcop_frontend_init(fc);
    275	if (ret)
    276		goto error;
    277
    278	flexcop_device_name(fc,"initialization of","complete");
    279	return 0;
    280
    281error:
    282	flexcop_device_exit(fc);
    283	return ret;
    284}
    285EXPORT_SYMBOL(flexcop_device_initialize);
    286
    287void flexcop_device_exit(struct flexcop_device *fc)
    288{
    289	flexcop_frontend_exit(fc);
    290	flexcop_i2c_exit(fc);
    291	flexcop_dvb_exit(fc);
    292}
    293EXPORT_SYMBOL(flexcop_device_exit);
    294
    295static int flexcop_module_init(void)
    296{
    297	info(DRIVER_NAME " loaded successfully");
    298	return 0;
    299}
    300
    301static void flexcop_module_cleanup(void)
    302{
    303	info(DRIVER_NAME " unloaded successfully");
    304}
    305
    306module_init(flexcop_module_init);
    307module_exit(flexcop_module_cleanup);
    308
    309MODULE_AUTHOR(DRIVER_AUTHOR);
    310MODULE_DESCRIPTION(DRIVER_NAME);
    311MODULE_LICENSE("GPL");