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/init.h>
  24
  25#include "dmxdev.h"
  26#include "dvbdev.h"
  27#include "dvb_demux.h"
  28#include "dvb_frontend.h"
  29
  30#include "smscoreapi.h"
  31#include "smsendian.h"
  32#include "sms-cards.h"
  33
  34DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  35
  36struct smsdvb_client_t {
  37        struct list_head entry;
  38
  39        struct smscore_device_t *coredev;
  40        struct smscore_client_t *smsclient;
  41
  42        struct dvb_adapter      adapter;
  43        struct dvb_demux        demux;
  44        struct dmxdev           dmxdev;
  45        struct dvb_frontend     frontend;
  46
  47        fe_status_t             fe_status;
  48
  49        struct completion       tune_done;
  50
  51        /* todo: save freq/band instead whole struct */
  52        struct dvb_frontend_parameters fe_params;
  53
  54        struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
  55        int event_fe_state;
  56        int event_unc_state;
  57};
  58
  59static struct list_head g_smsdvb_clients;
  60static struct mutex g_smsdvb_clientslock;
  61
  62static int sms_dbg;
  63module_param_named(debug, sms_dbg, int, 0644);
  64MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
  65
  66/* Events that may come from DVB v3 adapter */
  67static void sms_board_dvb3_event(struct smsdvb_client_t *client,
  68                enum SMS_DVB3_EVENTS event) {
  69
  70        struct smscore_device_t *coredev = client->coredev;
  71        switch (event) {
  72        case DVB3_EVENT_INIT:
  73                sms_debug("DVB3_EVENT_INIT");
  74                sms_board_event(coredev, BOARD_EVENT_BIND);
  75                break;
  76        case DVB3_EVENT_SLEEP:
  77                sms_debug("DVB3_EVENT_SLEEP");
  78                sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
  79                break;
  80        case DVB3_EVENT_HOTPLUG:
  81                sms_debug("DVB3_EVENT_HOTPLUG");
  82                sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
  83                break;
  84        case DVB3_EVENT_FE_LOCK:
  85                if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
  86                        client->event_fe_state = DVB3_EVENT_FE_LOCK;
  87                        sms_debug("DVB3_EVENT_FE_LOCK");
  88                        sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
  89                }
  90                break;
  91        case DVB3_EVENT_FE_UNLOCK:
  92                if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
  93                        client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
  94                        sms_debug("DVB3_EVENT_FE_UNLOCK");
  95                        sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
  96                }
  97                break;
  98        case DVB3_EVENT_UNC_OK:
  99                if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
 100                        client->event_unc_state = DVB3_EVENT_UNC_OK;
 101                        sms_debug("DVB3_EVENT_UNC_OK");
 102                        sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
 103                }
 104                break;
 105        case DVB3_EVENT_UNC_ERR:
 106                if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
 107                        client->event_unc_state = DVB3_EVENT_UNC_ERR;
 108                        sms_debug("DVB3_EVENT_UNC_ERR");
 109                        sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
 110                }
 111                break;
 112
 113        default:
 114                sms_err("Unknown dvb3 api event");
 115                break;
 116        }
 117}
 118
 119static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 120{
 121        struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
 122        struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
 123                        + cb->offset);
 124        u32 *pMsgData = (u32 *) phdr + 1;
 125        /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
 126        bool is_status_update = false;
 127
 128        smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
 129
 130        switch (phdr->msgType) {
 131        case MSG_SMS_DVBT_BDA_DATA:
 132                dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
 133                                 cb->size - sizeof(struct SmsMsgHdr_ST));
 134                break;
 135
 136        case MSG_SMS_RF_TUNE_RES:
 137                complete(&client->tune_done);
 138                break;
 139
 140        case MSG_SMS_SIGNAL_DETECTED_IND:
 141                sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
 142                client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
 143                is_status_update = true;
 144                break;
 145
 146        case MSG_SMS_NO_SIGNAL_IND:
 147                sms_info("MSG_SMS_NO_SIGNAL_IND");
 148                client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
 149                is_status_update = true;
 150                break;
 151
 152        case MSG_SMS_TRANSMISSION_IND: {
 153                sms_info("MSG_SMS_TRANSMISSION_IND");
 154
 155                pMsgData++;
 156                memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
 157                                sizeof(struct TRANSMISSION_STATISTICS_S));
 158
 159                /* Mo need to correct guard interval
 160                 * (as opposed to old statistics message).
 161                 */
 162                CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
 163                CORRECT_STAT_TRANSMISSON_MODE(
 164                                client->sms_stat_dvb.TransmissionData);
 165                is_status_update = true;
 166                break;
 167        }
 168        case MSG_SMS_HO_PER_SLICES_IND: {
 169                struct RECEPTION_STATISTICS_S *pReceptionData =
 170                                &client->sms_stat_dvb.ReceptionData;
 171                struct SRVM_SIGNAL_STATUS_S SignalStatusData;
 172
 173                /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
 174                pMsgData++;
 175                SignalStatusData.result = pMsgData[0];
 176                SignalStatusData.snr = pMsgData[1];
 177                SignalStatusData.inBandPower = (s32) pMsgData[2];
 178                SignalStatusData.tsPackets = pMsgData[3];
 179                SignalStatusData.etsPackets = pMsgData[4];
 180                SignalStatusData.constellation = pMsgData[5];
 181                SignalStatusData.hpCode = pMsgData[6];
 182                SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
 183                SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
 184                SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
 185                SignalStatusData.reason = pMsgData[10];
 186                SignalStatusData.requestId = pMsgData[11];
 187                pReceptionData->IsRfLocked = pMsgData[16];
 188                pReceptionData->IsDemodLocked = pMsgData[17];
 189                pReceptionData->ModemState = pMsgData[12];
 190                pReceptionData->SNR = pMsgData[1];
 191                pReceptionData->BER = pMsgData[13];
 192                pReceptionData->RSSI = pMsgData[14];
 193                CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
 194
 195                pReceptionData->InBandPwr = (s32) pMsgData[2];
 196                pReceptionData->CarrierOffset = (s32) pMsgData[15];
 197                pReceptionData->TotalTSPackets = pMsgData[3];
 198                pReceptionData->ErrorTSPackets = pMsgData[4];
 199
 200                /* TS PER */
 201                if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
 202                                > 0) {
 203                        pReceptionData->TS_PER = (SignalStatusData.etsPackets
 204                                        * 100) / (SignalStatusData.tsPackets
 205                                        + SignalStatusData.etsPackets);
 206                } else {
 207                        pReceptionData->TS_PER = 0;
 208                }
 209
 210                pReceptionData->BERBitCount = pMsgData[18];
 211                pReceptionData->BERErrorCount = pMsgData[19];
 212
 213                pReceptionData->MRC_SNR = pMsgData[20];
 214                pReceptionData->MRC_InBandPwr = pMsgData[21];
 215                pReceptionData->MRC_RSSI = pMsgData[22];
 216
 217                is_status_update = true;
 218                break;
 219        }
 220        }
 221        smscore_putbuffer(client->coredev, cb);
 222
 223        if (is_status_update) {
 224                if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
 225                        client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
 226                                | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 227                        sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
 228                        if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
 229                                        == 0)
 230                                sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
 231                        else
 232                                sms_board_dvb3_event(client,
 233                                                DVB3_EVENT_UNC_ERR);
 234
 235                } else {
 236                        /*client->fe_status =
 237                                (phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
 238                                0 : FE_HAS_SIGNAL;*/
 239                        client->fe_status = 0;
 240                        sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
 241                }
 242        }
 243
 244        return 0;
 245}
 246
 247static void smsdvb_unregister_client(struct smsdvb_client_t *client)
 248{
 249        /* must be called under clientslock */
 250
 251        list_del(&client->entry);
 252
 253        smscore_unregister_client(client->smsclient);
 254        dvb_unregister_frontend(&client->frontend);
 255        dvb_dmxdev_release(&client->dmxdev);
 256        dvb_dmx_release(&client->demux);
 257        dvb_unregister_adapter(&client->adapter);
 258        kfree(client);
 259}
 260
 261static void smsdvb_onremove(void *context)
 262{
 263        kmutex_lock(&g_smsdvb_clientslock);
 264
 265        smsdvb_unregister_client((struct smsdvb_client_t *) context);
 266
 267        kmutex_unlock(&g_smsdvb_clientslock);
 268}
 269
 270static int smsdvb_start_feed(struct dvb_demux_feed *feed)
 271{
 272        struct smsdvb_client_t *client =
 273                container_of(feed->demux, struct smsdvb_client_t, demux);
 274        struct SmsMsgData_ST PidMsg;
 275
 276        sms_debug("add pid %d(%x)",
 277                  feed->pid, feed->pid);
 278
 279        PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
 280        PidMsg.xMsgHeader.msgDstId = HIF_TASK;
 281        PidMsg.xMsgHeader.msgFlags = 0;
 282        PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
 283        PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
 284        PidMsg.msgData[0] = feed->pid;
 285
 286        smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
 287        return smsclient_sendrequest(client->smsclient,
 288                                     &PidMsg, sizeof(PidMsg));
 289}
 290
 291static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
 292{
 293        struct smsdvb_client_t *client =
 294                container_of(feed->demux, struct smsdvb_client_t, demux);
 295        struct SmsMsgData_ST PidMsg;
 296
 297        sms_debug("remove pid %d(%x)",
 298                  feed->pid, feed->pid);
 299
 300        PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
 301        PidMsg.xMsgHeader.msgDstId = HIF_TASK;
 302        PidMsg.xMsgHeader.msgFlags = 0;
 303        PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
 304        PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
 305        PidMsg.msgData[0] = feed->pid;
 306
 307        smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
 308        return smsclient_sendrequest(client->smsclient,
 309                                     &PidMsg, sizeof(PidMsg));
 310}
 311
 312static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
 313                                        void *buffer, size_t size,
 314                                        struct completion *completion)
 315{
 316        int rc;
 317
 318        smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
 319        rc = smsclient_sendrequest(client->smsclient, buffer, size);
 320        if (rc < 0)
 321                return rc;
 322
 323        return wait_for_completion_timeout(completion,
 324                                           msecs_to_jiffies(2000)) ?
 325                                                0 : -ETIME;
 326}
 327
 328static inline int led_feedback(struct smsdvb_client_t *client)
 329{
 330        if (client->fe_status & FE_HAS_LOCK)
 331                return sms_board_led_feedback(client->coredev,
 332                        (client->sms_stat_dvb.ReceptionData.BER
 333                        == 0) ? SMS_LED_HI : SMS_LED_LO);
 334        else
 335                return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
 336}
 337
 338static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 339{
 340        struct smsdvb_client_t *client;
 341        client = container_of(fe, struct smsdvb_client_t, frontend);
 342
 343        *stat = client->fe_status;
 344
 345        led_feedback(client);
 346
 347        return 0;
 348}
 349
 350static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 351{
 352        struct smsdvb_client_t *client;
 353        client = container_of(fe, struct smsdvb_client_t, frontend);
 354
 355        *ber = client->sms_stat_dvb.ReceptionData.BER;
 356
 357        led_feedback(client);
 358
 359        return 0;
 360}
 361
 362static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 363{
 364        struct smsdvb_client_t *client;
 365        client = container_of(fe, struct smsdvb_client_t, frontend);
 366
 367        if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
 368                *strength = 0;
 369                else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
 370                        *strength = 100;
 371                else
 372                        *strength =
 373                                (client->sms_stat_dvb.ReceptionData.InBandPwr
 374                                + 95) * 3 / 2;
 375
 376        led_feedback(client);
 377
 378        return 0;
 379}
 380
 381static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 382{
 383        struct smsdvb_client_t *client;
 384        client = container_of(fe, struct smsdvb_client_t, frontend);
 385
 386        *snr = client->sms_stat_dvb.ReceptionData.SNR;
 387
 388        led_feedback(client);
 389
 390        return 0;
 391}
 392
 393static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 394{
 395        struct smsdvb_client_t *client;
 396        client = container_of(fe, struct smsdvb_client_t, frontend);
 397
 398        *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
 399
 400        led_feedback(client);
 401
 402        return 0;
 403}
 404
 405static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
 406                                    struct dvb_frontend_tune_settings *tune)
 407{
 408        sms_debug("");
 409
 410        tune->min_delay_ms = 400;
 411        tune->step_size = 250000;
 412        tune->max_drift = 0;
 413        return 0;
 414}
 415
 416static int smsdvb_set_frontend(struct dvb_frontend *fe,
 417                               struct dvb_frontend_parameters *fep)
 418{
 419        struct smsdvb_client_t *client =
 420                container_of(fe, struct smsdvb_client_t, frontend);
 421
 422        struct {
 423                struct SmsMsgHdr_ST     Msg;
 424                u32             Data[3];
 425        } Msg;
 426
 427        int ret;
 428
 429        client->fe_status = FE_HAS_SIGNAL;
 430        client->event_fe_state = -1;
 431        client->event_unc_state = -1;
 432
 433        Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
 434        Msg.Msg.msgDstId = HIF_TASK;
 435        Msg.Msg.msgFlags = 0;
 436        Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
 437        Msg.Msg.msgLength = sizeof(Msg);
 438        Msg.Data[0] = fep->frequency;
 439        Msg.Data[2] = 12000000;
 440
 441        sms_debug("freq %d band %d",
 442                  fep->frequency, fep->u.ofdm.bandwidth);
 443
 444        switch (fep->u.ofdm.bandwidth) {
 445        case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
 446        case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
 447        case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
 448        case BANDWIDTH_AUTO: return -EOPNOTSUPP;
 449        default: return -EINVAL;
 450        }
 451        /* Disable LNA, if any. An error is returned if no LNA is present */
 452        ret = sms_board_lna_control(client->coredev, 0);
 453        if (ret == 0) {
 454                fe_status_t status;
 455
 456                /* tune with LNA off at first */
 457                ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
 458                                                  &client->tune_done);
 459
 460                smsdvb_read_status(fe, &status);
 461
 462                if (status & FE_HAS_LOCK)
 463                        return ret;
 464
 465                /* previous tune didnt lock - enable LNA and tune again */
 466                sms_board_lna_control(client->coredev, 1);
 467        }
 468
 469        return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
 470                                           &client->tune_done);
 471}
 472
 473static int smsdvb_get_frontend(struct dvb_frontend *fe,
 474                               struct dvb_frontend_parameters *fep)
 475{
 476        struct smsdvb_client_t *client =
 477                container_of(fe, struct smsdvb_client_t, frontend);
 478
 479        sms_debug("");
 480
 481        /* todo: */
 482        memcpy(fep, &client->fe_params,
 483               sizeof(struct dvb_frontend_parameters));
 484
 485        return 0;
 486}
 487
 488static int smsdvb_init(struct dvb_frontend *fe)
 489{
 490        struct smsdvb_client_t *client =
 491                container_of(fe, struct smsdvb_client_t, frontend);
 492
 493        sms_board_power(client->coredev, 1);
 494
 495        sms_board_dvb3_event(client, DVB3_EVENT_INIT);
 496        return 0;
 497}
 498
 499static int smsdvb_sleep(struct dvb_frontend *fe)
 500{
 501        struct smsdvb_client_t *client =
 502                container_of(fe, struct smsdvb_client_t, frontend);
 503
 504        sms_board_led_feedback(client->coredev, SMS_LED_OFF);
 505        sms_board_power(client->coredev, 0);
 506
 507        sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
 508
 509        return 0;
 510}
 511
 512static void smsdvb_release(struct dvb_frontend *fe)
 513{
 514        /* do nothing */
 515}
 516
 517static struct dvb_frontend_ops smsdvb_fe_ops = {
 518        .info = {
 519                .name                   = "Siano Mobile Digital MDTV Receiver",
 520                .type                   = FE_OFDM,
 521                .frequency_min          = 44250000,
 522                .frequency_max          = 867250000,
 523                .frequency_stepsize     = 250000,
 524                .caps = FE_CAN_INVERSION_AUTO |
 525                        FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 526                        FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 527                        FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
 528                        FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
 529                        FE_CAN_GUARD_INTERVAL_AUTO |
 530                        FE_CAN_RECOVER |
 531                        FE_CAN_HIERARCHY_AUTO,
 532        },
 533
 534        .release = smsdvb_release,
 535
 536        .set_frontend = smsdvb_set_frontend,
 537        .get_frontend = smsdvb_get_frontend,
 538        .get_tune_settings = smsdvb_get_tune_settings,
 539
 540        .read_status = smsdvb_read_status,
 541        .read_ber = smsdvb_read_ber,
 542        .read_signal_strength = smsdvb_read_signal_strength,
 543        .read_snr = smsdvb_read_snr,
 544        .read_ucblocks = smsdvb_read_ucblocks,
 545
 546        .init = smsdvb_init,
 547        .sleep = smsdvb_sleep,
 548};
 549
 550static int smsdvb_hotplug(struct smscore_device_t *coredev,
 551                          struct device *device, int arrival)
 552{
 553        struct smsclient_params_t params;
 554        struct smsdvb_client_t *client;
 555        int rc;
 556
 557        /* device removal handled by onremove callback */
 558        if (!arrival)
 559                return 0;
 560
 561        if (smscore_get_device_mode(coredev) != DEVICE_MODE_DVBT_BDA) {
 562                sms_err("SMS Device mode is not set for "
 563                        "DVB operation.");
 564                return 0;
 565        }
 566
 567        client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
 568        if (!client) {
 569                sms_err("kmalloc() failed");
 570                return -ENOMEM;
 571        }
 572
 573        /* register dvb adapter */
 574        rc = dvb_register_adapter(&client->adapter,
 575                                  sms_get_board(
 576                                        smscore_get_board_id(coredev))->name,
 577                                  THIS_MODULE, device, adapter_nr);
 578        if (rc < 0) {
 579                sms_err("dvb_register_adapter() failed %d", rc);
 580                goto adapter_error;
 581        }
 582
 583        /* init dvb demux */
 584        client->demux.dmx.capabilities = DMX_TS_FILTERING;
 585        client->demux.filternum = 32; /* todo: nova ??? */
 586        client->demux.feednum = 32;
 587        client->demux.start_feed = smsdvb_start_feed;
 588        client->demux.stop_feed = smsdvb_stop_feed;
 589
 590        rc = dvb_dmx_init(&client->demux);
 591        if (rc < 0) {
 592                sms_err("dvb_dmx_init failed %d", rc);
 593                goto dvbdmx_error;
 594        }
 595
 596        /* init dmxdev */
 597        client->dmxdev.filternum = 32;
 598        client->dmxdev.demux = &client->demux.dmx;
 599        client->dmxdev.capabilities = 0;
 600
 601        rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
 602        if (rc < 0) {
 603                sms_err("dvb_dmxdev_init failed %d", rc);
 604                goto dmxdev_error;
 605        }
 606
 607        /* init and register frontend */
 608        memcpy(&client->frontend.ops, &smsdvb_fe_ops,
 609               sizeof(struct dvb_frontend_ops));
 610
 611        rc = dvb_register_frontend(&client->adapter, &client->frontend);
 612        if (rc < 0) {
 613                sms_err("frontend registration failed %d", rc);
 614                goto frontend_error;
 615        }
 616
 617        params.initial_id = 1;
 618        params.data_type = MSG_SMS_DVBT_BDA_DATA;
 619        params.onresponse_handler = smsdvb_onresponse;
 620        params.onremove_handler = smsdvb_onremove;
 621        params.context = client;
 622
 623        rc = smscore_register_client(coredev, &params, &client->smsclient);
 624        if (rc < 0) {
 625                sms_err("smscore_register_client() failed %d", rc);
 626                goto client_error;
 627        }
 628
 629        client->coredev = coredev;
 630
 631        init_completion(&client->tune_done);
 632
 633        kmutex_lock(&g_smsdvb_clientslock);
 634
 635        list_add(&client->entry, &g_smsdvb_clients);
 636
 637        kmutex_unlock(&g_smsdvb_clientslock);
 638
 639        client->event_fe_state = -1;
 640        client->event_unc_state = -1;
 641        sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
 642
 643        sms_info("success");
 644        sms_board_setup(coredev);
 645
 646        return 0;
 647
 648client_error:
 649        dvb_unregister_frontend(&client->frontend);
 650
 651frontend_error:
 652        dvb_dmxdev_release(&client->dmxdev);
 653
 654dmxdev_error:
 655        dvb_dmx_release(&client->demux);
 656
 657dvbdmx_error:
 658        dvb_unregister_adapter(&client->adapter);
 659
 660adapter_error:
 661        kfree(client);
 662        return rc;
 663}
 664
 665int smsdvb_module_init(void)
 666{
 667        int rc;
 668
 669        INIT_LIST_HEAD(&g_smsdvb_clients);
 670        kmutex_init(&g_smsdvb_clientslock);
 671
 672        rc = smscore_register_hotplug(smsdvb_hotplug);
 673
 674        sms_debug("");
 675
 676        return rc;
 677}
 678
 679void smsdvb_module_exit(void)
 680{
 681        smscore_unregister_hotplug(smsdvb_hotplug);
 682
 683        kmutex_lock(&g_smsdvb_clientslock);
 684
 685        while (!list_empty(&g_smsdvb_clients))
 686               smsdvb_unregister_client(
 687                        (struct smsdvb_client_t *) g_smsdvb_clients.next);
 688
 689        kmutex_unlock(&g_smsdvb_clientslock);
 690}
 691
 692module_init(smsdvb_module_init);
 693module_exit(smsdvb_module_exit);
 694
 695MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
 696MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
 697MODULE_LICENSE("GPL");
 698