1 /****************************************************************
2 
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2008, Uri Shkolnik
6 
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the 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,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along 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 
35 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36 
37 struct 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 
57 static struct list_head g_smsdvb_clients;
58 static struct mutex g_smsdvb_clientslock;
59 
60 static int sms_dbg;
61 module_param_named(debug, sms_dbg, int, 0644);
62 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
63 
64 /* Events that may come from DVB v3 adapter */
sms_board_dvb3_event(struct smsdvb_client_t * client,enum SMS_DVB3_EVENTS event)65 static 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 
smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S * pReceptionData,struct SMSHOSTLIB_STATISTICS_ST * p)118 static 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 
smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S * pReceptionData,struct SMSHOSTLIB_STATISTICS_ISDBT_ST * p)175 static 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 
smsdvb_onresponse(void * context,struct smscore_buffer_t * cb)229 static 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 
smsdvb_unregister_client(struct smsdvb_client_t * client)392 static 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 
smsdvb_onremove(void * context)406 static 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 
smsdvb_start_feed(struct dvb_demux_feed * feed)415 static 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 
smsdvb_stop_feed(struct dvb_demux_feed * feed)436 static 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 
smsdvb_sendrequest_and_wait(struct smsdvb_client_t * client,void * buffer,size_t size,struct completion * completion)457 static 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 
smsdvb_send_statistics_request(struct smsdvb_client_t * client)473 static 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 
led_feedback(struct smsdvb_client_t * client)487 static 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 
smsdvb_read_status(struct dvb_frontend * fe,fe_status_t * stat)497 static 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 
smsdvb_read_ber(struct dvb_frontend * fe,u32 * ber)512 static 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 
smsdvb_read_signal_strength(struct dvb_frontend * fe,u16 * strength)527 static 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 
smsdvb_read_snr(struct dvb_frontend * fe,u16 * snr)550 static 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 
smsdvb_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)565 static 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 
smsdvb_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * tune)580 static 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 
smsdvb_dvbt_set_frontend(struct dvb_frontend * fe)591 static 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 
smsdvb_isdbt_set_frontend(struct dvb_frontend * fe)657 static 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 
smsdvb_set_frontend(struct dvb_frontend * fe)721 static 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 
smsdvb_get_frontend(struct dvb_frontend * fe)739 static 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 
smsdvb_init(struct dvb_frontend * fe)866 static 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 
smsdvb_sleep(struct dvb_frontend * fe)877 static 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 
smsdvb_release(struct dvb_frontend * fe)890 static void smsdvb_release(struct dvb_frontend *fe)
891 {
892 	/* do nothing */
893 }
894 
895 static 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 
smsdvb_hotplug(struct smscore_device_t * coredev,struct device * device,int arrival)927 static 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, &params, &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 
1029 client_error:
1030 	dvb_unregister_frontend(&client->frontend);
1031 
1032 frontend_error:
1033 	dvb_dmxdev_release(&client->dmxdev);
1034 
1035 dmxdev_error:
1036 	dvb_dmx_release(&client->demux);
1037 
1038 dvbdmx_error:
1039 	dvb_unregister_adapter(&client->adapter);
1040 
1041 adapter_error:
1042 	kfree(client);
1043 	return rc;
1044 }
1045 
smsdvb_module_init(void)1046 static 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 
smsdvb_module_exit(void)1060 static 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 
1073 module_init(smsdvb_module_init);
1074 module_exit(smsdvb_module_exit);
1075 
1076 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1077 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1078 MODULE_LICENSE("GPL");
1079