V4L/DVB (11782): Siano: smsdvb - use 'push' status mechanism

This patch replace the old method of pulling the device status by
sending "get_statistics" request, to push mode. This make status update
much faster, and reduce various operation time (UHF scan now takes 15s
instead of 2m). In order to make the change the following modification
have been applied:
1) core header - update statistics headers.
2) dvb adapter - omit the statistics request, add handling of
status indications.
3) core 'onresponse' - re-route messages addressed to other adapter
to the dvb adapter.

Signed-off-by: Uri Shkolnik <uris@siano-ms.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
index 8fb283b..881f5c5 100644
--- a/drivers/media/dvb/siano/smsdvb.c
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -40,12 +40,15 @@
 	struct dvb_frontend     frontend;
 
 	fe_status_t             fe_status;
-	int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
 
-	struct completion       tune_done, stat_done;
+	struct completion       tune_done;
 
 	/* todo: save freq/band instead whole struct */
 	struct dvb_frontend_parameters fe_params;
+
+	struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
+	int event_fe_state;
+	int event_unc_state;
 };
 
 static struct list_head g_smsdvb_clients;
@@ -55,11 +58,19 @@
 module_param_named(debug, sms_dbg, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 
+/* Events that may come from DVB v3 adapter */
+static void sms_board_dvb3_event(struct smsdvb_client_t *client,
+		enum SMS_DVB3_EVENTS event) {
+}
+
 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 {
 	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
-	struct SmsMsgHdr_ST *phdr =
-		(struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
+	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
+			+ cb->offset);
+	u32 *pMsgData = (u32 *) phdr + 1;
+	/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
+	bool is_status_update = false;
 
 	smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
 
@@ -73,43 +84,110 @@
 		complete(&client->tune_done);
 		break;
 
-	case MSG_SMS_GET_STATISTICS_RES:
-	{
-		struct SmsMsgStatisticsInfo_ST *p =
-			(struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
+	case MSG_SMS_SIGNAL_DETECTED_IND:
+		sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
+		client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
+		is_status_update = true;
+		break;
 
-		if (p->Stat.IsDemodLocked) {
-			client->fe_status = FE_HAS_SIGNAL |
-					    FE_HAS_CARRIER |
-					    FE_HAS_VITERBI |
-					    FE_HAS_SYNC |
-					    FE_HAS_LOCK;
+	case MSG_SMS_NO_SIGNAL_IND:
+		sms_info("MSG_SMS_NO_SIGNAL_IND");
+		client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
+		is_status_update = true;
+		break;
 
-			client->fe_snr = p->Stat.SNR;
-			client->fe_ber = p->Stat.BER;
-			client->fe_unc = p->Stat.BERErrorCount;
+	case MSG_SMS_TRANSMISSION_IND: {
+		sms_info("MSG_SMS_TRANSMISSION_IND");
 
-			if (p->Stat.InBandPwr < -95)
-				client->fe_signal_strength = 0;
-			else if (p->Stat.InBandPwr > -29)
-				client->fe_signal_strength = 100;
-			else
-				client->fe_signal_strength =
-					(p->Stat.InBandPwr + 95) * 3 / 2;
+		pMsgData++;
+		memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
+				sizeof(struct TRANSMISSION_STATISTICS_S));
+
+		/* Mo need to correct guard interval
+		 * (as opposed to old statistics message).
+		 */
+		CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
+		CORRECT_STAT_TRANSMISSON_MODE(
+				client->sms_stat_dvb.TransmissionData);
+		is_status_update = true;
+		break;
+	}
+	case MSG_SMS_HO_PER_SLICES_IND: {
+		struct RECEPTION_STATISTICS_S *pReceptionData =
+				&client->sms_stat_dvb.ReceptionData;
+		struct SRVM_SIGNAL_STATUS_S SignalStatusData;
+
+		/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
+		pMsgData++;
+		SignalStatusData.result = pMsgData[0];
+		SignalStatusData.snr = pMsgData[1];
+		SignalStatusData.inBandPower = (s32) pMsgData[2];
+		SignalStatusData.tsPackets = pMsgData[3];
+		SignalStatusData.etsPackets = pMsgData[4];
+		SignalStatusData.constellation = pMsgData[5];
+		SignalStatusData.hpCode = pMsgData[6];
+		SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
+		SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
+		SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
+		SignalStatusData.reason = pMsgData[10];
+		SignalStatusData.requestId = pMsgData[11];
+		pReceptionData->IsRfLocked = pMsgData[16];
+		pReceptionData->IsDemodLocked = pMsgData[17];
+		pReceptionData->ModemState = pMsgData[12];
+		pReceptionData->SNR = pMsgData[1];
+		pReceptionData->BER = pMsgData[13];
+		pReceptionData->RSSI = pMsgData[14];
+		CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
+
+		pReceptionData->InBandPwr = (s32) pMsgData[2];
+		pReceptionData->CarrierOffset = (s32) pMsgData[15];
+		pReceptionData->TotalTSPackets = pMsgData[3];
+		pReceptionData->ErrorTSPackets = pMsgData[4];
+
+		/* TS PER */
+		if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
+				> 0) {
+			pReceptionData->TS_PER = (SignalStatusData.etsPackets
+					* 100) / (SignalStatusData.tsPackets
+					+ SignalStatusData.etsPackets);
 		} else {
-			client->fe_status = 0;
-			client->fe_snr =
-			client->fe_ber =
-			client->fe_unc =
-			client->fe_signal_strength = 0;
+			pReceptionData->TS_PER = 0;
 		}
 
-		complete(&client->stat_done);
-		break;
-	} }
+		pReceptionData->BERBitCount = pMsgData[18];
+		pReceptionData->BERErrorCount = pMsgData[19];
 
+		pReceptionData->MRC_SNR = pMsgData[20];
+		pReceptionData->MRC_InBandPwr = pMsgData[21];
+		pReceptionData->MRC_RSSI = pMsgData[22];
+
+		is_status_update = true;
+		break;
+	}
+	}
 	smscore_putbuffer(client->coredev, cb);
 
+	if (is_status_update) {
+		if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
+			client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
+				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+			sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
+			if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
+					== 0)
+				sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
+			else
+				sms_board_dvb3_event(client,
+						DVB3_EVENT_UNC_ERR);
+
+		} else {
+			/*client->fe_status =
+				(phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
+				0 : FE_HAS_SIGNAL;*/
+			client->fe_status = 0;
+			sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
+		}
+	}
+
 	return 0;
 }
 
@@ -194,83 +272,61 @@
 						0 : -ETIME;
 }
 
-static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
-{
-	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
-			     DVBT_BDA_CONTROL_MSG_ID,
-			     HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
-	int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-					      &client->stat_done);
-	if (ret < 0)
-		return ret;
-
-	if (client->fe_status & FE_HAS_LOCK)
-		sms_board_led_feedback(client->coredev,
-				       (client->fe_unc == 0) ?
-				       SMS_LED_HI : SMS_LED_LO);
-	else
-		sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-	return ret;
-}
-
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
-	if (!rc)
-		*stat = client->fe_status;
+	*stat = client->fe_status;
 
-	return rc;
+	return 0;
 }
 
 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
-	if (!rc)
-		*ber = client->fe_ber;
+	*ber = client->sms_stat_dvb.ReceptionData.BER;
 
-	return rc;
+	return 0;
 }
 
 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
-	if (!rc)
-		*strength = client->fe_signal_strength;
+	if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
+		*strength = 0;
+		else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
+			*strength = 100;
+		else
+			*strength =
+				(client->sms_stat_dvb.ReceptionData.InBandPwr
+				+ 95) * 3 / 2;
 
-	return rc;
+	return 0;
 }
 
 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
-	if (!rc)
-		*snr = client->fe_snr;
+	*snr = client->sms_stat_dvb.ReceptionData.SNR;
 
-	return rc;
+	return 0;
 }
 
 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-	struct smsdvb_client_t *client =
-		container_of(fe, struct smsdvb_client_t, frontend);
-	int rc = smsdvb_send_statistics_request(client);
+	struct smsdvb_client_t *client;
+	client = container_of(fe, struct smsdvb_client_t, frontend);
 
-	if (!rc)
-		*ucblocks = client->fe_unc;
+	*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
 
-	return rc;
+	return 0;
 }
 
 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@@ -294,12 +350,15 @@
 		struct SmsMsgHdr_ST	Msg;
 		u32		Data[3];
 	} Msg;
-	int ret;
 
-	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
-	Msg.Msg.msgDstId  = HIF_TASK;
-	Msg.Msg.msgFlags  = 0;
-	Msg.Msg.msgType   = MSG_SMS_RF_TUNE_REQ;
+	client->fe_status = FE_HAS_SIGNAL;
+	client->event_fe_state = -1;
+	client->event_unc_state = -1;
+
+	Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+	Msg.Msg.msgDstId = HIF_TASK;
+	Msg.Msg.msgFlags = 0;
+	Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
 	Msg.Msg.msgLength = sizeof(Msg);
 	Msg.Data[0] = fep->frequency;
 	Msg.Data[2] = 12000000;
@@ -315,24 +374,6 @@
 	default: return -EINVAL;
 	}
 
-	/* Disable LNA, if any. An error is returned if no LNA is present */
-	ret = sms_board_lna_control(client->coredev, 0);
-	if (ret == 0) {
-		fe_status_t status;
-
-		/* tune with LNA off at first */
-		ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-						  &client->tune_done);
-
-		smsdvb_read_status(fe, &status);
-
-		if (status & FE_HAS_LOCK)
-			return ret;
-
-		/* previous tune didnt lock - enable LNA and tune again */
-		sms_board_lna_control(client->coredev, 1);
-	}
-
 	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
 					   &client->tune_done);
 }
@@ -357,8 +398,7 @@
 	struct smsdvb_client_t *client =
 		container_of(fe, struct smsdvb_client_t, frontend);
 
-	sms_board_power(client->coredev, 1);
-
+	sms_board_dvb3_event(client, DVB3_EVENT_INIT);
 	return 0;
 }
 
@@ -367,8 +407,7 @@
 	struct smsdvb_client_t *client =
 		container_of(fe, struct smsdvb_client_t, frontend);
 
-	sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-	sms_board_power(client->coredev, 0);
+	sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
 
 	return 0;
 }
@@ -500,8 +539,11 @@
 
 	kmutex_unlock(&g_smsdvb_clientslock);
 
-	sms_info("success");
+	client->event_fe_state = -1;
+	client->event_unc_state = -1;
+	sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
 
+	sms_info("success");
 	sms_board_setup(coredev);
 
 	return 0;