1 /* 2 * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: qdf_debugfs 21 * This file provides QDF debug file system APIs 22 */ 23 24 #include <qdf_debugfs.h> 25 #include <i_qdf_debugfs.h> 26 #include <qdf_mem.h> 27 #include <qdf_trace.h> 28 #include <qdf_module.h> 29 30 /* A private structure definition to qdf sequence */ 31 struct qdf_debugfs_seq_priv { 32 bool stop; 33 }; 34 35 /* entry for root debugfs directory*/ 36 static qdf_dentry_t qdf_debugfs_root; 37 38 QDF_STATUS qdf_debugfs_init(void) 39 { 40 qdf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 41 42 if (!qdf_debugfs_root) 43 return QDF_STATUS_E_FAILURE; 44 45 return QDF_STATUS_SUCCESS; 46 } 47 qdf_export_symbol(qdf_debugfs_init); 48 49 void qdf_debugfs_exit(void) 50 { 51 if (!qdf_debugfs_root) 52 return; 53 54 debugfs_remove_recursive(qdf_debugfs_root); 55 qdf_debugfs_root = NULL; 56 } 57 qdf_export_symbol(qdf_debugfs_exit); 58 59 qdf_dentry_t qdf_debugfs_get_root(void) 60 { 61 return qdf_debugfs_root; 62 } 63 qdf_export_symbol(qdf_debugfs_get_root); 64 65 umode_t qdf_debugfs_get_filemode(uint16_t mode) 66 { 67 umode_t ret = 0; 68 69 if (mode & QDF_FILE_USR_READ) 70 ret |= 0400; 71 if (mode & QDF_FILE_USR_WRITE) 72 ret |= 0200; 73 74 if (mode & QDF_FILE_GRP_READ) 75 ret |= 0040; 76 if (mode & QDF_FILE_GRP_WRITE) 77 ret |= 0020; 78 79 if (mode & QDF_FILE_OTH_READ) 80 ret |= 0004; 81 if (mode & QDF_FILE_OTH_WRITE) 82 ret |= 0002; 83 84 return ret; 85 } 86 87 /** 88 * ---------------------- Implementation note --------------------------------- 89 * 90 * A read in debugfs file triggers seq_read() which calls seq_read api. A 91 * sequence begins with the call of the function start(). If the return is a non 92 * NULL value, the function next() is called. This function is an iterator, the 93 * goal is to go though all the data. Each time next() is called, the function 94 * show() is also called. It writes data values in the buffer read by the user. 95 * The function next() is called until it returns NULL. The sequence ends when 96 * next() returns NULL, then the function stop() is called. 97 * 98 * NOTE: When a sequence is finished, another one starts. That means that 99 * at the end of function stop(), the function start() is called again. This 100 * loop finishes when the function start() returns NULL. 101 * ---------------------------------------------------------------------------- 102 */ 103 104 /* .seq_start() */ 105 static void *qdf_debugfs_seq_start(struct seq_file *seq, loff_t *pos) 106 { 107 struct qdf_debugfs_seq_priv *priv; 108 109 priv = qdf_mem_malloc(sizeof(*priv)); 110 if (!priv) 111 return NULL; 112 113 priv->stop = false; 114 115 return priv; 116 } 117 118 /* .seq_next() */ 119 static void *qdf_debugfs_seq_next(struct seq_file *seq, void *v, loff_t *pos) 120 { 121 struct qdf_debugfs_seq_priv *priv = v; 122 123 if (priv) 124 ++*pos; 125 126 if (priv && priv->stop) { 127 qdf_mem_free(priv); 128 priv = NULL; 129 } 130 131 return priv; 132 } 133 134 /* .seq_stop() */ 135 static void qdf_debugfs_seq_stop(struct seq_file *seq, void *v) 136 { 137 qdf_mem_free(v); 138 } 139 140 /* .seq_show() */ 141 static int qdf_debugfs_seq_show(struct seq_file *seq, void *v) 142 { 143 struct qdf_debugfs_seq_priv *priv = v; 144 struct qdf_debugfs_fops *fops; 145 QDF_STATUS status; 146 147 fops = seq->private; 148 149 if (fops && fops->show) { 150 status = fops->show(seq, fops->priv); 151 152 if (priv && (status != QDF_STATUS_E_AGAIN)) 153 priv->stop = true; 154 } 155 156 return 0; 157 } 158 159 void qdf_debugfs_printf(qdf_debugfs_file_t file, const char *f, ...) 160 { 161 va_list args; 162 163 va_start(args, f); 164 seq_vprintf(file, f, args); 165 va_end(args); 166 } 167 168 qdf_export_symbol(qdf_debugfs_printf); 169 170 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) 171 172 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 173 qdf_size_t len, int rowsize, int groupsize) 174 { 175 seq_hex_dump(file, "", DUMP_PREFIX_OFFSET, rowsize, groupsize, buf, len, 176 false); 177 } 178 179 #else 180 181 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 182 qdf_size_t len, int rowsize, int groupsize) 183 { 184 char *dst; 185 size_t dstlen, readlen, remaining = len; 186 int prefix = 0; 187 size_t commitlen; 188 189 while (remaining > 0 && (file->size > file->count)) { 190 seq_printf(file, "%.8x: ", prefix); 191 192 readlen = qdf_min(remaining, (qdf_size_t)rowsize); 193 dstlen = seq_get_buf(file, &dst); 194 hex_dump_to_buffer(buf, readlen, rowsize, groupsize, dst, 195 dstlen, false); 196 commitlen = strnlen(dst, dstlen); 197 seq_commit(file, commitlen); 198 seq_putc(file, '\n'); 199 200 remaining = (remaining > rowsize) ? remaining - rowsize : 0; 201 buf += readlen; 202 prefix += rowsize; 203 } 204 } 205 206 #endif 207 208 bool qdf_debugfs_overflow(qdf_debugfs_file_t file) 209 { 210 return seq_has_overflowed(file); 211 } 212 213 void qdf_debugfs_write(qdf_debugfs_file_t file, const uint8_t *buf, 214 qdf_size_t len) 215 { 216 seq_write(file, buf, len); 217 } 218 219 /* sequential file operation table */ 220 static const struct seq_operations __qdf_debugfs_seq_ops = { 221 .start = qdf_debugfs_seq_start, 222 .next = qdf_debugfs_seq_next, 223 .stop = qdf_debugfs_seq_stop, 224 .show = qdf_debugfs_seq_show, 225 }; 226 227 /* .open() */ 228 static int qdf_seq_open(struct inode *inode, struct file *file) 229 { 230 void *private = inode->i_private; 231 struct seq_file *seq; 232 int rc; 233 234 /** 235 * Note: seq_open() will allocate a struct seq_file and store its 236 * pointer in @file->private_data. It warns if private_data is not NULL. 237 */ 238 239 rc = seq_open(file, &__qdf_debugfs_seq_ops); 240 241 if (rc == 0) { 242 seq = file->private_data; 243 seq->private = private; 244 } 245 246 return rc; 247 } 248 249 /* .write() */ 250 static ssize_t qdf_seq_write(struct file *filp, const char __user *ubuf, 251 size_t len, loff_t *ppos) 252 { 253 struct qdf_debugfs_fops *fops; 254 struct seq_file *seq; 255 u8 *buf; 256 ssize_t rc = 0; 257 258 if (len == 0) 259 return 0; 260 261 seq = filp->private_data; 262 fops = seq->private; 263 if (fops && fops->write) { 264 buf = qdf_mem_malloc(len + 1); 265 if (buf) { 266 buf[len] = '\0'; 267 rc = simple_write_to_buffer(buf, len, ppos, ubuf, len); 268 fops->write(fops->priv, buf, len + 1); 269 qdf_mem_free(buf); 270 } 271 } 272 273 return rc; 274 } 275 276 /* debugfs file operation table */ 277 static const struct file_operations __qdf_debugfs_fops = { 278 .owner = THIS_MODULE, 279 .open = qdf_seq_open, 280 .read = seq_read, 281 .llseek = seq_lseek, 282 .release = seq_release, 283 .write = qdf_seq_write, 284 }; 285 286 qdf_dentry_t qdf_debugfs_create_dir(const char *name, qdf_dentry_t parent) 287 { 288 qdf_dentry_t dir; 289 290 if (!name) 291 return NULL; 292 if (!parent) 293 parent = qdf_debugfs_get_root(); 294 295 dir = debugfs_create_dir(name, parent); 296 297 if (IS_ERR_OR_NULL(dir)) { 298 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 299 "%s creation failed", name); 300 dir = NULL; 301 } 302 303 return dir; 304 } 305 qdf_export_symbol(qdf_debugfs_create_dir); 306 307 qdf_dentry_t qdf_debugfs_create_file(const char *name, uint16_t mode, 308 qdf_dentry_t parent, 309 struct qdf_debugfs_fops *fops) 310 { 311 qdf_dentry_t file; 312 umode_t filemode; 313 314 if (!name || !fops) 315 return NULL; 316 317 if (!parent) 318 parent = qdf_debugfs_get_root(); 319 320 filemode = qdf_debugfs_get_filemode(mode); 321 file = debugfs_create_file(name, filemode, parent, fops, 322 &__qdf_debugfs_fops); 323 324 if (IS_ERR_OR_NULL(file)) { 325 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 326 "%s creation failed 0x%pK", name, file); 327 file = NULL; 328 } 329 330 return file; 331 } 332 qdf_export_symbol(qdf_debugfs_create_file); 333 334 qdf_dentry_t qdf_debugfs_create_u8(const char *name, uint16_t mode, 335 qdf_dentry_t parent, u8 *value) 336 { 337 umode_t filemode; 338 339 if (!name) 340 return NULL; 341 342 if (!parent) 343 parent = qdf_debugfs_get_root(); 344 345 filemode = qdf_debugfs_get_filemode(mode); 346 return debugfs_create_u8(name, filemode, parent, value); 347 } 348 349 qdf_dentry_t qdf_debugfs_create_u16(const char *name, uint16_t mode, 350 qdf_dentry_t parent, u16 *value) 351 { 352 umode_t filemode; 353 354 if (!name) 355 return NULL; 356 357 if (!parent) 358 parent = qdf_debugfs_get_root(); 359 360 filemode = qdf_debugfs_get_filemode(mode); 361 return debugfs_create_u16(name, filemode, parent, value); 362 } 363 qdf_export_symbol(qdf_debugfs_create_u16); 364 365 qdf_dentry_t qdf_debugfs_create_u32(const char *name, 366 uint16_t mode, 367 qdf_dentry_t parent, u32 *value) 368 { 369 umode_t filemode; 370 371 if (!name) 372 return NULL; 373 374 if (!parent) 375 parent = qdf_debugfs_get_root(); 376 377 filemode = qdf_debugfs_get_filemode(mode); 378 return debugfs_create_u32(name, filemode, parent, value); 379 } 380 qdf_export_symbol(qdf_debugfs_create_u32); 381 382 qdf_dentry_t qdf_debugfs_create_u64(const char *name, uint16_t mode, 383 qdf_dentry_t parent, u64 *value) 384 { 385 umode_t filemode; 386 387 if (!name) 388 return NULL; 389 390 if (!parent) 391 parent = qdf_debugfs_get_root(); 392 393 filemode = qdf_debugfs_get_filemode(mode); 394 return debugfs_create_u64(name, filemode, parent, value); 395 } 396 qdf_export_symbol(qdf_debugfs_create_u64); 397 398 qdf_dentry_t qdf_debugfs_create_atomic(const char *name, uint16_t mode, 399 qdf_dentry_t parent, qdf_atomic_t *value) 400 { 401 umode_t filemode; 402 403 if (!name) 404 return NULL; 405 406 if (!parent) 407 parent = qdf_debugfs_get_root(); 408 409 filemode = qdf_debugfs_get_filemode(mode); 410 return debugfs_create_atomic_t(name, filemode, parent, value); 411 } 412 qdf_export_symbol(qdf_debugfs_create_atomic); 413 414 static int qdf_debugfs_string_show(struct seq_file *seq, void *pos) 415 { 416 char *str = seq->private; 417 418 seq_puts(seq, str); 419 seq_putc(seq, '\n'); 420 421 return 0; 422 } 423 424 static int qdf_debugfs_string_open(struct inode *inode, struct file *file) 425 { 426 return single_open(file, qdf_debugfs_string_show, inode->i_private); 427 } 428 429 static const struct file_operations qdf_string_fops = { 430 .owner = THIS_MODULE, 431 .open = qdf_debugfs_string_open, 432 .read = seq_read, 433 .llseek = seq_lseek, 434 .release = single_release 435 }; 436 437 qdf_dentry_t qdf_debugfs_create_string(const char *name, uint16_t mode, 438 qdf_dentry_t parent, char *str) 439 { 440 umode_t filemode; 441 442 if (!name) 443 return NULL; 444 445 if (!parent) 446 parent = qdf_debugfs_get_root(); 447 448 filemode = qdf_debugfs_get_filemode(mode); 449 return debugfs_create_file(name, filemode, parent, str, 450 &qdf_string_fops); 451 } 452 qdf_export_symbol(qdf_debugfs_create_string); 453 454 void qdf_debugfs_remove_dir_recursive(qdf_dentry_t d) 455 { 456 debugfs_remove_recursive(d); 457 } 458 qdf_export_symbol(qdf_debugfs_remove_dir_recursive); 459 460 void qdf_debugfs_remove_dir(qdf_dentry_t d) 461 { 462 debugfs_remove(d); 463 } 464 qdf_export_symbol(qdf_debugfs_remove_dir); 465 466 void qdf_debugfs_remove_file(qdf_dentry_t d) 467 { 468 debugfs_remove(d); 469 } 470 qdf_export_symbol(qdf_debugfs_remove_file); 471 472 static int qdf_debugfs_single_show(struct seq_file *seq, void *v) 473 { 474 struct qdf_debugfs_fops *fops = seq->private; 475 476 if (fops && fops->show) 477 fops->show(seq, fops->priv); 478 479 return 0; 480 } 481 482 /* .open() */ 483 static int qdf_debugfs_single_open(struct inode *inode, struct file *file) 484 { 485 return single_open(file, qdf_debugfs_single_show, 486 inode->i_private); 487 } 488 489 /* File operations for the simplified version */ 490 static const struct file_operations qdf_debugfs_fops_simple = { 491 .owner = THIS_MODULE, 492 .open = qdf_debugfs_single_open, 493 .release = single_release, 494 .read = seq_read, 495 .llseek = seq_lseek, 496 }; 497 498 qdf_dentry_t qdf_debugfs_create_file_simplified( 499 const char *name, uint16_t mode, 500 qdf_dentry_t parent, struct qdf_debugfs_fops *fops) 501 { 502 qdf_dentry_t file; 503 umode_t filemode; 504 505 if (!name || !fops) 506 return NULL; 507 508 if (!parent) 509 parent = qdf_debugfs_get_root(); 510 511 filemode = qdf_debugfs_get_filemode(mode); 512 file = debugfs_create_file(name, filemode, parent, fops, 513 &qdf_debugfs_fops_simple); 514 515 if (IS_ERR_OR_NULL(file)) { 516 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 517 "%s creation failed 0x%pK", name, file); 518 file = NULL; 519 } 520 521 return file; 522 } 523 qdf_export_symbol(qdf_debugfs_create_file_simplified); 524 525 int qdf_debugfs_printer(void *priv, const char *fmt, ...) 526 { 527 struct seq_file *file = priv; 528 va_list args; 529 530 va_start(args, fmt); 531 seq_vprintf(file, fmt, args); 532 seq_puts(file, "\n"); 533 va_end(args); 534 535 return 0; 536 } 537 qdf_export_symbol(qdf_debugfs_printer); 538