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