• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/media/dvb/dvb-usb/
1/*
2 * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
3 *
4 * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
5 *
6 * Based on the dvb-usb-framework code and the
7 * original Terratec Cinergy T2 driver by:
8 *
9 * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
10 *                  Holger Waechtler <holger@qanu.de>
11 *
12 *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 *
28 */
29
30#include "cinergyT2.h"
31
32
33/**
34 *  convert linux-dvb frontend parameter set into TPS.
35 *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
36 *
37 *  This function is probably reusable and may better get placed in a support
38 *  library.
39 *
40 *  We replace errornous fields by default TPS fields (the ones with value 0).
41 */
42
43static uint16_t compute_tps(struct dvb_frontend_parameters *p)
44{
45	struct dvb_ofdm_parameters *op = &p->u.ofdm;
46	uint16_t tps = 0;
47
48	switch (op->code_rate_HP) {
49	case FEC_2_3:
50		tps |= (1 << 7);
51		break;
52	case FEC_3_4:
53		tps |= (2 << 7);
54		break;
55	case FEC_5_6:
56		tps |= (3 << 7);
57		break;
58	case FEC_7_8:
59		tps |= (4 << 7);
60		break;
61	case FEC_1_2:
62	case FEC_AUTO:
63	default:
64		/* tps |= (0 << 7) */;
65	}
66
67	switch (op->code_rate_LP) {
68	case FEC_2_3:
69		tps |= (1 << 4);
70		break;
71	case FEC_3_4:
72		tps |= (2 << 4);
73		break;
74	case FEC_5_6:
75		tps |= (3 << 4);
76		break;
77	case FEC_7_8:
78		tps |= (4 << 4);
79		break;
80	case FEC_1_2:
81	case FEC_AUTO:
82	default:
83		/* tps |= (0 << 4) */;
84	}
85
86	switch (op->constellation) {
87	case QAM_16:
88		tps |= (1 << 13);
89		break;
90	case QAM_64:
91		tps |= (2 << 13);
92		break;
93	case QPSK:
94	default:
95		/* tps |= (0 << 13) */;
96	}
97
98	switch (op->transmission_mode) {
99	case TRANSMISSION_MODE_8K:
100		tps |= (1 << 0);
101		break;
102	case TRANSMISSION_MODE_2K:
103	default:
104		/* tps |= (0 << 0) */;
105	}
106
107	switch (op->guard_interval) {
108	case GUARD_INTERVAL_1_16:
109		tps |= (1 << 2);
110		break;
111	case GUARD_INTERVAL_1_8:
112		tps |= (2 << 2);
113		break;
114	case GUARD_INTERVAL_1_4:
115		tps |= (3 << 2);
116		break;
117	case GUARD_INTERVAL_1_32:
118	default:
119		/* tps |= (0 << 2) */;
120	}
121
122	switch (op->hierarchy_information) {
123	case HIERARCHY_1:
124		tps |= (1 << 10);
125		break;
126	case HIERARCHY_2:
127		tps |= (2 << 10);
128		break;
129	case HIERARCHY_4:
130		tps |= (3 << 10);
131		break;
132	case HIERARCHY_NONE:
133	default:
134		/* tps |= (0 << 10) */;
135	}
136
137	return tps;
138}
139
140struct cinergyt2_fe_state {
141	struct dvb_frontend fe;
142	struct dvb_usb_device *d;
143};
144
145static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
146					fe_status_t *status)
147{
148	struct cinergyt2_fe_state *state = fe->demodulator_priv;
149	struct dvbt_get_status_msg result;
150	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
151	int ret;
152
153	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
154			sizeof(result), 0);
155	if (ret < 0)
156		return ret;
157
158	*status = 0;
159
160	if (0xffff - le16_to_cpu(result.gain) > 30)
161		*status |= FE_HAS_SIGNAL;
162	if (result.lock_bits & (1 << 6))
163		*status |= FE_HAS_LOCK;
164	if (result.lock_bits & (1 << 5))
165		*status |= FE_HAS_SYNC;
166	if (result.lock_bits & (1 << 4))
167		*status |= FE_HAS_CARRIER;
168	if (result.lock_bits & (1 << 1))
169		*status |= FE_HAS_VITERBI;
170
171	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
172			(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
173		*status &= ~FE_HAS_LOCK;
174
175	return 0;
176}
177
178static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
179{
180	struct cinergyt2_fe_state *state = fe->demodulator_priv;
181	struct dvbt_get_status_msg status;
182	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
183	int ret;
184
185	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
186				sizeof(status), 0);
187	if (ret < 0)
188		return ret;
189
190	*ber = le32_to_cpu(status.viterbi_error_rate);
191	return 0;
192}
193
194static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
195{
196	struct cinergyt2_fe_state *state = fe->demodulator_priv;
197	struct dvbt_get_status_msg status;
198	u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
199	int ret;
200
201	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
202				sizeof(status), 0);
203	if (ret < 0) {
204		err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
205			ret);
206		return ret;
207	}
208	*unc = le32_to_cpu(status.uncorrected_block_count);
209	return 0;
210}
211
212static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
213						u16 *strength)
214{
215	struct cinergyt2_fe_state *state = fe->demodulator_priv;
216	struct dvbt_get_status_msg status;
217	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
218	int ret;
219
220	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
221				sizeof(status), 0);
222	if (ret < 0) {
223		err("cinergyt2_fe_read_signal_strength() Failed!"
224			" (Error=%d)\n", ret);
225		return ret;
226	}
227	*strength = (0xffff - le16_to_cpu(status.gain));
228	return 0;
229}
230
231static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
232{
233	struct cinergyt2_fe_state *state = fe->demodulator_priv;
234	struct dvbt_get_status_msg status;
235	char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
236	int ret;
237
238	ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
239				sizeof(status), 0);
240	if (ret < 0) {
241		err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
242		return ret;
243	}
244	*snr = (status.snr << 8) | status.snr;
245	return 0;
246}
247
248static int cinergyt2_fe_init(struct dvb_frontend *fe)
249{
250	return 0;
251}
252
253static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
254{
255	deb_info("cinergyt2_fe_sleep() Called\n");
256	return 0;
257}
258
259static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
260				struct dvb_frontend_tune_settings *tune)
261{
262	tune->min_delay_ms = 800;
263	return 0;
264}
265
266static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,
267				  struct dvb_frontend_parameters *fep)
268{
269	struct cinergyt2_fe_state *state = fe->demodulator_priv;
270	struct dvbt_set_parameters_msg param;
271	char result[2];
272	int err;
273
274	param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
275	param.tps = cpu_to_le16(compute_tps(fep));
276	param.freq = cpu_to_le32(fep->frequency / 1000);
277	param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;
278	param.flags = 0;
279
280	err = dvb_usb_generic_rw(state->d,
281			(char *)&param, sizeof(param),
282			result, sizeof(result), 0);
283	if (err < 0)
284		err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
285
286	return (err < 0) ? err : 0;
287}
288
289static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,
290				  struct dvb_frontend_parameters *fep)
291{
292	return 0;
293}
294
295static void cinergyt2_fe_release(struct dvb_frontend *fe)
296{
297	struct cinergyt2_fe_state *state = fe->demodulator_priv;
298	if (state != NULL)
299		kfree(state);
300}
301
302static struct dvb_frontend_ops cinergyt2_fe_ops;
303
304struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
305{
306	struct cinergyt2_fe_state *s = kzalloc(sizeof(
307					struct cinergyt2_fe_state), GFP_KERNEL);
308	if (s == NULL)
309		return NULL;
310
311	s->d = d;
312	memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
313	s->fe.demodulator_priv = s;
314	return &s->fe;
315}
316
317
318static struct dvb_frontend_ops cinergyt2_fe_ops = {
319	.info = {
320		.name			= DRIVER_NAME,
321		.type			= FE_OFDM,
322		.frequency_min		= 174000000,
323		.frequency_max		= 862000000,
324		.frequency_stepsize	= 166667,
325		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2
326			| FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
327			| FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8
328			| FE_CAN_FEC_AUTO | FE_CAN_QPSK
329			| FE_CAN_QAM_16 | FE_CAN_QAM_64
330			| FE_CAN_QAM_AUTO
331			| FE_CAN_TRANSMISSION_MODE_AUTO
332			| FE_CAN_GUARD_INTERVAL_AUTO
333			| FE_CAN_HIERARCHY_AUTO
334			| FE_CAN_RECOVER
335			| FE_CAN_MUTE_TS
336	},
337
338	.release		= cinergyt2_fe_release,
339
340	.init			= cinergyt2_fe_init,
341	.sleep			= cinergyt2_fe_sleep,
342
343	.set_frontend		= cinergyt2_fe_set_frontend,
344	.get_frontend		= cinergyt2_fe_get_frontend,
345	.get_tune_settings	= cinergyt2_fe_get_tune_settings,
346
347	.read_status		= cinergyt2_fe_read_status,
348	.read_ber		= cinergyt2_fe_read_ber,
349	.read_signal_strength	= cinergyt2_fe_read_signal_strength,
350	.read_snr		= cinergyt2_fe_read_snr,
351	.read_ucblocks		= cinergyt2_fe_read_unc_blocks,
352};
353