• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/media/dvb/siano/
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	/* todo: save freq/band instead whole struct */
53	struct dvb_frontend_parameters fe_params;
54
55	struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
56	int event_fe_state;
57	int event_unc_state;
58};
59
60static struct list_head g_smsdvb_clients;
61static struct mutex g_smsdvb_clientslock;
62
63static int sms_dbg;
64module_param_named(debug, sms_dbg, int, 0644);
65MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
66
67/* Events that may come from DVB v3 adapter */
68static void sms_board_dvb3_event(struct smsdvb_client_t *client,
69		enum SMS_DVB3_EVENTS event) {
70
71	struct smscore_device_t *coredev = client->coredev;
72	switch (event) {
73	case DVB3_EVENT_INIT:
74		sms_debug("DVB3_EVENT_INIT");
75		sms_board_event(coredev, BOARD_EVENT_BIND);
76		break;
77	case DVB3_EVENT_SLEEP:
78		sms_debug("DVB3_EVENT_SLEEP");
79		sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
80		break;
81	case DVB3_EVENT_HOTPLUG:
82		sms_debug("DVB3_EVENT_HOTPLUG");
83		sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
84		break;
85	case DVB3_EVENT_FE_LOCK:
86		if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
87			client->event_fe_state = DVB3_EVENT_FE_LOCK;
88			sms_debug("DVB3_EVENT_FE_LOCK");
89			sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
90		}
91		break;
92	case DVB3_EVENT_FE_UNLOCK:
93		if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
94			client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
95			sms_debug("DVB3_EVENT_FE_UNLOCK");
96			sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
97		}
98		break;
99	case DVB3_EVENT_UNC_OK:
100		if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
101			client->event_unc_state = DVB3_EVENT_UNC_OK;
102			sms_debug("DVB3_EVENT_UNC_OK");
103			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
104		}
105		break;
106	case DVB3_EVENT_UNC_ERR:
107		if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
108			client->event_unc_state = DVB3_EVENT_UNC_ERR;
109			sms_debug("DVB3_EVENT_UNC_ERR");
110			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
111		}
112		break;
113
114	default:
115		sms_err("Unknown dvb3 api event");
116		break;
117	}
118}
119
120
121static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
122				   struct SMSHOSTLIB_STATISTICS_ST *p)
123{
124	if (sms_dbg & 2) {
125		printk(KERN_DEBUG "Reserved = %d", p->Reserved);
126		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
127		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
128		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
129		printk(KERN_DEBUG "SNR = %d", p->SNR);
130		printk(KERN_DEBUG "BER = %d", p->BER);
131		printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
132		printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
133		printk(KERN_DEBUG "MFER = %d", p->MFER);
134		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
135		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
136		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
137		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
138		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
139		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
140		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
141		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
142		printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
143		printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
144		printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
145		printk(KERN_DEBUG "Constellation = %d", p->Constellation);
146		printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
147		printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
148		printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
149		printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
150		printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
151		printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
152		printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
153		printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
154		printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
155		printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
156		printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
157		printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
158		printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
159		printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
160		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
161		printk(KERN_DEBUG "PreBER = %d", p->PreBER);
162		printk(KERN_DEBUG "CellId = %d", p->CellId);
163		printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
164		printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
165		printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
166	}
167
168	pReceptionData->IsDemodLocked = p->IsDemodLocked;
169
170	pReceptionData->SNR = p->SNR;
171	pReceptionData->BER = p->BER;
172	pReceptionData->BERErrorCount = p->BERErrorCount;
173	pReceptionData->InBandPwr = p->InBandPwr;
174	pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
175};
176
177
178static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
179				    struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
180{
181	int i;
182
183	if (sms_dbg & 2) {
184		printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
185		printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
186		printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
187		printk(KERN_DEBUG "SNR = %d", p->SNR);
188		printk(KERN_DEBUG "RSSI = %d", p->RSSI);
189		printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
190		printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
191		printk(KERN_DEBUG "Frequency = %d", p->Frequency);
192		printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
193		printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
194		printk(KERN_DEBUG "ModemState = %d", p->ModemState);
195		printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
196		printk(KERN_DEBUG "SystemType = %d", p->SystemType);
197		printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
198		printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
199		printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
200
201		for (i = 0; i < 3; i++) {
202			printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
203			printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
204			printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
205			printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
206			printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
207			printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
208			printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
209			printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
210			printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
211			printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
212			printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
213			printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
214		}
215	}
216
217	pReceptionData->IsDemodLocked = p->IsDemodLocked;
218
219	pReceptionData->SNR = p->SNR;
220	pReceptionData->InBandPwr = p->InBandPwr;
221
222	pReceptionData->ErrorTSPackets = 0;
223	pReceptionData->BER = 0;
224	pReceptionData->BERErrorCount = 0;
225	for (i = 0; i < 3; i++) {
226		pReceptionData->BER += p->LayerInfo[i].BER;
227		pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
228		pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
229	}
230}
231
232static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
233{
234	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
235	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
236			+ cb->offset);
237	u32 *pMsgData = (u32 *) phdr + 1;
238	/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
239	bool is_status_update = false;
240
241	smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
242
243	switch (phdr->msgType) {
244	case MSG_SMS_DVBT_BDA_DATA:
245		dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
246				 cb->size - sizeof(struct SmsMsgHdr_ST));
247		break;
248
249	case MSG_SMS_RF_TUNE_RES:
250	case MSG_SMS_ISDBT_TUNE_RES:
251		complete(&client->tune_done);
252		break;
253
254	case MSG_SMS_SIGNAL_DETECTED_IND:
255		sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
256		client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
257		is_status_update = true;
258		break;
259
260	case MSG_SMS_NO_SIGNAL_IND:
261		sms_info("MSG_SMS_NO_SIGNAL_IND");
262		client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
263		is_status_update = true;
264		break;
265
266	case MSG_SMS_TRANSMISSION_IND: {
267		sms_info("MSG_SMS_TRANSMISSION_IND");
268
269		pMsgData++;
270		memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
271				sizeof(struct TRANSMISSION_STATISTICS_S));
272
273		/* Mo need to correct guard interval
274		 * (as opposed to old statistics message).
275		 */
276		CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
277		CORRECT_STAT_TRANSMISSON_MODE(
278				client->sms_stat_dvb.TransmissionData);
279		is_status_update = true;
280		break;
281	}
282	case MSG_SMS_HO_PER_SLICES_IND: {
283		struct RECEPTION_STATISTICS_S *pReceptionData =
284				&client->sms_stat_dvb.ReceptionData;
285		struct SRVM_SIGNAL_STATUS_S SignalStatusData;
286
287		/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
288		pMsgData++;
289		SignalStatusData.result = pMsgData[0];
290		SignalStatusData.snr = pMsgData[1];
291		SignalStatusData.inBandPower = (s32) pMsgData[2];
292		SignalStatusData.tsPackets = pMsgData[3];
293		SignalStatusData.etsPackets = pMsgData[4];
294		SignalStatusData.constellation = pMsgData[5];
295		SignalStatusData.hpCode = pMsgData[6];
296		SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
297		SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
298		SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
299		SignalStatusData.reason = pMsgData[10];
300		SignalStatusData.requestId = pMsgData[11];
301		pReceptionData->IsRfLocked = pMsgData[16];
302		pReceptionData->IsDemodLocked = pMsgData[17];
303		pReceptionData->ModemState = pMsgData[12];
304		pReceptionData->SNR = pMsgData[1];
305		pReceptionData->BER = pMsgData[13];
306		pReceptionData->RSSI = pMsgData[14];
307		CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
308
309		pReceptionData->InBandPwr = (s32) pMsgData[2];
310		pReceptionData->CarrierOffset = (s32) pMsgData[15];
311		pReceptionData->TotalTSPackets = pMsgData[3];
312		pReceptionData->ErrorTSPackets = pMsgData[4];
313
314		/* TS PER */
315		if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
316				> 0) {
317			pReceptionData->TS_PER = (SignalStatusData.etsPackets
318					* 100) / (SignalStatusData.tsPackets
319					+ SignalStatusData.etsPackets);
320		} else {
321			pReceptionData->TS_PER = 0;
322		}
323
324		pReceptionData->BERBitCount = pMsgData[18];
325		pReceptionData->BERErrorCount = pMsgData[19];
326
327		pReceptionData->MRC_SNR = pMsgData[20];
328		pReceptionData->MRC_InBandPwr = pMsgData[21];
329		pReceptionData->MRC_RSSI = pMsgData[22];
330
331		is_status_update = true;
332		break;
333	}
334	case MSG_SMS_GET_STATISTICS_RES: {
335		union {
336			struct SMSHOSTLIB_STATISTICS_ISDBT_ST  isdbt;
337			struct SmsMsgStatisticsInfo_ST         dvb;
338		} *p = (void *) (phdr + 1);
339		struct RECEPTION_STATISTICS_S *pReceptionData =
340				&client->sms_stat_dvb.ReceptionData;
341
342		sms_info("MSG_SMS_GET_STATISTICS_RES");
343
344		is_status_update = true;
345
346		switch (smscore_get_device_mode(client->coredev)) {
347		case DEVICE_MODE_ISDBT:
348		case DEVICE_MODE_ISDBT_BDA:
349			smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
350			break;
351		default:
352			smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
353		}
354		if (!pReceptionData->IsDemodLocked) {
355			pReceptionData->SNR = 0;
356			pReceptionData->BER = 0;
357			pReceptionData->BERErrorCount = 0;
358			pReceptionData->InBandPwr = 0;
359			pReceptionData->ErrorTSPackets = 0;
360		}
361
362		complete(&client->tune_done);
363		break;
364	}
365	default:
366		sms_info("Unhandled message %d", phdr->msgType);
367
368	}
369	smscore_putbuffer(client->coredev, cb);
370
371	if (is_status_update) {
372		if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
373			client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
374				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
375			sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
376			if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
377					== 0)
378				sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
379			else
380				sms_board_dvb3_event(client,
381						DVB3_EVENT_UNC_ERR);
382
383		} else {
384			if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
385				client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
386			else
387				client->fe_status = 0;
388			sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
389		}
390	}
391
392	return 0;
393}
394
395static void smsdvb_unregister_client(struct smsdvb_client_t *client)
396{
397	/* must be called under clientslock */
398
399	list_del(&client->entry);
400
401	smscore_unregister_client(client->smsclient);
402	dvb_unregister_frontend(&client->frontend);
403	dvb_dmxdev_release(&client->dmxdev);
404	dvb_dmx_release(&client->demux);
405	dvb_unregister_adapter(&client->adapter);
406	kfree(client);
407}
408
409static void smsdvb_onremove(void *context)
410{
411	kmutex_lock(&g_smsdvb_clientslock);
412
413	smsdvb_unregister_client((struct smsdvb_client_t *) context);
414
415	kmutex_unlock(&g_smsdvb_clientslock);
416}
417
418static int smsdvb_start_feed(struct dvb_demux_feed *feed)
419{
420	struct smsdvb_client_t *client =
421		container_of(feed->demux, struct smsdvb_client_t, demux);
422	struct SmsMsgData_ST PidMsg;
423
424	sms_debug("add pid %d(%x)",
425		  feed->pid, feed->pid);
426
427	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
428	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
429	PidMsg.xMsgHeader.msgFlags = 0;
430	PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
431	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
432	PidMsg.msgData[0] = feed->pid;
433
434	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
435	return smsclient_sendrequest(client->smsclient,
436				     &PidMsg, sizeof(PidMsg));
437}
438
439static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
440{
441	struct smsdvb_client_t *client =
442		container_of(feed->demux, struct smsdvb_client_t, demux);
443	struct SmsMsgData_ST PidMsg;
444
445	sms_debug("remove pid %d(%x)",
446		  feed->pid, feed->pid);
447
448	PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
449	PidMsg.xMsgHeader.msgDstId = HIF_TASK;
450	PidMsg.xMsgHeader.msgFlags = 0;
451	PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
452	PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
453	PidMsg.msgData[0] = feed->pid;
454
455	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
456	return smsclient_sendrequest(client->smsclient,
457				     &PidMsg, sizeof(PidMsg));
458}
459
460static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
461					void *buffer, size_t size,
462					struct completion *completion)
463{
464	int rc;
465
466	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
467	rc = smsclient_sendrequest(client->smsclient, buffer, size);
468	if (rc < 0)
469		return rc;
470
471	return wait_for_completion_timeout(completion,
472					   msecs_to_jiffies(2000)) ?
473						0 : -ETIME;
474}
475
476static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
477{
478	int rc;
479	struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
480				    DVBT_BDA_CONTROL_MSG_ID,
481				    HIF_TASK,
482				    sizeof(struct SmsMsgHdr_ST), 0 };
483
484	rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
485					  &client->tune_done);
486
487	return rc;
488}
489
490static inline int led_feedback(struct smsdvb_client_t *client)
491{
492	if (client->fe_status & FE_HAS_LOCK)
493		return sms_board_led_feedback(client->coredev,
494			(client->sms_stat_dvb.ReceptionData.BER
495			== 0) ? SMS_LED_HI : SMS_LED_LO);
496	else
497		return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
498}
499
500static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
501{
502	int rc;
503	struct smsdvb_client_t *client;
504	client = container_of(fe, struct smsdvb_client_t, frontend);
505
506	rc = smsdvb_send_statistics_request(client);
507
508	*stat = client->fe_status;
509
510	led_feedback(client);
511
512	return rc;
513}
514
515static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
516{
517	int rc;
518	struct smsdvb_client_t *client;
519	client = container_of(fe, struct smsdvb_client_t, frontend);
520
521	rc = smsdvb_send_statistics_request(client);
522
523	*ber = client->sms_stat_dvb.ReceptionData.BER;
524
525	led_feedback(client);
526
527	return rc;
528}
529
530static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
531{
532	int rc;
533
534	struct smsdvb_client_t *client;
535	client = container_of(fe, struct smsdvb_client_t, frontend);
536
537	rc = smsdvb_send_statistics_request(client);
538
539	if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
540		*strength = 0;
541		else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
542			*strength = 100;
543		else
544			*strength =
545				(client->sms_stat_dvb.ReceptionData.InBandPwr
546				+ 95) * 3 / 2;
547
548	led_feedback(client);
549
550	return rc;
551}
552
553static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
554{
555	int rc;
556	struct smsdvb_client_t *client;
557	client = container_of(fe, struct smsdvb_client_t, frontend);
558
559	rc = smsdvb_send_statistics_request(client);
560
561	*snr = client->sms_stat_dvb.ReceptionData.SNR;
562
563	led_feedback(client);
564
565	return rc;
566}
567
568static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
569{
570	int rc;
571	struct smsdvb_client_t *client;
572	client = container_of(fe, struct smsdvb_client_t, frontend);
573
574	rc = smsdvb_send_statistics_request(client);
575
576	*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
577
578	led_feedback(client);
579
580	return rc;
581}
582
583static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
584				    struct dvb_frontend_tune_settings *tune)
585{
586	sms_debug("");
587
588	tune->min_delay_ms = 400;
589	tune->step_size = 250000;
590	tune->max_drift = 0;
591	return 0;
592}
593
594static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
595				    struct dvb_frontend_parameters *p)
596{
597	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
598	struct smsdvb_client_t *client =
599		container_of(fe, struct smsdvb_client_t, frontend);
600
601	struct {
602		struct SmsMsgHdr_ST	Msg;
603		u32		Data[3];
604	} Msg;
605
606	int ret;
607
608	client->fe_status = FE_HAS_SIGNAL;
609	client->event_fe_state = -1;
610	client->event_unc_state = -1;
611	fe->dtv_property_cache.delivery_system = SYS_DVBT;
612
613	Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
614	Msg.Msg.msgDstId = HIF_TASK;
615	Msg.Msg.msgFlags = 0;
616	Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
617	Msg.Msg.msgLength = sizeof(Msg);
618	Msg.Data[0] = c->frequency;
619	Msg.Data[2] = 12000000;
620
621	sms_info("%s: freq %d band %d", __func__, c->frequency,
622		 c->bandwidth_hz);
623
624	switch (c->bandwidth_hz / 1000000) {
625	case 8:
626		Msg.Data[1] = BW_8_MHZ;
627		break;
628	case 7:
629		Msg.Data[1] = BW_7_MHZ;
630		break;
631	case 6:
632		Msg.Data[1] = BW_6_MHZ;
633		break;
634	case 0:
635		return -EOPNOTSUPP;
636	default:
637		return -EINVAL;
638	}
639	/* Disable LNA, if any. An error is returned if no LNA is present */
640	ret = sms_board_lna_control(client->coredev, 0);
641	if (ret == 0) {
642		fe_status_t status;
643
644		/* tune with LNA off at first */
645		ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
646						  &client->tune_done);
647
648		smsdvb_read_status(fe, &status);
649
650		if (status & FE_HAS_LOCK)
651			return ret;
652
653		/* previous tune didnt lock - enable LNA and tune again */
654		sms_board_lna_control(client->coredev, 1);
655	}
656
657	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
658					   &client->tune_done);
659}
660
661static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
662				     struct dvb_frontend_parameters *p)
663{
664	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
665	struct smsdvb_client_t *client =
666		container_of(fe, struct smsdvb_client_t, frontend);
667
668	struct {
669		struct SmsMsgHdr_ST	Msg;
670		u32		Data[4];
671	} Msg;
672
673	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
674
675	Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
676	Msg.Msg.msgDstId  = HIF_TASK;
677	Msg.Msg.msgFlags  = 0;
678	Msg.Msg.msgType   = MSG_SMS_ISDBT_TUNE_REQ;
679	Msg.Msg.msgLength = sizeof(Msg);
680
681	if (c->isdbt_sb_segment_idx == -1)
682		c->isdbt_sb_segment_idx = 0;
683
684	switch (c->isdbt_sb_segment_count) {
685	case 3:
686		Msg.Data[1] = BW_ISDBT_3SEG;
687		break;
688	case 1:
689		Msg.Data[1] = BW_ISDBT_1SEG;
690		break;
691	case 0:	/* AUTO */
692		switch (c->bandwidth_hz / 1000000) {
693		case 8:
694		case 7:
695			c->isdbt_sb_segment_count = 3;
696			Msg.Data[1] = BW_ISDBT_3SEG;
697			break;
698		case 6:
699			c->isdbt_sb_segment_count = 1;
700			Msg.Data[1] = BW_ISDBT_1SEG;
701			break;
702		default: /* Assumes 6 MHZ bw */
703			c->isdbt_sb_segment_count = 1;
704			c->bandwidth_hz = 6000;
705			Msg.Data[1] = BW_ISDBT_1SEG;
706			break;
707		}
708		break;
709	default:
710		sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
711		return -EINVAL;
712	}
713
714	Msg.Data[0] = c->frequency;
715	Msg.Data[2] = 12000000;
716	Msg.Data[3] = c->isdbt_sb_segment_idx;
717
718	sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
719		 c->frequency, c->isdbt_sb_segment_count,
720		 c->isdbt_sb_segment_idx);
721
722	return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
723					   &client->tune_done);
724}
725
726static int smsdvb_set_frontend(struct dvb_frontend *fe,
727			       struct dvb_frontend_parameters *fep)
728{
729	struct smsdvb_client_t *client =
730		container_of(fe, struct smsdvb_client_t, frontend);
731	struct smscore_device_t *coredev = client->coredev;
732
733	switch (smscore_get_device_mode(coredev)) {
734	case DEVICE_MODE_DVBT:
735	case DEVICE_MODE_DVBT_BDA:
736		return smsdvb_dvbt_set_frontend(fe, fep);
737	case DEVICE_MODE_ISDBT:
738	case DEVICE_MODE_ISDBT_BDA:
739		return smsdvb_isdbt_set_frontend(fe, fep);
740	default:
741		return -EINVAL;
742	}
743}
744
745static int smsdvb_get_frontend(struct dvb_frontend *fe,
746			       struct dvb_frontend_parameters *fep)
747{
748	struct smsdvb_client_t *client =
749		container_of(fe, struct smsdvb_client_t, frontend);
750
751	sms_debug("");
752
753	/* todo: */
754	memcpy(fep, &client->fe_params,
755	       sizeof(struct dvb_frontend_parameters));
756
757	return 0;
758}
759
760static int smsdvb_init(struct dvb_frontend *fe)
761{
762	struct smsdvb_client_t *client =
763		container_of(fe, struct smsdvb_client_t, frontend);
764
765	sms_board_power(client->coredev, 1);
766
767	sms_board_dvb3_event(client, DVB3_EVENT_INIT);
768	return 0;
769}
770
771static int smsdvb_sleep(struct dvb_frontend *fe)
772{
773	struct smsdvb_client_t *client =
774		container_of(fe, struct smsdvb_client_t, frontend);
775
776	sms_board_led_feedback(client->coredev, SMS_LED_OFF);
777	sms_board_power(client->coredev, 0);
778
779	sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
780
781	return 0;
782}
783
784static void smsdvb_release(struct dvb_frontend *fe)
785{
786	/* do nothing */
787}
788
789static struct dvb_frontend_ops smsdvb_fe_ops = {
790	.info = {
791		.name			= "Siano Mobile Digital MDTV Receiver",
792		.type			= FE_OFDM,
793		.frequency_min		= 44250000,
794		.frequency_max		= 867250000,
795		.frequency_stepsize	= 250000,
796		.caps = FE_CAN_INVERSION_AUTO |
797			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
798			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
799			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
800			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
801			FE_CAN_GUARD_INTERVAL_AUTO |
802			FE_CAN_RECOVER |
803			FE_CAN_HIERARCHY_AUTO,
804	},
805
806	.release = smsdvb_release,
807
808	.set_frontend = smsdvb_set_frontend,
809	.get_frontend = smsdvb_get_frontend,
810	.get_tune_settings = smsdvb_get_tune_settings,
811
812	.read_status = smsdvb_read_status,
813	.read_ber = smsdvb_read_ber,
814	.read_signal_strength = smsdvb_read_signal_strength,
815	.read_snr = smsdvb_read_snr,
816	.read_ucblocks = smsdvb_read_ucblocks,
817
818	.init = smsdvb_init,
819	.sleep = smsdvb_sleep,
820};
821
822static int smsdvb_hotplug(struct smscore_device_t *coredev,
823			  struct device *device, int arrival)
824{
825	struct smsclient_params_t params;
826	struct smsdvb_client_t *client;
827	int rc;
828
829	/* device removal handled by onremove callback */
830	if (!arrival)
831		return 0;
832	client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
833	if (!client) {
834		sms_err("kmalloc() failed");
835		return -ENOMEM;
836	}
837
838	/* register dvb adapter */
839	rc = dvb_register_adapter(&client->adapter,
840				  sms_get_board(
841					smscore_get_board_id(coredev))->name,
842				  THIS_MODULE, device, adapter_nr);
843	if (rc < 0) {
844		sms_err("dvb_register_adapter() failed %d", rc);
845		goto adapter_error;
846	}
847
848	/* init dvb demux */
849	client->demux.dmx.capabilities = DMX_TS_FILTERING;
850	client->demux.filternum = 32; /* todo: nova ??? */
851	client->demux.feednum = 32;
852	client->demux.start_feed = smsdvb_start_feed;
853	client->demux.stop_feed = smsdvb_stop_feed;
854
855	rc = dvb_dmx_init(&client->demux);
856	if (rc < 0) {
857		sms_err("dvb_dmx_init failed %d", rc);
858		goto dvbdmx_error;
859	}
860
861	/* init dmxdev */
862	client->dmxdev.filternum = 32;
863	client->dmxdev.demux = &client->demux.dmx;
864	client->dmxdev.capabilities = 0;
865
866	rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
867	if (rc < 0) {
868		sms_err("dvb_dmxdev_init failed %d", rc);
869		goto dmxdev_error;
870	}
871
872	/* init and register frontend */
873	memcpy(&client->frontend.ops, &smsdvb_fe_ops,
874	       sizeof(struct dvb_frontend_ops));
875
876	rc = dvb_register_frontend(&client->adapter, &client->frontend);
877	if (rc < 0) {
878		sms_err("frontend registration failed %d", rc);
879		goto frontend_error;
880	}
881
882	params.initial_id = 1;
883	params.data_type = MSG_SMS_DVBT_BDA_DATA;
884	params.onresponse_handler = smsdvb_onresponse;
885	params.onremove_handler = smsdvb_onremove;
886	params.context = client;
887
888	rc = smscore_register_client(coredev, &params, &client->smsclient);
889	if (rc < 0) {
890		sms_err("smscore_register_client() failed %d", rc);
891		goto client_error;
892	}
893
894	client->coredev = coredev;
895
896	init_completion(&client->tune_done);
897
898	kmutex_lock(&g_smsdvb_clientslock);
899
900	list_add(&client->entry, &g_smsdvb_clients);
901
902	kmutex_unlock(&g_smsdvb_clientslock);
903
904	client->event_fe_state = -1;
905	client->event_unc_state = -1;
906	sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
907
908	sms_info("success");
909	sms_board_setup(coredev);
910
911	return 0;
912
913client_error:
914	dvb_unregister_frontend(&client->frontend);
915
916frontend_error:
917	dvb_dmxdev_release(&client->dmxdev);
918
919dmxdev_error:
920	dvb_dmx_release(&client->demux);
921
922dvbdmx_error:
923	dvb_unregister_adapter(&client->adapter);
924
925adapter_error:
926	kfree(client);
927	return rc;
928}
929
930static int __init smsdvb_module_init(void)
931{
932	int rc;
933
934	INIT_LIST_HEAD(&g_smsdvb_clients);
935	kmutex_init(&g_smsdvb_clientslock);
936
937	rc = smscore_register_hotplug(smsdvb_hotplug);
938
939	sms_debug("");
940
941	return rc;
942}
943
944static void __exit smsdvb_module_exit(void)
945{
946	smscore_unregister_hotplug(smsdvb_hotplug);
947
948	kmutex_lock(&g_smsdvb_clientslock);
949
950	while (!list_empty(&g_smsdvb_clients))
951	       smsdvb_unregister_client(
952			(struct smsdvb_client_t *) g_smsdvb_clients.next);
953
954	kmutex_unlock(&g_smsdvb_clientslock);
955}
956
957module_init(smsdvb_module_init);
958module_exit(smsdvb_module_exit);
959
960MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
961MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
962MODULE_LICENSE("GPL");
963