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 QDF_STATUS qdf_debugfs_exit(void) 50 { 51 if (!qdf_debugfs_root) 52 return QDF_STATUS_SUCCESS; 53 54 debugfs_remove_recursive(qdf_debugfs_root); 55 qdf_debugfs_root = NULL; 56 57 return QDF_STATUS_SUCCESS; 58 } 59 qdf_export_symbol(qdf_debugfs_exit); 60 61 qdf_dentry_t qdf_debugfs_get_root(void) 62 { 63 return qdf_debugfs_root; 64 } 65 qdf_export_symbol(qdf_debugfs_get_root); 66 67 umode_t qdf_debugfs_get_filemode(uint16_t mode) 68 { 69 umode_t ret = 0; 70 71 if (mode & QDF_FILE_USR_READ) 72 ret |= 0400; 73 if (mode & QDF_FILE_USR_WRITE) 74 ret |= 0200; 75 76 if (mode & QDF_FILE_GRP_READ) 77 ret |= 0040; 78 if (mode & QDF_FILE_GRP_WRITE) 79 ret |= 0020; 80 81 if (mode & QDF_FILE_OTH_READ) 82 ret |= 0004; 83 if (mode & QDF_FILE_OTH_WRITE) 84 ret |= 0002; 85 86 return ret; 87 } 88 89 /** 90 * ---------------------- Implementation note --------------------------------- 91 * 92 * A read in debugfs file triggers seq_read() which calls seq_read api. A 93 * sequence begins with the call of the function start(). If the return is a non 94 * NULL value, the function next() is called. This function is an iterator, the 95 * goal is to go though all the data. Each time next() is called, the function 96 * show() is also called. It writes data values in the buffer read by the user. 97 * The function next() is called until it returns NULL. The sequence ends when 98 * next() returns NULL, then the function stop() is called. 99 * 100 * NOTE: When a sequence is finished, another one starts. That means that 101 * at the end of function stop(), the function start() is called again. This 102 * loop finishes when the function start() returns NULL. 103 * ---------------------------------------------------------------------------- 104 */ 105 106 /* .seq_start() */ 107 static void *qdf_debugfs_seq_start(struct seq_file *seq, loff_t *pos) 108 { 109 struct qdf_debugfs_seq_priv *priv; 110 111 priv = qdf_mem_malloc(sizeof(*priv)); 112 if (!priv) 113 return NULL; 114 115 priv->stop = false; 116 117 return priv; 118 } 119 120 /* .seq_next() */ 121 static void *qdf_debugfs_seq_next(struct seq_file *seq, void *v, loff_t *pos) 122 { 123 struct qdf_debugfs_seq_priv *priv = v; 124 125 if (priv) 126 ++*pos; 127 128 if (priv && priv->stop) { 129 qdf_mem_free(priv); 130 priv = NULL; 131 } 132 133 return priv; 134 } 135 136 /* .seq_stop() */ 137 static void qdf_debugfs_seq_stop(struct seq_file *seq, void *v) 138 { 139 qdf_mem_free(v); 140 } 141 142 /* .seq_show() */ 143 static int qdf_debugfs_seq_show(struct seq_file *seq, void *v) 144 { 145 struct qdf_debugfs_seq_priv *priv = v; 146 struct qdf_debugfs_fops *fops; 147 QDF_STATUS status; 148 149 fops = seq->private; 150 151 if (fops && fops->show) { 152 status = fops->show(seq, fops->priv); 153 154 if (priv && (status != QDF_STATUS_E_AGAIN)) 155 priv->stop = true; 156 } 157 158 return 0; 159 } 160 161 void qdf_debugfs_printf(qdf_debugfs_file_t file, const char *f, ...) 162 { 163 va_list args; 164 165 va_start(args, f); 166 seq_vprintf(file, f, args); 167 va_end(args); 168 } 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) 174 { 175 seq_hex_dump(file, "", DUMP_PREFIX_OFFSET, 16, 4, buf, len, false); 176 } 177 178 #else 179 180 void qdf_debugfs_hexdump(qdf_debugfs_file_t file, const uint8_t *buf, 181 qdf_size_t len) 182 { 183 const size_t rowsize = 16; 184 const size_t groupsize = 4; 185 char *dst; 186 size_t dstlen, readlen; 187 int prefix = 0; 188 size_t commitlen; 189 190 while (len > 0 && (file->size > file->count)) { 191 seq_printf(file, "%.8x: ", prefix); 192 193 readlen = min(len, rowsize); 194 dstlen = seq_get_buf(file, &dst); 195 hex_dump_to_buffer(buf, readlen, rowsize, groupsize, dst, 196 dstlen, false); 197 commitlen = strnlen(dst, dstlen); 198 seq_commit(file, commitlen); 199 seq_putc(file, '\n'); 200 201 len = (len > rowsize) ? len - rowsize : 0; 202 buf += readlen; 203 prefix += rowsize; 204 } 205 } 206 207 #endif 208 209 void qdf_debugfs_write(qdf_debugfs_file_t file, const uint8_t *buf, 210 qdf_size_t len) 211 { 212 seq_write(file, buf, len); 213 } 214 215 /* sequential file operation table */ 216 static const struct seq_operations __qdf_debugfs_seq_ops = { 217 .start = qdf_debugfs_seq_start, 218 .next = qdf_debugfs_seq_next, 219 .stop = qdf_debugfs_seq_stop, 220 .show = qdf_debugfs_seq_show, 221 }; 222 223 /* .open() */ 224 static int qdf_seq_open(struct inode *inode, struct file *file) 225 { 226 void *private = inode->i_private; 227 struct seq_file *seq; 228 int rc; 229 230 /** 231 * Note: seq_open() will allocate a struct seq_file and store its 232 * pointer in @file->private_data. It warns if private_data is not NULL. 233 */ 234 235 rc = seq_open(file, &__qdf_debugfs_seq_ops); 236 237 if (rc == 0) { 238 seq = file->private_data; 239 seq->private = private; 240 } 241 242 return rc; 243 } 244 245 /* .write() */ 246 static ssize_t qdf_seq_write(struct file *filp, const char __user *ubuf, 247 size_t len, loff_t *ppos) 248 { 249 struct qdf_debugfs_fops *fops; 250 struct seq_file *seq; 251 u8 *buf; 252 ssize_t rc = 0; 253 254 if (len == 0) 255 return 0; 256 257 seq = filp->private_data; 258 fops = seq->private; 259 if (fops && fops->write) { 260 buf = qdf_mem_malloc(len + 1); 261 if (buf) { 262 buf[len] = '\0'; 263 rc = simple_write_to_buffer(buf, len, ppos, ubuf, len); 264 fops->write(fops->priv, buf, len + 1); 265 qdf_mem_free(buf); 266 } 267 } 268 269 return rc; 270 } 271 272 /* debugfs file operation table */ 273 static const struct file_operations __qdf_debugfs_fops = { 274 .owner = THIS_MODULE, 275 .open = qdf_seq_open, 276 .read = seq_read, 277 .llseek = seq_lseek, 278 .release = seq_release, 279 .write = qdf_seq_write, 280 }; 281 282 qdf_dentry_t qdf_debugfs_create_dir(const char *name, qdf_dentry_t parent) 283 { 284 qdf_dentry_t dir; 285 286 if (!name) 287 return NULL; 288 if (!parent) 289 parent = qdf_debugfs_get_root(); 290 291 dir = debugfs_create_dir(name, parent); 292 293 if (IS_ERR_OR_NULL(dir)) { 294 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 295 "%s creation failed", name); 296 dir = NULL; 297 } 298 299 return dir; 300 } 301 qdf_export_symbol(qdf_debugfs_create_dir); 302 303 qdf_dentry_t qdf_debugfs_create_file(const char *name, uint16_t mode, 304 qdf_dentry_t parent, 305 struct qdf_debugfs_fops *fops) 306 { 307 qdf_dentry_t file; 308 umode_t filemode; 309 310 if (!name || !fops) 311 return NULL; 312 313 if (!parent) 314 parent = qdf_debugfs_get_root(); 315 316 filemode = qdf_debugfs_get_filemode(mode); 317 file = debugfs_create_file(name, filemode, parent, fops, 318 &__qdf_debugfs_fops); 319 320 if (IS_ERR_OR_NULL(file)) { 321 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, 322 "%s creation failed 0x%pK", name, file); 323 file = NULL; 324 } 325 326 return file; 327 } 328 qdf_export_symbol(qdf_debugfs_create_file); 329 330 qdf_dentry_t qdf_debugfs_create_u8(const char *name, uint16_t mode, 331 qdf_dentry_t parent, u8 *value) 332 { 333 umode_t filemode; 334 335 if (!name) 336 return NULL; 337 338 if (!parent) 339 parent = qdf_debugfs_get_root(); 340 341 filemode = qdf_debugfs_get_filemode(mode); 342 return debugfs_create_u8(name, filemode, parent, value); 343 } 344 345 qdf_dentry_t qdf_debugfs_create_u16(const char *name, uint16_t mode, 346 qdf_dentry_t parent, u16 *value) 347 { 348 umode_t filemode; 349 350 if (!name) 351 return NULL; 352 353 if (!parent) 354 parent = qdf_debugfs_get_root(); 355 356 filemode = qdf_debugfs_get_filemode(mode); 357 return debugfs_create_u16(name, filemode, parent, value); 358 } 359 qdf_export_symbol(qdf_debugfs_create_u16); 360 361 qdf_dentry_t qdf_debugfs_create_u32(const char *name, 362 uint16_t mode, 363 qdf_dentry_t parent, u32 *value) 364 { 365 umode_t filemode; 366 367 if (!name) 368 return NULL; 369 370 if (!parent) 371 parent = qdf_debugfs_get_root(); 372 373 filemode = qdf_debugfs_get_filemode(mode); 374 return debugfs_create_u32(name, filemode, parent, value); 375 } 376 qdf_export_symbol(qdf_debugfs_create_u32); 377 378 qdf_dentry_t qdf_debugfs_create_u64(const char *name, uint16_t mode, 379 qdf_dentry_t parent, u64 *value) 380 { 381 umode_t filemode; 382 383 if (!name) 384 return NULL; 385 386 if (!parent) 387 parent = qdf_debugfs_get_root(); 388 389 filemode = qdf_debugfs_get_filemode(mode); 390 return debugfs_create_u64(name, filemode, parent, value); 391 } 392 qdf_export_symbol(qdf_debugfs_create_u64); 393 394 qdf_dentry_t qdf_debugfs_create_atomic(const char *name, uint16_t mode, 395 qdf_dentry_t parent, qdf_atomic_t *value) 396 { 397 umode_t filemode; 398 399 if (!name) 400 return NULL; 401 402 if (!parent) 403 parent = qdf_debugfs_get_root(); 404 405 filemode = qdf_debugfs_get_filemode(mode); 406 return debugfs_create_atomic_t(name, filemode, parent, value); 407 } 408 qdf_export_symbol(qdf_debugfs_create_atomic); 409 410 static int qdf_debugfs_string_show(struct seq_file *seq, void *pos) 411 { 412 char *str = seq->private; 413 414 seq_puts(seq, str); 415 seq_putc(seq, '\n'); 416 417 return 0; 418 } 419 420 static int qdf_debugfs_string_open(struct inode *inode, struct file *file) 421 { 422 return single_open(file, qdf_debugfs_string_show, inode->i_private); 423 } 424 425 static const struct file_operations qdf_string_fops = { 426 .owner = THIS_MODULE, 427 .open = qdf_debugfs_string_open, 428 .read = seq_read, 429 .llseek = seq_lseek, 430 .release = single_release 431 }; 432 433 qdf_dentry_t qdf_debugfs_create_string(const char *name, uint16_t mode, 434 qdf_dentry_t parent, char *str) 435 { 436 umode_t filemode; 437 438 if (!name) 439 return NULL; 440 441 if (!parent) 442 parent = qdf_debugfs_get_root(); 443 444 filemode = qdf_debugfs_get_filemode(mode); 445 return debugfs_create_file(name, filemode, parent, str, 446 &qdf_string_fops); 447 } 448 qdf_export_symbol(qdf_debugfs_create_string); 449 450 void qdf_debugfs_remove_dir_recursive(qdf_dentry_t d) 451 { 452 debugfs_remove_recursive(d); 453 } 454 qdf_export_symbol(qdf_debugfs_remove_dir_recursive); 455 456 void qdf_debugfs_remove_dir(qdf_dentry_t d) 457 { 458 debugfs_remove(d); 459 } 460 qdf_export_symbol(qdf_debugfs_remove_dir); 461 462 void qdf_debugfs_remove_file(qdf_dentry_t d) 463 { 464 debugfs_remove(d); 465 } 466 qdf_export_symbol(qdf_debugfs_remove_file); 467