1 /****************************************************************
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2008, Uri Shkolnik
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.
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.
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/>.
20 ****************************************************************/
22 #include <linux/module.h>
23 #include <linux/slab.h>
24 #include <linux/init.h>
28 #include "dvb_demux.h"
29 #include "dvb_frontend.h"
31 #include "smscoreapi.h"
32 #include "sms-cards.h"
36 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr
);
38 static struct list_head g_smsdvb_clients
;
39 static struct mutex g_smsdvb_clientslock
;
42 module_param_named(debug
, sms_dbg
, int, 0644);
43 MODULE_PARM_DESC(debug
, "set debug level (info=1, adv=2 (or-able))");
46 u32 sms_to_bw_table
[] = {
52 [BW_1_5_MHZ
] = 1500000,
53 [BW_ISDBT_1SEG
] = 6000000,
54 [BW_ISDBT_3SEG
] = 6000000,
55 [BW_ISDBT_13SEG
] = 6000000,
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
,
65 u32 sms_to_code_rate_table
[] = {
74 u32 sms_to_hierarchy_table
[] = {
81 u32 sms_to_modulation_table
[] = {
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
) {
93 struct smscore_device_t
*coredev
= client
->coredev
;
96 sms_debug("DVB3_EVENT_INIT");
97 sms_board_event(coredev
, BOARD_EVENT_BIND
);
99 case DVB3_EVENT_SLEEP
:
100 sms_debug("DVB3_EVENT_SLEEP");
101 sms_board_event(coredev
, BOARD_EVENT_POWER_SUSPEND
);
103 case DVB3_EVENT_HOTPLUG
:
104 sms_debug("DVB3_EVENT_HOTPLUG");
105 sms_board_event(coredev
, BOARD_EVENT_POWER_INIT
);
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
);
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
);
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
);
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
);
137 sms_err("Unknown dvb3 api event");
142 static void smsdvb_stats_not_ready(struct dvb_frontend
*fe
)
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
;
150 switch (smscore_get_device_mode(coredev
)) {
151 case DEVICE_MODE_ISDBT
:
152 case DEVICE_MODE_ISDBT_BDA
:
158 /* Fill the length of each status counter */
160 /* Only global stats */
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
;
170 /* Signal is always available */
171 c
->strength
.stat
[0].scale
= FE_SCALE_RELATIVE
;
172 c
->strength
.stat
[0].uvalue
= 0;
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
;
184 static inline int sms_to_mode(u32 mode
)
188 return TRANSMISSION_MODE_2K
;
190 return TRANSMISSION_MODE_4K
;
192 return TRANSMISSION_MODE_8K
;
194 return TRANSMISSION_MODE_AUTO
;
197 static inline int sms_to_status(u32 is_demod_locked
, u32 is_rf_locked
)
200 return FE_HAS_SIGNAL
| FE_HAS_CARRIER
| FE_HAS_VITERBI
|
201 FE_HAS_SYNC
| FE_HAS_LOCK
;
204 return FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
210 #define convert_from_table(value, table, defval) ({ \
212 if (value < ARRAY_SIZE(table)) \
213 __ret = table[value]; \
219 #define sms_to_bw(value) \
220 convert_from_table(value, sms_to_bw_table, 0);
222 #define sms_to_guard_interval(value) \
223 convert_from_table(value, sms_to_guard_interval_table, \
224 GUARD_INTERVAL_AUTO);
226 #define sms_to_code_rate(value) \
227 convert_from_table(value, sms_to_code_rate_table, \
230 #define sms_to_hierarchy(value) \
231 convert_from_table(value, sms_to_hierarchy_table, \
234 #define sms_to_modulation(value) \
235 convert_from_table(value, sms_to_modulation_table, \
238 static void smsdvb_update_tx_params(struct smsdvb_client_t
*client
,
239 struct TRANSMISSION_STATISTICS_S
*p
)
241 struct dvb_frontend
*fe
= &client
->frontend
;
242 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
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
);
255 static void smsdvb_update_per_slices(struct smsdvb_client_t
*client
,
256 struct RECEPTION_STATISTICS_PER_SLICES_S
*p
)
258 struct dvb_frontend
*fe
= &client
->frontend
;
259 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
261 client
->fe_status
= sms_to_status(p
->IsDemodLocked
, p
->IsRfLocked
);
262 c
->modulation
= sms_to_modulation(p
->constellation
);
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
;
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
;
278 client
->legacy_per
= (p
->etsPackets
* 65535) /
279 (p
->tsPackets
+ p
->etsPackets
);
281 /* Signal Strength, in DBm */
282 c
->strength
.stat
[0].uvalue
= p
->RSSI
* 1000;
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;
289 static void smsdvb_update_dvb_stats(struct smsdvb_client_t
*client
,
290 struct SMSHOSTLIB_STATISTICS_ST
*p
)
292 struct dvb_frontend
*fe
= &client
->frontend
;
293 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
295 if (client
->prt_dvb_stats
)
296 client
->prt_dvb_stats(client
->debug_data
, p
);
298 client
->fe_status
= sms_to_status(p
->IsDemodLocked
, p
->IsRfLocked
);
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
);
311 /* update reception data */
312 c
->lna
= p
->IsExternalLNAOn
? 1 : 0;
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;
318 /* Signal Strength, in DBm */
319 c
->strength
.stat
[0].uvalue
= p
->RSSI
* 1000;
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
;
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
;
335 client
->legacy_ber
= p
->BER
;
338 static void smsdvb_update_isdbt_stats(struct smsdvb_client_t
*client
,
339 struct SMSHOSTLIB_STATISTICS_ISDBT_ST
*p
)
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
;
346 if (client
->prt_isdb_stats
)
347 client
->prt_isdb_stats(client
->debug_data
, p
);
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
;
361 c
->isdbt_layer_enabled
= 0;
363 /* update reception data */
364 c
->lna
= p
->IsExternalLNAOn
? 1 : 0;
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;
370 /* Signal Strength, in DBm */
371 c
->strength
.stat
[0].uvalue
= p
->RSSI
* 1000;
373 client
->last_per
= c
->block_error
.stat
[0].uvalue
;
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;
381 for (i
= 0; i
< n_layers
; i
++) {
382 lr
= &p
->LayerInfo
[i
];
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
;
391 c
->layer
[i
].modulation
= sms_to_modulation(lr
->Constellation
);
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
;
399 /* Update global PER counter */
400 c
->block_error
.stat
[0].uvalue
+= lr
->ErrorTSPackets
;
401 c
->block_count
.stat
[0].uvalue
+= lr
->TotalTSPackets
;
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
;
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
;
415 static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t
*client
,
416 struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST
*p
)
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
;
423 if (client
->prt_isdb_stats_ex
)
424 client
->prt_isdb_stats_ex(client
->debug_data
, p
);
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
;
438 c
->isdbt_layer_enabled
= 0;
440 /* update reception data */
441 c
->lna
= p
->IsExternalLNAOn
? 1 : 0;
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;
447 /* Signal Strength, in DBm */
448 c
->strength
.stat
[0].uvalue
= p
->RSSI
* 1000;
450 client
->last_per
= c
->block_error
.stat
[0].uvalue
;
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;
458 for (i
= 0; i
< n_layers
; i
++) {
459 lr
= &p
->LayerInfo
[i
];
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
;
468 c
->layer
[i
].modulation
= sms_to_modulation(lr
->Constellation
);
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
;
476 /* Update global PER counter */
477 c
->block_error
.stat
[0].uvalue
+= lr
->ErrorTSPackets
;
478 c
->block_count
.stat
[0].uvalue
+= lr
->TotalTSPackets
;
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
;
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
;
492 static int smsdvb_onresponse(void *context
, struct smscore_buffer_t
*cb
)
494 struct smsdvb_client_t
*client
= (struct smsdvb_client_t
*) context
;
495 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) (((u8
*) cb
->p
)
498 struct dvb_frontend
*fe
= &client
->frontend
;
499 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
500 bool is_status_update
= false;
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
));
508 case MSG_SMS_RF_TUNE_RES
:
509 case MSG_SMS_ISDBT_TUNE_RES
:
510 complete(&client
->tune_done
);
513 case MSG_SMS_SIGNAL_DETECTED_IND
:
514 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
|
515 FE_HAS_VITERBI
| FE_HAS_SYNC
|
518 is_status_update
= true;
521 case MSG_SMS_NO_SIGNAL_IND
:
522 client
->fe_status
= 0;
524 is_status_update
= true;
527 case MSG_SMS_TRANSMISSION_IND
:
528 smsdvb_update_tx_params(client
, p
);
530 is_status_update
= true;
533 case MSG_SMS_HO_PER_SLICES_IND
:
534 smsdvb_update_per_slices(client
, p
);
536 is_status_update
= true;
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
);
546 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */
547 smsdvb_update_dvb_stats(client
, p
+ sizeof(u32
));
550 is_status_update
= true;
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;
560 sms_info("message not handled");
562 smscore_putbuffer(client
->coredev
, cb
);
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
);
570 sms_board_dvb3_event(client
, DVB3_EVENT_UNC_ERR
);
572 smsdvb_stats_not_ready(fe
);
574 sms_board_dvb3_event(client
, DVB3_EVENT_FE_UNLOCK
);
576 complete(&client
->stats_done
);
582 static void smsdvb_unregister_client(struct smsdvb_client_t
*client
)
584 /* must be called under clientslock */
586 list_del(&client
->entry
);
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
);
597 static void smsdvb_onremove(void *context
)
599 kmutex_lock(&g_smsdvb_clientslock
);
601 smsdvb_unregister_client((struct smsdvb_client_t
*) context
);
603 kmutex_unlock(&g_smsdvb_clientslock
);
606 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
608 struct smsdvb_client_t
*client
=
609 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
610 struct SmsMsgData_ST PidMsg
;
612 sms_debug("add pid %d(%x)",
613 feed
->pid
, feed
->pid
);
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
;
622 return smsclient_sendrequest(client
->smsclient
,
623 &PidMsg
, sizeof(PidMsg
));
626 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
628 struct smsdvb_client_t
*client
=
629 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
630 struct SmsMsgData_ST PidMsg
;
632 sms_debug("remove pid %d(%x)",
633 feed
->pid
, feed
->pid
);
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
;
642 return smsclient_sendrequest(client
->smsclient
,
643 &PidMsg
, sizeof(PidMsg
));
646 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t
*client
,
647 void *buffer
, size_t size
,
648 struct completion
*completion
)
652 rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
656 return wait_for_completion_timeout(completion
,
657 msecs_to_jiffies(2000)) ?
661 static int smsdvb_send_statistics_request(struct smsdvb_client_t
*client
)
664 struct SmsMsgHdr_ST Msg
;
666 /* Don't request stats too fast */
667 if (client
->get_stats_jiffies
&&
668 (!time_after(jiffies
, client
->get_stats_jiffies
)))
670 client
->get_stats_jiffies
= jiffies
+ msecs_to_jiffies(100);
672 Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
673 Msg
.msgDstId
= HIF_TASK
;
675 Msg
.msgLength
= sizeof(Msg
);
677 switch (smscore_get_device_mode(client
->coredev
)) {
678 case DEVICE_MODE_ISDBT
:
679 case DEVICE_MODE_ISDBT_BDA
:
681 * Check for firmware version, to avoid breaking for old cards
683 if (client
->coredev
->fw_version
>= 0x800)
684 Msg
.msgType
= MSG_SMS_GET_STATISTICS_EX_REQ
;
686 Msg
.msgType
= MSG_SMS_GET_STATISTICS_REQ
;
689 Msg
.msgType
= MSG_SMS_GET_STATISTICS_REQ
;
692 rc
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
693 &client
->stats_done
);
698 static inline int led_feedback(struct smsdvb_client_t
*client
)
700 if (!(client
->fe_status
& FE_HAS_LOCK
))
701 return sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
703 return sms_board_led_feedback(client
->coredev
,
704 (client
->legacy_ber
== 0) ?
705 SMS_LED_HI
: SMS_LED_LO
);
708 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
711 struct smsdvb_client_t
*client
;
712 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
714 rc
= smsdvb_send_statistics_request(client
);
716 *stat
= client
->fe_status
;
718 led_feedback(client
);
723 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
726 struct smsdvb_client_t
*client
;
728 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
730 rc
= smsdvb_send_statistics_request(client
);
732 *ber
= client
->legacy_ber
;
734 led_feedback(client
);
739 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
741 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
743 s32 power
= (s32
) c
->strength
.stat
[0].uvalue
;
744 struct smsdvb_client_t
*client
;
746 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
748 rc
= smsdvb_send_statistics_request(client
);
752 else if (power
> -29)
755 *strength
= (power
+ 95) * 65535 / 66;
757 led_feedback(client
);
762 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
764 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
766 struct smsdvb_client_t
*client
;
768 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
770 rc
= smsdvb_send_statistics_request(client
);
772 /* Preferred scale for SNR with legacy API: 0.1 dB */
773 *snr
= c
->cnr
.stat
[0].svalue
/ 100;
775 led_feedback(client
);
780 static int smsdvb_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
783 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
784 struct smsdvb_client_t
*client
;
786 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
788 rc
= smsdvb_send_statistics_request(client
);
790 *ucblocks
= c
->block_error
.stat
[0].uvalue
;
792 led_feedback(client
);
797 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
,
798 struct dvb_frontend_tune_settings
*tune
)
802 tune
->min_delay_ms
= 400;
803 tune
->step_size
= 250000;
808 static int smsdvb_dvbt_set_frontend(struct dvb_frontend
*fe
)
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
);
815 struct SmsMsgHdr_ST Msg
;
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
;
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;
834 sms_info("%s: freq %d band %d", __func__
, c
->frequency
,
837 switch (c
->bandwidth_hz
/ 1000000) {
839 Msg
.Data
[1] = BW_8_MHZ
;
842 Msg
.Data
[1] = BW_7_MHZ
;
845 Msg
.Data
[1] = BW_6_MHZ
;
852 /* Disable LNA, if any. An error is returned if no LNA is present */
853 ret
= sms_board_lna_control(client
->coredev
, 0);
857 /* tune with LNA off at first */
858 ret
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
861 smsdvb_read_status(fe
, &status
);
863 if (status
& FE_HAS_LOCK
)
866 /* previous tune didn't lock - enable LNA and tune again */
867 sms_board_lna_control(client
->coredev
, 1);
870 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
874 static int smsdvb_isdbt_set_frontend(struct dvb_frontend
*fe
)
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
;
885 struct SmsMsgHdr_ST Msg
;
889 fe
->dtv_property_cache
.delivery_system
= SYS_ISDBT
;
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
);
897 if (c
->isdbt_sb_segment_idx
== -1)
898 c
->isdbt_sb_segment_idx
= 0;
900 if (!c
->isdbt_layer_enabled
)
901 c
->isdbt_layer_enabled
= 7;
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
;
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
;
917 c
->bandwidth_hz
= 6000000;
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
);
923 /* Disable LNA, if any. An error is returned if no LNA is present */
924 ret
= sms_board_lna_control(client
->coredev
, 0);
928 /* tune with LNA off at first */
929 ret
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
932 smsdvb_read_status(fe
, &status
);
934 if (status
& FE_HAS_LOCK
)
937 /* previous tune didn't lock - enable LNA and tune again */
938 sms_board_lna_control(client
->coredev
, 1);
940 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
944 static int smsdvb_set_frontend(struct dvb_frontend
*fe
)
946 struct smsdvb_client_t
*client
=
947 container_of(fe
, struct smsdvb_client_t
, frontend
);
948 struct smscore_device_t
*coredev
= client
->coredev
;
950 smsdvb_stats_not_ready(fe
);
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
);
964 /* Nothing to do here, as stats are automatically updated */
965 static int smsdvb_get_frontend(struct dvb_frontend
*fe
)
970 static int smsdvb_init(struct dvb_frontend
*fe
)
972 struct smsdvb_client_t
*client
=
973 container_of(fe
, struct smsdvb_client_t
, frontend
);
975 sms_board_power(client
->coredev
, 1);
977 sms_board_dvb3_event(client
, DVB3_EVENT_INIT
);
981 static int smsdvb_sleep(struct dvb_frontend
*fe
)
983 struct smsdvb_client_t
*client
=
984 container_of(fe
, struct smsdvb_client_t
, frontend
);
986 sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
987 sms_board_power(client
->coredev
, 0);
989 sms_board_dvb3_event(client
, DVB3_EVENT_SLEEP
);
994 static void smsdvb_release(struct dvb_frontend
*fe
)
999 static struct dvb_frontend_ops smsdvb_fe_ops
= {
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
|
1012 FE_CAN_HIERARCHY_AUTO
,
1015 .release
= smsdvb_release
,
1017 .set_frontend
= smsdvb_set_frontend
,
1018 .get_frontend
= smsdvb_get_frontend
,
1019 .get_tune_settings
= smsdvb_get_tune_settings
,
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
,
1027 .init
= smsdvb_init
,
1028 .sleep
= smsdvb_sleep
,
1031 static int smsdvb_hotplug(struct smscore_device_t
*coredev
,
1032 struct device
*device
, int arrival
)
1034 struct smsclient_params_t params
;
1035 struct smsdvb_client_t
*client
;
1038 /* device removal handled by onremove callback */
1041 client
= kzalloc(sizeof(struct smsdvb_client_t
), GFP_KERNEL
);
1043 sms_err("kmalloc() failed");
1047 /* register dvb adapter */
1048 rc
= dvb_register_adapter(&client
->adapter
,
1050 smscore_get_board_id(coredev
))->name
,
1051 THIS_MODULE
, device
, adapter_nr
);
1053 sms_err("dvb_register_adapter() failed %d", rc
);
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
;
1064 rc
= dvb_dmx_init(&client
->demux
);
1066 sms_err("dvb_dmx_init failed %d", rc
);
1071 client
->dmxdev
.filternum
= 32;
1072 client
->dmxdev
.demux
= &client
->demux
.dmx
;
1073 client
->dmxdev
.capabilities
= 0;
1075 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
1077 sms_err("dvb_dmxdev_init failed %d", rc
);
1081 /* init and register frontend */
1082 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
,
1083 sizeof(struct dvb_frontend_ops
));
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
;
1090 case DEVICE_MODE_ISDBT
:
1091 case DEVICE_MODE_ISDBT_BDA
:
1092 client
->frontend
.ops
.delsys
[0] = SYS_ISDBT
;
1096 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
1098 sms_err("frontend registration failed %d", rc
);
1099 goto frontend_error
;
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
;
1108 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
1110 sms_err("smscore_register_client() failed %d", rc
);
1114 client
->coredev
= coredev
;
1116 init_completion(&client
->tune_done
);
1117 init_completion(&client
->stats_done
);
1119 kmutex_lock(&g_smsdvb_clientslock
);
1121 list_add(&client
->entry
, &g_smsdvb_clients
);
1123 kmutex_unlock(&g_smsdvb_clientslock
);
1125 client
->event_fe_state
= -1;
1126 client
->event_unc_state
= -1;
1127 sms_board_dvb3_event(client
, DVB3_EVENT_HOTPLUG
);
1129 sms_info("success");
1130 sms_board_setup(coredev
);
1132 if (smsdvb_debugfs_create(client
) < 0)
1133 sms_info("failed to create debugfs node");
1138 dvb_unregister_frontend(&client
->frontend
);
1141 dvb_dmxdev_release(&client
->dmxdev
);
1144 dvb_dmx_release(&client
->demux
);
1147 dvb_unregister_adapter(&client
->adapter
);
1154 static int __init
smsdvb_module_init(void)
1158 INIT_LIST_HEAD(&g_smsdvb_clients
);
1159 kmutex_init(&g_smsdvb_clientslock
);
1161 smsdvb_debugfs_register();
1163 rc
= smscore_register_hotplug(smsdvb_hotplug
);
1170 static void __exit
smsdvb_module_exit(void)
1172 smscore_unregister_hotplug(smsdvb_hotplug
);
1174 kmutex_lock(&g_smsdvb_clientslock
);
1176 while (!list_empty(&g_smsdvb_clients
))
1177 smsdvb_unregister_client((struct smsdvb_client_t
*)g_smsdvb_clients
.next
);
1179 smsdvb_debugfs_unregister();
1181 kmutex_unlock(&g_smsdvb_clientslock
);
1184 module_init(smsdvb_module_init
);
1185 module_exit(smsdvb_module_exit
);
1187 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1188 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1189 MODULE_LICENSE("GPL");