Commit | Line | Data |
---|---|---|
503efe5c MCC |
1 | /*********************************************************************** |
2 | * | |
37e59f87 | 3 | * Copyright(c) 2013 Mauro Carvalho Chehab |
503efe5c MCC |
4 | * |
5 | * This program is free software: you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation, either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | ||
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | * | |
18 | ***********************************************************************/ | |
19 | ||
5e022d1a | 20 | #include "smscoreapi.h" |
503efe5c MCC |
21 | |
22 | #include <linux/module.h> | |
23 | #include <linux/slab.h> | |
24 | #include <linux/init.h> | |
25 | #include <linux/debugfs.h> | |
26 | #include <linux/spinlock.h> | |
27 | #include <linux/usb.h> | |
28 | ||
29 | #include "dmxdev.h" | |
30 | #include "dvbdev.h" | |
31 | #include "dvb_demux.h" | |
32 | #include "dvb_frontend.h" | |
33 | ||
503efe5c MCC |
34 | #include "smsdvb.h" |
35 | ||
36 | static struct dentry *smsdvb_debugfs_usb_root; | |
37 | ||
38 | struct smsdvb_debugfs { | |
39 | struct kref refcount; | |
40 | spinlock_t lock; | |
41 | ||
42 | char stats_data[PAGE_SIZE]; | |
43 | unsigned stats_count; | |
44 | bool stats_was_read; | |
45 | ||
46 | wait_queue_head_t stats_queue; | |
47 | }; | |
48 | ||
2bf0f93e | 49 | static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, |
cf0e9cfc | 50 | struct sms_stats *p) |
503efe5c MCC |
51 | { |
52 | int n = 0; | |
53 | char *buf; | |
54 | ||
55 | spin_lock(&debug_data->lock); | |
56 | if (debug_data->stats_count) { | |
57 | spin_unlock(&debug_data->lock); | |
58 | return; | |
59 | } | |
60 | ||
61 | buf = debug_data->stats_data; | |
62 | ||
63 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
dfef84fc | 64 | "is_rf_locked = %d\n", p->is_rf_locked); |
503efe5c | 65 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 66 | "is_demod_locked = %d\n", p->is_demod_locked); |
503efe5c | 67 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 68 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
503efe5c MCC |
69 | n += snprintf(&buf[n], PAGE_SIZE - n, |
70 | "SNR = %d\n", p->SNR); | |
71 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
28a59df4 | 72 | "ber = %d\n", p->ber); |
503efe5c MCC |
73 | n += snprintf(&buf[n], PAGE_SIZE - n, |
74 | "FIB_CRC = %d\n", p->FIB_CRC); | |
75 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
28a59df4 | 76 | "ts_per = %d\n", p->ts_per); |
503efe5c MCC |
77 | n += snprintf(&buf[n], PAGE_SIZE - n, |
78 | "MFER = %d\n", p->MFER); | |
79 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
80 | "RSSI = %d\n", p->RSSI); | |
81 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
dfef84fc | 82 | "in_band_pwr = %d\n", p->in_band_pwr); |
503efe5c | 83 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 84 | "carrier_offset = %d\n", p->carrier_offset); |
503efe5c | 85 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 86 | "modem_state = %d\n", p->modem_state); |
503efe5c | 87 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 88 | "frequency = %d\n", p->frequency); |
503efe5c | 89 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 90 | "bandwidth = %d\n", p->bandwidth); |
503efe5c | 91 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 92 | "transmission_mode = %d\n", p->transmission_mode); |
503efe5c | 93 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 94 | "modem_state = %d\n", p->modem_state); |
503efe5c | 95 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 96 | "guard_interval = %d\n", p->guard_interval); |
503efe5c | 97 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 98 | "code_rate = %d\n", p->code_rate); |
503efe5c | 99 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 100 | "lp_code_rate = %d\n", p->lp_code_rate); |
503efe5c | 101 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 102 | "hierarchy = %d\n", p->hierarchy); |
503efe5c | 103 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 104 | "constellation = %d\n", p->constellation); |
503efe5c | 105 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 106 | "burst_size = %d\n", p->burst_size); |
503efe5c | 107 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 108 | "burst_duration = %d\n", p->burst_duration); |
503efe5c | 109 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 110 | "burst_cycle_time = %d\n", p->burst_cycle_time); |
503efe5c | 111 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 112 | "calc_burst_cycle_time = %d\n", |
05ad412a | 113 | p->calc_burst_cycle_time); |
503efe5c | 114 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 115 | "num_of_rows = %d\n", p->num_of_rows); |
503efe5c | 116 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 117 | "num_of_padd_cols = %d\n", p->num_of_padd_cols); |
503efe5c | 118 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 119 | "num_of_punct_cols = %d\n", p->num_of_punct_cols); |
503efe5c | 120 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 121 | "error_ts_packets = %d\n", p->error_ts_packets); |
503efe5c | 122 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 123 | "total_ts_packets = %d\n", p->total_ts_packets); |
503efe5c | 124 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 125 | "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs); |
503efe5c | 126 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 127 | "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs); |
503efe5c | 128 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 129 | "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs); |
503efe5c | 130 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 131 | "ber_error_count = %d\n", p->ber_error_count); |
503efe5c | 132 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 133 | "ber_bit_count = %d\n", p->ber_bit_count); |
503efe5c | 134 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 135 | "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); |
503efe5c | 136 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 137 | "pre_ber = %d\n", p->pre_ber); |
503efe5c | 138 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 139 | "cell_id = %d\n", p->cell_id); |
503efe5c | 140 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 141 | "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp); |
503efe5c | 142 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 143 | "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp); |
503efe5c | 144 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 145 | "num_mpe_received = %d\n", p->num_mpe_received); |
503efe5c MCC |
146 | |
147 | debug_data->stats_count = n; | |
148 | spin_unlock(&debug_data->lock); | |
149 | wake_up(&debug_data->stats_queue); | |
150 | } | |
151 | ||
2bf0f93e | 152 | static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, |
cf0e9cfc | 153 | struct sms_isdbt_stats *p) |
503efe5c MCC |
154 | { |
155 | int i, n = 0; | |
156 | char *buf; | |
157 | ||
158 | spin_lock(&debug_data->lock); | |
159 | if (debug_data->stats_count) { | |
160 | spin_unlock(&debug_data->lock); | |
161 | return; | |
162 | } | |
163 | ||
164 | buf = debug_data->stats_data; | |
165 | ||
4cce1f4e | 166 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 167 | "statistics_type = %d\t", p->statistics_type); |
4cce1f4e | 168 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 169 | "full_size = %d\n", p->full_size); |
4cce1f4e | 170 | |
503efe5c | 171 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 172 | "is_rf_locked = %d\t\t", p->is_rf_locked); |
503efe5c | 173 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 174 | "is_demod_locked = %d\t", p->is_demod_locked); |
503efe5c | 175 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 176 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
503efe5c MCC |
177 | n += snprintf(&buf[n], PAGE_SIZE - n, |
178 | "SNR = %d dB\t\t", p->SNR); | |
179 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
180 | "RSSI = %d dBm\t\t", p->RSSI); | |
181 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
dfef84fc | 182 | "in_band_pwr = %d dBm\n", p->in_band_pwr); |
503efe5c | 183 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 184 | "carrier_offset = %d\t", p->carrier_offset); |
503efe5c | 185 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 186 | "bandwidth = %d\t\t", p->bandwidth); |
503efe5c | 187 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 188 | "frequency = %d Hz\n", p->frequency); |
503efe5c | 189 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 190 | "transmission_mode = %d\t", p->transmission_mode); |
503efe5c | 191 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 192 | "modem_state = %d\t\t", p->modem_state); |
503efe5c | 193 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 194 | "guard_interval = %d\n", p->guard_interval); |
503efe5c | 195 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 196 | "system_type = %d\t\t", p->system_type); |
503efe5c | 197 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 198 | "partial_reception = %d\t", p->partial_reception); |
503efe5c | 199 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 200 | "num_of_layers = %d\n", p->num_of_layers); |
503efe5c | 201 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 202 | "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); |
503efe5c MCC |
203 | |
204 | for (i = 0; i < 3; i++) { | |
28a59df4 MCC |
205 | if (p->layer_info[i].number_of_segments < 1 || |
206 | p->layer_info[i].number_of_segments > 13) | |
503efe5c MCC |
207 | continue; |
208 | ||
209 | n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
dfef84fc | 210 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", |
28a59df4 | 211 | p->layer_info[i].code_rate); |
dfef84fc | 212 | n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", |
28a59df4 MCC |
213 | p->layer_info[i].constellation); |
214 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
215 | p->layer_info[i].ber); | |
dfef84fc | 216 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", |
28a59df4 | 217 | p->layer_info[i].ber_error_count); |
dfef84fc | 218 | n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", |
28a59df4 | 219 | p->layer_info[i].ber_bit_count); |
dfef84fc | 220 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", |
28a59df4 MCC |
221 | p->layer_info[i].pre_ber); |
222 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", | |
223 | p->layer_info[i].ts_per); | |
dfef84fc | 224 | n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", |
28a59df4 | 225 | p->layer_info[i].error_ts_packets); |
dfef84fc | 226 | n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", |
28a59df4 | 227 | p->layer_info[i].total_ts_packets); |
dfef84fc | 228 | n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", |
28a59df4 | 229 | p->layer_info[i].ti_ldepth_i); |
503efe5c | 230 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 231 | "\tnumber_of_segments = %d\t", |
28a59df4 | 232 | p->layer_info[i].number_of_segments); |
dfef84fc | 233 | n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", |
28a59df4 | 234 | p->layer_info[i].tmcc_errors); |
503efe5c MCC |
235 | } |
236 | ||
237 | debug_data->stats_count = n; | |
238 | spin_unlock(&debug_data->lock); | |
239 | wake_up(&debug_data->stats_queue); | |
240 | } | |
241 | ||
2bf0f93e | 242 | static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, |
cf0e9cfc | 243 | struct sms_isdbt_stats_ex *p) |
503efe5c MCC |
244 | { |
245 | int i, n = 0; | |
246 | char *buf; | |
247 | ||
248 | spin_lock(&debug_data->lock); | |
249 | if (debug_data->stats_count) { | |
250 | spin_unlock(&debug_data->lock); | |
251 | return; | |
252 | } | |
253 | ||
254 | buf = debug_data->stats_data; | |
255 | ||
4cce1f4e | 256 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 257 | "statistics_type = %d\t", p->statistics_type); |
4cce1f4e | 258 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 259 | "full_size = %d\n", p->full_size); |
4cce1f4e | 260 | |
503efe5c | 261 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 262 | "is_rf_locked = %d\t\t", p->is_rf_locked); |
503efe5c | 263 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 264 | "is_demod_locked = %d\t", p->is_demod_locked); |
503efe5c | 265 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 266 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
503efe5c MCC |
267 | n += snprintf(&buf[n], PAGE_SIZE - n, |
268 | "SNR = %d dB\t\t", p->SNR); | |
269 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
270 | "RSSI = %d dBm\t\t", p->RSSI); | |
271 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
dfef84fc | 272 | "in_band_pwr = %d dBm\n", p->in_band_pwr); |
503efe5c | 273 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 274 | "carrier_offset = %d\t", p->carrier_offset); |
503efe5c | 275 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 276 | "bandwidth = %d\t\t", p->bandwidth); |
503efe5c | 277 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 278 | "frequency = %d Hz\n", p->frequency); |
503efe5c | 279 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 280 | "transmission_mode = %d\t", p->transmission_mode); |
503efe5c | 281 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 282 | "modem_state = %d\t\t", p->modem_state); |
503efe5c | 283 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 284 | "guard_interval = %d\n", p->guard_interval); |
503efe5c | 285 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 286 | "system_type = %d\t\t", p->system_type); |
503efe5c | 287 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 288 | "partial_reception = %d\t", p->partial_reception); |
503efe5c | 289 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc MCC |
290 | "num_of_layers = %d\n", p->num_of_layers); |
291 | n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t", | |
292 | p->segment_number); | |
293 | n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n", | |
294 | p->tune_bw); | |
503efe5c MCC |
295 | |
296 | for (i = 0; i < 3; i++) { | |
28a59df4 MCC |
297 | if (p->layer_info[i].number_of_segments < 1 || |
298 | p->layer_info[i].number_of_segments > 13) | |
503efe5c MCC |
299 | continue; |
300 | ||
301 | n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
dfef84fc | 302 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", |
28a59df4 | 303 | p->layer_info[i].code_rate); |
dfef84fc | 304 | n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", |
28a59df4 MCC |
305 | p->layer_info[i].constellation); |
306 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
307 | p->layer_info[i].ber); | |
dfef84fc | 308 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", |
28a59df4 | 309 | p->layer_info[i].ber_error_count); |
dfef84fc | 310 | n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", |
28a59df4 | 311 | p->layer_info[i].ber_bit_count); |
dfef84fc | 312 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", |
28a59df4 MCC |
313 | p->layer_info[i].pre_ber); |
314 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", | |
315 | p->layer_info[i].ts_per); | |
dfef84fc | 316 | n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", |
28a59df4 | 317 | p->layer_info[i].error_ts_packets); |
dfef84fc | 318 | n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", |
28a59df4 | 319 | p->layer_info[i].total_ts_packets); |
dfef84fc | 320 | n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", |
28a59df4 | 321 | p->layer_info[i].ti_ldepth_i); |
503efe5c | 322 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 323 | "\tnumber_of_segments = %d\t", |
28a59df4 | 324 | p->layer_info[i].number_of_segments); |
dfef84fc | 325 | n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", |
28a59df4 | 326 | p->layer_info[i].tmcc_errors); |
503efe5c MCC |
327 | } |
328 | ||
329 | ||
330 | debug_data->stats_count = n; | |
331 | spin_unlock(&debug_data->lock); | |
332 | ||
333 | wake_up(&debug_data->stats_queue); | |
334 | } | |
335 | ||
336 | static int smsdvb_stats_open(struct inode *inode, struct file *file) | |
337 | { | |
338 | struct smsdvb_client_t *client = inode->i_private; | |
339 | struct smsdvb_debugfs *debug_data = client->debug_data; | |
340 | ||
341 | kref_get(&debug_data->refcount); | |
342 | ||
343 | spin_lock(&debug_data->lock); | |
344 | debug_data->stats_count = 0; | |
345 | debug_data->stats_was_read = false; | |
346 | spin_unlock(&debug_data->lock); | |
347 | ||
348 | file->private_data = debug_data; | |
349 | ||
350 | return 0; | |
351 | } | |
352 | ||
6a28bd94 MCC |
353 | static void smsdvb_debugfs_data_release(struct kref *ref) |
354 | { | |
355 | struct smsdvb_debugfs *debug_data; | |
356 | ||
357 | debug_data = container_of(ref, struct smsdvb_debugfs, refcount); | |
358 | kfree(debug_data); | |
359 | } | |
360 | ||
503efe5c MCC |
361 | static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data) |
362 | { | |
363 | int rc = 1; | |
364 | ||
365 | spin_lock(&debug_data->lock); | |
366 | ||
367 | if (debug_data->stats_was_read) | |
368 | goto exit; | |
369 | ||
370 | rc = debug_data->stats_count; | |
371 | ||
372 | exit: | |
373 | spin_unlock(&debug_data->lock); | |
374 | return rc; | |
375 | } | |
376 | ||
6a28bd94 | 377 | static unsigned int smsdvb_stats_poll(struct file *file, poll_table *wait) |
503efe5c | 378 | { |
503efe5c | 379 | struct smsdvb_debugfs *debug_data = file->private_data; |
6a28bd94 | 380 | int rc; |
503efe5c | 381 | |
6a28bd94 | 382 | kref_get(&debug_data->refcount); |
503efe5c | 383 | |
6a28bd94 MCC |
384 | poll_wait(file, &debug_data->stats_queue, wait); |
385 | ||
386 | rc = smsdvb_stats_wait_read(debug_data); | |
387 | if (rc > 0) | |
388 | rc = POLLIN | POLLRDNORM; | |
389 | ||
390 | kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); | |
503efe5c MCC |
391 | |
392 | return rc; | |
393 | } | |
394 | ||
6a28bd94 MCC |
395 | static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, |
396 | size_t nbytes, loff_t *ppos) | |
503efe5c | 397 | { |
6a28bd94 MCC |
398 | int rc = 0, len; |
399 | struct smsdvb_debugfs *debug_data = file->private_data; | |
503efe5c | 400 | |
6a28bd94 MCC |
401 | kref_get(&debug_data->refcount); |
402 | ||
403 | if (file->f_flags & O_NONBLOCK) { | |
404 | rc = smsdvb_stats_wait_read(debug_data); | |
405 | if (!rc) { | |
406 | rc = -EWOULDBLOCK; | |
407 | goto ret; | |
408 | } | |
409 | } else { | |
410 | rc = wait_event_interruptible(debug_data->stats_queue, | |
411 | smsdvb_stats_wait_read(debug_data)); | |
412 | if (rc < 0) | |
413 | goto ret; | |
414 | } | |
415 | ||
416 | if (debug_data->stats_was_read) { | |
417 | rc = 0; /* EOF */ | |
418 | goto ret; | |
419 | } | |
420 | ||
421 | len = debug_data->stats_count - *ppos; | |
422 | if (len >= 0) | |
423 | rc = simple_read_from_buffer(user_buf, nbytes, ppos, | |
424 | debug_data->stats_data, len); | |
425 | else | |
426 | rc = 0; | |
427 | ||
428 | if (*ppos >= debug_data->stats_count) { | |
429 | spin_lock(&debug_data->lock); | |
430 | debug_data->stats_was_read = true; | |
431 | spin_unlock(&debug_data->lock); | |
432 | } | |
433 | ret: | |
434 | kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); | |
435 | return rc; | |
503efe5c MCC |
436 | } |
437 | ||
438 | static int smsdvb_stats_release(struct inode *inode, struct file *file) | |
439 | { | |
440 | struct smsdvb_debugfs *debug_data = file->private_data; | |
441 | ||
442 | spin_lock(&debug_data->lock); | |
6a28bd94 | 443 | debug_data->stats_was_read = true; /* return EOF to read() */ |
503efe5c MCC |
444 | spin_unlock(&debug_data->lock); |
445 | wake_up_interruptible_sync(&debug_data->stats_queue); | |
446 | ||
447 | kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); | |
448 | file->private_data = NULL; | |
449 | ||
450 | return 0; | |
451 | } | |
452 | ||
453 | static const struct file_operations debugfs_stats_ops = { | |
454 | .open = smsdvb_stats_open, | |
6a28bd94 | 455 | .poll = smsdvb_stats_poll, |
503efe5c MCC |
456 | .read = smsdvb_stats_read, |
457 | .release = smsdvb_stats_release, | |
458 | .llseek = generic_file_llseek, | |
459 | }; | |
460 | ||
461 | /* | |
462 | * Functions used by smsdvb, in order to create the interfaces | |
463 | */ | |
464 | ||
465 | int smsdvb_debugfs_create(struct smsdvb_client_t *client) | |
466 | { | |
467 | struct smscore_device_t *coredev = client->coredev; | |
468 | struct dentry *d; | |
469 | struct smsdvb_debugfs *debug_data; | |
470 | ||
471 | if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device) | |
472 | return -ENODEV; | |
473 | ||
474 | client->debugfs = debugfs_create_dir(coredev->devpath, | |
475 | smsdvb_debugfs_usb_root); | |
476 | if (IS_ERR_OR_NULL(client->debugfs)) { | |
477 | pr_info("Unable to create debugfs %s directory.\n", | |
478 | coredev->devpath); | |
479 | return -ENODEV; | |
480 | } | |
481 | ||
482 | d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, | |
483 | client, &debugfs_stats_ops); | |
484 | if (!d) { | |
485 | debugfs_remove(client->debugfs); | |
486 | return -ENOMEM; | |
487 | } | |
488 | ||
489 | debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL); | |
490 | if (!debug_data) | |
491 | return -ENOMEM; | |
492 | ||
493 | client->debug_data = debug_data; | |
494 | client->prt_dvb_stats = smsdvb_print_dvb_stats; | |
495 | client->prt_isdb_stats = smsdvb_print_isdb_stats; | |
496 | client->prt_isdb_stats_ex = smsdvb_print_isdb_stats_ex; | |
497 | ||
498 | init_waitqueue_head(&debug_data->stats_queue); | |
499 | spin_lock_init(&debug_data->lock); | |
500 | kref_init(&debug_data->refcount); | |
501 | ||
502 | return 0; | |
503 | } | |
504 | ||
505 | void smsdvb_debugfs_release(struct smsdvb_client_t *client) | |
506 | { | |
507 | if (!client->debugfs) | |
508 | return; | |
509 | ||
503efe5c MCC |
510 | client->prt_dvb_stats = NULL; |
511 | client->prt_isdb_stats = NULL; | |
512 | client->prt_isdb_stats_ex = NULL; | |
513 | ||
514 | debugfs_remove_recursive(client->debugfs); | |
515 | kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release); | |
516 | ||
517 | client->debug_data = NULL; | |
518 | client->debugfs = NULL; | |
519 | } | |
520 | ||
521 | int smsdvb_debugfs_register(void) | |
522 | { | |
523 | struct dentry *d; | |
524 | ||
525 | /* | |
526 | * FIXME: This was written to debug Siano USB devices. So, it creates | |
527 | * the debugfs node under <debugfs>/usb. | |
528 | * A similar logic would be needed for Siano sdio devices, but, in that | |
529 | * case, usb_debug_root is not a good choice. | |
530 | * | |
531 | * Perhaps the right fix here would be to create another sysfs root | |
532 | * node for sdio-based boards, but this may need some logic at sdio | |
533 | * subsystem. | |
534 | */ | |
535 | d = debugfs_create_dir("smsdvb", usb_debug_root); | |
536 | if (IS_ERR_OR_NULL(d)) { | |
5ed0a2c7 | 537 | pr_err("Couldn't create sysfs node for smsdvb\n"); |
503efe5c MCC |
538 | return PTR_ERR(d); |
539 | } else { | |
540 | smsdvb_debugfs_usb_root = d; | |
541 | } | |
542 | return 0; | |
543 | } | |
544 | ||
545 | void smsdvb_debugfs_unregister(void) | |
546 | { | |
05ad412a | 547 | debugfs_remove_recursive(smsdvb_debugfs_usb_root); |
503efe5c MCC |
548 | smsdvb_debugfs_usb_root = NULL; |
549 | } |