1 /* 2 * Copyright (c) 2017-2018 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 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) 169 170 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 171 qdf_size_t len, int rowsize, int groupsize) 172 { 173 seq_hex_dump(file, "", DUMP_PREFIX_OFFSET, rowsize, groupsize, buf, len, 174 false); 175 } 176 177 #else 178 179 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 180 qdf_size_t len, int rowsize, int groupsize) 181 { 182 char *dst; 183 size_t dstlen, readlen, remaining = len; 184 int prefix = 0; 185 size_t commitlen; 186 187 while (remaining > 0 && (file->size > file->count)) { 188 seq_printf(file, "%.8x: ", prefix); 189 190 readlen = qdf_min(remaining, (qdf_size_t)rowsize); 191 dstlen = seq_get_buf(file, &dst); 192 hex_dump_to_buffer(buf, readlen, rowsize, groupsize, dst, 193 dstlen, false); 194 commitlen = strnlen(dst, dstlen); 195 seq_commit(file, commitlen); 196 seq_putc(file, '\n'); 197 198 remaining = (remaining > rowsize) ? remaining - rowsize : 0; 199 buf += readlen; 200 prefix += rowsize; 201 } 202 } 203 204 #endif 205 206 bool qdf_debugfs_overflow(qdf_debugfs_file_t file) 207 { 208 return seq_has_overflowed(file); 209 } 210 211 void qdf_debugfs_write(qdf_debugfs_file_t file, const uint8_t *buf, 212 qdf_size_t len) 213 { 214 seq_write(file, buf, len); 215 } 216 217 /* sequential file operation table */ 218 static const struct seq_operations __qdf_debugfs_seq_ops = { 219 .start = qdf_debugfs_seq_start, 220 .next = qdf_debugfs_seq_next, 221 .stop = qdf_debugfs_seq_stop, 222 .show = qdf_debugfs_seq_show, 223 }; 224 225 /* .open() */ 226 static int qdf_seq_open(struct inode *inode, struct file *file) 227 { 228 void *private = inode->i_private; 229 struct seq_file *seq; 230 int rc; 231 232 /** 233 * Note: seq_open() will allocate a struct seq_file and store its 234 * pointer in @file->private_data. It warns if private_data is not NULL. 235 */ 236 237 rc = seq_open(file, &__qdf_debugfs_seq_ops); 238 239 if (rc == 0) { 240 seq = file->private_data; 241 seq->private = private; 242 } 243 244 return rc; 245 } 246 247 /* .write() */ 248 static ssize_t qdf_seq_write(struct file *filp, const char __user *ubuf, 249 size_t len, loff_t *ppos) 250 { 251 struct qdf_debugfs_fops *fops; 252 struct seq_file *seq; 253 u8 *buf; 254 ssize_t rc = 0; 255 256 if (len == 0) 257 return 0; 258 259 seq = filp->private_data; 260 fops = seq->private; 261 if (fops && fops->write) { 262 buf = qdf_mem_malloc(len + 1); 263 if (buf) { 264 buf[len] = '\0'; 265 rc = simple_write_to_buffer(buf, len, ppos, ubuf, len); 266 fops->write(fops->priv, buf, len + 1); 267 qdf_mem_free(buf); 268 } 269 } 270 271 return rc; 272 } 273 274 /* debugfs file operation table */ 275 static const struct file_operations __qdf_debugfs_fops = { 276 .owner = THIS_MODULE, 277 .open = qdf_seq_open, 278 .read = seq_read, 279 .llseek = seq_lseek, 280 .release = seq_release, 281 .write = qdf_seq_write, 282 }; 283 284 qdf_dentry_t qdf_debugfs_create_dir(const char *name, qdf_dentry_t parent) 285 { 286 qdf_dentry_t dir; 287 288 if (!name) 289 return NULL; 290 if (!parent) 291 parent = qdf_debugfs_get_root(); 292 293 dir = debugfs_create_dir(name, parent); 294 295 if (IS_ERR_OR_NULL(dir)) { 296 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 297 "%s creation failed", name); 298 dir = NULL; 299 } 300 301 return dir; 302 } 303 qdf_export_symbol(qdf_debugfs_create_dir); 304 305 qdf_dentry_t qdf_debugfs_create_file(const char *name, uint16_t mode, 306 qdf_dentry_t parent, 307 struct qdf_debugfs_fops *fops) 308 { 309 qdf_dentry_t file; 310 umode_t filemode; 311 312 if (!name || !fops) 313 return NULL; 314 315 if (!parent) 316 parent = qdf_debugfs_get_root(); 317 318 filemode = qdf_debugfs_get_filemode(mode); 319 file = debugfs_create_file(name, filemode, parent, fops, 320 &__qdf_debugfs_fops); 321 322 if (IS_ERR_OR_NULL(file)) { 323 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 324 "%s creation failed 0x%pK", name, file); 325 file = NULL; 326 } 327 328 return file; 329 } 330 qdf_export_symbol(qdf_debugfs_create_file); 331 332 qdf_dentry_t qdf_debugfs_create_u8(const char *name, uint16_t mode, 333 qdf_dentry_t parent, u8 *value) 334 { 335 umode_t filemode; 336 337 if (!name) 338 return NULL; 339 340 if (!parent) 341 parent = qdf_debugfs_get_root(); 342 343 filemode = qdf_debugfs_get_filemode(mode); 344 return debugfs_create_u8(name, filemode, parent, value); 345 } 346 347 qdf_dentry_t qdf_debugfs_create_u16(const char *name, uint16_t mode, 348 qdf_dentry_t parent, u16 *value) 349 { 350 umode_t filemode; 351 352 if (!name) 353 return NULL; 354 355 if (!parent) 356 parent = qdf_debugfs_get_root(); 357 358 filemode = qdf_debugfs_get_filemode(mode); 359 return debugfs_create_u16(name, filemode, parent, value); 360 } 361 qdf_export_symbol(qdf_debugfs_create_u16); 362 363 qdf_dentry_t qdf_debugfs_create_u32(const char *name, 364 uint16_t mode, 365 qdf_dentry_t parent, u32 *value) 366 { 367 umode_t filemode; 368 369 if (!name) 370 return NULL; 371 372 if (!parent) 373 parent = qdf_debugfs_get_root(); 374 375 filemode = qdf_debugfs_get_filemode(mode); 376 return debugfs_create_u32(name, filemode, parent, value); 377 } 378 qdf_export_symbol(qdf_debugfs_create_u32); 379 380 qdf_dentry_t qdf_debugfs_create_u64(const char *name, uint16_t mode, 381 qdf_dentry_t parent, u64 *value) 382 { 383 umode_t filemode; 384 385 if (!name) 386 return NULL; 387 388 if (!parent) 389 parent = qdf_debugfs_get_root(); 390 391 filemode = qdf_debugfs_get_filemode(mode); 392 return debugfs_create_u64(name, filemode, parent, value); 393 } 394 qdf_export_symbol(qdf_debugfs_create_u64); 395 396 qdf_dentry_t qdf_debugfs_create_atomic(const char *name, uint16_t mode, 397 qdf_dentry_t parent, qdf_atomic_t *value) 398 { 399 umode_t filemode; 400 401 if (!name) 402 return NULL; 403 404 if (!parent) 405 parent = qdf_debugfs_get_root(); 406 407 filemode = qdf_debugfs_get_filemode(mode); 408 return debugfs_create_atomic_t(name, filemode, parent, value); 409 } 410 qdf_export_symbol(qdf_debugfs_create_atomic); 411 412 static int qdf_debugfs_string_show(struct seq_file *seq, void *pos) 413 { 414 char *str = seq->private; 415 416 seq_puts(seq, str); 417 seq_putc(seq, '\n'); 418 419 return 0; 420 } 421 422 static int qdf_debugfs_string_open(struct inode *inode, struct file *file) 423 { 424 return single_open(file, qdf_debugfs_string_show, inode->i_private); 425 } 426 427 static const struct file_operations qdf_string_fops = { 428 .owner = THIS_MODULE, 429 .open = qdf_debugfs_string_open, 430 .read = seq_read, 431 .llseek = seq_lseek, 432 .release = single_release 433 }; 434 435 qdf_dentry_t qdf_debugfs_create_string(const char *name, uint16_t mode, 436 qdf_dentry_t parent, char *str) 437 { 438 umode_t filemode; 439 440 if (!name) 441 return NULL; 442 443 if (!parent) 444 parent = qdf_debugfs_get_root(); 445 446 filemode = qdf_debugfs_get_filemode(mode); 447 return debugfs_create_file(name, filemode, parent, str, 448 &qdf_string_fops); 449 } 450 qdf_export_symbol(qdf_debugfs_create_string); 451 452 void qdf_debugfs_remove_dir_recursive(qdf_dentry_t d) 453 { 454 debugfs_remove_recursive(d); 455 } 456 qdf_export_symbol(qdf_debugfs_remove_dir_recursive); 457 458 void qdf_debugfs_remove_dir(qdf_dentry_t d) 459 { 460 debugfs_remove(d); 461 } 462 qdf_export_symbol(qdf_debugfs_remove_dir); 463 464 void qdf_debugfs_remove_file(qdf_dentry_t d) 465 { 466 debugfs_remove(d); 467 } 468 qdf_export_symbol(qdf_debugfs_remove_file); 469