Path: blob/master/drivers/media/dvb/siano/smsdvb.c
15111 views
/****************************************************************12Siano Mobile Silicon, Inc.3MDTV receiver kernel modules.4Copyright (C) 2006-2008, Uri Shkolnik56This program is free software: you can redistribute it and/or modify7it under the terms of the GNU General Public License as published by8the Free Software Foundation, either version 2 of the License, or9(at your option) any later version.1011This program is distributed in the hope that it will be useful,12but WITHOUT ANY WARRANTY; without even the implied warranty of13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14GNU General Public License for more details.1516You should have received a copy of the GNU General Public License17along with this program. If not, see <http://www.gnu.org/licenses/>.1819****************************************************************/2021#include <linux/module.h>22#include <linux/slab.h>23#include <linux/init.h>2425#include "dmxdev.h"26#include "dvbdev.h"27#include "dvb_demux.h"28#include "dvb_frontend.h"2930#include "smscoreapi.h"31#include "smsendian.h"32#include "sms-cards.h"3334DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);3536struct smsdvb_client_t {37struct list_head entry;3839struct smscore_device_t *coredev;40struct smscore_client_t *smsclient;4142struct dvb_adapter adapter;43struct dvb_demux demux;44struct dmxdev dmxdev;45struct dvb_frontend frontend;4647fe_status_t fe_status;4849struct completion tune_done;5051/* todo: save freq/band instead whole struct */52struct dvb_frontend_parameters fe_params;5354struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;55int event_fe_state;56int event_unc_state;57};5859static struct list_head g_smsdvb_clients;60static struct mutex g_smsdvb_clientslock;6162static int sms_dbg;63module_param_named(debug, sms_dbg, int, 0644);64MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");6566/* Events that may come from DVB v3 adapter */67static void sms_board_dvb3_event(struct smsdvb_client_t *client,68enum SMS_DVB3_EVENTS event) {6970struct smscore_device_t *coredev = client->coredev;71switch (event) {72case DVB3_EVENT_INIT:73sms_debug("DVB3_EVENT_INIT");74sms_board_event(coredev, BOARD_EVENT_BIND);75break;76case DVB3_EVENT_SLEEP:77sms_debug("DVB3_EVENT_SLEEP");78sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);79break;80case DVB3_EVENT_HOTPLUG:81sms_debug("DVB3_EVENT_HOTPLUG");82sms_board_event(coredev, BOARD_EVENT_POWER_INIT);83break;84case DVB3_EVENT_FE_LOCK:85if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {86client->event_fe_state = DVB3_EVENT_FE_LOCK;87sms_debug("DVB3_EVENT_FE_LOCK");88sms_board_event(coredev, BOARD_EVENT_FE_LOCK);89}90break;91case DVB3_EVENT_FE_UNLOCK:92if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {93client->event_fe_state = DVB3_EVENT_FE_UNLOCK;94sms_debug("DVB3_EVENT_FE_UNLOCK");95sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);96}97break;98case DVB3_EVENT_UNC_OK:99if (client->event_unc_state != DVB3_EVENT_UNC_OK) {100client->event_unc_state = DVB3_EVENT_UNC_OK;101sms_debug("DVB3_EVENT_UNC_OK");102sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);103}104break;105case DVB3_EVENT_UNC_ERR:106if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {107client->event_unc_state = DVB3_EVENT_UNC_ERR;108sms_debug("DVB3_EVENT_UNC_ERR");109sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);110}111break;112113default:114sms_err("Unknown dvb3 api event");115break;116}117}118119120static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,121struct SMSHOSTLIB_STATISTICS_ST *p)122{123if (sms_dbg & 2) {124printk(KERN_DEBUG "Reserved = %d", p->Reserved);125printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);126printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);127printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);128printk(KERN_DEBUG "SNR = %d", p->SNR);129printk(KERN_DEBUG "BER = %d", p->BER);130printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);131printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);132printk(KERN_DEBUG "MFER = %d", p->MFER);133printk(KERN_DEBUG "RSSI = %d", p->RSSI);134printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);135printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);136printk(KERN_DEBUG "Frequency = %d", p->Frequency);137printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);138printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);139printk(KERN_DEBUG "ModemState = %d", p->ModemState);140printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);141printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);142printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);143printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);144printk(KERN_DEBUG "Constellation = %d", p->Constellation);145printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);146printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);147printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);148printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);149printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);150printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);151printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);152printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);153printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);154printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);155printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);156printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);157printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);158printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);159printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);160printk(KERN_DEBUG "PreBER = %d", p->PreBER);161printk(KERN_DEBUG "CellId = %d", p->CellId);162printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);163printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);164printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);165}166167pReceptionData->IsDemodLocked = p->IsDemodLocked;168169pReceptionData->SNR = p->SNR;170pReceptionData->BER = p->BER;171pReceptionData->BERErrorCount = p->BERErrorCount;172pReceptionData->InBandPwr = p->InBandPwr;173pReceptionData->ErrorTSPackets = p->ErrorTSPackets;174};175176177static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,178struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)179{180int i;181182if (sms_dbg & 2) {183printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);184printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);185printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);186printk(KERN_DEBUG "SNR = %d", p->SNR);187printk(KERN_DEBUG "RSSI = %d", p->RSSI);188printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);189printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);190printk(KERN_DEBUG "Frequency = %d", p->Frequency);191printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);192printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);193printk(KERN_DEBUG "ModemState = %d", p->ModemState);194printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);195printk(KERN_DEBUG "SystemType = %d", p->SystemType);196printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);197printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);198printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);199200for (i = 0; i < 3; i++) {201printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);202printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);203printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);204printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);205printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);206printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);207printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);208printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);209printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);210printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);211printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);212printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);213}214}215216pReceptionData->IsDemodLocked = p->IsDemodLocked;217218pReceptionData->SNR = p->SNR;219pReceptionData->InBandPwr = p->InBandPwr;220221pReceptionData->ErrorTSPackets = 0;222pReceptionData->BER = 0;223pReceptionData->BERErrorCount = 0;224for (i = 0; i < 3; i++) {225pReceptionData->BER += p->LayerInfo[i].BER;226pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;227pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;228}229}230231static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)232{233struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;234struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)235+ cb->offset);236u32 *pMsgData = (u32 *) phdr + 1;237/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/238bool is_status_update = false;239240smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);241242switch (phdr->msgType) {243case MSG_SMS_DVBT_BDA_DATA:244dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),245cb->size - sizeof(struct SmsMsgHdr_ST));246break;247248case MSG_SMS_RF_TUNE_RES:249case MSG_SMS_ISDBT_TUNE_RES:250complete(&client->tune_done);251break;252253case MSG_SMS_SIGNAL_DETECTED_IND:254sms_info("MSG_SMS_SIGNAL_DETECTED_IND");255client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;256is_status_update = true;257break;258259case MSG_SMS_NO_SIGNAL_IND:260sms_info("MSG_SMS_NO_SIGNAL_IND");261client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;262is_status_update = true;263break;264265case MSG_SMS_TRANSMISSION_IND: {266sms_info("MSG_SMS_TRANSMISSION_IND");267268pMsgData++;269memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,270sizeof(struct TRANSMISSION_STATISTICS_S));271272/* Mo need to correct guard interval273* (as opposed to old statistics message).274*/275CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);276CORRECT_STAT_TRANSMISSON_MODE(277client->sms_stat_dvb.TransmissionData);278is_status_update = true;279break;280}281case MSG_SMS_HO_PER_SLICES_IND: {282struct RECEPTION_STATISTICS_S *pReceptionData =283&client->sms_stat_dvb.ReceptionData;284struct SRVM_SIGNAL_STATUS_S SignalStatusData;285286/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/287pMsgData++;288SignalStatusData.result = pMsgData[0];289SignalStatusData.snr = pMsgData[1];290SignalStatusData.inBandPower = (s32) pMsgData[2];291SignalStatusData.tsPackets = pMsgData[3];292SignalStatusData.etsPackets = pMsgData[4];293SignalStatusData.constellation = pMsgData[5];294SignalStatusData.hpCode = pMsgData[6];295SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;296SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;297SignalStatusData.cellId = pMsgData[9] & 0xFFFF;298SignalStatusData.reason = pMsgData[10];299SignalStatusData.requestId = pMsgData[11];300pReceptionData->IsRfLocked = pMsgData[16];301pReceptionData->IsDemodLocked = pMsgData[17];302pReceptionData->ModemState = pMsgData[12];303pReceptionData->SNR = pMsgData[1];304pReceptionData->BER = pMsgData[13];305pReceptionData->RSSI = pMsgData[14];306CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);307308pReceptionData->InBandPwr = (s32) pMsgData[2];309pReceptionData->CarrierOffset = (s32) pMsgData[15];310pReceptionData->TotalTSPackets = pMsgData[3];311pReceptionData->ErrorTSPackets = pMsgData[4];312313/* TS PER */314if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)315> 0) {316pReceptionData->TS_PER = (SignalStatusData.etsPackets317* 100) / (SignalStatusData.tsPackets318+ SignalStatusData.etsPackets);319} else {320pReceptionData->TS_PER = 0;321}322323pReceptionData->BERBitCount = pMsgData[18];324pReceptionData->BERErrorCount = pMsgData[19];325326pReceptionData->MRC_SNR = pMsgData[20];327pReceptionData->MRC_InBandPwr = pMsgData[21];328pReceptionData->MRC_RSSI = pMsgData[22];329330is_status_update = true;331break;332}333case MSG_SMS_GET_STATISTICS_RES: {334union {335struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;336struct SmsMsgStatisticsInfo_ST dvb;337} *p = (void *) (phdr + 1);338struct RECEPTION_STATISTICS_S *pReceptionData =339&client->sms_stat_dvb.ReceptionData;340341sms_info("MSG_SMS_GET_STATISTICS_RES");342343is_status_update = true;344345switch (smscore_get_device_mode(client->coredev)) {346case DEVICE_MODE_ISDBT:347case DEVICE_MODE_ISDBT_BDA:348smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);349break;350default:351smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);352}353if (!pReceptionData->IsDemodLocked) {354pReceptionData->SNR = 0;355pReceptionData->BER = 0;356pReceptionData->BERErrorCount = 0;357pReceptionData->InBandPwr = 0;358pReceptionData->ErrorTSPackets = 0;359}360361complete(&client->tune_done);362break;363}364default:365sms_info("Unhandled message %d", phdr->msgType);366367}368smscore_putbuffer(client->coredev, cb);369370if (is_status_update) {371if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {372client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER373| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;374sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);375if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets376== 0)377sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);378else379sms_board_dvb3_event(client,380DVB3_EVENT_UNC_ERR);381382} else {383if (client->sms_stat_dvb.ReceptionData.IsRfLocked)384client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;385else386client->fe_status = 0;387sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);388}389}390391return 0;392}393394static void smsdvb_unregister_client(struct smsdvb_client_t *client)395{396/* must be called under clientslock */397398list_del(&client->entry);399400smscore_unregister_client(client->smsclient);401dvb_unregister_frontend(&client->frontend);402dvb_dmxdev_release(&client->dmxdev);403dvb_dmx_release(&client->demux);404dvb_unregister_adapter(&client->adapter);405kfree(client);406}407408static void smsdvb_onremove(void *context)409{410kmutex_lock(&g_smsdvb_clientslock);411412smsdvb_unregister_client((struct smsdvb_client_t *) context);413414kmutex_unlock(&g_smsdvb_clientslock);415}416417static int smsdvb_start_feed(struct dvb_demux_feed *feed)418{419struct smsdvb_client_t *client =420container_of(feed->demux, struct smsdvb_client_t, demux);421struct SmsMsgData_ST PidMsg;422423sms_debug("add pid %d(%x)",424feed->pid, feed->pid);425426PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;427PidMsg.xMsgHeader.msgDstId = HIF_TASK;428PidMsg.xMsgHeader.msgFlags = 0;429PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;430PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);431PidMsg.msgData[0] = feed->pid;432433smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);434return smsclient_sendrequest(client->smsclient,435&PidMsg, sizeof(PidMsg));436}437438static int smsdvb_stop_feed(struct dvb_demux_feed *feed)439{440struct smsdvb_client_t *client =441container_of(feed->demux, struct smsdvb_client_t, demux);442struct SmsMsgData_ST PidMsg;443444sms_debug("remove pid %d(%x)",445feed->pid, feed->pid);446447PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;448PidMsg.xMsgHeader.msgDstId = HIF_TASK;449PidMsg.xMsgHeader.msgFlags = 0;450PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;451PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);452PidMsg.msgData[0] = feed->pid;453454smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);455return smsclient_sendrequest(client->smsclient,456&PidMsg, sizeof(PidMsg));457}458459static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,460void *buffer, size_t size,461struct completion *completion)462{463int rc;464465smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);466rc = smsclient_sendrequest(client->smsclient, buffer, size);467if (rc < 0)468return rc;469470return wait_for_completion_timeout(completion,471msecs_to_jiffies(2000)) ?4720 : -ETIME;473}474475static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)476{477int rc;478struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,479DVBT_BDA_CONTROL_MSG_ID,480HIF_TASK,481sizeof(struct SmsMsgHdr_ST), 0 };482483rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),484&client->tune_done);485486return rc;487}488489static inline int led_feedback(struct smsdvb_client_t *client)490{491if (client->fe_status & FE_HAS_LOCK)492return sms_board_led_feedback(client->coredev,493(client->sms_stat_dvb.ReceptionData.BER494== 0) ? SMS_LED_HI : SMS_LED_LO);495else496return sms_board_led_feedback(client->coredev, SMS_LED_OFF);497}498499static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)500{501int rc;502struct smsdvb_client_t *client;503client = container_of(fe, struct smsdvb_client_t, frontend);504505rc = smsdvb_send_statistics_request(client);506507*stat = client->fe_status;508509led_feedback(client);510511return rc;512}513514static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)515{516int rc;517struct smsdvb_client_t *client;518client = container_of(fe, struct smsdvb_client_t, frontend);519520rc = smsdvb_send_statistics_request(client);521522*ber = client->sms_stat_dvb.ReceptionData.BER;523524led_feedback(client);525526return rc;527}528529static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)530{531int rc;532533struct smsdvb_client_t *client;534client = container_of(fe, struct smsdvb_client_t, frontend);535536rc = smsdvb_send_statistics_request(client);537538if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)539*strength = 0;540else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)541*strength = 100;542else543*strength =544(client->sms_stat_dvb.ReceptionData.InBandPwr545+ 95) * 3 / 2;546547led_feedback(client);548549return rc;550}551552static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)553{554int rc;555struct smsdvb_client_t *client;556client = container_of(fe, struct smsdvb_client_t, frontend);557558rc = smsdvb_send_statistics_request(client);559560*snr = client->sms_stat_dvb.ReceptionData.SNR;561562led_feedback(client);563564return rc;565}566567static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)568{569int rc;570struct smsdvb_client_t *client;571client = container_of(fe, struct smsdvb_client_t, frontend);572573rc = smsdvb_send_statistics_request(client);574575*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;576577led_feedback(client);578579return rc;580}581582static int smsdvb_get_tune_settings(struct dvb_frontend *fe,583struct dvb_frontend_tune_settings *tune)584{585sms_debug("");586587tune->min_delay_ms = 400;588tune->step_size = 250000;589tune->max_drift = 0;590return 0;591}592593static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,594struct dvb_frontend_parameters *p)595{596struct dtv_frontend_properties *c = &fe->dtv_property_cache;597struct smsdvb_client_t *client =598container_of(fe, struct smsdvb_client_t, frontend);599600struct {601struct SmsMsgHdr_ST Msg;602u32 Data[3];603} Msg;604605int ret;606607client->fe_status = FE_HAS_SIGNAL;608client->event_fe_state = -1;609client->event_unc_state = -1;610fe->dtv_property_cache.delivery_system = SYS_DVBT;611612Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;613Msg.Msg.msgDstId = HIF_TASK;614Msg.Msg.msgFlags = 0;615Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;616Msg.Msg.msgLength = sizeof(Msg);617Msg.Data[0] = c->frequency;618Msg.Data[2] = 12000000;619620sms_info("%s: freq %d band %d", __func__, c->frequency,621c->bandwidth_hz);622623switch (c->bandwidth_hz / 1000000) {624case 8:625Msg.Data[1] = BW_8_MHZ;626break;627case 7:628Msg.Data[1] = BW_7_MHZ;629break;630case 6:631Msg.Data[1] = BW_6_MHZ;632break;633case 0:634return -EOPNOTSUPP;635default:636return -EINVAL;637}638/* Disable LNA, if any. An error is returned if no LNA is present */639ret = sms_board_lna_control(client->coredev, 0);640if (ret == 0) {641fe_status_t status;642643/* tune with LNA off at first */644ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),645&client->tune_done);646647smsdvb_read_status(fe, &status);648649if (status & FE_HAS_LOCK)650return ret;651652/* previous tune didn't lock - enable LNA and tune again */653sms_board_lna_control(client->coredev, 1);654}655656return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),657&client->tune_done);658}659660static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,661struct dvb_frontend_parameters *p)662{663struct dtv_frontend_properties *c = &fe->dtv_property_cache;664struct smsdvb_client_t *client =665container_of(fe, struct smsdvb_client_t, frontend);666667struct {668struct SmsMsgHdr_ST Msg;669u32 Data[4];670} Msg;671672fe->dtv_property_cache.delivery_system = SYS_ISDBT;673674Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;675Msg.Msg.msgDstId = HIF_TASK;676Msg.Msg.msgFlags = 0;677Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;678Msg.Msg.msgLength = sizeof(Msg);679680if (c->isdbt_sb_segment_idx == -1)681c->isdbt_sb_segment_idx = 0;682683switch (c->isdbt_sb_segment_count) {684case 3:685Msg.Data[1] = BW_ISDBT_3SEG;686break;687case 1:688Msg.Data[1] = BW_ISDBT_1SEG;689break;690case 0: /* AUTO */691switch (c->bandwidth_hz / 1000000) {692case 8:693case 7:694c->isdbt_sb_segment_count = 3;695Msg.Data[1] = BW_ISDBT_3SEG;696break;697case 6:698c->isdbt_sb_segment_count = 1;699Msg.Data[1] = BW_ISDBT_1SEG;700break;701default: /* Assumes 6 MHZ bw */702c->isdbt_sb_segment_count = 1;703c->bandwidth_hz = 6000;704Msg.Data[1] = BW_ISDBT_1SEG;705break;706}707break;708default:709sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);710return -EINVAL;711}712713Msg.Data[0] = c->frequency;714Msg.Data[2] = 12000000;715Msg.Data[3] = c->isdbt_sb_segment_idx;716717sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,718c->frequency, c->isdbt_sb_segment_count,719c->isdbt_sb_segment_idx);720721return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),722&client->tune_done);723}724725static int smsdvb_set_frontend(struct dvb_frontend *fe,726struct dvb_frontend_parameters *fep)727{728struct smsdvb_client_t *client =729container_of(fe, struct smsdvb_client_t, frontend);730struct smscore_device_t *coredev = client->coredev;731732switch (smscore_get_device_mode(coredev)) {733case DEVICE_MODE_DVBT:734case DEVICE_MODE_DVBT_BDA:735return smsdvb_dvbt_set_frontend(fe, fep);736case DEVICE_MODE_ISDBT:737case DEVICE_MODE_ISDBT_BDA:738return smsdvb_isdbt_set_frontend(fe, fep);739default:740return -EINVAL;741}742}743744static int smsdvb_get_frontend(struct dvb_frontend *fe,745struct dvb_frontend_parameters *fep)746{747struct smsdvb_client_t *client =748container_of(fe, struct smsdvb_client_t, frontend);749750sms_debug("");751752/* todo: */753memcpy(fep, &client->fe_params,754sizeof(struct dvb_frontend_parameters));755756return 0;757}758759static int smsdvb_init(struct dvb_frontend *fe)760{761struct smsdvb_client_t *client =762container_of(fe, struct smsdvb_client_t, frontend);763764sms_board_power(client->coredev, 1);765766sms_board_dvb3_event(client, DVB3_EVENT_INIT);767return 0;768}769770static int smsdvb_sleep(struct dvb_frontend *fe)771{772struct smsdvb_client_t *client =773container_of(fe, struct smsdvb_client_t, frontend);774775sms_board_led_feedback(client->coredev, SMS_LED_OFF);776sms_board_power(client->coredev, 0);777778sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);779780return 0;781}782783static void smsdvb_release(struct dvb_frontend *fe)784{785/* do nothing */786}787788static struct dvb_frontend_ops smsdvb_fe_ops = {789.info = {790.name = "Siano Mobile Digital MDTV Receiver",791.type = FE_OFDM,792.frequency_min = 44250000,793.frequency_max = 867250000,794.frequency_stepsize = 250000,795.caps = FE_CAN_INVERSION_AUTO |796FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |797FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |798FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |799FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |800FE_CAN_GUARD_INTERVAL_AUTO |801FE_CAN_RECOVER |802FE_CAN_HIERARCHY_AUTO,803},804805.release = smsdvb_release,806807.set_frontend = smsdvb_set_frontend,808.get_frontend = smsdvb_get_frontend,809.get_tune_settings = smsdvb_get_tune_settings,810811.read_status = smsdvb_read_status,812.read_ber = smsdvb_read_ber,813.read_signal_strength = smsdvb_read_signal_strength,814.read_snr = smsdvb_read_snr,815.read_ucblocks = smsdvb_read_ucblocks,816817.init = smsdvb_init,818.sleep = smsdvb_sleep,819};820821static int smsdvb_hotplug(struct smscore_device_t *coredev,822struct device *device, int arrival)823{824struct smsclient_params_t params;825struct smsdvb_client_t *client;826int rc;827828/* device removal handled by onremove callback */829if (!arrival)830return 0;831client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);832if (!client) {833sms_err("kmalloc() failed");834return -ENOMEM;835}836837/* register dvb adapter */838rc = dvb_register_adapter(&client->adapter,839sms_get_board(840smscore_get_board_id(coredev))->name,841THIS_MODULE, device, adapter_nr);842if (rc < 0) {843sms_err("dvb_register_adapter() failed %d", rc);844goto adapter_error;845}846847/* init dvb demux */848client->demux.dmx.capabilities = DMX_TS_FILTERING;849client->demux.filternum = 32; /* todo: nova ??? */850client->demux.feednum = 32;851client->demux.start_feed = smsdvb_start_feed;852client->demux.stop_feed = smsdvb_stop_feed;853854rc = dvb_dmx_init(&client->demux);855if (rc < 0) {856sms_err("dvb_dmx_init failed %d", rc);857goto dvbdmx_error;858}859860/* init dmxdev */861client->dmxdev.filternum = 32;862client->dmxdev.demux = &client->demux.dmx;863client->dmxdev.capabilities = 0;864865rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);866if (rc < 0) {867sms_err("dvb_dmxdev_init failed %d", rc);868goto dmxdev_error;869}870871/* init and register frontend */872memcpy(&client->frontend.ops, &smsdvb_fe_ops,873sizeof(struct dvb_frontend_ops));874875rc = dvb_register_frontend(&client->adapter, &client->frontend);876if (rc < 0) {877sms_err("frontend registration failed %d", rc);878goto frontend_error;879}880881params.initial_id = 1;882params.data_type = MSG_SMS_DVBT_BDA_DATA;883params.onresponse_handler = smsdvb_onresponse;884params.onremove_handler = smsdvb_onremove;885params.context = client;886887rc = smscore_register_client(coredev, ¶ms, &client->smsclient);888if (rc < 0) {889sms_err("smscore_register_client() failed %d", rc);890goto client_error;891}892893client->coredev = coredev;894895init_completion(&client->tune_done);896897kmutex_lock(&g_smsdvb_clientslock);898899list_add(&client->entry, &g_smsdvb_clients);900901kmutex_unlock(&g_smsdvb_clientslock);902903client->event_fe_state = -1;904client->event_unc_state = -1;905sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);906907sms_info("success");908sms_board_setup(coredev);909910return 0;911912client_error:913dvb_unregister_frontend(&client->frontend);914915frontend_error:916dvb_dmxdev_release(&client->dmxdev);917918dmxdev_error:919dvb_dmx_release(&client->demux);920921dvbdmx_error:922dvb_unregister_adapter(&client->adapter);923924adapter_error:925kfree(client);926return rc;927}928929static int __init smsdvb_module_init(void)930{931int rc;932933INIT_LIST_HEAD(&g_smsdvb_clients);934kmutex_init(&g_smsdvb_clientslock);935936rc = smscore_register_hotplug(smsdvb_hotplug);937938sms_debug("");939940return rc;941}942943static void __exit smsdvb_module_exit(void)944{945smscore_unregister_hotplug(smsdvb_hotplug);946947kmutex_lock(&g_smsdvb_clientslock);948949while (!list_empty(&g_smsdvb_clients))950smsdvb_unregister_client(951(struct smsdvb_client_t *) g_smsdvb_clients.next);952953kmutex_unlock(&g_smsdvb_clientslock);954}955956module_init(smsdvb_module_init);957module_exit(smsdvb_module_exit);958959MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");960MODULE_AUTHOR("Siano Mobile Silicon, Inc. ([email protected])");961MODULE_LICENSE("GPL");962963964