[media] siano: don't request statistics too fast
[deliverable/linux.git] / drivers / media / common / siano / smsdvb-main.c
1 /****************************************************************
2
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2008, Uri Shkolnik
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the 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,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 ****************************************************************/
21
22 #include <linux/module.h>
23 #include <linux/slab.h>
24 #include <linux/init.h>
25
26 #include "dmxdev.h"
27 #include "dvbdev.h"
28 #include "dvb_demux.h"
29 #include "dvb_frontend.h"
30
31 #include "smscoreapi.h"
32 #include "sms-cards.h"
33
34 #include "smsdvb.h"
35
36 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
37
38 static struct list_head g_smsdvb_clients;
39 static struct mutex g_smsdvb_clientslock;
40
41 static int sms_dbg;
42 module_param_named(debug, sms_dbg, int, 0644);
43 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
44
45
46 u32 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
58 u32 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
65 u32 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
74 u32 sms_to_hierarchy_table[] = {
75 [0] = HIERARCHY_NONE,
76 [1] = HIERARCHY_1,
77 [2] = HIERARCHY_2,
78 [3] = HIERARCHY_4,
79 };
80
81 u32 sms_to_modulation_table[] = {
82 [0] = QPSK,
83 [1] = QAM_16,
84 [2] = QAM_64,
85 [3] = DQPSK,
86 };
87
88
89 /* Events that may come from DVB v3 adapter */
90 static void sms_board_dvb3_event(struct smsdvb_client_t *client,
91 enum SMS_DVB3_EVENTS event) {
92
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 }
140 }
141
142 static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
143 {
144 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;
149
150 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 }
157
158 /* Fill the length of each status counter */
159
160 /* Only global stats */
161 c->strength.len = 1;
162 c->cnr.len = 1;
163
164 /* 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;
169
170 /* 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;
181 }
182 }
183
184 static inline int sms_to_mode(u32 mode)
185 {
186 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 }
196
197 static 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;
202
203 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
238 static 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
255 static 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);
263
264 /* TS PER */
265 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
289 static 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
295 if (client->prt_dvb_stats)
296 client->prt_dvb_stats(client->debug_data, p);
297
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
338 static 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
346 if (client->prt_isdb_stats)
347 client->prt_isdb_stats(client->debug_data, p);
348
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
415 static 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
423 if (client->prt_isdb_stats_ex)
424 client->prt_isdb_stats_ex(client->debug_data, p);
425
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;
489 }
490 }
491
492 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
493 {
494 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
495 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
496 + cb->offset);
497 void *p = phdr + 1;
498 struct dvb_frontend *fe = &client->frontend;
499 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
500 bool is_status_update = false;
501
502 switch (phdr->msgType) {
503 case MSG_SMS_DVBT_BDA_DATA:
504 dvb_dmx_swfilter(&client->demux, p,
505 cb->size - sizeof(struct SmsMsgHdr_ST));
506 break;
507
508 case MSG_SMS_RF_TUNE_RES:
509 case MSG_SMS_ISDBT_TUNE_RES:
510 complete(&client->tune_done);
511 break;
512
513 case MSG_SMS_SIGNAL_DETECTED_IND:
514 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
515 FE_HAS_VITERBI | FE_HAS_SYNC |
516 FE_HAS_LOCK;
517
518 is_status_update = true;
519 break;
520
521 case MSG_SMS_NO_SIGNAL_IND:
522 client->fe_status = 0;
523
524 is_status_update = true;
525 break;
526
527 case MSG_SMS_TRANSMISSION_IND:
528 smsdvb_update_tx_params(client, p);
529
530 is_status_update = true;
531 break;
532
533 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:
540 switch (smscore_get_device_mode(client->coredev)) {
541 case DEVICE_MODE_ISDBT:
542 case DEVICE_MODE_ISDBT_BDA:
543 smsdvb_update_isdbt_stats(client, p);
544 break;
545 default:
546 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */
547 smsdvb_update_dvb_stats(client, p + sizeof(u32));
548 }
549
550 is_status_update = true;
551 break;
552
553 /* Only for ISDB-T */
554 case MSG_SMS_GET_STATISTICS_EX_RES:
555 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */
556 smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
557 is_status_update = true;
558 break;
559 default:
560 sms_info("message not handled");
561 }
562 smscore_putbuffer(client->coredev, cb);
563
564 if (is_status_update) {
565 if (client->fe_status == FE_HAS_LOCK) {
566 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
567 if (client->last_per == c->block_error.stat[0].uvalue)
568 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
569 else
570 sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
571 } else {
572 smsdvb_stats_not_ready(fe);
573
574 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
575 }
576 complete(&client->stats_done);
577 }
578
579 return 0;
580 }
581
582 static void smsdvb_unregister_client(struct smsdvb_client_t *client)
583 {
584 /* must be called under clientslock */
585
586 list_del(&client->entry);
587
588 smsdvb_debugfs_release(client);
589 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
597 static void smsdvb_onremove(void *context)
598 {
599 kmutex_lock(&g_smsdvb_clientslock);
600
601 smsdvb_unregister_client((struct smsdvb_client_t *) context);
602
603 kmutex_unlock(&g_smsdvb_clientslock);
604 }
605
606 static int smsdvb_start_feed(struct dvb_demux_feed *feed)
607 {
608 struct smsdvb_client_t *client =
609 container_of(feed->demux, struct smsdvb_client_t, demux);
610 struct SmsMsgData_ST PidMsg;
611
612 sms_debug("add pid %d(%x)",
613 feed->pid, feed->pid);
614
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
622 return smsclient_sendrequest(client->smsclient,
623 &PidMsg, sizeof(PidMsg));
624 }
625
626 static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
627 {
628 struct smsdvb_client_t *client =
629 container_of(feed->demux, struct smsdvb_client_t, demux);
630 struct SmsMsgData_ST PidMsg;
631
632 sms_debug("remove pid %d(%x)",
633 feed->pid, feed->pid);
634
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
642 return smsclient_sendrequest(client->smsclient,
643 &PidMsg, sizeof(PidMsg));
644 }
645
646 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
647 void *buffer, size_t size,
648 struct completion *completion)
649 {
650 int rc;
651
652 rc = smsclient_sendrequest(client->smsclient, buffer, size);
653 if (rc < 0)
654 return rc;
655
656 return wait_for_completion_timeout(completion,
657 msecs_to_jiffies(2000)) ?
658 0 : -ETIME;
659 }
660
661 static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
662 {
663 int rc;
664 struct SmsMsgHdr_ST Msg;
665
666 /* 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);
671
672 Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
673 Msg.msgDstId = HIF_TASK;
674 Msg.msgFlags = 0;
675 Msg.msgLength = sizeof(Msg);
676
677 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:
689 Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
690 }
691
692 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
693 &client->stats_done);
694
695 return rc;
696 }
697
698 static inline int led_feedback(struct smsdvb_client_t *client)
699 {
700 if (!(client->fe_status & FE_HAS_LOCK))
701 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
702
703 return sms_board_led_feedback(client->coredev,
704 (client->legacy_ber == 0) ?
705 SMS_LED_HI : SMS_LED_LO);
706 }
707
708 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
709 {
710 int rc;
711 struct smsdvb_client_t *client;
712 client = container_of(fe, struct smsdvb_client_t, frontend);
713
714 rc = smsdvb_send_statistics_request(client);
715
716 *stat = client->fe_status;
717
718 led_feedback(client);
719
720 return rc;
721 }
722
723 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
724 {
725 int rc;
726 struct smsdvb_client_t *client;
727
728 client = container_of(fe, struct smsdvb_client_t, frontend);
729
730 rc = smsdvb_send_statistics_request(client);
731
732 *ber = client->legacy_ber;
733
734 led_feedback(client);
735
736 return rc;
737 }
738
739 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
740 {
741 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
742 int rc;
743 s32 power = (s32) c->strength.stat[0].uvalue;
744 struct smsdvb_client_t *client;
745
746 client = container_of(fe, struct smsdvb_client_t, frontend);
747
748 rc = smsdvb_send_statistics_request(client);
749
750 if (power < -95)
751 *strength = 0;
752 else if (power > -29)
753 *strength = 65535;
754 else
755 *strength = (power + 95) * 65535 / 66;
756
757 led_feedback(client);
758
759 return rc;
760 }
761
762 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
763 {
764 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
765 int rc;
766 struct smsdvb_client_t *client;
767
768 client = container_of(fe, struct smsdvb_client_t, frontend);
769
770 rc = smsdvb_send_statistics_request(client);
771
772 /* Preferred scale for SNR with legacy API: 0.1 dB */
773 *snr = c->cnr.stat[0].svalue / 100;
774
775 led_feedback(client);
776
777 return rc;
778 }
779
780 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
781 {
782 int rc;
783 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
784 struct smsdvb_client_t *client;
785
786 client = container_of(fe, struct smsdvb_client_t, frontend);
787
788 rc = smsdvb_send_statistics_request(client);
789
790 *ucblocks = c->block_error.stat[0].uvalue;
791
792 led_feedback(client);
793
794 return rc;
795 }
796
797 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
798 struct dvb_frontend_tune_settings *tune)
799 {
800 sms_debug("");
801
802 tune->min_delay_ms = 400;
803 tune->step_size = 250000;
804 tune->max_drift = 0;
805 return 0;
806 }
807
808 static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
809 {
810 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
811 struct smsdvb_client_t *client =
812 container_of(fe, struct smsdvb_client_t, frontend);
813
814 struct {
815 struct SmsMsgHdr_ST Msg;
816 u32 Data[3];
817 } Msg;
818
819 int ret;
820
821 client->fe_status = 0;
822 client->event_fe_state = -1;
823 client->event_unc_state = -1;
824 fe->dtv_property_cache.delivery_system = SYS_DVBT;
825
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;
830 Msg.Msg.msgLength = sizeof(Msg);
831 Msg.Data[0] = c->frequency;
832 Msg.Data[2] = 12000000;
833
834 sms_info("%s: freq %d band %d", __func__, c->frequency,
835 c->bandwidth_hz);
836
837 switch (c->bandwidth_hz / 1000000) {
838 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;
851 }
852 /* 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
866 /* previous tune didn't lock - enable LNA and tune again */
867 sms_board_lna_control(client->coredev, 1);
868 }
869
870 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
871 &client->tune_done);
872 }
873
874 static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
875 {
876 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
877 struct smsdvb_client_t *client =
878 container_of(fe, struct smsdvb_client_t, frontend);
879 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;
882 int ret;
883
884 struct {
885 struct SmsMsgHdr_ST Msg;
886 u32 Data[4];
887 } Msg;
888
889 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
890
891 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);
896
897 if (c->isdbt_sb_segment_idx == -1)
898 c->isdbt_sb_segment_idx = 0;
899
900 if (!c->isdbt_layer_enabled)
901 c->isdbt_layer_enabled = 7;
902
903 Msg.Data[0] = c->frequency;
904 Msg.Data[1] = BW_ISDBT_1SEG;
905 Msg.Data[2] = 12000000;
906 Msg.Data[3] = c->isdbt_sb_segment_idx;
907
908 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
919 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
923 /* 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 }
940 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
941 &client->tune_done);
942 }
943
944 static int smsdvb_set_frontend(struct dvb_frontend *fe)
945 {
946 struct smsdvb_client_t *client =
947 container_of(fe, struct smsdvb_client_t, frontend);
948 struct smscore_device_t *coredev = client->coredev;
949
950 smsdvb_stats_not_ready(fe);
951
952 switch (smscore_get_device_mode(coredev)) {
953 case DEVICE_MODE_DVBT:
954 case DEVICE_MODE_DVBT_BDA:
955 return smsdvb_dvbt_set_frontend(fe);
956 case DEVICE_MODE_ISDBT:
957 case DEVICE_MODE_ISDBT_BDA:
958 return smsdvb_isdbt_set_frontend(fe);
959 default:
960 return -EINVAL;
961 }
962 }
963
964 /* Nothing to do here, as stats are automatically updated */
965 static int smsdvb_get_frontend(struct dvb_frontend *fe)
966 {
967 return 0;
968 }
969
970 static int smsdvb_init(struct dvb_frontend *fe)
971 {
972 struct smsdvb_client_t *client =
973 container_of(fe, struct smsdvb_client_t, frontend);
974
975 sms_board_power(client->coredev, 1);
976
977 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
978 return 0;
979 }
980
981 static int smsdvb_sleep(struct dvb_frontend *fe)
982 {
983 struct smsdvb_client_t *client =
984 container_of(fe, struct smsdvb_client_t, frontend);
985
986 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
987 sms_board_power(client->coredev, 0);
988
989 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
990
991 return 0;
992 }
993
994 static void smsdvb_release(struct dvb_frontend *fe)
995 {
996 /* do nothing */
997 }
998
999 static struct dvb_frontend_ops smsdvb_fe_ops = {
1000 .info = {
1001 .name = "Siano Mobile Digital MDTV Receiver",
1002 .frequency_min = 44250000,
1003 .frequency_max = 867250000,
1004 .frequency_stepsize = 250000,
1005 .caps = FE_CAN_INVERSION_AUTO |
1006 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,
1013 },
1014
1015 .release = smsdvb_release,
1016
1017 .set_frontend = smsdvb_set_frontend,
1018 .get_frontend = smsdvb_get_frontend,
1019 .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,
1025 .read_ucblocks = smsdvb_read_ucblocks,
1026
1027 .init = smsdvb_init,
1028 .sleep = smsdvb_sleep,
1029 };
1030
1031 static int smsdvb_hotplug(struct smscore_device_t *coredev,
1032 struct device *device, int arrival)
1033 {
1034 struct smsclient_params_t params;
1035 struct smsdvb_client_t *client;
1036 int rc;
1037
1038 /* device removal handled by onremove callback */
1039 if (!arrival)
1040 return 0;
1041 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
1042 if (!client) {
1043 sms_err("kmalloc() failed");
1044 return -ENOMEM;
1045 }
1046
1047 /* register dvb adapter */
1048 rc = dvb_register_adapter(&client->adapter,
1049 sms_get_board(
1050 smscore_get_board_id(coredev))->name,
1051 THIS_MODULE, device, adapter_nr);
1052 if (rc < 0) {
1053 sms_err("dvb_register_adapter() failed %d", rc);
1054 goto adapter_error;
1055 }
1056
1057 /* init dvb demux */
1058 client->demux.dmx.capabilities = DMX_TS_FILTERING;
1059 client->demux.filternum = 32; /* todo: nova ??? */
1060 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);
1065 if (rc < 0) {
1066 sms_err("dvb_dmx_init failed %d", rc);
1067 goto dvbdmx_error;
1068 }
1069
1070 /* init dmxdev */
1071 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);
1076 if (rc < 0) {
1077 sms_err("dvb_dmxdev_init failed %d", rc);
1078 goto dmxdev_error;
1079 }
1080
1081 /* init and register frontend */
1082 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
1083 sizeof(struct dvb_frontend_ops));
1084
1085 switch (smscore_get_device_mode(coredev)) {
1086 case DEVICE_MODE_DVBT:
1087 case DEVICE_MODE_DVBT_BDA:
1088 client->frontend.ops.delsys[0] = SYS_DVBT;
1089 break;
1090 case DEVICE_MODE_ISDBT:
1091 case DEVICE_MODE_ISDBT_BDA:
1092 client->frontend.ops.delsys[0] = SYS_ISDBT;
1093 break;
1094 }
1095
1096 rc = dvb_register_frontend(&client->adapter, &client->frontend);
1097 if (rc < 0) {
1098 sms_err("frontend registration failed %d", rc);
1099 goto frontend_error;
1100 }
1101
1102 params.initial_id = 1;
1103 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);
1109 if (rc < 0) {
1110 sms_err("smscore_register_client() failed %d", rc);
1111 goto client_error;
1112 }
1113
1114 client->coredev = coredev;
1115
1116 init_completion(&client->tune_done);
1117 init_completion(&client->stats_done);
1118
1119 kmutex_lock(&g_smsdvb_clientslock);
1120
1121 list_add(&client->entry, &g_smsdvb_clients);
1122
1123 kmutex_unlock(&g_smsdvb_clientslock);
1124
1125 client->event_fe_state = -1;
1126 client->event_unc_state = -1;
1127 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
1128
1129 sms_info("success");
1130 sms_board_setup(coredev);
1131
1132 if (smsdvb_debugfs_create(client) < 0)
1133 sms_info("failed to create debugfs node");
1134
1135 return 0;
1136
1137 client_error:
1138 dvb_unregister_frontend(&client->frontend);
1139
1140 frontend_error:
1141 dvb_dmxdev_release(&client->dmxdev);
1142
1143 dmxdev_error:
1144 dvb_dmx_release(&client->demux);
1145
1146 dvbdmx_error:
1147 dvb_unregister_adapter(&client->adapter);
1148
1149 adapter_error:
1150 kfree(client);
1151 return rc;
1152 }
1153
1154 static int __init smsdvb_module_init(void)
1155 {
1156 int rc;
1157
1158 INIT_LIST_HEAD(&g_smsdvb_clients);
1159 kmutex_init(&g_smsdvb_clientslock);
1160
1161 smsdvb_debugfs_register();
1162
1163 rc = smscore_register_hotplug(smsdvb_hotplug);
1164
1165 sms_debug("");
1166
1167 return rc;
1168 }
1169
1170 static void __exit smsdvb_module_exit(void)
1171 {
1172 smscore_unregister_hotplug(smsdvb_hotplug);
1173
1174 kmutex_lock(&g_smsdvb_clientslock);
1175
1176 while (!list_empty(&g_smsdvb_clients))
1177 smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);
1178
1179 smsdvb_debugfs_unregister();
1180
1181 kmutex_unlock(&g_smsdvb_clientslock);
1182 }
1183
1184 module_init(smsdvb_module_init);
1185 module_exit(smsdvb_module_exit);
1186
1187 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1188 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1189 MODULE_LICENSE("GPL");
This page took 0.090355 seconds and 6 git commands to generate.