Commit | Line | Data |
---|---|---|
3706a4da PB |
1 | /* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0 |
2 | * DVB-S receiver. | |
3 | * | |
4 | * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de> | |
5 | * Metzler Brothers Systementwicklung GbR | |
6 | * | |
99e44da7 | 7 | * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de> |
3706a4da PB |
8 | * |
9 | * Thanks to Twinhan who kindly provided hardware and information. | |
10 | * | |
11 | * This file can be removed soon, after the DST-driver is rewritten to provice | |
12 | * the frontend-controlling separately. | |
13 | * | |
14 | * This program is free software; you can redistribute it and/or modify it | |
15 | * under the terms of the GNU General Public License as published by the Free | |
16 | * Software Foundation, version 2. | |
17 | * | |
18 | * see Documentation/dvb/README.dvb-usb for more information | |
19 | * | |
20 | */ | |
21 | #include "vp702x.h" | |
22 | ||
23 | struct vp702x_fe_state { | |
24 | struct dvb_frontend fe; | |
25 | struct dvb_usb_device *d; | |
26 | ||
0540c496 PB |
27 | struct dvb_frontend_ops ops; |
28 | ||
0df289a2 MCC |
29 | enum fe_sec_voltage voltage; |
30 | enum fe_sec_tone_mode tone_mode; | |
3706a4da PB |
31 | |
32 | u8 lnb_buf[8]; | |
33 | ||
34 | u8 lock; | |
35 | u8 sig; | |
36 | u8 snr; | |
37 | ||
38 | unsigned long next_status_check; | |
39 | unsigned long status_check_interval; | |
40 | }; | |
41 | ||
42 | static int vp702x_fe_refresh_state(struct vp702x_fe_state *st) | |
43 | { | |
60f81f12 | 44 | struct vp702x_device_state *dst = st->d->priv; |
57873c72 FM |
45 | u8 *buf; |
46 | ||
47 | if (time_after(jiffies, st->next_status_check)) { | |
60f81f12 FM |
48 | mutex_lock(&dst->buf_mutex); |
49 | buf = dst->buf; | |
50 | ||
57873c72 | 51 | vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10); |
3706a4da | 52 | st->lock = buf[4]; |
57873c72 FM |
53 | |
54 | vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1); | |
55 | st->snr = buf[0]; | |
56 | ||
57 | vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1); | |
58 | st->sig = buf[0]; | |
59 | ||
60f81f12 | 60 | mutex_unlock(&dst->buf_mutex); |
3706a4da PB |
61 | st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; |
62 | } | |
63 | return 0; | |
64 | } | |
65 | ||
66 | static u8 vp702x_chksum(u8 *buf,int f, int count) | |
67 | { | |
68 | u8 s = 0; | |
69 | int i; | |
70 | for (i = f; i < f+count; i++) | |
71 | s += buf[i]; | |
72 | return ~s+1; | |
73 | } | |
74 | ||
0df289a2 MCC |
75 | static int vp702x_fe_read_status(struct dvb_frontend *fe, |
76 | enum fe_status *status) | |
3706a4da PB |
77 | { |
78 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
79 | vp702x_fe_refresh_state(st); | |
708bebdd | 80 | deb_fe("%s\n",__func__); |
3706a4da PB |
81 | |
82 | if (st->lock == 0) | |
83 | *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; | |
84 | else | |
85 | *status = 0; | |
86 | ||
3706a4da PB |
87 | if (*status & FE_HAS_LOCK) |
88 | st->status_check_interval = 1000; | |
89 | else | |
90 | st->status_check_interval = 250; | |
91 | return 0; | |
92 | } | |
93 | ||
94 | /* not supported by this Frontend */ | |
95 | static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber) | |
96 | { | |
97 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
98 | vp702x_fe_refresh_state(st); | |
99 | *ber = 0; | |
100 | return 0; | |
101 | } | |
102 | ||
103 | /* not supported by this Frontend */ | |
104 | static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) | |
105 | { | |
106 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
107 | vp702x_fe_refresh_state(st); | |
108 | *unc = 0; | |
109 | return 0; | |
110 | } | |
111 | ||
112 | static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) | |
113 | { | |
114 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
115 | vp702x_fe_refresh_state(st); | |
116 | ||
117 | *strength = (st->sig << 8) | st->sig; | |
118 | return 0; | |
119 | } | |
120 | ||
121 | static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr) | |
122 | { | |
123 | u8 _snr; | |
124 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
125 | vp702x_fe_refresh_state(st); | |
126 | ||
127 | _snr = (st->snr & 0x1f) * 0xff / 0x1f; | |
128 | *snr = (_snr << 8) | _snr; | |
129 | return 0; | |
130 | } | |
131 | ||
132 | static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) | |
133 | { | |
708bebdd | 134 | deb_fe("%s\n",__func__); |
3706a4da PB |
135 | tune->min_delay_ms = 2000; |
136 | return 0; | |
137 | } | |
138 | ||
4fa102d5 | 139 | static int vp702x_fe_set_frontend(struct dvb_frontend *fe) |
3706a4da | 140 | { |
4fa102d5 | 141 | struct dtv_frontend_properties *fep = &fe->dtv_property_cache; |
3706a4da | 142 | struct vp702x_fe_state *st = fe->demodulator_priv; |
60f81f12 | 143 | struct vp702x_device_state *dst = st->d->priv; |
3706a4da PB |
144 | u32 freq = fep->frequency/1000; |
145 | /*CalFrequency*/ | |
146 | /* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */ | |
147 | u64 sr; | |
57873c72 FM |
148 | u8 *cmd; |
149 | ||
60f81f12 FM |
150 | mutex_lock(&dst->buf_mutex); |
151 | ||
152 | cmd = dst->buf; | |
153 | memset(cmd, 0, 10); | |
3706a4da PB |
154 | |
155 | cmd[0] = (freq >> 8) & 0x7f; | |
156 | cmd[1] = freq & 0xff; | |
157 | cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */ | |
158 | ||
4fa102d5 | 159 | sr = (u64) (fep->symbol_rate/1000) << 20; |
3706a4da PB |
160 | do_div(sr,88000); |
161 | cmd[3] = (sr >> 12) & 0xff; | |
162 | cmd[4] = (sr >> 4) & 0xff; | |
163 | cmd[5] = (sr << 4) & 0xf0; | |
164 | ||
4ae5c2e5 | 165 | deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", |
4fa102d5 | 166 | fep->frequency, freq, freq, fep->symbol_rate, |
4ae5c2e5 | 167 | (unsigned long) sr, (unsigned long) sr); |
3706a4da PB |
168 | |
169 | /* if (fep->inversion == INVERSION_ON) | |
170 | cmd[6] |= 0x80; */ | |
171 | ||
172 | if (st->voltage == SEC_VOLTAGE_18) | |
173 | cmd[6] |= 0x40; | |
174 | ||
4fa102d5 | 175 | /* if (fep->symbol_rate > 8000000) |
3706a4da PB |
176 | cmd[6] |= 0x20; |
177 | ||
178 | if (fep->frequency < 1531000) | |
179 | cmd[6] |= 0x04; | |
180 | ||
181 | if (st->tone_mode == SEC_TONE_ON) | |
182 | cmd[6] |= 0x01;*/ | |
183 | ||
184 | cmd[7] = vp702x_chksum(cmd,0,7); | |
185 | ||
186 | st->status_check_interval = 250; | |
187 | st->next_status_check = jiffies; | |
188 | ||
57873c72 | 189 | vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); |
3706a4da | 190 | |
57873c72 | 191 | if (cmd[2] == 0 && cmd[3] == 0) |
3706a4da PB |
192 | deb_fe("tuning failed.\n"); |
193 | else | |
194 | deb_fe("tuning succeeded.\n"); | |
195 | ||
60f81f12 FM |
196 | mutex_unlock(&dst->buf_mutex); |
197 | ||
3706a4da PB |
198 | return 0; |
199 | } | |
200 | ||
0540c496 PB |
201 | static int vp702x_fe_init(struct dvb_frontend *fe) |
202 | { | |
203 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
708bebdd | 204 | deb_fe("%s\n",__func__); |
0540c496 PB |
205 | vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0); |
206 | return 0; | |
207 | } | |
208 | ||
209 | static int vp702x_fe_sleep(struct dvb_frontend *fe) | |
210 | { | |
708bebdd | 211 | deb_fe("%s\n",__func__); |
0540c496 PB |
212 | return 0; |
213 | } | |
214 | ||
3706a4da | 215 | static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe, |
50c25fff | 216 | struct dvb_diseqc_master_cmd *m) |
3706a4da | 217 | { |
57873c72 | 218 | u8 *cmd; |
5ad5e484 | 219 | struct vp702x_fe_state *st = fe->demodulator_priv; |
60f81f12 | 220 | struct vp702x_device_state *dst = st->d->priv; |
3706a4da | 221 | |
708bebdd | 222 | deb_fe("%s\n",__func__); |
3706a4da | 223 | |
60f81f12 FM |
224 | if (m->msg_len > 4) |
225 | return -EINVAL; | |
226 | ||
227 | mutex_lock(&dst->buf_mutex); | |
3706a4da | 228 | |
60f81f12 | 229 | cmd = dst->buf; |
3706a4da PB |
230 | cmd[1] = SET_DISEQC_CMD; |
231 | cmd[2] = m->msg_len; | |
232 | memcpy(&cmd[3], m->msg, m->msg_len); | |
57873c72 | 233 | cmd[7] = vp702x_chksum(cmd, 0, 7); |
3706a4da | 234 | |
57873c72 | 235 | vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100); |
3706a4da | 236 | |
57873c72 | 237 | if (cmd[2] == 0 && cmd[3] == 0) |
5ad5e484 PE |
238 | deb_fe("diseqc cmd failed.\n"); |
239 | else | |
240 | deb_fe("diseqc cmd succeeded.\n"); | |
60f81f12 FM |
241 | |
242 | mutex_unlock(&dst->buf_mutex); | |
243 | ||
244 | return 0; | |
3706a4da PB |
245 | } |
246 | ||
0df289a2 MCC |
247 | static int vp702x_fe_send_diseqc_burst(struct dvb_frontend *fe, |
248 | enum fe_sec_mini_cmd burst) | |
3706a4da | 249 | { |
708bebdd | 250 | deb_fe("%s\n",__func__); |
3706a4da PB |
251 | return 0; |
252 | } | |
253 | ||
0df289a2 MCC |
254 | static int vp702x_fe_set_tone(struct dvb_frontend *fe, |
255 | enum fe_sec_tone_mode tone) | |
3706a4da PB |
256 | { |
257 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
60f81f12 | 258 | struct vp702x_device_state *dst = st->d->priv; |
57873c72 FM |
259 | u8 *buf; |
260 | ||
708bebdd | 261 | deb_fe("%s\n",__func__); |
3706a4da PB |
262 | |
263 | st->tone_mode = tone; | |
264 | ||
265 | if (tone == SEC_TONE_ON) | |
266 | st->lnb_buf[2] = 0x02; | |
267 | else | |
268 | st->lnb_buf[2] = 0x00; | |
269 | ||
57873c72 | 270 | st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); |
60f81f12 FM |
271 | |
272 | mutex_lock(&dst->buf_mutex); | |
273 | ||
274 | buf = dst->buf; | |
57873c72 | 275 | memcpy(buf, st->lnb_buf, 8); |
3706a4da | 276 | |
57873c72 FM |
277 | vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); |
278 | if (buf[2] == 0 && buf[3] == 0) | |
3706a4da PB |
279 | deb_fe("set_tone cmd failed.\n"); |
280 | else | |
281 | deb_fe("set_tone cmd succeeded.\n"); | |
282 | ||
60f81f12 FM |
283 | mutex_unlock(&dst->buf_mutex); |
284 | ||
3706a4da PB |
285 | return 0; |
286 | } | |
287 | ||
0df289a2 MCC |
288 | static int vp702x_fe_set_voltage(struct dvb_frontend *fe, |
289 | enum fe_sec_voltage voltage) | |
3706a4da PB |
290 | { |
291 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
60f81f12 | 292 | struct vp702x_device_state *dst = st->d->priv; |
57873c72 | 293 | u8 *buf; |
708bebdd | 294 | deb_fe("%s\n",__func__); |
3706a4da PB |
295 | |
296 | st->voltage = voltage; | |
297 | ||
298 | if (voltage != SEC_VOLTAGE_OFF) | |
299 | st->lnb_buf[4] = 0x01; | |
300 | else | |
301 | st->lnb_buf[4] = 0x00; | |
302 | ||
57873c72 | 303 | st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7); |
60f81f12 FM |
304 | |
305 | mutex_lock(&dst->buf_mutex); | |
306 | ||
307 | buf = dst->buf; | |
57873c72 | 308 | memcpy(buf, st->lnb_buf, 8); |
3706a4da | 309 | |
57873c72 FM |
310 | vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100); |
311 | if (buf[2] == 0 && buf[3] == 0) | |
3706a4da PB |
312 | deb_fe("set_voltage cmd failed.\n"); |
313 | else | |
314 | deb_fe("set_voltage cmd succeeded.\n"); | |
315 | ||
60f81f12 | 316 | mutex_unlock(&dst->buf_mutex); |
3706a4da PB |
317 | return 0; |
318 | } | |
319 | ||
320 | static void vp702x_fe_release(struct dvb_frontend* fe) | |
321 | { | |
322 | struct vp702x_fe_state *st = fe->demodulator_priv; | |
323 | kfree(st); | |
324 | } | |
325 | ||
326 | static struct dvb_frontend_ops vp702x_fe_ops; | |
327 | ||
328 | struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) | |
329 | { | |
7408187d | 330 | struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL); |
3706a4da PB |
331 | if (s == NULL) |
332 | goto error; | |
3706a4da PB |
333 | |
334 | s->d = d; | |
dea74869 PB |
335 | |
336 | memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops)); | |
3706a4da PB |
337 | s->fe.demodulator_priv = s; |
338 | ||
339 | s->lnb_buf[1] = SET_LNB_POWER; | |
340 | s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ | |
341 | ||
8397703e | 342 | return &s->fe; |
3706a4da PB |
343 | error: |
344 | return NULL; | |
3706a4da PB |
345 | } |
346 | ||
347 | ||
348 | static struct dvb_frontend_ops vp702x_fe_ops = { | |
4fa102d5 | 349 | .delsys = { SYS_DVBS }, |
3706a4da PB |
350 | .info = { |
351 | .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", | |
3706a4da PB |
352 | .frequency_min = 950000, |
353 | .frequency_max = 2150000, | |
354 | .frequency_stepsize = 1000, /* kHz for QPSK frontends */ | |
355 | .frequency_tolerance = 0, | |
356 | .symbol_rate_min = 1000000, | |
357 | .symbol_rate_max = 45000000, | |
358 | .symbol_rate_tolerance = 500, /* ppm */ | |
359 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | |
360 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | | |
361 | FE_CAN_QPSK | | |
362 | FE_CAN_FEC_AUTO | |
363 | }, | |
364 | .release = vp702x_fe_release, | |
365 | ||
0540c496 PB |
366 | .init = vp702x_fe_init, |
367 | .sleep = vp702x_fe_sleep, | |
3706a4da | 368 | |
4fa102d5 | 369 | .set_frontend = vp702x_fe_set_frontend, |
3706a4da PB |
370 | .get_tune_settings = vp702x_fe_get_tune_settings, |
371 | ||
372 | .read_status = vp702x_fe_read_status, | |
373 | .read_ber = vp702x_fe_read_ber, | |
374 | .read_signal_strength = vp702x_fe_read_signal_strength, | |
375 | .read_snr = vp702x_fe_read_snr, | |
376 | .read_ucblocks = vp702x_fe_read_unc_blocks, | |
377 | ||
378 | .diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg, | |
379 | .diseqc_send_burst = vp702x_fe_send_diseqc_burst, | |
380 | .set_tone = vp702x_fe_set_tone, | |
381 | .set_voltage = vp702x_fe_set_voltage, | |
382 | }; |