[media] siano: apply debug flag to module level
[pohmelfs.git] / drivers / media / dvb / siano / smsdvb.c
blobb1f4911e835972c1c3b866cfb66661211b45168b
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>
26 #include "dmxdev.h"
27 #include "dvbdev.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;
45 struct dmxdev dmxdev;
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;
56 int event_fe_state;
57 int event_unc_state;
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;
68 switch (event) {
69 case DVB3_EVENT_INIT:
70 sms_debug("DVB3_EVENT_INIT");
71 sms_board_event(coredev, BOARD_EVENT_BIND);
72 break;
73 case DVB3_EVENT_SLEEP:
74 sms_debug("DVB3_EVENT_SLEEP");
75 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
76 break;
77 case DVB3_EVENT_HOTPLUG:
78 sms_debug("DVB3_EVENT_HOTPLUG");
79 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
80 break;
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);
87 break;
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);
94 break;
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);
101 break;
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);
108 break;
110 default:
111 sms_err("Unknown dvb3 api event");
112 break;
117 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
118 struct SMSHOSTLIB_STATISTICS_ST *p)
120 if (sms_dbg & 2) {
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)
177 int i;
179 if (sms_dbg & 2) {
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)
232 + cb->offset);
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));
243 break;
245 case MSG_SMS_RF_TUNE_RES:
246 case MSG_SMS_ISDBT_TUNE_RES:
247 complete(&client->tune_done);
248 break;
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;
254 break;
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;
260 break;
262 case MSG_SMS_TRANSMISSION_IND: {
263 sms_info("MSG_SMS_TRANSMISSION_IND");
265 pMsgData++;
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;
276 break;
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");*/
284 pMsgData++;
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];
310 /* TS PER */
311 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
312 > 0) {
313 pReceptionData->TS_PER = (SignalStatusData.etsPackets
314 * 100) / (SignalStatusData.tsPackets
315 + SignalStatusData.etsPackets);
316 } else {
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;
328 break;
330 case MSG_SMS_GET_STATISTICS_RES: {
331 union {
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);
346 break;
347 default:
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);
359 break;
361 default:
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
373 == 0)
374 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
375 else
376 sms_board_dvb3_event(client,
377 DVB3_EVENT_UNC_ERR);
379 } else {
380 if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
381 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
382 else
383 client->fe_status = 0;
384 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
388 return 0;
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);
402 kfree(client);
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)
460 int rc;
462 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
463 rc = smsclient_sendrequest(client->smsclient, buffer, size);
464 if (rc < 0)
465 return rc;
467 return wait_for_completion_timeout(completion,
468 msecs_to_jiffies(2000)) ?
469 0 : -ETIME;
472 static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
474 int rc;
475 struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
476 DVBT_BDA_CONTROL_MSG_ID,
477 HIF_TASK,
478 sizeof(struct SmsMsgHdr_ST), 0 };
480 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
481 &client->tune_done);
483 return rc;
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);
492 else
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)
498 int rc;
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);
508 return rc;
511 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
513 int rc;
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);
523 return rc;
526 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
528 int rc;
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)
536 *strength = 0;
537 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
538 *strength = 100;
539 else
540 *strength =
541 (client->sms_stat_dvb.ReceptionData.InBandPwr
542 + 95) * 3 / 2;
544 led_feedback(client);
546 return rc;
549 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
551 int rc;
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);
561 return rc;
564 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
566 int rc;
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);
576 return rc;
579 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
580 struct dvb_frontend_tune_settings *tune)
582 sms_debug("");
584 tune->min_delay_ms = 400;
585 tune->step_size = 250000;
586 tune->max_drift = 0;
587 return 0;
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);
597 struct {
598 struct SmsMsgHdr_ST Msg;
599 u32 Data[3];
600 } Msg;
602 int ret;
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,
618 c->bandwidth_hz);
620 switch (c->bandwidth_hz / 1000000) {
621 case 8:
622 Msg.Data[1] = BW_8_MHZ;
623 break;
624 case 7:
625 Msg.Data[1] = BW_7_MHZ;
626 break;
627 case 6:
628 Msg.Data[1] = BW_6_MHZ;
629 break;
630 case 0:
631 return -EOPNOTSUPP;
632 default:
633 return -EINVAL;
635 /* Disable LNA, if any. An error is returned if no LNA is present */
636 ret = sms_board_lna_control(client->coredev, 0);
637 if (ret == 0) {
638 fe_status_t status;
640 /* tune with LNA off at first */
641 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
642 &client->tune_done);
644 smsdvb_read_status(fe, &status);
646 if (status & FE_HAS_LOCK)
647 return ret;
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),
654 &client->tune_done);
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);
664 struct {
665 struct SmsMsgHdr_ST Msg;
666 u32 Data[4];
667 } 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) {
681 case 3:
682 Msg.Data[1] = BW_ISDBT_3SEG;
683 break;
684 case 1:
685 Msg.Data[1] = BW_ISDBT_1SEG;
686 break;
687 case 0: /* AUTO */
688 switch (c->bandwidth_hz / 1000000) {
689 case 8:
690 case 7:
691 c->isdbt_sb_segment_count = 3;
692 Msg.Data[1] = BW_ISDBT_3SEG;
693 break;
694 case 6:
695 c->isdbt_sb_segment_count = 1;
696 Msg.Data[1] = BW_ISDBT_1SEG;
697 break;
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;
702 break;
704 break;
705 default:
706 sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
707 return -EINVAL;
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),
719 &client->tune_done);
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);
736 default:
737 return -EINVAL;
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);
747 sms_debug("");
749 /* todo: */
750 memcpy(fep, &client->fe_params,
751 sizeof(struct dvb_frontend_parameters));
753 return 0;
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);
764 return 0;
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);
777 return 0;
780 static void smsdvb_release(struct dvb_frontend *fe)
782 /* do nothing */
785 static struct dvb_frontend_ops smsdvb_fe_ops = {
786 .info = {
787 .name = "Siano Mobile Digital MDTV Receiver",
788 .type = FE_OFDM,
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 |
798 FE_CAN_RECOVER |
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,
814 .init = smsdvb_init,
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;
823 int rc;
825 /* device removal handled by onremove callback */
826 if (!arrival)
827 return 0;
828 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
829 if (!client) {
830 sms_err("kmalloc() failed");
831 return -ENOMEM;
834 /* register dvb adapter */
835 rc = dvb_register_adapter(&client->adapter,
836 sms_get_board(
837 smscore_get_board_id(coredev))->name,
838 THIS_MODULE, device, adapter_nr);
839 if (rc < 0) {
840 sms_err("dvb_register_adapter() failed %d", rc);
841 goto adapter_error;
844 /* init dvb demux */
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);
852 if (rc < 0) {
853 sms_err("dvb_dmx_init failed %d", rc);
854 goto dvbdmx_error;
857 /* init dmxdev */
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);
863 if (rc < 0) {
864 sms_err("dvb_dmxdev_init failed %d", rc);
865 goto dmxdev_error;
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);
873 if (rc < 0) {
874 sms_err("frontend registration failed %d", rc);
875 goto frontend_error;
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, &params, &client->smsclient);
885 if (rc < 0) {
886 sms_err("smscore_register_client() failed %d", rc);
887 goto client_error;
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);
904 sms_info("success");
905 sms_board_setup(coredev);
907 return 0;
909 client_error:
910 dvb_unregister_frontend(&client->frontend);
912 frontend_error:
913 dvb_dmxdev_release(&client->dmxdev);
915 dmxdev_error:
916 dvb_dmx_release(&client->demux);
918 dvbdmx_error:
919 dvb_unregister_adapter(&client->adapter);
921 adapter_error:
922 kfree(client);
923 return rc;
926 static int __init smsdvb_module_init(void)
928 int rc;
930 INIT_LIST_HEAD(&g_smsdvb_clients);
931 kmutex_init(&g_smsdvb_clientslock);
933 rc = smscore_register_hotplug(smsdvb_hotplug);
935 sms_debug("");
937 return rc;
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");