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/init.h>
27 #include "dvb_demux.h"
28 #include "dvb_frontend.h"
30 #include "smscoreapi.h"
31 #include "smsendian.h"
32 #include "sms-cards.h"
34 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr
);
36 struct smsdvb_client_t
{
37 struct list_head entry
;
39 struct smscore_device_t
*coredev
;
40 struct smscore_client_t
*smsclient
;
42 struct dvb_adapter adapter
;
43 struct dvb_demux demux
;
45 struct dvb_frontend frontend
;
47 fe_status_t fe_status
;
49 struct completion tune_done
;
51 /* todo: save freq/band instead whole struct */
52 struct dvb_frontend_parameters fe_params
;
54 struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb
;
59 static struct list_head g_smsdvb_clients
;
60 static struct mutex g_smsdvb_clientslock
;
63 module_param_named(debug
, sms_dbg
, int, 0644);
64 MODULE_PARM_DESC(debug
, "set debug level (info=1, adv=2 (or-able))");
66 /* Events that may come from DVB v3 adapter */
67 static void sms_board_dvb3_event(struct smsdvb_client_t
*client
,
68 enum SMS_DVB3_EVENTS event
) {
70 struct smscore_device_t
*coredev
= client
->coredev
;
73 sms_debug("DVB3_EVENT_INIT");
74 sms_board_event(coredev
, BOARD_EVENT_BIND
);
76 case DVB3_EVENT_SLEEP
:
77 sms_debug("DVB3_EVENT_SLEEP");
78 sms_board_event(coredev
, BOARD_EVENT_POWER_SUSPEND
);
80 case DVB3_EVENT_HOTPLUG
:
81 sms_debug("DVB3_EVENT_HOTPLUG");
82 sms_board_event(coredev
, BOARD_EVENT_POWER_INIT
);
84 case DVB3_EVENT_FE_LOCK
:
85 if (client
->event_fe_state
!= DVB3_EVENT_FE_LOCK
) {
86 client
->event_fe_state
= DVB3_EVENT_FE_LOCK
;
87 sms_debug("DVB3_EVENT_FE_LOCK");
88 sms_board_event(coredev
, BOARD_EVENT_FE_LOCK
);
91 case DVB3_EVENT_FE_UNLOCK
:
92 if (client
->event_fe_state
!= DVB3_EVENT_FE_UNLOCK
) {
93 client
->event_fe_state
= DVB3_EVENT_FE_UNLOCK
;
94 sms_debug("DVB3_EVENT_FE_UNLOCK");
95 sms_board_event(coredev
, BOARD_EVENT_FE_UNLOCK
);
98 case DVB3_EVENT_UNC_OK
:
99 if (client
->event_unc_state
!= DVB3_EVENT_UNC_OK
) {
100 client
->event_unc_state
= DVB3_EVENT_UNC_OK
;
101 sms_debug("DVB3_EVENT_UNC_OK");
102 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_OK
);
105 case DVB3_EVENT_UNC_ERR
:
106 if (client
->event_unc_state
!= DVB3_EVENT_UNC_ERR
) {
107 client
->event_unc_state
= DVB3_EVENT_UNC_ERR
;
108 sms_debug("DVB3_EVENT_UNC_ERR");
109 sms_board_event(coredev
, BOARD_EVENT_MULTIPLEX_ERRORS
);
114 sms_err("Unknown dvb3 api event");
120 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
121 struct SMSHOSTLIB_STATISTICS_ST
*p
)
124 printk(KERN_DEBUG
"Reserved = %d", p
->Reserved
);
125 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
126 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
127 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
128 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
129 printk(KERN_DEBUG
"BER = %d", p
->BER
);
130 printk(KERN_DEBUG
"FIB_CRC = %d", p
->FIB_CRC
);
131 printk(KERN_DEBUG
"TS_PER = %d", p
->TS_PER
);
132 printk(KERN_DEBUG
"MFER = %d", p
->MFER
);
133 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
134 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
135 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
136 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
137 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
138 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
139 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
140 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
141 printk(KERN_DEBUG
"CodeRate = %d", p
->CodeRate
);
142 printk(KERN_DEBUG
"LPCodeRate = %d", p
->LPCodeRate
);
143 printk(KERN_DEBUG
"Hierarchy = %d", p
->Hierarchy
);
144 printk(KERN_DEBUG
"Constellation = %d", p
->Constellation
);
145 printk(KERN_DEBUG
"BurstSize = %d", p
->BurstSize
);
146 printk(KERN_DEBUG
"BurstDuration = %d", p
->BurstDuration
);
147 printk(KERN_DEBUG
"BurstCycleTime = %d", p
->BurstCycleTime
);
148 printk(KERN_DEBUG
"CalculatedBurstCycleTime = %d", p
->CalculatedBurstCycleTime
);
149 printk(KERN_DEBUG
"NumOfRows = %d", p
->NumOfRows
);
150 printk(KERN_DEBUG
"NumOfPaddCols = %d", p
->NumOfPaddCols
);
151 printk(KERN_DEBUG
"NumOfPunctCols = %d", p
->NumOfPunctCols
);
152 printk(KERN_DEBUG
"ErrorTSPackets = %d", p
->ErrorTSPackets
);
153 printk(KERN_DEBUG
"TotalTSPackets = %d", p
->TotalTSPackets
);
154 printk(KERN_DEBUG
"NumOfValidMpeTlbs = %d", p
->NumOfValidMpeTlbs
);
155 printk(KERN_DEBUG
"NumOfInvalidMpeTlbs = %d", p
->NumOfInvalidMpeTlbs
);
156 printk(KERN_DEBUG
"NumOfCorrectedMpeTlbs = %d", p
->NumOfCorrectedMpeTlbs
);
157 printk(KERN_DEBUG
"BERErrorCount = %d", p
->BERErrorCount
);
158 printk(KERN_DEBUG
"BERBitCount = %d", p
->BERBitCount
);
159 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
160 printk(KERN_DEBUG
"PreBER = %d", p
->PreBER
);
161 printk(KERN_DEBUG
"CellId = %d", p
->CellId
);
162 printk(KERN_DEBUG
"DvbhSrvIndHP = %d", p
->DvbhSrvIndHP
);
163 printk(KERN_DEBUG
"DvbhSrvIndLP = %d", p
->DvbhSrvIndLP
);
164 printk(KERN_DEBUG
"NumMPEReceived = %d", p
->NumMPEReceived
);
167 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
169 pReceptionData
->SNR
= p
->SNR
;
170 pReceptionData
->BER
= p
->BER
;
171 pReceptionData
->BERErrorCount
= p
->BERErrorCount
;
172 pReceptionData
->InBandPwr
= p
->InBandPwr
;
173 pReceptionData
->ErrorTSPackets
= p
->ErrorTSPackets
;
177 static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S
*pReceptionData
,
178 struct SMSHOSTLIB_STATISTICS_ISDBT_ST
*p
)
183 printk(KERN_DEBUG
"IsRfLocked = %d", p
->IsRfLocked
);
184 printk(KERN_DEBUG
"IsDemodLocked = %d", p
->IsDemodLocked
);
185 printk(KERN_DEBUG
"IsExternalLNAOn = %d", p
->IsExternalLNAOn
);
186 printk(KERN_DEBUG
"SNR = %d", p
->SNR
);
187 printk(KERN_DEBUG
"RSSI = %d", p
->RSSI
);
188 printk(KERN_DEBUG
"InBandPwr = %d", p
->InBandPwr
);
189 printk(KERN_DEBUG
"CarrierOffset = %d", p
->CarrierOffset
);
190 printk(KERN_DEBUG
"Frequency = %d", p
->Frequency
);
191 printk(KERN_DEBUG
"Bandwidth = %d", p
->Bandwidth
);
192 printk(KERN_DEBUG
"TransmissionMode = %d", p
->TransmissionMode
);
193 printk(KERN_DEBUG
"ModemState = %d", p
->ModemState
);
194 printk(KERN_DEBUG
"GuardInterval = %d", p
->GuardInterval
);
195 printk(KERN_DEBUG
"SystemType = %d", p
->SystemType
);
196 printk(KERN_DEBUG
"PartialReception = %d", p
->PartialReception
);
197 printk(KERN_DEBUG
"NumOfLayers = %d", p
->NumOfLayers
);
198 printk(KERN_DEBUG
"SmsToHostTxErrors = %d", p
->SmsToHostTxErrors
);
200 for (i
= 0; i
< 3; i
++) {
201 printk(KERN_DEBUG
"%d: CodeRate = %d", i
, p
->LayerInfo
[i
].CodeRate
);
202 printk(KERN_DEBUG
"%d: Constellation = %d", i
, p
->LayerInfo
[i
].Constellation
);
203 printk(KERN_DEBUG
"%d: BER = %d", i
, p
->LayerInfo
[i
].BER
);
204 printk(KERN_DEBUG
"%d: BERErrorCount = %d", i
, p
->LayerInfo
[i
].BERErrorCount
);
205 printk(KERN_DEBUG
"%d: BERBitCount = %d", i
, p
->LayerInfo
[i
].BERBitCount
);
206 printk(KERN_DEBUG
"%d: PreBER = %d", i
, p
->LayerInfo
[i
].PreBER
);
207 printk(KERN_DEBUG
"%d: TS_PER = %d", i
, p
->LayerInfo
[i
].TS_PER
);
208 printk(KERN_DEBUG
"%d: ErrorTSPackets = %d", i
, p
->LayerInfo
[i
].ErrorTSPackets
);
209 printk(KERN_DEBUG
"%d: TotalTSPackets = %d", i
, p
->LayerInfo
[i
].TotalTSPackets
);
210 printk(KERN_DEBUG
"%d: TILdepthI = %d", i
, p
->LayerInfo
[i
].TILdepthI
);
211 printk(KERN_DEBUG
"%d: NumberOfSegments = %d", i
, p
->LayerInfo
[i
].NumberOfSegments
);
212 printk(KERN_DEBUG
"%d: TMCCErrors = %d", i
, p
->LayerInfo
[i
].TMCCErrors
);
216 pReceptionData
->IsDemodLocked
= p
->IsDemodLocked
;
218 pReceptionData
->SNR
= p
->SNR
;
219 pReceptionData
->InBandPwr
= p
->InBandPwr
;
221 pReceptionData
->ErrorTSPackets
= 0;
222 pReceptionData
->BER
= 0;
223 pReceptionData
->BERErrorCount
= 0;
224 for (i
= 0; i
< 3; i
++) {
225 pReceptionData
->BER
+= p
->LayerInfo
[i
].BER
;
226 pReceptionData
->BERErrorCount
+= p
->LayerInfo
[i
].BERErrorCount
;
227 pReceptionData
->ErrorTSPackets
+= p
->LayerInfo
[i
].ErrorTSPackets
;
231 static int smsdvb_onresponse(void *context
, struct smscore_buffer_t
*cb
)
233 struct smsdvb_client_t
*client
= (struct smsdvb_client_t
*) context
;
234 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) (((u8
*) cb
->p
)
236 u32
*pMsgData
= (u32
*) phdr
+ 1;
237 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
238 bool is_status_update
= false;
240 smsendian_handle_rx_message((struct SmsMsgData_ST
*) phdr
);
242 switch (phdr
->msgType
) {
243 case MSG_SMS_DVBT_BDA_DATA
:
244 dvb_dmx_swfilter(&client
->demux
, (u8
*)(phdr
+ 1),
245 cb
->size
- sizeof(struct SmsMsgHdr_ST
));
248 case MSG_SMS_RF_TUNE_RES
:
249 case MSG_SMS_ISDBT_TUNE_RES
:
250 complete(&client
->tune_done
);
253 case MSG_SMS_SIGNAL_DETECTED_IND
:
254 sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
255 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= true;
256 is_status_update
= true;
259 case MSG_SMS_NO_SIGNAL_IND
:
260 sms_info("MSG_SMS_NO_SIGNAL_IND");
261 client
->sms_stat_dvb
.TransmissionData
.IsDemodLocked
= false;
262 is_status_update
= true;
265 case MSG_SMS_TRANSMISSION_IND
: {
266 sms_info("MSG_SMS_TRANSMISSION_IND");
269 memcpy(&client
->sms_stat_dvb
.TransmissionData
, pMsgData
,
270 sizeof(struct TRANSMISSION_STATISTICS_S
));
272 /* Mo need to correct guard interval
273 * (as opposed to old statistics message).
275 CORRECT_STAT_BANDWIDTH(client
->sms_stat_dvb
.TransmissionData
);
276 CORRECT_STAT_TRANSMISSON_MODE(
277 client
->sms_stat_dvb
.TransmissionData
);
278 is_status_update
= true;
281 case MSG_SMS_HO_PER_SLICES_IND
: {
282 struct RECEPTION_STATISTICS_S
*pReceptionData
=
283 &client
->sms_stat_dvb
.ReceptionData
;
284 struct SRVM_SIGNAL_STATUS_S SignalStatusData
;
286 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
288 SignalStatusData
.result
= pMsgData
[0];
289 SignalStatusData
.snr
= pMsgData
[1];
290 SignalStatusData
.inBandPower
= (s32
) pMsgData
[2];
291 SignalStatusData
.tsPackets
= pMsgData
[3];
292 SignalStatusData
.etsPackets
= pMsgData
[4];
293 SignalStatusData
.constellation
= pMsgData
[5];
294 SignalStatusData
.hpCode
= pMsgData
[6];
295 SignalStatusData
.tpsSrvIndLP
= pMsgData
[7] & 0x03;
296 SignalStatusData
.tpsSrvIndHP
= pMsgData
[8] & 0x03;
297 SignalStatusData
.cellId
= pMsgData
[9] & 0xFFFF;
298 SignalStatusData
.reason
= pMsgData
[10];
299 SignalStatusData
.requestId
= pMsgData
[11];
300 pReceptionData
->IsRfLocked
= pMsgData
[16];
301 pReceptionData
->IsDemodLocked
= pMsgData
[17];
302 pReceptionData
->ModemState
= pMsgData
[12];
303 pReceptionData
->SNR
= pMsgData
[1];
304 pReceptionData
->BER
= pMsgData
[13];
305 pReceptionData
->RSSI
= pMsgData
[14];
306 CORRECT_STAT_RSSI(client
->sms_stat_dvb
.ReceptionData
);
308 pReceptionData
->InBandPwr
= (s32
) pMsgData
[2];
309 pReceptionData
->CarrierOffset
= (s32
) pMsgData
[15];
310 pReceptionData
->TotalTSPackets
= pMsgData
[3];
311 pReceptionData
->ErrorTSPackets
= pMsgData
[4];
314 if ((SignalStatusData
.tsPackets
+ SignalStatusData
.etsPackets
)
316 pReceptionData
->TS_PER
= (SignalStatusData
.etsPackets
317 * 100) / (SignalStatusData
.tsPackets
318 + SignalStatusData
.etsPackets
);
320 pReceptionData
->TS_PER
= 0;
323 pReceptionData
->BERBitCount
= pMsgData
[18];
324 pReceptionData
->BERErrorCount
= pMsgData
[19];
326 pReceptionData
->MRC_SNR
= pMsgData
[20];
327 pReceptionData
->MRC_InBandPwr
= pMsgData
[21];
328 pReceptionData
->MRC_RSSI
= pMsgData
[22];
330 is_status_update
= true;
333 case MSG_SMS_GET_STATISTICS_RES
: {
335 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt
;
336 struct SmsMsgStatisticsInfo_ST dvb
;
337 } *p
= (void *) (phdr
+ 1);
338 struct RECEPTION_STATISTICS_S
*pReceptionData
=
339 &client
->sms_stat_dvb
.ReceptionData
;
341 sms_info("MSG_SMS_GET_STATISTICS_RES");
343 is_status_update
= true;
345 switch (smscore_get_device_mode(client
->coredev
)) {
346 case DEVICE_MODE_ISDBT
:
347 case DEVICE_MODE_ISDBT_BDA
:
348 smsdvb_update_isdbt_stats(pReceptionData
, &p
->isdbt
);
351 smsdvb_update_dvb_stats(pReceptionData
, &p
->dvb
.Stat
);
353 if (!pReceptionData
->IsDemodLocked
) {
354 pReceptionData
->SNR
= 0;
355 pReceptionData
->BER
= 0;
356 pReceptionData
->BERErrorCount
= 0;
357 pReceptionData
->InBandPwr
= 0;
358 pReceptionData
->ErrorTSPackets
= 0;
361 complete(&client
->tune_done
);
365 sms_info("Unhandled message %d", phdr
->msgType
);
368 smscore_putbuffer(client
->coredev
, cb
);
370 if (is_status_update
) {
371 if (client
->sms_stat_dvb
.ReceptionData
.IsDemodLocked
) {
372 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
373 | FE_HAS_VITERBI
| FE_HAS_SYNC
| FE_HAS_LOCK
;
374 sms_board_dvb3_event(client
, DVB3_EVENT_FE_LOCK
);
375 if (client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
377 sms_board_dvb3_event(client
, DVB3_EVENT_UNC_OK
);
379 sms_board_dvb3_event(client
,
383 if (client
->sms_stat_dvb
.ReceptionData
.IsRfLocked
)
384 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
386 client
->fe_status
= 0;
387 sms_board_dvb3_event(client
, DVB3_EVENT_FE_UNLOCK
);
394 static void smsdvb_unregister_client(struct smsdvb_client_t
*client
)
396 /* must be called under clientslock */
398 list_del(&client
->entry
);
400 smscore_unregister_client(client
->smsclient
);
401 dvb_unregister_frontend(&client
->frontend
);
402 dvb_dmxdev_release(&client
->dmxdev
);
403 dvb_dmx_release(&client
->demux
);
404 dvb_unregister_adapter(&client
->adapter
);
408 static void smsdvb_onremove(void *context
)
410 kmutex_lock(&g_smsdvb_clientslock
);
412 smsdvb_unregister_client((struct smsdvb_client_t
*) context
);
414 kmutex_unlock(&g_smsdvb_clientslock
);
417 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
419 struct smsdvb_client_t
*client
=
420 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
421 struct SmsMsgData_ST PidMsg
;
423 sms_debug("add pid %d(%x)",
424 feed
->pid
, feed
->pid
);
426 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
427 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
428 PidMsg
.xMsgHeader
.msgFlags
= 0;
429 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_ADD_PID_FILTER_REQ
;
430 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
431 PidMsg
.msgData
[0] = feed
->pid
;
433 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
434 return smsclient_sendrequest(client
->smsclient
,
435 &PidMsg
, sizeof(PidMsg
));
438 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
440 struct smsdvb_client_t
*client
=
441 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
442 struct SmsMsgData_ST PidMsg
;
444 sms_debug("remove pid %d(%x)",
445 feed
->pid
, feed
->pid
);
447 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
448 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
449 PidMsg
.xMsgHeader
.msgFlags
= 0;
450 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_REMOVE_PID_FILTER_REQ
;
451 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
452 PidMsg
.msgData
[0] = feed
->pid
;
454 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)&PidMsg
);
455 return smsclient_sendrequest(client
->smsclient
,
456 &PidMsg
, sizeof(PidMsg
));
459 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t
*client
,
460 void *buffer
, size_t size
,
461 struct completion
*completion
)
465 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)buffer
);
466 rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
470 return wait_for_completion_timeout(completion
,
471 msecs_to_jiffies(2000)) ?
475 static int smsdvb_send_statistics_request(struct smsdvb_client_t
*client
)
478 struct SmsMsgHdr_ST Msg
= { MSG_SMS_GET_STATISTICS_REQ
,
479 DVBT_BDA_CONTROL_MSG_ID
,
481 sizeof(struct SmsMsgHdr_ST
), 0 };
483 rc
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
489 static inline int led_feedback(struct smsdvb_client_t
*client
)
491 if (client
->fe_status
& FE_HAS_LOCK
)
492 return sms_board_led_feedback(client
->coredev
,
493 (client
->sms_stat_dvb
.ReceptionData
.BER
494 == 0) ? SMS_LED_HI
: SMS_LED_LO
);
496 return sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
499 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
502 struct smsdvb_client_t
*client
;
503 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
505 rc
= smsdvb_send_statistics_request(client
);
507 *stat
= client
->fe_status
;
509 led_feedback(client
);
514 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
517 struct smsdvb_client_t
*client
;
518 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
520 rc
= smsdvb_send_statistics_request(client
);
522 *ber
= client
->sms_stat_dvb
.ReceptionData
.BER
;
524 led_feedback(client
);
529 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
533 struct smsdvb_client_t
*client
;
534 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
536 rc
= smsdvb_send_statistics_request(client
);
538 if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
< -95)
540 else if (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
> -29)
544 (client
->sms_stat_dvb
.ReceptionData
.InBandPwr
547 led_feedback(client
);
552 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
555 struct smsdvb_client_t
*client
;
556 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
558 rc
= smsdvb_send_statistics_request(client
);
560 *snr
= client
->sms_stat_dvb
.ReceptionData
.SNR
;
562 led_feedback(client
);
567 static int smsdvb_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
570 struct smsdvb_client_t
*client
;
571 client
= container_of(fe
, struct smsdvb_client_t
, frontend
);
573 rc
= smsdvb_send_statistics_request(client
);
575 *ucblocks
= client
->sms_stat_dvb
.ReceptionData
.ErrorTSPackets
;
577 led_feedback(client
);
582 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
,
583 struct dvb_frontend_tune_settings
*tune
)
587 tune
->min_delay_ms
= 400;
588 tune
->step_size
= 250000;
593 static int smsdvb_dvbt_set_frontend(struct dvb_frontend
*fe
,
594 struct dvb_frontend_parameters
*p
)
596 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
597 struct smsdvb_client_t
*client
=
598 container_of(fe
, struct smsdvb_client_t
, frontend
);
601 struct SmsMsgHdr_ST Msg
;
607 client
->fe_status
= FE_HAS_SIGNAL
;
608 client
->event_fe_state
= -1;
609 client
->event_unc_state
= -1;
610 fe
->dtv_property_cache
.delivery_system
= SYS_DVBT
;
612 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
613 Msg
.Msg
.msgDstId
= HIF_TASK
;
614 Msg
.Msg
.msgFlags
= 0;
615 Msg
.Msg
.msgType
= MSG_SMS_RF_TUNE_REQ
;
616 Msg
.Msg
.msgLength
= sizeof(Msg
);
617 Msg
.Data
[0] = c
->frequency
;
618 Msg
.Data
[2] = 12000000;
620 sms_info("%s: freq %d band %d", __func__
, c
->frequency
,
623 switch (c
->bandwidth_hz
/ 1000000) {
625 Msg
.Data
[1] = BW_8_MHZ
;
628 Msg
.Data
[1] = BW_7_MHZ
;
631 Msg
.Data
[1] = BW_6_MHZ
;
638 /* Disable LNA, if any. An error is returned if no LNA is present */
639 ret
= sms_board_lna_control(client
->coredev
, 0);
643 /* tune with LNA off at first */
644 ret
= smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
647 smsdvb_read_status(fe
, &status
);
649 if (status
& FE_HAS_LOCK
)
652 /* previous tune didnt lock - enable LNA and tune again */
653 sms_board_lna_control(client
->coredev
, 1);
656 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
660 static int smsdvb_isdbt_set_frontend(struct dvb_frontend
*fe
,
661 struct dvb_frontend_parameters
*p
)
663 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
664 struct smsdvb_client_t
*client
=
665 container_of(fe
, struct smsdvb_client_t
, frontend
);
668 struct SmsMsgHdr_ST Msg
;
672 fe
->dtv_property_cache
.delivery_system
= SYS_ISDBT
;
674 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
675 Msg
.Msg
.msgDstId
= HIF_TASK
;
676 Msg
.Msg
.msgFlags
= 0;
677 Msg
.Msg
.msgType
= MSG_SMS_ISDBT_TUNE_REQ
;
678 Msg
.Msg
.msgLength
= sizeof(Msg
);
680 if (c
->isdbt_sb_segment_idx
== -1)
681 c
->isdbt_sb_segment_idx
= 0;
683 switch (c
->isdbt_sb_segment_count
) {
685 Msg
.Data
[1] = BW_ISDBT_3SEG
;
688 Msg
.Data
[1] = BW_ISDBT_1SEG
;
691 switch (c
->bandwidth_hz
/ 1000000) {
694 c
->isdbt_sb_segment_count
= 3;
695 Msg
.Data
[1] = BW_ISDBT_3SEG
;
698 c
->isdbt_sb_segment_count
= 1;
699 Msg
.Data
[1] = BW_ISDBT_1SEG
;
701 default: /* Assumes 6 MHZ bw */
702 c
->isdbt_sb_segment_count
= 1;
703 c
->bandwidth_hz
= 6000;
704 Msg
.Data
[1] = BW_ISDBT_1SEG
;
709 sms_info("Segment count %d not supported", c
->isdbt_sb_segment_count
);
713 Msg
.Data
[0] = c
->frequency
;
714 Msg
.Data
[2] = 12000000;
715 Msg
.Data
[3] = c
->isdbt_sb_segment_idx
;
717 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__
,
718 c
->frequency
, c
->isdbt_sb_segment_count
,
719 c
->isdbt_sb_segment_idx
);
721 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
725 static int smsdvb_set_frontend(struct dvb_frontend
*fe
,
726 struct dvb_frontend_parameters
*fep
)
728 struct smsdvb_client_t
*client
=
729 container_of(fe
, struct smsdvb_client_t
, frontend
);
730 struct smscore_device_t
*coredev
= client
->coredev
;
732 switch (smscore_get_device_mode(coredev
)) {
733 case DEVICE_MODE_DVBT
:
734 case DEVICE_MODE_DVBT_BDA
:
735 return smsdvb_dvbt_set_frontend(fe
, fep
);
736 case DEVICE_MODE_ISDBT
:
737 case DEVICE_MODE_ISDBT_BDA
:
738 return smsdvb_isdbt_set_frontend(fe
, fep
);
744 static int smsdvb_get_frontend(struct dvb_frontend
*fe
,
745 struct dvb_frontend_parameters
*fep
)
747 struct smsdvb_client_t
*client
=
748 container_of(fe
, struct smsdvb_client_t
, frontend
);
753 memcpy(fep
, &client
->fe_params
,
754 sizeof(struct dvb_frontend_parameters
));
759 static int smsdvb_init(struct dvb_frontend
*fe
)
761 struct smsdvb_client_t
*client
=
762 container_of(fe
, struct smsdvb_client_t
, frontend
);
764 sms_board_power(client
->coredev
, 1);
766 sms_board_dvb3_event(client
, DVB3_EVENT_INIT
);
770 static int smsdvb_sleep(struct dvb_frontend
*fe
)
772 struct smsdvb_client_t
*client
=
773 container_of(fe
, struct smsdvb_client_t
, frontend
);
775 sms_board_led_feedback(client
->coredev
, SMS_LED_OFF
);
776 sms_board_power(client
->coredev
, 0);
778 sms_board_dvb3_event(client
, DVB3_EVENT_SLEEP
);
783 static void smsdvb_release(struct dvb_frontend
*fe
)
788 static struct dvb_frontend_ops smsdvb_fe_ops
= {
790 .name
= "Siano Mobile Digital MDTV Receiver",
792 .frequency_min
= 44250000,
793 .frequency_max
= 867250000,
794 .frequency_stepsize
= 250000,
795 .caps
= FE_CAN_INVERSION_AUTO
|
796 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
797 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
798 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
|
799 FE_CAN_QAM_AUTO
| FE_CAN_TRANSMISSION_MODE_AUTO
|
800 FE_CAN_GUARD_INTERVAL_AUTO
|
802 FE_CAN_HIERARCHY_AUTO
,
805 .release
= smsdvb_release
,
807 .set_frontend
= smsdvb_set_frontend
,
808 .get_frontend
= smsdvb_get_frontend
,
809 .get_tune_settings
= smsdvb_get_tune_settings
,
811 .read_status
= smsdvb_read_status
,
812 .read_ber
= smsdvb_read_ber
,
813 .read_signal_strength
= smsdvb_read_signal_strength
,
814 .read_snr
= smsdvb_read_snr
,
815 .read_ucblocks
= smsdvb_read_ucblocks
,
818 .sleep
= smsdvb_sleep
,
821 static int smsdvb_hotplug(struct smscore_device_t
*coredev
,
822 struct device
*device
, int arrival
)
824 struct smsclient_params_t params
;
825 struct smsdvb_client_t
*client
;
828 /* device removal handled by onremove callback */
831 client
= kzalloc(sizeof(struct smsdvb_client_t
), GFP_KERNEL
);
833 sms_err("kmalloc() failed");
837 /* register dvb adapter */
838 rc
= dvb_register_adapter(&client
->adapter
,
840 smscore_get_board_id(coredev
))->name
,
841 THIS_MODULE
, device
, adapter_nr
);
843 sms_err("dvb_register_adapter() failed %d", rc
);
848 client
->demux
.dmx
.capabilities
= DMX_TS_FILTERING
;
849 client
->demux
.filternum
= 32; /* todo: nova ??? */
850 client
->demux
.feednum
= 32;
851 client
->demux
.start_feed
= smsdvb_start_feed
;
852 client
->demux
.stop_feed
= smsdvb_stop_feed
;
854 rc
= dvb_dmx_init(&client
->demux
);
856 sms_err("dvb_dmx_init failed %d", rc
);
861 client
->dmxdev
.filternum
= 32;
862 client
->dmxdev
.demux
= &client
->demux
.dmx
;
863 client
->dmxdev
.capabilities
= 0;
865 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
867 sms_err("dvb_dmxdev_init failed %d", rc
);
871 /* init and register frontend */
872 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
,
873 sizeof(struct dvb_frontend_ops
));
875 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
877 sms_err("frontend registration failed %d", rc
);
881 params
.initial_id
= 1;
882 params
.data_type
= MSG_SMS_DVBT_BDA_DATA
;
883 params
.onresponse_handler
= smsdvb_onresponse
;
884 params
.onremove_handler
= smsdvb_onremove
;
885 params
.context
= client
;
887 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
889 sms_err("smscore_register_client() failed %d", rc
);
893 client
->coredev
= coredev
;
895 init_completion(&client
->tune_done
);
897 kmutex_lock(&g_smsdvb_clientslock
);
899 list_add(&client
->entry
, &g_smsdvb_clients
);
901 kmutex_unlock(&g_smsdvb_clientslock
);
903 client
->event_fe_state
= -1;
904 client
->event_unc_state
= -1;
905 sms_board_dvb3_event(client
, DVB3_EVENT_HOTPLUG
);
908 sms_board_setup(coredev
);
913 dvb_unregister_frontend(&client
->frontend
);
916 dvb_dmxdev_release(&client
->dmxdev
);
919 dvb_dmx_release(&client
->demux
);
922 dvb_unregister_adapter(&client
->adapter
);
929 static int __init
smsdvb_module_init(void)
933 INIT_LIST_HEAD(&g_smsdvb_clients
);
934 kmutex_init(&g_smsdvb_clientslock
);
936 rc
= smscore_register_hotplug(smsdvb_hotplug
);
943 static void __exit
smsdvb_module_exit(void)
945 smscore_unregister_hotplug(smsdvb_hotplug
);
947 kmutex_lock(&g_smsdvb_clientslock
);
949 while (!list_empty(&g_smsdvb_clients
))
950 smsdvb_unregister_client(
951 (struct smsdvb_client_t
*) g_smsdvb_clients
.next
);
953 kmutex_unlock(&g_smsdvb_clientslock
);
956 module_init(smsdvb_module_init
);
957 module_exit(smsdvb_module_exit
);
959 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
960 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
961 MODULE_LICENSE("GPL");