Merge branch 'rmobile-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / media / dvb / siano / smsdvb.c
1 /****************************************************************
2
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2008, Uri Shkolnik
6
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.
11
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.
16
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/>.
19
20 ****************************************************************/
21
22 #include <linux/module.h>
23 #include <linux/slab.h>
24 #include <linux/init.h>
25
26 #include "dmxdev.h"
27 #include "dvbdev.h"
28 #include "dvb_demux.h"
29 #include "dvb_frontend.h"
30
31 #include "smscoreapi.h"
32 #include "smsendian.h"
33 #include "sms-cards.h"
34
35 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36
37 struct smsdvb_client_t {
38         struct list_head entry;
39
40         struct smscore_device_t *coredev;
41         struct smscore_client_t *smsclient;
42
43         struct dvb_adapter      adapter;
44         struct dvb_demux        demux;
45         struct dmxdev           dmxdev;
46         struct dvb_frontend     frontend;
47
48         fe_status_t             fe_status;
49
50         struct completion       tune_done;
51
52         /* todo: save freq/band instead whole struct */
53         struct dvb_frontend_parameters fe_params;
54
55         struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
56         int event_fe_state;
57         int event_unc_state;
58 };
59
60 static struct list_head g_smsdvb_clients;
61 static struct mutex g_smsdvb_clientslock;
62
63 static int sms_dbg;
64 module_param_named(debug, sms_dbg, int, 0644);
65 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
66
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) {
70
71         struct smscore_device_t *coredev = client->coredev;
72         switch (event) {
73         case DVB3_EVENT_INIT:
74                 sms_debug("DVB3_EVENT_INIT");
75                 sms_board_event(coredev, BOARD_EVENT_BIND);
76                 break;
77         case DVB3_EVENT_SLEEP:
78                 sms_debug("DVB3_EVENT_SLEEP");
79                 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
80                 break;
81         case DVB3_EVENT_HOTPLUG:
82                 sms_debug("DVB3_EVENT_HOTPLUG");
83                 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
84                 break;
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);
90                 }
91                 break;
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);
97                 }
98                 break;
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);
104                 }
105                 break;
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);
111                 }
112                 break;
113
114         default:
115                 sms_err("Unknown dvb3 api event");
116                 break;
117         }
118 }
119
120
121 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
122                                    struct SMSHOSTLIB_STATISTICS_ST *p)
123 {
124         if (sms_dbg & 2) {
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);
166         }
167
168         pReceptionData->IsDemodLocked = p->IsDemodLocked;
169
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;
175 };
176
177
178 static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
179                                     struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
180 {
181         int i;
182
183         if (sms_dbg & 2) {
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);
200
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);
214                 }
215         }
216
217         pReceptionData->IsDemodLocked = p->IsDemodLocked;
218
219         pReceptionData->SNR = p->SNR;
220         pReceptionData->InBandPwr = p->InBandPwr;
221
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;
229         }
230 }
231
232 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
233 {
234         struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
235         struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
236                         + cb->offset);
237         u32 *pMsgData = (u32 *) phdr + 1;
238         /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
239         bool is_status_update = false;
240
241         smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
242
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));
247                 break;
248
249         case MSG_SMS_RF_TUNE_RES:
250         case MSG_SMS_ISDBT_TUNE_RES:
251                 complete(&client->tune_done);
252                 break;
253
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;
258                 break;
259
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;
264                 break;
265
266         case MSG_SMS_TRANSMISSION_IND: {
267                 sms_info("MSG_SMS_TRANSMISSION_IND");
268
269                 pMsgData++;
270                 memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
271                                 sizeof(struct TRANSMISSION_STATISTICS_S));
272
273                 /* Mo need to correct guard interval
274                  * (as opposed to old statistics message).
275                  */
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;
280                 break;
281         }
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;
286
287                 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
288                 pMsgData++;
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);
308
309                 pReceptionData->InBandPwr = (s32) pMsgData[2];
310                 pReceptionData->CarrierOffset = (s32) pMsgData[15];
311                 pReceptionData->TotalTSPackets = pMsgData[3];
312                 pReceptionData->ErrorTSPackets = pMsgData[4];
313
314                 /* TS PER */
315                 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
316                                 > 0) {
317                         pReceptionData->TS_PER = (SignalStatusData.etsPackets
318                                         * 100) / (SignalStatusData.tsPackets
319                                         + SignalStatusData.etsPackets);
320                 } else {
321                         pReceptionData->TS_PER = 0;
322                 }
323
324                 pReceptionData->BERBitCount = pMsgData[18];
325                 pReceptionData->BERErrorCount = pMsgData[19];
326
327                 pReceptionData->MRC_SNR = pMsgData[20];
328                 pReceptionData->MRC_InBandPwr = pMsgData[21];
329                 pReceptionData->MRC_RSSI = pMsgData[22];
330
331                 is_status_update = true;
332                 break;
333         }
334         case MSG_SMS_GET_STATISTICS_RES: {
335                 union {
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;
341
342                 sms_info("MSG_SMS_GET_STATISTICS_RES");
343
344                 is_status_update = true;
345
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);
350                         break;
351                 default:
352                         smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
353                 }
354                 if (!pReceptionData->IsDemodLocked) {
355                         pReceptionData->SNR = 0;
356                         pReceptionData->BER = 0;
357                         pReceptionData->BERErrorCount = 0;
358                         pReceptionData->InBandPwr = 0;
359                         pReceptionData->ErrorTSPackets = 0;
360                 }
361
362                 complete(&client->tune_done);
363                 break;
364         }
365         default:
366                 sms_info("Unhandled message %d", phdr->msgType);
367
368         }
369         smscore_putbuffer(client->coredev, cb);
370
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
377                                         == 0)
378                                 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
379                         else
380                                 sms_board_dvb3_event(client,
381                                                 DVB3_EVENT_UNC_ERR);
382
383                 } else {
384                         if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
385                                 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
386                         else
387                                 client->fe_status = 0;
388                         sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
389                 }
390         }
391
392         return 0;
393 }
394
395 static void smsdvb_unregister_client(struct smsdvb_client_t *client)
396 {
397         /* must be called under clientslock */
398
399         list_del(&client->entry);
400
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);
406         kfree(client);
407 }
408
409 static void smsdvb_onremove(void *context)
410 {
411         kmutex_lock(&g_smsdvb_clientslock);
412
413         smsdvb_unregister_client((struct smsdvb_client_t *) context);
414
415         kmutex_unlock(&g_smsdvb_clientslock);
416 }
417
418 static int smsdvb_start_feed(struct dvb_demux_feed *feed)
419 {
420         struct smsdvb_client_t *client =
421                 container_of(feed->demux, struct smsdvb_client_t, demux);
422         struct SmsMsgData_ST PidMsg;
423
424         sms_debug("add pid %d(%x)",
425                   feed->pid, feed->pid);
426
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;
433
434         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
435         return smsclient_sendrequest(client->smsclient,
436                                      &PidMsg, sizeof(PidMsg));
437 }
438
439 static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
440 {
441         struct smsdvb_client_t *client =
442                 container_of(feed->demux, struct smsdvb_client_t, demux);
443         struct SmsMsgData_ST PidMsg;
444
445         sms_debug("remove pid %d(%x)",
446                   feed->pid, feed->pid);
447
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;
454
455         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
456         return smsclient_sendrequest(client->smsclient,
457                                      &PidMsg, sizeof(PidMsg));
458 }
459
460 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
461                                         void *buffer, size_t size,
462                                         struct completion *completion)
463 {
464         int rc;
465
466         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
467         rc = smsclient_sendrequest(client->smsclient, buffer, size);
468         if (rc < 0)
469                 return rc;
470
471         return wait_for_completion_timeout(completion,
472                                            msecs_to_jiffies(2000)) ?
473                                                 0 : -ETIME;
474 }
475
476 static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
477 {
478         int rc;
479         struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
480                                     DVBT_BDA_CONTROL_MSG_ID,
481                                     HIF_TASK,
482                                     sizeof(struct SmsMsgHdr_ST), 0 };
483
484         rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
485                                           &client->tune_done);
486
487         return rc;
488 }
489
490 static inline int led_feedback(struct smsdvb_client_t *client)
491 {
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);
496         else
497                 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
498 }
499
500 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
501 {
502         int rc;
503         struct smsdvb_client_t *client;
504         client = container_of(fe, struct smsdvb_client_t, frontend);
505
506         rc = smsdvb_send_statistics_request(client);
507
508         *stat = client->fe_status;
509
510         led_feedback(client);
511
512         return rc;
513 }
514
515 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
516 {
517         int rc;
518         struct smsdvb_client_t *client;
519         client = container_of(fe, struct smsdvb_client_t, frontend);
520
521         rc = smsdvb_send_statistics_request(client);
522
523         *ber = client->sms_stat_dvb.ReceptionData.BER;
524
525         led_feedback(client);
526
527         return rc;
528 }
529
530 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
531 {
532         int rc;
533
534         struct smsdvb_client_t *client;
535         client = container_of(fe, struct smsdvb_client_t, frontend);
536
537         rc = smsdvb_send_statistics_request(client);
538
539         if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
540                 *strength = 0;
541                 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
542                         *strength = 100;
543                 else
544                         *strength =
545                                 (client->sms_stat_dvb.ReceptionData.InBandPwr
546                                 + 95) * 3 / 2;
547
548         led_feedback(client);
549
550         return rc;
551 }
552
553 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
554 {
555         int rc;
556         struct smsdvb_client_t *client;
557         client = container_of(fe, struct smsdvb_client_t, frontend);
558
559         rc = smsdvb_send_statistics_request(client);
560
561         *snr = client->sms_stat_dvb.ReceptionData.SNR;
562
563         led_feedback(client);
564
565         return rc;
566 }
567
568 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
569 {
570         int rc;
571         struct smsdvb_client_t *client;
572         client = container_of(fe, struct smsdvb_client_t, frontend);
573
574         rc = smsdvb_send_statistics_request(client);
575
576         *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
577
578         led_feedback(client);
579
580         return rc;
581 }
582
583 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
584                                     struct dvb_frontend_tune_settings *tune)
585 {
586         sms_debug("");
587
588         tune->min_delay_ms = 400;
589         tune->step_size = 250000;
590         tune->max_drift = 0;
591         return 0;
592 }
593
594 static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
595                                     struct dvb_frontend_parameters *p)
596 {
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);
600
601         struct {
602                 struct SmsMsgHdr_ST     Msg;
603                 u32             Data[3];
604         } Msg;
605
606         int ret;
607
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;
612
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;
620
621         sms_info("%s: freq %d band %d", __func__, c->frequency,
622                  c->bandwidth_hz);
623
624         switch (c->bandwidth_hz / 1000000) {
625         case 8:
626                 Msg.Data[1] = BW_8_MHZ;
627                 break;
628         case 7:
629                 Msg.Data[1] = BW_7_MHZ;
630                 break;
631         case 6:
632                 Msg.Data[1] = BW_6_MHZ;
633                 break;
634         case 0:
635                 return -EOPNOTSUPP;
636         default:
637                 return -EINVAL;
638         }
639         /* Disable LNA, if any. An error is returned if no LNA is present */
640         ret = sms_board_lna_control(client->coredev, 0);
641         if (ret == 0) {
642                 fe_status_t status;
643
644                 /* tune with LNA off at first */
645                 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
646                                                   &client->tune_done);
647
648                 smsdvb_read_status(fe, &status);
649
650                 if (status & FE_HAS_LOCK)
651                         return ret;
652
653                 /* previous tune didn't lock - enable LNA and tune again */
654                 sms_board_lna_control(client->coredev, 1);
655         }
656
657         return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
658                                            &client->tune_done);
659 }
660
661 static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
662                                      struct dvb_frontend_parameters *p)
663 {
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);
667
668         struct {
669                 struct SmsMsgHdr_ST     Msg;
670                 u32             Data[4];
671         } Msg;
672
673         fe->dtv_property_cache.delivery_system = SYS_ISDBT;
674
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);
680
681         if (c->isdbt_sb_segment_idx == -1)
682                 c->isdbt_sb_segment_idx = 0;
683
684         switch (c->isdbt_sb_segment_count) {
685         case 3:
686                 Msg.Data[1] = BW_ISDBT_3SEG;
687                 break;
688         case 1:
689                 Msg.Data[1] = BW_ISDBT_1SEG;
690                 break;
691         case 0: /* AUTO */
692                 switch (c->bandwidth_hz / 1000000) {
693                 case 8:
694                 case 7:
695                         c->isdbt_sb_segment_count = 3;
696                         Msg.Data[1] = BW_ISDBT_3SEG;
697                         break;
698                 case 6:
699                         c->isdbt_sb_segment_count = 1;
700                         Msg.Data[1] = BW_ISDBT_1SEG;
701                         break;
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;
706                         break;
707                 }
708                 break;
709         default:
710                 sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
711                 return -EINVAL;
712         }
713
714         Msg.Data[0] = c->frequency;
715         Msg.Data[2] = 12000000;
716         Msg.Data[3] = c->isdbt_sb_segment_idx;
717
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);
721
722         return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
723                                            &client->tune_done);
724 }
725
726 static int smsdvb_set_frontend(struct dvb_frontend *fe,
727                                struct dvb_frontend_parameters *fep)
728 {
729         struct smsdvb_client_t *client =
730                 container_of(fe, struct smsdvb_client_t, frontend);
731         struct smscore_device_t *coredev = client->coredev;
732
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);
740         default:
741                 return -EINVAL;
742         }
743 }
744
745 static int smsdvb_get_frontend(struct dvb_frontend *fe,
746                                struct dvb_frontend_parameters *fep)
747 {
748         struct smsdvb_client_t *client =
749                 container_of(fe, struct smsdvb_client_t, frontend);
750
751         sms_debug("");
752
753         /* todo: */
754         memcpy(fep, &client->fe_params,
755                sizeof(struct dvb_frontend_parameters));
756
757         return 0;
758 }
759
760 static int smsdvb_init(struct dvb_frontend *fe)
761 {
762         struct smsdvb_client_t *client =
763                 container_of(fe, struct smsdvb_client_t, frontend);
764
765         sms_board_power(client->coredev, 1);
766
767         sms_board_dvb3_event(client, DVB3_EVENT_INIT);
768         return 0;
769 }
770
771 static int smsdvb_sleep(struct dvb_frontend *fe)
772 {
773         struct smsdvb_client_t *client =
774                 container_of(fe, struct smsdvb_client_t, frontend);
775
776         sms_board_led_feedback(client->coredev, SMS_LED_OFF);
777         sms_board_power(client->coredev, 0);
778
779         sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
780
781         return 0;
782 }
783
784 static void smsdvb_release(struct dvb_frontend *fe)
785 {
786         /* do nothing */
787 }
788
789 static struct dvb_frontend_ops smsdvb_fe_ops = {
790         .info = {
791                 .name                   = "Siano Mobile Digital MDTV Receiver",
792                 .type                   = FE_OFDM,
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 |
802                         FE_CAN_RECOVER |
803                         FE_CAN_HIERARCHY_AUTO,
804         },
805
806         .release = smsdvb_release,
807
808         .set_frontend = smsdvb_set_frontend,
809         .get_frontend = smsdvb_get_frontend,
810         .get_tune_settings = smsdvb_get_tune_settings,
811
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,
817
818         .init = smsdvb_init,
819         .sleep = smsdvb_sleep,
820 };
821
822 static int smsdvb_hotplug(struct smscore_device_t *coredev,
823                           struct device *device, int arrival)
824 {
825         struct smsclient_params_t params;
826         struct smsdvb_client_t *client;
827         int rc;
828
829         /* device removal handled by onremove callback */
830         if (!arrival)
831                 return 0;
832         client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
833         if (!client) {
834                 sms_err("kmalloc() failed");
835                 return -ENOMEM;
836         }
837
838         /* register dvb adapter */
839         rc = dvb_register_adapter(&client->adapter,
840                                   sms_get_board(
841                                         smscore_get_board_id(coredev))->name,
842                                   THIS_MODULE, device, adapter_nr);
843         if (rc < 0) {
844                 sms_err("dvb_register_adapter() failed %d", rc);
845                 goto adapter_error;
846         }
847
848         /* init dvb demux */
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;
854
855         rc = dvb_dmx_init(&client->demux);
856         if (rc < 0) {
857                 sms_err("dvb_dmx_init failed %d", rc);
858                 goto dvbdmx_error;
859         }
860
861         /* init dmxdev */
862         client->dmxdev.filternum = 32;
863         client->dmxdev.demux = &client->demux.dmx;
864         client->dmxdev.capabilities = 0;
865
866         rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
867         if (rc < 0) {
868                 sms_err("dvb_dmxdev_init failed %d", rc);
869                 goto dmxdev_error;
870         }
871
872         /* init and register frontend */
873         memcpy(&client->frontend.ops, &smsdvb_fe_ops,
874                sizeof(struct dvb_frontend_ops));
875
876         rc = dvb_register_frontend(&client->adapter, &client->frontend);
877         if (rc < 0) {
878                 sms_err("frontend registration failed %d", rc);
879                 goto frontend_error;
880         }
881
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;
887
888         rc = smscore_register_client(coredev, &params, &client->smsclient);
889         if (rc < 0) {
890                 sms_err("smscore_register_client() failed %d", rc);
891                 goto client_error;
892         }
893
894         client->coredev = coredev;
895
896         init_completion(&client->tune_done);
897
898         kmutex_lock(&g_smsdvb_clientslock);
899
900         list_add(&client->entry, &g_smsdvb_clients);
901
902         kmutex_unlock(&g_smsdvb_clientslock);
903
904         client->event_fe_state = -1;
905         client->event_unc_state = -1;
906         sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
907
908         sms_info("success");
909         sms_board_setup(coredev);
910
911         return 0;
912
913 client_error:
914         dvb_unregister_frontend(&client->frontend);
915
916 frontend_error:
917         dvb_dmxdev_release(&client->dmxdev);
918
919 dmxdev_error:
920         dvb_dmx_release(&client->demux);
921
922 dvbdmx_error:
923         dvb_unregister_adapter(&client->adapter);
924
925 adapter_error:
926         kfree(client);
927         return rc;
928 }
929
930 static int __init smsdvb_module_init(void)
931 {
932         int rc;
933
934         INIT_LIST_HEAD(&g_smsdvb_clients);
935         kmutex_init(&g_smsdvb_clientslock);
936
937         rc = smscore_register_hotplug(smsdvb_hotplug);
938
939         sms_debug("");
940
941         return rc;
942 }
943
944 static void __exit smsdvb_module_exit(void)
945 {
946         smscore_unregister_hotplug(smsdvb_hotplug);
947
948         kmutex_lock(&g_smsdvb_clientslock);
949
950         while (!list_empty(&g_smsdvb_clients))
951                smsdvb_unregister_client(
952                         (struct smsdvb_client_t *) g_smsdvb_clients.next);
953
954         kmutex_unlock(&g_smsdvb_clientslock);
955 }
956
957 module_init(smsdvb_module_init);
958 module_exit(smsdvb_module_exit);
959
960 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
961 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
962 MODULE_LICENSE("GPL");