Linux 2.6.34-rc3
[pohmelfs.git] / drivers / media / dvb / siano / smsdvb.c
blob5f3939821ca3eef3c786678cc91b9ef5ca326382
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>
25 #include "dmxdev.h"
26 #include "dvbdev.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;
44 struct dmxdev dmxdev;
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;
55 int event_fe_state;
56 int event_unc_state;
59 static struct list_head g_smsdvb_clients;
60 static struct mutex g_smsdvb_clientslock;
62 static int sms_dbg;
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;
71 switch (event) {
72 case DVB3_EVENT_INIT:
73 sms_debug("DVB3_EVENT_INIT");
74 sms_board_event(coredev, BOARD_EVENT_BIND);
75 break;
76 case DVB3_EVENT_SLEEP:
77 sms_debug("DVB3_EVENT_SLEEP");
78 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
79 break;
80 case DVB3_EVENT_HOTPLUG:
81 sms_debug("DVB3_EVENT_HOTPLUG");
82 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
83 break;
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);
90 break;
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);
97 break;
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);
104 break;
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);
111 break;
113 default:
114 sms_err("Unknown dvb3 api event");
115 break;
120 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
121 struct SMSHOSTLIB_STATISTICS_ST *p)
123 if (sms_dbg & 2) {
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)
180 int i;
182 if (sms_dbg & 2) {
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)
235 + cb->offset);
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));
246 break;
248 case MSG_SMS_RF_TUNE_RES:
249 case MSG_SMS_ISDBT_TUNE_RES:
250 complete(&client->tune_done);
251 break;
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;
257 break;
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;
263 break;
265 case MSG_SMS_TRANSMISSION_IND: {
266 sms_info("MSG_SMS_TRANSMISSION_IND");
268 pMsgData++;
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;
279 break;
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");*/
287 pMsgData++;
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];
313 /* TS PER */
314 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
315 > 0) {
316 pReceptionData->TS_PER = (SignalStatusData.etsPackets
317 * 100) / (SignalStatusData.tsPackets
318 + SignalStatusData.etsPackets);
319 } else {
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;
331 break;
333 case MSG_SMS_GET_STATISTICS_RES: {
334 union {
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);
349 break;
350 default:
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);
362 break;
364 default:
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
376 == 0)
377 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
378 else
379 sms_board_dvb3_event(client,
380 DVB3_EVENT_UNC_ERR);
382 } else {
383 if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
384 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
385 else
386 client->fe_status = 0;
387 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
391 return 0;
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);
405 kfree(client);
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)
463 int rc;
465 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
466 rc = smsclient_sendrequest(client->smsclient, buffer, size);
467 if (rc < 0)
468 return rc;
470 return wait_for_completion_timeout(completion,
471 msecs_to_jiffies(2000)) ?
472 0 : -ETIME;
475 static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
477 int rc;
478 struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
479 DVBT_BDA_CONTROL_MSG_ID,
480 HIF_TASK,
481 sizeof(struct SmsMsgHdr_ST), 0 };
483 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
484 &client->tune_done);
486 return rc;
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);
495 else
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)
501 int rc;
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);
511 return rc;
514 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
516 int rc;
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);
526 return rc;
529 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
531 int rc;
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)
539 *strength = 0;
540 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
541 *strength = 100;
542 else
543 *strength =
544 (client->sms_stat_dvb.ReceptionData.InBandPwr
545 + 95) * 3 / 2;
547 led_feedback(client);
549 return rc;
552 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
554 int rc;
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);
564 return rc;
567 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
569 int rc;
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);
579 return rc;
582 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
583 struct dvb_frontend_tune_settings *tune)
585 sms_debug("");
587 tune->min_delay_ms = 400;
588 tune->step_size = 250000;
589 tune->max_drift = 0;
590 return 0;
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);
600 struct {
601 struct SmsMsgHdr_ST Msg;
602 u32 Data[3];
603 } Msg;
605 int ret;
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,
621 c->bandwidth_hz);
623 switch (c->bandwidth_hz / 1000000) {
624 case 8:
625 Msg.Data[1] = BW_8_MHZ;
626 break;
627 case 7:
628 Msg.Data[1] = BW_7_MHZ;
629 break;
630 case 6:
631 Msg.Data[1] = BW_6_MHZ;
632 break;
633 case 0:
634 return -EOPNOTSUPP;
635 default:
636 return -EINVAL;
638 /* Disable LNA, if any. An error is returned if no LNA is present */
639 ret = sms_board_lna_control(client->coredev, 0);
640 if (ret == 0) {
641 fe_status_t status;
643 /* tune with LNA off at first */
644 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
645 &client->tune_done);
647 smsdvb_read_status(fe, &status);
649 if (status & FE_HAS_LOCK)
650 return ret;
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),
657 &client->tune_done);
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);
667 struct {
668 struct SmsMsgHdr_ST Msg;
669 u32 Data[4];
670 } 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) {
684 case 3:
685 Msg.Data[1] = BW_ISDBT_3SEG;
686 break;
687 case 1:
688 Msg.Data[1] = BW_ISDBT_1SEG;
689 break;
690 case 0: /* AUTO */
691 switch (c->bandwidth_hz / 1000000) {
692 case 8:
693 case 7:
694 c->isdbt_sb_segment_count = 3;
695 Msg.Data[1] = BW_ISDBT_3SEG;
696 break;
697 case 6:
698 c->isdbt_sb_segment_count = 1;
699 Msg.Data[1] = BW_ISDBT_1SEG;
700 break;
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;
705 break;
707 break;
708 default:
709 sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
710 return -EINVAL;
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),
722 &client->tune_done);
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);
739 default:
740 return -EINVAL;
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);
750 sms_debug("");
752 /* todo: */
753 memcpy(fep, &client->fe_params,
754 sizeof(struct dvb_frontend_parameters));
756 return 0;
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);
767 return 0;
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);
780 return 0;
783 static void smsdvb_release(struct dvb_frontend *fe)
785 /* do nothing */
788 static struct dvb_frontend_ops smsdvb_fe_ops = {
789 .info = {
790 .name = "Siano Mobile Digital MDTV Receiver",
791 .type = FE_OFDM,
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 |
801 FE_CAN_RECOVER |
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,
817 .init = smsdvb_init,
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;
826 int rc;
828 /* device removal handled by onremove callback */
829 if (!arrival)
830 return 0;
831 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
832 if (!client) {
833 sms_err("kmalloc() failed");
834 return -ENOMEM;
837 /* register dvb adapter */
838 rc = dvb_register_adapter(&client->adapter,
839 sms_get_board(
840 smscore_get_board_id(coredev))->name,
841 THIS_MODULE, device, adapter_nr);
842 if (rc < 0) {
843 sms_err("dvb_register_adapter() failed %d", rc);
844 goto adapter_error;
847 /* init dvb demux */
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);
855 if (rc < 0) {
856 sms_err("dvb_dmx_init failed %d", rc);
857 goto dvbdmx_error;
860 /* init dmxdev */
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);
866 if (rc < 0) {
867 sms_err("dvb_dmxdev_init failed %d", rc);
868 goto dmxdev_error;
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);
876 if (rc < 0) {
877 sms_err("frontend registration failed %d", rc);
878 goto frontend_error;
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, &params, &client->smsclient);
888 if (rc < 0) {
889 sms_err("smscore_register_client() failed %d", rc);
890 goto client_error;
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);
907 sms_info("success");
908 sms_board_setup(coredev);
910 return 0;
912 client_error:
913 dvb_unregister_frontend(&client->frontend);
915 frontend_error:
916 dvb_dmxdev_release(&client->dmxdev);
918 dmxdev_error:
919 dvb_dmx_release(&client->demux);
921 dvbdmx_error:
922 dvb_unregister_adapter(&client->adapter);
924 adapter_error:
925 kfree(client);
926 return rc;
929 static int __init smsdvb_module_init(void)
931 int rc;
933 INIT_LIST_HEAD(&g_smsdvb_clients);
934 kmutex_init(&g_smsdvb_clientslock);
936 rc = smscore_register_hotplug(smsdvb_hotplug);
938 sms_debug("");
940 return rc;
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");