blob: 864f53e7ca63887a0fb3f489dcce98b1ac1fe8a0 [file] [log] [blame]
Uri Shkolnike5275792009-04-27 09:09:47 -03001/****************************************************************
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****************************************************************/
Steven Toth8d4f9d02008-05-22 18:05:26 -030021
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030022#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030024#include <linux/init.h>
25
Uri Shkolnikc9679e32009-05-14 16:28:17 -030026#include "dmxdev.h"
27#include "dvbdev.h"
28#include "dvb_demux.h"
29#include "dvb_frontend.h"
30
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030031#include "smscoreapi.h"
Uri Shkolnikba79bb22009-05-12 11:37:09 -030032#include "smsendian.h"
Michael Krufky1c11d542008-06-18 22:09:55 -030033#include "sms-cards.h"
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030034
Michael Krufky9c59f9682008-05-19 18:57:12 -030035DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36
Michael Krufky62c71672008-08-31 17:15:47 -030037struct 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;
Michael Krufky62c71672008-08-31 17:15:47 -030049
Uri Shkolnik793786d2009-05-12 12:28:46 -030050 struct completion tune_done;
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -030051 struct completion stats_done;
Michael Krufky62c71672008-08-31 17:15:47 -030052
Uri Shkolnik793786d2009-05-12 12:28:46 -030053 struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
54 int event_fe_state;
55 int event_unc_state;
Michael Krufky62c71672008-08-31 17:15:47 -030056};
57
Adrian Bunkc5e0bd12008-07-21 23:17:36 -030058static struct list_head g_smsdvb_clients;
59static struct mutex g_smsdvb_clientslock;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030060
Michael Krufky0d02efe2009-02-27 02:42:16 -030061static int sms_dbg;
62module_param_named(debug, sms_dbg, int, 0644);
63MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
64
Uri Shkolnik793786d2009-05-12 12:28:46 -030065/* Events that may come from DVB v3 adapter */
66static void sms_board_dvb3_event(struct smsdvb_client_t *client,
67 enum SMS_DVB3_EVENTS event) {
Uri Shkolnik4db989f2009-05-19 12:28:02 -030068
69 struct smscore_device_t *coredev = client->coredev;
70 switch (event) {
71 case DVB3_EVENT_INIT:
72 sms_debug("DVB3_EVENT_INIT");
73 sms_board_event(coredev, BOARD_EVENT_BIND);
74 break;
75 case DVB3_EVENT_SLEEP:
76 sms_debug("DVB3_EVENT_SLEEP");
77 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
78 break;
79 case DVB3_EVENT_HOTPLUG:
80 sms_debug("DVB3_EVENT_HOTPLUG");
81 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
82 break;
83 case DVB3_EVENT_FE_LOCK:
84 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
85 client->event_fe_state = DVB3_EVENT_FE_LOCK;
86 sms_debug("DVB3_EVENT_FE_LOCK");
87 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
88 }
89 break;
90 case DVB3_EVENT_FE_UNLOCK:
91 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
92 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
93 sms_debug("DVB3_EVENT_FE_UNLOCK");
94 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
95 }
96 break;
97 case DVB3_EVENT_UNC_OK:
98 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
99 client->event_unc_state = DVB3_EVENT_UNC_OK;
100 sms_debug("DVB3_EVENT_UNC_OK");
101 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
102 }
103 break;
104 case DVB3_EVENT_UNC_ERR:
105 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
106 client->event_unc_state = DVB3_EVENT_UNC_ERR;
107 sms_debug("DVB3_EVENT_UNC_ERR");
108 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
109 }
110 break;
111
112 default:
113 sms_err("Unknown dvb3 api event");
114 break;
115 }
Uri Shkolnik793786d2009-05-12 12:28:46 -0300116}
117
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300118
119static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
120 struct SMSHOSTLIB_STATISTICS_ST *p)
121{
122 if (sms_dbg & 2) {
123 printk(KERN_DEBUG "Reserved = %d", p->Reserved);
124 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
125 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
126 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
127 printk(KERN_DEBUG "SNR = %d", p->SNR);
128 printk(KERN_DEBUG "BER = %d", p->BER);
129 printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
130 printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
131 printk(KERN_DEBUG "MFER = %d", p->MFER);
132 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
133 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
134 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
135 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
136 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
137 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
138 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
139 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
140 printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
141 printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
142 printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
143 printk(KERN_DEBUG "Constellation = %d", p->Constellation);
144 printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
145 printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
146 printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
147 printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
148 printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
149 printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
150 printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
151 printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
152 printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
153 printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
154 printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
155 printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
156 printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
157 printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
158 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
159 printk(KERN_DEBUG "PreBER = %d", p->PreBER);
160 printk(KERN_DEBUG "CellId = %d", p->CellId);
161 printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
162 printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
163 printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300164 }
165
166 pReceptionData->IsDemodLocked = p->IsDemodLocked;
167
168 pReceptionData->SNR = p->SNR;
169 pReceptionData->BER = p->BER;
170 pReceptionData->BERErrorCount = p->BERErrorCount;
171 pReceptionData->InBandPwr = p->InBandPwr;
172 pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
173};
174
175
176static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
177 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
178{
179 int i;
180
181 if (sms_dbg & 2) {
182 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
183 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
184 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
185 printk(KERN_DEBUG "SNR = %d", p->SNR);
186 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
187 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
188 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
189 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
190 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
191 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
192 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
193 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
194 printk(KERN_DEBUG "SystemType = %d", p->SystemType);
195 printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
196 printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
197 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
198
199 for (i = 0; i < 3; i++) {
200 printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
201 printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
202 printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
203 printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
204 printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
205 printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
206 printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
207 printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
208 printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
209 printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
210 printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
211 printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
212 }
213 }
214
215 pReceptionData->IsDemodLocked = p->IsDemodLocked;
216
217 pReceptionData->SNR = p->SNR;
218 pReceptionData->InBandPwr = p->InBandPwr;
219
220 pReceptionData->ErrorTSPackets = 0;
221 pReceptionData->BER = 0;
222 pReceptionData->BERErrorCount = 0;
223 for (i = 0; i < 3; i++) {
224 pReceptionData->BER += p->LayerInfo[i].BER;
225 pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
226 pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
227 }
228}
229
Michael Krufky0c071f32008-06-21 02:44:02 -0300230static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300231{
Michael Krufky18245e12008-06-15 17:52:24 -0300232 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300233 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
234 + cb->offset);
235 u32 *pMsgData = (u32 *) phdr + 1;
236 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
237 bool is_status_update = false;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300238
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300239 smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
240
Michael Krufkyfa830e82008-06-15 15:52:43 -0300241 switch (phdr->msgType) {
Michael Krufky82237412008-06-15 15:14:13 -0300242 case MSG_SMS_DVBT_BDA_DATA:
243 dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
Michael Krufky18245e12008-06-15 17:52:24 -0300244 cb->size - sizeof(struct SmsMsgHdr_ST));
Michael Krufky82237412008-06-15 15:14:13 -0300245 break;
246
247 case MSG_SMS_RF_TUNE_RES:
Michael Krufky6b26fce2009-12-22 21:08:49 -0300248 case MSG_SMS_ISDBT_TUNE_RES:
Michael Krufky82237412008-06-15 15:14:13 -0300249 complete(&client->tune_done);
250 break;
251
Uri Shkolnik793786d2009-05-12 12:28:46 -0300252 case MSG_SMS_SIGNAL_DETECTED_IND:
Uri Shkolnik793786d2009-05-12 12:28:46 -0300253 client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
254 is_status_update = true;
255 break;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300256
Uri Shkolnik793786d2009-05-12 12:28:46 -0300257 case MSG_SMS_NO_SIGNAL_IND:
Uri Shkolnik793786d2009-05-12 12:28:46 -0300258 client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
259 is_status_update = true;
260 break;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300261
Uri Shkolnik793786d2009-05-12 12:28:46 -0300262 case MSG_SMS_TRANSMISSION_IND: {
Uri Shkolnik793786d2009-05-12 12:28:46 -0300263 pMsgData++;
264 memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
265 sizeof(struct TRANSMISSION_STATISTICS_S));
266
267 /* Mo need to correct guard interval
268 * (as opposed to old statistics message).
269 */
270 CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
271 CORRECT_STAT_TRANSMISSON_MODE(
272 client->sms_stat_dvb.TransmissionData);
273 is_status_update = true;
274 break;
275 }
276 case MSG_SMS_HO_PER_SLICES_IND: {
277 struct RECEPTION_STATISTICS_S *pReceptionData =
278 &client->sms_stat_dvb.ReceptionData;
279 struct SRVM_SIGNAL_STATUS_S SignalStatusData;
280
Uri Shkolnik793786d2009-05-12 12:28:46 -0300281 pMsgData++;
282 SignalStatusData.result = pMsgData[0];
283 SignalStatusData.snr = pMsgData[1];
284 SignalStatusData.inBandPower = (s32) pMsgData[2];
285 SignalStatusData.tsPackets = pMsgData[3];
286 SignalStatusData.etsPackets = pMsgData[4];
287 SignalStatusData.constellation = pMsgData[5];
288 SignalStatusData.hpCode = pMsgData[6];
289 SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
290 SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
291 SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
292 SignalStatusData.reason = pMsgData[10];
293 SignalStatusData.requestId = pMsgData[11];
294 pReceptionData->IsRfLocked = pMsgData[16];
295 pReceptionData->IsDemodLocked = pMsgData[17];
296 pReceptionData->ModemState = pMsgData[12];
297 pReceptionData->SNR = pMsgData[1];
298 pReceptionData->BER = pMsgData[13];
299 pReceptionData->RSSI = pMsgData[14];
300 CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
301
302 pReceptionData->InBandPwr = (s32) pMsgData[2];
303 pReceptionData->CarrierOffset = (s32) pMsgData[15];
304 pReceptionData->TotalTSPackets = pMsgData[3];
305 pReceptionData->ErrorTSPackets = pMsgData[4];
306
307 /* TS PER */
308 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
309 > 0) {
310 pReceptionData->TS_PER = (SignalStatusData.etsPackets
311 * 100) / (SignalStatusData.tsPackets
312 + SignalStatusData.etsPackets);
Michael Krufky82237412008-06-15 15:14:13 -0300313 } else {
Uri Shkolnik793786d2009-05-12 12:28:46 -0300314 pReceptionData->TS_PER = 0;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300315 }
Michael Krufky82237412008-06-15 15:14:13 -0300316
Uri Shkolnik793786d2009-05-12 12:28:46 -0300317 pReceptionData->BERBitCount = pMsgData[18];
318 pReceptionData->BERErrorCount = pMsgData[19];
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300319
Uri Shkolnik793786d2009-05-12 12:28:46 -0300320 pReceptionData->MRC_SNR = pMsgData[20];
321 pReceptionData->MRC_InBandPwr = pMsgData[21];
322 pReceptionData->MRC_RSSI = pMsgData[22];
323
324 is_status_update = true;
325 break;
326 }
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300327 case MSG_SMS_GET_STATISTICS_RES: {
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300328 union {
329 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
330 struct SmsMsgStatisticsInfo_ST dvb;
331 } *p = (void *) (phdr + 1);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300332 struct RECEPTION_STATISTICS_S *pReceptionData =
333 &client->sms_stat_dvb.ReceptionData;
334
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300335 is_status_update = true;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300336
337 switch (smscore_get_device_mode(client->coredev)) {
338 case DEVICE_MODE_ISDBT:
339 case DEVICE_MODE_ISDBT_BDA:
340 smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
341 break;
342 default:
343 smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
344 }
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300345 if (!pReceptionData->IsDemodLocked) {
346 pReceptionData->SNR = 0;
347 pReceptionData->BER = 0;
348 pReceptionData->BERErrorCount = 0;
349 pReceptionData->InBandPwr = 0;
350 pReceptionData->ErrorTSPackets = 0;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300351 }
352
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300353 break;
354 }
355 default:
Mauro Carvalho Chehab4c3bdb52013-03-09 09:27:39 -0300356 sms_info("message not handled");
Uri Shkolnik793786d2009-05-12 12:28:46 -0300357 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300358 smscore_putbuffer(client->coredev, cb);
359
Uri Shkolnik793786d2009-05-12 12:28:46 -0300360 if (is_status_update) {
361 if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
362 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
363 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
364 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
365 if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
366 == 0)
367 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
368 else
369 sms_board_dvb3_event(client,
370 DVB3_EVENT_UNC_ERR);
371
372 } else {
Mauro Carvalho Chehabb4622c12009-12-25 18:04:17 -0300373 if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
374 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
375 else
376 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300377 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
378 }
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300379 complete(&client->stats_done);
Uri Shkolnik793786d2009-05-12 12:28:46 -0300380 }
381
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300382 return 0;
383}
384
Michael Krufky0c071f32008-06-21 02:44:02 -0300385static void smsdvb_unregister_client(struct smsdvb_client_t *client)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300386{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300387 /* must be called under clientslock */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300388
389 list_del(&client->entry);
390
391 smscore_unregister_client(client->smsclient);
392 dvb_unregister_frontend(&client->frontend);
393 dvb_dmxdev_release(&client->dmxdev);
394 dvb_dmx_release(&client->demux);
395 dvb_unregister_adapter(&client->adapter);
396 kfree(client);
397}
398
Michael Krufky0c071f32008-06-21 02:44:02 -0300399static void smsdvb_onremove(void *context)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300400{
401 kmutex_lock(&g_smsdvb_clientslock);
402
Michael Krufky18245e12008-06-15 17:52:24 -0300403 smsdvb_unregister_client((struct smsdvb_client_t *) context);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300404
405 kmutex_unlock(&g_smsdvb_clientslock);
406}
407
408static int smsdvb_start_feed(struct dvb_demux_feed *feed)
409{
Michael Krufky18245e12008-06-15 17:52:24 -0300410 struct smsdvb_client_t *client =
411 container_of(feed->demux, struct smsdvb_client_t, demux);
412 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300413
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300414 sms_debug("add pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300415 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300416
417 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
418 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
419 PidMsg.xMsgHeader.msgFlags = 0;
420 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
421 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
422 PidMsg.msgData[0] = feed->pid;
423
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300424 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
Michael Krufky82237412008-06-15 15:14:13 -0300425 return smsclient_sendrequest(client->smsclient,
426 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300427}
428
429static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
430{
Michael Krufky18245e12008-06-15 17:52:24 -0300431 struct smsdvb_client_t *client =
432 container_of(feed->demux, struct smsdvb_client_t, demux);
433 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300434
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300435 sms_debug("remove pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300436 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300437
438 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
439 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
440 PidMsg.xMsgHeader.msgFlags = 0;
441 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
442 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
443 PidMsg.msgData[0] = feed->pid;
444
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300445 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
Michael Krufky82237412008-06-15 15:14:13 -0300446 return smsclient_sendrequest(client->smsclient,
447 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300448}
449
Michael Krufky18245e12008-06-15 17:52:24 -0300450static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
Michael Krufkya83ccdd2008-05-06 03:11:51 -0300451 void *buffer, size_t size,
452 struct completion *completion)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300453{
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300454 int rc;
455
456 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
457 rc = smsclient_sendrequest(client->smsclient, buffer, size);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300458 if (rc < 0)
459 return rc;
460
Michael Krufky82237412008-06-15 15:14:13 -0300461 return wait_for_completion_timeout(completion,
462 msecs_to_jiffies(2000)) ?
463 0 : -ETIME;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300464}
465
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300466static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
467{
468 int rc;
469 struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
470 DVBT_BDA_CONTROL_MSG_ID,
471 HIF_TASK,
472 sizeof(struct SmsMsgHdr_ST), 0 };
473
474 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300475 &client->stats_done);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300476
477 return rc;
478}
479
Michael Krufky3746b612009-07-12 23:30:14 -0300480static inline int led_feedback(struct smsdvb_client_t *client)
481{
482 if (client->fe_status & FE_HAS_LOCK)
483 return sms_board_led_feedback(client->coredev,
484 (client->sms_stat_dvb.ReceptionData.BER
485 == 0) ? SMS_LED_HI : SMS_LED_LO);
486 else
487 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
488}
489
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300490static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
491{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300492 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300493 struct smsdvb_client_t *client;
494 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300495
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300496 rc = smsdvb_send_statistics_request(client);
497
Uri Shkolnik793786d2009-05-12 12:28:46 -0300498 *stat = client->fe_status;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300499
Michael Krufky3746b612009-07-12 23:30:14 -0300500 led_feedback(client);
501
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300502 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300503}
504
505static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
506{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300507 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300508 struct smsdvb_client_t *client;
509 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300510
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300511 rc = smsdvb_send_statistics_request(client);
512
Uri Shkolnik793786d2009-05-12 12:28:46 -0300513 *ber = client->sms_stat_dvb.ReceptionData.BER;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300514
Michael Krufky3746b612009-07-12 23:30:14 -0300515 led_feedback(client);
516
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300517 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300518}
519
520static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
521{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300522 int rc;
523
Uri Shkolnik793786d2009-05-12 12:28:46 -0300524 struct smsdvb_client_t *client;
525 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300526
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300527 rc = smsdvb_send_statistics_request(client);
528
Uri Shkolnik793786d2009-05-12 12:28:46 -0300529 if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
530 *strength = 0;
531 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
532 *strength = 100;
533 else
534 *strength =
535 (client->sms_stat_dvb.ReceptionData.InBandPwr
536 + 95) * 3 / 2;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300537
Michael Krufky3746b612009-07-12 23:30:14 -0300538 led_feedback(client);
539
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300540 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300541}
542
543static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
544{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300545 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300546 struct smsdvb_client_t *client;
547 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300548
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300549 rc = smsdvb_send_statistics_request(client);
550
Uri Shkolnik793786d2009-05-12 12:28:46 -0300551 *snr = client->sms_stat_dvb.ReceptionData.SNR;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300552
Michael Krufky3746b612009-07-12 23:30:14 -0300553 led_feedback(client);
554
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300555 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300556}
557
Michael Krufky851a9092008-11-22 14:56:37 -0300558static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
559{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300560 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300561 struct smsdvb_client_t *client;
562 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky851a9092008-11-22 14:56:37 -0300563
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300564 rc = smsdvb_send_statistics_request(client);
565
Uri Shkolnik793786d2009-05-12 12:28:46 -0300566 *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
Michael Krufky851a9092008-11-22 14:56:37 -0300567
Michael Krufky3746b612009-07-12 23:30:14 -0300568 led_feedback(client);
569
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300570 return rc;
Michael Krufky851a9092008-11-22 14:56:37 -0300571}
572
Michael Krufky82237412008-06-15 15:14:13 -0300573static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
574 struct dvb_frontend_tune_settings *tune)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300575{
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300576 sms_debug("");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300577
578 tune->min_delay_ms = 400;
579 tune->step_size = 250000;
580 tune->max_drift = 0;
581 return 0;
582}
583
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300584static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300585{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300586 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky18245e12008-06-15 17:52:24 -0300587 struct smsdvb_client_t *client =
588 container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300589
Michael Krufky18245e12008-06-15 17:52:24 -0300590 struct {
591 struct SmsMsgHdr_ST Msg;
Michael Krufky82237412008-06-15 15:14:13 -0300592 u32 Data[3];
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300593 } Msg;
594
Michael Krufky3746b612009-07-12 23:30:14 -0300595 int ret;
596
Uri Shkolnik793786d2009-05-12 12:28:46 -0300597 client->fe_status = FE_HAS_SIGNAL;
598 client->event_fe_state = -1;
599 client->event_unc_state = -1;
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300600 fe->dtv_property_cache.delivery_system = SYS_DVBT;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300601
602 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
603 Msg.Msg.msgDstId = HIF_TASK;
604 Msg.Msg.msgFlags = 0;
605 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300606 Msg.Msg.msgLength = sizeof(Msg);
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300607 Msg.Data[0] = c->frequency;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300608 Msg.Data[2] = 12000000;
609
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300610 sms_info("%s: freq %d band %d", __func__, c->frequency,
611 c->bandwidth_hz);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300612
Mauro Carvalho Chehab643e15a2009-12-25 07:29:06 -0300613 switch (c->bandwidth_hz / 1000000) {
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300614 case 8:
615 Msg.Data[1] = BW_8_MHZ;
616 break;
617 case 7:
618 Msg.Data[1] = BW_7_MHZ;
619 break;
620 case 6:
621 Msg.Data[1] = BW_6_MHZ;
622 break;
623 case 0:
624 return -EOPNOTSUPP;
625 default:
626 return -EINVAL;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300627 }
Michael Krufky3746b612009-07-12 23:30:14 -0300628 /* Disable LNA, if any. An error is returned if no LNA is present */
629 ret = sms_board_lna_control(client->coredev, 0);
630 if (ret == 0) {
631 fe_status_t status;
632
633 /* tune with LNA off at first */
634 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
635 &client->tune_done);
636
637 smsdvb_read_status(fe, &status);
638
639 if (status & FE_HAS_LOCK)
640 return ret;
641
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300642 /* previous tune didn't lock - enable LNA and tune again */
Michael Krufky3746b612009-07-12 23:30:14 -0300643 sms_board_lna_control(client->coredev, 1);
644 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300645
Michael Krufky82237412008-06-15 15:14:13 -0300646 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
647 &client->tune_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300648}
649
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300650static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300651{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300652 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300653 struct smsdvb_client_t *client =
654 container_of(fe, struct smsdvb_client_t, frontend);
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300655 int board_id = smscore_get_board_id(client->coredev);
656 struct sms_board *board = sms_get_board(board_id);
657 enum sms_device_type_st type = board->type;
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -0300658 int ret;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300659 struct {
660 struct SmsMsgHdr_ST Msg;
661 u32 Data[4];
662 } Msg;
663
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300664 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
665
Michael Krufky6b26fce2009-12-22 21:08:49 -0300666 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
667 Msg.Msg.msgDstId = HIF_TASK;
668 Msg.Msg.msgFlags = 0;
669 Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
670 Msg.Msg.msgLength = sizeof(Msg);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300671
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300672 if (c->isdbt_sb_segment_idx == -1)
673 c->isdbt_sb_segment_idx = 0;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300674
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300675 if (!c->isdbt_layer_enabled)
676 c->isdbt_layer_enabled = 7;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300677
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300678 Msg.Data[0] = c->frequency;
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300679 Msg.Data[1] = BW_ISDBT_1SEG;
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300680 Msg.Data[2] = 12000000;
681 Msg.Data[3] = c->isdbt_sb_segment_idx;
682
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300683 if (c->isdbt_partial_reception) {
684 if ((type == SMS_PELE || type == SMS_RIO) &&
685 c->isdbt_sb_segment_count > 3)
686 Msg.Data[1] = BW_ISDBT_13SEG;
687 else if (c->isdbt_sb_segment_count > 1)
688 Msg.Data[1] = BW_ISDBT_3SEG;
689 } else if (type == SMS_PELE || type == SMS_RIO)
690 Msg.Data[1] = BW_ISDBT_13SEG;
691
692 c->bandwidth_hz = 6000000;
693
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300694 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
695 c->frequency, c->isdbt_sb_segment_count,
696 c->isdbt_sb_segment_idx);
697
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -0300698 /* Disable LNA, if any. An error is returned if no LNA is present */
699 ret = sms_board_lna_control(client->coredev, 0);
700 if (ret == 0) {
701 fe_status_t status;
702
703 /* tune with LNA off at first */
704 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
705 &client->tune_done);
706
707 smsdvb_read_status(fe, &status);
708
709 if (status & FE_HAS_LOCK)
710 return ret;
711
712 /* previous tune didn't lock - enable LNA and tune again */
713 sms_board_lna_control(client->coredev, 1);
714 }
Michael Krufky6b26fce2009-12-22 21:08:49 -0300715 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
716 &client->tune_done);
717}
718
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300719static int smsdvb_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300720{
721 struct smsdvb_client_t *client =
722 container_of(fe, struct smsdvb_client_t, frontend);
723 struct smscore_device_t *coredev = client->coredev;
724
725 switch (smscore_get_device_mode(coredev)) {
726 case DEVICE_MODE_DVBT:
727 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300728 return smsdvb_dvbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300729 case DEVICE_MODE_ISDBT:
730 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300731 return smsdvb_isdbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300732 default:
733 return -EINVAL;
734 }
735}
736
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -0300737static int smsdvb_get_frontend(struct dvb_frontend *fe)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300738{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -0300739 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Michael Krufky18245e12008-06-15 17:52:24 -0300740 struct smsdvb_client_t *client =
741 container_of(fe, struct smsdvb_client_t, frontend);
Gianluca Gennarid1382102012-02-20 07:50:33 -0300742 struct smscore_device_t *coredev = client->coredev;
743 struct TRANSMISSION_STATISTICS_S *td =
744 &client->sms_stat_dvb.TransmissionData;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300745
Gianluca Gennarid1382102012-02-20 07:50:33 -0300746 switch (smscore_get_device_mode(coredev)) {
747 case DEVICE_MODE_DVBT:
748 case DEVICE_MODE_DVBT_BDA:
749 fep->frequency = td->Frequency;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300750
Gianluca Gennarid1382102012-02-20 07:50:33 -0300751 switch (td->Bandwidth) {
752 case 6:
753 fep->bandwidth_hz = 6000000;
754 break;
755 case 7:
756 fep->bandwidth_hz = 7000000;
757 break;
758 case 8:
759 fep->bandwidth_hz = 8000000;
760 break;
761 }
762
763 switch (td->TransmissionMode) {
764 case 2:
765 fep->transmission_mode = TRANSMISSION_MODE_2K;
766 break;
767 case 8:
768 fep->transmission_mode = TRANSMISSION_MODE_8K;
769 }
770
771 switch (td->GuardInterval) {
772 case 0:
773 fep->guard_interval = GUARD_INTERVAL_1_32;
774 break;
775 case 1:
776 fep->guard_interval = GUARD_INTERVAL_1_16;
777 break;
778 case 2:
779 fep->guard_interval = GUARD_INTERVAL_1_8;
780 break;
781 case 3:
782 fep->guard_interval = GUARD_INTERVAL_1_4;
783 break;
784 }
785
786 switch (td->CodeRate) {
787 case 0:
788 fep->code_rate_HP = FEC_1_2;
789 break;
790 case 1:
791 fep->code_rate_HP = FEC_2_3;
792 break;
793 case 2:
794 fep->code_rate_HP = FEC_3_4;
795 break;
796 case 3:
797 fep->code_rate_HP = FEC_5_6;
798 break;
799 case 4:
800 fep->code_rate_HP = FEC_7_8;
801 break;
802 }
803
804 switch (td->LPCodeRate) {
805 case 0:
806 fep->code_rate_LP = FEC_1_2;
807 break;
808 case 1:
809 fep->code_rate_LP = FEC_2_3;
810 break;
811 case 2:
812 fep->code_rate_LP = FEC_3_4;
813 break;
814 case 3:
815 fep->code_rate_LP = FEC_5_6;
816 break;
817 case 4:
818 fep->code_rate_LP = FEC_7_8;
819 break;
820 }
821
822 switch (td->Constellation) {
823 case 0:
824 fep->modulation = QPSK;
825 break;
826 case 1:
827 fep->modulation = QAM_16;
828 break;
829 case 2:
830 fep->modulation = QAM_64;
831 break;
832 }
833
834 switch (td->Hierarchy) {
835 case 0:
836 fep->hierarchy = HIERARCHY_NONE;
837 break;
838 case 1:
839 fep->hierarchy = HIERARCHY_1;
840 break;
841 case 2:
842 fep->hierarchy = HIERARCHY_2;
843 break;
844 case 3:
845 fep->hierarchy = HIERARCHY_4;
846 break;
847 }
848
849 fep->inversion = INVERSION_AUTO;
850 break;
851 case DEVICE_MODE_ISDBT:
852 case DEVICE_MODE_ISDBT_BDA:
853 fep->frequency = td->Frequency;
854 fep->bandwidth_hz = 6000000;
855 /* todo: retrive the other parameters */
856 break;
857 default:
858 return -EINVAL;
859 }
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300860
861 return 0;
862}
863
864static int smsdvb_init(struct dvb_frontend *fe)
865{
866 struct smsdvb_client_t *client =
867 container_of(fe, struct smsdvb_client_t, frontend);
868
Michael Krufky3746b612009-07-12 23:30:14 -0300869 sms_board_power(client->coredev, 1);
870
Uri Shkolnik793786d2009-05-12 12:28:46 -0300871 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300872 return 0;
873}
874
875static int smsdvb_sleep(struct dvb_frontend *fe)
876{
877 struct smsdvb_client_t *client =
878 container_of(fe, struct smsdvb_client_t, frontend);
879
Michael Krufky3746b612009-07-12 23:30:14 -0300880 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
881 sms_board_power(client->coredev, 0);
882
Uri Shkolnik793786d2009-05-12 12:28:46 -0300883 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300884
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300885 return 0;
886}
887
888static void smsdvb_release(struct dvb_frontend *fe)
889{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300890 /* do nothing */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300891}
892
893static struct dvb_frontend_ops smsdvb_fe_ops = {
894 .info = {
Uri Shkolnike0f14c22008-08-31 00:44:04 -0300895 .name = "Siano Mobile Digital MDTV Receiver",
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300896 .frequency_min = 44250000,
897 .frequency_max = 867250000,
898 .frequency_stepsize = 250000,
899 .caps = FE_CAN_INVERSION_AUTO |
Michael Krufky82237412008-06-15 15:14:13 -0300900 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
901 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
902 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
903 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
904 FE_CAN_GUARD_INTERVAL_AUTO |
905 FE_CAN_RECOVER |
906 FE_CAN_HIERARCHY_AUTO,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300907 },
908
909 .release = smsdvb_release,
910
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300911 .set_frontend = smsdvb_set_frontend,
912 .get_frontend = smsdvb_get_frontend,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300913 .get_tune_settings = smsdvb_get_tune_settings,
914
915 .read_status = smsdvb_read_status,
916 .read_ber = smsdvb_read_ber,
917 .read_signal_strength = smsdvb_read_signal_strength,
918 .read_snr = smsdvb_read_snr,
Michael Krufky851a9092008-11-22 14:56:37 -0300919 .read_ucblocks = smsdvb_read_ucblocks,
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300920
921 .init = smsdvb_init,
922 .sleep = smsdvb_sleep,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300923};
924
Michael Krufky0c071f32008-06-21 02:44:02 -0300925static int smsdvb_hotplug(struct smscore_device_t *coredev,
926 struct device *device, int arrival)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300927{
Michael Krufky18245e12008-06-15 17:52:24 -0300928 struct smsclient_params_t params;
929 struct smsdvb_client_t *client;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300930 int rc;
931
Michael Krufkyfa830e82008-06-15 15:52:43 -0300932 /* device removal handled by onremove callback */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300933 if (!arrival)
934 return 0;
Michael Krufky18245e12008-06-15 17:52:24 -0300935 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
Michael Krufky82237412008-06-15 15:14:13 -0300936 if (!client) {
Michael Krufkyeb250942008-06-19 22:07:23 -0300937 sms_err("kmalloc() failed");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300938 return -ENOMEM;
939 }
940
Michael Krufkyfa830e82008-06-15 15:52:43 -0300941 /* register dvb adapter */
Michael Krufky1c11d542008-06-18 22:09:55 -0300942 rc = dvb_register_adapter(&client->adapter,
943 sms_get_board(
944 smscore_get_board_id(coredev))->name,
Michael Krufky82237412008-06-15 15:14:13 -0300945 THIS_MODULE, device, adapter_nr);
946 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300947 sms_err("dvb_register_adapter() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300948 goto adapter_error;
949 }
950
Michael Krufkyfa830e82008-06-15 15:52:43 -0300951 /* init dvb demux */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300952 client->demux.dmx.capabilities = DMX_TS_FILTERING;
Michael Krufkyfa830e82008-06-15 15:52:43 -0300953 client->demux.filternum = 32; /* todo: nova ??? */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300954 client->demux.feednum = 32;
955 client->demux.start_feed = smsdvb_start_feed;
956 client->demux.stop_feed = smsdvb_stop_feed;
957
958 rc = dvb_dmx_init(&client->demux);
Michael Krufky82237412008-06-15 15:14:13 -0300959 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300960 sms_err("dvb_dmx_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300961 goto dvbdmx_error;
962 }
963
Michael Krufkyfa830e82008-06-15 15:52:43 -0300964 /* init dmxdev */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300965 client->dmxdev.filternum = 32;
966 client->dmxdev.demux = &client->demux.dmx;
967 client->dmxdev.capabilities = 0;
968
969 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
Michael Krufky82237412008-06-15 15:14:13 -0300970 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300971 sms_err("dvb_dmxdev_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300972 goto dmxdev_error;
973 }
974
Michael Krufkyfa830e82008-06-15 15:52:43 -0300975 /* init and register frontend */
Michael Krufky82237412008-06-15 15:14:13 -0300976 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
977 sizeof(struct dvb_frontend_ops));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300978
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300979 switch (smscore_get_device_mode(coredev)) {
980 case DEVICE_MODE_DVBT:
981 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -0300982 client->frontend.ops.delsys[0] = SYS_DVBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300983 break;
984 case DEVICE_MODE_ISDBT:
985 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -0300986 client->frontend.ops.delsys[0] = SYS_ISDBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300987 break;
988 }
989
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300990 rc = dvb_register_frontend(&client->adapter, &client->frontend);
Michael Krufky82237412008-06-15 15:14:13 -0300991 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300992 sms_err("frontend registration failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300993 goto frontend_error;
994 }
995
Michael Krufkyf17407a2008-06-14 00:43:26 -0300996 params.initial_id = 1;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300997 params.data_type = MSG_SMS_DVBT_BDA_DATA;
998 params.onresponse_handler = smsdvb_onresponse;
999 params.onremove_handler = smsdvb_onremove;
1000 params.context = client;
1001
1002 rc = smscore_register_client(coredev, &params, &client->smsclient);
Michael Krufky82237412008-06-15 15:14:13 -03001003 if (rc < 0) {
Michael Krufkyeb250942008-06-19 22:07:23 -03001004 sms_err("smscore_register_client() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001005 goto client_error;
1006 }
1007
1008 client->coredev = coredev;
1009
1010 init_completion(&client->tune_done);
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -03001011 init_completion(&client->stats_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001012
1013 kmutex_lock(&g_smsdvb_clientslock);
1014
1015 list_add(&client->entry, &g_smsdvb_clients);
1016
1017 kmutex_unlock(&g_smsdvb_clientslock);
1018
Uri Shkolnik793786d2009-05-12 12:28:46 -03001019 client->event_fe_state = -1;
1020 client->event_unc_state = -1;
1021 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001022
Uri Shkolnik793786d2009-05-12 12:28:46 -03001023 sms_info("success");
Michael Krufky250fa672008-11-16 22:45:42 -03001024 sms_board_setup(coredev);
1025
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001026 return 0;
1027
1028client_error:
1029 dvb_unregister_frontend(&client->frontend);
1030
1031frontend_error:
1032 dvb_dmxdev_release(&client->dmxdev);
1033
1034dmxdev_error:
1035 dvb_dmx_release(&client->demux);
1036
1037dvbdmx_error:
1038 dvb_unregister_adapter(&client->adapter);
1039
1040adapter_error:
1041 kfree(client);
1042 return rc;
1043}
1044
Márton Németh2184dda2009-12-11 20:05:10 -03001045static int __init smsdvb_module_init(void)
Steven Totheae55662008-05-22 18:04:36 -03001046{
1047 int rc;
1048
1049 INIT_LIST_HEAD(&g_smsdvb_clients);
1050 kmutex_init(&g_smsdvb_clientslock);
1051
1052 rc = smscore_register_hotplug(smsdvb_hotplug);
1053
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001054 sms_debug("");
Steven Totheae55662008-05-22 18:04:36 -03001055
1056 return rc;
1057}
1058
Márton Németh2184dda2009-12-11 20:05:10 -03001059static void __exit smsdvb_module_exit(void)
Steven Totheae55662008-05-22 18:04:36 -03001060{
1061 smscore_unregister_hotplug(smsdvb_hotplug);
1062
1063 kmutex_lock(&g_smsdvb_clientslock);
1064
1065 while (!list_empty(&g_smsdvb_clients))
Michael Krufky82237412008-06-15 15:14:13 -03001066 smsdvb_unregister_client(
Michael Krufky18245e12008-06-15 17:52:24 -03001067 (struct smsdvb_client_t *) g_smsdvb_clients.next);
Steven Totheae55662008-05-22 18:04:36 -03001068
1069 kmutex_unlock(&g_smsdvb_clientslock);
Steven Totheae55662008-05-22 18:04:36 -03001070}
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001071
1072module_init(smsdvb_module_init);
1073module_exit(smsdvb_module_exit);
1074
1075MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
Uri Shkolnik843d0602009-05-12 13:13:13 -03001076MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001077MODULE_LICENSE("GPL");