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