blob: 4242005082ed33204f49668a7d36c7fd0cca918f [file] [log] [blame]
Uri Shkolnike5275792009-04-27 09:09:47 -03001/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2008, Uri Shkolnik
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or
10(at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
Steven Toth8d4f9d02008-05-22 18:05:26 -030021
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030022#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030024#include <linux/init.h>
25
Uri Shkolnikc9679e32009-05-14 16:28:17 -030026#include "dmxdev.h"
27#include "dvbdev.h"
28#include "dvb_demux.h"
29#include "dvb_frontend.h"
30
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030031#include "smscoreapi.h"
Michael Krufky1c11d542008-06-18 22:09:55 -030032#include "sms-cards.h"
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030033
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -030034#include "smsdvb.h"
35
Michael Krufky9c59f9682008-05-19 18:57:12 -030036DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
37
Adrian Bunkc5e0bd12008-07-21 23:17:36 -030038static struct list_head g_smsdvb_clients;
39static struct mutex g_smsdvb_clientslock;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030040
Michael Krufky0d02efe2009-02-27 02:42:16 -030041static int sms_dbg;
42module_param_named(debug, sms_dbg, int, 0644);
43MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
44
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -030045
46u32 sms_to_bw_table[] = {
47 [BW_8_MHZ] = 8000000,
48 [BW_7_MHZ] = 7000000,
49 [BW_6_MHZ] = 6000000,
50 [BW_5_MHZ] = 5000000,
51 [BW_2_MHZ] = 2000000,
52 [BW_1_5_MHZ] = 1500000,
53 [BW_ISDBT_1SEG] = 6000000,
54 [BW_ISDBT_3SEG] = 6000000,
55 [BW_ISDBT_13SEG] = 6000000,
56};
57
58u32 sms_to_guard_interval_table[] = {
59 [0] = GUARD_INTERVAL_1_32,
60 [1] = GUARD_INTERVAL_1_16,
61 [2] = GUARD_INTERVAL_1_8,
62 [3] = GUARD_INTERVAL_1_4,
63};
64
65u32 sms_to_code_rate_table[] = {
66 [0] = FEC_1_2,
67 [1] = FEC_2_3,
68 [2] = FEC_3_4,
69 [3] = FEC_5_6,
70 [4] = FEC_7_8,
71};
72
73
74u32 sms_to_hierarchy_table[] = {
75 [0] = HIERARCHY_NONE,
76 [1] = HIERARCHY_1,
77 [2] = HIERARCHY_2,
78 [3] = HIERARCHY_4,
79};
80
81u32 sms_to_modulation_table[] = {
82 [0] = QPSK,
83 [1] = QAM_16,
84 [2] = QAM_64,
85 [3] = DQPSK,
86};
87
Mauro Carvalho Chehabff702eb2013-03-09 15:54:46 -030088
Uri Shkolnik793786d2009-05-12 12:28:46 -030089/* Events that may come from DVB v3 adapter */
90static void sms_board_dvb3_event(struct smsdvb_client_t *client,
91 enum SMS_DVB3_EVENTS event) {
Uri Shkolnik4db989f2009-05-19 12:28:02 -030092
93 struct smscore_device_t *coredev = client->coredev;
94 switch (event) {
95 case DVB3_EVENT_INIT:
96 sms_debug("DVB3_EVENT_INIT");
97 sms_board_event(coredev, BOARD_EVENT_BIND);
98 break;
99 case DVB3_EVENT_SLEEP:
100 sms_debug("DVB3_EVENT_SLEEP");
101 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
102 break;
103 case DVB3_EVENT_HOTPLUG:
104 sms_debug("DVB3_EVENT_HOTPLUG");
105 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
106 break;
107 case DVB3_EVENT_FE_LOCK:
108 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
109 client->event_fe_state = DVB3_EVENT_FE_LOCK;
110 sms_debug("DVB3_EVENT_FE_LOCK");
111 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
112 }
113 break;
114 case DVB3_EVENT_FE_UNLOCK:
115 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
116 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
117 sms_debug("DVB3_EVENT_FE_UNLOCK");
118 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
119 }
120 break;
121 case DVB3_EVENT_UNC_OK:
122 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
123 client->event_unc_state = DVB3_EVENT_UNC_OK;
124 sms_debug("DVB3_EVENT_UNC_OK");
125 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
126 }
127 break;
128 case DVB3_EVENT_UNC_ERR:
129 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
130 client->event_unc_state = DVB3_EVENT_UNC_ERR;
131 sms_debug("DVB3_EVENT_UNC_ERR");
132 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
133 }
134 break;
135
136 default:
137 sms_err("Unknown dvb3 api event");
138 break;
139 }
Uri Shkolnik793786d2009-05-12 12:28:46 -0300140}
141
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300142static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300143{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300144 struct smsdvb_client_t *client =
145 container_of(fe, struct smsdvb_client_t, frontend);
146 struct smscore_device_t *coredev = client->coredev;
147 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
148 int i, n_layers;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300149
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300150 switch (smscore_get_device_mode(coredev)) {
151 case DEVICE_MODE_ISDBT:
152 case DEVICE_MODE_ISDBT_BDA:
153 n_layers = 4;
154 default:
155 n_layers = 1;
156 }
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300157
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300158 /* Fill the length of each status counter */
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300159
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300160 /* Only global stats */
161 c->strength.len = 1;
162 c->cnr.len = 1;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300163
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300164 /* Per-layer stats */
165 c->post_bit_error.len = n_layers;
166 c->post_bit_count.len = n_layers;
167 c->block_error.len = n_layers;
168 c->block_count.len = n_layers;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300169
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300170 /* Signal is always available */
171 c->strength.stat[0].scale = FE_SCALE_RELATIVE;
172 c->strength.stat[0].uvalue = 0;
173
174 /* Put all of them at FE_SCALE_NOT_AVAILABLE */
175 for (i = 0; i < n_layers; i++) {
176 c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
177 c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
178 c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
179 c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
180 c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300181 }
182}
183
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300184static inline int sms_to_mode(u32 mode)
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300185{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300186 switch (mode) {
187 case 2:
188 return TRANSMISSION_MODE_2K;
189 case 4:
190 return TRANSMISSION_MODE_4K;
191 case 8:
192 return TRANSMISSION_MODE_8K;
193 }
194 return TRANSMISSION_MODE_AUTO;
195}
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300196
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300197static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)
198{
199 if (is_demod_locked)
200 return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
201 FE_HAS_SYNC | FE_HAS_LOCK;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300202
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300203 if (is_rf_locked)
204 return FE_HAS_SIGNAL | FE_HAS_CARRIER;
205
206 return 0;
207}
208
209
210#define convert_from_table(value, table, defval) ({ \
211 u32 __ret; \
212 if (value < ARRAY_SIZE(table)) \
213 __ret = table[value]; \
214 else \
215 __ret = defval; \
216 __ret; \
217})
218
219#define sms_to_bw(value) \
220 convert_from_table(value, sms_to_bw_table, 0);
221
222#define sms_to_guard_interval(value) \
223 convert_from_table(value, sms_to_guard_interval_table, \
224 GUARD_INTERVAL_AUTO);
225
226#define sms_to_code_rate(value) \
227 convert_from_table(value, sms_to_code_rate_table, \
228 FEC_NONE);
229
230#define sms_to_hierarchy(value) \
231 convert_from_table(value, sms_to_hierarchy_table, \
232 FEC_NONE);
233
234#define sms_to_modulation(value) \
235 convert_from_table(value, sms_to_modulation_table, \
236 FEC_NONE);
237
238static void smsdvb_update_tx_params(struct smsdvb_client_t *client,
239 struct TRANSMISSION_STATISTICS_S *p)
240{
241 struct dvb_frontend *fe = &client->frontend;
242 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
243
244 c->frequency = p->Frequency;
245 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
246 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
247 c->transmission_mode = sms_to_mode(p->TransmissionMode);
248 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
249 c->code_rate_HP = sms_to_code_rate(p->CodeRate);
250 c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
251 c->hierarchy = sms_to_hierarchy(p->Hierarchy);
252 c->modulation = sms_to_modulation(p->Constellation);
253}
254
255static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
256 struct RECEPTION_STATISTICS_PER_SLICES_S *p)
257{
258 struct dvb_frontend *fe = &client->frontend;
259 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
260
261 client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
262 c->modulation = sms_to_modulation(p->constellation);
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300263
264 /* TS PER */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300265 client->last_per = c->block_error.stat[0].uvalue;
266 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
267 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
268 c->block_error.stat[0].uvalue += p->etsPackets;
269 c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets;
270
271 /* BER */
272 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
273 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
274 c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
275 c->post_bit_count.stat[0].uvalue += p->BERBitCount;
276
277 /* Legacy PER/BER */
278 client->legacy_per = (p->etsPackets * 65535) /
279 (p->tsPackets + p->etsPackets);
280
281 /* Signal Strength, in DBm */
282 c->strength.stat[0].uvalue = p->RSSI * 1000;
283
284 /* Carrier to Noise ratio, in DB */
285 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
286 c->cnr.stat[0].svalue = p->snr * 1000;
287}
288
289static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
290 struct SMSHOSTLIB_STATISTICS_ST *p)
291{
292 struct dvb_frontend *fe = &client->frontend;
293 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
294
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300295 if (client->prt_dvb_stats)
296 client->prt_dvb_stats(client->debug_data, p);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300297
298 client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
299
300 /* Update DVB modulation parameters */
301 c->frequency = p->Frequency;
302 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
303 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
304 c->transmission_mode = sms_to_mode(p->TransmissionMode);
305 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
306 c->code_rate_HP = sms_to_code_rate(p->CodeRate);
307 c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
308 c->hierarchy = sms_to_hierarchy(p->Hierarchy);
309 c->modulation = sms_to_modulation(p->Constellation);
310
311 /* update reception data */
312 c->lna = p->IsExternalLNAOn ? 1 : 0;
313
314 /* Carrier to Noise ratio, in DB */
315 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
316 c->cnr.stat[0].svalue = p->SNR * 1000;
317
318 /* Signal Strength, in DBm */
319 c->strength.stat[0].uvalue = p->RSSI * 1000;
320
321 /* TS PER */
322 client->last_per = c->block_error.stat[0].uvalue;
323 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
324 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
325 c->block_error.stat[0].uvalue += p->ErrorTSPackets;
326 c->block_count.stat[0].uvalue += p->TotalTSPackets;
327
328 /* BER */
329 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
330 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
331 c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
332 c->post_bit_count.stat[0].uvalue += p->BERBitCount;
333
334 /* Legacy PER/BER */
335 client->legacy_ber = p->BER;
336};
337
338static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
339 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
340{
341 struct dvb_frontend *fe = &client->frontend;
342 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
343 struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
344 int i, n_layers;
345
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300346 if (client->prt_isdb_stats)
347 client->prt_isdb_stats(client->debug_data, p);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300348
349 /* Update ISDB-T transmission parameters */
350 c->frequency = p->Frequency;
351 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
352 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
353 c->transmission_mode = sms_to_mode(p->TransmissionMode);
354 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
355 c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
356 n_layers = p->NumOfLayers;
357 if (n_layers < 1)
358 n_layers = 1;
359 if (n_layers > 3)
360 n_layers = 3;
361 c->isdbt_layer_enabled = 0;
362
363 /* update reception data */
364 c->lna = p->IsExternalLNAOn ? 1 : 0;
365
366 /* Carrier to Noise ratio, in DB */
367 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
368 c->cnr.stat[0].svalue = p->SNR * 1000;
369
370 /* Signal Strength, in DBm */
371 c->strength.stat[0].uvalue = p->RSSI * 1000;
372
373 client->last_per = c->block_error.stat[0].uvalue;
374
375 /* Clears global counters, as the code below will sum it again */
376 c->block_error.stat[0].uvalue = 0;
377 c->block_count.stat[0].uvalue = 0;
378 c->post_bit_error.stat[0].uvalue = 0;
379 c->post_bit_count.stat[0].uvalue = 0;
380
381 for (i = 0; i < n_layers; i++) {
382 lr = &p->LayerInfo[i];
383
384 /* Update per-layer transmission parameters */
385 if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
386 c->isdbt_layer_enabled |= 1 << i;
387 c->layer[i].segment_count = lr->NumberOfSegments;
388 } else {
389 continue;
390 }
391 c->layer[i].modulation = sms_to_modulation(lr->Constellation);
392
393 /* TS PER */
394 c->block_error.stat[i].scale = FE_SCALE_COUNTER;
395 c->block_count.stat[i].scale = FE_SCALE_COUNTER;
396 c->block_error.stat[i].uvalue += lr->ErrorTSPackets;
397 c->block_count.stat[i].uvalue += lr->TotalTSPackets;
398
399 /* Update global PER counter */
400 c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
401 c->block_count.stat[0].uvalue += lr->TotalTSPackets;
402
403 /* BER */
404 c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER;
405 c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER;
406 c->post_bit_error.stat[i].uvalue += lr->BERErrorCount;
407 c->post_bit_count.stat[i].uvalue += lr->BERBitCount;
408
409 /* Update global BER counter */
410 c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
411 c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
412 }
413}
414
415static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
416 struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
417{
418 struct dvb_frontend *fe = &client->frontend;
419 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
420 struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
421 int i, n_layers;
422
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300423 if (client->prt_isdb_stats_ex)
424 client->prt_isdb_stats_ex(client->debug_data, p);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300425
426 /* Update ISDB-T transmission parameters */
427 c->frequency = p->Frequency;
428 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
429 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
430 c->transmission_mode = sms_to_mode(p->TransmissionMode);
431 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
432 c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
433 n_layers = p->NumOfLayers;
434 if (n_layers < 1)
435 n_layers = 1;
436 if (n_layers > 3)
437 n_layers = 3;
438 c->isdbt_layer_enabled = 0;
439
440 /* update reception data */
441 c->lna = p->IsExternalLNAOn ? 1 : 0;
442
443 /* Carrier to Noise ratio, in DB */
444 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
445 c->cnr.stat[0].svalue = p->SNR * 1000;
446
447 /* Signal Strength, in DBm */
448 c->strength.stat[0].uvalue = p->RSSI * 1000;
449
450 client->last_per = c->block_error.stat[0].uvalue;
451
452 /* Clears global counters, as the code below will sum it again */
453 c->block_error.stat[0].uvalue = 0;
454 c->block_count.stat[0].uvalue = 0;
455 c->post_bit_error.stat[0].uvalue = 0;
456 c->post_bit_count.stat[0].uvalue = 0;
457
458 for (i = 0; i < n_layers; i++) {
459 lr = &p->LayerInfo[i];
460
461 /* Update per-layer transmission parameters */
462 if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
463 c->isdbt_layer_enabled |= 1 << i;
464 c->layer[i].segment_count = lr->NumberOfSegments;
465 } else {
466 continue;
467 }
468 c->layer[i].modulation = sms_to_modulation(lr->Constellation);
469
470 /* TS PER */
471 c->block_error.stat[i].scale = FE_SCALE_COUNTER;
472 c->block_count.stat[i].scale = FE_SCALE_COUNTER;
473 c->block_error.stat[i].uvalue += lr->ErrorTSPackets;
474 c->block_count.stat[i].uvalue += lr->TotalTSPackets;
475
476 /* Update global PER counter */
477 c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
478 c->block_count.stat[0].uvalue += lr->TotalTSPackets;
479
480 /* BER */
481 c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER;
482 c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER;
483 c->post_bit_error.stat[i].uvalue += lr->BERErrorCount;
484 c->post_bit_count.stat[i].uvalue += lr->BERBitCount;
485
486 /* Update global BER counter */
487 c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
488 c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300489 }
490}
491
Michael Krufky0c071f32008-06-21 02:44:02 -0300492static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300493{
Michael Krufky18245e12008-06-15 17:52:24 -0300494 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300495 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
496 + cb->offset);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300497 void *p = phdr + 1;
498 struct dvb_frontend *fe = &client->frontend;
499 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300500 bool is_status_update = false;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300501
Michael Krufkyfa830e82008-06-15 15:52:43 -0300502 switch (phdr->msgType) {
Michael Krufky82237412008-06-15 15:14:13 -0300503 case MSG_SMS_DVBT_BDA_DATA:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300504 dvb_dmx_swfilter(&client->demux, p,
Michael Krufky18245e12008-06-15 17:52:24 -0300505 cb->size - sizeof(struct SmsMsgHdr_ST));
Michael Krufky82237412008-06-15 15:14:13 -0300506 break;
507
508 case MSG_SMS_RF_TUNE_RES:
Michael Krufky6b26fce2009-12-22 21:08:49 -0300509 case MSG_SMS_ISDBT_TUNE_RES:
Michael Krufky82237412008-06-15 15:14:13 -0300510 complete(&client->tune_done);
511 break;
512
Uri Shkolnik793786d2009-05-12 12:28:46 -0300513 case MSG_SMS_SIGNAL_DETECTED_IND:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300514 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
515 FE_HAS_VITERBI | FE_HAS_SYNC |
516 FE_HAS_LOCK;
517
Uri Shkolnik793786d2009-05-12 12:28:46 -0300518 is_status_update = true;
519 break;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300520
Uri Shkolnik793786d2009-05-12 12:28:46 -0300521 case MSG_SMS_NO_SIGNAL_IND:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300522 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300523
524 is_status_update = true;
525 break;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300526
527 case MSG_SMS_TRANSMISSION_IND:
528 smsdvb_update_tx_params(client, p);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300529
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300530 is_status_update = true;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300531 break;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300532
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300533 case MSG_SMS_HO_PER_SLICES_IND:
534 smsdvb_update_per_slices(client, p);
535
536 is_status_update = true;
537 break;
538
539 case MSG_SMS_GET_STATISTICS_RES:
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300540 switch (smscore_get_device_mode(client->coredev)) {
541 case DEVICE_MODE_ISDBT:
542 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300543 smsdvb_update_isdbt_stats(client, p);
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300544 break;
545 default:
Mauro Carvalho Chehabc02272f2013-03-09 23:01:48 -0300546 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */
547 smsdvb_update_dvb_stats(client, p + sizeof(u32));
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300548 }
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300549
550 is_status_update = true;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300551 break;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300552
553 /* Only for ISDB-T */
554 case MSG_SMS_GET_STATISTICS_EX_RES:
Mauro Carvalho Chehabc02272f2013-03-09 23:01:48 -0300555 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */
556 smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300557 is_status_update = true;
558 break;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300559 default:
Mauro Carvalho Chehab4c3bdb52013-03-09 09:27:39 -0300560 sms_info("message not handled");
Uri Shkolnik793786d2009-05-12 12:28:46 -0300561 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300562 smscore_putbuffer(client->coredev, cb);
563
Uri Shkolnik793786d2009-05-12 12:28:46 -0300564 if (is_status_update) {
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300565 if (client->fe_status == FE_HAS_LOCK) {
Uri Shkolnik793786d2009-05-12 12:28:46 -0300566 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300567 if (client->last_per == c->block_error.stat[0].uvalue)
Uri Shkolnik793786d2009-05-12 12:28:46 -0300568 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
569 else
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300570 sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
Uri Shkolnik793786d2009-05-12 12:28:46 -0300571 } else {
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300572 smsdvb_stats_not_ready(fe);
573
Uri Shkolnik793786d2009-05-12 12:28:46 -0300574 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
575 }
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300576 complete(&client->stats_done);
Uri Shkolnik793786d2009-05-12 12:28:46 -0300577 }
578
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300579 return 0;
580}
581
Michael Krufky0c071f32008-06-21 02:44:02 -0300582static void smsdvb_unregister_client(struct smsdvb_client_t *client)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300583{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300584 /* must be called under clientslock */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300585
586 list_del(&client->entry);
587
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300588 smsdvb_debugfs_release(client);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300589 smscore_unregister_client(client->smsclient);
590 dvb_unregister_frontend(&client->frontend);
591 dvb_dmxdev_release(&client->dmxdev);
592 dvb_dmx_release(&client->demux);
593 dvb_unregister_adapter(&client->adapter);
594 kfree(client);
595}
596
Michael Krufky0c071f32008-06-21 02:44:02 -0300597static void smsdvb_onremove(void *context)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300598{
599 kmutex_lock(&g_smsdvb_clientslock);
600
Michael Krufky18245e12008-06-15 17:52:24 -0300601 smsdvb_unregister_client((struct smsdvb_client_t *) context);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300602
603 kmutex_unlock(&g_smsdvb_clientslock);
604}
605
606static int smsdvb_start_feed(struct dvb_demux_feed *feed)
607{
Michael Krufky18245e12008-06-15 17:52:24 -0300608 struct smsdvb_client_t *client =
609 container_of(feed->demux, struct smsdvb_client_t, demux);
610 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300611
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300612 sms_debug("add pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300613 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300614
615 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
616 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
617 PidMsg.xMsgHeader.msgFlags = 0;
618 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
619 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
620 PidMsg.msgData[0] = feed->pid;
621
Michael Krufky82237412008-06-15 15:14:13 -0300622 return smsclient_sendrequest(client->smsclient,
623 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300624}
625
626static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
627{
Michael Krufky18245e12008-06-15 17:52:24 -0300628 struct smsdvb_client_t *client =
629 container_of(feed->demux, struct smsdvb_client_t, demux);
630 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300631
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300632 sms_debug("remove pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300633 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300634
635 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
636 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
637 PidMsg.xMsgHeader.msgFlags = 0;
638 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
639 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
640 PidMsg.msgData[0] = feed->pid;
641
Michael Krufky82237412008-06-15 15:14:13 -0300642 return smsclient_sendrequest(client->smsclient,
643 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300644}
645
Michael Krufky18245e12008-06-15 17:52:24 -0300646static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
Michael Krufkya83ccdd2008-05-06 03:11:51 -0300647 void *buffer, size_t size,
648 struct completion *completion)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300649{
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300650 int rc;
651
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300652 rc = smsclient_sendrequest(client->smsclient, buffer, size);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300653 if (rc < 0)
654 return rc;
655
Michael Krufky82237412008-06-15 15:14:13 -0300656 return wait_for_completion_timeout(completion,
657 msecs_to_jiffies(2000)) ?
658 0 : -ETIME;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300659}
660
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300661static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
662{
663 int rc;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300664 struct SmsMsgHdr_ST Msg;
665
Mauro Carvalho Chehaba9b9fbd2013-03-10 10:51:25 -0300666 /* Don't request stats too fast */
667 if (client->get_stats_jiffies &&
668 (!time_after(jiffies, client->get_stats_jiffies)))
669 return 0;
670 client->get_stats_jiffies = jiffies + msecs_to_jiffies(100);
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300671
672 Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
673 Msg.msgDstId = HIF_TASK;
674 Msg.msgFlags = 0;
675 Msg.msgLength = sizeof(Msg);
676
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300677 switch (smscore_get_device_mode(client->coredev)) {
678 case DEVICE_MODE_ISDBT:
679 case DEVICE_MODE_ISDBT_BDA:
680 /*
681 * Check for firmware version, to avoid breaking for old cards
682 */
683 if (client->coredev->fw_version >= 0x800)
684 Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ;
685 else
686 Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
687 break;
688 default:
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300689 Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300690 }
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300691
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300692 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300693 &client->stats_done);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300694
695 return rc;
696}
697
Michael Krufky3746b612009-07-12 23:30:14 -0300698static inline int led_feedback(struct smsdvb_client_t *client)
699{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300700 if (!(client->fe_status & FE_HAS_LOCK))
Michael Krufky3746b612009-07-12 23:30:14 -0300701 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300702
703 return sms_board_led_feedback(client->coredev,
704 (client->legacy_ber == 0) ?
705 SMS_LED_HI : SMS_LED_LO);
Michael Krufky3746b612009-07-12 23:30:14 -0300706}
707
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300708static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
709{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300710 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300711 struct smsdvb_client_t *client;
712 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300713
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300714 rc = smsdvb_send_statistics_request(client);
715
Uri Shkolnik793786d2009-05-12 12:28:46 -0300716 *stat = client->fe_status;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300717
Michael Krufky3746b612009-07-12 23:30:14 -0300718 led_feedback(client);
719
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300720 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300721}
722
723static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
724{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300725 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300726 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300727
Uri Shkolnik793786d2009-05-12 12:28:46 -0300728 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300729
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300730 rc = smsdvb_send_statistics_request(client);
731
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300732 *ber = client->legacy_ber;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300733
Michael Krufky3746b612009-07-12 23:30:14 -0300734 led_feedback(client);
735
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300736 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300737}
738
739static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
740{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300741 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300742 int rc;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300743 s32 power = (s32) c->strength.stat[0].uvalue;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300744 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300745
Uri Shkolnik793786d2009-05-12 12:28:46 -0300746 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300747
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300748 rc = smsdvb_send_statistics_request(client);
749
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300750 if (power < -95)
Uri Shkolnik793786d2009-05-12 12:28:46 -0300751 *strength = 0;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300752 else if (power > -29)
753 *strength = 65535;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300754 else
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300755 *strength = (power + 95) * 65535 / 66;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300756
Michael Krufky3746b612009-07-12 23:30:14 -0300757 led_feedback(client);
758
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300759 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300760}
761
762static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
763{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300764 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300765 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300766 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300767
Uri Shkolnik793786d2009-05-12 12:28:46 -0300768 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300769
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300770 rc = smsdvb_send_statistics_request(client);
771
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300772 /* Preferred scale for SNR with legacy API: 0.1 dB */
773 *snr = c->cnr.stat[0].svalue / 100;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300774
Michael Krufky3746b612009-07-12 23:30:14 -0300775 led_feedback(client);
776
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300777 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300778}
779
Michael Krufky851a9092008-11-22 14:56:37 -0300780static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
781{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300782 int rc;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300783 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300784 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300785
Uri Shkolnik793786d2009-05-12 12:28:46 -0300786 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky851a9092008-11-22 14:56:37 -0300787
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300788 rc = smsdvb_send_statistics_request(client);
789
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300790 *ucblocks = c->block_error.stat[0].uvalue;
Michael Krufky851a9092008-11-22 14:56:37 -0300791
Michael Krufky3746b612009-07-12 23:30:14 -0300792 led_feedback(client);
793
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300794 return rc;
Michael Krufky851a9092008-11-22 14:56:37 -0300795}
796
Michael Krufky82237412008-06-15 15:14:13 -0300797static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
798 struct dvb_frontend_tune_settings *tune)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300799{
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300800 sms_debug("");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300801
802 tune->min_delay_ms = 400;
803 tune->step_size = 250000;
804 tune->max_drift = 0;
805 return 0;
806}
807
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300808static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300809{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300810 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky18245e12008-06-15 17:52:24 -0300811 struct smsdvb_client_t *client =
812 container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300813
Michael Krufky18245e12008-06-15 17:52:24 -0300814 struct {
815 struct SmsMsgHdr_ST Msg;
Michael Krufky82237412008-06-15 15:14:13 -0300816 u32 Data[3];
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300817 } Msg;
818
Michael Krufky3746b612009-07-12 23:30:14 -0300819 int ret;
820
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300821 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300822 client->event_fe_state = -1;
823 client->event_unc_state = -1;
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300824 fe->dtv_property_cache.delivery_system = SYS_DVBT;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300825
826 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
827 Msg.Msg.msgDstId = HIF_TASK;
828 Msg.Msg.msgFlags = 0;
829 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300830 Msg.Msg.msgLength = sizeof(Msg);
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300831 Msg.Data[0] = c->frequency;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300832 Msg.Data[2] = 12000000;
833
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300834 sms_info("%s: freq %d band %d", __func__, c->frequency,
835 c->bandwidth_hz);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300836
Mauro Carvalho Chehab643e15a2009-12-25 07:29:06 -0300837 switch (c->bandwidth_hz / 1000000) {
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300838 case 8:
839 Msg.Data[1] = BW_8_MHZ;
840 break;
841 case 7:
842 Msg.Data[1] = BW_7_MHZ;
843 break;
844 case 6:
845 Msg.Data[1] = BW_6_MHZ;
846 break;
847 case 0:
848 return -EOPNOTSUPP;
849 default:
850 return -EINVAL;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300851 }
Michael Krufky3746b612009-07-12 23:30:14 -0300852 /* Disable LNA, if any. An error is returned if no LNA is present */
853 ret = sms_board_lna_control(client->coredev, 0);
854 if (ret == 0) {
855 fe_status_t status;
856
857 /* tune with LNA off at first */
858 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
859 &client->tune_done);
860
861 smsdvb_read_status(fe, &status);
862
863 if (status & FE_HAS_LOCK)
864 return ret;
865
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300866 /* previous tune didn't lock - enable LNA and tune again */
Michael Krufky3746b612009-07-12 23:30:14 -0300867 sms_board_lna_control(client->coredev, 1);
868 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300869
Michael Krufky82237412008-06-15 15:14:13 -0300870 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
871 &client->tune_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300872}
873
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300874static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300875{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300876 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300877 struct smsdvb_client_t *client =
878 container_of(fe, struct smsdvb_client_t, frontend);
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300879 int board_id = smscore_get_board_id(client->coredev);
880 struct sms_board *board = sms_get_board(board_id);
881 enum sms_device_type_st type = board->type;
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -0300882 int ret;
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300883
Michael Krufky6b26fce2009-12-22 21:08:49 -0300884 struct {
885 struct SmsMsgHdr_ST Msg;
886 u32 Data[4];
887 } Msg;
888
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300889 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
890
Michael Krufky6b26fce2009-12-22 21:08:49 -0300891 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
892 Msg.Msg.msgDstId = HIF_TASK;
893 Msg.Msg.msgFlags = 0;
894 Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
895 Msg.Msg.msgLength = sizeof(Msg);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300896
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300897 if (c->isdbt_sb_segment_idx == -1)
898 c->isdbt_sb_segment_idx = 0;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300899
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300900 if (!c->isdbt_layer_enabled)
901 c->isdbt_layer_enabled = 7;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300902
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300903 Msg.Data[0] = c->frequency;
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300904 Msg.Data[1] = BW_ISDBT_1SEG;
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300905 Msg.Data[2] = 12000000;
906 Msg.Data[3] = c->isdbt_sb_segment_idx;
907
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300908 if (c->isdbt_partial_reception) {
909 if ((type == SMS_PELE || type == SMS_RIO) &&
910 c->isdbt_sb_segment_count > 3)
911 Msg.Data[1] = BW_ISDBT_13SEG;
912 else if (c->isdbt_sb_segment_count > 1)
913 Msg.Data[1] = BW_ISDBT_3SEG;
914 } else if (type == SMS_PELE || type == SMS_RIO)
915 Msg.Data[1] = BW_ISDBT_13SEG;
916
917 c->bandwidth_hz = 6000000;
918
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300919 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
920 c->frequency, c->isdbt_sb_segment_count,
921 c->isdbt_sb_segment_idx);
922
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -0300923 /* Disable LNA, if any. An error is returned if no LNA is present */
924 ret = sms_board_lna_control(client->coredev, 0);
925 if (ret == 0) {
926 fe_status_t status;
927
928 /* tune with LNA off at first */
929 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
930 &client->tune_done);
931
932 smsdvb_read_status(fe, &status);
933
934 if (status & FE_HAS_LOCK)
935 return ret;
936
937 /* previous tune didn't lock - enable LNA and tune again */
938 sms_board_lna_control(client->coredev, 1);
939 }
Michael Krufky6b26fce2009-12-22 21:08:49 -0300940 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
941 &client->tune_done);
942}
943
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300944static int smsdvb_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300945{
946 struct smsdvb_client_t *client =
947 container_of(fe, struct smsdvb_client_t, frontend);
948 struct smscore_device_t *coredev = client->coredev;
949
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300950 smsdvb_stats_not_ready(fe);
951
Michael Krufky6b26fce2009-12-22 21:08:49 -0300952 switch (smscore_get_device_mode(coredev)) {
953 case DEVICE_MODE_DVBT:
954 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300955 return smsdvb_dvbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300956 case DEVICE_MODE_ISDBT:
957 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300958 return smsdvb_isdbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300959 default:
960 return -EINVAL;
961 }
962}
963
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300964/* Nothing to do here, as stats are automatically updated */
Mauro Carvalho Chehabeab0fa02013-03-09 12:05:58 -0300965static int smsdvb_get_frontend(struct dvb_frontend *fe)
966{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300967 return 0;
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300968}
969
970static int smsdvb_init(struct dvb_frontend *fe)
971{
972 struct smsdvb_client_t *client =
973 container_of(fe, struct smsdvb_client_t, frontend);
974
Michael Krufky3746b612009-07-12 23:30:14 -0300975 sms_board_power(client->coredev, 1);
976
Uri Shkolnik793786d2009-05-12 12:28:46 -0300977 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300978 return 0;
979}
980
981static int smsdvb_sleep(struct dvb_frontend *fe)
982{
983 struct smsdvb_client_t *client =
984 container_of(fe, struct smsdvb_client_t, frontend);
985
Michael Krufky3746b612009-07-12 23:30:14 -0300986 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
987 sms_board_power(client->coredev, 0);
988
Uri Shkolnik793786d2009-05-12 12:28:46 -0300989 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300990
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300991 return 0;
992}
993
994static void smsdvb_release(struct dvb_frontend *fe)
995{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300996 /* do nothing */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300997}
998
999static struct dvb_frontend_ops smsdvb_fe_ops = {
1000 .info = {
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001001 .name = "Siano Mobile Digital MDTV Receiver",
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001002 .frequency_min = 44250000,
1003 .frequency_max = 867250000,
1004 .frequency_stepsize = 250000,
1005 .caps = FE_CAN_INVERSION_AUTO |
Michael Krufky82237412008-06-15 15:14:13 -03001006 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1007 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1008 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
1009 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
1010 FE_CAN_GUARD_INTERVAL_AUTO |
1011 FE_CAN_RECOVER |
1012 FE_CAN_HIERARCHY_AUTO,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001013 },
1014
1015 .release = smsdvb_release,
1016
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001017 .set_frontend = smsdvb_set_frontend,
1018 .get_frontend = smsdvb_get_frontend,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001019 .get_tune_settings = smsdvb_get_tune_settings,
1020
1021 .read_status = smsdvb_read_status,
1022 .read_ber = smsdvb_read_ber,
1023 .read_signal_strength = smsdvb_read_signal_strength,
1024 .read_snr = smsdvb_read_snr,
Michael Krufky851a9092008-11-22 14:56:37 -03001025 .read_ucblocks = smsdvb_read_ucblocks,
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001026
1027 .init = smsdvb_init,
1028 .sleep = smsdvb_sleep,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001029};
1030
Michael Krufky0c071f32008-06-21 02:44:02 -03001031static int smsdvb_hotplug(struct smscore_device_t *coredev,
1032 struct device *device, int arrival)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001033{
Michael Krufky18245e12008-06-15 17:52:24 -03001034 struct smsclient_params_t params;
1035 struct smsdvb_client_t *client;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001036 int rc;
1037
Michael Krufkyfa830e82008-06-15 15:52:43 -03001038 /* device removal handled by onremove callback */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001039 if (!arrival)
1040 return 0;
Michael Krufky18245e12008-06-15 17:52:24 -03001041 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
Michael Krufky82237412008-06-15 15:14:13 -03001042 if (!client) {
Michael Krufkyeb250942008-06-19 22:07:23 -03001043 sms_err("kmalloc() failed");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001044 return -ENOMEM;
1045 }
1046
Michael Krufkyfa830e82008-06-15 15:52:43 -03001047 /* register dvb adapter */
Michael Krufky1c11d542008-06-18 22:09:55 -03001048 rc = dvb_register_adapter(&client->adapter,
1049 sms_get_board(
1050 smscore_get_board_id(coredev))->name,
Michael Krufky82237412008-06-15 15:14:13 -03001051 THIS_MODULE, device, adapter_nr);
1052 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001053 sms_err("dvb_register_adapter() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001054 goto adapter_error;
1055 }
1056
Michael Krufkyfa830e82008-06-15 15:52:43 -03001057 /* init dvb demux */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001058 client->demux.dmx.capabilities = DMX_TS_FILTERING;
Michael Krufkyfa830e82008-06-15 15:52:43 -03001059 client->demux.filternum = 32; /* todo: nova ??? */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001060 client->demux.feednum = 32;
1061 client->demux.start_feed = smsdvb_start_feed;
1062 client->demux.stop_feed = smsdvb_stop_feed;
1063
1064 rc = dvb_dmx_init(&client->demux);
Michael Krufky82237412008-06-15 15:14:13 -03001065 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001066 sms_err("dvb_dmx_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001067 goto dvbdmx_error;
1068 }
1069
Michael Krufkyfa830e82008-06-15 15:52:43 -03001070 /* init dmxdev */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001071 client->dmxdev.filternum = 32;
1072 client->dmxdev.demux = &client->demux.dmx;
1073 client->dmxdev.capabilities = 0;
1074
1075 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
Michael Krufky82237412008-06-15 15:14:13 -03001076 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001077 sms_err("dvb_dmxdev_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001078 goto dmxdev_error;
1079 }
1080
Michael Krufkyfa830e82008-06-15 15:52:43 -03001081 /* init and register frontend */
Michael Krufky82237412008-06-15 15:14:13 -03001082 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
1083 sizeof(struct dvb_frontend_ops));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001084
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001085 switch (smscore_get_device_mode(coredev)) {
1086 case DEVICE_MODE_DVBT:
1087 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -03001088 client->frontend.ops.delsys[0] = SYS_DVBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001089 break;
1090 case DEVICE_MODE_ISDBT:
1091 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -03001092 client->frontend.ops.delsys[0] = SYS_ISDBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001093 break;
1094 }
1095
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001096 rc = dvb_register_frontend(&client->adapter, &client->frontend);
Michael Krufky82237412008-06-15 15:14:13 -03001097 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001098 sms_err("frontend registration failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001099 goto frontend_error;
1100 }
1101
Michael Krufkyf17407a2008-06-14 00:43:26 -03001102 params.initial_id = 1;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001103 params.data_type = MSG_SMS_DVBT_BDA_DATA;
1104 params.onresponse_handler = smsdvb_onresponse;
1105 params.onremove_handler = smsdvb_onremove;
1106 params.context = client;
1107
1108 rc = smscore_register_client(coredev, &params, &client->smsclient);
Michael Krufky82237412008-06-15 15:14:13 -03001109 if (rc < 0) {
Michael Krufkyeb250942008-06-19 22:07:23 -03001110 sms_err("smscore_register_client() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001111 goto client_error;
1112 }
1113
1114 client->coredev = coredev;
1115
1116 init_completion(&client->tune_done);
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -03001117 init_completion(&client->stats_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001118
1119 kmutex_lock(&g_smsdvb_clientslock);
1120
1121 list_add(&client->entry, &g_smsdvb_clients);
1122
1123 kmutex_unlock(&g_smsdvb_clientslock);
1124
Uri Shkolnik793786d2009-05-12 12:28:46 -03001125 client->event_fe_state = -1;
1126 client->event_unc_state = -1;
1127 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001128
Uri Shkolnik793786d2009-05-12 12:28:46 -03001129 sms_info("success");
Michael Krufky250fa672008-11-16 22:45:42 -03001130 sms_board_setup(coredev);
1131
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001132 if (smsdvb_debugfs_create(client) < 0)
Mauro Carvalho Chehab3f6b87c2013-03-09 22:33:06 -03001133 sms_info("failed to create debugfs node");
1134
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001135 return 0;
1136
1137client_error:
1138 dvb_unregister_frontend(&client->frontend);
1139
1140frontend_error:
1141 dvb_dmxdev_release(&client->dmxdev);
1142
1143dmxdev_error:
1144 dvb_dmx_release(&client->demux);
1145
1146dvbdmx_error:
1147 dvb_unregister_adapter(&client->adapter);
1148
1149adapter_error:
1150 kfree(client);
1151 return rc;
1152}
1153
Márton Németh2184dda2009-12-11 20:05:10 -03001154static int __init smsdvb_module_init(void)
Steven Totheae55662008-05-22 18:04:36 -03001155{
1156 int rc;
1157
1158 INIT_LIST_HEAD(&g_smsdvb_clients);
1159 kmutex_init(&g_smsdvb_clientslock);
1160
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001161 smsdvb_debugfs_register();
Mauro Carvalho Chehab3f6b87c2013-03-09 22:33:06 -03001162
Steven Totheae55662008-05-22 18:04:36 -03001163 rc = smscore_register_hotplug(smsdvb_hotplug);
1164
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001165 sms_debug("");
Steven Totheae55662008-05-22 18:04:36 -03001166
1167 return rc;
1168}
1169
Márton Németh2184dda2009-12-11 20:05:10 -03001170static void __exit smsdvb_module_exit(void)
Steven Totheae55662008-05-22 18:04:36 -03001171{
1172 smscore_unregister_hotplug(smsdvb_hotplug);
1173
1174 kmutex_lock(&g_smsdvb_clientslock);
1175
1176 while (!list_empty(&g_smsdvb_clients))
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001177 smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);
Steven Totheae55662008-05-22 18:04:36 -03001178
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001179 smsdvb_debugfs_unregister();
Mauro Carvalho Chehab3f6b87c2013-03-09 22:33:06 -03001180
Steven Totheae55662008-05-22 18:04:36 -03001181 kmutex_unlock(&g_smsdvb_clientslock);
Steven Totheae55662008-05-22 18:04:36 -03001182}
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001183
1184module_init(smsdvb_module_init);
1185module_exit(smsdvb_module_exit);
1186
1187MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
Uri Shkolnik843d0602009-05-12 13:13:13 -03001188MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001189MODULE_LICENSE("GPL");