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