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