blob: c53cb4e8d0c66195ffbefafb1c3e95d4a4aa98a5 [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
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -030034#include "smsdvb.h"
35
Michael Krufky9c59f9682008-05-19 18:57:12 -030036DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
37
Adrian Bunkc5e0bd12008-07-21 23:17:36 -030038static struct list_head g_smsdvb_clients;
39static struct mutex g_smsdvb_clientslock;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030040
Michael Krufky0d02efe2009-02-27 02:42:16 -030041static int sms_dbg;
42module_param_named(debug, sms_dbg, int, 0644);
43MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
44
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -030045
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -030046u32 sms_to_guard_interval_table[] = {
47 [0] = GUARD_INTERVAL_1_32,
48 [1] = GUARD_INTERVAL_1_16,
49 [2] = GUARD_INTERVAL_1_8,
50 [3] = GUARD_INTERVAL_1_4,
51};
52
53u32 sms_to_code_rate_table[] = {
54 [0] = FEC_1_2,
55 [1] = FEC_2_3,
56 [2] = FEC_3_4,
57 [3] = FEC_5_6,
58 [4] = FEC_7_8,
59};
60
61
62u32 sms_to_hierarchy_table[] = {
63 [0] = HIERARCHY_NONE,
64 [1] = HIERARCHY_1,
65 [2] = HIERARCHY_2,
66 [3] = HIERARCHY_4,
67};
68
69u32 sms_to_modulation_table[] = {
70 [0] = QPSK,
71 [1] = QAM_16,
72 [2] = QAM_64,
73 [3] = DQPSK,
74};
75
Mauro Carvalho Chehabff702eb2013-03-09 15:54:46 -030076
Uri Shkolnik793786d2009-05-12 12:28:46 -030077/* Events that may come from DVB v3 adapter */
78static void sms_board_dvb3_event(struct smsdvb_client_t *client,
79 enum SMS_DVB3_EVENTS event) {
Uri Shkolnik4db989f2009-05-19 12:28:02 -030080
81 struct smscore_device_t *coredev = client->coredev;
82 switch (event) {
83 case DVB3_EVENT_INIT:
84 sms_debug("DVB3_EVENT_INIT");
85 sms_board_event(coredev, BOARD_EVENT_BIND);
86 break;
87 case DVB3_EVENT_SLEEP:
88 sms_debug("DVB3_EVENT_SLEEP");
89 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
90 break;
91 case DVB3_EVENT_HOTPLUG:
92 sms_debug("DVB3_EVENT_HOTPLUG");
93 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
94 break;
95 case DVB3_EVENT_FE_LOCK:
96 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
97 client->event_fe_state = DVB3_EVENT_FE_LOCK;
98 sms_debug("DVB3_EVENT_FE_LOCK");
99 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
100 }
101 break;
102 case DVB3_EVENT_FE_UNLOCK:
103 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
104 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
105 sms_debug("DVB3_EVENT_FE_UNLOCK");
106 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
107 }
108 break;
109 case DVB3_EVENT_UNC_OK:
110 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
111 client->event_unc_state = DVB3_EVENT_UNC_OK;
112 sms_debug("DVB3_EVENT_UNC_OK");
113 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
114 }
115 break;
116 case DVB3_EVENT_UNC_ERR:
117 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
118 client->event_unc_state = DVB3_EVENT_UNC_ERR;
119 sms_debug("DVB3_EVENT_UNC_ERR");
120 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
121 }
122 break;
123
124 default:
125 sms_err("Unknown dvb3 api event");
126 break;
127 }
Uri Shkolnik793786d2009-05-12 12:28:46 -0300128}
129
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300130static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300131{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300132 struct smsdvb_client_t *client =
133 container_of(fe, struct smsdvb_client_t, frontend);
134 struct smscore_device_t *coredev = client->coredev;
135 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
136 int i, n_layers;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300137
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300138 switch (smscore_get_device_mode(coredev)) {
139 case DEVICE_MODE_ISDBT:
140 case DEVICE_MODE_ISDBT_BDA:
141 n_layers = 4;
142 default:
143 n_layers = 1;
144 }
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300145
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300146 /* Global stats */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300147 c->strength.len = 1;
148 c->cnr.len = 1;
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300149 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
150 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300151
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300152 /* Per-layer stats */
153 c->post_bit_error.len = n_layers;
154 c->post_bit_count.len = n_layers;
155 c->block_error.len = n_layers;
156 c->block_count.len = n_layers;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300157
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300158 /*
159 * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically
160 * changed when the stats become available.
161 */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300162 for (i = 0; i < n_layers; i++) {
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300163 c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
164 c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
165 c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
166 c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300167 }
168}
169
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300170static inline int sms_to_mode(u32 mode)
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300171{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300172 switch (mode) {
173 case 2:
174 return TRANSMISSION_MODE_2K;
175 case 4:
176 return TRANSMISSION_MODE_4K;
177 case 8:
178 return TRANSMISSION_MODE_8K;
179 }
180 return TRANSMISSION_MODE_AUTO;
181}
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300182
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300183static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)
184{
185 if (is_demod_locked)
186 return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
187 FE_HAS_SYNC | FE_HAS_LOCK;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300188
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300189 if (is_rf_locked)
190 return FE_HAS_SIGNAL | FE_HAS_CARRIER;
191
192 return 0;
193}
194
Mauro Carvalho Chehab5c3b8742013-03-10 19:21:13 -0300195static inline u32 sms_to_bw(u32 value)
196{
197 return value * 1000000;
198}
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300199
200#define convert_from_table(value, table, defval) ({ \
201 u32 __ret; \
202 if (value < ARRAY_SIZE(table)) \
203 __ret = table[value]; \
204 else \
205 __ret = defval; \
206 __ret; \
207})
208
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300209#define sms_to_guard_interval(value) \
210 convert_from_table(value, sms_to_guard_interval_table, \
211 GUARD_INTERVAL_AUTO);
212
213#define sms_to_code_rate(value) \
214 convert_from_table(value, sms_to_code_rate_table, \
215 FEC_NONE);
216
217#define sms_to_hierarchy(value) \
218 convert_from_table(value, sms_to_hierarchy_table, \
219 FEC_NONE);
220
221#define sms_to_modulation(value) \
222 convert_from_table(value, sms_to_modulation_table, \
223 FEC_NONE);
224
225static void smsdvb_update_tx_params(struct smsdvb_client_t *client,
226 struct TRANSMISSION_STATISTICS_S *p)
227{
228 struct dvb_frontend *fe = &client->frontend;
229 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
230
231 c->frequency = p->Frequency;
232 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
233 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
234 c->transmission_mode = sms_to_mode(p->TransmissionMode);
235 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
236 c->code_rate_HP = sms_to_code_rate(p->CodeRate);
237 c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
238 c->hierarchy = sms_to_hierarchy(p->Hierarchy);
239 c->modulation = sms_to_modulation(p->Constellation);
240}
241
242static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
243 struct RECEPTION_STATISTICS_PER_SLICES_S *p)
244{
245 struct dvb_frontend *fe = &client->frontend;
246 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
247
248 client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
249 c->modulation = sms_to_modulation(p->constellation);
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300250
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300251 /* Signal Strength, in DBm */
252 c->strength.stat[0].uvalue = p->inBandPower * 1000;
253
254 /* Carrier to Noise ratio, in DB */
255 c->cnr.stat[0].svalue = p->snr * 1000;
256
257 /* PER/BER requires demod lock */
258 if (!p->IsDemodLocked)
259 return;
260
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300261 /* TS PER */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300262 client->last_per = c->block_error.stat[0].uvalue;
263 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
264 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
265 c->block_error.stat[0].uvalue += p->etsPackets;
266 c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets;
267
268 /* BER */
269 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
270 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
271 c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
272 c->post_bit_count.stat[0].uvalue += p->BERBitCount;
273
274 /* Legacy PER/BER */
275 client->legacy_per = (p->etsPackets * 65535) /
276 (p->tsPackets + p->etsPackets);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300277}
278
279static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
280 struct SMSHOSTLIB_STATISTICS_ST *p)
281{
282 struct dvb_frontend *fe = &client->frontend;
283 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
284
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300285 if (client->prt_dvb_stats)
286 client->prt_dvb_stats(client->debug_data, p);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300287
288 client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
289
290 /* Update DVB modulation parameters */
291 c->frequency = p->Frequency;
292 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
293 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
294 c->transmission_mode = sms_to_mode(p->TransmissionMode);
295 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
296 c->code_rate_HP = sms_to_code_rate(p->CodeRate);
297 c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
298 c->hierarchy = sms_to_hierarchy(p->Hierarchy);
299 c->modulation = sms_to_modulation(p->Constellation);
300
301 /* update reception data */
302 c->lna = p->IsExternalLNAOn ? 1 : 0;
303
304 /* Carrier to Noise ratio, in DB */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300305 c->cnr.stat[0].svalue = p->SNR * 1000;
306
307 /* Signal Strength, in DBm */
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300308 c->strength.stat[0].uvalue = p->InBandPwr * 1000;
309
310 /* PER/BER requires demod lock */
311 if (!p->IsDemodLocked)
312 return;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300313
314 /* TS PER */
315 client->last_per = c->block_error.stat[0].uvalue;
316 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
317 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
318 c->block_error.stat[0].uvalue += p->ErrorTSPackets;
319 c->block_count.stat[0].uvalue += p->TotalTSPackets;
320
321 /* BER */
322 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
323 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
324 c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
325 c->post_bit_count.stat[0].uvalue += p->BERBitCount;
326
327 /* Legacy PER/BER */
328 client->legacy_ber = p->BER;
329};
330
331static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
332 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
333{
334 struct dvb_frontend *fe = &client->frontend;
335 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
336 struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
337 int i, n_layers;
338
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300339 if (client->prt_isdb_stats)
340 client->prt_isdb_stats(client->debug_data, p);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300341
Mauro Carvalho Chehab773adad2013-03-16 21:05:30 -0300342 client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
343
344 /*
345 * Firmware 2.1 seems to report only lock status and
346 * Signal strength. The signal strength indicator is at the
347 * wrong field.
348 */
349 if (p->StatisticsType == 0) {
350 c->strength.stat[0].uvalue = ((s32)p->TransmissionMode) * 1000;
351 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
352 return;
353 }
354
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300355 /* Update ISDB-T transmission parameters */
356 c->frequency = p->Frequency;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300357 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
358 c->transmission_mode = sms_to_mode(p->TransmissionMode);
359 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
360 c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
361 n_layers = p->NumOfLayers;
362 if (n_layers < 1)
363 n_layers = 1;
364 if (n_layers > 3)
365 n_layers = 3;
366 c->isdbt_layer_enabled = 0;
367
368 /* update reception data */
369 c->lna = p->IsExternalLNAOn ? 1 : 0;
370
371 /* Carrier to Noise ratio, in DB */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300372 c->cnr.stat[0].svalue = p->SNR * 1000;
373
374 /* Signal Strength, in DBm */
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300375 c->strength.stat[0].uvalue = p->InBandPwr * 1000;
376
377 /* PER/BER and per-layer stats require demod lock */
378 if (!p->IsDemodLocked)
379 return;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300380
381 client->last_per = c->block_error.stat[0].uvalue;
382
383 /* Clears global counters, as the code below will sum it again */
384 c->block_error.stat[0].uvalue = 0;
385 c->block_count.stat[0].uvalue = 0;
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300386 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
387 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300388 c->post_bit_error.stat[0].uvalue = 0;
389 c->post_bit_count.stat[0].uvalue = 0;
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300390 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
391 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300392
393 for (i = 0; i < n_layers; i++) {
394 lr = &p->LayerInfo[i];
395
396 /* Update per-layer transmission parameters */
397 if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
398 c->isdbt_layer_enabled |= 1 << i;
399 c->layer[i].segment_count = lr->NumberOfSegments;
400 } else {
401 continue;
402 }
403 c->layer[i].modulation = sms_to_modulation(lr->Constellation);
404
405 /* TS PER */
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300406 c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
407 c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
408 c->block_error.stat[i + 1].uvalue += lr->ErrorTSPackets;
409 c->block_count.stat[i + 1].uvalue += lr->TotalTSPackets;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300410
411 /* Update global PER counter */
412 c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
413 c->block_count.stat[0].uvalue += lr->TotalTSPackets;
414
415 /* BER */
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300416 c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
417 c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
418 c->post_bit_error.stat[i + 1].uvalue += lr->BERErrorCount;
419 c->post_bit_count.stat[i + 1].uvalue += lr->BERBitCount;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300420
421 /* Update global BER counter */
422 c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
423 c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
424 }
425}
426
427static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
428 struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
429{
430 struct dvb_frontend *fe = &client->frontend;
431 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
432 struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
433 int i, n_layers;
434
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300435 if (client->prt_isdb_stats_ex)
436 client->prt_isdb_stats_ex(client->debug_data, p);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300437
438 /* Update ISDB-T transmission parameters */
439 c->frequency = p->Frequency;
440 client->fe_status = sms_to_status(p->IsDemodLocked, 0);
441 c->bandwidth_hz = sms_to_bw(p->Bandwidth);
442 c->transmission_mode = sms_to_mode(p->TransmissionMode);
443 c->guard_interval = sms_to_guard_interval(p->GuardInterval);
444 c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
445 n_layers = p->NumOfLayers;
446 if (n_layers < 1)
447 n_layers = 1;
448 if (n_layers > 3)
449 n_layers = 3;
450 c->isdbt_layer_enabled = 0;
451
452 /* update reception data */
453 c->lna = p->IsExternalLNAOn ? 1 : 0;
454
455 /* Carrier to Noise ratio, in DB */
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300456 c->cnr.stat[0].svalue = p->SNR * 1000;
457
458 /* Signal Strength, in DBm */
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300459 c->strength.stat[0].uvalue = p->InBandPwr * 1000;
460
461 /* PER/BER and per-layer stats require demod lock */
462 if (!p->IsDemodLocked)
463 return;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300464
465 client->last_per = c->block_error.stat[0].uvalue;
466
467 /* Clears global counters, as the code below will sum it again */
468 c->block_error.stat[0].uvalue = 0;
469 c->block_count.stat[0].uvalue = 0;
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300470 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
471 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300472 c->post_bit_error.stat[0].uvalue = 0;
473 c->post_bit_count.stat[0].uvalue = 0;
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300474 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
475 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300476
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300477 c->post_bit_error.len = n_layers + 1;
478 c->post_bit_count.len = n_layers + 1;
479 c->block_error.len = n_layers + 1;
480 c->block_count.len = n_layers + 1;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300481 for (i = 0; i < n_layers; i++) {
482 lr = &p->LayerInfo[i];
483
484 /* Update per-layer transmission parameters */
485 if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
486 c->isdbt_layer_enabled |= 1 << i;
487 c->layer[i].segment_count = lr->NumberOfSegments;
488 } else {
489 continue;
490 }
491 c->layer[i].modulation = sms_to_modulation(lr->Constellation);
492
493 /* TS PER */
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300494 c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
495 c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
496 c->block_error.stat[i + 1].uvalue += lr->ErrorTSPackets;
497 c->block_count.stat[i + 1].uvalue += lr->TotalTSPackets;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300498
499 /* Update global PER counter */
500 c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
501 c->block_count.stat[0].uvalue += lr->TotalTSPackets;
502
503 /* BER */
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300504 c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
505 c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
506 c->post_bit_error.stat[i + 1].uvalue += lr->BERErrorCount;
507 c->post_bit_count.stat[i + 1].uvalue += lr->BERBitCount;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300508
509 /* Update global BER counter */
510 c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
511 c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300512 }
513}
514
Michael Krufky0c071f32008-06-21 02:44:02 -0300515static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300516{
Michael Krufky18245e12008-06-15 17:52:24 -0300517 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300518 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
519 + cb->offset);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300520 void *p = phdr + 1;
521 struct dvb_frontend *fe = &client->frontend;
522 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300523 bool is_status_update = false;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300524
Michael Krufkyfa830e82008-06-15 15:52:43 -0300525 switch (phdr->msgType) {
Michael Krufky82237412008-06-15 15:14:13 -0300526 case MSG_SMS_DVBT_BDA_DATA:
Mauro Carvalho Chehabe1b2ac42013-03-15 07:22:08 -0300527 /*
528 * Only feed data to dvb demux if are there any feed listening
529 * to it and if the device has tuned
530 */
531 if (client->feed_users && client->has_tuned)
532 dvb_dmx_swfilter(&client->demux, p,
533 cb->size - sizeof(struct SmsMsgHdr_ST));
Michael Krufky82237412008-06-15 15:14:13 -0300534 break;
535
536 case MSG_SMS_RF_TUNE_RES:
Michael Krufky6b26fce2009-12-22 21:08:49 -0300537 case MSG_SMS_ISDBT_TUNE_RES:
Michael Krufky82237412008-06-15 15:14:13 -0300538 complete(&client->tune_done);
539 break;
540
Uri Shkolnik793786d2009-05-12 12:28:46 -0300541 case MSG_SMS_SIGNAL_DETECTED_IND:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300542 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
543 FE_HAS_VITERBI | FE_HAS_SYNC |
544 FE_HAS_LOCK;
545
Uri Shkolnik793786d2009-05-12 12:28:46 -0300546 is_status_update = true;
547 break;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300548
Uri Shkolnik793786d2009-05-12 12:28:46 -0300549 case MSG_SMS_NO_SIGNAL_IND:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300550 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300551
552 is_status_update = true;
553 break;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300554
555 case MSG_SMS_TRANSMISSION_IND:
556 smsdvb_update_tx_params(client, p);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300557
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300558 is_status_update = true;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300559 break;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300560
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300561 case MSG_SMS_HO_PER_SLICES_IND:
562 smsdvb_update_per_slices(client, p);
563
564 is_status_update = true;
565 break;
566
567 case MSG_SMS_GET_STATISTICS_RES:
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300568 switch (smscore_get_device_mode(client->coredev)) {
569 case DEVICE_MODE_ISDBT:
570 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300571 smsdvb_update_isdbt_stats(client, p);
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300572 break;
573 default:
Mauro Carvalho Chehabc02272f2013-03-09 23:01:48 -0300574 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */
575 smsdvb_update_dvb_stats(client, p + sizeof(u32));
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300576 }
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300577
578 is_status_update = true;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300579 break;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300580
581 /* Only for ISDB-T */
582 case MSG_SMS_GET_STATISTICS_EX_RES:
Mauro Carvalho Chehabc02272f2013-03-09 23:01:48 -0300583 /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */
584 smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300585 is_status_update = true;
586 break;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300587 default:
Mauro Carvalho Chehab4c3bdb52013-03-09 09:27:39 -0300588 sms_info("message not handled");
Uri Shkolnik793786d2009-05-12 12:28:46 -0300589 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300590 smscore_putbuffer(client->coredev, cb);
591
Uri Shkolnik793786d2009-05-12 12:28:46 -0300592 if (is_status_update) {
Mauro Carvalho Chehab96710452013-03-10 13:38:41 -0300593 if (client->fe_status & FE_HAS_LOCK) {
Uri Shkolnik793786d2009-05-12 12:28:46 -0300594 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300595 if (client->last_per == c->block_error.stat[0].uvalue)
Uri Shkolnik793786d2009-05-12 12:28:46 -0300596 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
597 else
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300598 sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
Mauro Carvalho Chehabe1b2ac42013-03-15 07:22:08 -0300599 client->has_tuned = true;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300600 } else {
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300601 smsdvb_stats_not_ready(fe);
Mauro Carvalho Chehabe1b2ac42013-03-15 07:22:08 -0300602 client->has_tuned = false;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300603 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
604 }
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300605 complete(&client->stats_done);
Uri Shkolnik793786d2009-05-12 12:28:46 -0300606 }
607
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300608 return 0;
609}
610
Michael Krufky0c071f32008-06-21 02:44:02 -0300611static void smsdvb_unregister_client(struct smsdvb_client_t *client)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300612{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300613 /* must be called under clientslock */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300614
615 list_del(&client->entry);
616
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300617 smsdvb_debugfs_release(client);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300618 smscore_unregister_client(client->smsclient);
619 dvb_unregister_frontend(&client->frontend);
620 dvb_dmxdev_release(&client->dmxdev);
621 dvb_dmx_release(&client->demux);
622 dvb_unregister_adapter(&client->adapter);
623 kfree(client);
624}
625
Michael Krufky0c071f32008-06-21 02:44:02 -0300626static void smsdvb_onremove(void *context)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300627{
628 kmutex_lock(&g_smsdvb_clientslock);
629
Michael Krufky18245e12008-06-15 17:52:24 -0300630 smsdvb_unregister_client((struct smsdvb_client_t *) context);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300631
632 kmutex_unlock(&g_smsdvb_clientslock);
633}
634
635static int smsdvb_start_feed(struct dvb_demux_feed *feed)
636{
Michael Krufky18245e12008-06-15 17:52:24 -0300637 struct smsdvb_client_t *client =
638 container_of(feed->demux, struct smsdvb_client_t, demux);
639 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300640
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300641 sms_debug("add pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300642 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300643
Mauro Carvalho Chehabe1b2ac42013-03-15 07:22:08 -0300644 client->feed_users++;
645
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300646 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
647 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
648 PidMsg.xMsgHeader.msgFlags = 0;
649 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
650 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
651 PidMsg.msgData[0] = feed->pid;
652
Michael Krufky82237412008-06-15 15:14:13 -0300653 return smsclient_sendrequest(client->smsclient,
654 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300655}
656
657static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
658{
Michael Krufky18245e12008-06-15 17:52:24 -0300659 struct smsdvb_client_t *client =
660 container_of(feed->demux, struct smsdvb_client_t, demux);
661 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300662
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300663 sms_debug("remove pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300664 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300665
Mauro Carvalho Chehabe1b2ac42013-03-15 07:22:08 -0300666 client->feed_users--;
667
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300668 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
669 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
670 PidMsg.xMsgHeader.msgFlags = 0;
671 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
672 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
673 PidMsg.msgData[0] = feed->pid;
674
Michael Krufky82237412008-06-15 15:14:13 -0300675 return smsclient_sendrequest(client->smsclient,
676 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300677}
678
Michael Krufky18245e12008-06-15 17:52:24 -0300679static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
Michael Krufkya83ccdd2008-05-06 03:11:51 -0300680 void *buffer, size_t size,
681 struct completion *completion)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300682{
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300683 int rc;
684
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300685 rc = smsclient_sendrequest(client->smsclient, buffer, size);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300686 if (rc < 0)
687 return rc;
688
Michael Krufky82237412008-06-15 15:14:13 -0300689 return wait_for_completion_timeout(completion,
690 msecs_to_jiffies(2000)) ?
691 0 : -ETIME;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300692}
693
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300694static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
695{
696 int rc;
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300697 struct SmsMsgHdr_ST Msg;
698
Mauro Carvalho Chehaba9b9fbd2013-03-10 10:51:25 -0300699 /* Don't request stats too fast */
700 if (client->get_stats_jiffies &&
701 (!time_after(jiffies, client->get_stats_jiffies)))
702 return 0;
703 client->get_stats_jiffies = jiffies + msecs_to_jiffies(100);
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300704
705 Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
706 Msg.msgDstId = HIF_TASK;
707 Msg.msgFlags = 0;
708 Msg.msgLength = sizeof(Msg);
709
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300710 switch (smscore_get_device_mode(client->coredev)) {
711 case DEVICE_MODE_ISDBT:
712 case DEVICE_MODE_ISDBT_BDA:
713 /*
714 * Check for firmware version, to avoid breaking for old cards
715 */
716 if (client->coredev->fw_version >= 0x800)
717 Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ;
718 else
719 Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
720 break;
721 default:
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300722 Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300723 }
Mauro Carvalho Chehabb4059092013-03-07 21:58:47 -0300724
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300725 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -0300726 &client->stats_done);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300727
728 return rc;
729}
730
Michael Krufky3746b612009-07-12 23:30:14 -0300731static inline int led_feedback(struct smsdvb_client_t *client)
732{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300733 if (!(client->fe_status & FE_HAS_LOCK))
Michael Krufky3746b612009-07-12 23:30:14 -0300734 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300735
736 return sms_board_led_feedback(client->coredev,
737 (client->legacy_ber == 0) ?
738 SMS_LED_HI : SMS_LED_LO);
Michael Krufky3746b612009-07-12 23:30:14 -0300739}
740
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300741static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
742{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300743 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300744 struct smsdvb_client_t *client;
745 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300746
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300747 rc = smsdvb_send_statistics_request(client);
748
Uri Shkolnik793786d2009-05-12 12:28:46 -0300749 *stat = client->fe_status;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300750
Michael Krufky3746b612009-07-12 23:30:14 -0300751 led_feedback(client);
752
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300753 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300754}
755
756static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
757{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300758 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300759 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300760
Uri Shkolnik793786d2009-05-12 12:28:46 -0300761 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300762
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300763 rc = smsdvb_send_statistics_request(client);
764
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300765 *ber = client->legacy_ber;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300766
Michael Krufky3746b612009-07-12 23:30:14 -0300767 led_feedback(client);
768
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300769 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300770}
771
772static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
773{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300774 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300775 int rc;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300776 s32 power = (s32) c->strength.stat[0].uvalue;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300777 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300778
Uri Shkolnik793786d2009-05-12 12:28:46 -0300779 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300780
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300781 rc = smsdvb_send_statistics_request(client);
782
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300783 if (power < -95)
Uri Shkolnik793786d2009-05-12 12:28:46 -0300784 *strength = 0;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300785 else if (power > -29)
786 *strength = 65535;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300787 else
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300788 *strength = (power + 95) * 65535 / 66;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300789
Michael Krufky3746b612009-07-12 23:30:14 -0300790 led_feedback(client);
791
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300792 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300793}
794
795static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
796{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300797 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300798 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300799 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300800
Uri Shkolnik793786d2009-05-12 12:28:46 -0300801 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300802
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300803 rc = smsdvb_send_statistics_request(client);
804
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300805 /* Preferred scale for SNR with legacy API: 0.1 dB */
806 *snr = c->cnr.stat[0].svalue / 100;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300807
Michael Krufky3746b612009-07-12 23:30:14 -0300808 led_feedback(client);
809
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300810 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300811}
812
Michael Krufky851a9092008-11-22 14:56:37 -0300813static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
814{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300815 int rc;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300816 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300817 struct smsdvb_client_t *client;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300818
Uri Shkolnik793786d2009-05-12 12:28:46 -0300819 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky851a9092008-11-22 14:56:37 -0300820
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300821 rc = smsdvb_send_statistics_request(client);
822
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300823 *ucblocks = c->block_error.stat[0].uvalue;
Michael Krufky851a9092008-11-22 14:56:37 -0300824
Michael Krufky3746b612009-07-12 23:30:14 -0300825 led_feedback(client);
826
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300827 return rc;
Michael Krufky851a9092008-11-22 14:56:37 -0300828}
829
Michael Krufky82237412008-06-15 15:14:13 -0300830static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
831 struct dvb_frontend_tune_settings *tune)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300832{
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300833 sms_debug("");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300834
835 tune->min_delay_ms = 400;
836 tune->step_size = 250000;
837 tune->max_drift = 0;
838 return 0;
839}
840
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300841static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300842{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300843 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky18245e12008-06-15 17:52:24 -0300844 struct smsdvb_client_t *client =
845 container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300846
Michael Krufky18245e12008-06-15 17:52:24 -0300847 struct {
848 struct SmsMsgHdr_ST Msg;
Michael Krufky82237412008-06-15 15:14:13 -0300849 u32 Data[3];
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300850 } Msg;
851
Michael Krufky3746b612009-07-12 23:30:14 -0300852 int ret;
853
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300854 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300855 client->event_fe_state = -1;
856 client->event_unc_state = -1;
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300857 fe->dtv_property_cache.delivery_system = SYS_DVBT;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300858
859 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
860 Msg.Msg.msgDstId = HIF_TASK;
861 Msg.Msg.msgFlags = 0;
862 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300863 Msg.Msg.msgLength = sizeof(Msg);
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300864 Msg.Data[0] = c->frequency;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300865 Msg.Data[2] = 12000000;
866
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300867 sms_info("%s: freq %d band %d", __func__, c->frequency,
868 c->bandwidth_hz);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300869
Mauro Carvalho Chehab643e15a2009-12-25 07:29:06 -0300870 switch (c->bandwidth_hz / 1000000) {
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300871 case 8:
872 Msg.Data[1] = BW_8_MHZ;
873 break;
874 case 7:
875 Msg.Data[1] = BW_7_MHZ;
876 break;
877 case 6:
878 Msg.Data[1] = BW_6_MHZ;
879 break;
880 case 0:
881 return -EOPNOTSUPP;
882 default:
883 return -EINVAL;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300884 }
Michael Krufky3746b612009-07-12 23:30:14 -0300885 /* Disable LNA, if any. An error is returned if no LNA is present */
886 ret = sms_board_lna_control(client->coredev, 0);
887 if (ret == 0) {
888 fe_status_t status;
889
890 /* tune with LNA off at first */
891 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
892 &client->tune_done);
893
894 smsdvb_read_status(fe, &status);
895
896 if (status & FE_HAS_LOCK)
897 return ret;
898
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300899 /* previous tune didn't lock - enable LNA and tune again */
Michael Krufky3746b612009-07-12 23:30:14 -0300900 sms_board_lna_control(client->coredev, 1);
901 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300902
Michael Krufky82237412008-06-15 15:14:13 -0300903 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
904 &client->tune_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300905}
906
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300907static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300908{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300909 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300910 struct smsdvb_client_t *client =
911 container_of(fe, struct smsdvb_client_t, frontend);
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300912 int board_id = smscore_get_board_id(client->coredev);
913 struct sms_board *board = sms_get_board(board_id);
914 enum sms_device_type_st type = board->type;
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -0300915 int ret;
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -0300916
Michael Krufky6b26fce2009-12-22 21:08:49 -0300917 struct {
918 struct SmsMsgHdr_ST Msg;
919 u32 Data[4];
920 } Msg;
921
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300922 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
923
Michael Krufky6b26fce2009-12-22 21:08:49 -0300924 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
925 Msg.Msg.msgDstId = HIF_TASK;
926 Msg.Msg.msgFlags = 0;
927 Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
928 Msg.Msg.msgLength = sizeof(Msg);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300929
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300930 if (c->isdbt_sb_segment_idx == -1)
931 c->isdbt_sb_segment_idx = 0;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300932
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300933 if (!c->isdbt_layer_enabled)
934 c->isdbt_layer_enabled = 7;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300935
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300936 Msg.Data[0] = c->frequency;
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300937 Msg.Data[1] = BW_ISDBT_1SEG;
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300938 Msg.Data[2] = 12000000;
939 Msg.Data[3] = c->isdbt_sb_segment_idx;
940
Mauro Carvalho Chehaba51fea42013-03-07 16:34:06 -0300941 if (c->isdbt_partial_reception) {
942 if ((type == SMS_PELE || type == SMS_RIO) &&
943 c->isdbt_sb_segment_count > 3)
944 Msg.Data[1] = BW_ISDBT_13SEG;
945 else if (c->isdbt_sb_segment_count > 1)
946 Msg.Data[1] = BW_ISDBT_3SEG;
947 } else if (type == SMS_PELE || type == SMS_RIO)
948 Msg.Data[1] = BW_ISDBT_13SEG;
949
950 c->bandwidth_hz = 6000000;
951
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300952 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
953 c->frequency, c->isdbt_sb_segment_count,
954 c->isdbt_sb_segment_idx);
955
Mauro Carvalho Chehab0c189fa2013-03-07 16:34:53 -0300956 /* Disable LNA, if any. An error is returned if no LNA is present */
957 ret = sms_board_lna_control(client->coredev, 0);
958 if (ret == 0) {
959 fe_status_t status;
960
961 /* tune with LNA off at first */
962 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
963 &client->tune_done);
964
965 smsdvb_read_status(fe, &status);
966
967 if (status & FE_HAS_LOCK)
968 return ret;
969
970 /* previous tune didn't lock - enable LNA and tune again */
971 sms_board_lna_control(client->coredev, 1);
972 }
Michael Krufky6b26fce2009-12-22 21:08:49 -0300973 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
974 &client->tune_done);
975}
976
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300977static int smsdvb_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300978{
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300979 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300980 struct smsdvb_client_t *client =
981 container_of(fe, struct smsdvb_client_t, frontend);
982 struct smscore_device_t *coredev = client->coredev;
983
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300984 smsdvb_stats_not_ready(fe);
Mauro Carvalho Chehabf5de95e2013-03-10 12:06:30 -0300985 c->strength.stat[0].uvalue = 0;
986 c->cnr.stat[0].uvalue = 0;
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -0300987
Mauro Carvalho Chehabe1b2ac42013-03-15 07:22:08 -0300988 client->has_tuned = false;
989
Michael Krufky6b26fce2009-12-22 21:08:49 -0300990 switch (smscore_get_device_mode(coredev)) {
991 case DEVICE_MODE_DVBT:
992 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300993 return smsdvb_dvbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300994 case DEVICE_MODE_ISDBT:
995 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300996 return smsdvb_isdbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300997 default:
998 return -EINVAL;
999 }
1000}
1001
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -03001002/* Nothing to do here, as stats are automatically updated */
Mauro Carvalho Chehabeab0fa02013-03-09 12:05:58 -03001003static int smsdvb_get_frontend(struct dvb_frontend *fe)
1004{
Mauro Carvalho Chehabd42f1cb2013-03-09 19:26:28 -03001005 return 0;
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001006}
1007
1008static int smsdvb_init(struct dvb_frontend *fe)
1009{
1010 struct smsdvb_client_t *client =
1011 container_of(fe, struct smsdvb_client_t, frontend);
1012
Michael Krufky3746b612009-07-12 23:30:14 -03001013 sms_board_power(client->coredev, 1);
1014
Uri Shkolnik793786d2009-05-12 12:28:46 -03001015 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001016 return 0;
1017}
1018
1019static int smsdvb_sleep(struct dvb_frontend *fe)
1020{
1021 struct smsdvb_client_t *client =
1022 container_of(fe, struct smsdvb_client_t, frontend);
1023
Michael Krufky3746b612009-07-12 23:30:14 -03001024 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
1025 sms_board_power(client->coredev, 0);
1026
Uri Shkolnik793786d2009-05-12 12:28:46 -03001027 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001028
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001029 return 0;
1030}
1031
1032static void smsdvb_release(struct dvb_frontend *fe)
1033{
Michael Krufkyfa830e82008-06-15 15:52:43 -03001034 /* do nothing */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001035}
1036
1037static struct dvb_frontend_ops smsdvb_fe_ops = {
1038 .info = {
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001039 .name = "Siano Mobile Digital MDTV Receiver",
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001040 .frequency_min = 44250000,
1041 .frequency_max = 867250000,
1042 .frequency_stepsize = 250000,
1043 .caps = FE_CAN_INVERSION_AUTO |
Michael Krufky82237412008-06-15 15:14:13 -03001044 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1045 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1046 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
1047 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
1048 FE_CAN_GUARD_INTERVAL_AUTO |
1049 FE_CAN_RECOVER |
1050 FE_CAN_HIERARCHY_AUTO,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001051 },
1052
1053 .release = smsdvb_release,
1054
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001055 .set_frontend = smsdvb_set_frontend,
1056 .get_frontend = smsdvb_get_frontend,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001057 .get_tune_settings = smsdvb_get_tune_settings,
1058
1059 .read_status = smsdvb_read_status,
1060 .read_ber = smsdvb_read_ber,
1061 .read_signal_strength = smsdvb_read_signal_strength,
1062 .read_snr = smsdvb_read_snr,
Michael Krufky851a9092008-11-22 14:56:37 -03001063 .read_ucblocks = smsdvb_read_ucblocks,
Michael Krufky7a6fbed2008-11-22 14:26:37 -03001064
1065 .init = smsdvb_init,
1066 .sleep = smsdvb_sleep,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001067};
1068
Michael Krufky0c071f32008-06-21 02:44:02 -03001069static int smsdvb_hotplug(struct smscore_device_t *coredev,
1070 struct device *device, int arrival)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001071{
Michael Krufky18245e12008-06-15 17:52:24 -03001072 struct smsclient_params_t params;
1073 struct smsdvb_client_t *client;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001074 int rc;
1075
Michael Krufkyfa830e82008-06-15 15:52:43 -03001076 /* device removal handled by onremove callback */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001077 if (!arrival)
1078 return 0;
Michael Krufky18245e12008-06-15 17:52:24 -03001079 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
Michael Krufky82237412008-06-15 15:14:13 -03001080 if (!client) {
Michael Krufkyeb250942008-06-19 22:07:23 -03001081 sms_err("kmalloc() failed");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001082 return -ENOMEM;
1083 }
1084
Michael Krufkyfa830e82008-06-15 15:52:43 -03001085 /* register dvb adapter */
Michael Krufky1c11d542008-06-18 22:09:55 -03001086 rc = dvb_register_adapter(&client->adapter,
1087 sms_get_board(
1088 smscore_get_board_id(coredev))->name,
Michael Krufky82237412008-06-15 15:14:13 -03001089 THIS_MODULE, device, adapter_nr);
1090 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001091 sms_err("dvb_register_adapter() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001092 goto adapter_error;
1093 }
1094
Michael Krufkyfa830e82008-06-15 15:52:43 -03001095 /* init dvb demux */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001096 client->demux.dmx.capabilities = DMX_TS_FILTERING;
Michael Krufkyfa830e82008-06-15 15:52:43 -03001097 client->demux.filternum = 32; /* todo: nova ??? */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001098 client->demux.feednum = 32;
1099 client->demux.start_feed = smsdvb_start_feed;
1100 client->demux.stop_feed = smsdvb_stop_feed;
1101
1102 rc = dvb_dmx_init(&client->demux);
Michael Krufky82237412008-06-15 15:14:13 -03001103 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001104 sms_err("dvb_dmx_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001105 goto dvbdmx_error;
1106 }
1107
Michael Krufkyfa830e82008-06-15 15:52:43 -03001108 /* init dmxdev */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001109 client->dmxdev.filternum = 32;
1110 client->dmxdev.demux = &client->demux.dmx;
1111 client->dmxdev.capabilities = 0;
1112
1113 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
Michael Krufky82237412008-06-15 15:14:13 -03001114 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001115 sms_err("dvb_dmxdev_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001116 goto dmxdev_error;
1117 }
1118
Michael Krufkyfa830e82008-06-15 15:52:43 -03001119 /* init and register frontend */
Michael Krufky82237412008-06-15 15:14:13 -03001120 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
1121 sizeof(struct dvb_frontend_ops));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001122
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001123 switch (smscore_get_device_mode(coredev)) {
1124 case DEVICE_MODE_DVBT:
1125 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -03001126 client->frontend.ops.delsys[0] = SYS_DVBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001127 break;
1128 case DEVICE_MODE_ISDBT:
1129 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -03001130 client->frontend.ops.delsys[0] = SYS_ISDBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -03001131 break;
1132 }
1133
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001134 rc = dvb_register_frontend(&client->adapter, &client->frontend);
Michael Krufky82237412008-06-15 15:14:13 -03001135 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001136 sms_err("frontend registration failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001137 goto frontend_error;
1138 }
1139
Michael Krufkyf17407a2008-06-14 00:43:26 -03001140 params.initial_id = 1;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001141 params.data_type = MSG_SMS_DVBT_BDA_DATA;
1142 params.onresponse_handler = smsdvb_onresponse;
1143 params.onremove_handler = smsdvb_onremove;
1144 params.context = client;
1145
1146 rc = smscore_register_client(coredev, &params, &client->smsclient);
Michael Krufky82237412008-06-15 15:14:13 -03001147 if (rc < 0) {
Michael Krufkyeb250942008-06-19 22:07:23 -03001148 sms_err("smscore_register_client() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001149 goto client_error;
1150 }
1151
1152 client->coredev = coredev;
1153
1154 init_completion(&client->tune_done);
Mauro Carvalho Chehab76e41a62013-03-07 16:32:33 -03001155 init_completion(&client->stats_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001156
1157 kmutex_lock(&g_smsdvb_clientslock);
1158
1159 list_add(&client->entry, &g_smsdvb_clients);
1160
1161 kmutex_unlock(&g_smsdvb_clientslock);
1162
Uri Shkolnik793786d2009-05-12 12:28:46 -03001163 client->event_fe_state = -1;
1164 client->event_unc_state = -1;
1165 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001166
Uri Shkolnik793786d2009-05-12 12:28:46 -03001167 sms_info("success");
Michael Krufky250fa672008-11-16 22:45:42 -03001168 sms_board_setup(coredev);
1169
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001170 if (smsdvb_debugfs_create(client) < 0)
Mauro Carvalho Chehab3f6b87c2013-03-09 22:33:06 -03001171 sms_info("failed to create debugfs node");
1172
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001173 return 0;
1174
1175client_error:
1176 dvb_unregister_frontend(&client->frontend);
1177
1178frontend_error:
1179 dvb_dmxdev_release(&client->dmxdev);
1180
1181dmxdev_error:
1182 dvb_dmx_release(&client->demux);
1183
1184dvbdmx_error:
1185 dvb_unregister_adapter(&client->adapter);
1186
1187adapter_error:
1188 kfree(client);
1189 return rc;
1190}
1191
Márton Németh2184dda2009-12-11 20:05:10 -03001192static int __init smsdvb_module_init(void)
Steven Totheae55662008-05-22 18:04:36 -03001193{
1194 int rc;
1195
1196 INIT_LIST_HEAD(&g_smsdvb_clients);
1197 kmutex_init(&g_smsdvb_clientslock);
1198
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001199 smsdvb_debugfs_register();
Mauro Carvalho Chehab3f6b87c2013-03-09 22:33:06 -03001200
Steven Totheae55662008-05-22 18:04:36 -03001201 rc = smscore_register_hotplug(smsdvb_hotplug);
1202
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001203 sms_debug("");
Steven Totheae55662008-05-22 18:04:36 -03001204
1205 return rc;
1206}
1207
Márton Németh2184dda2009-12-11 20:05:10 -03001208static void __exit smsdvb_module_exit(void)
Steven Totheae55662008-05-22 18:04:36 -03001209{
1210 smscore_unregister_hotplug(smsdvb_hotplug);
1211
1212 kmutex_lock(&g_smsdvb_clientslock);
1213
1214 while (!list_empty(&g_smsdvb_clients))
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001215 smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);
Steven Totheae55662008-05-22 18:04:36 -03001216
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001217 smsdvb_debugfs_unregister();
Mauro Carvalho Chehab3f6b87c2013-03-09 22:33:06 -03001218
Steven Totheae55662008-05-22 18:04:36 -03001219 kmutex_unlock(&g_smsdvb_clientslock);
Steven Totheae55662008-05-22 18:04:36 -03001220}
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001221
1222module_init(smsdvb_module_init);
1223module_exit(smsdvb_module_exit);
1224
1225MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
Uri Shkolnik843d0602009-05-12 13:13:13 -03001226MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001227MODULE_LICENSE("GPL");