1/* 2 * FireDTV driver (formerly known as FireSAT) 3 * 4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com> 5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 */ 12 13#include <linux/device.h> 14#include <linux/errno.h> 15#include <linux/kernel.h> 16#include <linux/string.h> 17#include <linux/types.h> 18 19#include <dvb_frontend.h> 20 21#include "firedtv.h" 22 23static int fdtv_dvb_init(struct dvb_frontend *fe) 24{ 25 struct firedtv *fdtv = fe->sec_priv; 26 int err; 27 28 /* FIXME - allocate free channel at IRM */ 29 fdtv->isochannel = fdtv->adapter.num; 30 31 err = cmp_establish_pp_connection(fdtv, fdtv->subunit, 32 fdtv->isochannel); 33 if (err) { 34 dev_err(fdtv->device, 35 "could not establish point to point connection\n"); 36 return err; 37 } 38 39 return fdtv_start_iso(fdtv); 40} 41 42static int fdtv_sleep(struct dvb_frontend *fe) 43{ 44 struct firedtv *fdtv = fe->sec_priv; 45 46 fdtv_stop_iso(fdtv); 47 cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); 48 fdtv->isochannel = -1; 49 return 0; 50} 51 52#define LNBCONTROL_DONTCARE 0xff 53 54static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe, 55 struct dvb_diseqc_master_cmd *cmd) 56{ 57 struct firedtv *fdtv = fe->sec_priv; 58 59 return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 60 LNBCONTROL_DONTCARE, 1, cmd); 61} 62 63static int fdtv_diseqc_send_burst(struct dvb_frontend *fe, 64 enum fe_sec_mini_cmd minicmd) 65{ 66 return 0; 67} 68 69static int fdtv_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) 70{ 71 struct firedtv *fdtv = fe->sec_priv; 72 73 fdtv->tone = tone; 74 return 0; 75} 76 77static int fdtv_set_voltage(struct dvb_frontend *fe, 78 enum fe_sec_voltage voltage) 79{ 80 struct firedtv *fdtv = fe->sec_priv; 81 82 fdtv->voltage = voltage; 83 return 0; 84} 85 86static int fdtv_read_status(struct dvb_frontend *fe, enum fe_status *status) 87{ 88 struct firedtv *fdtv = fe->sec_priv; 89 struct firedtv_tuner_status stat; 90 91 if (avc_tuner_status(fdtv, &stat)) 92 return -EINVAL; 93 94 if (stat.no_rf) 95 *status = 0; 96 else 97 *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC | 98 FE_HAS_CARRIER | FE_HAS_LOCK; 99 return 0; 100} 101 102static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber) 103{ 104 struct firedtv *fdtv = fe->sec_priv; 105 struct firedtv_tuner_status stat; 106 107 if (avc_tuner_status(fdtv, &stat)) 108 return -EINVAL; 109 110 *ber = stat.ber; 111 return 0; 112} 113 114static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength) 115{ 116 struct firedtv *fdtv = fe->sec_priv; 117 struct firedtv_tuner_status stat; 118 119 if (avc_tuner_status(fdtv, &stat)) 120 return -EINVAL; 121 122 *strength = stat.signal_strength << 8; 123 return 0; 124} 125 126static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr) 127{ 128 struct firedtv *fdtv = fe->sec_priv; 129 struct firedtv_tuner_status stat; 130 131 if (avc_tuner_status(fdtv, &stat)) 132 return -EINVAL; 133 134 /* C/N[dB] = -10 * log10(snr / 65535) */ 135 *snr = stat.carrier_noise_ratio * 257; 136 return 0; 137} 138 139static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks) 140{ 141 return -EOPNOTSUPP; 142} 143 144static int fdtv_set_frontend(struct dvb_frontend *fe) 145{ 146 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 147 struct firedtv *fdtv = fe->sec_priv; 148 149 return avc_tuner_dsd(fdtv, p); 150} 151 152void fdtv_frontend_init(struct firedtv *fdtv, const char *name) 153{ 154 struct dvb_frontend_ops *ops = &fdtv->fe.ops; 155 struct dvb_frontend_info *fi = &ops->info; 156 157 ops->init = fdtv_dvb_init; 158 ops->sleep = fdtv_sleep; 159 160 ops->set_frontend = fdtv_set_frontend; 161 162 ops->read_status = fdtv_read_status; 163 ops->read_ber = fdtv_read_ber; 164 ops->read_signal_strength = fdtv_read_signal_strength; 165 ops->read_snr = fdtv_read_snr; 166 ops->read_ucblocks = fdtv_read_uncorrected_blocks; 167 168 ops->diseqc_send_master_cmd = fdtv_diseqc_send_master_cmd; 169 ops->diseqc_send_burst = fdtv_diseqc_send_burst; 170 ops->set_tone = fdtv_set_tone; 171 ops->set_voltage = fdtv_set_voltage; 172 173 switch (fdtv->type) { 174 case FIREDTV_DVB_S: 175 ops->delsys[0] = SYS_DVBS; 176 177 fi->frequency_min = 950000; 178 fi->frequency_max = 2150000; 179 fi->frequency_stepsize = 125; 180 fi->symbol_rate_min = 1000000; 181 fi->symbol_rate_max = 40000000; 182 183 fi->caps = FE_CAN_INVERSION_AUTO | 184 FE_CAN_FEC_1_2 | 185 FE_CAN_FEC_2_3 | 186 FE_CAN_FEC_3_4 | 187 FE_CAN_FEC_5_6 | 188 FE_CAN_FEC_7_8 | 189 FE_CAN_FEC_AUTO | 190 FE_CAN_QPSK; 191 break; 192 193 case FIREDTV_DVB_S2: 194 ops->delsys[0] = SYS_DVBS; 195 ops->delsys[1] = SYS_DVBS2; 196 197 fi->frequency_min = 950000; 198 fi->frequency_max = 2150000; 199 fi->frequency_stepsize = 125; 200 fi->symbol_rate_min = 1000000; 201 fi->symbol_rate_max = 40000000; 202 203 fi->caps = FE_CAN_INVERSION_AUTO | 204 FE_CAN_FEC_1_2 | 205 FE_CAN_FEC_2_3 | 206 FE_CAN_FEC_3_4 | 207 FE_CAN_FEC_5_6 | 208 FE_CAN_FEC_7_8 | 209 FE_CAN_FEC_AUTO | 210 FE_CAN_QPSK | 211 FE_CAN_2G_MODULATION; 212 break; 213 214 case FIREDTV_DVB_C: 215 ops->delsys[0] = SYS_DVBC_ANNEX_A; 216 217 fi->frequency_min = 47000000; 218 fi->frequency_max = 866000000; 219 fi->frequency_stepsize = 62500; 220 fi->symbol_rate_min = 870000; 221 fi->symbol_rate_max = 6900000; 222 223 fi->caps = FE_CAN_INVERSION_AUTO | 224 FE_CAN_QAM_16 | 225 FE_CAN_QAM_32 | 226 FE_CAN_QAM_64 | 227 FE_CAN_QAM_128 | 228 FE_CAN_QAM_256 | 229 FE_CAN_QAM_AUTO; 230 break; 231 232 case FIREDTV_DVB_T: 233 ops->delsys[0] = SYS_DVBT; 234 235 fi->frequency_min = 49000000; 236 fi->frequency_max = 861000000; 237 fi->frequency_stepsize = 62500; 238 239 fi->caps = FE_CAN_INVERSION_AUTO | 240 FE_CAN_FEC_2_3 | 241 FE_CAN_TRANSMISSION_MODE_AUTO | 242 FE_CAN_GUARD_INTERVAL_AUTO | 243 FE_CAN_HIERARCHY_AUTO; 244 break; 245 246 default: 247 dev_err(fdtv->device, "no frontend for model type %d\n", 248 fdtv->type); 249 } 250 strcpy(fi->name, name); 251 252 fdtv->fe.dvb = &fdtv->adapter; 253 fdtv->fe.sec_priv = fdtv; 254} 255