1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * TTUSB DEC Frontend Driver
4  *
5  * Copyright (C) 2003-2004 Alex Woods <linux-dvb@giblets.org>
6  */
7 
8 #include <media/dvb_frontend.h>
9 #include "ttusbdecfe.h"
10 
11 
12 #define LOF_HI			10600000
13 #define LOF_LO			9750000
14 
15 struct ttusbdecfe_state {
16 
17 	/* configuration settings */
18 	const struct ttusbdecfe_config* config;
19 
20 	struct dvb_frontend frontend;
21 
22 	u8 hi_band;
23 	u8 voltage;
24 };
25 
26 
27 static int ttusbdecfe_dvbs_read_status(struct dvb_frontend *fe,
28 				       enum fe_status *status)
29 {
30 	*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
31 		FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
32 	return 0;
33 }
34 
35 
36 static int ttusbdecfe_dvbt_read_status(struct dvb_frontend *fe,
37 				       enum fe_status *status)
38 {
39 	struct ttusbdecfe_state* state = fe->demodulator_priv;
40 	u8 b[] = { 0x00, 0x00, 0x00, 0x00,
41 		   0x00, 0x00, 0x00, 0x00 };
42 	u8 result[4];
43 	int len, ret;
44 
45 	*status=0;
46 
47 	ret=state->config->send_command(fe, 0x73, sizeof(b), b, &len, result);
48 	if(ret)
49 		return ret;
50 
51 	if(len != 4) {
52 		printk(KERN_ERR "%s: unexpected reply\n", __func__);
53 		return -EIO;
54 	}
55 
56 	switch(result[3]) {
57 		case 1:  /* not tuned yet */
58 		case 2:  /* no signal/no lock*/
59 			break;
60 		case 3:	 /* signal found and locked*/
61 			*status = FE_HAS_SIGNAL | FE_HAS_VITERBI |
62 			FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK;
63 			break;
64 		case 4:
65 			*status = FE_TIMEDOUT;
66 			break;
67 		default:
68 			pr_info("%s: returned unknown value: %d\n",
69 				__func__, result[3]);
70 			return -EIO;
71 	}
72 
73 	return 0;
74 }
75 
76 static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend *fe)
77 {
78 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
79 	struct ttusbdecfe_state *state = fe->demodulator_priv;
80 	u8 b[] = { 0x00, 0x00, 0x00, 0x03,
81 		   0x00, 0x00, 0x00, 0x00,
82 		   0x00, 0x00, 0x00, 0x01,
83 		   0x00, 0x00, 0x00, 0xff,
84 		   0x00, 0x00, 0x00, 0xff };
85 
86 	__be32 freq = htonl(p->frequency / 1000);
87 	memcpy(&b[4], &freq, sizeof (u32));
88 	state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
89 
90 	return 0;
91 }
92 
93 static int ttusbdecfe_dvbt_get_tune_settings(struct dvb_frontend* fe,
94 					struct dvb_frontend_tune_settings* fesettings)
95 {
96 		fesettings->min_delay_ms = 1500;
97 		/* Drift compensation makes no sense for DVB-T */
98 		fesettings->step_size = 0;
99 		fesettings->max_drift = 0;
100 		return 0;
101 }
102 
103 static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend *fe)
104 {
105 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
106 	struct ttusbdecfe_state *state = fe->demodulator_priv;
107 
108 	u8 b[] = { 0x00, 0x00, 0x00, 0x01,
109 		   0x00, 0x00, 0x00, 0x00,
110 		   0x00, 0x00, 0x00, 0x01,
111 		   0x00, 0x00, 0x00, 0x00,
112 		   0x00, 0x00, 0x00, 0x00,
113 		   0x00, 0x00, 0x00, 0x00,
114 		   0x00, 0x00, 0x00, 0x00,
115 		   0x00, 0x00, 0x00, 0x00,
116 		   0x00, 0x00, 0x00, 0x00,
117 		   0x00, 0x00, 0x00, 0x00 };
118 	__be32 freq;
119 	__be32 sym_rate;
120 	__be32 band;
121 	__be32 lnb_voltage;
122 
123 	freq = htonl(p->frequency +
124 	       (state->hi_band ? LOF_HI : LOF_LO));
125 	memcpy(&b[4], &freq, sizeof(u32));
126 	sym_rate = htonl(p->symbol_rate);
127 	memcpy(&b[12], &sym_rate, sizeof(u32));
128 	band = htonl(state->hi_band ? LOF_HI : LOF_LO);
129 	memcpy(&b[24], &band, sizeof(u32));
130 	lnb_voltage = htonl(state->voltage);
131 	memcpy(&b[28], &lnb_voltage, sizeof(u32));
132 
133 	state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL);
134 
135 	return 0;
136 }
137 
138 static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
139 {
140 	struct ttusbdecfe_state *state = fe->demodulator_priv;
141 	u8 b[] = { 0x00, 0xff, 0x00, 0x00,
142 		   0x00, 0x00, 0x00, 0x00,
143 		   0x00, 0x00 };
144 
145 	if (cmd->msg_len > sizeof(b) - 4)
146 		return -EINVAL;
147 
148 	memcpy(&b[4], cmd->msg, cmd->msg_len);
149 
150 	state->config->send_command(fe, 0x72,
151 				    sizeof(b) - (6 - cmd->msg_len), b,
152 				    NULL, NULL);
153 
154 	return 0;
155 }
156 
157 
158 static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend *fe,
159 				    enum fe_sec_tone_mode tone)
160 {
161 	struct ttusbdecfe_state *state = fe->demodulator_priv;
162 
163 	state->hi_band = (SEC_TONE_ON == tone);
164 
165 	return 0;
166 }
167 
168 
169 static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend *fe,
170 				       enum fe_sec_voltage voltage)
171 {
172 	struct ttusbdecfe_state *state = fe->demodulator_priv;
173 
174 	switch (voltage) {
175 	case SEC_VOLTAGE_13:
176 		state->voltage = 13;
177 		break;
178 	case SEC_VOLTAGE_18:
179 		state->voltage = 18;
180 		break;
181 	default:
182 		return -EINVAL;
183 	}
184 
185 	return 0;
186 }
187 
188 static void ttusbdecfe_release(struct dvb_frontend* fe)
189 {
190 	struct ttusbdecfe_state *state = fe->demodulator_priv;
191 	kfree(state);
192 }
193 
194 static const struct dvb_frontend_ops ttusbdecfe_dvbt_ops;
195 
196 struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config)
197 {
198 	struct ttusbdecfe_state* state = NULL;
199 
200 	/* allocate memory for the internal state */
201 	state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
202 	if (state == NULL)
203 		return NULL;
204 
205 	/* setup the state */
206 	state->config = config;
207 
208 	/* create dvb_frontend */
209 	memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
210 	state->frontend.demodulator_priv = state;
211 	return &state->frontend;
212 }
213 
214 static const struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
215 
216 struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config)
217 {
218 	struct ttusbdecfe_state* state = NULL;
219 
220 	/* allocate memory for the internal state */
221 	state = kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
222 	if (state == NULL)
223 		return NULL;
224 
225 	/* setup the state */
226 	state->config = config;
227 	state->voltage = 0;
228 	state->hi_band = 0;
229 
230 	/* create dvb_frontend */
231 	memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
232 	state->frontend.demodulator_priv = state;
233 	return &state->frontend;
234 }
235 
236 static const struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
237 	.delsys = { SYS_DVBT },
238 	.info = {
239 		.name			= "TechnoTrend/Hauppauge DEC2000-t Frontend",
240 		.frequency_min_hz	=  51 * MHz,
241 		.frequency_max_hz	= 858 * MHz,
242 		.frequency_stepsize_hz	= 62500,
243 		.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
244 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
245 			FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
246 			FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
247 			FE_CAN_HIERARCHY_AUTO,
248 	},
249 
250 	.release = ttusbdecfe_release,
251 
252 	.set_frontend = ttusbdecfe_dvbt_set_frontend,
253 
254 	.get_tune_settings = ttusbdecfe_dvbt_get_tune_settings,
255 
256 	.read_status = ttusbdecfe_dvbt_read_status,
257 };
258 
259 static const struct dvb_frontend_ops ttusbdecfe_dvbs_ops = {
260 	.delsys = { SYS_DVBS },
261 	.info = {
262 		.name			= "TechnoTrend/Hauppauge DEC3000-s Frontend",
263 		.frequency_min_hz	=  950 * MHz,
264 		.frequency_max_hz	= 2150 * MHz,
265 		.frequency_stepsize_hz	=  125 * kHz,
266 		.symbol_rate_min        = 1000000,  /* guessed */
267 		.symbol_rate_max        = 45000000, /* guessed */
268 		.caps =	FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
269 			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
270 			FE_CAN_QPSK
271 	},
272 
273 	.release = ttusbdecfe_release,
274 
275 	.set_frontend = ttusbdecfe_dvbs_set_frontend,
276 
277 	.read_status = ttusbdecfe_dvbs_read_status,
278 
279 	.diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd,
280 	.set_voltage = ttusbdecfe_dvbs_set_voltage,
281 	.set_tone = ttusbdecfe_dvbs_set_tone,
282 };
283 
284 MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver");
285 MODULE_AUTHOR("Alex Woods/Andrew de Quincey");
286 MODULE_LICENSE("GPL");
287 
288 EXPORT_SYMBOL(ttusbdecfe_dvbt_attach);
289 EXPORT_SYMBOL(ttusbdecfe_dvbs_attach);
290