linux/drivers/media/dvb/siano/smsdvb.c
<<
>>
Prefs
   1/****************************************************************
   2
   3Siano Mobile Silicon, Inc.
   4MDTV receiver kernel modules.
   5Copyright (C) 2006-2008, Uri Shkolnik
   6
   7This program is free software: you can redistribute it and/or modify
   8it under the terms of the GNU General Public License as published by
   9the 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,
  13but WITHOUT ANY WARRANTY; without even the implied warranty of
  14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15GNU General Public License for more details.
  16
  17You should have received a copy of the GNU General Public License
  18along 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
  35DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  36
  37struct 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
  57static struct list_head g_smsdvb_clients;
  58static struct mutex g_smsdvb_clientslock;
  59
  60static int sms_dbg;
  61module_param_named(debug, sms_dbg, int, 0644);
  62MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
  63
  64/* Events that may come from DVB v3 adapter */
  65static 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
 118static 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
 175static 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
 229static 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
 392static 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
 406static 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
 415static 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
 436static 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
 457static 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
 473static 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
 487static 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
 497static 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
 512static 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
 527static 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
 550static 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
 565static 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
 580static 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
 591static 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
 657static 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
 721static 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
 739static 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
 866static 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
 877static 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
 890static void smsdvb_release(struct dvb_frontend *fe)
 891{
 892        /* do nothing */
 893}
 894
 895static 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
 927static 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
1029client_error:
1030        dvb_unregister_frontend(&client->frontend);
1031
1032frontend_error:
1033        dvb_dmxdev_release(&client->dmxdev);
1034
1035dmxdev_error:
1036        dvb_dmx_release(&client->demux);
1037
1038dvbdmx_error:
1039        dvb_unregister_adapter(&client->adapter);
1040
1041adapter_error:
1042        kfree(client);
1043        return rc;
1044}
1045
1046static 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
1060static 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
1073module_init(smsdvb_module_init);
1074module_exit(smsdvb_module_exit);
1075
1076MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1077MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1078MODULE_LICENSE("GPL");
1079