blob: 70ea3e9b4ac6f710147fd32919a61d0351fb5220 [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"
Michael Krufky1c11d542008-06-18 22:09:55 -030032#include "sms-cards.h"
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030033
Michael Krufky9c59f9682008-05-19 18:57:12 -030034DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
35
Michael Krufky62c7167d2008-08-31 17:15:47 -030036struct smsdvb_client_t {
37 struct list_head entry;
38
39 struct smscore_device_t *coredev;
40 struct smscore_client_t *smsclient;
41
42 struct dvb_adapter adapter;
43 struct dvb_demux demux;
44 struct dmxdev dmxdev;
45 struct dvb_frontend frontend;
46
47 fe_status_t fe_status;
Michael Krufky62c7167d2008-08-31 17:15:47 -030048
Uri Shkolnik793786d2009-05-12 12:28:46 -030049 struct completion tune_done;
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -030050 struct completion stats_done;
Michael Krufky62c7167d2008-08-31 17:15:47 -030051
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -030052 int last_per;
53
54 int legacy_ber, legacy_per;
55
Uri Shkolnik793786d2009-05-12 12:28:46 -030056 int event_fe_state;
57 int event_unc_state;
Michael Krufky62c7167d2008-08-31 17:15:47 -030058};
59
Adrian Bunkc5e0bd12008-07-21 23:17:36 -030060static struct list_head g_smsdvb_clients;
61static struct mutex g_smsdvb_clientslock;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030062
Michael Krufky0d02efe2009-02-27 02:42:16 -030063static 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
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -030067/*
68 * This struct is a mix of RECEPTION_STATISTICS_EX_S and SRVM_SIGNAL_STATUS_S.
69 * It was obtained by comparing the way it was filled by the original code
70 */
71struct RECEPTION_STATISTICS_PER_SLICES_S {
72 u32 result;
73 u32 snr;
74 s32 inBandPower;
75 u32 tsPackets;
76 u32 etsPackets;
77 u32 constellation;
78 u32 hpCode;
79 u32 tpsSrvIndLP;
80 u32 tpsSrvIndHP;
81 u32 cellId;
82 u32 reason;
83 u32 requestId;
84 u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
85
86 u32 BER; /* Post Viterbi BER [1E-5] */
87 s32 RSSI; /* dBm */
88 s32 CarrierOffset; /* Carrier Offset in bin/1024 */
89
90 u32 IsRfLocked; /* 0 - not locked, 1 - locked */
91 u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
92
93 u32 BERBitCount; /* Total number of SYNC bits. */
94 u32 BERErrorCount; /* Number of erronous SYNC bits. */
95
96 s32 MRC_SNR; /* dB */
97 s32 MRC_InBandPwr; /* In band power in dBM */
98 s32 MRC_RSSI; /* dBm */
99};
100
101u32 sms_to_bw_table[] = {
102 [BW_8_MHZ] = 8000000,
103 [BW_7_MHZ] = 7000000,
104 [BW_6_MHZ] = 6000000,
105 [BW_5_MHZ] = 5000000,
106 [BW_2_MHZ] = 2000000,
107 [BW_1_5_MHZ] = 1500000,
108 [BW_ISDBT_1SEG] = 6000000,
109 [BW_ISDBT_3SEG] = 6000000,
110 [BW_ISDBT_13SEG] = 6000000,
111};
112
113u32 sms_to_guard_interval_table[] = {
114 [0] = GUARD_INTERVAL_1_32,
115 [1] = GUARD_INTERVAL_1_16,
116 [2] = GUARD_INTERVAL_1_8,
117 [3] = GUARD_INTERVAL_1_4,
118};
119
120u32 sms_to_code_rate_table[] = {
121 [0] = FEC_1_2,
122 [1] = FEC_2_3,
123 [2] = FEC_3_4,
124 [3] = FEC_5_6,
125 [4] = FEC_7_8,
126};
127
128
129u32 sms_to_hierarchy_table[] = {
130 [0] = HIERARCHY_NONE,
131 [1] = HIERARCHY_1,
132 [2] = HIERARCHY_2,
133 [3] = HIERARCHY_4,
134};
135
136u32 sms_to_modulation_table[] = {
137 [0] = QPSK,
138 [1] = QAM_16,
139 [2] = QAM_64,
140 [3] = DQPSK,
141};
142
Mauro Carvalho Chehabff702eb2013-03-09 15:54:46 -0300143static void smsdvb_print_dvb_stats(struct SMSHOSTLIB_STATISTICS_ST *p)
144{
145 if (!(sms_dbg & 2))
146 return;
147
148 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
149 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
150 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
151 printk(KERN_DEBUG "SNR = %d", p->SNR);
152 printk(KERN_DEBUG "BER = %d", p->BER);
153 printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
154 printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
155 printk(KERN_DEBUG "MFER = %d", p->MFER);
156 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
157 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
158 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
159 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
160 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
161 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
162 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
163 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
164 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
165 printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
166 printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
167 printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
168 printk(KERN_DEBUG "Constellation = %d", p->Constellation);
169 printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
170 printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
171 printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
172 printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
173 printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
174 printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
175 printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
176 printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
177 printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
178 printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
179 printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
180 printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
181 printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
182 printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
183 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
184 printk(KERN_DEBUG "PreBER = %d", p->PreBER);
185 printk(KERN_DEBUG "CellId = %d", p->CellId);
186 printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
187 printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
188 printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
189}
190
191static void smsdvb_print_isdb_stats(struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
192{
193 int i;
194
195 if (!(sms_dbg & 2))
196 return;
197
198 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
199 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
200 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
201 printk(KERN_DEBUG "SNR = %d", p->SNR);
202 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
203 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
204 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
205 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
206 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
207 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
208 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
209 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
210 printk(KERN_DEBUG "SystemType = %d", p->SystemType);
211 printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
212 printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
213 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
214
215 for (i = 0; i < 3; i++) {
216 printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
217 printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
218 printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
219 printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
220 printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
221 printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
222 printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
223 printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
224 printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
225 printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
226 printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
227 printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
228 }
229}
230
231static void
232smsdvb_print_isdb_stats_ex(struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
233{
234 int i;
235
236 if (!(sms_dbg & 2))
237 return;
238
239 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
240 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
241 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
242 printk(KERN_DEBUG "SNR = %d", p->SNR);
243 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
244 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
245 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
246 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
247 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
248 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
249 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
250 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
251 printk(KERN_DEBUG "SystemType = %d", p->SystemType);
252 printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
253 printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
254 printk(KERN_DEBUG "SegmentNumber = %d", p->SegmentNumber);
255 printk(KERN_DEBUG "TuneBW = %d", p->TuneBW);
256
257 for (i = 0; i < 3; i++) {
258 printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
259 printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
260 printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
261 printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
262 printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
263 printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
264 printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
265 printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
266 printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
267 printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
268 printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
269 printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
270 }
271}
272
Uri Shkolnik793786d2009-05-12 12:28:46 -0300273/* Events that may come from DVB v3 adapter */
274static void sms_board_dvb3_event(struct smsdvb_client_t *client,
275 enum SMS_DVB3_EVENTS event) {
Uri Shkolnik4db989f2009-05-19 12:28:02 -0300276
277 struct smscore_device_t *coredev = client->coredev;
278 switch (event) {
279 case DVB3_EVENT_INIT:
280 sms_debug("DVB3_EVENT_INIT");
281 sms_board_event(coredev, BOARD_EVENT_BIND);
282 break;
283 case DVB3_EVENT_SLEEP:
284 sms_debug("DVB3_EVENT_SLEEP");
285 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
286 break;
287 case DVB3_EVENT_HOTPLUG:
288 sms_debug("DVB3_EVENT_HOTPLUG");
289 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
290 break;
291 case DVB3_EVENT_FE_LOCK:
292 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
293 client->event_fe_state = DVB3_EVENT_FE_LOCK;
294 sms_debug("DVB3_EVENT_FE_LOCK");
295 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
296 }
297 break;
298 case DVB3_EVENT_FE_UNLOCK:
299 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
300 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
301 sms_debug("DVB3_EVENT_FE_UNLOCK");
302 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
303 }
304 break;
305 case DVB3_EVENT_UNC_OK:
306 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
307 client->event_unc_state = DVB3_EVENT_UNC_OK;
308 sms_debug("DVB3_EVENT_UNC_OK");
309 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
310 }
311 break;
312 case DVB3_EVENT_UNC_ERR:
313 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
314 client->event_unc_state = DVB3_EVENT_UNC_ERR;
315 sms_debug("DVB3_EVENT_UNC_ERR");
316 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
317 }
318 break;
319
320 default:
321 sms_err("Unknown dvb3 api event");
322 break;
323 }
Uri Shkolnik793786d2009-05-12 12:28:46 -0300324}
325
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300326static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300327{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300328 struct smsdvb_client_t *client =
329 container_of(fe, struct smsdvb_client_t, frontend);
330 struct smscore_device_t *coredev = client->coredev;
331 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
332 int i, n_layers;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300333
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300334 switch (smscore_get_device_mode(coredev)) {
335 case DEVICE_MODE_ISDBT:
336 case DEVICE_MODE_ISDBT_BDA:
337 n_layers = 4;
338 default:
339 n_layers = 1;
340 }
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300341
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300342 /* Fill the length of each status counter */
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300343
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300344 /* Only global stats */
345 c->strength.len = 1;
346 c->cnr.len = 1;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300347
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300348 /* Per-layer stats */
349 c->post_bit_error.len = n_layers;
350 c->post_bit_count.len = n_layers;
351 c->block_error.len = n_layers;
352 c->block_count.len = n_layers;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300353
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300354 /* Signal is always available */
355 c->strength.stat[0].scale = FE_SCALE_RELATIVE;
356 c->strength.stat[0].uvalue = 0;
357
358 /* Put all of them at FE_SCALE_NOT_AVAILABLE */
359 for (i = 0; i < n_layers; i++) {
360 c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
361 c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
362 c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
363 c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
364 c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300365 }
366}
367
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300368static inline int sms_to_mode(u32 mode)
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300369{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300370 switch (mode) {
371 case 2:
372 return TRANSMISSION_MODE_2K;
373 case 4:
374 return TRANSMISSION_MODE_4K;
375 case 8:
376 return TRANSMISSION_MODE_8K;
377 }
378 return TRANSMISSION_MODE_AUTO;
379}
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300380
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300381static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)
382{
383 if (is_demod_locked)
384 return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
385 FE_HAS_SYNC | FE_HAS_LOCK;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300386
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300387 if (is_rf_locked)
388 return FE_HAS_SIGNAL | FE_HAS_CARRIER;
389
390 return 0;
391}
392
393
394#define convert_from_table(value, table, defval) ({ \
395 u32 __ret; \
396 if (value < ARRAY_SIZE(table)) \
397 __ret = table[value]; \
398 else \
399 __ret = defval; \
400 __ret; \
401})
402
403#define sms_to_bw(value) \
404 convert_from_table(value, sms_to_bw_table, 0);
405
406#define sms_to_guard_interval(value) \
407 convert_from_table(value, sms_to_guard_interval_table, \
408 GUARD_INTERVAL_AUTO);
409
410#define sms_to_code_rate(value) \
411 convert_from_table(value, sms_to_code_rate_table, \
412 FEC_NONE);
413
414#define sms_to_hierarchy(value) \
415 convert_from_table(value, sms_to_hierarchy_table, \
416 FEC_NONE);
417
418#define sms_to_modulation(value) \
419 convert_from_table(value, sms_to_modulation_table, \
420 FEC_NONE);
421
422static void smsdvb_update_tx_params(struct smsdvb_client_t *client,
423 struct TRANSMISSION_STATISTICS_S *p)
424{
425 struct dvb_frontend *fe = &client->frontend;
426 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
427
428 c->frequency = p->Frequency;
429 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
430 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
431 c->transmission_mode = sms_to_mode(p->TransmissionMode);
432 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
433 c->code_rate_HP = sms_to_code_rate(p->CodeRate);
434 c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
435 c->hierarchy = sms_to_hierarchy(p->Hierarchy);
436 c->modulation = sms_to_modulation(p->Constellation);
437}
438
439static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
440 struct RECEPTION_STATISTICS_PER_SLICES_S *p)
441{
442 struct dvb_frontend *fe = &client->frontend;
443 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
444
445 client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
446 c->modulation = sms_to_modulation(p->constellation);
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300447
448 /* TS PER */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300449 client->last_per = c->block_error.stat[0].uvalue;
450 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
451 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
452 c->block_error.stat[0].uvalue += p->etsPackets;
453 c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets;
454
455 /* BER */
456 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
457 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
458 c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
459 c->post_bit_count.stat[0].uvalue += p->BERBitCount;
460
461 /* Legacy PER/BER */
462 client->legacy_per = (p->etsPackets * 65535) /
463 (p->tsPackets + p->etsPackets);
464
465 /* Signal Strength, in DBm */
466 c->strength.stat[0].uvalue = p->RSSI * 1000;
467
468 /* Carrier to Noise ratio, in DB */
469 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
470 c->cnr.stat[0].svalue = p->snr * 1000;
471}
472
473static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
474 struct SMSHOSTLIB_STATISTICS_ST *p)
475{
476 struct dvb_frontend *fe = &client->frontend;
477 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
478
479 smsdvb_print_dvb_stats(p);
480
481 client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
482
483 /* Update DVB modulation parameters */
484 c->frequency = p->Frequency;
485 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
486 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
487 c->transmission_mode = sms_to_mode(p->TransmissionMode);
488 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
489 c->code_rate_HP = sms_to_code_rate(p->CodeRate);
490 c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
491 c->hierarchy = sms_to_hierarchy(p->Hierarchy);
492 c->modulation = sms_to_modulation(p->Constellation);
493
494 /* update reception data */
495 c->lna = p->IsExternalLNAOn ? 1 : 0;
496
497 /* Carrier to Noise ratio, in DB */
498 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
499 c->cnr.stat[0].svalue = p->SNR * 1000;
500
501 /* Signal Strength, in DBm */
502 c->strength.stat[0].uvalue = p->RSSI * 1000;
503
504 /* TS PER */
505 client->last_per = c->block_error.stat[0].uvalue;
506 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
507 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
508 c->block_error.stat[0].uvalue += p->ErrorTSPackets;
509 c->block_count.stat[0].uvalue += p->TotalTSPackets;
510
511 /* BER */
512 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
513 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
514 c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
515 c->post_bit_count.stat[0].uvalue += p->BERBitCount;
516
517 /* Legacy PER/BER */
518 client->legacy_ber = p->BER;
519};
520
521static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
522 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
523{
524 struct dvb_frontend *fe = &client->frontend;
525 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
526 struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
527 int i, n_layers;
528
529 smsdvb_print_isdb_stats(p);
530
531 /* Update ISDB-T transmission parameters */
532 c->frequency = p->Frequency;
533 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
534 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
535 c->transmission_mode = sms_to_mode(p->TransmissionMode);
536 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
537 c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
538 n_layers = p->NumOfLayers;
539 if (n_layers < 1)
540 n_layers = 1;
541 if (n_layers > 3)
542 n_layers = 3;
543 c->isdbt_layer_enabled = 0;
544
545 /* update reception data */
546 c->lna = p->IsExternalLNAOn ? 1 : 0;
547
548 /* Carrier to Noise ratio, in DB */
549 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
550 c->cnr.stat[0].svalue = p->SNR * 1000;
551
552 /* Signal Strength, in DBm */
553 c->strength.stat[0].uvalue = p->RSSI * 1000;
554
555 client->last_per = c->block_error.stat[0].uvalue;
556
557 /* Clears global counters, as the code below will sum it again */
558 c->block_error.stat[0].uvalue = 0;
559 c->block_count.stat[0].uvalue = 0;
560 c->post_bit_error.stat[0].uvalue = 0;
561 c->post_bit_count.stat[0].uvalue = 0;
562
563 for (i = 0; i < n_layers; i++) {
564 lr = &p->LayerInfo[i];
565
566 /* Update per-layer transmission parameters */
567 if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
568 c->isdbt_layer_enabled |= 1 << i;
569 c->layer[i].segment_count = lr->NumberOfSegments;
570 } else {
571 continue;
572 }
573 c->layer[i].modulation = sms_to_modulation(lr->Constellation);
574
575 /* TS PER */
576 c->block_error.stat[i].scale = FE_SCALE_COUNTER;
577 c->block_count.stat[i].scale = FE_SCALE_COUNTER;
578 c->block_error.stat[i].uvalue += lr->ErrorTSPackets;
579 c->block_count.stat[i].uvalue += lr->TotalTSPackets;
580
581 /* Update global PER counter */
582 c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
583 c->block_count.stat[0].uvalue += lr->TotalTSPackets;
584
585 /* BER */
586 c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER;
587 c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER;
588 c->post_bit_error.stat[i].uvalue += lr->BERErrorCount;
589 c->post_bit_count.stat[i].uvalue += lr->BERBitCount;
590
591 /* Update global BER counter */
592 c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
593 c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
594 }
595}
596
597static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
598 struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
599{
600 struct dvb_frontend *fe = &client->frontend;
601 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
602 struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
603 int i, n_layers;
604
605 smsdvb_print_isdb_stats_ex(p);
606
607 /* Update ISDB-T transmission parameters */
608 c->frequency = p->Frequency;
609 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
610 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
611 c->transmission_mode = sms_to_mode(p->TransmissionMode);
612 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
613 c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
614 n_layers = p->NumOfLayers;
615 if (n_layers < 1)
616 n_layers = 1;
617 if (n_layers > 3)
618 n_layers = 3;
619 c->isdbt_layer_enabled = 0;
620
621 /* update reception data */
622 c->lna = p->IsExternalLNAOn ? 1 : 0;
623
624 /* Carrier to Noise ratio, in DB */
625 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
626 c->cnr.stat[0].svalue = p->SNR * 1000;
627
628 /* Signal Strength, in DBm */
629 c->strength.stat[0].uvalue = p->RSSI * 1000;
630
631 client->last_per = c->block_error.stat[0].uvalue;
632
633 /* Clears global counters, as the code below will sum it again */
634 c->block_error.stat[0].uvalue = 0;
635 c->block_count.stat[0].uvalue = 0;
636 c->post_bit_error.stat[0].uvalue = 0;
637 c->post_bit_count.stat[0].uvalue = 0;
638
639 for (i = 0; i < n_layers; i++) {
640 lr = &p->LayerInfo[i];
641
642 /* Update per-layer transmission parameters */
643 if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
644 c->isdbt_layer_enabled |= 1 << i;
645 c->layer[i].segment_count = lr->NumberOfSegments;
646 } else {
647 continue;
648 }
649 c->layer[i].modulation = sms_to_modulation(lr->Constellation);
650
651 /* TS PER */
652 c->block_error.stat[i].scale = FE_SCALE_COUNTER;
653 c->block_count.stat[i].scale = FE_SCALE_COUNTER;
654 c->block_error.stat[i].uvalue += lr->ErrorTSPackets;
655 c->block_count.stat[i].uvalue += lr->TotalTSPackets;
656
657 /* Update global PER counter */
658 c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
659 c->block_count.stat[0].uvalue += lr->TotalTSPackets;
660
661 /* BER */
662 c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER;
663 c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER;
664 c->post_bit_error.stat[i].uvalue += lr->BERErrorCount;
665 c->post_bit_count.stat[i].uvalue += lr->BERBitCount;
666
667 /* Update global BER counter */
668 c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
669 c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300670 }
671}
672
Michael Krufky0c071f32008-06-21 02:44:02 -0300673static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300674{
Michael Krufky18245e12008-06-15 17:52:24 -0300675 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300676 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
677 + cb->offset);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300678 void *p = phdr + 1;
679 struct dvb_frontend *fe = &client->frontend;
680 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300681 bool is_status_update = false;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300682
Michael Krufkyfa830e82008-06-15 15:52:43 -0300683 switch (phdr->msgType) {
Michael Krufky82237412008-06-15 15:14:13 -0300684 case MSG_SMS_DVBT_BDA_DATA:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300685 dvb_dmx_swfilter(&client->demux, p,
Michael Krufky18245e12008-06-15 17:52:24 -0300686 cb->size - sizeof(struct SmsMsgHdr_ST));
Michael Krufky82237412008-06-15 15:14:13 -0300687 break;
688
689 case MSG_SMS_RF_TUNE_RES:
Michael Krufky6b26fce2009-12-22 21:08:49 -0300690 case MSG_SMS_ISDBT_TUNE_RES:
Michael Krufky82237412008-06-15 15:14:13 -0300691 complete(&client->tune_done);
692 break;
693
Uri Shkolnik793786d2009-05-12 12:28:46 -0300694 case MSG_SMS_SIGNAL_DETECTED_IND:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300695 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
696 FE_HAS_VITERBI | FE_HAS_SYNC |
697 FE_HAS_LOCK;
698
Uri Shkolnik793786d2009-05-12 12:28:46 -0300699 is_status_update = true;
700 break;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300701
Uri Shkolnik793786d2009-05-12 12:28:46 -0300702 case MSG_SMS_NO_SIGNAL_IND:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300703 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300704
705 is_status_update = true;
706 break;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300707
708 case MSG_SMS_TRANSMISSION_IND:
709 smsdvb_update_tx_params(client, p);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300710
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300711 is_status_update = true;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300712 break;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300713
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300714 case MSG_SMS_HO_PER_SLICES_IND:
715 smsdvb_update_per_slices(client, p);
716
717 is_status_update = true;
718 break;
719
720 case MSG_SMS_GET_STATISTICS_RES:
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300721 switch (smscore_get_device_mode(client->coredev)) {
722 case DEVICE_MODE_ISDBT:
723 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300724 smsdvb_update_isdbt_stats(client, p);
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300725 break;
726 default:
Mauro Carvalho Chehabc02272f2013-03-09 23:01:48 -0300727 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */
728 smsdvb_update_dvb_stats(client, p + sizeof(u32));
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300729 }
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300730
731 is_status_update = true;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300732 break;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300733
734 /* Only for ISDB-T */
735 case MSG_SMS_GET_STATISTICS_EX_RES:
Mauro Carvalho Chehabc02272f2013-03-09 23:01:48 -0300736 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */
737 smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300738 is_status_update = true;
739 break;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300740 default:
Mauro Carvalho Chehab4c3bdb52013-03-09 09:27:39 -0300741 sms_info("message not handled");
Uri Shkolnik793786d2009-05-12 12:28:46 -0300742 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300743 smscore_putbuffer(client->coredev, cb);
744
Uri Shkolnik793786d2009-05-12 12:28:46 -0300745 if (is_status_update) {
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300746 if (client->fe_status == FE_HAS_LOCK) {
Uri Shkolnik793786d2009-05-12 12:28:46 -0300747 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300748 if (client->last_per == c->block_error.stat[0].uvalue)
Uri Shkolnik793786d2009-05-12 12:28:46 -0300749 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
750 else
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300751 sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
Uri Shkolnik793786d2009-05-12 12:28:46 -0300752 } else {
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300753 smsdvb_stats_not_ready(fe);
754
Uri Shkolnik793786d2009-05-12 12:28:46 -0300755 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
756 }
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300757 complete(&client->stats_done);
Uri Shkolnik793786d2009-05-12 12:28:46 -0300758 }
759
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300760 return 0;
761}
762
Michael Krufky0c071f32008-06-21 02:44:02 -0300763static void smsdvb_unregister_client(struct smsdvb_client_t *client)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300764{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300765 /* must be called under clientslock */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300766
767 list_del(&client->entry);
768
769 smscore_unregister_client(client->smsclient);
770 dvb_unregister_frontend(&client->frontend);
771 dvb_dmxdev_release(&client->dmxdev);
772 dvb_dmx_release(&client->demux);
773 dvb_unregister_adapter(&client->adapter);
774 kfree(client);
775}
776
Michael Krufky0c071f32008-06-21 02:44:02 -0300777static void smsdvb_onremove(void *context)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300778{
779 kmutex_lock(&g_smsdvb_clientslock);
780
Michael Krufky18245e12008-06-15 17:52:24 -0300781 smsdvb_unregister_client((struct smsdvb_client_t *) context);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300782
783 kmutex_unlock(&g_smsdvb_clientslock);
784}
785
786static int smsdvb_start_feed(struct dvb_demux_feed *feed)
787{
Michael Krufky18245e12008-06-15 17:52:24 -0300788 struct smsdvb_client_t *client =
789 container_of(feed->demux, struct smsdvb_client_t, demux);
790 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300791
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300792 sms_debug("add pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300793 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300794
795 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
796 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
797 PidMsg.xMsgHeader.msgFlags = 0;
798 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
799 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
800 PidMsg.msgData[0] = feed->pid;
801
Michael Krufky82237412008-06-15 15:14:13 -0300802 return smsclient_sendrequest(client->smsclient,
803 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300804}
805
806static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
807{
Michael Krufky18245e12008-06-15 17:52:24 -0300808 struct smsdvb_client_t *client =
809 container_of(feed->demux, struct smsdvb_client_t, demux);
810 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300811
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300812 sms_debug("remove pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300813 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300814
815 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
816 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
817 PidMsg.xMsgHeader.msgFlags = 0;
818 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
819 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
820 PidMsg.msgData[0] = feed->pid;
821
Michael Krufky82237412008-06-15 15:14:13 -0300822 return smsclient_sendrequest(client->smsclient,
823 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300824}
825
Michael Krufky18245e12008-06-15 17:52:24 -0300826static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
Michael Krufkya83ccdd2008-05-06 03:11:51 -0300827 void *buffer, size_t size,
828 struct completion *completion)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300829{
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300830 int rc;
831
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300832 rc = smsclient_sendrequest(client->smsclient, buffer, size);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300833 if (rc < 0)
834 return rc;
835
Michael Krufky82237412008-06-15 15:14:13 -0300836 return wait_for_completion_timeout(completion,
837 msecs_to_jiffies(2000)) ?
838 0 : -ETIME;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300839}
840
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300841static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
842{
843 int rc;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300844 struct SmsMsgHdr_ST Msg;
845
846
847 Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
848 Msg.msgDstId = HIF_TASK;
849 Msg.msgFlags = 0;
850 Msg.msgLength = sizeof(Msg);
851
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300852 switch (smscore_get_device_mode(client->coredev)) {
853 case DEVICE_MODE_ISDBT:
854 case DEVICE_MODE_ISDBT_BDA:
855 /*
856 * Check for firmware version, to avoid breaking for old cards
857 */
858 if (client->coredev->fw_version >= 0x800)
859 Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ;
860 else
861 Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
862 break;
863 default:
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300864 Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300865 }
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300866
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300867 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300868 &client->stats_done);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300869
870 return rc;
871}
872
Michael Krufky3746b612009-07-12 23:30:14 -0300873static inline int led_feedback(struct smsdvb_client_t *client)
874{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300875 if (!(client->fe_status & FE_HAS_LOCK))
Michael Krufky3746b612009-07-12 23:30:14 -0300876 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300877
878 return sms_board_led_feedback(client->coredev,
879 (client->legacy_ber == 0) ?
880 SMS_LED_HI : SMS_LED_LO);
Michael Krufky3746b612009-07-12 23:30:14 -0300881}
882
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300883static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
884{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300885 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300886 struct smsdvb_client_t *client;
887 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300888
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300889 rc = smsdvb_send_statistics_request(client);
890
Uri Shkolnik793786d2009-05-12 12:28:46 -0300891 *stat = client->fe_status;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300892
Michael Krufky3746b612009-07-12 23:30:14 -0300893 led_feedback(client);
894
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300895 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300896}
897
898static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
899{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300900 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300901 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300902
Uri Shkolnik793786d2009-05-12 12:28:46 -0300903 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300904
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300905 rc = smsdvb_send_statistics_request(client);
906
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300907 *ber = client->legacy_ber;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300908
Michael Krufky3746b612009-07-12 23:30:14 -0300909 led_feedback(client);
910
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300911 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300912}
913
914static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
915{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300916 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300917 int rc;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300918 s32 power = (s32) c->strength.stat[0].uvalue;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300919 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300920
Uri Shkolnik793786d2009-05-12 12:28:46 -0300921 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300922
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300923 rc = smsdvb_send_statistics_request(client);
924
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300925 if (power < -95)
Uri Shkolnik793786d2009-05-12 12:28:46 -0300926 *strength = 0;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300927 else if (power > -29)
928 *strength = 65535;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300929 else
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300930 *strength = (power + 95) * 65535 / 66;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300931
Michael Krufky3746b612009-07-12 23:30:14 -0300932 led_feedback(client);
933
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300934 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300935}
936
937static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
938{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300939 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300940 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300941 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300942
Uri Shkolnik793786d2009-05-12 12:28:46 -0300943 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300944
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300945 rc = smsdvb_send_statistics_request(client);
946
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300947 /* Preferred scale for SNR with legacy API: 0.1 dB */
948 *snr = c->cnr.stat[0].svalue / 100;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300949
Michael Krufky3746b612009-07-12 23:30:14 -0300950 led_feedback(client);
951
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300952 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300953}
954
Michael Krufky851a9092008-11-22 14:56:37 -0300955static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
956{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300957 int rc;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300958 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300959 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300960
Uri Shkolnik793786d2009-05-12 12:28:46 -0300961 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky851a9092008-11-22 14:56:37 -0300962
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300963 rc = smsdvb_send_statistics_request(client);
964
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300965 *ucblocks = c->block_error.stat[0].uvalue;
Michael Krufky851a9092008-11-22 14:56:37 -0300966
Michael Krufky3746b612009-07-12 23:30:14 -0300967 led_feedback(client);
968
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300969 return rc;
Michael Krufky851a9092008-11-22 14:56:37 -0300970}
971
Michael Krufky82237412008-06-15 15:14:13 -0300972static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
973 struct dvb_frontend_tune_settings *tune)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300974{
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300975 sms_debug("");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300976
977 tune->min_delay_ms = 400;
978 tune->step_size = 250000;
979 tune->max_drift = 0;
980 return 0;
981}
982
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300983static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300984{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300985 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky18245e12008-06-15 17:52:24 -0300986 struct smsdvb_client_t *client =
987 container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300988
Michael Krufky18245e12008-06-15 17:52:24 -0300989 struct {
990 struct SmsMsgHdr_ST Msg;
Michael Krufky82237412008-06-15 15:14:13 -0300991 u32 Data[3];
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300992 } Msg;
993
Michael Krufky3746b612009-07-12 23:30:14 -0300994 int ret;
995
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300996 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300997 client->event_fe_state = -1;
998 client->event_unc_state = -1;
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300999 fe->dtv_property_cache.delivery_system = SYS_DVBT;
Uri Shkolnik793786d2009-05-12 12:28:46 -03001000
1001 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1002 Msg.Msg.msgDstId = HIF_TASK;
1003 Msg.Msg.msgFlags = 0;
1004 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001005 Msg.Msg.msgLength = sizeof(Msg);
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001006 Msg.Data[0] = c->frequency;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001007 Msg.Data[2] = 12000000;
1008
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001009 sms_info("%s: freq %d band %d", __func__, c->frequency,
1010 c->bandwidth_hz);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001011
Mauro Carvalho Chehab643e15a2009-12-25 07:29:06 -03001012 switch (c->bandwidth_hz / 1000000) {
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001013 case 8:
1014 Msg.Data[1] = BW_8_MHZ;
1015 break;
1016 case 7:
1017 Msg.Data[1] = BW_7_MHZ;
1018 break;
1019 case 6:
1020 Msg.Data[1] = BW_6_MHZ;
1021 break;
1022 case 0:
1023 return -EOPNOTSUPP;
1024 default:
1025 return -EINVAL;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001026 }
Michael Krufky3746b612009-07-12 23:30:14 -03001027 /* Disable LNA, if any. An error is returned if no LNA is present */
1028 ret = sms_board_lna_control(client->coredev, 0);
1029 if (ret == 0) {
1030 fe_status_t status;
1031
1032 /* tune with LNA off at first */
1033 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
1034 &client->tune_done);
1035
1036 smsdvb_read_status(fe, &status);
1037
1038 if (status & FE_HAS_LOCK)
1039 return ret;
1040
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001041 /* previous tune didn't lock - enable LNA and tune again */
Michael Krufky3746b612009-07-12 23:30:14 -03001042 sms_board_lna_control(client->coredev, 1);
1043 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001044
Michael Krufky82237412008-06-15 15:14:13 -03001045 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
1046 &client->tune_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001047}
1048
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001049static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -03001050{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001051 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky6b26fce2009-12-22 21:08:49 -03001052 struct smsdvb_client_t *client =
1053 container_of(fe, struct smsdvb_client_t, frontend);
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -03001054 int board_id = smscore_get_board_id(client->coredev);
1055 struct sms_board *board = sms_get_board(board_id);
1056 enum sms_device_type_st type = board->type;
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -03001057 int ret;
Michael Krufky6b26fce2009-12-22 21:08:49 -03001058 struct {
1059 struct SmsMsgHdr_ST Msg;
1060 u32 Data[4];
1061 } Msg;
1062
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -03001063 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
1064
Michael Krufky6b26fce2009-12-22 21:08:49 -03001065 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1066 Msg.Msg.msgDstId = HIF_TASK;
1067 Msg.Msg.msgFlags = 0;
1068 Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
1069 Msg.Msg.msgLength = sizeof(Msg);
Michael Krufky6b26fce2009-12-22 21:08:49 -03001070
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001071 if (c->isdbt_sb_segment_idx == -1)
1072 c->isdbt_sb_segment_idx = 0;
Michael Krufky6b26fce2009-12-22 21:08:49 -03001073
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -03001074 if (!c->isdbt_layer_enabled)
1075 c->isdbt_layer_enabled = 7;
Michael Krufky6b26fce2009-12-22 21:08:49 -03001076
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001077 Msg.Data[0] = c->frequency;
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -03001078 Msg.Data[1] = BW_ISDBT_1SEG;
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001079 Msg.Data[2] = 12000000;
1080 Msg.Data[3] = c->isdbt_sb_segment_idx;
1081
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -03001082 if (c->isdbt_partial_reception) {
1083 if ((type == SMS_PELE || type == SMS_RIO) &&
1084 c->isdbt_sb_segment_count > 3)
1085 Msg.Data[1] = BW_ISDBT_13SEG;
1086 else if (c->isdbt_sb_segment_count > 1)
1087 Msg.Data[1] = BW_ISDBT_3SEG;
1088 } else if (type == SMS_PELE || type == SMS_RIO)
1089 Msg.Data[1] = BW_ISDBT_13SEG;
1090
1091 c->bandwidth_hz = 6000000;
1092
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -03001093 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
1094 c->frequency, c->isdbt_sb_segment_count,
1095 c->isdbt_sb_segment_idx);
1096
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -03001097 /* Disable LNA, if any. An error is returned if no LNA is present */
1098 ret = sms_board_lna_control(client->coredev, 0);
1099 if (ret == 0) {
1100 fe_status_t status;
1101
1102 /* tune with LNA off at first */
1103 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
1104 &client->tune_done);
1105
1106 smsdvb_read_status(fe, &status);
1107
1108 if (status & FE_HAS_LOCK)
1109 return ret;
1110
1111 /* previous tune didn't lock - enable LNA and tune again */
1112 sms_board_lna_control(client->coredev, 1);
1113 }
Michael Krufky6b26fce2009-12-22 21:08:49 -03001114 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
1115 &client->tune_done);
1116}
1117
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001118static int smsdvb_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -03001119{
1120 struct smsdvb_client_t *client =
1121 container_of(fe, struct smsdvb_client_t, frontend);
1122 struct smscore_device_t *coredev = client->coredev;
1123
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -03001124 smsdvb_stats_not_ready(fe);
1125
Michael Krufky6b26fce2009-12-22 21:08:49 -03001126 switch (smscore_get_device_mode(coredev)) {
1127 case DEVICE_MODE_DVBT:
1128 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001129 return smsdvb_dvbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -03001130 case DEVICE_MODE_ISDBT:
1131 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001132 return smsdvb_isdbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -03001133 default:
1134 return -EINVAL;
1135 }
1136}
1137
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -03001138/* Nothing to do here, as stats are automatically updated */
Mauro Carvalho Chehabeab0fa02013-03-09 12:05:58 -03001139static int smsdvb_get_frontend(struct dvb_frontend *fe)
1140{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -03001141 return 0;
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001142}
1143
1144static int smsdvb_init(struct dvb_frontend *fe)
1145{
1146 struct smsdvb_client_t *client =
1147 container_of(fe, struct smsdvb_client_t, frontend);
1148
Michael Krufky3746b612009-07-12 23:30:14 -03001149 sms_board_power(client->coredev, 1);
1150
Uri Shkolnik793786d2009-05-12 12:28:46 -03001151 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001152 return 0;
1153}
1154
1155static int smsdvb_sleep(struct dvb_frontend *fe)
1156{
1157 struct smsdvb_client_t *client =
1158 container_of(fe, struct smsdvb_client_t, frontend);
1159
Michael Krufky3746b612009-07-12 23:30:14 -03001160 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
1161 sms_board_power(client->coredev, 0);
1162
Uri Shkolnik793786d2009-05-12 12:28:46 -03001163 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001164
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001165 return 0;
1166}
1167
1168static void smsdvb_release(struct dvb_frontend *fe)
1169{
Michael Krufkyfa830e82008-06-15 15:52:43 -03001170 /* do nothing */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001171}
1172
1173static struct dvb_frontend_ops smsdvb_fe_ops = {
1174 .info = {
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001175 .name = "Siano Mobile Digital MDTV Receiver",
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001176 .frequency_min = 44250000,
1177 .frequency_max = 867250000,
1178 .frequency_stepsize = 250000,
1179 .caps = FE_CAN_INVERSION_AUTO |
Michael Krufky82237412008-06-15 15:14:13 -03001180 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1181 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1182 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
1183 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
1184 FE_CAN_GUARD_INTERVAL_AUTO |
1185 FE_CAN_RECOVER |
1186 FE_CAN_HIERARCHY_AUTO,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001187 },
1188
1189 .release = smsdvb_release,
1190
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001191 .set_frontend = smsdvb_set_frontend,
1192 .get_frontend = smsdvb_get_frontend,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001193 .get_tune_settings = smsdvb_get_tune_settings,
1194
1195 .read_status = smsdvb_read_status,
1196 .read_ber = smsdvb_read_ber,
1197 .read_signal_strength = smsdvb_read_signal_strength,
1198 .read_snr = smsdvb_read_snr,
Michael Krufky851a9092008-11-22 14:56:37 -03001199 .read_ucblocks = smsdvb_read_ucblocks,
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001200
1201 .init = smsdvb_init,
1202 .sleep = smsdvb_sleep,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001203};
1204
Michael Krufky0c071f32008-06-21 02:44:02 -03001205static int smsdvb_hotplug(struct smscore_device_t *coredev,
1206 struct device *device, int arrival)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001207{
Michael Krufky18245e12008-06-15 17:52:24 -03001208 struct smsclient_params_t params;
1209 struct smsdvb_client_t *client;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001210 int rc;
1211
Michael Krufkyfa830e82008-06-15 15:52:43 -03001212 /* device removal handled by onremove callback */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001213 if (!arrival)
1214 return 0;
Michael Krufky18245e12008-06-15 17:52:24 -03001215 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
Michael Krufky82237412008-06-15 15:14:13 -03001216 if (!client) {
Michael Krufkyeb250942008-06-19 22:07:23 -03001217 sms_err("kmalloc() failed");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001218 return -ENOMEM;
1219 }
1220
Michael Krufkyfa830e82008-06-15 15:52:43 -03001221 /* register dvb adapter */
Michael Krufky1c11d542008-06-18 22:09:55 -03001222 rc = dvb_register_adapter(&client->adapter,
1223 sms_get_board(
1224 smscore_get_board_id(coredev))->name,
Michael Krufky82237412008-06-15 15:14:13 -03001225 THIS_MODULE, device, adapter_nr);
1226 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001227 sms_err("dvb_register_adapter() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001228 goto adapter_error;
1229 }
1230
Michael Krufkyfa830e82008-06-15 15:52:43 -03001231 /* init dvb demux */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001232 client->demux.dmx.capabilities = DMX_TS_FILTERING;
Michael Krufkyfa830e82008-06-15 15:52:43 -03001233 client->demux.filternum = 32; /* todo: nova ??? */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001234 client->demux.feednum = 32;
1235 client->demux.start_feed = smsdvb_start_feed;
1236 client->demux.stop_feed = smsdvb_stop_feed;
1237
1238 rc = dvb_dmx_init(&client->demux);
Michael Krufky82237412008-06-15 15:14:13 -03001239 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001240 sms_err("dvb_dmx_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001241 goto dvbdmx_error;
1242 }
1243
Michael Krufkyfa830e82008-06-15 15:52:43 -03001244 /* init dmxdev */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001245 client->dmxdev.filternum = 32;
1246 client->dmxdev.demux = &client->demux.dmx;
1247 client->dmxdev.capabilities = 0;
1248
1249 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
Michael Krufky82237412008-06-15 15:14:13 -03001250 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001251 sms_err("dvb_dmxdev_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001252 goto dmxdev_error;
1253 }
1254
Michael Krufkyfa830e82008-06-15 15:52:43 -03001255 /* init and register frontend */
Michael Krufky82237412008-06-15 15:14:13 -03001256 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
1257 sizeof(struct dvb_frontend_ops));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001258
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001259 switch (smscore_get_device_mode(coredev)) {
1260 case DEVICE_MODE_DVBT:
1261 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -03001262 client->frontend.ops.delsys[0] = SYS_DVBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001263 break;
1264 case DEVICE_MODE_ISDBT:
1265 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -03001266 client->frontend.ops.delsys[0] = SYS_ISDBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001267 break;
1268 }
1269
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001270 rc = dvb_register_frontend(&client->adapter, &client->frontend);
Michael Krufky82237412008-06-15 15:14:13 -03001271 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001272 sms_err("frontend registration failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001273 goto frontend_error;
1274 }
1275
Michael Krufkyf17407a2008-06-14 00:43:26 -03001276 params.initial_id = 1;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001277 params.data_type = MSG_SMS_DVBT_BDA_DATA;
1278 params.onresponse_handler = smsdvb_onresponse;
1279 params.onremove_handler = smsdvb_onremove;
1280 params.context = client;
1281
1282 rc = smscore_register_client(coredev, &params, &client->smsclient);
Michael Krufky82237412008-06-15 15:14:13 -03001283 if (rc < 0) {
Michael Krufkyeb250942008-06-19 22:07:23 -03001284 sms_err("smscore_register_client() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001285 goto client_error;
1286 }
1287
1288 client->coredev = coredev;
1289
1290 init_completion(&client->tune_done);
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -03001291 init_completion(&client->stats_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001292
1293 kmutex_lock(&g_smsdvb_clientslock);
1294
1295 list_add(&client->entry, &g_smsdvb_clients);
1296
1297 kmutex_unlock(&g_smsdvb_clientslock);
1298
Uri Shkolnik793786d2009-05-12 12:28:46 -03001299 client->event_fe_state = -1;
1300 client->event_unc_state = -1;
1301 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001302
Uri Shkolnik793786d2009-05-12 12:28:46 -03001303 sms_info("success");
Michael Krufky250fa672008-11-16 22:45:42 -03001304 sms_board_setup(coredev);
1305
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001306 return 0;
1307
1308client_error:
1309 dvb_unregister_frontend(&client->frontend);
1310
1311frontend_error:
1312 dvb_dmxdev_release(&client->dmxdev);
1313
1314dmxdev_error:
1315 dvb_dmx_release(&client->demux);
1316
1317dvbdmx_error:
1318 dvb_unregister_adapter(&client->adapter);
1319
1320adapter_error:
1321 kfree(client);
1322 return rc;
1323}
1324
Márton Németh2184dda2009-12-11 20:05:10 -03001325static int __init smsdvb_module_init(void)
Steven Totheae55662008-05-22 18:04:36 -03001326{
1327 int rc;
1328
1329 INIT_LIST_HEAD(&g_smsdvb_clients);
1330 kmutex_init(&g_smsdvb_clientslock);
1331
1332 rc = smscore_register_hotplug(smsdvb_hotplug);
1333
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001334 sms_debug("");
Steven Totheae55662008-05-22 18:04:36 -03001335
1336 return rc;
1337}
1338
Márton Németh2184dda2009-12-11 20:05:10 -03001339static void __exit smsdvb_module_exit(void)
Steven Totheae55662008-05-22 18:04:36 -03001340{
1341 smscore_unregister_hotplug(smsdvb_hotplug);
1342
1343 kmutex_lock(&g_smsdvb_clientslock);
1344
1345 while (!list_empty(&g_smsdvb_clients))
Michael Krufky82237412008-06-15 15:14:13 -03001346 smsdvb_unregister_client(
Michael Krufky18245e12008-06-15 17:52:24 -03001347 (struct smsdvb_client_t *) g_smsdvb_clients.next);
Steven Totheae55662008-05-22 18:04:36 -03001348
1349 kmutex_unlock(&g_smsdvb_clientslock);
Steven Totheae55662008-05-22 18:04:36 -03001350}
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001351
1352module_init(smsdvb_module_init);
1353module_exit(smsdvb_module_exit);
1354
1355MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
Uri Shkolnik843d0602009-05-12 13:13:13 -03001356MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001357MODULE_LICENSE("GPL");