1272 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/****************************************************************3 4Siano Mobile Silicon, Inc.5MDTV receiver kernel modules.6Copyright (C) 2006-2008, Uri Shkolnik7 8 9****************************************************************/10 11#include "smscoreapi.h"12 13#include <linux/module.h>14#include <linux/slab.h>15#include <linux/init.h>16#include <asm/div64.h>17 18#include <media/dmxdev.h>19#include <media/dvbdev.h>20#include <media/dvb_demux.h>21#include <media/dvb_frontend.h>22 23#include "sms-cards.h"24 25#include "smsdvb.h"26 27DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);28 29static LIST_HEAD(g_smsdvb_clients);30static DEFINE_MUTEX(g_smsdvb_clientslock);31 32static u32 sms_to_guard_interval_table[] = {33 [0] = GUARD_INTERVAL_1_32,34 [1] = GUARD_INTERVAL_1_16,35 [2] = GUARD_INTERVAL_1_8,36 [3] = GUARD_INTERVAL_1_4,37};38 39static u32 sms_to_code_rate_table[] = {40 [0] = FEC_1_2,41 [1] = FEC_2_3,42 [2] = FEC_3_4,43 [3] = FEC_5_6,44 [4] = FEC_7_8,45};46 47 48static u32 sms_to_hierarchy_table[] = {49 [0] = HIERARCHY_NONE,50 [1] = HIERARCHY_1,51 [2] = HIERARCHY_2,52 [3] = HIERARCHY_4,53};54 55static u32 sms_to_modulation_table[] = {56 [0] = QPSK,57 [1] = QAM_16,58 [2] = QAM_64,59 [3] = DQPSK,60};61 62 63/* Events that may come from DVB v3 adapter */64static void sms_board_dvb3_event(struct smsdvb_client_t *client,65 enum SMS_DVB3_EVENTS event) {66 67 struct smscore_device_t *coredev = client->coredev;68 switch (event) {69 case DVB3_EVENT_INIT:70 pr_debug("DVB3_EVENT_INIT\n");71 sms_board_event(coredev, BOARD_EVENT_BIND);72 break;73 case DVB3_EVENT_SLEEP:74 pr_debug("DVB3_EVENT_SLEEP\n");75 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);76 break;77 case DVB3_EVENT_HOTPLUG:78 pr_debug("DVB3_EVENT_HOTPLUG\n");79 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);80 break;81 case DVB3_EVENT_FE_LOCK:82 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {83 client->event_fe_state = DVB3_EVENT_FE_LOCK;84 pr_debug("DVB3_EVENT_FE_LOCK\n");85 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);86 }87 break;88 case DVB3_EVENT_FE_UNLOCK:89 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {90 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;91 pr_debug("DVB3_EVENT_FE_UNLOCK\n");92 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);93 }94 break;95 case DVB3_EVENT_UNC_OK:96 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {97 client->event_unc_state = DVB3_EVENT_UNC_OK;98 pr_debug("DVB3_EVENT_UNC_OK\n");99 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);100 }101 break;102 case DVB3_EVENT_UNC_ERR:103 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {104 client->event_unc_state = DVB3_EVENT_UNC_ERR;105 pr_debug("DVB3_EVENT_UNC_ERR\n");106 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);107 }108 break;109 110 default:111 pr_err("Unknown dvb3 api event\n");112 break;113 }114}115 116static void smsdvb_stats_not_ready(struct dvb_frontend *fe)117{118 struct smsdvb_client_t *client =119 container_of(fe, struct smsdvb_client_t, frontend);120 struct smscore_device_t *coredev = client->coredev;121 struct dtv_frontend_properties *c = &fe->dtv_property_cache;122 int i, n_layers;123 124 switch (smscore_get_device_mode(coredev)) {125 case DEVICE_MODE_ISDBT:126 case DEVICE_MODE_ISDBT_BDA:127 n_layers = 4;128 break;129 default:130 n_layers = 1;131 }132 133 /* Global stats */134 c->strength.len = 1;135 c->cnr.len = 1;136 c->strength.stat[0].scale = FE_SCALE_DECIBEL;137 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;138 139 /* Per-layer stats */140 c->post_bit_error.len = n_layers;141 c->post_bit_count.len = n_layers;142 c->block_error.len = n_layers;143 c->block_count.len = n_layers;144 145 /*146 * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically147 * changed when the stats become available.148 */149 for (i = 0; i < n_layers; i++) {150 c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;151 c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;152 c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;153 c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;154 }155}156 157static inline int sms_to_mode(u32 mode)158{159 switch (mode) {160 case 2:161 return TRANSMISSION_MODE_2K;162 case 4:163 return TRANSMISSION_MODE_4K;164 case 8:165 return TRANSMISSION_MODE_8K;166 }167 return TRANSMISSION_MODE_AUTO;168}169 170static inline int sms_to_isdbt_mode(u32 mode)171{172 switch (mode) {173 case 1:174 return TRANSMISSION_MODE_2K;175 case 2:176 return TRANSMISSION_MODE_4K;177 case 3:178 return TRANSMISSION_MODE_8K;179 }180 return TRANSMISSION_MODE_AUTO;181}182 183static inline int sms_to_isdbt_guard_interval(u32 interval)184{185 switch (interval) {186 case 4:187 return GUARD_INTERVAL_1_4;188 case 8:189 return GUARD_INTERVAL_1_8;190 case 16:191 return GUARD_INTERVAL_1_16;192 case 32:193 return GUARD_INTERVAL_1_32;194 }195 return GUARD_INTERVAL_AUTO;196}197 198static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)199{200 if (is_demod_locked)201 return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |202 FE_HAS_SYNC | FE_HAS_LOCK;203 204 if (is_rf_locked)205 return FE_HAS_SIGNAL | FE_HAS_CARRIER;206 207 return 0;208}209 210static inline u32 sms_to_bw(u32 value)211{212 return value * 1000000;213}214 215#define convert_from_table(value, table, defval) ({ \216 u32 __ret; \217 if (value < ARRAY_SIZE(table)) \218 __ret = table[value]; \219 else \220 __ret = defval; \221 __ret; \222})223 224#define sms_to_guard_interval(value) \225 convert_from_table(value, sms_to_guard_interval_table, \226 GUARD_INTERVAL_AUTO);227 228#define sms_to_code_rate(value) \229 convert_from_table(value, sms_to_code_rate_table, \230 FEC_NONE);231 232#define sms_to_hierarchy(value) \233 convert_from_table(value, sms_to_hierarchy_table, \234 FEC_NONE);235 236#define sms_to_modulation(value) \237 convert_from_table(value, sms_to_modulation_table, \238 FEC_NONE);239 240static void smsdvb_update_tx_params(struct smsdvb_client_t *client,241 struct sms_tx_stats *p)242{243 struct dvb_frontend *fe = &client->frontend;244 struct dtv_frontend_properties *c = &fe->dtv_property_cache;245 246 c->frequency = p->frequency;247 client->fe_status = sms_to_status(p->is_demod_locked, 0);248 c->bandwidth_hz = sms_to_bw(p->bandwidth);249 c->transmission_mode = sms_to_mode(p->transmission_mode);250 c->guard_interval = sms_to_guard_interval(p->guard_interval);251 c->code_rate_HP = sms_to_code_rate(p->code_rate);252 c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);253 c->hierarchy = sms_to_hierarchy(p->hierarchy);254 c->modulation = sms_to_modulation(p->constellation);255}256 257static void smsdvb_update_per_slices(struct smsdvb_client_t *client,258 struct RECEPTION_STATISTICS_PER_SLICES_S *p)259{260 struct dvb_frontend *fe = &client->frontend;261 struct dtv_frontend_properties *c = &fe->dtv_property_cache;262 u64 tmp;263 264 client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);265 c->modulation = sms_to_modulation(p->constellation);266 267 /* signal Strength, in DBm */268 c->strength.stat[0].uvalue = p->in_band_power * 1000;269 270 /* Carrier to noise ratio, in DB */271 c->cnr.stat[0].svalue = p->snr * 1000;272 273 /* PER/BER requires demod lock */274 if (!p->is_demod_locked)275 return;276 277 /* TS PER */278 client->last_per = c->block_error.stat[0].uvalue;279 c->block_error.stat[0].scale = FE_SCALE_COUNTER;280 c->block_count.stat[0].scale = FE_SCALE_COUNTER;281 c->block_error.stat[0].uvalue += p->ets_packets;282 c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets;283 284 /* ber */285 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;286 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;287 c->post_bit_error.stat[0].uvalue += p->ber_error_count;288 c->post_bit_count.stat[0].uvalue += p->ber_bit_count;289 290 /* Legacy PER/BER */291 tmp = p->ets_packets * 65535ULL;292 if (p->ts_packets + p->ets_packets)293 do_div(tmp, p->ts_packets + p->ets_packets);294 client->legacy_per = tmp;295}296 297static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,298 struct sms_stats *p)299{300 struct dvb_frontend *fe = &client->frontend;301 struct dtv_frontend_properties *c = &fe->dtv_property_cache;302 303 if (client->prt_dvb_stats)304 client->prt_dvb_stats(client->debug_data, p);305 306 client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);307 308 /* Update DVB modulation parameters */309 c->frequency = p->frequency;310 client->fe_status = sms_to_status(p->is_demod_locked, 0);311 c->bandwidth_hz = sms_to_bw(p->bandwidth);312 c->transmission_mode = sms_to_mode(p->transmission_mode);313 c->guard_interval = sms_to_guard_interval(p->guard_interval);314 c->code_rate_HP = sms_to_code_rate(p->code_rate);315 c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);316 c->hierarchy = sms_to_hierarchy(p->hierarchy);317 c->modulation = sms_to_modulation(p->constellation);318 319 /* update reception data */320 c->lna = p->is_external_lna_on ? 1 : 0;321 322 /* Carrier to noise ratio, in DB */323 c->cnr.stat[0].svalue = p->SNR * 1000;324 325 /* signal Strength, in DBm */326 c->strength.stat[0].uvalue = p->in_band_pwr * 1000;327 328 /* PER/BER requires demod lock */329 if (!p->is_demod_locked)330 return;331 332 /* TS PER */333 client->last_per = c->block_error.stat[0].uvalue;334 c->block_error.stat[0].scale = FE_SCALE_COUNTER;335 c->block_count.stat[0].scale = FE_SCALE_COUNTER;336 c->block_error.stat[0].uvalue += p->error_ts_packets;337 c->block_count.stat[0].uvalue += p->total_ts_packets;338 339 /* ber */340 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;341 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;342 c->post_bit_error.stat[0].uvalue += p->ber_error_count;343 c->post_bit_count.stat[0].uvalue += p->ber_bit_count;344 345 /* Legacy PER/BER */346 client->legacy_ber = p->ber;347};348 349static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,350 struct sms_isdbt_stats *p)351{352 struct dvb_frontend *fe = &client->frontend;353 struct dtv_frontend_properties *c = &fe->dtv_property_cache;354 struct sms_isdbt_layer_stats *lr;355 int i, n_layers;356 357 if (client->prt_isdb_stats)358 client->prt_isdb_stats(client->debug_data, p);359 360 client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);361 362 /*363 * Firmware 2.1 seems to report only lock status and364 * signal strength. The signal strength indicator is at the365 * wrong field.366 */367 if (p->statistics_type == 0) {368 c->strength.stat[0].uvalue = ((s32)p->transmission_mode) * 1000;369 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;370 return;371 }372 373 /* Update ISDB-T transmission parameters */374 c->frequency = p->frequency;375 c->bandwidth_hz = sms_to_bw(p->bandwidth);376 c->transmission_mode = sms_to_isdbt_mode(p->transmission_mode);377 c->guard_interval = sms_to_isdbt_guard_interval(p->guard_interval);378 c->isdbt_partial_reception = p->partial_reception ? 1 : 0;379 n_layers = p->num_of_layers;380 if (n_layers < 1)381 n_layers = 1;382 if (n_layers > 3)383 n_layers = 3;384 c->isdbt_layer_enabled = 0;385 386 /* update reception data */387 c->lna = p->is_external_lna_on ? 1 : 0;388 389 /* Carrier to noise ratio, in DB */390 c->cnr.stat[0].svalue = p->SNR * 1000;391 392 /* signal Strength, in DBm */393 c->strength.stat[0].uvalue = p->in_band_pwr * 1000;394 395 /* PER/BER and per-layer stats require demod lock */396 if (!p->is_demod_locked)397 return;398 399 client->last_per = c->block_error.stat[0].uvalue;400 401 /* Clears global counters, as the code below will sum it again */402 c->block_error.stat[0].uvalue = 0;403 c->block_count.stat[0].uvalue = 0;404 c->block_error.stat[0].scale = FE_SCALE_COUNTER;405 c->block_count.stat[0].scale = FE_SCALE_COUNTER;406 c->post_bit_error.stat[0].uvalue = 0;407 c->post_bit_count.stat[0].uvalue = 0;408 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;409 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;410 411 for (i = 0; i < n_layers; i++) {412 lr = &p->layer_info[i];413 414 /* Update per-layer transmission parameters */415 if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {416 c->isdbt_layer_enabled |= 1 << i;417 c->layer[i].segment_count = lr->number_of_segments;418 } else {419 continue;420 }421 c->layer[i].modulation = sms_to_modulation(lr->constellation);422 c->layer[i].fec = sms_to_code_rate(lr->code_rate);423 424 /* Time interleaving */425 c->layer[i].interleaving = (u8)lr->ti_ldepth_i;426 427 /* TS PER */428 c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;429 c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;430 c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;431 c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;432 433 /* Update global PER counter */434 c->block_error.stat[0].uvalue += lr->error_ts_packets;435 c->block_count.stat[0].uvalue += lr->total_ts_packets;436 437 /* BER */438 c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;439 c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;440 c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;441 c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;442 443 /* Update global BER counter */444 c->post_bit_error.stat[0].uvalue += lr->ber_error_count;445 c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;446 }447}448 449static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,450 struct sms_isdbt_stats_ex *p)451{452 struct dvb_frontend *fe = &client->frontend;453 struct dtv_frontend_properties *c = &fe->dtv_property_cache;454 struct sms_isdbt_layer_stats *lr;455 int i, n_layers;456 457 if (client->prt_isdb_stats_ex)458 client->prt_isdb_stats_ex(client->debug_data, p);459 460 /* Update ISDB-T transmission parameters */461 c->frequency = p->frequency;462 client->fe_status = sms_to_status(p->is_demod_locked, 0);463 c->bandwidth_hz = sms_to_bw(p->bandwidth);464 c->transmission_mode = sms_to_isdbt_mode(p->transmission_mode);465 c->guard_interval = sms_to_isdbt_guard_interval(p->guard_interval);466 c->isdbt_partial_reception = p->partial_reception ? 1 : 0;467 n_layers = p->num_of_layers;468 if (n_layers < 1)469 n_layers = 1;470 if (n_layers > 3)471 n_layers = 3;472 c->isdbt_layer_enabled = 0;473 474 /* update reception data */475 c->lna = p->is_external_lna_on ? 1 : 0;476 477 /* Carrier to noise ratio, in DB */478 c->cnr.stat[0].svalue = p->SNR * 1000;479 480 /* signal Strength, in DBm */481 c->strength.stat[0].uvalue = p->in_band_pwr * 1000;482 483 /* PER/BER and per-layer stats require demod lock */484 if (!p->is_demod_locked)485 return;486 487 client->last_per = c->block_error.stat[0].uvalue;488 489 /* Clears global counters, as the code below will sum it again */490 c->block_error.stat[0].uvalue = 0;491 c->block_count.stat[0].uvalue = 0;492 c->block_error.stat[0].scale = FE_SCALE_COUNTER;493 c->block_count.stat[0].scale = FE_SCALE_COUNTER;494 c->post_bit_error.stat[0].uvalue = 0;495 c->post_bit_count.stat[0].uvalue = 0;496 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;497 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;498 499 c->post_bit_error.len = n_layers + 1;500 c->post_bit_count.len = n_layers + 1;501 c->block_error.len = n_layers + 1;502 c->block_count.len = n_layers + 1;503 for (i = 0; i < n_layers; i++) {504 lr = &p->layer_info[i];505 506 /* Update per-layer transmission parameters */507 if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {508 c->isdbt_layer_enabled |= 1 << i;509 c->layer[i].segment_count = lr->number_of_segments;510 } else {511 continue;512 }513 c->layer[i].modulation = sms_to_modulation(lr->constellation);514 c->layer[i].fec = sms_to_code_rate(lr->code_rate);515 516 /* Time interleaving */517 c->layer[i].interleaving = (u8)lr->ti_ldepth_i;518 519 /* TS PER */520 c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;521 c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;522 c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;523 c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;524 525 /* Update global PER counter */526 c->block_error.stat[0].uvalue += lr->error_ts_packets;527 c->block_count.stat[0].uvalue += lr->total_ts_packets;528 529 /* ber */530 c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;531 c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;532 c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;533 c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;534 535 /* Update global ber counter */536 c->post_bit_error.stat[0].uvalue += lr->ber_error_count;537 c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;538 }539}540 541static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)542{543 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;544 struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) (((u8 *) cb->p)545 + cb->offset);546 void *p = phdr + 1;547 struct dvb_frontend *fe = &client->frontend;548 struct dtv_frontend_properties *c = &fe->dtv_property_cache;549 bool is_status_update = false;550 551 switch (phdr->msg_type) {552 case MSG_SMS_DVBT_BDA_DATA:553 /*554 * Only feed data to dvb demux if are there any feed listening555 * to it and if the device has tuned556 */557 if (client->feed_users && client->has_tuned)558 dvb_dmx_swfilter(&client->demux, p,559 cb->size - sizeof(struct sms_msg_hdr));560 break;561 562 case MSG_SMS_RF_TUNE_RES:563 case MSG_SMS_ISDBT_TUNE_RES:564 complete(&client->tune_done);565 break;566 567 case MSG_SMS_SIGNAL_DETECTED_IND:568 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |569 FE_HAS_VITERBI | FE_HAS_SYNC |570 FE_HAS_LOCK;571 572 is_status_update = true;573 break;574 575 case MSG_SMS_NO_SIGNAL_IND:576 client->fe_status = 0;577 578 is_status_update = true;579 break;580 581 case MSG_SMS_TRANSMISSION_IND:582 smsdvb_update_tx_params(client, p);583 584 is_status_update = true;585 break;586 587 case MSG_SMS_HO_PER_SLICES_IND:588 smsdvb_update_per_slices(client, p);589 590 is_status_update = true;591 break;592 593 case MSG_SMS_GET_STATISTICS_RES:594 switch (smscore_get_device_mode(client->coredev)) {595 case DEVICE_MODE_ISDBT:596 case DEVICE_MODE_ISDBT_BDA:597 smsdvb_update_isdbt_stats(client, p);598 break;599 default:600 /* Skip sms_msg_statistics_info:request_result field */601 smsdvb_update_dvb_stats(client, p + sizeof(u32));602 }603 604 is_status_update = true;605 break;606 607 /* Only for ISDB-T */608 case MSG_SMS_GET_STATISTICS_EX_RES:609 /* Skip sms_msg_statistics_info:request_result field? */610 smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));611 is_status_update = true;612 break;613 default:614 pr_debug("message not handled\n");615 }616 smscore_putbuffer(client->coredev, cb);617 618 if (is_status_update) {619 if (client->fe_status & FE_HAS_LOCK) {620 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);621 if (client->last_per == c->block_error.stat[0].uvalue)622 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);623 else624 sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);625 client->has_tuned = true;626 } else {627 smsdvb_stats_not_ready(fe);628 client->has_tuned = false;629 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);630 }631 complete(&client->stats_done);632 }633 634 return 0;635}636 637static void smsdvb_media_device_unregister(struct smsdvb_client_t *client)638{639#ifdef CONFIG_MEDIA_CONTROLLER_DVB640 struct smscore_device_t *coredev = client->coredev;641 642 if (!coredev->media_dev)643 return;644 media_device_unregister(coredev->media_dev);645 media_device_cleanup(coredev->media_dev);646 kfree(coredev->media_dev);647 coredev->media_dev = NULL;648#endif649}650 651static void smsdvb_unregister_client(struct smsdvb_client_t *client)652{653 /* must be called under clientslock */654 655 list_del(&client->entry);656 657 smsdvb_debugfs_release(client);658 smscore_unregister_client(client->smsclient);659 dvb_unregister_frontend(&client->frontend);660 dvb_dmxdev_release(&client->dmxdev);661 dvb_dmx_release(&client->demux);662 smsdvb_media_device_unregister(client);663 dvb_unregister_adapter(&client->adapter);664 kfree(client);665}666 667static void smsdvb_onremove(void *context)668{669 mutex_lock(&g_smsdvb_clientslock);670 671 smsdvb_unregister_client((struct smsdvb_client_t *) context);672 673 mutex_unlock(&g_smsdvb_clientslock);674}675 676static int smsdvb_start_feed(struct dvb_demux_feed *feed)677{678 struct smsdvb_client_t *client =679 container_of(feed->demux, struct smsdvb_client_t, demux);680 struct sms_msg_data pid_msg;681 682 pr_debug("add pid %d(%x)\n",683 feed->pid, feed->pid);684 685 client->feed_users++;686 687 pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;688 pid_msg.x_msg_header.msg_dst_id = HIF_TASK;689 pid_msg.x_msg_header.msg_flags = 0;690 pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ;691 pid_msg.x_msg_header.msg_length = sizeof(pid_msg);692 pid_msg.msg_data = feed->pid;693 694 return smsclient_sendrequest(client->smsclient,695 &pid_msg, sizeof(pid_msg));696}697 698static int smsdvb_stop_feed(struct dvb_demux_feed *feed)699{700 struct smsdvb_client_t *client =701 container_of(feed->demux, struct smsdvb_client_t, demux);702 struct sms_msg_data pid_msg;703 704 pr_debug("remove pid %d(%x)\n",705 feed->pid, feed->pid);706 707 client->feed_users--;708 709 pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;710 pid_msg.x_msg_header.msg_dst_id = HIF_TASK;711 pid_msg.x_msg_header.msg_flags = 0;712 pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ;713 pid_msg.x_msg_header.msg_length = sizeof(pid_msg);714 pid_msg.msg_data = feed->pid;715 716 return smsclient_sendrequest(client->smsclient,717 &pid_msg, sizeof(pid_msg));718}719 720static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,721 void *buffer, size_t size,722 struct completion *completion)723{724 int rc;725 726 rc = smsclient_sendrequest(client->smsclient, buffer, size);727 if (rc < 0)728 return rc;729 730 return wait_for_completion_timeout(completion,731 msecs_to_jiffies(2000)) ?732 0 : -ETIME;733}734 735static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)736{737 int rc;738 struct sms_msg_hdr msg;739 740 /* Don't request stats too fast */741 if (client->get_stats_jiffies &&742 (!time_after(jiffies, client->get_stats_jiffies)))743 return 0;744 client->get_stats_jiffies = jiffies + msecs_to_jiffies(100);745 746 msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;747 msg.msg_dst_id = HIF_TASK;748 msg.msg_flags = 0;749 msg.msg_length = sizeof(msg);750 751 switch (smscore_get_device_mode(client->coredev)) {752 case DEVICE_MODE_ISDBT:753 case DEVICE_MODE_ISDBT_BDA:754 /*755 * Check for firmware version, to avoid breaking for old cards756 */757 if (client->coredev->fw_version >= 0x800)758 msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ;759 else760 msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;761 break;762 default:763 msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;764 }765 766 rc = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),767 &client->stats_done);768 769 return rc;770}771 772static inline int led_feedback(struct smsdvb_client_t *client)773{774 if (!(client->fe_status & FE_HAS_LOCK))775 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);776 777 return sms_board_led_feedback(client->coredev,778 (client->legacy_ber == 0) ?779 SMS_LED_HI : SMS_LED_LO);780}781 782static int smsdvb_read_status(struct dvb_frontend *fe, enum fe_status *stat)783{784 int rc;785 struct smsdvb_client_t *client;786 client = container_of(fe, struct smsdvb_client_t, frontend);787 788 rc = smsdvb_send_statistics_request(client);789 790 *stat = client->fe_status;791 792 led_feedback(client);793 794 return rc;795}796 797static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)798{799 int rc;800 struct smsdvb_client_t *client;801 802 client = container_of(fe, struct smsdvb_client_t, frontend);803 804 rc = smsdvb_send_statistics_request(client);805 806 *ber = client->legacy_ber;807 808 led_feedback(client);809 810 return rc;811}812 813static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)814{815 struct dtv_frontend_properties *c = &fe->dtv_property_cache;816 int rc;817 s32 power = (s32) c->strength.stat[0].uvalue;818 struct smsdvb_client_t *client;819 820 client = container_of(fe, struct smsdvb_client_t, frontend);821 822 rc = smsdvb_send_statistics_request(client);823 824 if (power < -95)825 *strength = 0;826 else if (power > -29)827 *strength = 65535;828 else829 *strength = (power + 95) * 65535 / 66;830 831 led_feedback(client);832 833 return rc;834}835 836static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)837{838 struct dtv_frontend_properties *c = &fe->dtv_property_cache;839 int rc;840 struct smsdvb_client_t *client;841 842 client = container_of(fe, struct smsdvb_client_t, frontend);843 844 rc = smsdvb_send_statistics_request(client);845 846 /* Preferred scale for SNR with legacy API: 0.1 dB */847 *snr = ((u32)c->cnr.stat[0].svalue) / 100;848 849 led_feedback(client);850 851 return rc;852}853 854static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)855{856 int rc;857 struct dtv_frontend_properties *c = &fe->dtv_property_cache;858 struct smsdvb_client_t *client;859 860 client = container_of(fe, struct smsdvb_client_t, frontend);861 862 rc = smsdvb_send_statistics_request(client);863 864 *ucblocks = c->block_error.stat[0].uvalue;865 866 led_feedback(client);867 868 return rc;869}870 871static int smsdvb_get_tune_settings(struct dvb_frontend *fe,872 struct dvb_frontend_tune_settings *tune)873{874 pr_debug("\n");875 876 tune->min_delay_ms = 400;877 tune->step_size = 250000;878 tune->max_drift = 0;879 return 0;880}881 882static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)883{884 struct dtv_frontend_properties *c = &fe->dtv_property_cache;885 struct smsdvb_client_t *client =886 container_of(fe, struct smsdvb_client_t, frontend);887 888 struct {889 struct sms_msg_hdr msg;890 u32 Data[3];891 } msg;892 893 int ret;894 895 client->fe_status = 0;896 client->event_fe_state = -1;897 client->event_unc_state = -1;898 fe->dtv_property_cache.delivery_system = SYS_DVBT;899 900 msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;901 msg.msg.msg_dst_id = HIF_TASK;902 msg.msg.msg_flags = 0;903 msg.msg.msg_type = MSG_SMS_RF_TUNE_REQ;904 msg.msg.msg_length = sizeof(msg);905 msg.Data[0] = c->frequency;906 msg.Data[2] = 12000000;907 908 pr_debug("%s: freq %d band %d\n", __func__, c->frequency,909 c->bandwidth_hz);910 911 switch (c->bandwidth_hz / 1000000) {912 case 8:913 msg.Data[1] = BW_8_MHZ;914 break;915 case 7:916 msg.Data[1] = BW_7_MHZ;917 break;918 case 6:919 msg.Data[1] = BW_6_MHZ;920 break;921 case 0:922 return -EOPNOTSUPP;923 default:924 return -EINVAL;925 }926 /* Disable LNA, if any. An error is returned if no LNA is present */927 ret = sms_board_lna_control(client->coredev, 0);928 if (ret == 0) {929 enum fe_status status;930 931 /* tune with LNA off at first */932 ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),933 &client->tune_done);934 935 smsdvb_read_status(fe, &status);936 937 if (status & FE_HAS_LOCK)938 return ret;939 940 /* previous tune didn't lock - enable LNA and tune again */941 sms_board_lna_control(client->coredev, 1);942 }943 944 return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),945 &client->tune_done);946}947 948static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)949{950 struct dtv_frontend_properties *c = &fe->dtv_property_cache;951 struct smsdvb_client_t *client =952 container_of(fe, struct smsdvb_client_t, frontend);953 int board_id = smscore_get_board_id(client->coredev);954 struct sms_board *board = sms_get_board(board_id);955 enum sms_device_type_st type = board->type;956 int ret;957 958 struct {959 struct sms_msg_hdr msg;960 u32 Data[4];961 } msg;962 963 fe->dtv_property_cache.delivery_system = SYS_ISDBT;964 965 msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;966 msg.msg.msg_dst_id = HIF_TASK;967 msg.msg.msg_flags = 0;968 msg.msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ;969 msg.msg.msg_length = sizeof(msg);970 971 if (c->isdbt_sb_segment_idx == -1)972 c->isdbt_sb_segment_idx = 0;973 974 if (!c->isdbt_layer_enabled)975 c->isdbt_layer_enabled = 7;976 977 msg.Data[0] = c->frequency;978 msg.Data[1] = BW_ISDBT_1SEG;979 msg.Data[2] = 12000000;980 msg.Data[3] = c->isdbt_sb_segment_idx;981 982 if (c->isdbt_partial_reception) {983 if ((type == SMS_PELE || type == SMS_RIO) &&984 c->isdbt_sb_segment_count > 3)985 msg.Data[1] = BW_ISDBT_13SEG;986 else if (c->isdbt_sb_segment_count > 1)987 msg.Data[1] = BW_ISDBT_3SEG;988 } else if (type == SMS_PELE || type == SMS_RIO)989 msg.Data[1] = BW_ISDBT_13SEG;990 991 c->bandwidth_hz = 6000000;992 993 pr_debug("freq %d segwidth %d segindex %d\n",994 c->frequency, c->isdbt_sb_segment_count,995 c->isdbt_sb_segment_idx);996 997 /* Disable LNA, if any. An error is returned if no LNA is present */998 ret = sms_board_lna_control(client->coredev, 0);999 if (ret == 0) {1000 enum fe_status status;1001 1002 /* tune with LNA off at first */1003 ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),1004 &client->tune_done);1005 1006 smsdvb_read_status(fe, &status);1007 1008 if (status & FE_HAS_LOCK)1009 return ret;1010 1011 /* previous tune didn't lock - enable LNA and tune again */1012 sms_board_lna_control(client->coredev, 1);1013 }1014 return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),1015 &client->tune_done);1016}1017 1018static int smsdvb_set_frontend(struct dvb_frontend *fe)1019{1020 struct dtv_frontend_properties *c = &fe->dtv_property_cache;1021 struct smsdvb_client_t *client =1022 container_of(fe, struct smsdvb_client_t, frontend);1023 struct smscore_device_t *coredev = client->coredev;1024 1025 smsdvb_stats_not_ready(fe);1026 c->strength.stat[0].uvalue = 0;1027 c->cnr.stat[0].uvalue = 0;1028 1029 client->has_tuned = false;1030 1031 switch (smscore_get_device_mode(coredev)) {1032 case DEVICE_MODE_DVBT:1033 case DEVICE_MODE_DVBT_BDA:1034 return smsdvb_dvbt_set_frontend(fe);1035 case DEVICE_MODE_ISDBT:1036 case DEVICE_MODE_ISDBT_BDA:1037 return smsdvb_isdbt_set_frontend(fe);1038 default:1039 return -EINVAL;1040 }1041}1042 1043static int smsdvb_init(struct dvb_frontend *fe)1044{1045 struct smsdvb_client_t *client =1046 container_of(fe, struct smsdvb_client_t, frontend);1047 1048 sms_board_power(client->coredev, 1);1049 1050 sms_board_dvb3_event(client, DVB3_EVENT_INIT);1051 return 0;1052}1053 1054static int smsdvb_sleep(struct dvb_frontend *fe)1055{1056 struct smsdvb_client_t *client =1057 container_of(fe, struct smsdvb_client_t, frontend);1058 1059 sms_board_led_feedback(client->coredev, SMS_LED_OFF);1060 sms_board_power(client->coredev, 0);1061 1062 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);1063 1064 return 0;1065}1066 1067static void smsdvb_release(struct dvb_frontend *fe)1068{1069 /* do nothing */1070}1071 1072static const struct dvb_frontend_ops smsdvb_fe_ops = {1073 .info = {1074 .name = "Siano Mobile Digital MDTV Receiver",1075 .frequency_min_hz = 44250 * kHz,1076 .frequency_max_hz = 867250 * kHz,1077 .frequency_stepsize_hz = 250 * kHz,1078 .caps = FE_CAN_INVERSION_AUTO |1079 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |1080 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |1081 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |1082 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |1083 FE_CAN_GUARD_INTERVAL_AUTO |1084 FE_CAN_RECOVER |1085 FE_CAN_HIERARCHY_AUTO,1086 },1087 1088 .release = smsdvb_release,1089 1090 .set_frontend = smsdvb_set_frontend,1091 .get_tune_settings = smsdvb_get_tune_settings,1092 1093 .read_status = smsdvb_read_status,1094 .read_ber = smsdvb_read_ber,1095 .read_signal_strength = smsdvb_read_signal_strength,1096 .read_snr = smsdvb_read_snr,1097 .read_ucblocks = smsdvb_read_ucblocks,1098 1099 .init = smsdvb_init,1100 .sleep = smsdvb_sleep,1101};1102 1103static int smsdvb_hotplug(struct smscore_device_t *coredev,1104 struct device *device, int arrival)1105{1106 struct smsclient_params_t params;1107 struct smsdvb_client_t *client;1108 int rc;1109 1110 /* device removal handled by onremove callback */1111 if (!arrival)1112 return 0;1113 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);1114 if (!client)1115 return -ENOMEM;1116 1117 /* register dvb adapter */1118 rc = dvb_register_adapter(&client->adapter,1119 sms_get_board(1120 smscore_get_board_id(coredev))->name,1121 THIS_MODULE, device, adapter_nr);1122 if (rc < 0) {1123 pr_err("dvb_register_adapter() failed %d\n", rc);1124 goto adapter_error;1125 }1126 dvb_register_media_controller(&client->adapter, coredev->media_dev);1127 1128 /* init dvb demux */1129 client->demux.dmx.capabilities = DMX_TS_FILTERING;1130 client->demux.filternum = 32; /* todo: nova ??? */1131 client->demux.feednum = 32;1132 client->demux.start_feed = smsdvb_start_feed;1133 client->demux.stop_feed = smsdvb_stop_feed;1134 1135 rc = dvb_dmx_init(&client->demux);1136 if (rc < 0) {1137 pr_err("dvb_dmx_init failed %d\n", rc);1138 goto dvbdmx_error;1139 }1140 1141 /* init dmxdev */1142 client->dmxdev.filternum = 32;1143 client->dmxdev.demux = &client->demux.dmx;1144 client->dmxdev.capabilities = 0;1145 1146 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);1147 if (rc < 0) {1148 pr_err("dvb_dmxdev_init failed %d\n", rc);1149 goto dmxdev_error;1150 }1151 1152 /* init and register frontend */1153 memcpy(&client->frontend.ops, &smsdvb_fe_ops,1154 sizeof(struct dvb_frontend_ops));1155 1156 switch (smscore_get_device_mode(coredev)) {1157 case DEVICE_MODE_DVBT:1158 case DEVICE_MODE_DVBT_BDA:1159 client->frontend.ops.delsys[0] = SYS_DVBT;1160 break;1161 case DEVICE_MODE_ISDBT:1162 case DEVICE_MODE_ISDBT_BDA:1163 client->frontend.ops.delsys[0] = SYS_ISDBT;1164 break;1165 }1166 1167 rc = dvb_register_frontend(&client->adapter, &client->frontend);1168 if (rc < 0) {1169 pr_err("frontend registration failed %d\n", rc);1170 goto frontend_error;1171 }1172 1173 params.initial_id = 1;1174 params.data_type = MSG_SMS_DVBT_BDA_DATA;1175 params.onresponse_handler = smsdvb_onresponse;1176 params.onremove_handler = smsdvb_onremove;1177 params.context = client;1178 1179 rc = smscore_register_client(coredev, ¶ms, &client->smsclient);1180 if (rc < 0) {1181 pr_err("smscore_register_client() failed %d\n", rc);1182 goto client_error;1183 }1184 1185 client->coredev = coredev;1186 1187 init_completion(&client->tune_done);1188 init_completion(&client->stats_done);1189 1190 mutex_lock(&g_smsdvb_clientslock);1191 1192 list_add(&client->entry, &g_smsdvb_clients);1193 1194 mutex_unlock(&g_smsdvb_clientslock);1195 1196 client->event_fe_state = -1;1197 client->event_unc_state = -1;1198 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);1199 1200 sms_board_setup(coredev);1201 1202 if (smsdvb_debugfs_create(client) < 0)1203 pr_info("failed to create debugfs node\n");1204 1205 rc = dvb_create_media_graph(&client->adapter, true);1206 if (rc < 0) {1207 pr_err("dvb_create_media_graph failed %d\n", rc);1208 goto media_graph_error;1209 }1210 1211 pr_info("DVB interface registered.\n");1212 return 0;1213 1214media_graph_error:1215 mutex_lock(&g_smsdvb_clientslock);1216 list_del(&client->entry);1217 mutex_unlock(&g_smsdvb_clientslock);1218 1219 smsdvb_debugfs_release(client);1220 1221client_error:1222 dvb_unregister_frontend(&client->frontend);1223 1224frontend_error:1225 dvb_dmxdev_release(&client->dmxdev);1226 1227dmxdev_error:1228 dvb_dmx_release(&client->demux);1229 1230dvbdmx_error:1231 smsdvb_media_device_unregister(client);1232 dvb_unregister_adapter(&client->adapter);1233 1234adapter_error:1235 kfree(client);1236 return rc;1237}1238 1239static int __init smsdvb_module_init(void)1240{1241 int rc;1242 1243 smsdvb_debugfs_register();1244 1245 rc = smscore_register_hotplug(smsdvb_hotplug);1246 1247 pr_debug("\n");1248 1249 return rc;1250}1251 1252static void __exit smsdvb_module_exit(void)1253{1254 smscore_unregister_hotplug(smsdvb_hotplug);1255 1256 mutex_lock(&g_smsdvb_clientslock);1257 1258 while (!list_empty(&g_smsdvb_clients))1259 smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);1260 1261 smsdvb_debugfs_unregister();1262 1263 mutex_unlock(&g_smsdvb_clientslock);1264}1265 1266module_init(smsdvb_module_init);1267module_exit(smsdvb_module_exit);1268 1269MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");1270MODULE_AUTHOR("Siano Mobile Silicon, Inc. <uris@siano-ms.com>");1271MODULE_LICENSE("GPL");1272