blob: 4d5dd471e2e1a5b3bef2762d52d66412c2706bbc [file] [log] [blame]
Mauro Carvalho Chehab503efe52013-03-10 09:04:44 -03001/***********************************************************************
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
38static struct dentry *smsdvb_debugfs_usb_root;
39
40struct 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
51void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data,
52 struct SMSHOSTLIB_STATISTICS_ST *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 "IsRfLocked = %d\n", p->IsRfLocked);
67 n += snprintf(&buf[n], PAGE_SIZE - n,
68 "IsDemodLocked = %d\n", p->IsDemodLocked);
69 n += snprintf(&buf[n], PAGE_SIZE - n,
70 "IsExternalLNAOn = %d\n", p->IsExternalLNAOn);
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 "InBandPwr = %d\n", p->InBandPwr);
85 n += snprintf(&buf[n], PAGE_SIZE - n,
86 "CarrierOffset = %d\n", p->CarrierOffset);
87 n += snprintf(&buf[n], PAGE_SIZE - n,
88 "ModemState = %d\n", p->ModemState);
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 "TransmissionMode = %d\n", p->TransmissionMode);
95 n += snprintf(&buf[n], PAGE_SIZE - n,
96 "ModemState = %d\n", p->ModemState);
97 n += snprintf(&buf[n], PAGE_SIZE - n,
98 "GuardInterval = %d\n", p->GuardInterval);
99 n += snprintf(&buf[n], PAGE_SIZE - n,
100 "CodeRate = %d\n", p->CodeRate);
101 n += snprintf(&buf[n], PAGE_SIZE - n,
102 "LPCodeRate = %d\n", p->LPCodeRate);
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 "BurstSize = %d\n", p->BurstSize);
109 n += snprintf(&buf[n], PAGE_SIZE - n,
110 "BurstDuration = %d\n", p->BurstDuration);
111 n += snprintf(&buf[n], PAGE_SIZE - n,
112 "BurstCycleTime = %d\n", p->BurstCycleTime);
113 n += snprintf(&buf[n], PAGE_SIZE - n,
114 "CalculatedBurstCycleTime = %d\n",
115 p->CalculatedBurstCycleTime);
116 n += snprintf(&buf[n], PAGE_SIZE - n,
117 "NumOfRows = %d\n", p->NumOfRows);
118 n += snprintf(&buf[n], PAGE_SIZE - n,
119 "NumOfPaddCols = %d\n", p->NumOfPaddCols);
120 n += snprintf(&buf[n], PAGE_SIZE - n,
121 "NumOfPunctCols = %d\n", p->NumOfPunctCols);
122 n += snprintf(&buf[n], PAGE_SIZE - n,
123 "ErrorTSPackets = %d\n", p->ErrorTSPackets);
124 n += snprintf(&buf[n], PAGE_SIZE - n,
125 "TotalTSPackets = %d\n", p->TotalTSPackets);
126 n += snprintf(&buf[n], PAGE_SIZE - n,
127 "NumOfValidMpeTlbs = %d\n", p->NumOfValidMpeTlbs);
128 n += snprintf(&buf[n], PAGE_SIZE - n,
129 "NumOfInvalidMpeTlbs = %d\n", p->NumOfInvalidMpeTlbs);
130 n += snprintf(&buf[n], PAGE_SIZE - n,
131 "NumOfCorrectedMpeTlbs = %d\n", p->NumOfCorrectedMpeTlbs);
132 n += snprintf(&buf[n], PAGE_SIZE - n,
133 "BERErrorCount = %d\n", p->BERErrorCount);
134 n += snprintf(&buf[n], PAGE_SIZE - n,
135 "BERBitCount = %d\n", p->BERBitCount);
136 n += snprintf(&buf[n], PAGE_SIZE - n,
137 "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors);
138 n += snprintf(&buf[n], PAGE_SIZE - n,
139 "PreBER = %d\n", p->PreBER);
140 n += snprintf(&buf[n], PAGE_SIZE - n,
141 "CellId = %d\n", p->CellId);
142 n += snprintf(&buf[n], PAGE_SIZE - n,
143 "DvbhSrvIndHP = %d\n", p->DvbhSrvIndHP);
144 n += snprintf(&buf[n], PAGE_SIZE - n,
145 "DvbhSrvIndLP = %d\n", p->DvbhSrvIndLP);
146 n += snprintf(&buf[n], PAGE_SIZE - n,
147 "NumMPEReceived = %d\n", p->NumMPEReceived);
148
149 debug_data->stats_count = n;
150 spin_unlock(&debug_data->lock);
151 wake_up(&debug_data->stats_queue);
152}
153
154void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data,
155 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *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 "IsRfLocked = %d\t\t", p->IsRfLocked);
170 n += snprintf(&buf[n], PAGE_SIZE - n,
171 "IsDemodLocked = %d\t", p->IsDemodLocked);
172 n += snprintf(&buf[n], PAGE_SIZE - n,
173 "IsExternalLNAOn = %d\n", p->IsExternalLNAOn);
174 n += snprintf(&buf[n], PAGE_SIZE - n,
175 "SNR = %d dB\t\t", p->SNR);
176 n += snprintf(&buf[n], PAGE_SIZE - n,
177 "RSSI = %d dBm\t\t", p->RSSI);
178 n += snprintf(&buf[n], PAGE_SIZE - n,
179 "InBandPwr = %d dBm\n", p->InBandPwr);
180 n += snprintf(&buf[n], PAGE_SIZE - n,
181 "CarrierOffset = %d\t", p->CarrierOffset);
182 n += snprintf(&buf[n], PAGE_SIZE - n,
183 "Bandwidth = %d\t\t", p->Bandwidth);
184 n += snprintf(&buf[n], PAGE_SIZE - n,
185 "Frequency = %d Hz\n", p->Frequency);
186 n += snprintf(&buf[n], PAGE_SIZE - n,
187 "TransmissionMode = %d\t", p->TransmissionMode);
188 n += snprintf(&buf[n], PAGE_SIZE - n,
189 "ModemState = %d\t\t", p->ModemState);
190 n += snprintf(&buf[n], PAGE_SIZE - n,
191 "GuardInterval = %d\n", p->GuardInterval);
192 n += snprintf(&buf[n], PAGE_SIZE - n,
193 "SystemType = %d\t\t", p->SystemType);
194 n += snprintf(&buf[n], PAGE_SIZE - n,
195 "PartialReception = %d\t", p->PartialReception);
196 n += snprintf(&buf[n], PAGE_SIZE - n,
197 "NumOfLayers = %d\n", p->NumOfLayers);
198 n += snprintf(&buf[n], PAGE_SIZE - n,
199 "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors);
200
201 for (i = 0; i < 3; i++) {
202 if (p->LayerInfo[i].NumberOfSegments < 1 ||
203 p->LayerInfo[i].NumberOfSegments > 13)
204 continue;
205
206 n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
207 n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t",
208 p->LayerInfo[i].CodeRate);
209 n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n",
210 p->LayerInfo[i].Constellation);
211 n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t",
212 p->LayerInfo[i].BER);
213 n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t",
214 p->LayerInfo[i].BERErrorCount);
215 n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n",
216 p->LayerInfo[i].BERBitCount);
217 n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t",
218 p->LayerInfo[i].PreBER);
219 n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n",
220 p->LayerInfo[i].TS_PER);
221 n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t",
222 p->LayerInfo[i].ErrorTSPackets);
223 n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t",
224 p->LayerInfo[i].TotalTSPackets);
225 n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n",
226 p->LayerInfo[i].TILdepthI);
227 n += snprintf(&buf[n], PAGE_SIZE - n,
228 "\tNumberOfSegments = %d\t",
229 p->LayerInfo[i].NumberOfSegments);
230 n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n",
231 p->LayerInfo[i].TMCCErrors);
232 }
233
234 debug_data->stats_count = n;
235 spin_unlock(&debug_data->lock);
236 wake_up(&debug_data->stats_queue);
237}
238
239void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data,
240 struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
241{
242 int i, n = 0;
243 char *buf;
244
245 spin_lock(&debug_data->lock);
246 if (debug_data->stats_count) {
247 spin_unlock(&debug_data->lock);
248 return;
249 }
250
251 buf = debug_data->stats_data;
252
253 n += snprintf(&buf[n], PAGE_SIZE - n,
254 "IsRfLocked = %d\t\t", p->IsRfLocked);
255 n += snprintf(&buf[n], PAGE_SIZE - n,
256 "IsDemodLocked = %d\t", p->IsDemodLocked);
257 n += snprintf(&buf[n], PAGE_SIZE - n,
258 "IsExternalLNAOn = %d\n", p->IsExternalLNAOn);
259 n += snprintf(&buf[n], PAGE_SIZE - n,
260 "SNR = %d dB\t\t", p->SNR);
261 n += snprintf(&buf[n], PAGE_SIZE - n,
262 "RSSI = %d dBm\t\t", p->RSSI);
263 n += snprintf(&buf[n], PAGE_SIZE - n,
264 "InBandPwr = %d dBm\n", p->InBandPwr);
265 n += snprintf(&buf[n], PAGE_SIZE - n,
266 "CarrierOffset = %d\t", p->CarrierOffset);
267 n += snprintf(&buf[n], PAGE_SIZE - n,
268 "Bandwidth = %d\t\t", p->Bandwidth);
269 n += snprintf(&buf[n], PAGE_SIZE - n,
270 "Frequency = %d Hz\n", p->Frequency);
271 n += snprintf(&buf[n], PAGE_SIZE - n,
272 "TransmissionMode = %d\t", p->TransmissionMode);
273 n += snprintf(&buf[n], PAGE_SIZE - n,
274 "ModemState = %d\t\t", p->ModemState);
275 n += snprintf(&buf[n], PAGE_SIZE - n,
276 "GuardInterval = %d\n", p->GuardInterval);
277 n += snprintf(&buf[n], PAGE_SIZE - n,
278 "SystemType = %d\t\t", p->SystemType);
279 n += snprintf(&buf[n], PAGE_SIZE - n,
280 "PartialReception = %d\t", p->PartialReception);
281 n += snprintf(&buf[n], PAGE_SIZE - n,
282 "NumOfLayers = %d\n", p->NumOfLayers);
283 n += snprintf(&buf[n], PAGE_SIZE - n, "SegmentNumber = %d\t",
284 p->SegmentNumber);
285 n += snprintf(&buf[n], PAGE_SIZE - n, "TuneBW = %d\n",
286 p->TuneBW);
287
288 for (i = 0; i < 3; i++) {
289 if (p->LayerInfo[i].NumberOfSegments < 1 ||
290 p->LayerInfo[i].NumberOfSegments > 13)
291 continue;
292
293 n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
294 n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t",
295 p->LayerInfo[i].CodeRate);
296 n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n",
297 p->LayerInfo[i].Constellation);
298 n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t",
299 p->LayerInfo[i].BER);
300 n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t",
301 p->LayerInfo[i].BERErrorCount);
302 n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n",
303 p->LayerInfo[i].BERBitCount);
304 n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t",
305 p->LayerInfo[i].PreBER);
306 n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n",
307 p->LayerInfo[i].TS_PER);
308 n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t",
309 p->LayerInfo[i].ErrorTSPackets);
310 n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t",
311 p->LayerInfo[i].TotalTSPackets);
312 n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n",
313 p->LayerInfo[i].TILdepthI);
314 n += snprintf(&buf[n], PAGE_SIZE - n,
315 "\tNumberOfSegments = %d\t",
316 p->LayerInfo[i].NumberOfSegments);
317 n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n",
318 p->LayerInfo[i].TMCCErrors);
319 }
320
321
322 debug_data->stats_count = n;
323 spin_unlock(&debug_data->lock);
324
325 wake_up(&debug_data->stats_queue);
326}
327
328static int smsdvb_stats_open(struct inode *inode, struct file *file)
329{
330 struct smsdvb_client_t *client = inode->i_private;
331 struct smsdvb_debugfs *debug_data = client->debug_data;
332
333 kref_get(&debug_data->refcount);
334
335 spin_lock(&debug_data->lock);
336 debug_data->stats_count = 0;
337 debug_data->stats_was_read = false;
338 spin_unlock(&debug_data->lock);
339
340 file->private_data = debug_data;
341
342 return 0;
343}
344
345static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data)
346{
347 int rc = 1;
348
349 spin_lock(&debug_data->lock);
350
351 if (debug_data->stats_was_read)
352 goto exit;
353
354 rc = debug_data->stats_count;
355
356exit:
357 spin_unlock(&debug_data->lock);
358 return rc;
359}
360
361static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf,
362 size_t nbytes, loff_t *ppos)
363{
364 int rc = 0;
365 struct smsdvb_debugfs *debug_data = file->private_data;
366
367 rc = wait_event_interruptible(debug_data->stats_queue,
368 smsdvb_stats_wait_read(debug_data));
369 if (rc < 0)
370 return rc;
371
372 rc = simple_read_from_buffer(user_buf, nbytes, ppos,
373 debug_data->stats_data,
374 debug_data->stats_count);
375 spin_lock(&debug_data->lock);
376 debug_data->stats_was_read = true;
377 spin_unlock(&debug_data->lock);
378
379 return rc;
380}
381
382static void smsdvb_debugfs_data_release(struct kref *ref)
383{
384 struct smsdvb_debugfs *debug_data;
385
386 debug_data = container_of(ref, struct smsdvb_debugfs, refcount);
387 kfree(debug_data);
388}
389
390static int smsdvb_stats_release(struct inode *inode, struct file *file)
391{
392 struct smsdvb_debugfs *debug_data = file->private_data;
393
394 spin_lock(&debug_data->lock);
395 debug_data->stats_was_read = true;
396 spin_unlock(&debug_data->lock);
397 wake_up_interruptible_sync(&debug_data->stats_queue);
398
399 kref_put(&debug_data->refcount, smsdvb_debugfs_data_release);
400 file->private_data = NULL;
401
402 return 0;
403}
404
405static const struct file_operations debugfs_stats_ops = {
406 .open = smsdvb_stats_open,
407 .read = smsdvb_stats_read,
408 .release = smsdvb_stats_release,
409 .llseek = generic_file_llseek,
410};
411
412/*
413 * Functions used by smsdvb, in order to create the interfaces
414 */
415
416int smsdvb_debugfs_create(struct smsdvb_client_t *client)
417{
418 struct smscore_device_t *coredev = client->coredev;
419 struct dentry *d;
420 struct smsdvb_debugfs *debug_data;
421
422 if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device)
423 return -ENODEV;
424
425 client->debugfs = debugfs_create_dir(coredev->devpath,
426 smsdvb_debugfs_usb_root);
427 if (IS_ERR_OR_NULL(client->debugfs)) {
428 pr_info("Unable to create debugfs %s directory.\n",
429 coredev->devpath);
430 return -ENODEV;
431 }
432
433 d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs,
434 client, &debugfs_stats_ops);
435 if (!d) {
436 debugfs_remove(client->debugfs);
437 return -ENOMEM;
438 }
439
440 debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL);
441 if (!debug_data)
442 return -ENOMEM;
443
444 client->debug_data = debug_data;
445 client->prt_dvb_stats = smsdvb_print_dvb_stats;
446 client->prt_isdb_stats = smsdvb_print_isdb_stats;
447 client->prt_isdb_stats_ex = smsdvb_print_isdb_stats_ex;
448
449 init_waitqueue_head(&debug_data->stats_queue);
450 spin_lock_init(&debug_data->lock);
451 kref_init(&debug_data->refcount);
452
453 return 0;
454}
455
456void smsdvb_debugfs_release(struct smsdvb_client_t *client)
457{
458 if (!client->debugfs)
459 return;
460
461printk("%s\n", __func__);
462
463 client->prt_dvb_stats = NULL;
464 client->prt_isdb_stats = NULL;
465 client->prt_isdb_stats_ex = NULL;
466
467 debugfs_remove_recursive(client->debugfs);
468 kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release);
469
470 client->debug_data = NULL;
471 client->debugfs = NULL;
472}
473
474int smsdvb_debugfs_register(void)
475{
476 struct dentry *d;
477
478 /*
479 * FIXME: This was written to debug Siano USB devices. So, it creates
480 * the debugfs node under <debugfs>/usb.
481 * A similar logic would be needed for Siano sdio devices, but, in that
482 * case, usb_debug_root is not a good choice.
483 *
484 * Perhaps the right fix here would be to create another sysfs root
485 * node for sdio-based boards, but this may need some logic at sdio
486 * subsystem.
487 */
488 d = debugfs_create_dir("smsdvb", usb_debug_root);
489 if (IS_ERR_OR_NULL(d)) {
490 sms_err("Couldn't create sysfs node for smsdvb");
491 return PTR_ERR(d);
492 } else {
493 smsdvb_debugfs_usb_root = d;
494 }
495 return 0;
496}
497
498void smsdvb_debugfs_unregister(void)
499{
500 if (smsdvb_debugfs_usb_root)
501 debugfs_remove_recursive(smsdvb_debugfs_usb_root);
502 smsdvb_debugfs_usb_root = NULL;
503}