| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * flexcop.c - driver for digital TV devices equipped with B2C2 FlexcopII(b)/III | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 2004-5 Patrick Boettcher <patrick.boettcher@desy.de> | 
 | 5 |  * | 
 | 6 |  * based on the skystar2-driver | 
 | 7 |  * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc | 
 | 8 |  * | 
 | 9 |  * Acknowledgements: | 
 | 10 |  *     John Jurrius from BBTI, Inc. for extensive support with | 
 | 11 |  *         code examples and data books | 
 | 12 |  * | 
 | 13 |  *     Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting) | 
 | 14 |  * | 
 | 15 |  * Contributions to the skystar2-driver have been done by | 
 | 16 |  *     Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes) | 
 | 17 |  *     Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code) | 
 | 18 |  *     Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac filtering) | 
 | 19 |  * | 
 | 20 |  * | 
 | 21 |  * This program is free software; you can redistribute it and/or | 
 | 22 |  * modify it under the terms of the GNU Lesser General Public License | 
 | 23 |  * as published by the Free Software Foundation; either version 2.1 | 
 | 24 |  * of the License, or (at your option) any later version. | 
 | 25 |  * | 
 | 26 |  * This program is distributed in the hope that it will be useful, | 
 | 27 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 | 28 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 | 29 |  * GNU General Public License for more details. | 
 | 30 |  * | 
 | 31 |  * You should have received a copy of the GNU Lesser General Public License | 
 | 32 |  * along with this program; if not, write to the Free Software | 
 | 33 |  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. | 
 | 34 |  */ | 
 | 35 |  | 
 | 36 | #include "flexcop.h" | 
 | 37 |  | 
 | 38 | #define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip" | 
 | 39 | #define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de" | 
 | 40 |  | 
 | 41 | #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG | 
 | 42 | #define DEBSTATUS "" | 
 | 43 | #else | 
 | 44 | #define DEBSTATUS " (debugging is not enabled)" | 
 | 45 | #endif | 
 | 46 |  | 
 | 47 | int b2c2_flexcop_debug; | 
 | 48 | module_param_named(debug, b2c2_flexcop_debug,  int, 0644); | 
| Patrick Boettcher | 64221be | 2005-07-07 17:57:49 -0700 | [diff] [blame] | 49 | MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 50 | #undef DEBSTATUS | 
 | 51 |  | 
| Janne Grunau | 78e9200 | 2008-04-09 19:13:13 -0300 | [diff] [blame] | 52 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 
 | 53 |  | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 54 | /* global zero for ibi values */ | 
 | 55 | flexcop_ibi_value ibi_zero; | 
 | 56 |  | 
 | 57 | static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) | 
 | 58 | { | 
 | 59 | 	struct flexcop_device *fc = dvbdmxfeed->demux->priv; | 
 | 60 | 	return flexcop_pid_feed_control(fc,dvbdmxfeed,1); | 
 | 61 | } | 
 | 62 |  | 
 | 63 | static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | 
 | 64 | { | 
 | 65 | 	struct flexcop_device *fc = dvbdmxfeed->demux->priv; | 
 | 66 | 	return flexcop_pid_feed_control(fc,dvbdmxfeed,0); | 
 | 67 | } | 
 | 68 |  | 
 | 69 | static int flexcop_dvb_init(struct flexcop_device *fc) | 
 | 70 | { | 
| Janne Grunau | 78e9200 | 2008-04-09 19:13:13 -0300 | [diff] [blame] | 71 | 	int ret = dvb_register_adapter(&fc->dvb_adapter, | 
 | 72 | 				       "FlexCop Digital TV device", fc->owner, | 
 | 73 | 				       fc->dev, adapter_nr); | 
 | 74 | 	if (ret < 0) { | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 75 | 		err("error registering DVB adapter"); | 
 | 76 | 		return ret; | 
 | 77 | 	} | 
 | 78 | 	fc->dvb_adapter.priv = fc; | 
 | 79 |  | 
 | 80 | 	fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); | 
 | 81 | 	fc->demux.priv = fc; | 
 | 82 |  | 
 | 83 | 	fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED; | 
 | 84 |  | 
 | 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; | 
| Trent Piepho | 8397703 | 2006-05-12 20:36:24 -0300 | [diff] [blame] | 123 | 	return 0; | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 124 |  | 
 | 125 | err_connect_frontend: | 
 | 126 | 	fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend); | 
 | 127 | err_dmx_add_mem_frontend: | 
 | 128 | 	fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend); | 
 | 129 | err_dmx_add_hw_frontend: | 
 | 130 | 	dvb_dmxdev_release(&fc->dmxdev); | 
 | 131 | err_dmx_dev: | 
 | 132 | 	dvb_dmx_release(&fc->demux); | 
 | 133 | err_dmx: | 
 | 134 | 	dvb_unregister_adapter(&fc->dvb_adapter); | 
 | 135 | 	return ret; | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 136 | } | 
 | 137 |  | 
 | 138 | static 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,&fc->mem_frontend); | 
 | 145 | 		fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->hw_frontend); | 
 | 146 | 		dvb_dmxdev_release(&fc->dmxdev); | 
 | 147 | 		dvb_dmx_release(&fc->demux); | 
 | 148 | 		dvb_unregister_adapter(&fc->dvb_adapter); | 
 | 149 |  | 
 | 150 | 		deb_info("deinitialized dvb stuff\n"); | 
 | 151 | 	} | 
 | 152 | 	fc->init_state &= ~FC_STATE_DVB_INIT; | 
 | 153 | } | 
 | 154 |  | 
 | 155 | /* these methods are necessary to achieve the long-term-goal of hiding the | 
 | 156 |  * struct flexcop_device from the bus-parts */ | 
 | 157 | void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len) | 
 | 158 | { | 
 | 159 | 	dvb_dmx_swfilter(&fc->demux, buf, len); | 
 | 160 | } | 
 | 161 | EXPORT_SYMBOL(flexcop_pass_dmx_data); | 
 | 162 |  | 
 | 163 | void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no) | 
 | 164 | { | 
 | 165 | 	dvb_dmx_swfilter_packets(&fc->demux, buf, no); | 
 | 166 | } | 
 | 167 | EXPORT_SYMBOL(flexcop_pass_dmx_packets); | 
 | 168 |  | 
 | 169 | static void flexcop_reset(struct flexcop_device *fc) | 
 | 170 | { | 
 | 171 | 	flexcop_ibi_value v210,v204; | 
 | 172 |  | 
 | 173 | /* reset the flexcop itself */ | 
 | 174 | 	fc->write_ibi_reg(fc,ctrl_208,ibi_zero); | 
 | 175 |  | 
 | 176 | 	v210.raw = 0; | 
| Patrick Boettcher | 64221be | 2005-07-07 17:57:49 -0700 | [diff] [blame] | 177 | 	v210.sw_reset_210.reset_block_000 = 1; | 
 | 178 | 	v210.sw_reset_210.reset_block_100 = 1; | 
 | 179 | 	v210.sw_reset_210.reset_block_200 = 1; | 
 | 180 | 	v210.sw_reset_210.reset_block_300 = 1; | 
 | 181 | 	v210.sw_reset_210.reset_block_400 = 1; | 
 | 182 | 	v210.sw_reset_210.reset_block_500 = 1; | 
 | 183 | 	v210.sw_reset_210.reset_block_600 = 1; | 
 | 184 | 	v210.sw_reset_210.reset_block_700 = 1; | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 185 | 	v210.sw_reset_210.Block_reset_enable = 0xb2; | 
| Patrick Boettcher | 64221be | 2005-07-07 17:57:49 -0700 | [diff] [blame] | 186 |  | 
 | 187 | 	v210.sw_reset_210.Special_controls = 0xc259; | 
 | 188 |  | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 189 | 	fc->write_ibi_reg(fc,sw_reset_210,v210); | 
| Patrick Boettcher | 64221be | 2005-07-07 17:57:49 -0700 | [diff] [blame] | 190 | 	msleep(1); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 191 |  | 
 | 192 | /* reset the periphical devices */ | 
 | 193 |  | 
 | 194 | 	v204 = fc->read_ibi_reg(fc,misc_204); | 
 | 195 | 	v204.misc_204.Per_reset_sig = 0; | 
 | 196 | 	fc->write_ibi_reg(fc,misc_204,v204); | 
| Michael Krufky | c0b11b9 | 2005-11-08 21:35:32 -0800 | [diff] [blame] | 197 | 	msleep(1); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 198 | 	v204.misc_204.Per_reset_sig = 1; | 
 | 199 | 	fc->write_ibi_reg(fc,misc_204,v204); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 200 | } | 
 | 201 |  | 
| Patrick Boettcher | 64221be | 2005-07-07 17:57:49 -0700 | [diff] [blame] | 202 | void flexcop_reset_block_300(struct flexcop_device *fc) | 
 | 203 | { | 
 | 204 | 	flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208), | 
 | 205 | 					  v210 = fc->read_ibi_reg(fc,sw_reset_210); | 
 | 206 |  | 
 | 207 | 	deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw); | 
 | 208 |  | 
 | 209 | 	fc->write_ibi_reg(fc,ctrl_208,ibi_zero); | 
 | 210 |  | 
 | 211 | 	v210.sw_reset_210.reset_block_300 = 1; | 
 | 212 | 	v210.sw_reset_210.Block_reset_enable = 0xb2; | 
 | 213 |  | 
 | 214 | 	fc->write_ibi_reg(fc,sw_reset_210,v210); | 
 | 215 | 	msleep(1); | 
 | 216 |  | 
 | 217 | 	fc->write_ibi_reg(fc,ctrl_208,v208_save); | 
 | 218 | } | 
| Patrick Boettcher | 64221be | 2005-07-07 17:57:49 -0700 | [diff] [blame] | 219 |  | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 220 | struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) | 
 | 221 | { | 
 | 222 | 	void *bus; | 
| Panagiotis Issaris | 7408187 | 2006-01-11 19:40:56 -0200 | [diff] [blame] | 223 | 	struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device), GFP_KERNEL); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 224 | 	if (!fc) { | 
 | 225 | 		err("no memory"); | 
 | 226 | 		return NULL; | 
 | 227 | 	} | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 228 |  | 
| Panagiotis Issaris | 7408187 | 2006-01-11 19:40:56 -0200 | [diff] [blame] | 229 | 	bus = kzalloc(bus_specific_len, GFP_KERNEL); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 230 | 	if (!bus) { | 
 | 231 | 		err("no memory"); | 
 | 232 | 		kfree(fc); | 
 | 233 | 		return NULL; | 
 | 234 | 	} | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 235 |  | 
 | 236 | 	fc->bus_specific = bus; | 
 | 237 |  | 
 | 238 | 	return fc; | 
 | 239 | } | 
 | 240 | EXPORT_SYMBOL(flexcop_device_kmalloc); | 
 | 241 |  | 
 | 242 | void flexcop_device_kfree(struct flexcop_device *fc) | 
 | 243 | { | 
 | 244 | 	kfree(fc->bus_specific); | 
 | 245 | 	kfree(fc); | 
 | 246 | } | 
 | 247 | EXPORT_SYMBOL(flexcop_device_kfree); | 
 | 248 |  | 
 | 249 | int flexcop_device_initialize(struct flexcop_device *fc) | 
 | 250 | { | 
 | 251 | 	int ret; | 
 | 252 | 	ibi_zero.raw = 0; | 
 | 253 |  | 
 | 254 | 	flexcop_reset(fc); | 
 | 255 | 	flexcop_determine_revision(fc); | 
 | 256 | 	flexcop_sram_init(fc); | 
 | 257 | 	flexcop_hw_filter_init(fc); | 
 | 258 |  | 
 | 259 | 	flexcop_smc_ctrl(fc, 0); | 
 | 260 |  | 
| Johannes Stezenbach | 7782413 | 2005-05-16 21:54:14 -0700 | [diff] [blame] | 261 | 	if ((ret = flexcop_dvb_init(fc))) | 
 | 262 | 		goto error; | 
 | 263 |  | 
| Patrick Boettcher | 6394cf5 | 2008-03-29 20:49:57 -0300 | [diff] [blame] | 264 | 	/* i2c has to be done before doing EEProm stuff - | 
 | 265 | 	 * because the EEProm is accessed via i2c */ | 
 | 266 | 	ret = flexcop_i2c_init(fc); | 
 | 267 | 	if (ret) | 
 | 268 | 		goto error; | 
 | 269 |  | 
| Johannes Stezenbach | 7782413 | 2005-05-16 21:54:14 -0700 | [diff] [blame] | 270 | 	/* do the MAC address reading after initializing the dvb_adapter */ | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 271 | 	if (fc->get_mac_addr(fc, 0) == 0) { | 
| Johannes Stezenbach | 7782413 | 2005-05-16 21:54:14 -0700 | [diff] [blame] | 272 | 		u8 *b = fc->dvb_adapter.proposed_mac; | 
| Johannes Berg | 7c510e4 | 2008-10-27 17:47:26 -0700 | [diff] [blame] | 273 | 		info("MAC address = %pM", b); | 
| Johannes Stezenbach | 7782413 | 2005-05-16 21:54:14 -0700 | [diff] [blame] | 274 | 		flexcop_set_mac_filter(fc,b); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 275 | 		flexcop_mac_filter_ctrl(fc,1); | 
 | 276 | 	} else | 
 | 277 | 		warn("reading of MAC address failed.\n"); | 
 | 278 |  | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 279 | 	if ((ret = flexcop_frontend_init(fc))) | 
 | 280 | 		goto error; | 
 | 281 |  | 
 | 282 | 	flexcop_device_name(fc,"initialization of","complete"); | 
 | 283 |  | 
| Trent Piepho | 8397703 | 2006-05-12 20:36:24 -0300 | [diff] [blame] | 284 | 	return 0; | 
 | 285 |  | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 286 | error: | 
 | 287 | 	flexcop_device_exit(fc); | 
| Johannes Stezenbach | 2add87a | 2005-05-16 21:54:10 -0700 | [diff] [blame] | 288 | 	return ret; | 
 | 289 | } | 
 | 290 | EXPORT_SYMBOL(flexcop_device_initialize); | 
 | 291 |  | 
 | 292 | void flexcop_device_exit(struct flexcop_device *fc) | 
 | 293 | { | 
 | 294 | 	flexcop_frontend_exit(fc); | 
 | 295 | 	flexcop_i2c_exit(fc); | 
 | 296 | 	flexcop_dvb_exit(fc); | 
 | 297 | } | 
 | 298 | EXPORT_SYMBOL(flexcop_device_exit); | 
 | 299 |  | 
 | 300 | static int flexcop_module_init(void) | 
 | 301 | { | 
 | 302 | 	info(DRIVER_NAME " loaded successfully"); | 
 | 303 | 	return 0; | 
 | 304 | } | 
 | 305 |  | 
 | 306 | static void flexcop_module_cleanup(void) | 
 | 307 | { | 
 | 308 | 	info(DRIVER_NAME " unloaded successfully"); | 
 | 309 | } | 
 | 310 |  | 
 | 311 | module_init(flexcop_module_init); | 
 | 312 | module_exit(flexcop_module_cleanup); | 
 | 313 |  | 
 | 314 | MODULE_AUTHOR(DRIVER_AUTHOR); | 
 | 315 | MODULE_DESCRIPTION(DRIVER_NAME); | 
 | 316 | MODULE_LICENSE("GPL"); |