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 "smsendian.h"
33 #include "sms-cards.h"
35 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr
);
37 struct smsdvb_client_t
{
38 struct list_head entry
;
40 struct smscore_device_t
*coredev
;
41 struct smscore_client_t
*smsclient
;
43 struct dvb_adapter adapter
;
44 struct dvb_demux demux
;
46 struct dvb_frontend frontend
;
48 fe_status_t fe_status
;
50 struct completion tune_done
;
52 struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb
;
57 static struct list_head g_smsdvb_clients
;
58 static struct mutex g_smsdvb_clientslock
;
61 module_param_named(debug
, sms_dbg
, int, 0644);
62 MODULE_PARM_DESC(debug
, "set debug level (info=1, adv=2 (or-able))");
64 /* Events that may come from DVB v3 adapter */
65 static void sms_board_dvb3_event(struct smsdvb_client_t
*client
,
66 enum SMS_DVB3_EVENTS event
) {
68 struct smscore_device_t
*coredev
= client
->coredev
;
71 sms_debug("DVB3_EVENT_INIT");
72 sms_board_event(coredev
, BOARD_EVENT_BIND
);
74 case DVB3_EVENT_SLEEP
:
75 sms_debug("DVB3_EVENT_SLEEP");
76 sms_board_event(coredev
, BOARD_EVENT_POWER_SUSPEND
);
78 case DVB3_EVENT_HOTPLUG
:
79 sms_debug("DVB3_EVENT_HOTPLUG");
80 sms_board_event(coredev
, BOARD_EVENT_POWER_INIT
);
82 case DVB3_EVENT_FE_LOCK
:
83 if (client
->event_fe_state
!= DVB3_EVENT_FE_LOCK
) {
84 client
->event_fe_state
= DVB3_EVENT_FE_LOCK
;
85 sms_debug("DVB3_EVENT_FE_LOCK");
86 sms_board_event(coredev
, BOARD_EVENT_FE_LOCK
);
89 case DVB3_EVENT_FE_UNLOCK
:
90 if (client
->event_fe_state
!= DVB3_EVENT_FE_UNLOCK
) {
91 client
->event_fe_state
= DVB3_EVENT_FE_UNLOCK
;
92 sms_debug("DVB3_EVENT_FE_UNLOCK");
93 sms_board_event(coredev
, BOARD_EVENT_FE_UNLOCK
);
96 case DVB3_EVENT_UNC_OK
:
97 if (client
->event_unc_state
!= DVB3_EVENT_UNC_OK
) {
98 client
->event_unc_state
= DVB3_EVENT_UNC_OK
;
99 sms_debug("DVB3_EVENT_UNC_OK");
100 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_OK
);
103 case DVB3_EVENT_UNC_ERR
:
104 if (client
->event_unc_state
!= DVB3_EVENT_UNC_ERR
) {
105 client
->event_unc_state
= DVB3_EVENT_UNC_ERR
;
106 sms_debug("DVB3_EVENT_UNC_ERR");
107 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_ERRORS
);
112 sms_err("Unknown dvb3 api event");
118 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
119 struct SMSHOSTLIB_STATISTICS_ST
*p
)
122 printk(KERN_DEBUG
"Reserved = %d", p
->Reserved
);
123 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
124 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
125 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
126 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
127 printk(KERN_DEBUG
"BER = %d", p
->BER
);
128 printk(KERN_DEBUG
"FIB_CRC = %d", p
->FIB_CRC
);
129 printk(KERN_DEBUG
"TS_PER = %d", p
->TS_PER
);
130 printk(KERN_DEBUG
"MFER = %d", p
->MFER
);
131 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
132 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
133 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
134 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
135 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
136 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
137 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
138 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
139 printk(KERN_DEBUG
"CodeRate = %d", p
->CodeRate
);
140 printk(KERN_DEBUG
"LPCodeRate = %d", p
->LPCodeRate
);
141 printk(KERN_DEBUG
"Hierarchy = %d", p
->Hierarchy
);
142 printk(KERN_DEBUG
"Constellation = %d", p
->Constellation
);
143 printk(KERN_DEBUG
"BurstSize = %d", p
->BurstSize
);
144 printk(KERN_DEBUG
"BurstDuration = %d", p
->BurstDuration
);
145 printk(KERN_DEBUG
"BurstCycleTime = %d", p
->BurstCycleTime
);
146 printk(KERN_DEBUG
"CalculatedBurstCycleTime = %d", p
->CalculatedBurstCycleTime
);
147 printk(KERN_DEBUG
"NumOfRows = %d", p
->NumOfRows
);
148 printk(KERN_DEBUG
"NumOfPaddCols = %d", p
->NumOfPaddCols
);
149 printk(KERN_DEBUG
"NumOfPunctCols = %d", p
->NumOfPunctCols
);
150 printk(KERN_DEBUG
"ErrorTSPackets = %d", p
->ErrorTSPackets
);
151 printk(KERN_DEBUG
"TotalTSPackets = %d", p
->TotalTSPackets
);
152 printk(KERN_DEBUG
"NumOfValidMpeTlbs = %d", p
->NumOfValidMpeTlbs
);
153 printk(KERN_DEBUG
"NumOfInvalidMpeTlbs = %d", p
->NumOfInvalidMpeTlbs
);
154 printk(KERN_DEBUG
"NumOfCorrectedMpeTlbs = %d", p
->NumOfCorrectedMpeTlbs
);
155 printk(KERN_DEBUG
"BERErrorCount = %d", p
->BERErrorCount
);
156 printk(KERN_DEBUG
"BERBitCount = %d", p
->BERBitCount
);
157 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
158 printk(KERN_DEBUG
"PreBER = %d", p
->PreBER
);
159 printk(KERN_DEBUG
"CellId = %d", p
->CellId
);
160 printk(KERN_DEBUG
"DvbhSrvIndHP = %d", p
->DvbhSrvIndHP
);
161 printk(KERN_DEBUG
"DvbhSrvIndLP = %d", p
->DvbhSrvIndLP
);
162 printk(KERN_DEBUG
"NumMPEReceived = %d", p
->NumMPEReceived
);
165 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
167 pReceptionData
->SNR
= p
->SNR
;
168 pReceptionData
->BER
= p
->BER
;
169 pReceptionData
->BERErrorCount
= p
->BERErrorCount
;
170 pReceptionData
->InBandPwr
= p
->InBandPwr
;
171 pReceptionData
->ErrorTSPackets
= p
->ErrorTSPackets
;
175 static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
176 struct SMSHOSTLIB_STATISTICS_ISDBT_ST
*p
)
181 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
182 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
183 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
184 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
185 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
186 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
187 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
188 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
189 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
190 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
191 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
192 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
193 printk(KERN_DEBUG
"SystemType = %d", p
->SystemType
);
194 printk(KERN_DEBUG
"PartialReception = %d", p
->PartialReception
);
195 printk(KERN_DEBUG
"NumOfLayers = %d", p
->NumOfLayers
);
196 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
198 for (i
= 0; i
< 3; i
++) {
199 printk(KERN_DEBUG
"%d: CodeRate = %d", i
, p
->LayerInfo
[i
].CodeRate
);
200 printk(KERN_DEBUG
"%d: Constellation = %d", i
, p
->LayerInfo
[i
].Constellation
);
201 printk(KERN_DEBUG
"%d: BER = %d", i
, p
->LayerInfo
[i
].BER
);
202 printk(KERN_DEBUG
"%d: BERErrorCount = %d", i
, p
->LayerInfo
[i
].BERErrorCount
);
203 printk(KERN_DEBUG
"%d: BERBitCount = %d", i
, p
->LayerInfo
[i
].BERBitCount
);
204 printk(KERN_DEBUG
"%d: PreBER = %d", i
, p
->LayerInfo
[i
].PreBER
);
205 printk(KERN_DEBUG
"%d: TS_PER = %d", i
, p
->LayerInfo
[i
].TS_PER
);
206 printk(KERN_DEBUG
"%d: ErrorTSPackets = %d", i
, p
->LayerInfo
[i
].ErrorTSPackets
);
207 printk(KERN_DEBUG
"%d: TotalTSPackets = %d", i
, p
->LayerInfo
[i
].TotalTSPackets
);
208 printk(KERN_DEBUG
"%d: TILdepthI = %d", i
, p
->LayerInfo
[i
].TILdepthI
);
209 printk(KERN_DEBUG
"%d: NumberOfSegments = %d", i
, p
->LayerInfo
[i
].NumberOfSegments
);
210 printk(KERN_DEBUG
"%d: TMCCErrors = %d", i
, p
->LayerInfo
[i
].TMCCErrors
);
214 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
216 pReceptionData
->SNR
= p
->SNR
;
217 pReceptionData
->InBandPwr
= p
->InBandPwr
;
219 pReceptionData
->ErrorTSPackets
= 0;
220 pReceptionData
->BER
= 0;
221 pReceptionData
->BERErrorCount
= 0;
222 for (i
= 0; i
< 3; i
++) {
223 pReceptionData
->BER
+= p
->LayerInfo
[i
].BER
;
224 pReceptionData
->BERErrorCount
+= p
->LayerInfo
[i
].BERErrorCount
;
225 pReceptionData
->ErrorTSPackets
+= p
->LayerInfo
[i
].ErrorTSPackets
;
229 static int smsdvb_onresponse(void *context
, struct smscore_buffer_t
*cb
)
231 struct smsdvb_client_t
*client
= (struct smsdvb_client_t
*) context
;
232 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) (((u8
*) cb
->p
)
234 u32
*pMsgData
= (u32
*) phdr
+ 1;
235 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
236 bool is_status_update
= false;
238 smsendian_handle_rx_message((struct SmsMsgData_ST
*) phdr
);
240 switch (phdr
->msgType
) {
241 case MSG_SMS_DVBT_BDA_DATA
:
242 dvb_dmx_swfilter(&client
->demux
, (u8
*)(phdr
+ 1),
243 cb
->size
- sizeof(struct SmsMsgHdr_ST
));
246 case MSG_SMS_RF_TUNE_RES
:
247 case MSG_SMS_ISDBT_TUNE_RES
:
248 complete(&client
->tune_done
);
251 case MSG_SMS_SIGNAL_DETECTED_IND
:
252 sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
253 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= true;
254 is_status_update
= true;
257 case MSG_SMS_NO_SIGNAL_IND
:
258 sms_info("MSG_SMS_NO_SIGNAL_IND");
259 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= false;
260 is_status_update
= true;
263 case MSG_SMS_TRANSMISSION_IND
: {
264 sms_info("MSG_SMS_TRANSMISSION_IND");
267 memcpy(&client
->sms_stat_dvb
.TransmissionData
, pMsgData
,
268 sizeof(struct TRANSMISSION_STATISTICS_S
));
270 /* Mo need to correct guard interval
271 * (as opposed to old statistics message).
273 CORRECT_STAT_BANDWIDTH(client
->sms_stat_dvb
.TransmissionData
);
274 CORRECT_STAT_TRANSMISSON_MODE(
275 client
->sms_stat_dvb
.TransmissionData
);
276 is_status_update
= true;
279 case MSG_SMS_HO_PER_SLICES_IND
: {
280 struct RECEPTION_STATISTICS_S
*pReceptionData
=
281 &client
->sms_stat_dvb
.ReceptionData
;
282 struct SRVM_SIGNAL_STATUS_S SignalStatusData
;
284 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
286 SignalStatusData
.result
= pMsgData
[0];
287 SignalStatusData
.snr
= pMsgData
[1];
288 SignalStatusData
.inBandPower
= (s32
) pMsgData
[2];
289 SignalStatusData
.tsPackets
= pMsgData
[3];
290 SignalStatusData
.etsPackets
= pMsgData
[4];
291 SignalStatusData
.constellation
= pMsgData
[5];
292 SignalStatusData
.hpCode
= pMsgData
[6];
293 SignalStatusData
.tpsSrvIndLP
= pMsgData
[7] & 0x03;
294 SignalStatusData
.tpsSrvIndHP
= pMsgData
[8] & 0x03;
295 SignalStatusData
.cellId
= pMsgData
[9] & 0xFFFF;
296 SignalStatusData
.reason
= pMsgData
[10];
297 SignalStatusData
.requestId
= pMsgData
[11];
298 pReceptionData
->IsRfLocked
= pMsgData
[16];
299 pReceptionData
->IsDemodLocked
= pMsgData
[17];
300 pReceptionData
->ModemState
= pMsgData
[12];
301 pReceptionData
->SNR
= pMsgData
[1];
302 pReceptionData
->BER
= pMsgData
[13];
303 pReceptionData
->RSSI
= pMsgData
[14];
304 CORRECT_STAT_RSSI(client
->sms_stat_dvb
.ReceptionData
);
306 pReceptionData
->InBandPwr
= (s32
) pMsgData
[2];
307 pReceptionData
->CarrierOffset
= (s32
) pMsgData
[15];
308 pReceptionData
->TotalTSPackets
= pMsgData
[3];
309 pReceptionData
->ErrorTSPackets
= pMsgData
[4];
312 if ((SignalStatusData
.tsPackets
+ SignalStatusData
.etsPackets
)
314 pReceptionData
->TS_PER
= (SignalStatusData
.etsPackets
315 * 100) / (SignalStatusData
.tsPackets
316 + SignalStatusData
.etsPackets
);
318 pReceptionData
->TS_PER
= 0;
321 pReceptionData
->BERBitCount
= pMsgData
[18];
322 pReceptionData
->BERErrorCount
= pMsgData
[19];
324 pReceptionData
->MRC_SNR
= pMsgData
[20];
325 pReceptionData
->MRC_InBandPwr
= pMsgData
[21];
326 pReceptionData
->MRC_RSSI
= pMsgData
[22];
328 is_status_update
= true;
331 case MSG_SMS_GET_STATISTICS_RES
: {
333 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt
;
334 struct SmsMsgStatisticsInfo_ST dvb
;
335 } *p
= (void *) (phdr
+ 1);
336 struct RECEPTION_STATISTICS_S
*pReceptionData
=
337 &client
->sms_stat_dvb
.ReceptionData
;
339 sms_info("MSG_SMS_GET_STATISTICS_RES");
341 is_status_update
= true;
343 switch (smscore_get_device_mode(client
->coredev
)) {
344 case DEVICE_MODE_ISDBT
:
345 case DEVICE_MODE_ISDBT_BDA
:
346 smsdvb_update_isdbt_stats(pReceptionData
, &p
->isdbt
);
349 smsdvb_update_dvb_stats(pReceptionData
, &p
->dvb
.Stat
);
351 if (!pReceptionData
->IsDemodLocked
) {
352 pReceptionData
->SNR
= 0;
353 pReceptionData
->BER
= 0;
354 pReceptionData
->BERErrorCount
= 0;
355 pReceptionData
->InBandPwr
= 0;
356 pReceptionData
->ErrorTSPackets
= 0;
359 complete(&client
->tune_done
);
363 sms_info("Unhandled message %d", phdr
->msgType
);
366 smscore_putbuffer(client
->coredev
, cb
);
368 if (is_status_update
) {
369 if (client
->sms_stat_dvb
.ReceptionData
.IsDemodLocked
) {
370 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
371 | FE_HAS_VITERBI
| FE_HAS_SYNC
| FE_HAS_LOCK
;
372 sms_board_dvb3_event(client
, DVB3_EVENT_FE_LOCK
);
373 if (client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
375 sms_board_dvb3_event(client
, DVB3_EVENT_UNC_OK
);
377 sms_board_dvb3_event(client
,
381 if (client
->sms_stat_dvb
.ReceptionData
.IsRfLocked
)
382 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
384 client
->fe_status
= 0;
385 sms_board_dvb3_event(client
, DVB3_EVENT_FE_UNLOCK
);
392 static void smsdvb_unregister_client(struct smsdvb_client_t
*client
)
394 /* must be called under clientslock */
396 list_del(&client
->entry
);
398 smscore_unregister_client(client
->smsclient
);
399 dvb_unregister_frontend(&client
->frontend
);
400 dvb_dmxdev_release(&client
->dmxdev
);
401 dvb_dmx_release(&client
->demux
);
402 dvb_unregister_adapter(&client
->adapter
);
406 static void smsdvb_onremove(void *context
)
408 kmutex_lock(&g_smsdvb_clientslock
);
410 smsdvb_unregister_client((struct smsdvb_client_t
*) context
);
412 kmutex_unlock(&g_smsdvb_clientslock
);
415 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
417 struct smsdvb_client_t
*client
=
418 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
419 struct SmsMsgData_ST PidMsg
;
421 sms_debug("add pid %d(%x)",
422 feed
->pid
, feed
->pid
);
424 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
425 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
426 PidMsg
.xMsgHeader
.msgFlags
= 0;
427 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_ADD_PID_FILTER_REQ
;
428 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
429 PidMsg
.msgData
[0] = feed
->pid
;
431 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
432 return smsclient_sendrequest(client
->smsclient
,
433 &PidMsg
, sizeof(PidMsg
));
436 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
438 struct smsdvb_client_t
*client
=
439 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
440 struct SmsMsgData_ST PidMsg
;
442 sms_debug("remove pid %d(%x)",
443 feed
->pid
, feed
->pid
);
445 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
446 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
447 PidMsg
.xMsgHeader
.msgFlags
= 0;
448 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_REMOVE_PID_FILTER_REQ
;
449 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
450 PidMsg
.msgData
[0] = feed
->pid
;
452 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
453 return smsclient_sendrequest(client
->smsclient
,
454 &PidMsg
, sizeof(PidMsg
));
457 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t
*client
,
458 void *buffer
, size_t size
,
459 struct completion
*completion
)
463 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)buffer
);
464 rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
468 return wait_for_completion_timeout(completion
,
469 msecs_to_jiffies(2000)) ?
473 static int smsdvb_send_statistics_request(struct smsdvb_client_t
*client
)
476 struct SmsMsgHdr_ST Msg
= { MSG_SMS_GET_STATISTICS_REQ
,
477 DVBT_BDA_CONTROL_MSG_ID
,
479 sizeof(struct SmsMsgHdr_ST
), 0 };
481 rc
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
487 static inline int led_feedback(struct smsdvb_client_t
*client
)
489 if (client
->fe_status
& FE_HAS_LOCK
)
490 return sms_board_led_feedback(client
->coredev
,
491 (client
->sms_stat_dvb
.ReceptionData
.BER
492 == 0) ? SMS_LED_HI
: SMS_LED_LO
);
494 return sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
497 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
500 struct smsdvb_client_t
*client
;
501 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
503 rc
= smsdvb_send_statistics_request(client
);
505 *stat
= client
->fe_status
;
507 led_feedback(client
);
512 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
515 struct smsdvb_client_t
*client
;
516 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
518 rc
= smsdvb_send_statistics_request(client
);
520 *ber
= client
->sms_stat_dvb
.ReceptionData
.BER
;
522 led_feedback(client
);
527 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
531 struct smsdvb_client_t
*client
;
532 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
534 rc
= smsdvb_send_statistics_request(client
);
536 if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
< -95)
538 else if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
> -29)
542 (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
545 led_feedback(client
);
550 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
553 struct smsdvb_client_t
*client
;
554 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
556 rc
= smsdvb_send_statistics_request(client
);
558 *snr
= client
->sms_stat_dvb
.ReceptionData
.SNR
;
560 led_feedback(client
);
565 static int smsdvb_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
568 struct smsdvb_client_t
*client
;
569 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
571 rc
= smsdvb_send_statistics_request(client
);
573 *ucblocks
= client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
;
575 led_feedback(client
);
580 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
,
581 struct dvb_frontend_tune_settings
*tune
)
585 tune
->min_delay_ms
= 400;
586 tune
->step_size
= 250000;
591 static int smsdvb_dvbt_set_frontend(struct dvb_frontend
*fe
)
593 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
594 struct smsdvb_client_t
*client
=
595 container_of(fe
, struct smsdvb_client_t
, frontend
);
598 struct SmsMsgHdr_ST Msg
;
604 client
->fe_status
= FE_HAS_SIGNAL
;
605 client
->event_fe_state
= -1;
606 client
->event_unc_state
= -1;
607 fe
->dtv_property_cache
.delivery_system
= SYS_DVBT
;
609 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
610 Msg
.Msg
.msgDstId
= HIF_TASK
;
611 Msg
.Msg
.msgFlags
= 0;
612 Msg
.Msg
.msgType
= MSG_SMS_RF_TUNE_REQ
;
613 Msg
.Msg
.msgLength
= sizeof(Msg
);
614 Msg
.Data
[0] = c
->frequency
;
615 Msg
.Data
[2] = 12000000;
617 sms_info("%s: freq %d band %d", __func__
, c
->frequency
,
620 switch (c
->bandwidth_hz
/ 1000000) {
622 Msg
.Data
[1] = BW_8_MHZ
;
625 Msg
.Data
[1] = BW_7_MHZ
;
628 Msg
.Data
[1] = BW_6_MHZ
;
635 /* Disable LNA, if any. An error is returned if no LNA is present */
636 ret
= sms_board_lna_control(client
->coredev
, 0);
640 /* tune with LNA off at first */
641 ret
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
644 smsdvb_read_status(fe
, &status
);
646 if (status
& FE_HAS_LOCK
)
649 /* previous tune didn't lock - enable LNA and tune again */
650 sms_board_lna_control(client
->coredev
, 1);
653 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
657 static int smsdvb_isdbt_set_frontend(struct dvb_frontend
*fe
)
659 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
660 struct smsdvb_client_t
*client
=
661 container_of(fe
, struct smsdvb_client_t
, frontend
);
664 struct SmsMsgHdr_ST Msg
;
668 fe
->dtv_property_cache
.delivery_system
= SYS_ISDBT
;
670 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
671 Msg
.Msg
.msgDstId
= HIF_TASK
;
672 Msg
.Msg
.msgFlags
= 0;
673 Msg
.Msg
.msgType
= MSG_SMS_ISDBT_TUNE_REQ
;
674 Msg
.Msg
.msgLength
= sizeof(Msg
);
676 if (c
->isdbt_sb_segment_idx
== -1)
677 c
->isdbt_sb_segment_idx
= 0;
679 switch (c
->isdbt_sb_segment_count
) {
681 Msg
.Data
[1] = BW_ISDBT_3SEG
;
684 Msg
.Data
[1] = BW_ISDBT_1SEG
;
687 switch (c
->bandwidth_hz
/ 1000000) {
690 c
->isdbt_sb_segment_count
= 3;
691 Msg
.Data
[1] = BW_ISDBT_3SEG
;
694 c
->isdbt_sb_segment_count
= 1;
695 Msg
.Data
[1] = BW_ISDBT_1SEG
;
697 default: /* Assumes 6 MHZ bw */
698 c
->isdbt_sb_segment_count
= 1;
699 c
->bandwidth_hz
= 6000;
700 Msg
.Data
[1] = BW_ISDBT_1SEG
;
705 sms_info("Segment count %d not supported", c
->isdbt_sb_segment_count
);
709 Msg
.Data
[0] = c
->frequency
;
710 Msg
.Data
[2] = 12000000;
711 Msg
.Data
[3] = c
->isdbt_sb_segment_idx
;
713 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__
,
714 c
->frequency
, c
->isdbt_sb_segment_count
,
715 c
->isdbt_sb_segment_idx
);
717 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
721 static int smsdvb_set_frontend(struct dvb_frontend
*fe
)
723 struct smsdvb_client_t
*client
=
724 container_of(fe
, struct smsdvb_client_t
, frontend
);
725 struct smscore_device_t
*coredev
= client
->coredev
;
727 switch (smscore_get_device_mode(coredev
)) {
728 case DEVICE_MODE_DVBT
:
729 case DEVICE_MODE_DVBT_BDA
:
730 return smsdvb_dvbt_set_frontend(fe
);
731 case DEVICE_MODE_ISDBT
:
732 case DEVICE_MODE_ISDBT_BDA
:
733 return smsdvb_isdbt_set_frontend(fe
);
739 static int smsdvb_get_frontend(struct dvb_frontend
*fe
)
741 struct dtv_frontend_properties
*fep
= &fe
->dtv_property_cache
;
742 struct smsdvb_client_t
*client
=
743 container_of(fe
, struct smsdvb_client_t
, frontend
);
744 struct smscore_device_t
*coredev
= client
->coredev
;
745 struct TRANSMISSION_STATISTICS_S
*td
=
746 &client
->sms_stat_dvb
.TransmissionData
;
748 switch (smscore_get_device_mode(coredev
)) {
749 case DEVICE_MODE_DVBT
:
750 case DEVICE_MODE_DVBT_BDA
:
751 fep
->frequency
= td
->Frequency
;
753 switch (td
->Bandwidth
) {
755 fep
->bandwidth_hz
= 6000000;
758 fep
->bandwidth_hz
= 7000000;
761 fep
->bandwidth_hz
= 8000000;
765 switch (td
->TransmissionMode
) {
767 fep
->transmission_mode
= TRANSMISSION_MODE_2K
;
770 fep
->transmission_mode
= TRANSMISSION_MODE_8K
;
773 switch (td
->GuardInterval
) {
775 fep
->guard_interval
= GUARD_INTERVAL_1_32
;
778 fep
->guard_interval
= GUARD_INTERVAL_1_16
;
781 fep
->guard_interval
= GUARD_INTERVAL_1_8
;
784 fep
->guard_interval
= GUARD_INTERVAL_1_4
;
788 switch (td
->CodeRate
) {
790 fep
->code_rate_HP
= FEC_1_2
;
793 fep
->code_rate_HP
= FEC_2_3
;
796 fep
->code_rate_HP
= FEC_3_4
;
799 fep
->code_rate_HP
= FEC_5_6
;
802 fep
->code_rate_HP
= FEC_7_8
;
806 switch (td
->LPCodeRate
) {
808 fep
->code_rate_LP
= FEC_1_2
;
811 fep
->code_rate_LP
= FEC_2_3
;
814 fep
->code_rate_LP
= FEC_3_4
;
817 fep
->code_rate_LP
= FEC_5_6
;
820 fep
->code_rate_LP
= FEC_7_8
;
824 switch (td
->Constellation
) {
826 fep
->modulation
= QPSK
;
829 fep
->modulation
= QAM_16
;
832 fep
->modulation
= QAM_64
;
836 switch (td
->Hierarchy
) {
838 fep
->hierarchy
= HIERARCHY_NONE
;
841 fep
->hierarchy
= HIERARCHY_1
;
844 fep
->hierarchy
= HIERARCHY_2
;
847 fep
->hierarchy
= HIERARCHY_4
;
851 fep
->inversion
= INVERSION_AUTO
;
853 case DEVICE_MODE_ISDBT
:
854 case DEVICE_MODE_ISDBT_BDA
:
855 fep
->frequency
= td
->Frequency
;
856 fep
->bandwidth_hz
= 6000000;
857 /* todo: retrive the other parameters */
866 static int smsdvb_init(struct dvb_frontend
*fe
)
868 struct smsdvb_client_t
*client
=
869 container_of(fe
, struct smsdvb_client_t
, frontend
);
871 sms_board_power(client
->coredev
, 1);
873 sms_board_dvb3_event(client
, DVB3_EVENT_INIT
);
877 static int smsdvb_sleep(struct dvb_frontend
*fe
)
879 struct smsdvb_client_t
*client
=
880 container_of(fe
, struct smsdvb_client_t
, frontend
);
882 sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
883 sms_board_power(client
->coredev
, 0);
885 sms_board_dvb3_event(client
, DVB3_EVENT_SLEEP
);
890 static void smsdvb_release(struct dvb_frontend
*fe
)
895 static struct dvb_frontend_ops smsdvb_fe_ops
= {
897 .name
= "Siano Mobile Digital MDTV Receiver",
898 .frequency_min
= 44250000,
899 .frequency_max
= 867250000,
900 .frequency_stepsize
= 250000,
901 .caps
= FE_CAN_INVERSION_AUTO
|
902 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
903 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
904 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
|
905 FE_CAN_QAM_AUTO
| FE_CAN_TRANSMISSION_MODE_AUTO
|
906 FE_CAN_GUARD_INTERVAL_AUTO
|
908 FE_CAN_HIERARCHY_AUTO
,
911 .release
= smsdvb_release
,
913 .set_frontend
= smsdvb_set_frontend
,
914 .get_frontend
= smsdvb_get_frontend
,
915 .get_tune_settings
= smsdvb_get_tune_settings
,
917 .read_status
= smsdvb_read_status
,
918 .read_ber
= smsdvb_read_ber
,
919 .read_signal_strength
= smsdvb_read_signal_strength
,
920 .read_snr
= smsdvb_read_snr
,
921 .read_ucblocks
= smsdvb_read_ucblocks
,
924 .sleep
= smsdvb_sleep
,
927 static int smsdvb_hotplug(struct smscore_device_t
*coredev
,
928 struct device
*device
, int arrival
)
930 struct smsclient_params_t params
;
931 struct smsdvb_client_t
*client
;
934 /* device removal handled by onremove callback */
937 client
= kzalloc(sizeof(struct smsdvb_client_t
), GFP_KERNEL
);
939 sms_err("kmalloc() failed");
943 /* register dvb adapter */
944 rc
= dvb_register_adapter(&client
->adapter
,
946 smscore_get_board_id(coredev
))->name
,
947 THIS_MODULE
, device
, adapter_nr
);
949 sms_err("dvb_register_adapter() failed %d", rc
);
954 client
->demux
.dmx
.capabilities
= DMX_TS_FILTERING
;
955 client
->demux
.filternum
= 32; /* todo: nova ??? */
956 client
->demux
.feednum
= 32;
957 client
->demux
.start_feed
= smsdvb_start_feed
;
958 client
->demux
.stop_feed
= smsdvb_stop_feed
;
960 rc
= dvb_dmx_init(&client
->demux
);
962 sms_err("dvb_dmx_init failed %d", rc
);
967 client
->dmxdev
.filternum
= 32;
968 client
->dmxdev
.demux
= &client
->demux
.dmx
;
969 client
->dmxdev
.capabilities
= 0;
971 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
973 sms_err("dvb_dmxdev_init failed %d", rc
);
977 /* init and register frontend */
978 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
,
979 sizeof(struct dvb_frontend_ops
));
981 switch (smscore_get_device_mode(coredev
)) {
982 case DEVICE_MODE_DVBT
:
983 case DEVICE_MODE_DVBT_BDA
:
984 client
->frontend
.ops
.delsys
[0] = SYS_DVBT
;
986 case DEVICE_MODE_ISDBT
:
987 case DEVICE_MODE_ISDBT_BDA
:
988 client
->frontend
.ops
.delsys
[0] = SYS_ISDBT
;
992 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
994 sms_err("frontend registration failed %d", rc
);
998 params
.initial_id
= 1;
999 params
.data_type
= MSG_SMS_DVBT_BDA_DATA
;
1000 params
.onresponse_handler
= smsdvb_onresponse
;
1001 params
.onremove_handler
= smsdvb_onremove
;
1002 params
.context
= client
;
1004 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
1006 sms_err("smscore_register_client() failed %d", rc
);
1010 client
->coredev
= coredev
;
1012 init_completion(&client
->tune_done
);
1014 kmutex_lock(&g_smsdvb_clientslock
);
1016 list_add(&client
->entry
, &g_smsdvb_clients
);
1018 kmutex_unlock(&g_smsdvb_clientslock
);
1020 client
->event_fe_state
= -1;
1021 client
->event_unc_state
= -1;
1022 sms_board_dvb3_event(client
, DVB3_EVENT_HOTPLUG
);
1024 sms_info("success");
1025 sms_board_setup(coredev
);
1030 dvb_unregister_frontend(&client
->frontend
);
1033 dvb_dmxdev_release(&client
->dmxdev
);
1036 dvb_dmx_release(&client
->demux
);
1039 dvb_unregister_adapter(&client
->adapter
);
1046 static int __init
smsdvb_module_init(void)
1050 INIT_LIST_HEAD(&g_smsdvb_clients
);
1051 kmutex_init(&g_smsdvb_clientslock
);
1053 rc
= smscore_register_hotplug(smsdvb_hotplug
);
1060 static void __exit
smsdvb_module_exit(void)
1062 smscore_unregister_hotplug(smsdvb_hotplug
);
1064 kmutex_lock(&g_smsdvb_clientslock
);
1066 while (!list_empty(&g_smsdvb_clients
))
1067 smsdvb_unregister_client(
1068 (struct smsdvb_client_t
*) g_smsdvb_clients
.next
);
1070 kmutex_unlock(&g_smsdvb_clientslock
);
1073 module_init(smsdvb_module_init
);
1074 module_exit(smsdvb_module_exit
);
1076 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1077 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1078 MODULE_LICENSE("GPL");