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