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, ¶ms, &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