1/* DVB USB compliant Linux driver for the 2 * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module 3 * 4 * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) 5 * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) 6 * 7 * Thanks to GENPIX for the sample code used to implement this module. 8 * 9 * This module is based off the vp7045 and vp702x modules 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License as published by the Free 13 * Software Foundation, version 2. 14 * 15 * see Documentation/dvb/README.dvb-usb for more information 16 */ 17#include "gp8psk.h" 18 19struct gp8psk_fe_state { 20 struct dvb_frontend fe; 21 struct dvb_usb_device *d; 22 u8 lock; 23 u16 snr; 24 unsigned long next_status_check; 25 unsigned long status_check_interval; 26}; 27 28static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) 29{ 30 struct gp8psk_fe_state *st = fe->demodulator_priv; 31 u8 status; 32 gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1); 33 return status & bmDCtuned; 34} 35 36static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) 37{ 38 struct gp8psk_fe_state *state = fe->demodulator_priv; 39 return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); 40} 41 42static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) 43{ 44 u8 buf[6]; 45 if (time_after(jiffies,st->next_status_check)) { 46 gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); 47 gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); 48 st->snr = (buf[1]) << 8 | buf[0]; 49 st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; 50 } 51 return 0; 52} 53 54static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) 55{ 56 struct gp8psk_fe_state *st = fe->demodulator_priv; 57 gp8psk_fe_update_status(st); 58 59 if (st->lock) 60 *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; 61 else 62 *status = 0; 63 64 if (*status & FE_HAS_LOCK) 65 st->status_check_interval = 1000; 66 else 67 st->status_check_interval = 100; 68 return 0; 69} 70 71/* not supported by this Frontend */ 72static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber) 73{ 74 (void) fe; 75 *ber = 0; 76 return 0; 77} 78 79/* not supported by this Frontend */ 80static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) 81{ 82 (void) fe; 83 *unc = 0; 84 return 0; 85} 86 87static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) 88{ 89 struct gp8psk_fe_state *st = fe->demodulator_priv; 90 gp8psk_fe_update_status(st); 91 /* snr is reported in dBu*256 */ 92 *snr = st->snr; 93 return 0; 94} 95 96static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) 97{ 98 struct gp8psk_fe_state *st = fe->demodulator_priv; 99 gp8psk_fe_update_status(st); 100 /* snr is reported in dBu*256 */ 101 /* snr / 38.4 ~= 100% strength */ 102 /* snr * 17 returns 100% strength as 65535 */ 103 if (st->snr > 0xf00) 104 *strength = 0xffff; 105 else 106 *strength = (st->snr << 4) + st->snr; /* snr*17 */ 107 return 0; 108} 109 110static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) 111{ 112 tune->min_delay_ms = 200; 113 return 0; 114} 115 116static int gp8psk_fe_set_property(struct dvb_frontend *fe, 117 struct dtv_property *tvp) 118{ 119 deb_fe("%s(..)\n", __func__); 120 return 0; 121} 122 123static int gp8psk_fe_get_property(struct dvb_frontend *fe, 124 struct dtv_property *tvp) 125{ 126 deb_fe("%s(..)\n", __func__); 127 return 0; 128} 129 130 131static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, 132 struct dvb_frontend_parameters *fep) 133{ 134 struct gp8psk_fe_state *state = fe->demodulator_priv; 135 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 136 u8 cmd[10]; 137 u32 freq = fep->frequency * 1000; 138 int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); 139 140 deb_fe("%s()\n", __func__); 141 142 cmd[4] = freq & 0xff; 143 cmd[5] = (freq >> 8) & 0xff; 144 cmd[6] = (freq >> 16) & 0xff; 145 cmd[7] = (freq >> 24) & 0xff; 146 147 switch (c->delivery_system) { 148 case SYS_DVBS: 149 /* Allow QPSK and 8PSK (even for DVB-S) */ 150 if (c->modulation != QPSK && c->modulation != PSK_8) { 151 deb_fe("%s: unsupported modulation selected (%d)\n", 152 __func__, c->modulation); 153 return -EOPNOTSUPP; 154 } 155 c->fec_inner = FEC_AUTO; 156 break; 157 case SYS_DVBS2: 158 deb_fe("%s: DVB-S2 delivery system selected\n", __func__); 159 break; 160 161 default: 162 deb_fe("%s: unsupported delivery system selected (%d)\n", 163 __func__, c->delivery_system); 164 return -EOPNOTSUPP; 165 } 166 167 cmd[0] = c->symbol_rate & 0xff; 168 cmd[1] = (c->symbol_rate >> 8) & 0xff; 169 cmd[2] = (c->symbol_rate >> 16) & 0xff; 170 cmd[3] = (c->symbol_rate >> 24) & 0xff; 171 switch (c->modulation) { 172 case QPSK: 173 if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) 174 if (gp8psk_tuned_to_DCII(fe)) 175 gp8psk_bcm4500_reload(state->d); 176 switch (c->fec_inner) { 177 case FEC_1_2: 178 cmd[9] = 0; break; 179 case FEC_2_3: 180 cmd[9] = 1; break; 181 case FEC_3_4: 182 cmd[9] = 2; break; 183 case FEC_5_6: 184 cmd[9] = 3; break; 185 case FEC_7_8: 186 cmd[9] = 4; break; 187 case FEC_AUTO: 188 cmd[9] = 5; break; 189 default: 190 cmd[9] = 5; break; 191 } 192 cmd[8] = ADV_MOD_DVB_QPSK; 193 break; 194 case PSK_8: /* PSK_8 is for compatibility with DN */ 195 cmd[8] = ADV_MOD_TURBO_8PSK; 196 switch (c->fec_inner) { 197 case FEC_2_3: 198 cmd[9] = 0; break; 199 case FEC_3_4: 200 cmd[9] = 1; break; 201 case FEC_3_5: 202 cmd[9] = 2; break; 203 case FEC_5_6: 204 cmd[9] = 3; break; 205 case FEC_8_9: 206 cmd[9] = 4; break; 207 default: 208 cmd[9] = 0; break; 209 } 210 break; 211 case QAM_16: /* QAM_16 is for compatibility with DN */ 212 cmd[8] = ADV_MOD_TURBO_16QAM; 213 cmd[9] = 0; 214 break; 215 default: /* Unknown modulation */ 216 deb_fe("%s: unsupported modulation selected (%d)\n", 217 __func__, c->modulation); 218 return -EOPNOTSUPP; 219 } 220 221 if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) 222 gp8psk_set_tuner_mode(fe, 0); 223 gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10); 224 225 state->lock = 0; 226 state->next_status_check = jiffies; 227 state->status_check_interval = 200; 228 229 return 0; 230} 231 232static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, 233 struct dvb_diseqc_master_cmd *m) 234{ 235 struct gp8psk_fe_state *st = fe->demodulator_priv; 236 237 deb_fe("%s\n",__func__); 238 239 if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, 240 m->msg, m->msg_len)) { 241 return -EINVAL; 242 } 243 return 0; 244} 245 246static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, 247 fe_sec_mini_cmd_t burst) 248{ 249 struct gp8psk_fe_state *st = fe->demodulator_priv; 250 u8 cmd; 251 252 deb_fe("%s\n",__func__); 253 254 /* These commands are certainly wrong */ 255 cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; 256 257 if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, 258 &cmd, 0)) { 259 return -EINVAL; 260 } 261 return 0; 262} 263 264static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) 265{ 266 struct gp8psk_fe_state* state = fe->demodulator_priv; 267 268 if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, 269 (tone == SEC_TONE_ON), 0, NULL, 0)) { 270 return -EINVAL; 271 } 272 return 0; 273} 274 275static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) 276{ 277 struct gp8psk_fe_state* state = fe->demodulator_priv; 278 279 if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, 280 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { 281 return -EINVAL; 282 } 283 return 0; 284} 285 286static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) 287{ 288 struct gp8psk_fe_state* state = fe->demodulator_priv; 289 return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); 290} 291 292static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) 293{ 294 struct gp8psk_fe_state* state = fe->demodulator_priv; 295 u8 cmd = sw_cmd & 0x7f; 296 297 if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, 298 NULL, 0)) { 299 return -EINVAL; 300 } 301 if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), 302 0, NULL, 0)) { 303 return -EINVAL; 304 } 305 306 return 0; 307} 308 309static void gp8psk_fe_release(struct dvb_frontend* fe) 310{ 311 struct gp8psk_fe_state *state = fe->demodulator_priv; 312 kfree(state); 313} 314 315static struct dvb_frontend_ops gp8psk_fe_ops; 316 317struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) 318{ 319 struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); 320 if (s == NULL) 321 goto error; 322 323 s->d = d; 324 memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); 325 s->fe.demodulator_priv = s; 326 327 goto success; 328error: 329 return NULL; 330success: 331 return &s->fe; 332} 333 334 335static struct dvb_frontend_ops gp8psk_fe_ops = { 336 .info = { 337 .name = "Genpix 8psk-to-USB2 DVB-S", 338 .type = FE_QPSK, 339 .frequency_min = 800000, 340 .frequency_max = 2250000, 341 .frequency_stepsize = 100, 342 .symbol_rate_min = 1000000, 343 .symbol_rate_max = 45000000, 344 .symbol_rate_tolerance = 500, /* ppm */ 345 .caps = FE_CAN_INVERSION_AUTO | 346 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 347 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 348 /* 349 * FE_CAN_QAM_16 is for compatibility 350 * (Myth incorrectly detects Turbo-QPSK as plain QAM-16) 351 */ 352 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC 353 }, 354 355 .release = gp8psk_fe_release, 356 357 .init = NULL, 358 .sleep = NULL, 359 360 .set_property = gp8psk_fe_set_property, 361 .get_property = gp8psk_fe_get_property, 362 .set_frontend = gp8psk_fe_set_frontend, 363 364 .get_tune_settings = gp8psk_fe_get_tune_settings, 365 366 .read_status = gp8psk_fe_read_status, 367 .read_ber = gp8psk_fe_read_ber, 368 .read_signal_strength = gp8psk_fe_read_signal_strength, 369 .read_snr = gp8psk_fe_read_snr, 370 .read_ucblocks = gp8psk_fe_read_unc_blocks, 371 372 .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg, 373 .diseqc_send_burst = gp8psk_fe_send_diseqc_burst, 374 .set_tone = gp8psk_fe_set_tone, 375 .set_voltage = gp8psk_fe_set_voltage, 376 .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, 377 .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage 378}; 379