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
;
64 module_param_named(debug
, sms_dbg
, int, 0644);
65 MODULE_PARM_DESC(debug
, "set debug level (info=1, adv=2 (or-able))");
67 /* Events that may come from DVB v3 adapter */
68 static void sms_board_dvb3_event(struct smsdvb_client_t
*client
,
69 enum SMS_DVB3_EVENTS event
) {
71 struct smscore_device_t
*coredev
= client
->coredev
;
74 sms_debug("DVB3_EVENT_INIT");
75 sms_board_event(coredev
, BOARD_EVENT_BIND
);
77 case DVB3_EVENT_SLEEP
:
78 sms_debug("DVB3_EVENT_SLEEP");
79 sms_board_event(coredev
, BOARD_EVENT_POWER_SUSPEND
);
81 case DVB3_EVENT_HOTPLUG
:
82 sms_debug("DVB3_EVENT_HOTPLUG");
83 sms_board_event(coredev
, BOARD_EVENT_POWER_INIT
);
85 case DVB3_EVENT_FE_LOCK
:
86 if (client
->event_fe_state
!= DVB3_EVENT_FE_LOCK
) {
87 client
->event_fe_state
= DVB3_EVENT_FE_LOCK
;
88 sms_debug("DVB3_EVENT_FE_LOCK");
89 sms_board_event(coredev
, BOARD_EVENT_FE_LOCK
);
92 case DVB3_EVENT_FE_UNLOCK
:
93 if (client
->event_fe_state
!= DVB3_EVENT_FE_UNLOCK
) {
94 client
->event_fe_state
= DVB3_EVENT_FE_UNLOCK
;
95 sms_debug("DVB3_EVENT_FE_UNLOCK");
96 sms_board_event(coredev
, BOARD_EVENT_FE_UNLOCK
);
99 case DVB3_EVENT_UNC_OK
:
100 if (client
->event_unc_state
!= DVB3_EVENT_UNC_OK
) {
101 client
->event_unc_state
= DVB3_EVENT_UNC_OK
;
102 sms_debug("DVB3_EVENT_UNC_OK");
103 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_OK
);
106 case DVB3_EVENT_UNC_ERR
:
107 if (client
->event_unc_state
!= DVB3_EVENT_UNC_ERR
) {
108 client
->event_unc_state
= DVB3_EVENT_UNC_ERR
;
109 sms_debug("DVB3_EVENT_UNC_ERR");
110 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_ERRORS
);
115 sms_err("Unknown dvb3 api event");
121 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
122 struct SMSHOSTLIB_STATISTICS_ST
*p
)
125 printk(KERN_DEBUG
"Reserved = %d", p
->Reserved
);
126 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
127 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
128 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
129 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
130 printk(KERN_DEBUG
"BER = %d", p
->BER
);
131 printk(KERN_DEBUG
"FIB_CRC = %d", p
->FIB_CRC
);
132 printk(KERN_DEBUG
"TS_PER = %d", p
->TS_PER
);
133 printk(KERN_DEBUG
"MFER = %d", p
->MFER
);
134 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
135 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
136 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
137 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
138 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
139 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
140 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
141 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
142 printk(KERN_DEBUG
"CodeRate = %d", p
->CodeRate
);
143 printk(KERN_DEBUG
"LPCodeRate = %d", p
->LPCodeRate
);
144 printk(KERN_DEBUG
"Hierarchy = %d", p
->Hierarchy
);
145 printk(KERN_DEBUG
"Constellation = %d", p
->Constellation
);
146 printk(KERN_DEBUG
"BurstSize = %d", p
->BurstSize
);
147 printk(KERN_DEBUG
"BurstDuration = %d", p
->BurstDuration
);
148 printk(KERN_DEBUG
"BurstCycleTime = %d", p
->BurstCycleTime
);
149 printk(KERN_DEBUG
"CalculatedBurstCycleTime = %d", p
->CalculatedBurstCycleTime
);
150 printk(KERN_DEBUG
"NumOfRows = %d", p
->NumOfRows
);
151 printk(KERN_DEBUG
"NumOfPaddCols = %d", p
->NumOfPaddCols
);
152 printk(KERN_DEBUG
"NumOfPunctCols = %d", p
->NumOfPunctCols
);
153 printk(KERN_DEBUG
"ErrorTSPackets = %d", p
->ErrorTSPackets
);
154 printk(KERN_DEBUG
"TotalTSPackets = %d", p
->TotalTSPackets
);
155 printk(KERN_DEBUG
"NumOfValidMpeTlbs = %d", p
->NumOfValidMpeTlbs
);
156 printk(KERN_DEBUG
"NumOfInvalidMpeTlbs = %d", p
->NumOfInvalidMpeTlbs
);
157 printk(KERN_DEBUG
"NumOfCorrectedMpeTlbs = %d", p
->NumOfCorrectedMpeTlbs
);
158 printk(KERN_DEBUG
"BERErrorCount = %d", p
->BERErrorCount
);
159 printk(KERN_DEBUG
"BERBitCount = %d", p
->BERBitCount
);
160 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
161 printk(KERN_DEBUG
"PreBER = %d", p
->PreBER
);
162 printk(KERN_DEBUG
"CellId = %d", p
->CellId
);
163 printk(KERN_DEBUG
"DvbhSrvIndHP = %d", p
->DvbhSrvIndHP
);
164 printk(KERN_DEBUG
"DvbhSrvIndLP = %d", p
->DvbhSrvIndLP
);
165 printk(KERN_DEBUG
"NumMPEReceived = %d", p
->NumMPEReceived
);
168 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
170 pReceptionData
->SNR
= p
->SNR
;
171 pReceptionData
->BER
= p
->BER
;
172 pReceptionData
->BERErrorCount
= p
->BERErrorCount
;
173 pReceptionData
->InBandPwr
= p
->InBandPwr
;
174 pReceptionData
->ErrorTSPackets
= p
->ErrorTSPackets
;
178 static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
179 struct SMSHOSTLIB_STATISTICS_ISDBT_ST
*p
)
184 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
185 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
186 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
187 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
188 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
189 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
190 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
191 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
192 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
193 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
194 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
195 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
196 printk(KERN_DEBUG
"SystemType = %d", p
->SystemType
);
197 printk(KERN_DEBUG
"PartialReception = %d", p
->PartialReception
);
198 printk(KERN_DEBUG
"NumOfLayers = %d", p
->NumOfLayers
);
199 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
201 for (i
= 0; i
< 3; i
++) {
202 printk(KERN_DEBUG
"%d: CodeRate = %d", i
, p
->LayerInfo
[i
].CodeRate
);
203 printk(KERN_DEBUG
"%d: Constellation = %d", i
, p
->LayerInfo
[i
].Constellation
);
204 printk(KERN_DEBUG
"%d: BER = %d", i
, p
->LayerInfo
[i
].BER
);
205 printk(KERN_DEBUG
"%d: BERErrorCount = %d", i
, p
->LayerInfo
[i
].BERErrorCount
);
206 printk(KERN_DEBUG
"%d: BERBitCount = %d", i
, p
->LayerInfo
[i
].BERBitCount
);
207 printk(KERN_DEBUG
"%d: PreBER = %d", i
, p
->LayerInfo
[i
].PreBER
);
208 printk(KERN_DEBUG
"%d: TS_PER = %d", i
, p
->LayerInfo
[i
].TS_PER
);
209 printk(KERN_DEBUG
"%d: ErrorTSPackets = %d", i
, p
->LayerInfo
[i
].ErrorTSPackets
);
210 printk(KERN_DEBUG
"%d: TotalTSPackets = %d", i
, p
->LayerInfo
[i
].TotalTSPackets
);
211 printk(KERN_DEBUG
"%d: TILdepthI = %d", i
, p
->LayerInfo
[i
].TILdepthI
);
212 printk(KERN_DEBUG
"%d: NumberOfSegments = %d", i
, p
->LayerInfo
[i
].NumberOfSegments
);
213 printk(KERN_DEBUG
"%d: TMCCErrors = %d", i
, p
->LayerInfo
[i
].TMCCErrors
);
217 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
219 pReceptionData
->SNR
= p
->SNR
;
220 pReceptionData
->InBandPwr
= p
->InBandPwr
;
222 pReceptionData
->ErrorTSPackets
= 0;
223 pReceptionData
->BER
= 0;
224 pReceptionData
->BERErrorCount
= 0;
225 for (i
= 0; i
< 3; i
++) {
226 pReceptionData
->BER
+= p
->LayerInfo
[i
].BER
;
227 pReceptionData
->BERErrorCount
+= p
->LayerInfo
[i
].BERErrorCount
;
228 pReceptionData
->ErrorTSPackets
+= p
->LayerInfo
[i
].ErrorTSPackets
;
232 static int smsdvb_onresponse(void *context
, struct smscore_buffer_t
*cb
)
234 struct smsdvb_client_t
*client
= (struct smsdvb_client_t
*) context
;
235 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) (((u8
*) cb
->p
)
237 u32
*pMsgData
= (u32
*) phdr
+ 1;
238 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
239 bool is_status_update
= false;
241 smsendian_handle_rx_message((struct SmsMsgData_ST
*) phdr
);
243 switch (phdr
->msgType
) {
244 case MSG_SMS_DVBT_BDA_DATA
:
245 dvb_dmx_swfilter(&client
->demux
, (u8
*)(phdr
+ 1),
246 cb
->size
- sizeof(struct SmsMsgHdr_ST
));
249 case MSG_SMS_RF_TUNE_RES
:
250 case MSG_SMS_ISDBT_TUNE_RES
:
251 complete(&client
->tune_done
);
254 case MSG_SMS_SIGNAL_DETECTED_IND
:
255 sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
256 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= true;
257 is_status_update
= true;
260 case MSG_SMS_NO_SIGNAL_IND
:
261 sms_info("MSG_SMS_NO_SIGNAL_IND");
262 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= false;
263 is_status_update
= true;
266 case MSG_SMS_TRANSMISSION_IND
: {
267 sms_info("MSG_SMS_TRANSMISSION_IND");
270 memcpy(&client
->sms_stat_dvb
.TransmissionData
, pMsgData
,
271 sizeof(struct TRANSMISSION_STATISTICS_S
));
273 /* Mo need to correct guard interval
274 * (as opposed to old statistics message).
276 CORRECT_STAT_BANDWIDTH(client
->sms_stat_dvb
.TransmissionData
);
277 CORRECT_STAT_TRANSMISSON_MODE(
278 client
->sms_stat_dvb
.TransmissionData
);
279 is_status_update
= true;
282 case MSG_SMS_HO_PER_SLICES_IND
: {
283 struct RECEPTION_STATISTICS_S
*pReceptionData
=
284 &client
->sms_stat_dvb
.ReceptionData
;
285 struct SRVM_SIGNAL_STATUS_S SignalStatusData
;
287 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
289 SignalStatusData
.result
= pMsgData
[0];
290 SignalStatusData
.snr
= pMsgData
[1];
291 SignalStatusData
.inBandPower
= (s32
) pMsgData
[2];
292 SignalStatusData
.tsPackets
= pMsgData
[3];
293 SignalStatusData
.etsPackets
= pMsgData
[4];
294 SignalStatusData
.constellation
= pMsgData
[5];
295 SignalStatusData
.hpCode
= pMsgData
[6];
296 SignalStatusData
.tpsSrvIndLP
= pMsgData
[7] & 0x03;
297 SignalStatusData
.tpsSrvIndHP
= pMsgData
[8] & 0x03;
298 SignalStatusData
.cellId
= pMsgData
[9] & 0xFFFF;
299 SignalStatusData
.reason
= pMsgData
[10];
300 SignalStatusData
.requestId
= pMsgData
[11];
301 pReceptionData
->IsRfLocked
= pMsgData
[16];
302 pReceptionData
->IsDemodLocked
= pMsgData
[17];
303 pReceptionData
->ModemState
= pMsgData
[12];
304 pReceptionData
->SNR
= pMsgData
[1];
305 pReceptionData
->BER
= pMsgData
[13];
306 pReceptionData
->RSSI
= pMsgData
[14];
307 CORRECT_STAT_RSSI(client
->sms_stat_dvb
.ReceptionData
);
309 pReceptionData
->InBandPwr
= (s32
) pMsgData
[2];
310 pReceptionData
->CarrierOffset
= (s32
) pMsgData
[15];
311 pReceptionData
->TotalTSPackets
= pMsgData
[3];
312 pReceptionData
->ErrorTSPackets
= pMsgData
[4];
315 if ((SignalStatusData
.tsPackets
+ SignalStatusData
.etsPackets
)
317 pReceptionData
->TS_PER
= (SignalStatusData
.etsPackets
318 * 100) / (SignalStatusData
.tsPackets
319 + SignalStatusData
.etsPackets
);
321 pReceptionData
->TS_PER
= 0;
324 pReceptionData
->BERBitCount
= pMsgData
[18];
325 pReceptionData
->BERErrorCount
= pMsgData
[19];
327 pReceptionData
->MRC_SNR
= pMsgData
[20];
328 pReceptionData
->MRC_InBandPwr
= pMsgData
[21];
329 pReceptionData
->MRC_RSSI
= pMsgData
[22];
331 is_status_update
= true;
334 case MSG_SMS_GET_STATISTICS_RES
: {
336 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt
;
337 struct SmsMsgStatisticsInfo_ST dvb
;
338 } *p
= (void *) (phdr
+ 1);
339 struct RECEPTION_STATISTICS_S
*pReceptionData
=
340 &client
->sms_stat_dvb
.ReceptionData
;
342 sms_info("MSG_SMS_GET_STATISTICS_RES");
344 is_status_update
= true;
346 switch (smscore_get_device_mode(client
->coredev
)) {
347 case DEVICE_MODE_ISDBT
:
348 case DEVICE_MODE_ISDBT_BDA
:
349 smsdvb_update_isdbt_stats(pReceptionData
, &p
->isdbt
);
352 smsdvb_update_dvb_stats(pReceptionData
, &p
->dvb
.Stat
);
354 if (!pReceptionData
->IsDemodLocked
) {
355 pReceptionData
->SNR
= 0;
356 pReceptionData
->BER
= 0;
357 pReceptionData
->BERErrorCount
= 0;
358 pReceptionData
->InBandPwr
= 0;
359 pReceptionData
->ErrorTSPackets
= 0;
362 complete(&client
->tune_done
);
366 sms_info("Unhandled message %d", phdr
->msgType
);
369 smscore_putbuffer(client
->coredev
, cb
);
371 if (is_status_update
) {
372 if (client
->sms_stat_dvb
.ReceptionData
.IsDemodLocked
) {
373 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
374 | FE_HAS_VITERBI
| FE_HAS_SYNC
| FE_HAS_LOCK
;
375 sms_board_dvb3_event(client
, DVB3_EVENT_FE_LOCK
);
376 if (client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
378 sms_board_dvb3_event(client
, DVB3_EVENT_UNC_OK
);
380 sms_board_dvb3_event(client
,
384 if (client
->sms_stat_dvb
.ReceptionData
.IsRfLocked
)
385 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
387 client
->fe_status
= 0;
388 sms_board_dvb3_event(client
, DVB3_EVENT_FE_UNLOCK
);
395 static void smsdvb_unregister_client(struct smsdvb_client_t
*client
)
397 /* must be called under clientslock */
399 list_del(&client
->entry
);
401 smscore_unregister_client(client
->smsclient
);
402 dvb_unregister_frontend(&client
->frontend
);
403 dvb_dmxdev_release(&client
->dmxdev
);
404 dvb_dmx_release(&client
->demux
);
405 dvb_unregister_adapter(&client
->adapter
);
409 static void smsdvb_onremove(void *context
)
411 kmutex_lock(&g_smsdvb_clientslock
);
413 smsdvb_unregister_client((struct smsdvb_client_t
*) context
);
415 kmutex_unlock(&g_smsdvb_clientslock
);
418 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
420 struct smsdvb_client_t
*client
=
421 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
422 struct SmsMsgData_ST PidMsg
;
424 sms_debug("add pid %d(%x)",
425 feed
->pid
, feed
->pid
);
427 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
428 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
429 PidMsg
.xMsgHeader
.msgFlags
= 0;
430 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_ADD_PID_FILTER_REQ
;
431 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
432 PidMsg
.msgData
[0] = feed
->pid
;
434 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
435 return smsclient_sendrequest(client
->smsclient
,
436 &PidMsg
, sizeof(PidMsg
));
439 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
441 struct smsdvb_client_t
*client
=
442 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
443 struct SmsMsgData_ST PidMsg
;
445 sms_debug("remove pid %d(%x)",
446 feed
->pid
, feed
->pid
);
448 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
449 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
450 PidMsg
.xMsgHeader
.msgFlags
= 0;
451 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_REMOVE_PID_FILTER_REQ
;
452 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
453 PidMsg
.msgData
[0] = feed
->pid
;
455 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
456 return smsclient_sendrequest(client
->smsclient
,
457 &PidMsg
, sizeof(PidMsg
));
460 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t
*client
,
461 void *buffer
, size_t size
,
462 struct completion
*completion
)
466 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)buffer
);
467 rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
471 return wait_for_completion_timeout(completion
,
472 msecs_to_jiffies(2000)) ?
476 static int smsdvb_send_statistics_request(struct smsdvb_client_t
*client
)
479 struct SmsMsgHdr_ST Msg
= { MSG_SMS_GET_STATISTICS_REQ
,
480 DVBT_BDA_CONTROL_MSG_ID
,
482 sizeof(struct SmsMsgHdr_ST
), 0 };
484 rc
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
490 static inline int led_feedback(struct smsdvb_client_t
*client
)
492 if (client
->fe_status
& FE_HAS_LOCK
)
493 return sms_board_led_feedback(client
->coredev
,
494 (client
->sms_stat_dvb
.ReceptionData
.BER
495 == 0) ? SMS_LED_HI
: SMS_LED_LO
);
497 return sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
500 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
503 struct smsdvb_client_t
*client
;
504 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
506 rc
= smsdvb_send_statistics_request(client
);
508 *stat
= client
->fe_status
;
510 led_feedback(client
);
515 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
518 struct smsdvb_client_t
*client
;
519 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
521 rc
= smsdvb_send_statistics_request(client
);
523 *ber
= client
->sms_stat_dvb
.ReceptionData
.BER
;
525 led_feedback(client
);
530 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
534 struct smsdvb_client_t
*client
;
535 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
537 rc
= smsdvb_send_statistics_request(client
);
539 if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
< -95)
541 else if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
> -29)
545 (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
548 led_feedback(client
);
553 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
556 struct smsdvb_client_t
*client
;
557 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
559 rc
= smsdvb_send_statistics_request(client
);
561 *snr
= client
->sms_stat_dvb
.ReceptionData
.SNR
;
563 led_feedback(client
);
568 static int smsdvb_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
571 struct smsdvb_client_t
*client
;
572 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
574 rc
= smsdvb_send_statistics_request(client
);
576 *ucblocks
= client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
;
578 led_feedback(client
);
583 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
,
584 struct dvb_frontend_tune_settings
*tune
)
588 tune
->min_delay_ms
= 400;
589 tune
->step_size
= 250000;
594 static int smsdvb_dvbt_set_frontend(struct dvb_frontend
*fe
,
595 struct dvb_frontend_parameters
*p
)
597 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
598 struct smsdvb_client_t
*client
=
599 container_of(fe
, struct smsdvb_client_t
, frontend
);
602 struct SmsMsgHdr_ST Msg
;
608 client
->fe_status
= FE_HAS_SIGNAL
;
609 client
->event_fe_state
= -1;
610 client
->event_unc_state
= -1;
611 fe
->dtv_property_cache
.delivery_system
= SYS_DVBT
;
613 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
614 Msg
.Msg
.msgDstId
= HIF_TASK
;
615 Msg
.Msg
.msgFlags
= 0;
616 Msg
.Msg
.msgType
= MSG_SMS_RF_TUNE_REQ
;
617 Msg
.Msg
.msgLength
= sizeof(Msg
);
618 Msg
.Data
[0] = c
->frequency
;
619 Msg
.Data
[2] = 12000000;
621 sms_info("%s: freq %d band %d", __func__
, c
->frequency
,
624 switch (c
->bandwidth_hz
/ 1000000) {
626 Msg
.Data
[1] = BW_8_MHZ
;
629 Msg
.Data
[1] = BW_7_MHZ
;
632 Msg
.Data
[1] = BW_6_MHZ
;
639 /* Disable LNA, if any. An error is returned if no LNA is present */
640 ret
= sms_board_lna_control(client
->coredev
, 0);
644 /* tune with LNA off at first */
645 ret
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
648 smsdvb_read_status(fe
, &status
);
650 if (status
& FE_HAS_LOCK
)
653 /* previous tune didn't lock - enable LNA and tune again */
654 sms_board_lna_control(client
->coredev
, 1);
657 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
661 static int smsdvb_isdbt_set_frontend(struct dvb_frontend
*fe
,
662 struct dvb_frontend_parameters
*p
)
664 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
665 struct smsdvb_client_t
*client
=
666 container_of(fe
, struct smsdvb_client_t
, frontend
);
669 struct SmsMsgHdr_ST Msg
;
673 fe
->dtv_property_cache
.delivery_system
= SYS_ISDBT
;
675 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
676 Msg
.Msg
.msgDstId
= HIF_TASK
;
677 Msg
.Msg
.msgFlags
= 0;
678 Msg
.Msg
.msgType
= MSG_SMS_ISDBT_TUNE_REQ
;
679 Msg
.Msg
.msgLength
= sizeof(Msg
);
681 if (c
->isdbt_sb_segment_idx
== -1)
682 c
->isdbt_sb_segment_idx
= 0;
684 switch (c
->isdbt_sb_segment_count
) {
686 Msg
.Data
[1] = BW_ISDBT_3SEG
;
689 Msg
.Data
[1] = BW_ISDBT_1SEG
;
692 switch (c
->bandwidth_hz
/ 1000000) {
695 c
->isdbt_sb_segment_count
= 3;
696 Msg
.Data
[1] = BW_ISDBT_3SEG
;
699 c
->isdbt_sb_segment_count
= 1;
700 Msg
.Data
[1] = BW_ISDBT_1SEG
;
702 default: /* Assumes 6 MHZ bw */
703 c
->isdbt_sb_segment_count
= 1;
704 c
->bandwidth_hz
= 6000;
705 Msg
.Data
[1] = BW_ISDBT_1SEG
;
710 sms_info("Segment count %d not supported", c
->isdbt_sb_segment_count
);
714 Msg
.Data
[0] = c
->frequency
;
715 Msg
.Data
[2] = 12000000;
716 Msg
.Data
[3] = c
->isdbt_sb_segment_idx
;
718 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__
,
719 c
->frequency
, c
->isdbt_sb_segment_count
,
720 c
->isdbt_sb_segment_idx
);
722 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
726 static int smsdvb_set_frontend(struct dvb_frontend
*fe
,
727 struct dvb_frontend_parameters
*fep
)
729 struct smsdvb_client_t
*client
=
730 container_of(fe
, struct smsdvb_client_t
, frontend
);
731 struct smscore_device_t
*coredev
= client
->coredev
;
733 switch (smscore_get_device_mode(coredev
)) {
734 case DEVICE_MODE_DVBT
:
735 case DEVICE_MODE_DVBT_BDA
:
736 return smsdvb_dvbt_set_frontend(fe
, fep
);
737 case DEVICE_MODE_ISDBT
:
738 case DEVICE_MODE_ISDBT_BDA
:
739 return smsdvb_isdbt_set_frontend(fe
, fep
);
745 static int smsdvb_get_frontend(struct dvb_frontend
*fe
,
746 struct dvb_frontend_parameters
*fep
)
748 struct smsdvb_client_t
*client
=
749 container_of(fe
, struct smsdvb_client_t
, frontend
);
754 memcpy(fep
, &client
->fe_params
,
755 sizeof(struct dvb_frontend_parameters
));
760 static int smsdvb_init(struct dvb_frontend
*fe
)
762 struct smsdvb_client_t
*client
=
763 container_of(fe
, struct smsdvb_client_t
, frontend
);
765 sms_board_power(client
->coredev
, 1);
767 sms_board_dvb3_event(client
, DVB3_EVENT_INIT
);
771 static int smsdvb_sleep(struct dvb_frontend
*fe
)
773 struct smsdvb_client_t
*client
=
774 container_of(fe
, struct smsdvb_client_t
, frontend
);
776 sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
777 sms_board_power(client
->coredev
, 0);
779 sms_board_dvb3_event(client
, DVB3_EVENT_SLEEP
);
784 static void smsdvb_release(struct dvb_frontend
*fe
)
789 static struct dvb_frontend_ops smsdvb_fe_ops
= {
791 .name
= "Siano Mobile Digital MDTV Receiver",
793 .frequency_min
= 44250000,
794 .frequency_max
= 867250000,
795 .frequency_stepsize
= 250000,
796 .caps
= FE_CAN_INVERSION_AUTO
|
797 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
798 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
799 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
|
800 FE_CAN_QAM_AUTO
| FE_CAN_TRANSMISSION_MODE_AUTO
|
801 FE_CAN_GUARD_INTERVAL_AUTO
|
803 FE_CAN_HIERARCHY_AUTO
,
806 .release
= smsdvb_release
,
808 .set_frontend
= smsdvb_set_frontend
,
809 .get_frontend
= smsdvb_get_frontend
,
810 .get_tune_settings
= smsdvb_get_tune_settings
,
812 .read_status
= smsdvb_read_status
,
813 .read_ber
= smsdvb_read_ber
,
814 .read_signal_strength
= smsdvb_read_signal_strength
,
815 .read_snr
= smsdvb_read_snr
,
816 .read_ucblocks
= smsdvb_read_ucblocks
,
819 .sleep
= smsdvb_sleep
,
822 static int smsdvb_hotplug(struct smscore_device_t
*coredev
,
823 struct device
*device
, int arrival
)
825 struct smsclient_params_t params
;
826 struct smsdvb_client_t
*client
;
829 /* device removal handled by onremove callback */
832 client
= kzalloc(sizeof(struct smsdvb_client_t
), GFP_KERNEL
);
834 sms_err("kmalloc() failed");
838 /* register dvb adapter */
839 rc
= dvb_register_adapter(&client
->adapter
,
841 smscore_get_board_id(coredev
))->name
,
842 THIS_MODULE
, device
, adapter_nr
);
844 sms_err("dvb_register_adapter() failed %d", rc
);
849 client
->demux
.dmx
.capabilities
= DMX_TS_FILTERING
;
850 client
->demux
.filternum
= 32; /* todo: nova ??? */
851 client
->demux
.feednum
= 32;
852 client
->demux
.start_feed
= smsdvb_start_feed
;
853 client
->demux
.stop_feed
= smsdvb_stop_feed
;
855 rc
= dvb_dmx_init(&client
->demux
);
857 sms_err("dvb_dmx_init failed %d", rc
);
862 client
->dmxdev
.filternum
= 32;
863 client
->dmxdev
.demux
= &client
->demux
.dmx
;
864 client
->dmxdev
.capabilities
= 0;
866 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
868 sms_err("dvb_dmxdev_init failed %d", rc
);
872 /* init and register frontend */
873 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
,
874 sizeof(struct dvb_frontend_ops
));
876 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
878 sms_err("frontend registration failed %d", rc
);
882 params
.initial_id
= 1;
883 params
.data_type
= MSG_SMS_DVBT_BDA_DATA
;
884 params
.onresponse_handler
= smsdvb_onresponse
;
885 params
.onremove_handler
= smsdvb_onremove
;
886 params
.context
= client
;
888 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
890 sms_err("smscore_register_client() failed %d", rc
);
894 client
->coredev
= coredev
;
896 init_completion(&client
->tune_done
);
898 kmutex_lock(&g_smsdvb_clientslock
);
900 list_add(&client
->entry
, &g_smsdvb_clients
);
902 kmutex_unlock(&g_smsdvb_clientslock
);
904 client
->event_fe_state
= -1;
905 client
->event_unc_state
= -1;
906 sms_board_dvb3_event(client
, DVB3_EVENT_HOTPLUG
);
909 sms_board_setup(coredev
);
914 dvb_unregister_frontend(&client
->frontend
);
917 dvb_dmxdev_release(&client
->dmxdev
);
920 dvb_dmx_release(&client
->demux
);
923 dvb_unregister_adapter(&client
->adapter
);
930 static int __init
smsdvb_module_init(void)
934 INIT_LIST_HEAD(&g_smsdvb_clients
);
935 kmutex_init(&g_smsdvb_clientslock
);
937 rc
= smscore_register_hotplug(smsdvb_hotplug
);
944 static void __exit
smsdvb_module_exit(void)
946 smscore_unregister_hotplug(smsdvb_hotplug
);
948 kmutex_lock(&g_smsdvb_clientslock
);
950 while (!list_empty(&g_smsdvb_clients
))
951 smsdvb_unregister_client(
952 (struct smsdvb_client_t
*) g_smsdvb_clients
.next
);
954 kmutex_unlock(&g_smsdvb_clientslock
);
957 module_init(smsdvb_module_init
);
958 module_exit(smsdvb_module_exit
);
960 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
961 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
962 MODULE_LICENSE("GPL");