[media] siano: get rid of CammelCase from smscoreapi.h
[deliverable/linux.git] / drivers / media / common / siano / smsdvb-main.c
CommitLineData
e5275793
US
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2008, Uri Shkolnik
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or
10(at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
8d4f9d0e 21
2e5c1ec8 22#include <linux/module.h>
5a0e3ad6 23#include <linux/slab.h>
2e5c1ec8
MK
24#include <linux/init.h>
25
c9679e3b
US
26#include "dmxdev.h"
27#include "dvbdev.h"
28#include "dvb_demux.h"
29#include "dvb_frontend.h"
30
2e5c1ec8 31#include "smscoreapi.h"
1c11d546 32#include "sms-cards.h"
2e5c1ec8 33
503efe5c 34#include "smsdvb.h"
62c7167d 35
503efe5c 36DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
62c7167d 37
c5e0bd1a
AB
38static struct list_head g_smsdvb_clients;
39static struct mutex g_smsdvb_clientslock;
2e5c1ec8 40
0d02efe4
MK
41static 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
d42f1cb2 45
d42f1cb2
MCC
46u32 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
ff702eb8 76
793786d1
US
77/* 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) {
4db989f7
US
80
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 }
793786d1
US
128}
129
d42f1cb2
MCC
130static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
131{
132 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;
137
138 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 }
145
f5de95e2 146 /* Global stats */
d42f1cb2
MCC
147 c->strength.len = 1;
148 c->cnr.len = 1;
f5de95e2
MCC
149 c->strength.stat[0].scale = FE_SCALE_DECIBEL;
150 c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
d42f1cb2
MCC
151
152 /* 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;
157
f5de95e2
MCC
158 /*
159 * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically
160 * changed when the stats become available.
161 */
d42f1cb2 162 for (i = 0; i < n_layers; i++) {
d42f1cb2
MCC
163 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;
167 }
168}
169
170static inline int sms_to_mode(u32 mode)
171{
172 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}
182
183static 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;
188
189 if (is_rf_locked)
190 return FE_HAS_SIGNAL | FE_HAS_CARRIER;
191
192 return 0;
193}
194
5c3b8743
MCC
195static inline u32 sms_to_bw(u32 value)
196{
197 return value * 1000000;
198}
d42f1cb2
MCC
199
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
d42f1cb2
MCC
209#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
dfef84fc
MCC
231 c->frequency = p->frequency;
232 client->fe_status = sms_to_status(p->is_demod_locked, 0);
233 c->bandwidth_hz = sms_to_bw(p->bandwidth);
234 c->transmission_mode = sms_to_mode(p->transmission_mode);
235 c->guard_interval = sms_to_guard_interval(p->guard_interval);
236 c->code_rate_HP = sms_to_code_rate(p->code_rate);
237 c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
238 c->hierarchy = sms_to_hierarchy(p->hierarchy);
239 c->modulation = sms_to_modulation(p->constellation);
d42f1cb2
MCC
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
dfef84fc 248 client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
d42f1cb2
MCC
249 c->modulation = sms_to_modulation(p->constellation);
250
dfef84fc
MCC
251 /* signal Strength, in DBm */
252 c->strength.stat[0].uvalue = p->in_band_power * 1000;
f5de95e2 253
dfef84fc 254 /* Carrier to noise ratio, in DB */
f5de95e2
MCC
255 c->cnr.stat[0].svalue = p->snr * 1000;
256
257 /* PER/BER requires demod lock */
dfef84fc 258 if (!p->is_demod_locked)
f5de95e2
MCC
259 return;
260
d42f1cb2
MCC
261 /* TS PER */
262 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;
dfef84fc
MCC
265 c->block_error.stat[0].uvalue += p->ets_packets;
266 c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets;
d42f1cb2
MCC
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;
dfef84fc
MCC
271 c->post_bit_error.stat[0].uvalue += p->ber_error_count;
272 c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
d42f1cb2
MCC
273
274 /* Legacy PER/BER */
dfef84fc
MCC
275 client->legacy_per = (p->ets_packets * 65535) /
276 (p->ts_packets + p->ets_packets);
d42f1cb2
MCC
277}
278
279static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
ff702eb8 280 struct SMSHOSTLIB_STATISTICS_ST *p)
5eb23975 281{
d42f1cb2
MCC
282 struct dvb_frontend *fe = &client->frontend;
283 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
284
503efe5c
MCC
285 if (client->prt_dvb_stats)
286 client->prt_dvb_stats(client->debug_data, p);
5eb23975 287
dfef84fc 288 client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
d42f1cb2
MCC
289
290 /* Update DVB modulation parameters */
dfef84fc
MCC
291 c->frequency = p->frequency;
292 client->fe_status = sms_to_status(p->is_demod_locked, 0);
293 c->bandwidth_hz = sms_to_bw(p->bandwidth);
294 c->transmission_mode = sms_to_mode(p->transmission_mode);
295 c->guard_interval = sms_to_guard_interval(p->guard_interval);
296 c->code_rate_HP = sms_to_code_rate(p->code_rate);
297 c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
298 c->hierarchy = sms_to_hierarchy(p->hierarchy);
299 c->modulation = sms_to_modulation(p->constellation);
d42f1cb2 300
b4059095 301 /* update reception data */
dfef84fc 302 c->lna = p->is_external_lna_on ? 1 : 0;
d42f1cb2 303
dfef84fc 304 /* Carrier to noise ratio, in DB */
d42f1cb2
MCC
305 c->cnr.stat[0].svalue = p->SNR * 1000;
306
dfef84fc
MCC
307 /* signal Strength, in DBm */
308 c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
f5de95e2
MCC
309
310 /* PER/BER requires demod lock */
dfef84fc 311 if (!p->is_demod_locked)
f5de95e2 312 return;
d42f1cb2
MCC
313
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;
dfef84fc
MCC
318 c->block_error.stat[0].uvalue += p->error_ts_packets;
319 c->block_count.stat[0].uvalue += p->total_ts_packets;
d42f1cb2
MCC
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;
dfef84fc
MCC
324 c->post_bit_error.stat[0].uvalue += p->ber_error_count;
325 c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
d42f1cb2
MCC
326
327 /* Legacy PER/BER */
328 client->legacy_ber = p->BER;
5eb23975
MCC
329};
330
d42f1cb2 331static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
ff702eb8 332 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
5eb23975 333{
d42f1cb2
MCC
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
503efe5c
MCC
339 if (client->prt_isdb_stats)
340 client->prt_isdb_stats(client->debug_data, p);
5eb23975 341
dfef84fc 342 client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
773adad1
MCC
343
344 /*
345 * Firmware 2.1 seems to report only lock status and
dfef84fc 346 * signal strength. The signal strength indicator is at the
773adad1
MCC
347 * wrong field.
348 */
dfef84fc
MCC
349 if (p->statistics_type == 0) {
350 c->strength.stat[0].uvalue = ((s32)p->transmission_mode) * 1000;
773adad1
MCC
351 c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
352 return;
353 }
354
d42f1cb2 355 /* Update ISDB-T transmission parameters */
dfef84fc
MCC
356 c->frequency = p->frequency;
357 c->bandwidth_hz = sms_to_bw(p->bandwidth);
358 c->transmission_mode = sms_to_mode(p->transmission_mode);
359 c->guard_interval = sms_to_guard_interval(p->guard_interval);
360 c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
361 n_layers = p->num_of_layers;
d42f1cb2
MCC
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
b4059095 368 /* update reception data */
dfef84fc 369 c->lna = p->is_external_lna_on ? 1 : 0;
b4059095 370
dfef84fc 371 /* Carrier to noise ratio, in DB */
d42f1cb2
MCC
372 c->cnr.stat[0].svalue = p->SNR * 1000;
373
dfef84fc
MCC
374 /* signal Strength, in DBm */
375 c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
f5de95e2
MCC
376
377 /* PER/BER and per-layer stats require demod lock */
dfef84fc 378 if (!p->is_demod_locked)
f5de95e2 379 return;
d42f1cb2
MCC
380
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;
9671045f
MCC
386 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
387 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
d42f1cb2
MCC
388 c->post_bit_error.stat[0].uvalue = 0;
389 c->post_bit_count.stat[0].uvalue = 0;
9671045f
MCC
390 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
391 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
d42f1cb2
MCC
392
393 for (i = 0; i < n_layers; i++) {
394 lr = &p->LayerInfo[i];
395
396 /* Update per-layer transmission parameters */
dfef84fc 397 if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
d42f1cb2 398 c->isdbt_layer_enabled |= 1 << i;
dfef84fc 399 c->layer[i].segment_count = lr->number_of_segments;
d42f1cb2
MCC
400 } else {
401 continue;
402 }
dfef84fc 403 c->layer[i].modulation = sms_to_modulation(lr->constellation);
d42f1cb2
MCC
404
405 /* TS PER */
9671045f
MCC
406 c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
407 c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
dfef84fc
MCC
408 c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
409 c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
d42f1cb2
MCC
410
411 /* Update global PER counter */
dfef84fc
MCC
412 c->block_error.stat[0].uvalue += lr->error_ts_packets;
413 c->block_count.stat[0].uvalue += lr->total_ts_packets;
d42f1cb2
MCC
414
415 /* BER */
9671045f
MCC
416 c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
417 c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
dfef84fc
MCC
418 c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
419 c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
d42f1cb2
MCC
420
421 /* Update global BER counter */
dfef84fc
MCC
422 c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
423 c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
b4059095
MCC
424 }
425}
426
d42f1cb2
MCC
427static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
428 struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
b4059095 429{
d42f1cb2
MCC
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
503efe5c
MCC
435 if (client->prt_isdb_stats_ex)
436 client->prt_isdb_stats_ex(client->debug_data, p);
b4059095 437
d42f1cb2 438 /* Update ISDB-T transmission parameters */
dfef84fc
MCC
439 c->frequency = p->frequency;
440 client->fe_status = sms_to_status(p->is_demod_locked, 0);
441 c->bandwidth_hz = sms_to_bw(p->bandwidth);
442 c->transmission_mode = sms_to_mode(p->transmission_mode);
443 c->guard_interval = sms_to_guard_interval(p->guard_interval);
444 c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
445 n_layers = p->num_of_layers;
d42f1cb2
MCC
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
b4059095 452 /* update reception data */
dfef84fc 453 c->lna = p->is_external_lna_on ? 1 : 0;
b4059095 454
dfef84fc 455 /* Carrier to noise ratio, in DB */
d42f1cb2
MCC
456 c->cnr.stat[0].svalue = p->SNR * 1000;
457
dfef84fc
MCC
458 /* signal Strength, in DBm */
459 c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
f5de95e2
MCC
460
461 /* PER/BER and per-layer stats require demod lock */
dfef84fc 462 if (!p->is_demod_locked)
f5de95e2 463 return;
d42f1cb2
MCC
464
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;
9671045f
MCC
470 c->block_error.stat[0].scale = FE_SCALE_COUNTER;
471 c->block_count.stat[0].scale = FE_SCALE_COUNTER;
d42f1cb2
MCC
472 c->post_bit_error.stat[0].uvalue = 0;
473 c->post_bit_count.stat[0].uvalue = 0;
9671045f
MCC
474 c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
475 c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
d42f1cb2 476
9671045f
MCC
477 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;
d42f1cb2
MCC
481 for (i = 0; i < n_layers; i++) {
482 lr = &p->LayerInfo[i];
483
484 /* Update per-layer transmission parameters */
dfef84fc 485 if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
d42f1cb2 486 c->isdbt_layer_enabled |= 1 << i;
dfef84fc 487 c->layer[i].segment_count = lr->number_of_segments;
d42f1cb2
MCC
488 } else {
489 continue;
490 }
dfef84fc 491 c->layer[i].modulation = sms_to_modulation(lr->constellation);
d42f1cb2
MCC
492
493 /* TS PER */
9671045f
MCC
494 c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
495 c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
dfef84fc
MCC
496 c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
497 c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
d42f1cb2
MCC
498
499 /* Update global PER counter */
dfef84fc
MCC
500 c->block_error.stat[0].uvalue += lr->error_ts_packets;
501 c->block_count.stat[0].uvalue += lr->total_ts_packets;
d42f1cb2
MCC
502
503 /* BER */
9671045f
MCC
504 c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
505 c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
dfef84fc
MCC
506 c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
507 c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
d42f1cb2
MCC
508
509 /* Update global BER counter */
dfef84fc
MCC
510 c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
511 c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
5eb23975
MCC
512 }
513}
514
0c071f37 515static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
2e5c1ec8 516{
18245e18 517 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
dfef84fc 518 struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) (((u8 *) cb->p)
793786d1 519 + cb->offset);
d42f1cb2
MCC
520 void *p = phdr + 1;
521 struct dvb_frontend *fe = &client->frontend;
522 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
793786d1 523 bool is_status_update = false;
2e5c1ec8 524
dfef84fc 525 switch (phdr->msg_type) {
82237416 526 case MSG_SMS_DVBT_BDA_DATA:
e1b2ac4d
MCC
527 /*
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,
dfef84fc 533 cb->size - sizeof(struct sms_msg_hdr));
82237416
MK
534 break;
535
536 case MSG_SMS_RF_TUNE_RES:
6b26fcea 537 case MSG_SMS_ISDBT_TUNE_RES:
82237416
MK
538 complete(&client->tune_done);
539 break;
2e5c1ec8 540
793786d1 541 case MSG_SMS_SIGNAL_DETECTED_IND:
d42f1cb2
MCC
542 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
543 FE_HAS_VITERBI | FE_HAS_SYNC |
544 FE_HAS_LOCK;
545
793786d1
US
546 is_status_update = true;
547 break;
548
549 case MSG_SMS_NO_SIGNAL_IND:
d42f1cb2
MCC
550 client->fe_status = 0;
551
793786d1
US
552 is_status_update = true;
553 break;
554
d42f1cb2
MCC
555 case MSG_SMS_TRANSMISSION_IND:
556 smsdvb_update_tx_params(client, p);
793786d1 557
793786d1
US
558 is_status_update = true;
559 break;
793786d1 560
d42f1cb2
MCC
561 case MSG_SMS_HO_PER_SLICES_IND:
562 smsdvb_update_per_slices(client, p);
793786d1
US
563
564 is_status_update = true;
565 break;
5eb23975 566
d42f1cb2 567 case MSG_SMS_GET_STATISTICS_RES:
5eb23975
MCC
568 switch (smscore_get_device_mode(client->coredev)) {
569 case DEVICE_MODE_ISDBT:
570 case DEVICE_MODE_ISDBT_BDA:
d42f1cb2 571 smsdvb_update_isdbt_stats(client, p);
5eb23975
MCC
572 break;
573 default:
dfef84fc 574 /* Skip sms_msg_statistics_info:request_result field */
c02272f9 575 smsdvb_update_dvb_stats(client, p + sizeof(u32));
67ae1d26
MCC
576 }
577
d42f1cb2 578 is_status_update = true;
67ae1d26 579 break;
b4059095 580
d42f1cb2
MCC
581 /* Only for ISDB-T */
582 case MSG_SMS_GET_STATISTICS_EX_RES:
dfef84fc 583 /* Skip sms_msg_statistics_info:request_result field? */
c02272f9 584 smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
b4059095 585 is_status_update = true;
b4059095 586 break;
67ae1d26 587 default:
4c3bdb5e 588 sms_info("message not handled");
793786d1 589 }
2e5c1ec8
MK
590 smscore_putbuffer(client->coredev, cb);
591
793786d1 592 if (is_status_update) {
9671045f 593 if (client->fe_status & FE_HAS_LOCK) {
793786d1 594 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
d42f1cb2 595 if (client->last_per == c->block_error.stat[0].uvalue)
793786d1
US
596 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
597 else
d42f1cb2 598 sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
e1b2ac4d 599 client->has_tuned = true;
793786d1 600 } else {
d42f1cb2 601 smsdvb_stats_not_ready(fe);
e1b2ac4d 602 client->has_tuned = false;
793786d1
US
603 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
604 }
76e41a65 605 complete(&client->stats_done);
793786d1
US
606 }
607
2e5c1ec8
MK
608 return 0;
609}
610
0c071f37 611static void smsdvb_unregister_client(struct smsdvb_client_t *client)
2e5c1ec8 612{
fa830e8a 613 /* must be called under clientslock */
2e5c1ec8
MK
614
615 list_del(&client->entry);
616
503efe5c 617 smsdvb_debugfs_release(client);
2e5c1ec8
MK
618 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
0c071f37 626static void smsdvb_onremove(void *context)
2e5c1ec8
MK
627{
628 kmutex_lock(&g_smsdvb_clientslock);
629
18245e18 630 smsdvb_unregister_client((struct smsdvb_client_t *) context);
2e5c1ec8
MK
631
632 kmutex_unlock(&g_smsdvb_clientslock);
633}
634
635static int smsdvb_start_feed(struct dvb_demux_feed *feed)
636{
18245e18
MK
637 struct smsdvb_client_t *client =
638 container_of(feed->demux, struct smsdvb_client_t, demux);
dfef84fc 639 struct sms_msg_data PidMsg;
2e5c1ec8 640
a0c0abcb 641 sms_debug("add pid %d(%x)",
068d6c0f 642 feed->pid, feed->pid);
2e5c1ec8 643
e1b2ac4d
MCC
644 client->feed_users++;
645
dfef84fc
MCC
646 PidMsg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
647 PidMsg.x_msg_header.msg_dst_id = HIF_TASK;
648 PidMsg.x_msg_header.msg_flags = 0;
649 PidMsg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ;
650 PidMsg.x_msg_header.msg_length = sizeof(PidMsg);
2e5c1ec8
MK
651 PidMsg.msgData[0] = feed->pid;
652
82237416
MK
653 return smsclient_sendrequest(client->smsclient,
654 &PidMsg, sizeof(PidMsg));
2e5c1ec8
MK
655}
656
657static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
658{
18245e18
MK
659 struct smsdvb_client_t *client =
660 container_of(feed->demux, struct smsdvb_client_t, demux);
dfef84fc 661 struct sms_msg_data PidMsg;
2e5c1ec8 662
a0c0abcb 663 sms_debug("remove pid %d(%x)",
068d6c0f 664 feed->pid, feed->pid);
2e5c1ec8 665
e1b2ac4d
MCC
666 client->feed_users--;
667
dfef84fc
MCC
668 PidMsg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
669 PidMsg.x_msg_header.msg_dst_id = HIF_TASK;
670 PidMsg.x_msg_header.msg_flags = 0;
671 PidMsg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ;
672 PidMsg.x_msg_header.msg_length = sizeof(PidMsg);
2e5c1ec8
MK
673 PidMsg.msgData[0] = feed->pid;
674
82237416
MK
675 return smsclient_sendrequest(client->smsclient,
676 &PidMsg, sizeof(PidMsg));
2e5c1ec8
MK
677}
678
18245e18 679static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
a83ccdd6
MK
680 void *buffer, size_t size,
681 struct completion *completion)
2e5c1ec8 682{
ba79bb2c
US
683 int rc;
684
ba79bb2c 685 rc = smsclient_sendrequest(client->smsclient, buffer, size);
2e5c1ec8
MK
686 if (rc < 0)
687 return rc;
688
82237416
MK
689 return wait_for_completion_timeout(completion,
690 msecs_to_jiffies(2000)) ?
691 0 : -ETIME;
2e5c1ec8
MK
692}
693
67ae1d26
MCC
694static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
695{
696 int rc;
dfef84fc 697 struct sms_msg_hdr Msg;
b4059095 698
a9b9fbdf
MCC
699 /* 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);
b4059095 704
dfef84fc
MCC
705 Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
706 Msg.msg_dst_id = HIF_TASK;
707 Msg.msg_flags = 0;
708 Msg.msg_length = sizeof(Msg);
b4059095 709
d42f1cb2
MCC
710 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)
dfef84fc 717 Msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ;
d42f1cb2 718 else
dfef84fc 719 Msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
d42f1cb2
MCC
720 break;
721 default:
dfef84fc 722 Msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
d42f1cb2 723 }
b4059095 724
67ae1d26 725 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
76e41a65 726 &client->stats_done);
67ae1d26
MCC
727
728 return rc;
729}
730
3746b617
MK
731static inline int led_feedback(struct smsdvb_client_t *client)
732{
d42f1cb2 733 if (!(client->fe_status & FE_HAS_LOCK))
3746b617 734 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
d42f1cb2
MCC
735
736 return sms_board_led_feedback(client->coredev,
737 (client->legacy_ber == 0) ?
738 SMS_LED_HI : SMS_LED_LO);
3746b617
MK
739}
740
2e5c1ec8
MK
741static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
742{
67ae1d26 743 int rc;
793786d1
US
744 struct smsdvb_client_t *client;
745 client = container_of(fe, struct smsdvb_client_t, frontend);
2e5c1ec8 746
67ae1d26
MCC
747 rc = smsdvb_send_statistics_request(client);
748
793786d1 749 *stat = client->fe_status;
2e5c1ec8 750
3746b617
MK
751 led_feedback(client);
752
67ae1d26 753 return rc;
2e5c1ec8
MK
754}
755
756static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
757{
67ae1d26 758 int rc;
793786d1 759 struct smsdvb_client_t *client;
d42f1cb2 760
793786d1 761 client = container_of(fe, struct smsdvb_client_t, frontend);
2e5c1ec8 762
67ae1d26
MCC
763 rc = smsdvb_send_statistics_request(client);
764
d42f1cb2 765 *ber = client->legacy_ber;
2e5c1ec8 766
3746b617
MK
767 led_feedback(client);
768
67ae1d26 769 return rc;
2e5c1ec8
MK
770}
771
772static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
773{
d42f1cb2 774 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
67ae1d26 775 int rc;
d42f1cb2 776 s32 power = (s32) c->strength.stat[0].uvalue;
793786d1 777 struct smsdvb_client_t *client;
d42f1cb2 778
793786d1 779 client = container_of(fe, struct smsdvb_client_t, frontend);
2e5c1ec8 780
67ae1d26
MCC
781 rc = smsdvb_send_statistics_request(client);
782
d42f1cb2 783 if (power < -95)
793786d1 784 *strength = 0;
d42f1cb2
MCC
785 else if (power > -29)
786 *strength = 65535;
793786d1 787 else
d42f1cb2 788 *strength = (power + 95) * 65535 / 66;
2e5c1ec8 789
3746b617
MK
790 led_feedback(client);
791
67ae1d26 792 return rc;
2e5c1ec8
MK
793}
794
795static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
796{
d42f1cb2 797 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
67ae1d26 798 int rc;
793786d1 799 struct smsdvb_client_t *client;
d42f1cb2 800
793786d1 801 client = container_of(fe, struct smsdvb_client_t, frontend);
2e5c1ec8 802
67ae1d26
MCC
803 rc = smsdvb_send_statistics_request(client);
804
d42f1cb2
MCC
805 /* Preferred scale for SNR with legacy API: 0.1 dB */
806 *snr = c->cnr.stat[0].svalue / 100;
2e5c1ec8 807
3746b617
MK
808 led_feedback(client);
809
67ae1d26 810 return rc;
2e5c1ec8
MK
811}
812
851a9091
MK
813static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
814{
67ae1d26 815 int rc;
d42f1cb2 816 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
793786d1 817 struct smsdvb_client_t *client;
d42f1cb2 818
793786d1 819 client = container_of(fe, struct smsdvb_client_t, frontend);
851a9091 820
67ae1d26
MCC
821 rc = smsdvb_send_statistics_request(client);
822
d42f1cb2 823 *ucblocks = c->block_error.stat[0].uvalue;
851a9091 824
3746b617
MK
825 led_feedback(client);
826
67ae1d26 827 return rc;
851a9091
MK
828}
829
82237416
MK
830static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
831 struct dvb_frontend_tune_settings *tune)
2e5c1ec8 832{
a0c0abcb 833 sms_debug("");
2e5c1ec8
MK
834
835 tune->min_delay_ms = 400;
836 tune->step_size = 250000;
837 tune->max_drift = 0;
838 return 0;
839}
840
15115c17 841static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
2e5c1ec8 842{
cf4fab72 843 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
18245e18
MK
844 struct smsdvb_client_t *client =
845 container_of(fe, struct smsdvb_client_t, frontend);
2e5c1ec8 846
18245e18 847 struct {
dfef84fc 848 struct sms_msg_hdr Msg;
82237416 849 u32 Data[3];
2e5c1ec8
MK
850 } Msg;
851
3746b617
MK
852 int ret;
853
d42f1cb2 854 client->fe_status = 0;
793786d1
US
855 client->event_fe_state = -1;
856 client->event_unc_state = -1;
e85c97a0 857 fe->dtv_property_cache.delivery_system = SYS_DVBT;
793786d1 858
dfef84fc
MCC
859 Msg.Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
860 Msg.Msg.msg_dst_id = HIF_TASK;
861 Msg.Msg.msg_flags = 0;
862 Msg.Msg.msg_type = MSG_SMS_RF_TUNE_REQ;
863 Msg.Msg.msg_length = sizeof(Msg);
cf4fab72 864 Msg.Data[0] = c->frequency;
2e5c1ec8
MK
865 Msg.Data[2] = 12000000;
866
cf4fab72
MCC
867 sms_info("%s: freq %d band %d", __func__, c->frequency,
868 c->bandwidth_hz);
2e5c1ec8 869
643e15a0 870 switch (c->bandwidth_hz / 1000000) {
cf4fab72
MCC
871 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;
2e5c1ec8 884 }
3746b617
MK
885 /* 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
25985edc 899 /* previous tune didn't lock - enable LNA and tune again */
3746b617
MK
900 sms_board_lna_control(client->coredev, 1);
901 }
2e5c1ec8 902
82237416
MK
903 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
904 &client->tune_done);
2e5c1ec8
MK
905}
906
15115c17 907static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
6b26fcea 908{
cf4fab72 909 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
6b26fcea
MK
910 struct smsdvb_client_t *client =
911 container_of(fe, struct smsdvb_client_t, frontend);
a51fea4f
MCC
912 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;
0c189fa6 915 int ret;
503efe5c 916
6b26fcea 917 struct {
dfef84fc 918 struct sms_msg_hdr Msg;
6b26fcea
MK
919 u32 Data[4];
920 } Msg;
921
e85c97a0
MCC
922 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
923
dfef84fc
MCC
924 Msg.Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
925 Msg.Msg.msg_dst_id = HIF_TASK;
926 Msg.Msg.msg_flags = 0;
927 Msg.Msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ;
928 Msg.Msg.msg_length = sizeof(Msg);
6b26fcea 929
cf4fab72
MCC
930 if (c->isdbt_sb_segment_idx == -1)
931 c->isdbt_sb_segment_idx = 0;
6b26fcea 932
a51fea4f
MCC
933 if (!c->isdbt_layer_enabled)
934 c->isdbt_layer_enabled = 7;
6b26fcea 935
cf4fab72 936 Msg.Data[0] = c->frequency;
a51fea4f 937 Msg.Data[1] = BW_ISDBT_1SEG;
cf4fab72
MCC
938 Msg.Data[2] = 12000000;
939 Msg.Data[3] = c->isdbt_sb_segment_idx;
940
a51fea4f
MCC
941 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
98c3f94e 952 sms_info("%s: freq %d segwidth %d segindex %d", __func__,
cf4fab72
MCC
953 c->frequency, c->isdbt_sb_segment_count,
954 c->isdbt_sb_segment_idx);
955
0c189fa6
MCC
956 /* 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 }
6b26fcea
MK
973 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
974 &client->tune_done);
975}
976
15115c17 977static int smsdvb_set_frontend(struct dvb_frontend *fe)
6b26fcea 978{
f5de95e2 979 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
6b26fcea
MK
980 struct smsdvb_client_t *client =
981 container_of(fe, struct smsdvb_client_t, frontend);
982 struct smscore_device_t *coredev = client->coredev;
983
d42f1cb2 984 smsdvb_stats_not_ready(fe);
f5de95e2
MCC
985 c->strength.stat[0].uvalue = 0;
986 c->cnr.stat[0].uvalue = 0;
d42f1cb2 987
e1b2ac4d
MCC
988 client->has_tuned = false;
989
6b26fcea
MK
990 switch (smscore_get_device_mode(coredev)) {
991 case DEVICE_MODE_DVBT:
992 case DEVICE_MODE_DVBT_BDA:
15115c17 993 return smsdvb_dvbt_set_frontend(fe);
6b26fcea
MK
994 case DEVICE_MODE_ISDBT:
995 case DEVICE_MODE_ISDBT_BDA:
15115c17 996 return smsdvb_isdbt_set_frontend(fe);
6b26fcea
MK
997 default:
998 return -EINVAL;
999 }
1000}
1001
d42f1cb2 1002/* Nothing to do here, as stats are automatically updated */
eab0fa0f
MCC
1003static int smsdvb_get_frontend(struct dvb_frontend *fe)
1004{
d42f1cb2 1005 return 0;
7a6fbed6
MK
1006}
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
3746b617
MK
1013 sms_board_power(client->coredev, 1);
1014
793786d1 1015 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
7a6fbed6
MK
1016 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
3746b617
MK
1024 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
1025 sms_board_power(client->coredev, 0);
1026
793786d1 1027 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
7a6fbed6 1028
2e5c1ec8
MK
1029 return 0;
1030}
1031
1032static void smsdvb_release(struct dvb_frontend *fe)
1033{
fa830e8a 1034 /* do nothing */
2e5c1ec8
MK
1035}
1036
1037static struct dvb_frontend_ops smsdvb_fe_ops = {
1038 .info = {
e0f14c25 1039 .name = "Siano Mobile Digital MDTV Receiver",
2e5c1ec8
MK
1040 .frequency_min = 44250000,
1041 .frequency_max = 867250000,
1042 .frequency_stepsize = 250000,
1043 .caps = FE_CAN_INVERSION_AUTO |
82237416
MK
1044 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,
2e5c1ec8
MK
1051 },
1052
1053 .release = smsdvb_release,
1054
15115c17
MCC
1055 .set_frontend = smsdvb_set_frontend,
1056 .get_frontend = smsdvb_get_frontend,
2e5c1ec8
MK
1057 .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,
851a9091 1063 .read_ucblocks = smsdvb_read_ucblocks,
7a6fbed6
MK
1064
1065 .init = smsdvb_init,
1066 .sleep = smsdvb_sleep,
2e5c1ec8
MK
1067};
1068
0c071f37
MK
1069static int smsdvb_hotplug(struct smscore_device_t *coredev,
1070 struct device *device, int arrival)
2e5c1ec8 1071{
18245e18
MK
1072 struct smsclient_params_t params;
1073 struct smsdvb_client_t *client;
2e5c1ec8
MK
1074 int rc;
1075
fa830e8a 1076 /* device removal handled by onremove callback */
2e5c1ec8
MK
1077 if (!arrival)
1078 return 0;
18245e18 1079 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
82237416 1080 if (!client) {
eb250942 1081 sms_err("kmalloc() failed");
2e5c1ec8
MK
1082 return -ENOMEM;
1083 }
1084
fa830e8a 1085 /* register dvb adapter */
1c11d546
MK
1086 rc = dvb_register_adapter(&client->adapter,
1087 sms_get_board(
1088 smscore_get_board_id(coredev))->name,
82237416
MK
1089 THIS_MODULE, device, adapter_nr);
1090 if (rc < 0) {
a0c0abcb 1091 sms_err("dvb_register_adapter() failed %d", rc);
2e5c1ec8
MK
1092 goto adapter_error;
1093 }
1094
fa830e8a 1095 /* init dvb demux */
2e5c1ec8 1096 client->demux.dmx.capabilities = DMX_TS_FILTERING;
fa830e8a 1097 client->demux.filternum = 32; /* todo: nova ??? */
2e5c1ec8
MK
1098 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);
82237416 1103 if (rc < 0) {
a0c0abcb 1104 sms_err("dvb_dmx_init failed %d", rc);
2e5c1ec8
MK
1105 goto dvbdmx_error;
1106 }
1107
fa830e8a 1108 /* init dmxdev */
2e5c1ec8
MK
1109 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);
82237416 1114 if (rc < 0) {
a0c0abcb 1115 sms_err("dvb_dmxdev_init failed %d", rc);
2e5c1ec8
MK
1116 goto dmxdev_error;
1117 }
1118
fa830e8a 1119 /* init and register frontend */
82237416
MK
1120 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
1121 sizeof(struct dvb_frontend_ops));
2e5c1ec8 1122
15115c17
MCC
1123 switch (smscore_get_device_mode(coredev)) {
1124 case DEVICE_MODE_DVBT:
1125 case DEVICE_MODE_DVBT_BDA:
9bd58e77 1126 client->frontend.ops.delsys[0] = SYS_DVBT;
15115c17
MCC
1127 break;
1128 case DEVICE_MODE_ISDBT:
1129 case DEVICE_MODE_ISDBT_BDA:
9bd58e77 1130 client->frontend.ops.delsys[0] = SYS_ISDBT;
15115c17
MCC
1131 break;
1132 }
1133
2e5c1ec8 1134 rc = dvb_register_frontend(&client->adapter, &client->frontend);
82237416 1135 if (rc < 0) {
a0c0abcb 1136 sms_err("frontend registration failed %d", rc);
2e5c1ec8
MK
1137 goto frontend_error;
1138 }
1139
f17407a8 1140 params.initial_id = 1;
2e5c1ec8
MK
1141 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);
82237416 1147 if (rc < 0) {
eb250942 1148 sms_err("smscore_register_client() failed %d", rc);
2e5c1ec8
MK
1149 goto client_error;
1150 }
1151
1152 client->coredev = coredev;
1153
1154 init_completion(&client->tune_done);
76e41a65 1155 init_completion(&client->stats_done);
2e5c1ec8
MK
1156
1157 kmutex_lock(&g_smsdvb_clientslock);
1158
1159 list_add(&client->entry, &g_smsdvb_clients);
1160
1161 kmutex_unlock(&g_smsdvb_clientslock);
1162
793786d1
US
1163 client->event_fe_state = -1;
1164 client->event_unc_state = -1;
1165 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
2e5c1ec8 1166
793786d1 1167 sms_info("success");
250fa674
MK
1168 sms_board_setup(coredev);
1169
503efe5c 1170 if (smsdvb_debugfs_create(client) < 0)
3f6b87cf
MCC
1171 sms_info("failed to create debugfs node");
1172
2e5c1ec8
MK
1173 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
2184dda0 1192static int __init smsdvb_module_init(void)
eae55660
ST
1193{
1194 int rc;
1195
1196 INIT_LIST_HEAD(&g_smsdvb_clients);
1197 kmutex_init(&g_smsdvb_clientslock);
1198
503efe5c 1199 smsdvb_debugfs_register();
3f6b87cf 1200
eae55660
ST
1201 rc = smscore_register_hotplug(smsdvb_hotplug);
1202
a0c0abcb 1203 sms_debug("");
eae55660
ST
1204
1205 return rc;
1206}
1207
2184dda0 1208static void __exit smsdvb_module_exit(void)
eae55660
ST
1209{
1210 smscore_unregister_hotplug(smsdvb_hotplug);
1211
1212 kmutex_lock(&g_smsdvb_clientslock);
1213
1214 while (!list_empty(&g_smsdvb_clients))
503efe5c 1215 smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);
eae55660 1216
503efe5c 1217 smsdvb_debugfs_unregister();
3f6b87cf 1218
eae55660 1219 kmutex_unlock(&g_smsdvb_clientslock);
eae55660 1220}
e0f14c25
US
1221
1222module_init(smsdvb_module_init);
1223module_exit(smsdvb_module_exit);
1224
1225MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
843d0605 1226MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
e0f14c25 1227MODULE_LICENSE("GPL");
This page took 0.427744 seconds and 5 git commands to generate.