smsdvb-main.c revision 1668844ee642ed5734fc3e7ab5d7746ef8661961
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2008, Uri Shkolnik
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or
10(at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
21
22#include <linux/module.h>
23#include <linux/slab.h>
24#include <linux/init.h>
25#include <asm/div64.h>
26
27#include "dmxdev.h"
28#include "dvbdev.h"
29#include "dvb_demux.h"
30#include "dvb_frontend.h"
31
32#include "smscoreapi.h"
33#include "sms-cards.h"
34
35#include "smsdvb.h"
36
37DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
38
39static struct list_head g_smsdvb_clients;
40static struct mutex g_smsdvb_clientslock;
41
42static int sms_dbg;
43module_param_named(debug, sms_dbg, int, 0644);
44MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
45
46
47static u32 sms_to_guard_interval_table[] = {
48	[0] = GUARD_INTERVAL_1_32,
49	[1] = GUARD_INTERVAL_1_16,
50	[2] = GUARD_INTERVAL_1_8,
51	[3] = GUARD_INTERVAL_1_4,
52};
53
54static u32 sms_to_code_rate_table[] = {
55	[0] = FEC_1_2,
56	[1] = FEC_2_3,
57	[2] = FEC_3_4,
58	[3] = FEC_5_6,
59	[4] = FEC_7_8,
60};
61
62
63static u32 sms_to_hierarchy_table[] = {
64	[0] = HIERARCHY_NONE,
65	[1] = HIERARCHY_1,
66	[2] = HIERARCHY_2,
67	[3] = HIERARCHY_4,
68};
69
70static u32 sms_to_modulation_table[] = {
71	[0] = QPSK,
72	[1] = QAM_16,
73	[2] = QAM_64,
74	[3] = DQPSK,
75};
76
77
78/* Events that may come from DVB v3 adapter */
79static void sms_board_dvb3_event(struct smsdvb_client_t *client,
80		enum SMS_DVB3_EVENTS event) {
81
82	struct smscore_device_t *coredev = client->coredev;
83	switch (event) {
84	case DVB3_EVENT_INIT:
85		sms_debug("DVB3_EVENT_INIT");
86		sms_board_event(coredev, BOARD_EVENT_BIND);
87		break;
88	case DVB3_EVENT_SLEEP:
89		sms_debug("DVB3_EVENT_SLEEP");
90		sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
91		break;
92	case DVB3_EVENT_HOTPLUG:
93		sms_debug("DVB3_EVENT_HOTPLUG");
94		sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
95		break;
96	case DVB3_EVENT_FE_LOCK:
97		if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
98			client->event_fe_state = DVB3_EVENT_FE_LOCK;
99			sms_debug("DVB3_EVENT_FE_LOCK");
100			sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
101		}
102		break;
103	case DVB3_EVENT_FE_UNLOCK:
104		if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
105			client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
106			sms_debug("DVB3_EVENT_FE_UNLOCK");
107			sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
108		}
109		break;
110	case DVB3_EVENT_UNC_OK:
111		if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
112			client->event_unc_state = DVB3_EVENT_UNC_OK;
113			sms_debug("DVB3_EVENT_UNC_OK");
114			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
115		}
116		break;
117	case DVB3_EVENT_UNC_ERR:
118		if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
119			client->event_unc_state = DVB3_EVENT_UNC_ERR;
120			sms_debug("DVB3_EVENT_UNC_ERR");
121			sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
122		}
123		break;
124
125	default:
126		sms_err("Unknown dvb3 api event");
127		break;
128	}
129}
130
131static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
132{
133	struct smsdvb_client_t *client =
134		container_of(fe, struct smsdvb_client_t, frontend);
135	struct smscore_device_t *coredev = client->coredev;
136	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
137	int i, n_layers;
138
139	switch (smscore_get_device_mode(coredev)) {
140	case DEVICE_MODE_ISDBT:
141	case DEVICE_MODE_ISDBT_BDA:
142		n_layers = 4;
143		break;
144	default:
145		n_layers = 1;
146	}
147
148	/* Global stats */
149	c->strength.len = 1;
150	c->cnr.len = 1;
151	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
152	c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
153
154	/* Per-layer stats */
155	c->post_bit_error.len = n_layers;
156	c->post_bit_count.len = n_layers;
157	c->block_error.len = n_layers;
158	c->block_count.len = n_layers;
159
160	/*
161	 * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically
162	 * changed when the stats become available.
163	 */
164	for (i = 0; i < n_layers; i++) {
165		c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
166		c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
167		c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
168		c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
169	}
170}
171
172static inline int sms_to_mode(u32 mode)
173{
174	switch (mode) {
175	case 2:
176		return TRANSMISSION_MODE_2K;
177	case 4:
178		return TRANSMISSION_MODE_4K;
179	case 8:
180		return TRANSMISSION_MODE_8K;
181	}
182	return TRANSMISSION_MODE_AUTO;
183}
184
185static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)
186{
187	if (is_demod_locked)
188		return FE_HAS_SIGNAL  | FE_HAS_CARRIER | FE_HAS_VITERBI |
189		       FE_HAS_SYNC    | FE_HAS_LOCK;
190
191	if (is_rf_locked)
192		return FE_HAS_SIGNAL | FE_HAS_CARRIER;
193
194	return 0;
195}
196
197static inline u32 sms_to_bw(u32 value)
198{
199	return value * 1000000;
200}
201
202#define convert_from_table(value, table, defval) ({			\
203	u32 __ret;							\
204	if (value < ARRAY_SIZE(table))					\
205		__ret = table[value];					\
206	else								\
207		__ret = defval;						\
208	__ret;								\
209})
210
211#define sms_to_guard_interval(value)					\
212	convert_from_table(value, sms_to_guard_interval_table,		\
213			   GUARD_INTERVAL_AUTO);
214
215#define sms_to_code_rate(value)						\
216	convert_from_table(value, sms_to_code_rate_table,		\
217			   FEC_NONE);
218
219#define sms_to_hierarchy(value)						\
220	convert_from_table(value, sms_to_hierarchy_table,		\
221			   FEC_NONE);
222
223#define sms_to_modulation(value)					\
224	convert_from_table(value, sms_to_modulation_table,		\
225			   FEC_NONE);
226
227static void smsdvb_update_tx_params(struct smsdvb_client_t *client,
228				    struct sms_tx_stats *p)
229{
230	struct dvb_frontend *fe = &client->frontend;
231	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
232
233	c->frequency = p->frequency;
234	client->fe_status = sms_to_status(p->is_demod_locked, 0);
235	c->bandwidth_hz = sms_to_bw(p->bandwidth);
236	c->transmission_mode = sms_to_mode(p->transmission_mode);
237	c->guard_interval = sms_to_guard_interval(p->guard_interval);
238	c->code_rate_HP = sms_to_code_rate(p->code_rate);
239	c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
240	c->hierarchy = sms_to_hierarchy(p->hierarchy);
241	c->modulation = sms_to_modulation(p->constellation);
242}
243
244static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
245				     struct RECEPTION_STATISTICS_PER_SLICES_S *p)
246{
247	struct dvb_frontend *fe = &client->frontend;
248	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
249	u64 tmp;
250
251	client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
252	c->modulation = sms_to_modulation(p->constellation);
253
254	/* signal Strength, in DBm */
255	c->strength.stat[0].uvalue = p->in_band_power * 1000;
256
257	/* Carrier to noise ratio, in DB */
258	c->cnr.stat[0].svalue = p->snr * 1000;
259
260	/* PER/BER requires demod lock */
261	if (!p->is_demod_locked)
262		return;
263
264	/* TS PER */
265	client->last_per = c->block_error.stat[0].uvalue;
266	c->block_error.stat[0].scale = FE_SCALE_COUNTER;
267	c->block_count.stat[0].scale = FE_SCALE_COUNTER;
268	c->block_error.stat[0].uvalue += p->ets_packets;
269	c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets;
270
271	/* ber */
272	c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
273	c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
274	c->post_bit_error.stat[0].uvalue += p->ber_error_count;
275	c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
276
277	/* Legacy PER/BER */
278	tmp = p->ets_packets * 65535;
279	if (p->ts_packets + p->ets_packets)
280		do_div(tmp, p->ts_packets + p->ets_packets);
281	client->legacy_per = tmp;
282}
283
284static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
285				    struct sms_stats *p)
286{
287	struct dvb_frontend *fe = &client->frontend;
288	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
289
290	if (client->prt_dvb_stats)
291		client->prt_dvb_stats(client->debug_data, p);
292
293	client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
294
295	/* Update DVB modulation parameters */
296	c->frequency = p->frequency;
297	client->fe_status = sms_to_status(p->is_demod_locked, 0);
298	c->bandwidth_hz = sms_to_bw(p->bandwidth);
299	c->transmission_mode = sms_to_mode(p->transmission_mode);
300	c->guard_interval = sms_to_guard_interval(p->guard_interval);
301	c->code_rate_HP = sms_to_code_rate(p->code_rate);
302	c->code_rate_LP = sms_to_code_rate(p->lp_code_rate);
303	c->hierarchy = sms_to_hierarchy(p->hierarchy);
304	c->modulation = sms_to_modulation(p->constellation);
305
306	/* update reception data */
307	c->lna = p->is_external_lna_on ? 1 : 0;
308
309	/* Carrier to noise ratio, in DB */
310	c->cnr.stat[0].svalue = p->SNR * 1000;
311
312	/* signal Strength, in DBm */
313	c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
314
315	/* PER/BER requires demod lock */
316	if (!p->is_demod_locked)
317		return;
318
319	/* TS PER */
320	client->last_per = c->block_error.stat[0].uvalue;
321	c->block_error.stat[0].scale = FE_SCALE_COUNTER;
322	c->block_count.stat[0].scale = FE_SCALE_COUNTER;
323	c->block_error.stat[0].uvalue += p->error_ts_packets;
324	c->block_count.stat[0].uvalue += p->total_ts_packets;
325
326	/* ber */
327	c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
328	c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
329	c->post_bit_error.stat[0].uvalue += p->ber_error_count;
330	c->post_bit_count.stat[0].uvalue += p->ber_bit_count;
331
332	/* Legacy PER/BER */
333	client->legacy_ber = p->ber;
334};
335
336static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
337				      struct sms_isdbt_stats *p)
338{
339	struct dvb_frontend *fe = &client->frontend;
340	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
341	struct sms_isdbt_layer_stats *lr;
342	int i, n_layers;
343
344	if (client->prt_isdb_stats)
345		client->prt_isdb_stats(client->debug_data, p);
346
347	client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked);
348
349	/*
350	 * Firmware 2.1 seems to report only lock status and
351	 * signal strength. The signal strength indicator is at the
352	 * wrong field.
353	 */
354	if (p->statistics_type == 0) {
355		c->strength.stat[0].uvalue = ((s32)p->transmission_mode) * 1000;
356		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
357		return;
358	}
359
360	/* Update ISDB-T transmission parameters */
361	c->frequency = p->frequency;
362	c->bandwidth_hz = sms_to_bw(p->bandwidth);
363	c->transmission_mode = sms_to_mode(p->transmission_mode);
364	c->guard_interval = sms_to_guard_interval(p->guard_interval);
365	c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
366	n_layers = p->num_of_layers;
367	if (n_layers < 1)
368		n_layers = 1;
369	if (n_layers > 3)
370		n_layers = 3;
371	c->isdbt_layer_enabled = 0;
372
373	/* update reception data */
374	c->lna = p->is_external_lna_on ? 1 : 0;
375
376	/* Carrier to noise ratio, in DB */
377	c->cnr.stat[0].svalue = p->SNR * 1000;
378
379	/* signal Strength, in DBm */
380	c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
381
382	/* PER/BER and per-layer stats require demod lock */
383	if (!p->is_demod_locked)
384		return;
385
386	client->last_per = c->block_error.stat[0].uvalue;
387
388	/* Clears global counters, as the code below will sum it again */
389	c->block_error.stat[0].uvalue = 0;
390	c->block_count.stat[0].uvalue = 0;
391	c->block_error.stat[0].scale = FE_SCALE_COUNTER;
392	c->block_count.stat[0].scale = FE_SCALE_COUNTER;
393	c->post_bit_error.stat[0].uvalue = 0;
394	c->post_bit_count.stat[0].uvalue = 0;
395	c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
396	c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
397
398	for (i = 0; i < n_layers; i++) {
399		lr = &p->layer_info[i];
400
401		/* Update per-layer transmission parameters */
402		if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
403			c->isdbt_layer_enabled |= 1 << i;
404			c->layer[i].segment_count = lr->number_of_segments;
405		} else {
406			continue;
407		}
408		c->layer[i].modulation = sms_to_modulation(lr->constellation);
409
410		/* TS PER */
411		c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
412		c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
413		c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
414		c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
415
416		/* Update global PER counter */
417		c->block_error.stat[0].uvalue += lr->error_ts_packets;
418		c->block_count.stat[0].uvalue += lr->total_ts_packets;
419
420		/* BER */
421		c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
422		c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
423		c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
424		c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
425
426		/* Update global BER counter */
427		c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
428		c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
429	}
430}
431
432static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
433					 struct sms_isdbt_stats_ex *p)
434{
435	struct dvb_frontend *fe = &client->frontend;
436	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
437	struct sms_isdbt_layer_stats *lr;
438	int i, n_layers;
439
440	if (client->prt_isdb_stats_ex)
441		client->prt_isdb_stats_ex(client->debug_data, p);
442
443	/* Update ISDB-T transmission parameters */
444	c->frequency = p->frequency;
445	client->fe_status = sms_to_status(p->is_demod_locked, 0);
446	c->bandwidth_hz = sms_to_bw(p->bandwidth);
447	c->transmission_mode = sms_to_mode(p->transmission_mode);
448	c->guard_interval = sms_to_guard_interval(p->guard_interval);
449	c->isdbt_partial_reception = p->partial_reception ? 1 : 0;
450	n_layers = p->num_of_layers;
451	if (n_layers < 1)
452		n_layers = 1;
453	if (n_layers > 3)
454		n_layers = 3;
455	c->isdbt_layer_enabled = 0;
456
457	/* update reception data */
458	c->lna = p->is_external_lna_on ? 1 : 0;
459
460	/* Carrier to noise ratio, in DB */
461	c->cnr.stat[0].svalue = p->SNR * 1000;
462
463	/* signal Strength, in DBm */
464	c->strength.stat[0].uvalue = p->in_band_pwr * 1000;
465
466	/* PER/BER and per-layer stats require demod lock */
467	if (!p->is_demod_locked)
468		return;
469
470	client->last_per = c->block_error.stat[0].uvalue;
471
472	/* Clears global counters, as the code below will sum it again */
473	c->block_error.stat[0].uvalue = 0;
474	c->block_count.stat[0].uvalue = 0;
475	c->block_error.stat[0].scale = FE_SCALE_COUNTER;
476	c->block_count.stat[0].scale = FE_SCALE_COUNTER;
477	c->post_bit_error.stat[0].uvalue = 0;
478	c->post_bit_count.stat[0].uvalue = 0;
479	c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
480	c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
481
482	c->post_bit_error.len = n_layers + 1;
483	c->post_bit_count.len = n_layers + 1;
484	c->block_error.len = n_layers + 1;
485	c->block_count.len = n_layers + 1;
486	for (i = 0; i < n_layers; i++) {
487		lr = &p->layer_info[i];
488
489		/* Update per-layer transmission parameters */
490		if (lr->number_of_segments > 0 && lr->number_of_segments < 13) {
491			c->isdbt_layer_enabled |= 1 << i;
492			c->layer[i].segment_count = lr->number_of_segments;
493		} else {
494			continue;
495		}
496		c->layer[i].modulation = sms_to_modulation(lr->constellation);
497
498		/* TS PER */
499		c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER;
500		c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER;
501		c->block_error.stat[i + 1].uvalue += lr->error_ts_packets;
502		c->block_count.stat[i + 1].uvalue += lr->total_ts_packets;
503
504		/* Update global PER counter */
505		c->block_error.stat[0].uvalue += lr->error_ts_packets;
506		c->block_count.stat[0].uvalue += lr->total_ts_packets;
507
508		/* ber */
509		c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER;
510		c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER;
511		c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count;
512		c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count;
513
514		/* Update global ber counter */
515		c->post_bit_error.stat[0].uvalue += lr->ber_error_count;
516		c->post_bit_count.stat[0].uvalue += lr->ber_bit_count;
517	}
518}
519
520static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
521{
522	struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
523	struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) (((u8 *) cb->p)
524			+ cb->offset);
525	void *p = phdr + 1;
526	struct dvb_frontend *fe = &client->frontend;
527	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
528	bool is_status_update = false;
529
530	switch (phdr->msg_type) {
531	case MSG_SMS_DVBT_BDA_DATA:
532		/*
533		 * Only feed data to dvb demux if are there any feed listening
534		 * to it and if the device has tuned
535		 */
536		if (client->feed_users && client->has_tuned)
537			dvb_dmx_swfilter(&client->demux, p,
538					 cb->size - sizeof(struct sms_msg_hdr));
539		break;
540
541	case MSG_SMS_RF_TUNE_RES:
542	case MSG_SMS_ISDBT_TUNE_RES:
543		complete(&client->tune_done);
544		break;
545
546	case MSG_SMS_SIGNAL_DETECTED_IND:
547		client->fe_status = FE_HAS_SIGNAL  | FE_HAS_CARRIER |
548				    FE_HAS_VITERBI | FE_HAS_SYNC    |
549				    FE_HAS_LOCK;
550
551		is_status_update = true;
552		break;
553
554	case MSG_SMS_NO_SIGNAL_IND:
555		client->fe_status = 0;
556
557		is_status_update = true;
558		break;
559
560	case MSG_SMS_TRANSMISSION_IND:
561		smsdvb_update_tx_params(client, p);
562
563		is_status_update = true;
564		break;
565
566	case MSG_SMS_HO_PER_SLICES_IND:
567		smsdvb_update_per_slices(client, p);
568
569		is_status_update = true;
570		break;
571
572	case MSG_SMS_GET_STATISTICS_RES:
573		switch (smscore_get_device_mode(client->coredev)) {
574		case DEVICE_MODE_ISDBT:
575		case DEVICE_MODE_ISDBT_BDA:
576			smsdvb_update_isdbt_stats(client, p);
577			break;
578		default:
579			/* Skip sms_msg_statistics_info:request_result field */
580			smsdvb_update_dvb_stats(client, p + sizeof(u32));
581		}
582
583		is_status_update = true;
584		break;
585
586	/* Only for ISDB-T */
587	case MSG_SMS_GET_STATISTICS_EX_RES:
588		/* Skip sms_msg_statistics_info:request_result field? */
589		smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32));
590		is_status_update = true;
591		break;
592	default:
593		sms_info("message not handled");
594	}
595	smscore_putbuffer(client->coredev, cb);
596
597	if (is_status_update) {
598		if (client->fe_status & FE_HAS_LOCK) {
599			sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
600			if (client->last_per == c->block_error.stat[0].uvalue)
601				sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
602			else
603				sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
604			client->has_tuned = true;
605		} else {
606			smsdvb_stats_not_ready(fe);
607			client->has_tuned = false;
608			sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
609		}
610		complete(&client->stats_done);
611	}
612
613	return 0;
614}
615
616static void smsdvb_unregister_client(struct smsdvb_client_t *client)
617{
618	/* must be called under clientslock */
619
620	list_del(&client->entry);
621
622	smsdvb_debugfs_release(client);
623	smscore_unregister_client(client->smsclient);
624	dvb_unregister_frontend(&client->frontend);
625	dvb_dmxdev_release(&client->dmxdev);
626	dvb_dmx_release(&client->demux);
627	dvb_unregister_adapter(&client->adapter);
628	kfree(client);
629}
630
631static void smsdvb_onremove(void *context)
632{
633	kmutex_lock(&g_smsdvb_clientslock);
634
635	smsdvb_unregister_client((struct smsdvb_client_t *) context);
636
637	kmutex_unlock(&g_smsdvb_clientslock);
638}
639
640static int smsdvb_start_feed(struct dvb_demux_feed *feed)
641{
642	struct smsdvb_client_t *client =
643		container_of(feed->demux, struct smsdvb_client_t, demux);
644	struct sms_msg_data pid_msg;
645
646	sms_debug("add pid %d(%x)",
647		  feed->pid, feed->pid);
648
649	client->feed_users++;
650
651	pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
652	pid_msg.x_msg_header.msg_dst_id = HIF_TASK;
653	pid_msg.x_msg_header.msg_flags = 0;
654	pid_msg.x_msg_header.msg_type  = MSG_SMS_ADD_PID_FILTER_REQ;
655	pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
656	pid_msg.msg_data[0] = feed->pid;
657
658	return smsclient_sendrequest(client->smsclient,
659				     &pid_msg, sizeof(pid_msg));
660}
661
662static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
663{
664	struct smsdvb_client_t *client =
665		container_of(feed->demux, struct smsdvb_client_t, demux);
666	struct sms_msg_data pid_msg;
667
668	sms_debug("remove pid %d(%x)",
669		  feed->pid, feed->pid);
670
671	client->feed_users--;
672
673	pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
674	pid_msg.x_msg_header.msg_dst_id = HIF_TASK;
675	pid_msg.x_msg_header.msg_flags = 0;
676	pid_msg.x_msg_header.msg_type  = MSG_SMS_REMOVE_PID_FILTER_REQ;
677	pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
678	pid_msg.msg_data[0] = feed->pid;
679
680	return smsclient_sendrequest(client->smsclient,
681				     &pid_msg, sizeof(pid_msg));
682}
683
684static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
685					void *buffer, size_t size,
686					struct completion *completion)
687{
688	int rc;
689
690	rc = smsclient_sendrequest(client->smsclient, buffer, size);
691	if (rc < 0)
692		return rc;
693
694	return wait_for_completion_timeout(completion,
695					   msecs_to_jiffies(2000)) ?
696						0 : -ETIME;
697}
698
699static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
700{
701	int rc;
702	struct sms_msg_hdr msg;
703
704	/* Don't request stats too fast */
705	if (client->get_stats_jiffies &&
706	   (!time_after(jiffies, client->get_stats_jiffies)))
707		return 0;
708	client->get_stats_jiffies = jiffies + msecs_to_jiffies(100);
709
710	msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
711	msg.msg_dst_id = HIF_TASK;
712	msg.msg_flags = 0;
713	msg.msg_length = sizeof(msg);
714
715	switch (smscore_get_device_mode(client->coredev)) {
716	case DEVICE_MODE_ISDBT:
717	case DEVICE_MODE_ISDBT_BDA:
718		/*
719		* Check for firmware version, to avoid breaking for old cards
720		*/
721		if (client->coredev->fw_version >= 0x800)
722			msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ;
723		else
724			msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
725		break;
726	default:
727		msg.msg_type = MSG_SMS_GET_STATISTICS_REQ;
728	}
729
730	rc = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
731					 &client->stats_done);
732
733	return rc;
734}
735
736static inline int led_feedback(struct smsdvb_client_t *client)
737{
738	if (!(client->fe_status & FE_HAS_LOCK))
739		return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
740
741	return sms_board_led_feedback(client->coredev,
742				     (client->legacy_ber == 0) ?
743				     SMS_LED_HI : SMS_LED_LO);
744}
745
746static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
747{
748	int rc;
749	struct smsdvb_client_t *client;
750	client = container_of(fe, struct smsdvb_client_t, frontend);
751
752	rc = smsdvb_send_statistics_request(client);
753
754	*stat = client->fe_status;
755
756	led_feedback(client);
757
758	return rc;
759}
760
761static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
762{
763	int rc;
764	struct smsdvb_client_t *client;
765
766	client = container_of(fe, struct smsdvb_client_t, frontend);
767
768	rc = smsdvb_send_statistics_request(client);
769
770	*ber = client->legacy_ber;
771
772	led_feedback(client);
773
774	return rc;
775}
776
777static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
778{
779	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
780	int rc;
781	s32 power = (s32) c->strength.stat[0].uvalue;
782	struct smsdvb_client_t *client;
783
784	client = container_of(fe, struct smsdvb_client_t, frontend);
785
786	rc = smsdvb_send_statistics_request(client);
787
788	if (power < -95)
789		*strength = 0;
790		else if (power > -29)
791			*strength = 65535;
792		else
793			*strength = (power + 95) * 65535 / 66;
794
795	led_feedback(client);
796
797	return rc;
798}
799
800static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
801{
802	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
803	int rc;
804	struct smsdvb_client_t *client;
805
806	client = container_of(fe, struct smsdvb_client_t, frontend);
807
808	rc = smsdvb_send_statistics_request(client);
809
810	/* Preferred scale for SNR with legacy API: 0.1 dB */
811	*snr = ((u32)c->cnr.stat[0].svalue) / 100;
812
813	led_feedback(client);
814
815	return rc;
816}
817
818static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
819{
820	int rc;
821	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
822	struct smsdvb_client_t *client;
823
824	client = container_of(fe, struct smsdvb_client_t, frontend);
825
826	rc = smsdvb_send_statistics_request(client);
827
828	*ucblocks = c->block_error.stat[0].uvalue;
829
830	led_feedback(client);
831
832	return rc;
833}
834
835static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
836				    struct dvb_frontend_tune_settings *tune)
837{
838	sms_debug("");
839
840	tune->min_delay_ms = 400;
841	tune->step_size = 250000;
842	tune->max_drift = 0;
843	return 0;
844}
845
846static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
847{
848	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
849	struct smsdvb_client_t *client =
850		container_of(fe, struct smsdvb_client_t, frontend);
851
852	struct {
853		struct sms_msg_hdr	msg;
854		u32		Data[3];
855	} msg;
856
857	int ret;
858
859	client->fe_status = 0;
860	client->event_fe_state = -1;
861	client->event_unc_state = -1;
862	fe->dtv_property_cache.delivery_system = SYS_DVBT;
863
864	msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID;
865	msg.msg.msg_dst_id = HIF_TASK;
866	msg.msg.msg_flags = 0;
867	msg.msg.msg_type = MSG_SMS_RF_TUNE_REQ;
868	msg.msg.msg_length = sizeof(msg);
869	msg.Data[0] = c->frequency;
870	msg.Data[2] = 12000000;
871
872	sms_info("%s: freq %d band %d", __func__, c->frequency,
873		 c->bandwidth_hz);
874
875	switch (c->bandwidth_hz / 1000000) {
876	case 8:
877		msg.Data[1] = BW_8_MHZ;
878		break;
879	case 7:
880		msg.Data[1] = BW_7_MHZ;
881		break;
882	case 6:
883		msg.Data[1] = BW_6_MHZ;
884		break;
885	case 0:
886		return -EOPNOTSUPP;
887	default:
888		return -EINVAL;
889	}
890	/* Disable LNA, if any. An error is returned if no LNA is present */
891	ret = sms_board_lna_control(client->coredev, 0);
892	if (ret == 0) {
893		fe_status_t status;
894
895		/* tune with LNA off at first */
896		ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
897						  &client->tune_done);
898
899		smsdvb_read_status(fe, &status);
900
901		if (status & FE_HAS_LOCK)
902			return ret;
903
904		/* previous tune didn't lock - enable LNA and tune again */
905		sms_board_lna_control(client->coredev, 1);
906	}
907
908	return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
909					   &client->tune_done);
910}
911
912static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
913{
914	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
915	struct smsdvb_client_t *client =
916		container_of(fe, struct smsdvb_client_t, frontend);
917	int board_id = smscore_get_board_id(client->coredev);
918	struct sms_board *board = sms_get_board(board_id);
919	enum sms_device_type_st type = board->type;
920	int ret;
921
922	struct {
923		struct sms_msg_hdr	msg;
924		u32		Data[4];
925	} msg;
926
927	fe->dtv_property_cache.delivery_system = SYS_ISDBT;
928
929	msg.msg.msg_src_id  = DVBT_BDA_CONTROL_MSG_ID;
930	msg.msg.msg_dst_id  = HIF_TASK;
931	msg.msg.msg_flags  = 0;
932	msg.msg.msg_type   = MSG_SMS_ISDBT_TUNE_REQ;
933	msg.msg.msg_length = sizeof(msg);
934
935	if (c->isdbt_sb_segment_idx == -1)
936		c->isdbt_sb_segment_idx = 0;
937
938	if (!c->isdbt_layer_enabled)
939		c->isdbt_layer_enabled = 7;
940
941	msg.Data[0] = c->frequency;
942	msg.Data[1] = BW_ISDBT_1SEG;
943	msg.Data[2] = 12000000;
944	msg.Data[3] = c->isdbt_sb_segment_idx;
945
946	if (c->isdbt_partial_reception) {
947		if ((type == SMS_PELE || type == SMS_RIO) &&
948		    c->isdbt_sb_segment_count > 3)
949			msg.Data[1] = BW_ISDBT_13SEG;
950		else if (c->isdbt_sb_segment_count > 1)
951			msg.Data[1] = BW_ISDBT_3SEG;
952	} else if (type == SMS_PELE || type == SMS_RIO)
953		msg.Data[1] = BW_ISDBT_13SEG;
954
955	c->bandwidth_hz = 6000000;
956
957	sms_info("%s: freq %d segwidth %d segindex %d", __func__,
958		 c->frequency, c->isdbt_sb_segment_count,
959		 c->isdbt_sb_segment_idx);
960
961	/* Disable LNA, if any. An error is returned if no LNA is present */
962	ret = sms_board_lna_control(client->coredev, 0);
963	if (ret == 0) {
964		fe_status_t status;
965
966		/* tune with LNA off at first */
967		ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
968						  &client->tune_done);
969
970		smsdvb_read_status(fe, &status);
971
972		if (status & FE_HAS_LOCK)
973			return ret;
974
975		/* previous tune didn't lock - enable LNA and tune again */
976		sms_board_lna_control(client->coredev, 1);
977	}
978	return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg),
979					   &client->tune_done);
980}
981
982static int smsdvb_set_frontend(struct dvb_frontend *fe)
983{
984	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
985	struct smsdvb_client_t *client =
986		container_of(fe, struct smsdvb_client_t, frontend);
987	struct smscore_device_t *coredev = client->coredev;
988
989	smsdvb_stats_not_ready(fe);
990	c->strength.stat[0].uvalue = 0;
991	c->cnr.stat[0].uvalue = 0;
992
993	client->has_tuned = false;
994
995	switch (smscore_get_device_mode(coredev)) {
996	case DEVICE_MODE_DVBT:
997	case DEVICE_MODE_DVBT_BDA:
998		return smsdvb_dvbt_set_frontend(fe);
999	case DEVICE_MODE_ISDBT:
1000	case DEVICE_MODE_ISDBT_BDA:
1001		return smsdvb_isdbt_set_frontend(fe);
1002	default:
1003		return -EINVAL;
1004	}
1005}
1006
1007/* Nothing to do here, as stats are automatically updated */
1008static int smsdvb_get_frontend(struct dvb_frontend *fe)
1009{
1010	return 0;
1011}
1012
1013static int smsdvb_init(struct dvb_frontend *fe)
1014{
1015	struct smsdvb_client_t *client =
1016		container_of(fe, struct smsdvb_client_t, frontend);
1017
1018	sms_board_power(client->coredev, 1);
1019
1020	sms_board_dvb3_event(client, DVB3_EVENT_INIT);
1021	return 0;
1022}
1023
1024static int smsdvb_sleep(struct dvb_frontend *fe)
1025{
1026	struct smsdvb_client_t *client =
1027		container_of(fe, struct smsdvb_client_t, frontend);
1028
1029	sms_board_led_feedback(client->coredev, SMS_LED_OFF);
1030	sms_board_power(client->coredev, 0);
1031
1032	sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
1033
1034	return 0;
1035}
1036
1037static void smsdvb_release(struct dvb_frontend *fe)
1038{
1039	/* do nothing */
1040}
1041
1042static struct dvb_frontend_ops smsdvb_fe_ops = {
1043	.info = {
1044		.name			= "Siano Mobile Digital MDTV Receiver",
1045		.frequency_min		= 44250000,
1046		.frequency_max		= 867250000,
1047		.frequency_stepsize	= 250000,
1048		.caps = FE_CAN_INVERSION_AUTO |
1049			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1050			FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1051			FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
1052			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
1053			FE_CAN_GUARD_INTERVAL_AUTO |
1054			FE_CAN_RECOVER |
1055			FE_CAN_HIERARCHY_AUTO,
1056	},
1057
1058	.release = smsdvb_release,
1059
1060	.set_frontend = smsdvb_set_frontend,
1061	.get_frontend = smsdvb_get_frontend,
1062	.get_tune_settings = smsdvb_get_tune_settings,
1063
1064	.read_status = smsdvb_read_status,
1065	.read_ber = smsdvb_read_ber,
1066	.read_signal_strength = smsdvb_read_signal_strength,
1067	.read_snr = smsdvb_read_snr,
1068	.read_ucblocks = smsdvb_read_ucblocks,
1069
1070	.init = smsdvb_init,
1071	.sleep = smsdvb_sleep,
1072};
1073
1074static int smsdvb_hotplug(struct smscore_device_t *coredev,
1075			  struct device *device, int arrival)
1076{
1077	struct smsclient_params_t params;
1078	struct smsdvb_client_t *client;
1079	int rc;
1080
1081	/* device removal handled by onremove callback */
1082	if (!arrival)
1083		return 0;
1084	client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
1085	if (!client) {
1086		sms_err("kmalloc() failed");
1087		return -ENOMEM;
1088	}
1089
1090	/* register dvb adapter */
1091	rc = dvb_register_adapter(&client->adapter,
1092				  sms_get_board(
1093					smscore_get_board_id(coredev))->name,
1094				  THIS_MODULE, device, adapter_nr);
1095	if (rc < 0) {
1096		sms_err("dvb_register_adapter() failed %d", rc);
1097		goto adapter_error;
1098	}
1099
1100	/* init dvb demux */
1101	client->demux.dmx.capabilities = DMX_TS_FILTERING;
1102	client->demux.filternum = 32; /* todo: nova ??? */
1103	client->demux.feednum = 32;
1104	client->demux.start_feed = smsdvb_start_feed;
1105	client->demux.stop_feed = smsdvb_stop_feed;
1106
1107	rc = dvb_dmx_init(&client->demux);
1108	if (rc < 0) {
1109		sms_err("dvb_dmx_init failed %d", rc);
1110		goto dvbdmx_error;
1111	}
1112
1113	/* init dmxdev */
1114	client->dmxdev.filternum = 32;
1115	client->dmxdev.demux = &client->demux.dmx;
1116	client->dmxdev.capabilities = 0;
1117
1118	rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
1119	if (rc < 0) {
1120		sms_err("dvb_dmxdev_init failed %d", rc);
1121		goto dmxdev_error;
1122	}
1123
1124	/* init and register frontend */
1125	memcpy(&client->frontend.ops, &smsdvb_fe_ops,
1126	       sizeof(struct dvb_frontend_ops));
1127
1128	switch (smscore_get_device_mode(coredev)) {
1129	case DEVICE_MODE_DVBT:
1130	case DEVICE_MODE_DVBT_BDA:
1131		client->frontend.ops.delsys[0] = SYS_DVBT;
1132		break;
1133	case DEVICE_MODE_ISDBT:
1134	case DEVICE_MODE_ISDBT_BDA:
1135		client->frontend.ops.delsys[0] = SYS_ISDBT;
1136		break;
1137	}
1138
1139	rc = dvb_register_frontend(&client->adapter, &client->frontend);
1140	if (rc < 0) {
1141		sms_err("frontend registration failed %d", rc);
1142		goto frontend_error;
1143	}
1144
1145	params.initial_id = 1;
1146	params.data_type = MSG_SMS_DVBT_BDA_DATA;
1147	params.onresponse_handler = smsdvb_onresponse;
1148	params.onremove_handler = smsdvb_onremove;
1149	params.context = client;
1150
1151	rc = smscore_register_client(coredev, &params, &client->smsclient);
1152	if (rc < 0) {
1153		sms_err("smscore_register_client() failed %d", rc);
1154		goto client_error;
1155	}
1156
1157	client->coredev = coredev;
1158
1159	init_completion(&client->tune_done);
1160	init_completion(&client->stats_done);
1161
1162	kmutex_lock(&g_smsdvb_clientslock);
1163
1164	list_add(&client->entry, &g_smsdvb_clients);
1165
1166	kmutex_unlock(&g_smsdvb_clientslock);
1167
1168	client->event_fe_state = -1;
1169	client->event_unc_state = -1;
1170	sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
1171
1172	sms_info("success");
1173	sms_board_setup(coredev);
1174
1175	if (smsdvb_debugfs_create(client) < 0)
1176		sms_info("failed to create debugfs node");
1177
1178	return 0;
1179
1180client_error:
1181	dvb_unregister_frontend(&client->frontend);
1182
1183frontend_error:
1184	dvb_dmxdev_release(&client->dmxdev);
1185
1186dmxdev_error:
1187	dvb_dmx_release(&client->demux);
1188
1189dvbdmx_error:
1190	dvb_unregister_adapter(&client->adapter);
1191
1192adapter_error:
1193	kfree(client);
1194	return rc;
1195}
1196
1197static int __init smsdvb_module_init(void)
1198{
1199	int rc;
1200
1201	INIT_LIST_HEAD(&g_smsdvb_clients);
1202	kmutex_init(&g_smsdvb_clientslock);
1203
1204	smsdvb_debugfs_register();
1205
1206	rc = smscore_register_hotplug(smsdvb_hotplug);
1207
1208	sms_debug("");
1209
1210	return rc;
1211}
1212
1213static void __exit smsdvb_module_exit(void)
1214{
1215	smscore_unregister_hotplug(smsdvb_hotplug);
1216
1217	kmutex_lock(&g_smsdvb_clientslock);
1218
1219	while (!list_empty(&g_smsdvb_clients))
1220		smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next);
1221
1222	smsdvb_debugfs_unregister();
1223
1224	kmutex_unlock(&g_smsdvb_clientslock);
1225}
1226
1227module_init(smsdvb_module_init);
1228module_exit(smsdvb_module_exit);
1229
1230MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1231MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1232MODULE_LICENSE("GPL");
1233