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