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 /* todo: save freq/band instead whole struct */
53 struct dvb_frontend_parameters fe_params
;
55 struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb
;
60 static struct list_head g_smsdvb_clients
;
61 static struct mutex g_smsdvb_clientslock
;
63 /* Events that may come from DVB v3 adapter */
64 static void sms_board_dvb3_event(struct smsdvb_client_t
*client
,
65 enum SMS_DVB3_EVENTS event
) {
67 struct smscore_device_t
*coredev
= client
->coredev
;
70 sms_debug("DVB3_EVENT_INIT");
71 sms_board_event(coredev
, BOARD_EVENT_BIND
);
73 case DVB3_EVENT_SLEEP
:
74 sms_debug("DVB3_EVENT_SLEEP");
75 sms_board_event(coredev
, BOARD_EVENT_POWER_SUSPEND
);
77 case DVB3_EVENT_HOTPLUG
:
78 sms_debug("DVB3_EVENT_HOTPLUG");
79 sms_board_event(coredev
, BOARD_EVENT_POWER_INIT
);
81 case DVB3_EVENT_FE_LOCK
:
82 if (client
->event_fe_state
!= DVB3_EVENT_FE_LOCK
) {
83 client
->event_fe_state
= DVB3_EVENT_FE_LOCK
;
84 sms_debug("DVB3_EVENT_FE_LOCK");
85 sms_board_event(coredev
, BOARD_EVENT_FE_LOCK
);
88 case DVB3_EVENT_FE_UNLOCK
:
89 if (client
->event_fe_state
!= DVB3_EVENT_FE_UNLOCK
) {
90 client
->event_fe_state
= DVB3_EVENT_FE_UNLOCK
;
91 sms_debug("DVB3_EVENT_FE_UNLOCK");
92 sms_board_event(coredev
, BOARD_EVENT_FE_UNLOCK
);
95 case DVB3_EVENT_UNC_OK
:
96 if (client
->event_unc_state
!= DVB3_EVENT_UNC_OK
) {
97 client
->event_unc_state
= DVB3_EVENT_UNC_OK
;
98 sms_debug("DVB3_EVENT_UNC_OK");
99 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_OK
);
102 case DVB3_EVENT_UNC_ERR
:
103 if (client
->event_unc_state
!= DVB3_EVENT_UNC_ERR
) {
104 client
->event_unc_state
= DVB3_EVENT_UNC_ERR
;
105 sms_debug("DVB3_EVENT_UNC_ERR");
106 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_ERRORS
);
111 sms_err("Unknown dvb3 api event");
117 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
118 struct SMSHOSTLIB_STATISTICS_ST
*p
)
121 printk(KERN_DEBUG
"Reserved = %d", p
->Reserved
);
122 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
123 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
124 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
125 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
126 printk(KERN_DEBUG
"BER = %d", p
->BER
);
127 printk(KERN_DEBUG
"FIB_CRC = %d", p
->FIB_CRC
);
128 printk(KERN_DEBUG
"TS_PER = %d", p
->TS_PER
);
129 printk(KERN_DEBUG
"MFER = %d", p
->MFER
);
130 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
131 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
132 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
133 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
134 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
135 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
136 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
137 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
138 printk(KERN_DEBUG
"CodeRate = %d", p
->CodeRate
);
139 printk(KERN_DEBUG
"LPCodeRate = %d", p
->LPCodeRate
);
140 printk(KERN_DEBUG
"Hierarchy = %d", p
->Hierarchy
);
141 printk(KERN_DEBUG
"Constellation = %d", p
->Constellation
);
142 printk(KERN_DEBUG
"BurstSize = %d", p
->BurstSize
);
143 printk(KERN_DEBUG
"BurstDuration = %d", p
->BurstDuration
);
144 printk(KERN_DEBUG
"BurstCycleTime = %d", p
->BurstCycleTime
);
145 printk(KERN_DEBUG
"CalculatedBurstCycleTime = %d", p
->CalculatedBurstCycleTime
);
146 printk(KERN_DEBUG
"NumOfRows = %d", p
->NumOfRows
);
147 printk(KERN_DEBUG
"NumOfPaddCols = %d", p
->NumOfPaddCols
);
148 printk(KERN_DEBUG
"NumOfPunctCols = %d", p
->NumOfPunctCols
);
149 printk(KERN_DEBUG
"ErrorTSPackets = %d", p
->ErrorTSPackets
);
150 printk(KERN_DEBUG
"TotalTSPackets = %d", p
->TotalTSPackets
);
151 printk(KERN_DEBUG
"NumOfValidMpeTlbs = %d", p
->NumOfValidMpeTlbs
);
152 printk(KERN_DEBUG
"NumOfInvalidMpeTlbs = %d", p
->NumOfInvalidMpeTlbs
);
153 printk(KERN_DEBUG
"NumOfCorrectedMpeTlbs = %d", p
->NumOfCorrectedMpeTlbs
);
154 printk(KERN_DEBUG
"BERErrorCount = %d", p
->BERErrorCount
);
155 printk(KERN_DEBUG
"BERBitCount = %d", p
->BERBitCount
);
156 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
157 printk(KERN_DEBUG
"PreBER = %d", p
->PreBER
);
158 printk(KERN_DEBUG
"CellId = %d", p
->CellId
);
159 printk(KERN_DEBUG
"DvbhSrvIndHP = %d", p
->DvbhSrvIndHP
);
160 printk(KERN_DEBUG
"DvbhSrvIndLP = %d", p
->DvbhSrvIndLP
);
161 printk(KERN_DEBUG
"NumMPEReceived = %d", p
->NumMPEReceived
);
164 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
166 pReceptionData
->SNR
= p
->SNR
;
167 pReceptionData
->BER
= p
->BER
;
168 pReceptionData
->BERErrorCount
= p
->BERErrorCount
;
169 pReceptionData
->InBandPwr
= p
->InBandPwr
;
170 pReceptionData
->ErrorTSPackets
= p
->ErrorTSPackets
;
174 static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
175 struct SMSHOSTLIB_STATISTICS_ISDBT_ST
*p
)
180 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
181 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
182 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
183 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
184 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
185 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
186 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
187 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
188 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
189 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
190 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
191 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
192 printk(KERN_DEBUG
"SystemType = %d", p
->SystemType
);
193 printk(KERN_DEBUG
"PartialReception = %d", p
->PartialReception
);
194 printk(KERN_DEBUG
"NumOfLayers = %d", p
->NumOfLayers
);
195 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
197 for (i
= 0; i
< 3; i
++) {
198 printk(KERN_DEBUG
"%d: CodeRate = %d", i
, p
->LayerInfo
[i
].CodeRate
);
199 printk(KERN_DEBUG
"%d: Constellation = %d", i
, p
->LayerInfo
[i
].Constellation
);
200 printk(KERN_DEBUG
"%d: BER = %d", i
, p
->LayerInfo
[i
].BER
);
201 printk(KERN_DEBUG
"%d: BERErrorCount = %d", i
, p
->LayerInfo
[i
].BERErrorCount
);
202 printk(KERN_DEBUG
"%d: BERBitCount = %d", i
, p
->LayerInfo
[i
].BERBitCount
);
203 printk(KERN_DEBUG
"%d: PreBER = %d", i
, p
->LayerInfo
[i
].PreBER
);
204 printk(KERN_DEBUG
"%d: TS_PER = %d", i
, p
->LayerInfo
[i
].TS_PER
);
205 printk(KERN_DEBUG
"%d: ErrorTSPackets = %d", i
, p
->LayerInfo
[i
].ErrorTSPackets
);
206 printk(KERN_DEBUG
"%d: TotalTSPackets = %d", i
, p
->LayerInfo
[i
].TotalTSPackets
);
207 printk(KERN_DEBUG
"%d: TILdepthI = %d", i
, p
->LayerInfo
[i
].TILdepthI
);
208 printk(KERN_DEBUG
"%d: NumberOfSegments = %d", i
, p
->LayerInfo
[i
].NumberOfSegments
);
209 printk(KERN_DEBUG
"%d: TMCCErrors = %d", i
, p
->LayerInfo
[i
].TMCCErrors
);
213 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
215 pReceptionData
->SNR
= p
->SNR
;
216 pReceptionData
->InBandPwr
= p
->InBandPwr
;
218 pReceptionData
->ErrorTSPackets
= 0;
219 pReceptionData
->BER
= 0;
220 pReceptionData
->BERErrorCount
= 0;
221 for (i
= 0; i
< 3; i
++) {
222 pReceptionData
->BER
+= p
->LayerInfo
[i
].BER
;
223 pReceptionData
->BERErrorCount
+= p
->LayerInfo
[i
].BERErrorCount
;
224 pReceptionData
->ErrorTSPackets
+= p
->LayerInfo
[i
].ErrorTSPackets
;
228 static int smsdvb_onresponse(void *context
, struct smscore_buffer_t
*cb
)
230 struct smsdvb_client_t
*client
= (struct smsdvb_client_t
*) context
;
231 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) (((u8
*) cb
->p
)
233 u32
*pMsgData
= (u32
*) phdr
+ 1;
234 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
235 bool is_status_update
= false;
237 smsendian_handle_rx_message((struct SmsMsgData_ST
*) phdr
);
239 switch (phdr
->msgType
) {
240 case MSG_SMS_DVBT_BDA_DATA
:
241 dvb_dmx_swfilter(&client
->demux
, (u8
*)(phdr
+ 1),
242 cb
->size
- sizeof(struct SmsMsgHdr_ST
));
245 case MSG_SMS_RF_TUNE_RES
:
246 case MSG_SMS_ISDBT_TUNE_RES
:
247 complete(&client
->tune_done
);
250 case MSG_SMS_SIGNAL_DETECTED_IND
:
251 sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
252 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= true;
253 is_status_update
= true;
256 case MSG_SMS_NO_SIGNAL_IND
:
257 sms_info("MSG_SMS_NO_SIGNAL_IND");
258 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= false;
259 is_status_update
= true;
262 case MSG_SMS_TRANSMISSION_IND
: {
263 sms_info("MSG_SMS_TRANSMISSION_IND");
266 memcpy(&client
->sms_stat_dvb
.TransmissionData
, pMsgData
,
267 sizeof(struct TRANSMISSION_STATISTICS_S
));
269 /* Mo need to correct guard interval
270 * (as opposed to old statistics message).
272 CORRECT_STAT_BANDWIDTH(client
->sms_stat_dvb
.TransmissionData
);
273 CORRECT_STAT_TRANSMISSON_MODE(
274 client
->sms_stat_dvb
.TransmissionData
);
275 is_status_update
= true;
278 case MSG_SMS_HO_PER_SLICES_IND
: {
279 struct RECEPTION_STATISTICS_S
*pReceptionData
=
280 &client
->sms_stat_dvb
.ReceptionData
;
281 struct SRVM_SIGNAL_STATUS_S SignalStatusData
;
283 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
285 SignalStatusData
.result
= pMsgData
[0];
286 SignalStatusData
.snr
= pMsgData
[1];
287 SignalStatusData
.inBandPower
= (s32
) pMsgData
[2];
288 SignalStatusData
.tsPackets
= pMsgData
[3];
289 SignalStatusData
.etsPackets
= pMsgData
[4];
290 SignalStatusData
.constellation
= pMsgData
[5];
291 SignalStatusData
.hpCode
= pMsgData
[6];
292 SignalStatusData
.tpsSrvIndLP
= pMsgData
[7] & 0x03;
293 SignalStatusData
.tpsSrvIndHP
= pMsgData
[8] & 0x03;
294 SignalStatusData
.cellId
= pMsgData
[9] & 0xFFFF;
295 SignalStatusData
.reason
= pMsgData
[10];
296 SignalStatusData
.requestId
= pMsgData
[11];
297 pReceptionData
->IsRfLocked
= pMsgData
[16];
298 pReceptionData
->IsDemodLocked
= pMsgData
[17];
299 pReceptionData
->ModemState
= pMsgData
[12];
300 pReceptionData
->SNR
= pMsgData
[1];
301 pReceptionData
->BER
= pMsgData
[13];
302 pReceptionData
->RSSI
= pMsgData
[14];
303 CORRECT_STAT_RSSI(client
->sms_stat_dvb
.ReceptionData
);
305 pReceptionData
->InBandPwr
= (s32
) pMsgData
[2];
306 pReceptionData
->CarrierOffset
= (s32
) pMsgData
[15];
307 pReceptionData
->TotalTSPackets
= pMsgData
[3];
308 pReceptionData
->ErrorTSPackets
= pMsgData
[4];
311 if ((SignalStatusData
.tsPackets
+ SignalStatusData
.etsPackets
)
313 pReceptionData
->TS_PER
= (SignalStatusData
.etsPackets
314 * 100) / (SignalStatusData
.tsPackets
315 + SignalStatusData
.etsPackets
);
317 pReceptionData
->TS_PER
= 0;
320 pReceptionData
->BERBitCount
= pMsgData
[18];
321 pReceptionData
->BERErrorCount
= pMsgData
[19];
323 pReceptionData
->MRC_SNR
= pMsgData
[20];
324 pReceptionData
->MRC_InBandPwr
= pMsgData
[21];
325 pReceptionData
->MRC_RSSI
= pMsgData
[22];
327 is_status_update
= true;
330 case MSG_SMS_GET_STATISTICS_RES
: {
332 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt
;
333 struct SmsMsgStatisticsInfo_ST dvb
;
334 } *p
= (void *) (phdr
+ 1);
335 struct RECEPTION_STATISTICS_S
*pReceptionData
=
336 &client
->sms_stat_dvb
.ReceptionData
;
338 sms_info("MSG_SMS_GET_STATISTICS_RES");
340 is_status_update
= true;
342 switch (smscore_get_device_mode(client
->coredev
)) {
343 case DEVICE_MODE_ISDBT
:
344 case DEVICE_MODE_ISDBT_BDA
:
345 smsdvb_update_isdbt_stats(pReceptionData
, &p
->isdbt
);
348 smsdvb_update_dvb_stats(pReceptionData
, &p
->dvb
.Stat
);
350 if (!pReceptionData
->IsDemodLocked
) {
351 pReceptionData
->SNR
= 0;
352 pReceptionData
->BER
= 0;
353 pReceptionData
->BERErrorCount
= 0;
354 pReceptionData
->InBandPwr
= 0;
355 pReceptionData
->ErrorTSPackets
= 0;
358 complete(&client
->tune_done
);
362 sms_info("Unhandled message %d", phdr
->msgType
);
365 smscore_putbuffer(client
->coredev
, cb
);
367 if (is_status_update
) {
368 if (client
->sms_stat_dvb
.ReceptionData
.IsDemodLocked
) {
369 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
370 | FE_HAS_VITERBI
| FE_HAS_SYNC
| FE_HAS_LOCK
;
371 sms_board_dvb3_event(client
, DVB3_EVENT_FE_LOCK
);
372 if (client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
374 sms_board_dvb3_event(client
, DVB3_EVENT_UNC_OK
);
376 sms_board_dvb3_event(client
,
380 if (client
->sms_stat_dvb
.ReceptionData
.IsRfLocked
)
381 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
383 client
->fe_status
= 0;
384 sms_board_dvb3_event(client
, DVB3_EVENT_FE_UNLOCK
);
391 static void smsdvb_unregister_client(struct smsdvb_client_t
*client
)
393 /* must be called under clientslock */
395 list_del(&client
->entry
);
397 smscore_unregister_client(client
->smsclient
);
398 dvb_unregister_frontend(&client
->frontend
);
399 dvb_dmxdev_release(&client
->dmxdev
);
400 dvb_dmx_release(&client
->demux
);
401 dvb_unregister_adapter(&client
->adapter
);
405 static void smsdvb_onremove(void *context
)
407 kmutex_lock(&g_smsdvb_clientslock
);
409 smsdvb_unregister_client((struct smsdvb_client_t
*) context
);
411 kmutex_unlock(&g_smsdvb_clientslock
);
414 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
416 struct smsdvb_client_t
*client
=
417 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
418 struct SmsMsgData_ST PidMsg
;
420 sms_debug("add pid %d(%x)",
421 feed
->pid
, feed
->pid
);
423 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
424 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
425 PidMsg
.xMsgHeader
.msgFlags
= 0;
426 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_ADD_PID_FILTER_REQ
;
427 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
428 PidMsg
.msgData
[0] = feed
->pid
;
430 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
431 return smsclient_sendrequest(client
->smsclient
,
432 &PidMsg
, sizeof(PidMsg
));
435 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
437 struct smsdvb_client_t
*client
=
438 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
439 struct SmsMsgData_ST PidMsg
;
441 sms_debug("remove pid %d(%x)",
442 feed
->pid
, feed
->pid
);
444 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
445 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
446 PidMsg
.xMsgHeader
.msgFlags
= 0;
447 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_REMOVE_PID_FILTER_REQ
;
448 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
449 PidMsg
.msgData
[0] = feed
->pid
;
451 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
452 return smsclient_sendrequest(client
->smsclient
,
453 &PidMsg
, sizeof(PidMsg
));
456 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t
*client
,
457 void *buffer
, size_t size
,
458 struct completion
*completion
)
462 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)buffer
);
463 rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
467 return wait_for_completion_timeout(completion
,
468 msecs_to_jiffies(2000)) ?
472 static int smsdvb_send_statistics_request(struct smsdvb_client_t
*client
)
475 struct SmsMsgHdr_ST Msg
= { MSG_SMS_GET_STATISTICS_REQ
,
476 DVBT_BDA_CONTROL_MSG_ID
,
478 sizeof(struct SmsMsgHdr_ST
), 0 };
480 rc
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
486 static inline int led_feedback(struct smsdvb_client_t
*client
)
488 if (client
->fe_status
& FE_HAS_LOCK
)
489 return sms_board_led_feedback(client
->coredev
,
490 (client
->sms_stat_dvb
.ReceptionData
.BER
491 == 0) ? SMS_LED_HI
: SMS_LED_LO
);
493 return sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
496 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
499 struct smsdvb_client_t
*client
;
500 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
502 rc
= smsdvb_send_statistics_request(client
);
504 *stat
= client
->fe_status
;
506 led_feedback(client
);
511 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
514 struct smsdvb_client_t
*client
;
515 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
517 rc
= smsdvb_send_statistics_request(client
);
519 *ber
= client
->sms_stat_dvb
.ReceptionData
.BER
;
521 led_feedback(client
);
526 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
530 struct smsdvb_client_t
*client
;
531 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
533 rc
= smsdvb_send_statistics_request(client
);
535 if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
< -95)
537 else if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
> -29)
541 (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
544 led_feedback(client
);
549 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
552 struct smsdvb_client_t
*client
;
553 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
555 rc
= smsdvb_send_statistics_request(client
);
557 *snr
= client
->sms_stat_dvb
.ReceptionData
.SNR
;
559 led_feedback(client
);
564 static int smsdvb_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
567 struct smsdvb_client_t
*client
;
568 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
570 rc
= smsdvb_send_statistics_request(client
);
572 *ucblocks
= client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
;
574 led_feedback(client
);
579 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
,
580 struct dvb_frontend_tune_settings
*tune
)
584 tune
->min_delay_ms
= 400;
585 tune
->step_size
= 250000;
590 static int smsdvb_dvbt_set_frontend(struct dvb_frontend
*fe
,
591 struct dvb_frontend_parameters
*p
)
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
,
658 struct dvb_frontend_parameters
*p
)
660 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
661 struct smsdvb_client_t
*client
=
662 container_of(fe
, struct smsdvb_client_t
, frontend
);
665 struct SmsMsgHdr_ST Msg
;
669 fe
->dtv_property_cache
.delivery_system
= SYS_ISDBT
;
671 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
672 Msg
.Msg
.msgDstId
= HIF_TASK
;
673 Msg
.Msg
.msgFlags
= 0;
674 Msg
.Msg
.msgType
= MSG_SMS_ISDBT_TUNE_REQ
;
675 Msg
.Msg
.msgLength
= sizeof(Msg
);
677 if (c
->isdbt_sb_segment_idx
== -1)
678 c
->isdbt_sb_segment_idx
= 0;
680 switch (c
->isdbt_sb_segment_count
) {
682 Msg
.Data
[1] = BW_ISDBT_3SEG
;
685 Msg
.Data
[1] = BW_ISDBT_1SEG
;
688 switch (c
->bandwidth_hz
/ 1000000) {
691 c
->isdbt_sb_segment_count
= 3;
692 Msg
.Data
[1] = BW_ISDBT_3SEG
;
695 c
->isdbt_sb_segment_count
= 1;
696 Msg
.Data
[1] = BW_ISDBT_1SEG
;
698 default: /* Assumes 6 MHZ bw */
699 c
->isdbt_sb_segment_count
= 1;
700 c
->bandwidth_hz
= 6000;
701 Msg
.Data
[1] = BW_ISDBT_1SEG
;
706 sms_info("Segment count %d not supported", c
->isdbt_sb_segment_count
);
710 Msg
.Data
[0] = c
->frequency
;
711 Msg
.Data
[2] = 12000000;
712 Msg
.Data
[3] = c
->isdbt_sb_segment_idx
;
714 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__
,
715 c
->frequency
, c
->isdbt_sb_segment_count
,
716 c
->isdbt_sb_segment_idx
);
718 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
722 static int smsdvb_set_frontend(struct dvb_frontend
*fe
,
723 struct dvb_frontend_parameters
*fep
)
725 struct smsdvb_client_t
*client
=
726 container_of(fe
, struct smsdvb_client_t
, frontend
);
727 struct smscore_device_t
*coredev
= client
->coredev
;
729 switch (smscore_get_device_mode(coredev
)) {
730 case DEVICE_MODE_DVBT
:
731 case DEVICE_MODE_DVBT_BDA
:
732 return smsdvb_dvbt_set_frontend(fe
, fep
);
733 case DEVICE_MODE_ISDBT
:
734 case DEVICE_MODE_ISDBT_BDA
:
735 return smsdvb_isdbt_set_frontend(fe
, fep
);
741 static int smsdvb_get_frontend(struct dvb_frontend
*fe
,
742 struct dvb_frontend_parameters
*fep
)
744 struct smsdvb_client_t
*client
=
745 container_of(fe
, struct smsdvb_client_t
, frontend
);
750 memcpy(fep
, &client
->fe_params
,
751 sizeof(struct dvb_frontend_parameters
));
756 static int smsdvb_init(struct dvb_frontend
*fe
)
758 struct smsdvb_client_t
*client
=
759 container_of(fe
, struct smsdvb_client_t
, frontend
);
761 sms_board_power(client
->coredev
, 1);
763 sms_board_dvb3_event(client
, DVB3_EVENT_INIT
);
767 static int smsdvb_sleep(struct dvb_frontend
*fe
)
769 struct smsdvb_client_t
*client
=
770 container_of(fe
, struct smsdvb_client_t
, frontend
);
772 sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
773 sms_board_power(client
->coredev
, 0);
775 sms_board_dvb3_event(client
, DVB3_EVENT_SLEEP
);
780 static void smsdvb_release(struct dvb_frontend
*fe
)
785 static struct dvb_frontend_ops smsdvb_fe_ops
= {
787 .name
= "Siano Mobile Digital MDTV Receiver",
789 .frequency_min
= 44250000,
790 .frequency_max
= 867250000,
791 .frequency_stepsize
= 250000,
792 .caps
= FE_CAN_INVERSION_AUTO
|
793 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
794 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
795 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
|
796 FE_CAN_QAM_AUTO
| FE_CAN_TRANSMISSION_MODE_AUTO
|
797 FE_CAN_GUARD_INTERVAL_AUTO
|
799 FE_CAN_HIERARCHY_AUTO
,
802 .release
= smsdvb_release
,
804 .set_frontend
= smsdvb_set_frontend
,
805 .get_frontend
= smsdvb_get_frontend
,
806 .get_tune_settings
= smsdvb_get_tune_settings
,
808 .read_status
= smsdvb_read_status
,
809 .read_ber
= smsdvb_read_ber
,
810 .read_signal_strength
= smsdvb_read_signal_strength
,
811 .read_snr
= smsdvb_read_snr
,
812 .read_ucblocks
= smsdvb_read_ucblocks
,
815 .sleep
= smsdvb_sleep
,
818 static int smsdvb_hotplug(struct smscore_device_t
*coredev
,
819 struct device
*device
, int arrival
)
821 struct smsclient_params_t params
;
822 struct smsdvb_client_t
*client
;
825 /* device removal handled by onremove callback */
828 client
= kzalloc(sizeof(struct smsdvb_client_t
), GFP_KERNEL
);
830 sms_err("kmalloc() failed");
834 /* register dvb adapter */
835 rc
= dvb_register_adapter(&client
->adapter
,
837 smscore_get_board_id(coredev
))->name
,
838 THIS_MODULE
, device
, adapter_nr
);
840 sms_err("dvb_register_adapter() failed %d", rc
);
845 client
->demux
.dmx
.capabilities
= DMX_TS_FILTERING
;
846 client
->demux
.filternum
= 32; /* todo: nova ??? */
847 client
->demux
.feednum
= 32;
848 client
->demux
.start_feed
= smsdvb_start_feed
;
849 client
->demux
.stop_feed
= smsdvb_stop_feed
;
851 rc
= dvb_dmx_init(&client
->demux
);
853 sms_err("dvb_dmx_init failed %d", rc
);
858 client
->dmxdev
.filternum
= 32;
859 client
->dmxdev
.demux
= &client
->demux
.dmx
;
860 client
->dmxdev
.capabilities
= 0;
862 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
864 sms_err("dvb_dmxdev_init failed %d", rc
);
868 /* init and register frontend */
869 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
,
870 sizeof(struct dvb_frontend_ops
));
872 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
874 sms_err("frontend registration failed %d", rc
);
878 params
.initial_id
= 1;
879 params
.data_type
= MSG_SMS_DVBT_BDA_DATA
;
880 params
.onresponse_handler
= smsdvb_onresponse
;
881 params
.onremove_handler
= smsdvb_onremove
;
882 params
.context
= client
;
884 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
886 sms_err("smscore_register_client() failed %d", rc
);
890 client
->coredev
= coredev
;
892 init_completion(&client
->tune_done
);
894 kmutex_lock(&g_smsdvb_clientslock
);
896 list_add(&client
->entry
, &g_smsdvb_clients
);
898 kmutex_unlock(&g_smsdvb_clientslock
);
900 client
->event_fe_state
= -1;
901 client
->event_unc_state
= -1;
902 sms_board_dvb3_event(client
, DVB3_EVENT_HOTPLUG
);
905 sms_board_setup(coredev
);
910 dvb_unregister_frontend(&client
->frontend
);
913 dvb_dmxdev_release(&client
->dmxdev
);
916 dvb_dmx_release(&client
->demux
);
919 dvb_unregister_adapter(&client
->adapter
);
926 static int __init
smsdvb_module_init(void)
930 INIT_LIST_HEAD(&g_smsdvb_clients
);
931 kmutex_init(&g_smsdvb_clientslock
);
933 rc
= smscore_register_hotplug(smsdvb_hotplug
);
940 static void __exit
smsdvb_module_exit(void)
942 smscore_unregister_hotplug(smsdvb_hotplug
);
944 kmutex_lock(&g_smsdvb_clientslock
);
946 while (!list_empty(&g_smsdvb_clients
))
947 smsdvb_unregister_client(
948 (struct smsdvb_client_t
*) g_smsdvb_clients
.next
);
950 kmutex_unlock(&g_smsdvb_clientslock
);
953 module_init(smsdvb_module_init
);
954 module_exit(smsdvb_module_exit
);
956 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
957 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
958 MODULE_LICENSE("GPL");