1 // SPDX-License-Identifier: GPL-2.0+
3 // Copyright(c) 2013 Mauro Carvalho Chehab
5 #include "smscoreapi.h"
7 #include <linux/module.h>
8 #include <linux/slab.h>
9 #include <linux/init.h>
10 #include <linux/debugfs.h>
11 #include <linux/spinlock.h>
12 #include <linux/usb.h>
14 #include <media/dmxdev.h>
15 #include <media/dvbdev.h>
16 #include <media/dvb_demux.h>
17 #include <media/dvb_frontend.h>
21 static struct dentry
*smsdvb_debugfs_usb_root
;
23 struct smsdvb_debugfs
{
27 char stats_data
[PAGE_SIZE
];
31 wait_queue_head_t stats_queue
;
34 static void smsdvb_print_dvb_stats(struct smsdvb_debugfs
*debug_data
,
40 spin_lock(&debug_data
->lock
);
41 if (debug_data
->stats_count
) {
42 spin_unlock(&debug_data
->lock
);
46 buf
= debug_data
->stats_data
;
48 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
49 "is_rf_locked = %d\n", p
->is_rf_locked
);
50 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
51 "is_demod_locked = %d\n", p
->is_demod_locked
);
52 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
53 "is_external_lna_on = %d\n", p
->is_external_lna_on
);
54 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
55 "SNR = %d\n", p
->SNR
);
56 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
57 "ber = %d\n", p
->ber
);
58 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
59 "FIB_CRC = %d\n", p
->FIB_CRC
);
60 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
61 "ts_per = %d\n", p
->ts_per
);
62 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
63 "MFER = %d\n", p
->MFER
);
64 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
65 "RSSI = %d\n", p
->RSSI
);
66 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
67 "in_band_pwr = %d\n", p
->in_band_pwr
);
68 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
69 "carrier_offset = %d\n", p
->carrier_offset
);
70 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
71 "modem_state = %d\n", p
->modem_state
);
72 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
73 "frequency = %d\n", p
->frequency
);
74 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
75 "bandwidth = %d\n", p
->bandwidth
);
76 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
77 "transmission_mode = %d\n", p
->transmission_mode
);
78 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
79 "modem_state = %d\n", p
->modem_state
);
80 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
81 "guard_interval = %d\n", p
->guard_interval
);
82 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
83 "code_rate = %d\n", p
->code_rate
);
84 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
85 "lp_code_rate = %d\n", p
->lp_code_rate
);
86 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
87 "hierarchy = %d\n", p
->hierarchy
);
88 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
89 "constellation = %d\n", p
->constellation
);
90 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
91 "burst_size = %d\n", p
->burst_size
);
92 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
93 "burst_duration = %d\n", p
->burst_duration
);
94 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
95 "burst_cycle_time = %d\n", p
->burst_cycle_time
);
96 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
97 "calc_burst_cycle_time = %d\n",
98 p
->calc_burst_cycle_time
);
99 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
100 "num_of_rows = %d\n", p
->num_of_rows
);
101 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
102 "num_of_padd_cols = %d\n", p
->num_of_padd_cols
);
103 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
104 "num_of_punct_cols = %d\n", p
->num_of_punct_cols
);
105 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
106 "error_ts_packets = %d\n", p
->error_ts_packets
);
107 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
108 "total_ts_packets = %d\n", p
->total_ts_packets
);
109 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
110 "num_of_valid_mpe_tlbs = %d\n", p
->num_of_valid_mpe_tlbs
);
111 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
112 "num_of_invalid_mpe_tlbs = %d\n", p
->num_of_invalid_mpe_tlbs
);
113 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
114 "num_of_corrected_mpe_tlbs = %d\n", p
->num_of_corrected_mpe_tlbs
);
115 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
116 "ber_error_count = %d\n", p
->ber_error_count
);
117 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
118 "ber_bit_count = %d\n", p
->ber_bit_count
);
119 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
120 "sms_to_host_tx_errors = %d\n", p
->sms_to_host_tx_errors
);
121 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
122 "pre_ber = %d\n", p
->pre_ber
);
123 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
124 "cell_id = %d\n", p
->cell_id
);
125 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
126 "dvbh_srv_ind_hp = %d\n", p
->dvbh_srv_ind_hp
);
127 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
128 "dvbh_srv_ind_lp = %d\n", p
->dvbh_srv_ind_lp
);
129 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
130 "num_mpe_received = %d\n", p
->num_mpe_received
);
132 debug_data
->stats_count
= n
;
133 spin_unlock(&debug_data
->lock
);
134 wake_up(&debug_data
->stats_queue
);
137 static void smsdvb_print_isdb_stats(struct smsdvb_debugfs
*debug_data
,
138 struct sms_isdbt_stats
*p
)
143 spin_lock(&debug_data
->lock
);
144 if (debug_data
->stats_count
) {
145 spin_unlock(&debug_data
->lock
);
149 buf
= debug_data
->stats_data
;
151 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
152 "statistics_type = %d\t", p
->statistics_type
);
153 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
154 "full_size = %d\n", p
->full_size
);
156 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
157 "is_rf_locked = %d\t\t", p
->is_rf_locked
);
158 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
159 "is_demod_locked = %d\t", p
->is_demod_locked
);
160 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
161 "is_external_lna_on = %d\n", p
->is_external_lna_on
);
162 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
163 "SNR = %d dB\t\t", p
->SNR
);
164 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
165 "RSSI = %d dBm\t\t", p
->RSSI
);
166 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
167 "in_band_pwr = %d dBm\n", p
->in_band_pwr
);
168 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
169 "carrier_offset = %d\t", p
->carrier_offset
);
170 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
171 "bandwidth = %d\t\t", p
->bandwidth
);
172 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
173 "frequency = %d Hz\n", p
->frequency
);
174 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
175 "transmission_mode = %d\t", p
->transmission_mode
);
176 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
177 "modem_state = %d\t\t", p
->modem_state
);
178 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
179 "guard_interval = %d\n", p
->guard_interval
);
180 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
181 "system_type = %d\t\t", p
->system_type
);
182 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
183 "partial_reception = %d\t", p
->partial_reception
);
184 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
185 "num_of_layers = %d\n", p
->num_of_layers
);
186 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
187 "sms_to_host_tx_errors = %d\n", p
->sms_to_host_tx_errors
);
189 for (i
= 0; i
< 3; i
++) {
190 if (p
->layer_info
[i
].number_of_segments
< 1 ||
191 p
->layer_info
[i
].number_of_segments
> 13)
194 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\nLayer %d\n", i
);
195 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tcode_rate = %d\t",
196 p
->layer_info
[i
].code_rate
);
197 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "constellation = %d\n",
198 p
->layer_info
[i
].constellation
);
199 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tber = %-5d\t",
200 p
->layer_info
[i
].ber
);
201 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tber_error_count = %-5d\t",
202 p
->layer_info
[i
].ber_error_count
);
203 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "ber_bit_count = %-5d\n",
204 p
->layer_info
[i
].ber_bit_count
);
205 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tpre_ber = %-5d\t",
206 p
->layer_info
[i
].pre_ber
);
207 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tts_per = %-5d\n",
208 p
->layer_info
[i
].ts_per
);
209 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\terror_ts_packets = %-5d\t",
210 p
->layer_info
[i
].error_ts_packets
);
211 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "total_ts_packets = %-5d\t",
212 p
->layer_info
[i
].total_ts_packets
);
213 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "ti_ldepth_i = %d\n",
214 p
->layer_info
[i
].ti_ldepth_i
);
215 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
216 "\tnumber_of_segments = %d\t",
217 p
->layer_info
[i
].number_of_segments
);
218 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "tmcc_errors = %d\n",
219 p
->layer_info
[i
].tmcc_errors
);
222 debug_data
->stats_count
= n
;
223 spin_unlock(&debug_data
->lock
);
224 wake_up(&debug_data
->stats_queue
);
227 static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs
*debug_data
,
228 struct sms_isdbt_stats_ex
*p
)
233 spin_lock(&debug_data
->lock
);
234 if (debug_data
->stats_count
) {
235 spin_unlock(&debug_data
->lock
);
239 buf
= debug_data
->stats_data
;
241 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
242 "statistics_type = %d\t", p
->statistics_type
);
243 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
244 "full_size = %d\n", p
->full_size
);
246 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
247 "is_rf_locked = %d\t\t", p
->is_rf_locked
);
248 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
249 "is_demod_locked = %d\t", p
->is_demod_locked
);
250 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
251 "is_external_lna_on = %d\n", p
->is_external_lna_on
);
252 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
253 "SNR = %d dB\t\t", p
->SNR
);
254 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
255 "RSSI = %d dBm\t\t", p
->RSSI
);
256 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
257 "in_band_pwr = %d dBm\n", p
->in_band_pwr
);
258 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
259 "carrier_offset = %d\t", p
->carrier_offset
);
260 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
261 "bandwidth = %d\t\t", p
->bandwidth
);
262 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
263 "frequency = %d Hz\n", p
->frequency
);
264 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
265 "transmission_mode = %d\t", p
->transmission_mode
);
266 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
267 "modem_state = %d\t\t", p
->modem_state
);
268 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
269 "guard_interval = %d\n", p
->guard_interval
);
270 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
271 "system_type = %d\t\t", p
->system_type
);
272 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
273 "partial_reception = %d\t", p
->partial_reception
);
274 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
275 "num_of_layers = %d\n", p
->num_of_layers
);
276 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "segment_number = %d\t",
278 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "tune_bw = %d\n",
281 for (i
= 0; i
< 3; i
++) {
282 if (p
->layer_info
[i
].number_of_segments
< 1 ||
283 p
->layer_info
[i
].number_of_segments
> 13)
286 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\nLayer %d\n", i
);
287 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tcode_rate = %d\t",
288 p
->layer_info
[i
].code_rate
);
289 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "constellation = %d\n",
290 p
->layer_info
[i
].constellation
);
291 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tber = %-5d\t",
292 p
->layer_info
[i
].ber
);
293 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tber_error_count = %-5d\t",
294 p
->layer_info
[i
].ber_error_count
);
295 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "ber_bit_count = %-5d\n",
296 p
->layer_info
[i
].ber_bit_count
);
297 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tpre_ber = %-5d\t",
298 p
->layer_info
[i
].pre_ber
);
299 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\tts_per = %-5d\n",
300 p
->layer_info
[i
].ts_per
);
301 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "\terror_ts_packets = %-5d\t",
302 p
->layer_info
[i
].error_ts_packets
);
303 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "total_ts_packets = %-5d\t",
304 p
->layer_info
[i
].total_ts_packets
);
305 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "ti_ldepth_i = %d\n",
306 p
->layer_info
[i
].ti_ldepth_i
);
307 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
,
308 "\tnumber_of_segments = %d\t",
309 p
->layer_info
[i
].number_of_segments
);
310 n
+= snprintf(&buf
[n
], PAGE_SIZE
- n
, "tmcc_errors = %d\n",
311 p
->layer_info
[i
].tmcc_errors
);
315 debug_data
->stats_count
= n
;
316 spin_unlock(&debug_data
->lock
);
318 wake_up(&debug_data
->stats_queue
);
321 static int smsdvb_stats_open(struct inode
*inode
, struct file
*file
)
323 struct smsdvb_client_t
*client
= inode
->i_private
;
324 struct smsdvb_debugfs
*debug_data
= client
->debug_data
;
326 kref_get(&debug_data
->refcount
);
328 spin_lock(&debug_data
->lock
);
329 debug_data
->stats_count
= 0;
330 debug_data
->stats_was_read
= false;
331 spin_unlock(&debug_data
->lock
);
333 file
->private_data
= debug_data
;
338 static void smsdvb_debugfs_data_release(struct kref
*ref
)
340 struct smsdvb_debugfs
*debug_data
;
342 debug_data
= container_of(ref
, struct smsdvb_debugfs
, refcount
);
346 static int smsdvb_stats_wait_read(struct smsdvb_debugfs
*debug_data
)
350 spin_lock(&debug_data
->lock
);
352 if (debug_data
->stats_was_read
)
355 rc
= debug_data
->stats_count
;
358 spin_unlock(&debug_data
->lock
);
362 static __poll_t
smsdvb_stats_poll(struct file
*file
, poll_table
*wait
)
364 struct smsdvb_debugfs
*debug_data
= file
->private_data
;
367 kref_get(&debug_data
->refcount
);
369 poll_wait(file
, &debug_data
->stats_queue
, wait
);
371 rc
= smsdvb_stats_wait_read(debug_data
);
372 kref_put(&debug_data
->refcount
, smsdvb_debugfs_data_release
);
374 return rc
> 0 ? EPOLLIN
| EPOLLRDNORM
: 0;
377 static ssize_t
smsdvb_stats_read(struct file
*file
, char __user
*user_buf
,
378 size_t nbytes
, loff_t
*ppos
)
381 struct smsdvb_debugfs
*debug_data
= file
->private_data
;
383 kref_get(&debug_data
->refcount
);
385 if (file
->f_flags
& O_NONBLOCK
) {
386 rc
= smsdvb_stats_wait_read(debug_data
);
392 rc
= wait_event_interruptible(debug_data
->stats_queue
,
393 smsdvb_stats_wait_read(debug_data
));
398 if (debug_data
->stats_was_read
) {
403 len
= debug_data
->stats_count
- *ppos
;
405 rc
= simple_read_from_buffer(user_buf
, nbytes
, ppos
,
406 debug_data
->stats_data
, len
);
410 if (*ppos
>= debug_data
->stats_count
) {
411 spin_lock(&debug_data
->lock
);
412 debug_data
->stats_was_read
= true;
413 spin_unlock(&debug_data
->lock
);
416 kref_put(&debug_data
->refcount
, smsdvb_debugfs_data_release
);
420 static int smsdvb_stats_release(struct inode
*inode
, struct file
*file
)
422 struct smsdvb_debugfs
*debug_data
= file
->private_data
;
424 spin_lock(&debug_data
->lock
);
425 debug_data
->stats_was_read
= true; /* return EOF to read() */
426 spin_unlock(&debug_data
->lock
);
427 wake_up_interruptible_sync(&debug_data
->stats_queue
);
429 kref_put(&debug_data
->refcount
, smsdvb_debugfs_data_release
);
430 file
->private_data
= NULL
;
435 static const struct file_operations debugfs_stats_ops
= {
436 .open
= smsdvb_stats_open
,
437 .poll
= smsdvb_stats_poll
,
438 .read
= smsdvb_stats_read
,
439 .release
= smsdvb_stats_release
,
440 .llseek
= generic_file_llseek
,
444 * Functions used by smsdvb, in order to create the interfaces
447 int smsdvb_debugfs_create(struct smsdvb_client_t
*client
)
449 struct smscore_device_t
*coredev
= client
->coredev
;
451 struct smsdvb_debugfs
*debug_data
;
453 if (!smsdvb_debugfs_usb_root
|| !coredev
->is_usb_device
)
456 client
->debugfs
= debugfs_create_dir(coredev
->devpath
,
457 smsdvb_debugfs_usb_root
);
458 if (IS_ERR_OR_NULL(client
->debugfs
)) {
459 pr_info("Unable to create debugfs %s directory.\n",
464 d
= debugfs_create_file("stats", S_IRUGO
| S_IWUSR
, client
->debugfs
,
465 client
, &debugfs_stats_ops
);
467 debugfs_remove(client
->debugfs
);
471 debug_data
= kzalloc(sizeof(*client
->debug_data
), GFP_KERNEL
);
475 client
->debug_data
= debug_data
;
476 client
->prt_dvb_stats
= smsdvb_print_dvb_stats
;
477 client
->prt_isdb_stats
= smsdvb_print_isdb_stats
;
478 client
->prt_isdb_stats_ex
= smsdvb_print_isdb_stats_ex
;
480 init_waitqueue_head(&debug_data
->stats_queue
);
481 spin_lock_init(&debug_data
->lock
);
482 kref_init(&debug_data
->refcount
);
487 void smsdvb_debugfs_release(struct smsdvb_client_t
*client
)
489 if (!client
->debugfs
)
492 client
->prt_dvb_stats
= NULL
;
493 client
->prt_isdb_stats
= NULL
;
494 client
->prt_isdb_stats_ex
= NULL
;
496 debugfs_remove_recursive(client
->debugfs
);
497 kref_put(&client
->debug_data
->refcount
, smsdvb_debugfs_data_release
);
499 client
->debug_data
= NULL
;
500 client
->debugfs
= NULL
;
503 void smsdvb_debugfs_register(void)
508 * FIXME: This was written to debug Siano USB devices. So, it creates
509 * the debugfs node under <debugfs>/usb.
510 * A similar logic would be needed for Siano sdio devices, but, in that
511 * case, usb_debug_root is not a good choice.
513 * Perhaps the right fix here would be to create another sysfs root
514 * node for sdio-based boards, but this may need some logic at sdio
517 d
= debugfs_create_dir("smsdvb", usb_debug_root
);
518 if (IS_ERR_OR_NULL(d
)) {
519 pr_err("Couldn't create sysfs node for smsdvb\n");
522 smsdvb_debugfs_usb_root
= d
;
525 void smsdvb_debugfs_unregister(void)
527 if (!smsdvb_debugfs_usb_root
)
529 debugfs_remove_recursive(smsdvb_debugfs_usb_root
);
530 smsdvb_debugfs_usb_root
= NULL
;