]>
Commit | Line | Data |
---|---|---|
1e6f57b2 MCC |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // | |
3 | // Copyright(c) 2013 Mauro Carvalho Chehab | |
503efe5c | 4 | |
5e022d1a | 5 | #include "smscoreapi.h" |
503efe5c MCC |
6 | |
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> | |
13 | ||
fada1935 MCC |
14 | #include <media/dmxdev.h> |
15 | #include <media/dvbdev.h> | |
16 | #include <media/dvb_demux.h> | |
17 | #include <media/dvb_frontend.h> | |
503efe5c | 18 | |
503efe5c MCC |
19 | #include "smsdvb.h" |
20 | ||
21 | static struct dentry *smsdvb_debugfs_usb_root; | |
22 | ||
23 | struct smsdvb_debugfs { | |
24 | struct kref refcount; | |
25 | spinlock_t lock; | |
26 | ||
27 | char stats_data[PAGE_SIZE]; | |
28 | unsigned stats_count; | |
29 | bool stats_was_read; | |
30 | ||
31 | wait_queue_head_t stats_queue; | |
32 | }; | |
33 | ||
2bf0f93e | 34 | static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, |
cf0e9cfc | 35 | struct sms_stats *p) |
503efe5c MCC |
36 | { |
37 | int n = 0; | |
38 | char *buf; | |
39 | ||
40 | spin_lock(&debug_data->lock); | |
41 | if (debug_data->stats_count) { | |
42 | spin_unlock(&debug_data->lock); | |
43 | return; | |
44 | } | |
45 | ||
46 | buf = debug_data->stats_data; | |
47 | ||
48 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
dfef84fc | 49 | "is_rf_locked = %d\n", p->is_rf_locked); |
503efe5c | 50 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 51 | "is_demod_locked = %d\n", p->is_demod_locked); |
503efe5c | 52 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 53 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
503efe5c MCC |
54 | n += snprintf(&buf[n], PAGE_SIZE - n, |
55 | "SNR = %d\n", p->SNR); | |
56 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
28a59df4 | 57 | "ber = %d\n", p->ber); |
503efe5c MCC |
58 | n += snprintf(&buf[n], PAGE_SIZE - n, |
59 | "FIB_CRC = %d\n", p->FIB_CRC); | |
60 | n += snprintf(&buf[n], PAGE_SIZE - n, | |
28a59df4 | 61 | "ts_per = %d\n", p->ts_per); |
503efe5c MCC |
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, | |
dfef84fc | 67 | "in_band_pwr = %d\n", p->in_band_pwr); |
503efe5c | 68 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 69 | "carrier_offset = %d\n", p->carrier_offset); |
503efe5c | 70 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 71 | "modem_state = %d\n", p->modem_state); |
503efe5c | 72 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 73 | "frequency = %d\n", p->frequency); |
503efe5c | 74 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 75 | "bandwidth = %d\n", p->bandwidth); |
503efe5c | 76 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 77 | "transmission_mode = %d\n", p->transmission_mode); |
503efe5c | 78 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 79 | "modem_state = %d\n", p->modem_state); |
503efe5c | 80 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 81 | "guard_interval = %d\n", p->guard_interval); |
503efe5c | 82 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 83 | "code_rate = %d\n", p->code_rate); |
503efe5c | 84 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 85 | "lp_code_rate = %d\n", p->lp_code_rate); |
503efe5c | 86 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 87 | "hierarchy = %d\n", p->hierarchy); |
503efe5c | 88 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 89 | "constellation = %d\n", p->constellation); |
503efe5c | 90 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 91 | "burst_size = %d\n", p->burst_size); |
503efe5c | 92 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 93 | "burst_duration = %d\n", p->burst_duration); |
503efe5c | 94 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 95 | "burst_cycle_time = %d\n", p->burst_cycle_time); |
503efe5c | 96 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 97 | "calc_burst_cycle_time = %d\n", |
05ad412a | 98 | p->calc_burst_cycle_time); |
503efe5c | 99 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 100 | "num_of_rows = %d\n", p->num_of_rows); |
503efe5c | 101 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 102 | "num_of_padd_cols = %d\n", p->num_of_padd_cols); |
503efe5c | 103 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 104 | "num_of_punct_cols = %d\n", p->num_of_punct_cols); |
503efe5c | 105 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 106 | "error_ts_packets = %d\n", p->error_ts_packets); |
503efe5c | 107 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 108 | "total_ts_packets = %d\n", p->total_ts_packets); |
503efe5c | 109 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 110 | "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs); |
503efe5c | 111 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 112 | "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs); |
503efe5c | 113 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 114 | "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs); |
503efe5c | 115 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 116 | "ber_error_count = %d\n", p->ber_error_count); |
503efe5c | 117 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 118 | "ber_bit_count = %d\n", p->ber_bit_count); |
503efe5c | 119 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 120 | "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); |
503efe5c | 121 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 122 | "pre_ber = %d\n", p->pre_ber); |
503efe5c | 123 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 124 | "cell_id = %d\n", p->cell_id); |
503efe5c | 125 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 126 | "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp); |
503efe5c | 127 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 128 | "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp); |
503efe5c | 129 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 130 | "num_mpe_received = %d\n", p->num_mpe_received); |
503efe5c MCC |
131 | |
132 | debug_data->stats_count = n; | |
133 | spin_unlock(&debug_data->lock); | |
134 | wake_up(&debug_data->stats_queue); | |
135 | } | |
136 | ||
2bf0f93e | 137 | static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, |
cf0e9cfc | 138 | struct sms_isdbt_stats *p) |
503efe5c MCC |
139 | { |
140 | int i, n = 0; | |
141 | char *buf; | |
142 | ||
143 | spin_lock(&debug_data->lock); | |
144 | if (debug_data->stats_count) { | |
145 | spin_unlock(&debug_data->lock); | |
146 | return; | |
147 | } | |
148 | ||
149 | buf = debug_data->stats_data; | |
150 | ||
4cce1f4e | 151 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 152 | "statistics_type = %d\t", p->statistics_type); |
4cce1f4e | 153 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 154 | "full_size = %d\n", p->full_size); |
4cce1f4e | 155 | |
503efe5c | 156 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 157 | "is_rf_locked = %d\t\t", p->is_rf_locked); |
503efe5c | 158 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 159 | "is_demod_locked = %d\t", p->is_demod_locked); |
503efe5c | 160 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 161 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
503efe5c MCC |
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, | |
dfef84fc | 167 | "in_band_pwr = %d dBm\n", p->in_band_pwr); |
503efe5c | 168 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 169 | "carrier_offset = %d\t", p->carrier_offset); |
503efe5c | 170 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 171 | "bandwidth = %d\t\t", p->bandwidth); |
503efe5c | 172 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 173 | "frequency = %d Hz\n", p->frequency); |
503efe5c | 174 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 175 | "transmission_mode = %d\t", p->transmission_mode); |
503efe5c | 176 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 177 | "modem_state = %d\t\t", p->modem_state); |
503efe5c | 178 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 179 | "guard_interval = %d\n", p->guard_interval); |
503efe5c | 180 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 181 | "system_type = %d\t\t", p->system_type); |
503efe5c | 182 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 183 | "partial_reception = %d\t", p->partial_reception); |
503efe5c | 184 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 185 | "num_of_layers = %d\n", p->num_of_layers); |
503efe5c | 186 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 187 | "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); |
503efe5c MCC |
188 | |
189 | for (i = 0; i < 3; i++) { | |
28a59df4 MCC |
190 | if (p->layer_info[i].number_of_segments < 1 || |
191 | p->layer_info[i].number_of_segments > 13) | |
503efe5c MCC |
192 | continue; |
193 | ||
194 | n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
dfef84fc | 195 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", |
28a59df4 | 196 | p->layer_info[i].code_rate); |
dfef84fc | 197 | n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", |
28a59df4 MCC |
198 | p->layer_info[i].constellation); |
199 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
200 | p->layer_info[i].ber); | |
dfef84fc | 201 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", |
28a59df4 | 202 | p->layer_info[i].ber_error_count); |
dfef84fc | 203 | n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", |
28a59df4 | 204 | p->layer_info[i].ber_bit_count); |
dfef84fc | 205 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", |
28a59df4 MCC |
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); | |
dfef84fc | 209 | n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", |
28a59df4 | 210 | p->layer_info[i].error_ts_packets); |
dfef84fc | 211 | n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", |
28a59df4 | 212 | p->layer_info[i].total_ts_packets); |
dfef84fc | 213 | n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", |
28a59df4 | 214 | p->layer_info[i].ti_ldepth_i); |
503efe5c | 215 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 216 | "\tnumber_of_segments = %d\t", |
28a59df4 | 217 | p->layer_info[i].number_of_segments); |
dfef84fc | 218 | n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", |
28a59df4 | 219 | p->layer_info[i].tmcc_errors); |
503efe5c MCC |
220 | } |
221 | ||
222 | debug_data->stats_count = n; | |
223 | spin_unlock(&debug_data->lock); | |
224 | wake_up(&debug_data->stats_queue); | |
225 | } | |
226 | ||
2bf0f93e | 227 | static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, |
cf0e9cfc | 228 | struct sms_isdbt_stats_ex *p) |
503efe5c MCC |
229 | { |
230 | int i, n = 0; | |
231 | char *buf; | |
232 | ||
233 | spin_lock(&debug_data->lock); | |
234 | if (debug_data->stats_count) { | |
235 | spin_unlock(&debug_data->lock); | |
236 | return; | |
237 | } | |
238 | ||
239 | buf = debug_data->stats_data; | |
240 | ||
4cce1f4e | 241 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 242 | "statistics_type = %d\t", p->statistics_type); |
4cce1f4e | 243 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 244 | "full_size = %d\n", p->full_size); |
4cce1f4e | 245 | |
503efe5c | 246 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 247 | "is_rf_locked = %d\t\t", p->is_rf_locked); |
503efe5c | 248 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 249 | "is_demod_locked = %d\t", p->is_demod_locked); |
503efe5c | 250 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 251 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
503efe5c MCC |
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, | |
dfef84fc | 257 | "in_band_pwr = %d dBm\n", p->in_band_pwr); |
503efe5c | 258 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 259 | "carrier_offset = %d\t", p->carrier_offset); |
503efe5c | 260 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 261 | "bandwidth = %d\t\t", p->bandwidth); |
503efe5c | 262 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 263 | "frequency = %d Hz\n", p->frequency); |
503efe5c | 264 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 265 | "transmission_mode = %d\t", p->transmission_mode); |
503efe5c | 266 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 267 | "modem_state = %d\t\t", p->modem_state); |
503efe5c | 268 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 269 | "guard_interval = %d\n", p->guard_interval); |
503efe5c | 270 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 271 | "system_type = %d\t\t", p->system_type); |
503efe5c | 272 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 273 | "partial_reception = %d\t", p->partial_reception); |
503efe5c | 274 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc MCC |
275 | "num_of_layers = %d\n", p->num_of_layers); |
276 | n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t", | |
277 | p->segment_number); | |
278 | n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n", | |
279 | p->tune_bw); | |
503efe5c MCC |
280 | |
281 | for (i = 0; i < 3; i++) { | |
28a59df4 MCC |
282 | if (p->layer_info[i].number_of_segments < 1 || |
283 | p->layer_info[i].number_of_segments > 13) | |
503efe5c MCC |
284 | continue; |
285 | ||
286 | n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
dfef84fc | 287 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", |
28a59df4 | 288 | p->layer_info[i].code_rate); |
dfef84fc | 289 | n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", |
28a59df4 MCC |
290 | p->layer_info[i].constellation); |
291 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
292 | p->layer_info[i].ber); | |
dfef84fc | 293 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", |
28a59df4 | 294 | p->layer_info[i].ber_error_count); |
dfef84fc | 295 | n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", |
28a59df4 | 296 | p->layer_info[i].ber_bit_count); |
dfef84fc | 297 | n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", |
28a59df4 MCC |
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); | |
dfef84fc | 301 | n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", |
28a59df4 | 302 | p->layer_info[i].error_ts_packets); |
dfef84fc | 303 | n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", |
28a59df4 | 304 | p->layer_info[i].total_ts_packets); |
dfef84fc | 305 | n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", |
28a59df4 | 306 | p->layer_info[i].ti_ldepth_i); |
503efe5c | 307 | n += snprintf(&buf[n], PAGE_SIZE - n, |
dfef84fc | 308 | "\tnumber_of_segments = %d\t", |
28a59df4 | 309 | p->layer_info[i].number_of_segments); |
dfef84fc | 310 | n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", |
28a59df4 | 311 | p->layer_info[i].tmcc_errors); |
503efe5c MCC |
312 | } |
313 | ||
314 | ||
315 | debug_data->stats_count = n; | |
316 | spin_unlock(&debug_data->lock); | |
317 | ||
318 | wake_up(&debug_data->stats_queue); | |
319 | } | |
320 | ||
321 | static int smsdvb_stats_open(struct inode *inode, struct file *file) | |
322 | { | |
323 | struct smsdvb_client_t *client = inode->i_private; | |
324 | struct smsdvb_debugfs *debug_data = client->debug_data; | |
325 | ||
326 | kref_get(&debug_data->refcount); | |
327 | ||
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); | |
332 | ||
333 | file->private_data = debug_data; | |
334 | ||
335 | return 0; | |
336 | } | |
337 | ||
6a28bd94 MCC |
338 | static void smsdvb_debugfs_data_release(struct kref *ref) |
339 | { | |
340 | struct smsdvb_debugfs *debug_data; | |
341 | ||
342 | debug_data = container_of(ref, struct smsdvb_debugfs, refcount); | |
343 | kfree(debug_data); | |
344 | } | |
345 | ||
503efe5c MCC |
346 | static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data) |
347 | { | |
348 | int rc = 1; | |
349 | ||
350 | spin_lock(&debug_data->lock); | |
351 | ||
352 | if (debug_data->stats_was_read) | |
353 | goto exit; | |
354 | ||
355 | rc = debug_data->stats_count; | |
356 | ||
357 | exit: | |
358 | spin_unlock(&debug_data->lock); | |
359 | return rc; | |
360 | } | |
361 | ||
c23e0cb8 | 362 | static __poll_t smsdvb_stats_poll(struct file *file, poll_table *wait) |
503efe5c | 363 | { |
503efe5c | 364 | struct smsdvb_debugfs *debug_data = file->private_data; |
6a28bd94 | 365 | int rc; |
503efe5c | 366 | |
6a28bd94 | 367 | kref_get(&debug_data->refcount); |
503efe5c | 368 | |
6a28bd94 MCC |
369 | poll_wait(file, &debug_data->stats_queue, wait); |
370 | ||
371 | rc = smsdvb_stats_wait_read(debug_data); | |
6a28bd94 | 372 | kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); |
503efe5c | 373 | |
a9a08845 | 374 | return rc > 0 ? EPOLLIN | EPOLLRDNORM : 0; |
503efe5c MCC |
375 | } |
376 | ||
6a28bd94 MCC |
377 | static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, |
378 | size_t nbytes, loff_t *ppos) | |
503efe5c | 379 | { |
6a28bd94 MCC |
380 | int rc = 0, len; |
381 | struct smsdvb_debugfs *debug_data = file->private_data; | |
503efe5c | 382 | |
6a28bd94 MCC |
383 | kref_get(&debug_data->refcount); |
384 | ||
385 | if (file->f_flags & O_NONBLOCK) { | |
386 | rc = smsdvb_stats_wait_read(debug_data); | |
387 | if (!rc) { | |
388 | rc = -EWOULDBLOCK; | |
389 | goto ret; | |
390 | } | |
391 | } else { | |
392 | rc = wait_event_interruptible(debug_data->stats_queue, | |
393 | smsdvb_stats_wait_read(debug_data)); | |
394 | if (rc < 0) | |
395 | goto ret; | |
396 | } | |
397 | ||
398 | if (debug_data->stats_was_read) { | |
399 | rc = 0; /* EOF */ | |
400 | goto ret; | |
401 | } | |
402 | ||
403 | len = debug_data->stats_count - *ppos; | |
404 | if (len >= 0) | |
405 | rc = simple_read_from_buffer(user_buf, nbytes, ppos, | |
406 | debug_data->stats_data, len); | |
407 | else | |
408 | rc = 0; | |
409 | ||
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); | |
414 | } | |
415 | ret: | |
416 | kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); | |
417 | return rc; | |
503efe5c MCC |
418 | } |
419 | ||
420 | static int smsdvb_stats_release(struct inode *inode, struct file *file) | |
421 | { | |
422 | struct smsdvb_debugfs *debug_data = file->private_data; | |
423 | ||
424 | spin_lock(&debug_data->lock); | |
6a28bd94 | 425 | debug_data->stats_was_read = true; /* return EOF to read() */ |
503efe5c MCC |
426 | spin_unlock(&debug_data->lock); |
427 | wake_up_interruptible_sync(&debug_data->stats_queue); | |
428 | ||
429 | kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); | |
430 | file->private_data = NULL; | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
435 | static const struct file_operations debugfs_stats_ops = { | |
436 | .open = smsdvb_stats_open, | |
6a28bd94 | 437 | .poll = smsdvb_stats_poll, |
503efe5c MCC |
438 | .read = smsdvb_stats_read, |
439 | .release = smsdvb_stats_release, | |
440 | .llseek = generic_file_llseek, | |
441 | }; | |
442 | ||
443 | /* | |
444 | * Functions used by smsdvb, in order to create the interfaces | |
445 | */ | |
446 | ||
447 | int smsdvb_debugfs_create(struct smsdvb_client_t *client) | |
448 | { | |
449 | struct smscore_device_t *coredev = client->coredev; | |
450 | struct dentry *d; | |
451 | struct smsdvb_debugfs *debug_data; | |
452 | ||
453 | if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device) | |
454 | return -ENODEV; | |
455 | ||
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", | |
460 | coredev->devpath); | |
461 | return -ENODEV; | |
462 | } | |
463 | ||
464 | d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, | |
465 | client, &debugfs_stats_ops); | |
466 | if (!d) { | |
467 | debugfs_remove(client->debugfs); | |
468 | return -ENOMEM; | |
469 | } | |
470 | ||
471 | debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL); | |
472 | if (!debug_data) | |
473 | return -ENOMEM; | |
474 | ||
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; | |
479 | ||
480 | init_waitqueue_head(&debug_data->stats_queue); | |
481 | spin_lock_init(&debug_data->lock); | |
482 | kref_init(&debug_data->refcount); | |
483 | ||
484 | return 0; | |
485 | } | |
486 | ||
487 | void smsdvb_debugfs_release(struct smsdvb_client_t *client) | |
488 | { | |
489 | if (!client->debugfs) | |
490 | return; | |
491 | ||
503efe5c MCC |
492 | client->prt_dvb_stats = NULL; |
493 | client->prt_isdb_stats = NULL; | |
494 | client->prt_isdb_stats_ex = NULL; | |
495 | ||
496 | debugfs_remove_recursive(client->debugfs); | |
497 | kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release); | |
498 | ||
499 | client->debug_data = NULL; | |
500 | client->debugfs = NULL; | |
501 | } | |
502 | ||
503 | int smsdvb_debugfs_register(void) | |
504 | { | |
505 | struct dentry *d; | |
506 | ||
507 | /* | |
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. | |
512 | * | |
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 | |
515 | * subsystem. | |
516 | */ | |
517 | d = debugfs_create_dir("smsdvb", usb_debug_root); | |
518 | if (IS_ERR_OR_NULL(d)) { | |
5ed0a2c7 | 519 | pr_err("Couldn't create sysfs node for smsdvb\n"); |
503efe5c MCC |
520 | return PTR_ERR(d); |
521 | } else { | |
522 | smsdvb_debugfs_usb_root = d; | |
523 | } | |
524 | return 0; | |
525 | } | |
526 | ||
527 | void smsdvb_debugfs_unregister(void) | |
528 | { | |
05ad412a | 529 | debugfs_remove_recursive(smsdvb_debugfs_usb_root); |
503efe5c MCC |
530 | smsdvb_debugfs_usb_root = NULL; |
531 | } |