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
15struct 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
27static 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
36static 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
76static 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
93static 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
103static 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
138static 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
158static 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
169static 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
188static void ttusbdecfe_release(struct dvb_frontend* fe)
189{
190 struct ttusbdecfe_state *state = fe->demodulator_priv;
191 kfree(objp: state);
192}
193
194static const struct dvb_frontend_ops ttusbdecfe_dvbt_ops;
195
196struct 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(size: 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
214static const struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
215
216struct 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(size: 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
236static 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
259static 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
284MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver");
285MODULE_AUTHOR("Alex Woods/Andrew de Quincey");
286MODULE_LICENSE("GPL");
287
288EXPORT_SYMBOL(ttusbdecfe_dvbt_attach);
289EXPORT_SYMBOL(ttusbdecfe_dvbs_attach);
290

source code of linux/drivers/media/usb/ttusb-dec/ttusbdecfe.c