1/* DVB USB compliant Linux driver for the 2 * - GENPIX 8pks/qpsk USB2.0 DVB-S module 3 * 4 * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) 5 * 6 * Thanks to GENPIX for the sample code used to implement this module. 7 * 8 * This module is based off the vp7045 and vp702x modules 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the Free 12 * Software Foundation, version 2. 13 * 14 * see Documentation/dvb/README.dvb-usb for more information 15 */ 16#include "gp8psk.h" 17 18struct gp8psk_fe_state { 19 struct dvb_frontend fe; 20 21 struct dvb_usb_device *d; 22 23 u16 snr; 24 25 unsigned long next_snr_check; 26}; 27 28static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) 29{ 30 struct gp8psk_fe_state *st = fe->demodulator_priv; 31 u8 lock; 32 33 if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1)) 34 return -EINVAL; 35 36 if (lock) 37 *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; 38 else 39 *status = 0; 40 41 return 0; 42} 43 44/* not supported by this Frontend */ 45static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber) 46{ 47 (void) fe; 48 *ber = 0; 49 return 0; 50} 51 52/* not supported by this Frontend */ 53static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) 54{ 55 (void) fe; 56 *unc = 0; 57 return 0; 58} 59 60static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) 61{ 62 struct gp8psk_fe_state *st = fe->demodulator_priv; 63 u8 buf[2]; 64 65 if (time_after(jiffies,st->next_snr_check)) { 66 gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2); 67 *snr = (int)(buf[1]) << 8 | buf[0]; 68 /* snr is reported in dBu*256 */ 69 /* snr / 38.4 ~= 100% strength */ 70 /* snr * 17 returns 100% strength as 65535 */ 71 if (*snr <= 3855) 72 *snr = (*snr<<4) + *snr; // snr * 17 73 else 74 *snr = 65535; 75 st->next_snr_check = jiffies + (10*HZ)/1000; 76 } else { 77 *snr = st->snr; 78 } 79 return 0; 80} 81 82static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) 83{ 84 return gp8psk_fe_read_snr(fe, strength); 85} 86 87static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) 88{ 89 tune->min_delay_ms = 800; 90 return 0; 91} 92 93static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, 94 struct dvb_frontend_parameters *fep) 95{ 96 struct gp8psk_fe_state *state = fe->demodulator_priv; 97 u8 cmd[10]; 98 u32 freq = fep->frequency * 1000; 99 100 cmd[4] = freq & 0xff; 101 cmd[5] = (freq >> 8) & 0xff; 102 cmd[6] = (freq >> 16) & 0xff; 103 cmd[7] = (freq >> 24) & 0xff; 104 105 switch(fe->ops.info.type) { 106 case FE_QPSK: 107 cmd[0] = fep->u.qpsk.symbol_rate & 0xff; 108 cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff; 109 cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff; 110 cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff; 111 cmd[8] = ADV_MOD_DVB_QPSK; 112 cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/ 113 break; 114 default: 115 // other modes are unsuported right now 116 cmd[0] = 0; 117 cmd[1] = 0; 118 cmd[2] = 0; 119 cmd[3] = 0; 120 cmd[8] = 0; 121 cmd[9] = 0; 122 break; 123 } 124 125 gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10); 126 127 state->next_snr_check = jiffies; 128 129 return 0; 130} 131 132static int gp8psk_fe_get_frontend(struct dvb_frontend* fe, 133 struct dvb_frontend_parameters *fep) 134{ 135 return 0; 136} 137 138 139static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, 140 struct dvb_diseqc_master_cmd *m) 141{ 142 struct gp8psk_fe_state *st = fe->demodulator_priv; 143 144 deb_fe("%s\n",__FUNCTION__); 145 146 if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, 147 m->msg, m->msg_len)) { 148 return -EINVAL; 149 } 150 return 0; 151} 152 153static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, 154 fe_sec_mini_cmd_t burst) 155{ 156 struct gp8psk_fe_state *st = fe->demodulator_priv; 157 u8 cmd; 158 159 deb_fe("%s\n",__FUNCTION__); 160 161 /* These commands are certainly wrong */ 162 cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; 163 164 if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, 165 &cmd, 0)) { 166 return -EINVAL; 167 } 168 return 0; 169} 170 171static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) 172{ 173 struct gp8psk_fe_state* state = fe->demodulator_priv; 174 175 if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, 176 (tone == SEC_TONE_ON), 0, NULL, 0)) { 177 return -EINVAL; 178 } 179 return 0; 180} 181 182static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) 183{ 184 struct gp8psk_fe_state* state = fe->demodulator_priv; 185 186 if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, 187 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { 188 return -EINVAL; 189 } 190 return 0; 191} 192 193static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) 194{ 195 struct gp8psk_fe_state* state = fe->demodulator_priv; 196 u8 cmd = sw_cmd & 0x7f; 197 198 if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, 199 NULL, 0)) { 200 return -EINVAL; 201 } 202 if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), 203 0, NULL, 0)) { 204 return -EINVAL; 205 } 206 207 return 0; 208} 209 210static void gp8psk_fe_release(struct dvb_frontend* fe) 211{ 212 struct gp8psk_fe_state *state = fe->demodulator_priv; 213 kfree(state); 214} 215 216static struct dvb_frontend_ops gp8psk_fe_ops; 217 218struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) 219{ 220 struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); 221 if (s == NULL) 222 goto error; 223 224 s->d = d; 225 memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); 226 s->fe.demodulator_priv = s; 227 228 goto success; 229error: 230 return NULL; 231success: 232 return &s->fe; 233} 234 235 236static struct dvb_frontend_ops gp8psk_fe_ops = { 237 .info = { 238 .name = "Genpix 8psk-USB DVB-S", 239 .type = FE_QPSK, 240 .frequency_min = 950000, 241 .frequency_max = 2150000, 242 .frequency_stepsize = 100, 243 .symbol_rate_min = 1000000, 244 .symbol_rate_max = 45000000, 245 .symbol_rate_tolerance = 500, /* ppm */ 246 .caps = FE_CAN_INVERSION_AUTO | 247 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 248 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 249 FE_CAN_QPSK 250 }, 251 252 .release = gp8psk_fe_release, 253 254 .init = NULL, 255 .sleep = NULL, 256 257 .set_frontend = gp8psk_fe_set_frontend, 258 .get_frontend = gp8psk_fe_get_frontend, 259 .get_tune_settings = gp8psk_fe_get_tune_settings, 260 261 .read_status = gp8psk_fe_read_status, 262 .read_ber = gp8psk_fe_read_ber, 263 .read_signal_strength = gp8psk_fe_read_signal_strength, 264 .read_snr = gp8psk_fe_read_snr, 265 .read_ucblocks = gp8psk_fe_read_unc_blocks, 266 267 .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg, 268 .diseqc_send_burst = gp8psk_fe_send_diseqc_burst, 269 .set_tone = gp8psk_fe_set_tone, 270 .set_voltage = gp8psk_fe_set_voltage, 271 .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, 272}; 273