Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[~shefty/rdma-dev.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         struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
53         int event_fe_state;
54         int event_unc_state;
55 };
56
57 static struct list_head g_smsdvb_clients;
58 static struct mutex g_smsdvb_clientslock;
59
60 static int sms_dbg;
61 module_param_named(debug, sms_dbg, int, 0644);
62 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
63
64 /* Events that may come from DVB v3 adapter */
65 static void sms_board_dvb3_event(struct smsdvb_client_t *client,
66                 enum SMS_DVB3_EVENTS event) {
67
68         struct smscore_device_t *coredev = client->coredev;
69         switch (event) {
70         case DVB3_EVENT_INIT:
71                 sms_debug("DVB3_EVENT_INIT");
72                 sms_board_event(coredev, BOARD_EVENT_BIND);
73                 break;
74         case DVB3_EVENT_SLEEP:
75                 sms_debug("DVB3_EVENT_SLEEP");
76                 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
77                 break;
78         case DVB3_EVENT_HOTPLUG:
79                 sms_debug("DVB3_EVENT_HOTPLUG");
80                 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
81                 break;
82         case DVB3_EVENT_FE_LOCK:
83                 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
84                         client->event_fe_state = DVB3_EVENT_FE_LOCK;
85                         sms_debug("DVB3_EVENT_FE_LOCK");
86                         sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
87                 }
88                 break;
89         case DVB3_EVENT_FE_UNLOCK:
90                 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
91                         client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
92                         sms_debug("DVB3_EVENT_FE_UNLOCK");
93                         sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
94                 }
95                 break;
96         case DVB3_EVENT_UNC_OK:
97                 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
98                         client->event_unc_state = DVB3_EVENT_UNC_OK;
99                         sms_debug("DVB3_EVENT_UNC_OK");
100                         sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
101                 }
102                 break;
103         case DVB3_EVENT_UNC_ERR:
104                 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
105                         client->event_unc_state = DVB3_EVENT_UNC_ERR;
106                         sms_debug("DVB3_EVENT_UNC_ERR");
107                         sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
108                 }
109                 break;
110
111         default:
112                 sms_err("Unknown dvb3 api event");
113                 break;
114         }
115 }
116
117
118 static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
119                                    struct SMSHOSTLIB_STATISTICS_ST *p)
120 {
121         if (sms_dbg & 2) {
122                 printk(KERN_DEBUG "Reserved = %d", p->Reserved);
123                 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
124                 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
125                 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
126                 printk(KERN_DEBUG "SNR = %d", p->SNR);
127                 printk(KERN_DEBUG "BER = %d", p->BER);
128                 printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
129                 printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
130                 printk(KERN_DEBUG "MFER = %d", p->MFER);
131                 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
132                 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
133                 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
134                 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
135                 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
136                 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
137                 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
138                 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
139                 printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
140                 printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
141                 printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
142                 printk(KERN_DEBUG "Constellation = %d", p->Constellation);
143                 printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
144                 printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
145                 printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
146                 printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
147                 printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
148                 printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
149                 printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
150                 printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
151                 printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
152                 printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
153                 printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
154                 printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
155                 printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
156                 printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
157                 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
158                 printk(KERN_DEBUG "PreBER = %d", p->PreBER);
159                 printk(KERN_DEBUG "CellId = %d", p->CellId);
160                 printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
161                 printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
162                 printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
163         }
164
165         pReceptionData->IsDemodLocked = p->IsDemodLocked;
166
167         pReceptionData->SNR = p->SNR;
168         pReceptionData->BER = p->BER;
169         pReceptionData->BERErrorCount = p->BERErrorCount;
170         pReceptionData->InBandPwr = p->InBandPwr;
171         pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
172 };
173
174
175 static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
176                                     struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
177 {
178         int i;
179
180         if (sms_dbg & 2) {
181                 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
182                 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
183                 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
184                 printk(KERN_DEBUG "SNR = %d", p->SNR);
185                 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
186                 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
187                 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
188                 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
189                 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
190                 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
191                 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
192                 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
193                 printk(KERN_DEBUG "SystemType = %d", p->SystemType);
194                 printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
195                 printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
196                 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
197
198                 for (i = 0; i < 3; i++) {
199                         printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
200                         printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
201                         printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
202                         printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
203                         printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
204                         printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
205                         printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
206                         printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
207                         printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
208                         printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
209                         printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
210                         printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
211                 }
212         }
213
214         pReceptionData->IsDemodLocked = p->IsDemodLocked;
215
216         pReceptionData->SNR = p->SNR;
217         pReceptionData->InBandPwr = p->InBandPwr;
218
219         pReceptionData->ErrorTSPackets = 0;
220         pReceptionData->BER = 0;
221         pReceptionData->BERErrorCount = 0;
222         for (i = 0; i < 3; i++) {
223                 pReceptionData->BER += p->LayerInfo[i].BER;
224                 pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
225                 pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
226         }
227 }
228
229 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
230 {
231         struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
232         struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
233                         + cb->offset);
234         u32 *pMsgData = (u32 *) phdr + 1;
235         /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
236         bool is_status_update = false;
237
238         smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
239
240         switch (phdr->msgType) {
241         case MSG_SMS_DVBT_BDA_DATA:
242                 dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
243                                  cb->size - sizeof(struct SmsMsgHdr_ST));
244                 break;
245
246         case MSG_SMS_RF_TUNE_RES:
247         case MSG_SMS_ISDBT_TUNE_RES:
248                 complete(&client->tune_done);
249                 break;
250
251         case MSG_SMS_SIGNAL_DETECTED_IND:
252                 sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
253                 client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
254                 is_status_update = true;
255                 break;
256
257         case MSG_SMS_NO_SIGNAL_IND:
258                 sms_info("MSG_SMS_NO_SIGNAL_IND");
259                 client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
260                 is_status_update = true;
261                 break;
262
263         case MSG_SMS_TRANSMISSION_IND: {
264                 sms_info("MSG_SMS_TRANSMISSION_IND");
265
266                 pMsgData++;
267                 memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
268                                 sizeof(struct TRANSMISSION_STATISTICS_S));
269
270                 /* Mo need to correct guard interval
271                  * (as opposed to old statistics message).
272                  */
273                 CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
274                 CORRECT_STAT_TRANSMISSON_MODE(
275                                 client->sms_stat_dvb.TransmissionData);
276                 is_status_update = true;
277                 break;
278         }
279         case MSG_SMS_HO_PER_SLICES_IND: {
280                 struct RECEPTION_STATISTICS_S *pReceptionData =
281                                 &client->sms_stat_dvb.ReceptionData;
282                 struct SRVM_SIGNAL_STATUS_S SignalStatusData;
283
284                 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
285                 pMsgData++;
286                 SignalStatusData.result = pMsgData[0];
287                 SignalStatusData.snr = pMsgData[1];
288                 SignalStatusData.inBandPower = (s32) pMsgData[2];
289                 SignalStatusData.tsPackets = pMsgData[3];
290                 SignalStatusData.etsPackets = pMsgData[4];
291                 SignalStatusData.constellation = pMsgData[5];
292                 SignalStatusData.hpCode = pMsgData[6];
293                 SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
294                 SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
295                 SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
296                 SignalStatusData.reason = pMsgData[10];
297                 SignalStatusData.requestId = pMsgData[11];
298                 pReceptionData->IsRfLocked = pMsgData[16];
299                 pReceptionData->IsDemodLocked = pMsgData[17];
300                 pReceptionData->ModemState = pMsgData[12];
301                 pReceptionData->SNR = pMsgData[1];
302                 pReceptionData->BER = pMsgData[13];
303                 pReceptionData->RSSI = pMsgData[14];
304                 CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
305
306                 pReceptionData->InBandPwr = (s32) pMsgData[2];
307                 pReceptionData->CarrierOffset = (s32) pMsgData[15];
308                 pReceptionData->TotalTSPackets = pMsgData[3];
309                 pReceptionData->ErrorTSPackets = pMsgData[4];
310
311                 /* TS PER */
312                 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
313                                 > 0) {
314                         pReceptionData->TS_PER = (SignalStatusData.etsPackets
315                                         * 100) / (SignalStatusData.tsPackets
316                                         + SignalStatusData.etsPackets);
317                 } else {
318                         pReceptionData->TS_PER = 0;
319                 }
320
321                 pReceptionData->BERBitCount = pMsgData[18];
322                 pReceptionData->BERErrorCount = pMsgData[19];
323
324                 pReceptionData->MRC_SNR = pMsgData[20];
325                 pReceptionData->MRC_InBandPwr = pMsgData[21];
326                 pReceptionData->MRC_RSSI = pMsgData[22];
327
328                 is_status_update = true;
329                 break;
330         }
331         case MSG_SMS_GET_STATISTICS_RES: {
332                 union {
333                         struct SMSHOSTLIB_STATISTICS_ISDBT_ST  isdbt;
334                         struct SmsMsgStatisticsInfo_ST         dvb;
335                 } *p = (void *) (phdr + 1);
336                 struct RECEPTION_STATISTICS_S *pReceptionData =
337                                 &client->sms_stat_dvb.ReceptionData;
338
339                 sms_info("MSG_SMS_GET_STATISTICS_RES");
340
341                 is_status_update = true;
342
343                 switch (smscore_get_device_mode(client->coredev)) {
344                 case DEVICE_MODE_ISDBT:
345                 case DEVICE_MODE_ISDBT_BDA:
346                         smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
347                         break;
348                 default:
349                         smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
350                 }
351                 if (!pReceptionData->IsDemodLocked) {
352                         pReceptionData->SNR = 0;
353                         pReceptionData->BER = 0;
354                         pReceptionData->BERErrorCount = 0;
355                         pReceptionData->InBandPwr = 0;
356                         pReceptionData->ErrorTSPackets = 0;
357                 }
358
359                 complete(&client->tune_done);
360                 break;
361         }
362         default:
363                 sms_info("Unhandled message %d", phdr->msgType);
364
365         }
366         smscore_putbuffer(client->coredev, cb);
367
368         if (is_status_update) {
369                 if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
370                         client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
371                                 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
372                         sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
373                         if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
374                                         == 0)
375                                 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
376                         else
377                                 sms_board_dvb3_event(client,
378                                                 DVB3_EVENT_UNC_ERR);
379
380                 } else {
381                         if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
382                                 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
383                         else
384                                 client->fe_status = 0;
385                         sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
386                 }
387         }
388
389         return 0;
390 }
391
392 static void smsdvb_unregister_client(struct smsdvb_client_t *client)
393 {
394         /* must be called under clientslock */
395
396         list_del(&client->entry);
397
398         smscore_unregister_client(client->smsclient);
399         dvb_unregister_frontend(&client->frontend);
400         dvb_dmxdev_release(&client->dmxdev);
401         dvb_dmx_release(&client->demux);
402         dvb_unregister_adapter(&client->adapter);
403         kfree(client);
404 }
405
406 static void smsdvb_onremove(void *context)
407 {
408         kmutex_lock(&g_smsdvb_clientslock);
409
410         smsdvb_unregister_client((struct smsdvb_client_t *) context);
411
412         kmutex_unlock(&g_smsdvb_clientslock);
413 }
414
415 static int smsdvb_start_feed(struct dvb_demux_feed *feed)
416 {
417         struct smsdvb_client_t *client =
418                 container_of(feed->demux, struct smsdvb_client_t, demux);
419         struct SmsMsgData_ST PidMsg;
420
421         sms_debug("add pid %d(%x)",
422                   feed->pid, feed->pid);
423
424         PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
425         PidMsg.xMsgHeader.msgDstId = HIF_TASK;
426         PidMsg.xMsgHeader.msgFlags = 0;
427         PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
428         PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
429         PidMsg.msgData[0] = feed->pid;
430
431         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
432         return smsclient_sendrequest(client->smsclient,
433                                      &PidMsg, sizeof(PidMsg));
434 }
435
436 static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
437 {
438         struct smsdvb_client_t *client =
439                 container_of(feed->demux, struct smsdvb_client_t, demux);
440         struct SmsMsgData_ST PidMsg;
441
442         sms_debug("remove pid %d(%x)",
443                   feed->pid, feed->pid);
444
445         PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
446         PidMsg.xMsgHeader.msgDstId = HIF_TASK;
447         PidMsg.xMsgHeader.msgFlags = 0;
448         PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
449         PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
450         PidMsg.msgData[0] = feed->pid;
451
452         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
453         return smsclient_sendrequest(client->smsclient,
454                                      &PidMsg, sizeof(PidMsg));
455 }
456
457 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
458                                         void *buffer, size_t size,
459                                         struct completion *completion)
460 {
461         int rc;
462
463         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
464         rc = smsclient_sendrequest(client->smsclient, buffer, size);
465         if (rc < 0)
466                 return rc;
467
468         return wait_for_completion_timeout(completion,
469                                            msecs_to_jiffies(2000)) ?
470                                                 0 : -ETIME;
471 }
472
473 static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
474 {
475         int rc;
476         struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
477                                     DVBT_BDA_CONTROL_MSG_ID,
478                                     HIF_TASK,
479                                     sizeof(struct SmsMsgHdr_ST), 0 };
480
481         rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
482                                           &client->tune_done);
483
484         return rc;
485 }
486
487 static inline int led_feedback(struct smsdvb_client_t *client)
488 {
489         if (client->fe_status & FE_HAS_LOCK)
490                 return sms_board_led_feedback(client->coredev,
491                         (client->sms_stat_dvb.ReceptionData.BER
492                         == 0) ? SMS_LED_HI : SMS_LED_LO);
493         else
494                 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
495 }
496
497 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
498 {
499         int rc;
500         struct smsdvb_client_t *client;
501         client = container_of(fe, struct smsdvb_client_t, frontend);
502
503         rc = smsdvb_send_statistics_request(client);
504
505         *stat = client->fe_status;
506
507         led_feedback(client);
508
509         return rc;
510 }
511
512 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
513 {
514         int rc;
515         struct smsdvb_client_t *client;
516         client = container_of(fe, struct smsdvb_client_t, frontend);
517
518         rc = smsdvb_send_statistics_request(client);
519
520         *ber = client->sms_stat_dvb.ReceptionData.BER;
521
522         led_feedback(client);
523
524         return rc;
525 }
526
527 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
528 {
529         int rc;
530
531         struct smsdvb_client_t *client;
532         client = container_of(fe, struct smsdvb_client_t, frontend);
533
534         rc = smsdvb_send_statistics_request(client);
535
536         if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
537                 *strength = 0;
538                 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
539                         *strength = 100;
540                 else
541                         *strength =
542                                 (client->sms_stat_dvb.ReceptionData.InBandPwr
543                                 + 95) * 3 / 2;
544
545         led_feedback(client);
546
547         return rc;
548 }
549
550 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
551 {
552         int rc;
553         struct smsdvb_client_t *client;
554         client = container_of(fe, struct smsdvb_client_t, frontend);
555
556         rc = smsdvb_send_statistics_request(client);
557
558         *snr = client->sms_stat_dvb.ReceptionData.SNR;
559
560         led_feedback(client);
561
562         return rc;
563 }
564
565 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
566 {
567         int rc;
568         struct smsdvb_client_t *client;
569         client = container_of(fe, struct smsdvb_client_t, frontend);
570
571         rc = smsdvb_send_statistics_request(client);
572
573         *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
574
575         led_feedback(client);
576
577         return rc;
578 }
579
580 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
581                                     struct dvb_frontend_tune_settings *tune)
582 {
583         sms_debug("");
584
585         tune->min_delay_ms = 400;
586         tune->step_size = 250000;
587         tune->max_drift = 0;
588         return 0;
589 }
590
591 static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
592 {
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);
596
597         struct {
598                 struct SmsMsgHdr_ST     Msg;
599                 u32             Data[3];
600         } Msg;
601
602         int ret;
603
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;
608
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;
616
617         sms_info("%s: freq %d band %d", __func__, c->frequency,
618                  c->bandwidth_hz);
619
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;
634         }
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;
639
640                 /* tune with LNA off at first */
641                 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
642                                                   &client->tune_done);
643
644                 smsdvb_read_status(fe, &status);
645
646                 if (status & FE_HAS_LOCK)
647                         return ret;
648
649                 /* previous tune didn't lock - enable LNA and tune again */
650                 sms_board_lna_control(client->coredev, 1);
651         }
652
653         return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
654                                            &client->tune_done);
655 }
656
657 static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
658 {
659         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
660         struct smsdvb_client_t *client =
661                 container_of(fe, struct smsdvb_client_t, frontend);
662
663         struct {
664                 struct SmsMsgHdr_ST     Msg;
665                 u32             Data[4];
666         } Msg;
667
668         fe->dtv_property_cache.delivery_system = SYS_ISDBT;
669
670         Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
671         Msg.Msg.msgDstId  = HIF_TASK;
672         Msg.Msg.msgFlags  = 0;
673         Msg.Msg.msgType   = MSG_SMS_ISDBT_TUNE_REQ;
674         Msg.Msg.msgLength = sizeof(Msg);
675
676         if (c->isdbt_sb_segment_idx == -1)
677                 c->isdbt_sb_segment_idx = 0;
678
679         switch (c->isdbt_sb_segment_count) {
680         case 3:
681                 Msg.Data[1] = BW_ISDBT_3SEG;
682                 break;
683         case 1:
684                 Msg.Data[1] = BW_ISDBT_1SEG;
685                 break;
686         case 0: /* AUTO */
687                 switch (c->bandwidth_hz / 1000000) {
688                 case 8:
689                 case 7:
690                         c->isdbt_sb_segment_count = 3;
691                         Msg.Data[1] = BW_ISDBT_3SEG;
692                         break;
693                 case 6:
694                         c->isdbt_sb_segment_count = 1;
695                         Msg.Data[1] = BW_ISDBT_1SEG;
696                         break;
697                 default: /* Assumes 6 MHZ bw */
698                         c->isdbt_sb_segment_count = 1;
699                         c->bandwidth_hz = 6000;
700                         Msg.Data[1] = BW_ISDBT_1SEG;
701                         break;
702                 }
703                 break;
704         default:
705                 sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
706                 return -EINVAL;
707         }
708
709         Msg.Data[0] = c->frequency;
710         Msg.Data[2] = 12000000;
711         Msg.Data[3] = c->isdbt_sb_segment_idx;
712
713         sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
714                  c->frequency, c->isdbt_sb_segment_count,
715                  c->isdbt_sb_segment_idx);
716
717         return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
718                                            &client->tune_done);
719 }
720
721 static int smsdvb_set_frontend(struct dvb_frontend *fe)
722 {
723         struct smsdvb_client_t *client =
724                 container_of(fe, struct smsdvb_client_t, frontend);
725         struct smscore_device_t *coredev = client->coredev;
726
727         switch (smscore_get_device_mode(coredev)) {
728         case DEVICE_MODE_DVBT:
729         case DEVICE_MODE_DVBT_BDA:
730                 return smsdvb_dvbt_set_frontend(fe);
731         case DEVICE_MODE_ISDBT:
732         case DEVICE_MODE_ISDBT_BDA:
733                 return smsdvb_isdbt_set_frontend(fe);
734         default:
735                 return -EINVAL;
736         }
737 }
738
739 static int smsdvb_get_frontend(struct dvb_frontend *fe)
740 {
741         struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
742         struct smsdvb_client_t *client =
743                 container_of(fe, struct smsdvb_client_t, frontend);
744         struct smscore_device_t *coredev = client->coredev;
745         struct TRANSMISSION_STATISTICS_S *td =
746                 &client->sms_stat_dvb.TransmissionData;
747
748         switch (smscore_get_device_mode(coredev)) {
749         case DEVICE_MODE_DVBT:
750         case DEVICE_MODE_DVBT_BDA:
751                 fep->frequency = td->Frequency;
752
753                 switch (td->Bandwidth) {
754                 case 6:
755                         fep->bandwidth_hz = 6000000;
756                         break;
757                 case 7:
758                         fep->bandwidth_hz = 7000000;
759                         break;
760                 case 8:
761                         fep->bandwidth_hz = 8000000;
762                         break;
763                 }
764
765                 switch (td->TransmissionMode) {
766                 case 2:
767                         fep->transmission_mode = TRANSMISSION_MODE_2K;
768                         break;
769                 case 8:
770                         fep->transmission_mode = TRANSMISSION_MODE_8K;
771                 }
772
773                 switch (td->GuardInterval) {
774                 case 0:
775                         fep->guard_interval = GUARD_INTERVAL_1_32;
776                         break;
777                 case 1:
778                         fep->guard_interval = GUARD_INTERVAL_1_16;
779                         break;
780                 case 2:
781                         fep->guard_interval = GUARD_INTERVAL_1_8;
782                         break;
783                 case 3:
784                         fep->guard_interval = GUARD_INTERVAL_1_4;
785                         break;
786                 }
787
788                 switch (td->CodeRate) {
789                 case 0:
790                         fep->code_rate_HP = FEC_1_2;
791                         break;
792                 case 1:
793                         fep->code_rate_HP = FEC_2_3;
794                         break;
795                 case 2:
796                         fep->code_rate_HP = FEC_3_4;
797                         break;
798                 case 3:
799                         fep->code_rate_HP = FEC_5_6;
800                         break;
801                 case 4:
802                         fep->code_rate_HP = FEC_7_8;
803                         break;
804                 }
805
806                 switch (td->LPCodeRate) {
807                 case 0:
808                         fep->code_rate_LP = FEC_1_2;
809                         break;
810                 case 1:
811                         fep->code_rate_LP = FEC_2_3;
812                         break;
813                 case 2:
814                         fep->code_rate_LP = FEC_3_4;
815                         break;
816                 case 3:
817                         fep->code_rate_LP = FEC_5_6;
818                         break;
819                 case 4:
820                         fep->code_rate_LP = FEC_7_8;
821                         break;
822                 }
823
824                 switch (td->Constellation) {
825                 case 0:
826                         fep->modulation = QPSK;
827                         break;
828                 case 1:
829                         fep->modulation = QAM_16;
830                         break;
831                 case 2:
832                         fep->modulation = QAM_64;
833                         break;
834                 }
835
836                 switch (td->Hierarchy) {
837                 case 0:
838                         fep->hierarchy = HIERARCHY_NONE;
839                         break;
840                 case 1:
841                         fep->hierarchy = HIERARCHY_1;
842                         break;
843                 case 2:
844                         fep->hierarchy = HIERARCHY_2;
845                         break;
846                 case 3:
847                         fep->hierarchy = HIERARCHY_4;
848                         break;
849                 }
850
851                 fep->inversion = INVERSION_AUTO;
852                 break;
853         case DEVICE_MODE_ISDBT:
854         case DEVICE_MODE_ISDBT_BDA:
855                 fep->frequency = td->Frequency;
856                 fep->bandwidth_hz = 6000000;
857                 /* todo: retrive the other parameters */
858                 break;
859         default:
860                 return -EINVAL;
861         }
862
863         return 0;
864 }
865
866 static int smsdvb_init(struct dvb_frontend *fe)
867 {
868         struct smsdvb_client_t *client =
869                 container_of(fe, struct smsdvb_client_t, frontend);
870
871         sms_board_power(client->coredev, 1);
872
873         sms_board_dvb3_event(client, DVB3_EVENT_INIT);
874         return 0;
875 }
876
877 static int smsdvb_sleep(struct dvb_frontend *fe)
878 {
879         struct smsdvb_client_t *client =
880                 container_of(fe, struct smsdvb_client_t, frontend);
881
882         sms_board_led_feedback(client->coredev, SMS_LED_OFF);
883         sms_board_power(client->coredev, 0);
884
885         sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
886
887         return 0;
888 }
889
890 static void smsdvb_release(struct dvb_frontend *fe)
891 {
892         /* do nothing */
893 }
894
895 static struct dvb_frontend_ops smsdvb_fe_ops = {
896         .info = {
897                 .name                   = "Siano Mobile Digital MDTV Receiver",
898                 .frequency_min          = 44250000,
899                 .frequency_max          = 867250000,
900                 .frequency_stepsize     = 250000,
901                 .caps = FE_CAN_INVERSION_AUTO |
902                         FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
903                         FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
904                         FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
905                         FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
906                         FE_CAN_GUARD_INTERVAL_AUTO |
907                         FE_CAN_RECOVER |
908                         FE_CAN_HIERARCHY_AUTO,
909         },
910
911         .release = smsdvb_release,
912
913         .set_frontend = smsdvb_set_frontend,
914         .get_frontend = smsdvb_get_frontend,
915         .get_tune_settings = smsdvb_get_tune_settings,
916
917         .read_status = smsdvb_read_status,
918         .read_ber = smsdvb_read_ber,
919         .read_signal_strength = smsdvb_read_signal_strength,
920         .read_snr = smsdvb_read_snr,
921         .read_ucblocks = smsdvb_read_ucblocks,
922
923         .init = smsdvb_init,
924         .sleep = smsdvb_sleep,
925 };
926
927 static int smsdvb_hotplug(struct smscore_device_t *coredev,
928                           struct device *device, int arrival)
929 {
930         struct smsclient_params_t params;
931         struct smsdvb_client_t *client;
932         int rc;
933
934         /* device removal handled by onremove callback */
935         if (!arrival)
936                 return 0;
937         client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
938         if (!client) {
939                 sms_err("kmalloc() failed");
940                 return -ENOMEM;
941         }
942
943         /* register dvb adapter */
944         rc = dvb_register_adapter(&client->adapter,
945                                   sms_get_board(
946                                         smscore_get_board_id(coredev))->name,
947                                   THIS_MODULE, device, adapter_nr);
948         if (rc < 0) {
949                 sms_err("dvb_register_adapter() failed %d", rc);
950                 goto adapter_error;
951         }
952
953         /* init dvb demux */
954         client->demux.dmx.capabilities = DMX_TS_FILTERING;
955         client->demux.filternum = 32; /* todo: nova ??? */
956         client->demux.feednum = 32;
957         client->demux.start_feed = smsdvb_start_feed;
958         client->demux.stop_feed = smsdvb_stop_feed;
959
960         rc = dvb_dmx_init(&client->demux);
961         if (rc < 0) {
962                 sms_err("dvb_dmx_init failed %d", rc);
963                 goto dvbdmx_error;
964         }
965
966         /* init dmxdev */
967         client->dmxdev.filternum = 32;
968         client->dmxdev.demux = &client->demux.dmx;
969         client->dmxdev.capabilities = 0;
970
971         rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
972         if (rc < 0) {
973                 sms_err("dvb_dmxdev_init failed %d", rc);
974                 goto dmxdev_error;
975         }
976
977         /* init and register frontend */
978         memcpy(&client->frontend.ops, &smsdvb_fe_ops,
979                sizeof(struct dvb_frontend_ops));
980
981         switch (smscore_get_device_mode(coredev)) {
982         case DEVICE_MODE_DVBT:
983         case DEVICE_MODE_DVBT_BDA:
984                 client->frontend.ops.delsys[0] = SYS_DVBT;
985                 break;
986         case DEVICE_MODE_ISDBT:
987         case DEVICE_MODE_ISDBT_BDA:
988                 client->frontend.ops.delsys[0] = SYS_ISDBT;
989                 break;
990         }
991
992         rc = dvb_register_frontend(&client->adapter, &client->frontend);
993         if (rc < 0) {
994                 sms_err("frontend registration failed %d", rc);
995                 goto frontend_error;
996         }
997
998         params.initial_id = 1;
999         params.data_type = MSG_SMS_DVBT_BDA_DATA;
1000         params.onresponse_handler = smsdvb_onresponse;
1001         params.onremove_handler = smsdvb_onremove;
1002         params.context = client;
1003
1004         rc = smscore_register_client(coredev, &params, &client->smsclient);
1005         if (rc < 0) {
1006                 sms_err("smscore_register_client() failed %d", rc);
1007                 goto client_error;
1008         }
1009
1010         client->coredev = coredev;
1011
1012         init_completion(&client->tune_done);
1013
1014         kmutex_lock(&g_smsdvb_clientslock);
1015
1016         list_add(&client->entry, &g_smsdvb_clients);
1017
1018         kmutex_unlock(&g_smsdvb_clientslock);
1019
1020         client->event_fe_state = -1;
1021         client->event_unc_state = -1;
1022         sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
1023
1024         sms_info("success");
1025         sms_board_setup(coredev);
1026
1027         return 0;
1028
1029 client_error:
1030         dvb_unregister_frontend(&client->frontend);
1031
1032 frontend_error:
1033         dvb_dmxdev_release(&client->dmxdev);
1034
1035 dmxdev_error:
1036         dvb_dmx_release(&client->demux);
1037
1038 dvbdmx_error:
1039         dvb_unregister_adapter(&client->adapter);
1040
1041 adapter_error:
1042         kfree(client);
1043         return rc;
1044 }
1045
1046 static int __init smsdvb_module_init(void)
1047 {
1048         int rc;
1049
1050         INIT_LIST_HEAD(&g_smsdvb_clients);
1051         kmutex_init(&g_smsdvb_clientslock);
1052
1053         rc = smscore_register_hotplug(smsdvb_hotplug);
1054
1055         sms_debug("");
1056
1057         return rc;
1058 }
1059
1060 static void __exit smsdvb_module_exit(void)
1061 {
1062         smscore_unregister_hotplug(smsdvb_hotplug);
1063
1064         kmutex_lock(&g_smsdvb_clientslock);
1065
1066         while (!list_empty(&g_smsdvb_clients))
1067                smsdvb_unregister_client(
1068                         (struct smsdvb_client_t *) g_smsdvb_clients.next);
1069
1070         kmutex_unlock(&g_smsdvb_clientslock);
1071 }
1072
1073 module_init(smsdvb_module_init);
1074 module_exit(smsdvb_module_exit);
1075
1076 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1077 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1078 MODULE_LICENSE("GPL");