• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 struct 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 
gp8psk_tuned_to_DCII(struct dvb_frontend * fe)28 static 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 
gp8psk_set_tuner_mode(struct dvb_frontend * fe,int mode)36 static 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 
gp8psk_fe_update_status(struct gp8psk_fe_state * st)42 static 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 
gp8psk_fe_read_status(struct dvb_frontend * fe,fe_status_t * status)54 static 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 */
gp8psk_fe_read_ber(struct dvb_frontend * fe,u32 * ber)72 static 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 */
gp8psk_fe_read_unc_blocks(struct dvb_frontend * fe,u32 * unc)80 static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
81 {
82 	(void) fe;
83 	*unc = 0;
84 	return 0;
85 }
86 
gp8psk_fe_read_snr(struct dvb_frontend * fe,u16 * snr)87 static 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 
gp8psk_fe_read_signal_strength(struct dvb_frontend * fe,u16 * strength)96 static 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 
gp8psk_fe_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * tune)110 static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
111 {
112 	tune->min_delay_ms = 800;
113 	return 0;
114 }
115 
gp8psk_fe_set_frontend(struct dvb_frontend * fe)116 static int gp8psk_fe_set_frontend(struct dvb_frontend *fe)
117 {
118 	struct gp8psk_fe_state *state = fe->demodulator_priv;
119 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
120 	u8 cmd[10];
121 	u32 freq = c->frequency * 1000;
122 	int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct);
123 
124 	deb_fe("%s()\n", __func__);
125 
126 	cmd[4] = freq         & 0xff;
127 	cmd[5] = (freq >> 8)  & 0xff;
128 	cmd[6] = (freq >> 16) & 0xff;
129 	cmd[7] = (freq >> 24) & 0xff;
130 
131 	/* backwards compatibility: DVB-S + 8-PSK were used for Turbo-FEC */
132 	if (c->delivery_system == SYS_DVBS && c->modulation == PSK_8)
133 		c->delivery_system = SYS_TURBO;
134 
135 	switch (c->delivery_system) {
136 	case SYS_DVBS:
137 		if (c->modulation != QPSK) {
138 			deb_fe("%s: unsupported modulation selected (%d)\n",
139 				__func__, c->modulation);
140 			return -EOPNOTSUPP;
141 		}
142 		c->fec_inner = FEC_AUTO;
143 		break;
144 	case SYS_DVBS2: /* kept for backwards compatibility */
145 		deb_fe("%s: DVB-S2 delivery system selected\n", __func__);
146 		break;
147 	case SYS_TURBO:
148 		deb_fe("%s: Turbo-FEC delivery system selected\n", __func__);
149 		break;
150 
151 	default:
152 		deb_fe("%s: unsupported delivery system selected (%d)\n",
153 			__func__, c->delivery_system);
154 		return -EOPNOTSUPP;
155 	}
156 
157 	cmd[0] =  c->symbol_rate        & 0xff;
158 	cmd[1] = (c->symbol_rate >>  8) & 0xff;
159 	cmd[2] = (c->symbol_rate >> 16) & 0xff;
160 	cmd[3] = (c->symbol_rate >> 24) & 0xff;
161 	switch (c->modulation) {
162 	case QPSK:
163 		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
164 			if (gp8psk_tuned_to_DCII(fe))
165 				gp8psk_bcm4500_reload(state->d);
166 		switch (c->fec_inner) {
167 		case FEC_1_2:
168 			cmd[9] = 0; break;
169 		case FEC_2_3:
170 			cmd[9] = 1; break;
171 		case FEC_3_4:
172 			cmd[9] = 2; break;
173 		case FEC_5_6:
174 			cmd[9] = 3; break;
175 		case FEC_7_8:
176 			cmd[9] = 4; break;
177 		case FEC_AUTO:
178 			cmd[9] = 5; break;
179 		default:
180 			cmd[9] = 5; break;
181 		}
182 		if (c->delivery_system == SYS_TURBO)
183 			cmd[8] = ADV_MOD_TURBO_QPSK;
184 		else
185 			cmd[8] = ADV_MOD_DVB_QPSK;
186 		break;
187 	case PSK_8: /* PSK_8 is for compatibility with DN */
188 		cmd[8] = ADV_MOD_TURBO_8PSK;
189 		switch (c->fec_inner) {
190 		case FEC_2_3:
191 			cmd[9] = 0; break;
192 		case FEC_3_4:
193 			cmd[9] = 1; break;
194 		case FEC_3_5:
195 			cmd[9] = 2; break;
196 		case FEC_5_6:
197 			cmd[9] = 3; break;
198 		case FEC_8_9:
199 			cmd[9] = 4; break;
200 		default:
201 			cmd[9] = 0; break;
202 		}
203 		break;
204 	case QAM_16: /* QAM_16 is for compatibility with DN */
205 		cmd[8] = ADV_MOD_TURBO_16QAM;
206 		cmd[9] = 0;
207 		break;
208 	default: /* Unknown modulation */
209 		deb_fe("%s: unsupported modulation selected (%d)\n",
210 			__func__, c->modulation);
211 		return -EOPNOTSUPP;
212 	}
213 
214 	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
215 		gp8psk_set_tuner_mode(fe, 0);
216 	gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10);
217 
218 	state->lock = 0;
219 	state->next_status_check = jiffies;
220 	state->status_check_interval = 200;
221 
222 	return 0;
223 }
224 
gp8psk_fe_send_diseqc_msg(struct dvb_frontend * fe,struct dvb_diseqc_master_cmd * m)225 static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
226 				    struct dvb_diseqc_master_cmd *m)
227 {
228 	struct gp8psk_fe_state *st = fe->demodulator_priv;
229 
230 	deb_fe("%s\n",__func__);
231 
232 	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
233 			m->msg, m->msg_len)) {
234 		return -EINVAL;
235 	}
236 	return 0;
237 }
238 
gp8psk_fe_send_diseqc_burst(struct dvb_frontend * fe,fe_sec_mini_cmd_t burst)239 static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
240 				    fe_sec_mini_cmd_t burst)
241 {
242 	struct gp8psk_fe_state *st = fe->demodulator_priv;
243 	u8 cmd;
244 
245 	deb_fe("%s\n",__func__);
246 
247 	/* These commands are certainly wrong */
248 	cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
249 
250 	if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
251 			&cmd, 0)) {
252 		return -EINVAL;
253 	}
254 	return 0;
255 }
256 
gp8psk_fe_set_tone(struct dvb_frontend * fe,fe_sec_tone_mode_t tone)257 static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
258 {
259 	struct gp8psk_fe_state* state = fe->demodulator_priv;
260 
261 	if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
262 		 (tone == SEC_TONE_ON), 0, NULL, 0)) {
263 		return -EINVAL;
264 	}
265 	return 0;
266 }
267 
gp8psk_fe_set_voltage(struct dvb_frontend * fe,fe_sec_voltage_t voltage)268 static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
269 {
270 	struct gp8psk_fe_state* state = fe->demodulator_priv;
271 
272 	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
273 			 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
274 		return -EINVAL;
275 	}
276 	return 0;
277 }
278 
gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend * fe,long onoff)279 static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
280 {
281 	struct gp8psk_fe_state* state = fe->demodulator_priv;
282 	return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
283 }
284 
gp8psk_fe_send_legacy_dish_cmd(struct dvb_frontend * fe,unsigned long sw_cmd)285 static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
286 {
287 	struct gp8psk_fe_state* state = fe->demodulator_priv;
288 	u8 cmd = sw_cmd & 0x7f;
289 
290 	if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
291 			NULL, 0)) {
292 		return -EINVAL;
293 	}
294 	if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
295 			0, NULL, 0)) {
296 		return -EINVAL;
297 	}
298 
299 	return 0;
300 }
301 
gp8psk_fe_release(struct dvb_frontend * fe)302 static void gp8psk_fe_release(struct dvb_frontend* fe)
303 {
304 	struct gp8psk_fe_state *state = fe->demodulator_priv;
305 	kfree(state);
306 }
307 
308 static struct dvb_frontend_ops gp8psk_fe_ops;
309 
gp8psk_fe_attach(struct dvb_usb_device * d)310 struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
311 {
312 	struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
313 	if (s == NULL)
314 		goto error;
315 
316 	s->d = d;
317 	memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
318 	s->fe.demodulator_priv = s;
319 
320 	goto success;
321 error:
322 	return NULL;
323 success:
324 	return &s->fe;
325 }
326 
327 
328 static struct dvb_frontend_ops gp8psk_fe_ops = {
329 	.delsys = { SYS_DVBS },
330 	.info = {
331 		.name			= "Genpix DVB-S",
332 		.frequency_min		= 800000,
333 		.frequency_max		= 2250000,
334 		.frequency_stepsize	= 100,
335 		.symbol_rate_min        = 1000000,
336 		.symbol_rate_max        = 45000000,
337 		.symbol_rate_tolerance  = 500,  /* ppm */
338 		.caps = FE_CAN_INVERSION_AUTO |
339 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
340 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
341 			/*
342 			 * FE_CAN_QAM_16 is for compatibility
343 			 * (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
344 			 */
345 			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
346 	},
347 
348 	.release = gp8psk_fe_release,
349 
350 	.init = NULL,
351 	.sleep = NULL,
352 
353 	.set_frontend = gp8psk_fe_set_frontend,
354 
355 	.get_tune_settings = gp8psk_fe_get_tune_settings,
356 
357 	.read_status = gp8psk_fe_read_status,
358 	.read_ber = gp8psk_fe_read_ber,
359 	.read_signal_strength = gp8psk_fe_read_signal_strength,
360 	.read_snr = gp8psk_fe_read_snr,
361 	.read_ucblocks = gp8psk_fe_read_unc_blocks,
362 
363 	.diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
364 	.diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
365 	.set_tone = gp8psk_fe_set_tone,
366 	.set_voltage = gp8psk_fe_set_voltage,
367 	.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
368 	.enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
369 };
370