1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/dcache.h> 3 #include <linux/debugfs.h> 4 #include <linux/delay.h> 5 #include <linux/hardirq.h> 6 #include <linux/mm.h> 7 #include <linux/string.h> 8 #include <linux/slab.h> 9 #include <linux/export.h> 10 11 #include "decl.h" 12 #include "cmd.h" 13 #include "debugfs.h" 14 15 static struct dentry *lbs_dir; 16 static char *szStates[] = { 17 "Connected", 18 "Disconnected" 19 }; 20 21 #ifdef PROC_DEBUG 22 static void lbs_debug_init(struct lbs_private *priv); 23 #endif 24 25 static ssize_t write_file_dummy(struct file *file, const char __user *buf, 26 size_t count, loff_t *ppos) 27 { 28 return -EINVAL; 29 } 30 31 static const size_t len = PAGE_SIZE; 32 33 static ssize_t lbs_dev_info(struct file *file, char __user *userbuf, 34 size_t count, loff_t *ppos) 35 { 36 struct lbs_private *priv = file->private_data; 37 size_t pos = 0; 38 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 39 ssize_t res; 40 if (!buf) 41 return -ENOMEM; 42 43 pos += snprintf(buf+pos, len-pos, "state = %s\n", 44 szStates[priv->connect_status]); 45 pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", 46 (u32) priv->regioncode); 47 48 res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 49 50 kfree(buf); 51 return res; 52 } 53 54 static ssize_t lbs_sleepparams_write(struct file *file, 55 const char __user *user_buf, size_t count, 56 loff_t *ppos) 57 { 58 struct lbs_private *priv = file->private_data; 59 ssize_t ret; 60 struct sleep_params sp; 61 int p1, p2, p3, p4, p5, p6; 62 char *buf; 63 64 buf = memdup_user_nul(user_buf, min(count, len - 1)); 65 if (IS_ERR(buf)) 66 return PTR_ERR(buf); 67 68 ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); 69 if (ret != 6) { 70 ret = -EINVAL; 71 goto out_unlock; 72 } 73 sp.sp_error = p1; 74 sp.sp_offset = p2; 75 sp.sp_stabletime = p3; 76 sp.sp_calcontrol = p4; 77 sp.sp_extsleepclk = p5; 78 sp.sp_reserved = p6; 79 80 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp); 81 if (!ret) 82 ret = count; 83 else if (ret > 0) 84 ret = -EINVAL; 85 86 out_unlock: 87 kfree(buf); 88 return ret; 89 } 90 91 static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, 92 size_t count, loff_t *ppos) 93 { 94 struct lbs_private *priv = file->private_data; 95 ssize_t ret; 96 size_t pos = 0; 97 struct sleep_params sp; 98 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 99 if (!buf) 100 return -ENOMEM; 101 102 ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); 103 if (ret) 104 goto out_unlock; 105 106 pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error, 107 sp.sp_offset, sp.sp_stabletime, 108 sp.sp_calcontrol, sp.sp_extsleepclk, 109 sp.sp_reserved); 110 111 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 112 113 out_unlock: 114 kfree(buf); 115 return ret; 116 } 117 118 static ssize_t lbs_host_sleep_write(struct file *file, 119 const char __user *user_buf, size_t count, 120 loff_t *ppos) 121 { 122 struct lbs_private *priv = file->private_data; 123 ssize_t ret; 124 int host_sleep; 125 char *buf; 126 127 buf = memdup_user_nul(user_buf, min(count, len - 1)); 128 if (IS_ERR(buf)) 129 return PTR_ERR(buf); 130 131 ret = sscanf(buf, "%d", &host_sleep); 132 if (ret != 1) { 133 ret = -EINVAL; 134 goto out_unlock; 135 } 136 137 if (host_sleep == 0) 138 ret = lbs_set_host_sleep(priv, 0); 139 else if (host_sleep == 1) { 140 if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { 141 netdev_info(priv->dev, 142 "wake parameters not configured\n"); 143 ret = -EINVAL; 144 goto out_unlock; 145 } 146 ret = lbs_set_host_sleep(priv, 1); 147 } else { 148 netdev_err(priv->dev, "invalid option\n"); 149 ret = -EINVAL; 150 } 151 152 if (!ret) 153 ret = count; 154 155 out_unlock: 156 kfree(buf); 157 return ret; 158 } 159 160 static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf, 161 size_t count, loff_t *ppos) 162 { 163 struct lbs_private *priv = file->private_data; 164 ssize_t ret; 165 size_t pos = 0; 166 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 167 if (!buf) 168 return -ENOMEM; 169 170 pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated); 171 172 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 173 174 kfree(buf); 175 return ret; 176 } 177 178 /* 179 * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might 180 * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the 181 * firmware. Here's an example: 182 * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00 183 * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03 184 * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 185 * 186 * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length, 187 * 00 00 are the data bytes of this TLV. For this TLV, their meaning is 188 * defined in mrvlietypes_thresholds 189 * 190 * This function searches in this TLV data chunk for a given TLV type 191 * and returns a pointer to the first data byte of the TLV, or to NULL 192 * if the TLV hasn't been found. 193 */ 194 static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) 195 { 196 struct mrvl_ie_header *tlv_h; 197 uint16_t length; 198 ssize_t pos = 0; 199 200 while (pos < size) { 201 tlv_h = (struct mrvl_ie_header *) tlv; 202 if (!tlv_h->len) 203 return NULL; 204 if (tlv_h->type == cpu_to_le16(tlv_type)) 205 return tlv_h; 206 length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h); 207 pos += length; 208 tlv += length; 209 } 210 return NULL; 211 } 212 213 214 static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, 215 struct file *file, char __user *userbuf, 216 size_t count, loff_t *ppos) 217 { 218 struct cmd_ds_802_11_subscribe_event *subscribed; 219 struct mrvl_ie_thresholds *got; 220 struct lbs_private *priv = file->private_data; 221 ssize_t ret = 0; 222 size_t pos = 0; 223 char *buf; 224 u8 value; 225 u8 freq; 226 int events = 0; 227 228 buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 229 if (!buf) 230 return -ENOMEM; 231 232 subscribed = kzalloc_obj(*subscribed); 233 if (!subscribed) { 234 ret = -ENOMEM; 235 goto out_page; 236 } 237 238 subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed)); 239 subscribed->action = cpu_to_le16(CMD_ACT_GET); 240 241 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed); 242 if (ret) 243 goto out_cmd; 244 245 got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv)); 246 if (got) { 247 value = got->value; 248 freq = got->freq; 249 events = le16_to_cpu(subscribed->events); 250 251 pos += snprintf(buf, len, "%d %d %d\n", value, freq, 252 !!(events & event_mask)); 253 } 254 255 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 256 257 out_cmd: 258 kfree(subscribed); 259 260 out_page: 261 kfree(buf); 262 return ret; 263 } 264 265 266 static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, 267 struct file *file, 268 const char __user *userbuf, size_t count, 269 loff_t *ppos) 270 { 271 struct cmd_ds_802_11_subscribe_event *events; 272 struct mrvl_ie_thresholds *tlv; 273 struct lbs_private *priv = file->private_data; 274 int value, freq, new_mask; 275 uint16_t curr_mask; 276 char *buf; 277 int ret; 278 279 buf = memdup_user_nul(userbuf, min(count, len - 1)); 280 if (IS_ERR(buf)) 281 return PTR_ERR(buf); 282 283 ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask); 284 if (ret != 3) { 285 ret = -EINVAL; 286 goto out_page; 287 } 288 events = kzalloc_obj(*events); 289 if (!events) { 290 ret = -ENOMEM; 291 goto out_page; 292 } 293 294 events->hdr.size = cpu_to_le16(sizeof(*events)); 295 events->action = cpu_to_le16(CMD_ACT_GET); 296 297 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); 298 if (ret) 299 goto out_events; 300 301 curr_mask = le16_to_cpu(events->events); 302 303 if (new_mask) 304 new_mask = curr_mask | event_mask; 305 else 306 new_mask = curr_mask & ~event_mask; 307 308 /* Now everything is set and we can send stuff down to the firmware */ 309 310 tlv = (void *)events->tlv; 311 312 events->action = cpu_to_le16(CMD_ACT_SET); 313 events->events = cpu_to_le16(new_mask); 314 tlv->header.type = cpu_to_le16(tlv_type); 315 tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header)); 316 tlv->value = value; 317 if (tlv_type != TLV_TYPE_BCNMISS) 318 tlv->freq = freq; 319 320 /* The command header, the action, the event mask, and one TLV */ 321 events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv)); 322 323 ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); 324 325 if (!ret) 326 ret = count; 327 out_events: 328 kfree(events); 329 out_page: 330 kfree(buf); 331 return ret; 332 } 333 334 335 static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf, 336 size_t count, loff_t *ppos) 337 { 338 return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, 339 file, userbuf, count, ppos); 340 } 341 342 343 static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf, 344 size_t count, loff_t *ppos) 345 { 346 return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, 347 file, userbuf, count, ppos); 348 } 349 350 351 static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf, 352 size_t count, loff_t *ppos) 353 { 354 return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, 355 file, userbuf, count, ppos); 356 } 357 358 359 static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf, 360 size_t count, loff_t *ppos) 361 { 362 return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, 363 file, userbuf, count, ppos); 364 } 365 366 367 static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf, 368 size_t count, loff_t *ppos) 369 { 370 return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, 371 file, userbuf, count, ppos); 372 } 373 374 375 static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf, 376 size_t count, loff_t *ppos) 377 { 378 return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, 379 file, userbuf, count, ppos); 380 } 381 382 383 static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf, 384 size_t count, loff_t *ppos) 385 { 386 return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, 387 file, userbuf, count, ppos); 388 } 389 390 391 static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf, 392 size_t count, loff_t *ppos) 393 { 394 return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, 395 file, userbuf, count, ppos); 396 } 397 398 399 static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf, 400 size_t count, loff_t *ppos) 401 { 402 return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, 403 file, userbuf, count, ppos); 404 } 405 406 407 static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf, 408 size_t count, loff_t *ppos) 409 { 410 return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, 411 file, userbuf, count, ppos); 412 } 413 414 static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf, 415 size_t count, loff_t *ppos) 416 { 417 return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, 418 file, userbuf, count, ppos); 419 } 420 421 422 static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf, 423 size_t count, loff_t *ppos) 424 { 425 return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, 426 file, userbuf, count, ppos); 427 } 428 429 430 static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, 431 size_t count, loff_t *ppos) 432 { 433 struct lbs_private *priv = file->private_data; 434 ssize_t pos = 0; 435 int ret; 436 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 437 u32 val = 0; 438 439 if (!buf) 440 return -ENOMEM; 441 442 ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val); 443 mdelay(10); 444 if (!ret) { 445 pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n", 446 priv->mac_offset, val); 447 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 448 } 449 kfree(buf); 450 return ret; 451 } 452 453 static ssize_t lbs_rdmac_write(struct file *file, 454 const char __user *userbuf, 455 size_t count, loff_t *ppos) 456 { 457 struct lbs_private *priv = file->private_data; 458 char *buf; 459 460 buf = memdup_user_nul(userbuf, min(count, len - 1)); 461 if (IS_ERR(buf)) 462 return PTR_ERR(buf); 463 464 priv->mac_offset = simple_strtoul(buf, NULL, 16); 465 kfree(buf); 466 return count; 467 } 468 469 static ssize_t lbs_wrmac_write(struct file *file, 470 const char __user *userbuf, 471 size_t count, loff_t *ppos) 472 { 473 474 struct lbs_private *priv = file->private_data; 475 ssize_t res; 476 u32 offset, value; 477 char *buf; 478 479 buf = memdup_user_nul(userbuf, min(count, len - 1)); 480 if (IS_ERR(buf)) 481 return PTR_ERR(buf); 482 483 res = sscanf(buf, "%x %x", &offset, &value); 484 if (res != 2) { 485 res = -EFAULT; 486 goto out_unlock; 487 } 488 489 res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value); 490 mdelay(10); 491 492 if (!res) 493 res = count; 494 out_unlock: 495 kfree(buf); 496 return res; 497 } 498 499 static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, 500 size_t count, loff_t *ppos) 501 { 502 struct lbs_private *priv = file->private_data; 503 ssize_t pos = 0; 504 int ret; 505 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 506 u32 val; 507 508 if (!buf) 509 return -ENOMEM; 510 511 ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val); 512 mdelay(10); 513 if (!ret) { 514 pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n", 515 priv->bbp_offset, val); 516 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 517 } 518 kfree(buf); 519 520 return ret; 521 } 522 523 static ssize_t lbs_rdbbp_write(struct file *file, 524 const char __user *userbuf, 525 size_t count, loff_t *ppos) 526 { 527 struct lbs_private *priv = file->private_data; 528 char *buf; 529 530 buf = memdup_user_nul(userbuf, min(count, len - 1)); 531 if (IS_ERR(buf)) 532 return PTR_ERR(buf); 533 534 priv->bbp_offset = simple_strtoul(buf, NULL, 16); 535 kfree(buf); 536 537 return count; 538 } 539 540 static ssize_t lbs_wrbbp_write(struct file *file, 541 const char __user *userbuf, 542 size_t count, loff_t *ppos) 543 { 544 545 struct lbs_private *priv = file->private_data; 546 ssize_t res; 547 u32 offset, value; 548 char *buf; 549 550 buf = memdup_user_nul(userbuf, min(count, len - 1)); 551 if (IS_ERR(buf)) 552 return PTR_ERR(buf); 553 554 res = sscanf(buf, "%x %x", &offset, &value); 555 if (res != 2) { 556 res = -EFAULT; 557 goto out_unlock; 558 } 559 560 res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value); 561 mdelay(10); 562 563 if (!res) 564 res = count; 565 out_unlock: 566 kfree(buf); 567 return res; 568 } 569 570 static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, 571 size_t count, loff_t *ppos) 572 { 573 struct lbs_private *priv = file->private_data; 574 ssize_t pos = 0; 575 int ret; 576 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 577 u32 val; 578 579 if (!buf) 580 return -ENOMEM; 581 582 ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val); 583 mdelay(10); 584 if (!ret) { 585 pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n", 586 priv->rf_offset, val); 587 ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 588 } 589 kfree(buf); 590 591 return ret; 592 } 593 594 static ssize_t lbs_rdrf_write(struct file *file, 595 const char __user *userbuf, 596 size_t count, loff_t *ppos) 597 { 598 struct lbs_private *priv = file->private_data; 599 char *buf; 600 601 buf = memdup_user_nul(userbuf, min(count, len - 1)); 602 if (IS_ERR(buf)) 603 return PTR_ERR(buf); 604 605 priv->rf_offset = simple_strtoul(buf, NULL, 16); 606 kfree(buf); 607 return count; 608 } 609 610 static ssize_t lbs_wrrf_write(struct file *file, 611 const char __user *userbuf, 612 size_t count, loff_t *ppos) 613 { 614 615 struct lbs_private *priv = file->private_data; 616 ssize_t res; 617 u32 offset, value; 618 char *buf; 619 620 buf = memdup_user_nul(userbuf, min(count, len - 1)); 621 if (IS_ERR(buf)) 622 return PTR_ERR(buf); 623 624 res = sscanf(buf, "%x %x", &offset, &value); 625 if (res != 2) { 626 res = -EFAULT; 627 goto out_unlock; 628 } 629 630 res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value); 631 mdelay(10); 632 633 if (!res) 634 res = count; 635 out_unlock: 636 kfree(buf); 637 return res; 638 } 639 640 #define FOPS(fread, fwrite) { \ 641 .owner = THIS_MODULE, \ 642 .open = simple_open, \ 643 .read = (fread), \ 644 .write = (fwrite), \ 645 .llseek = generic_file_llseek, \ 646 } 647 648 struct lbs_debugfs_files { 649 const char *name; 650 umode_t perm; 651 struct file_operations fops; 652 }; 653 654 static const struct lbs_debugfs_files debugfs_files[] = { 655 { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, 656 { "sleepparams", 0644, FOPS(lbs_sleepparams_read, 657 lbs_sleepparams_write), }, 658 { "hostsleep", 0644, FOPS(lbs_host_sleep_read, 659 lbs_host_sleep_write), }, 660 }; 661 662 static const struct lbs_debugfs_files debugfs_events_files[] = { 663 {"low_rssi", 0644, FOPS(lbs_lowrssi_read, 664 lbs_lowrssi_write), }, 665 {"low_snr", 0644, FOPS(lbs_lowsnr_read, 666 lbs_lowsnr_write), }, 667 {"failure_count", 0644, FOPS(lbs_failcount_read, 668 lbs_failcount_write), }, 669 {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read, 670 lbs_bcnmiss_write), }, 671 {"high_rssi", 0644, FOPS(lbs_highrssi_read, 672 lbs_highrssi_write), }, 673 {"high_snr", 0644, FOPS(lbs_highsnr_read, 674 lbs_highsnr_write), }, 675 }; 676 677 static const struct lbs_debugfs_files debugfs_regs_files[] = { 678 {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), }, 679 {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), }, 680 {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), }, 681 {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), }, 682 {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), }, 683 {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), }, 684 }; 685 686 void lbs_debugfs_init(void) 687 { 688 if (!lbs_dir) 689 lbs_dir = debugfs_create_dir("lbs_wireless", NULL); 690 } 691 692 void lbs_debugfs_remove(void) 693 { 694 debugfs_remove(lbs_dir); 695 } 696 697 void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev) 698 { 699 int i; 700 const struct lbs_debugfs_files *files; 701 if (!lbs_dir) 702 goto exit; 703 704 priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir); 705 706 for (i=0; i<ARRAY_SIZE(debugfs_files); i++) { 707 files = &debugfs_files[i]; 708 priv->debugfs_files[i] = debugfs_create_file(files->name, 709 files->perm, 710 priv->debugfs_dir, 711 priv, 712 &files->fops); 713 } 714 715 priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir); 716 717 for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) { 718 files = &debugfs_events_files[i]; 719 priv->debugfs_events_files[i] = debugfs_create_file(files->name, 720 files->perm, 721 priv->events_dir, 722 priv, 723 &files->fops); 724 } 725 726 priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir); 727 728 for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) { 729 files = &debugfs_regs_files[i]; 730 priv->debugfs_regs_files[i] = debugfs_create_file(files->name, 731 files->perm, 732 priv->regs_dir, 733 priv, 734 &files->fops); 735 } 736 737 #ifdef PROC_DEBUG 738 lbs_debug_init(priv); 739 #endif 740 exit: 741 return; 742 } 743 744 void lbs_debugfs_remove_one(struct lbs_private *priv) 745 { 746 int i; 747 748 for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) 749 debugfs_remove(priv->debugfs_regs_files[i]); 750 751 debugfs_remove(priv->regs_dir); 752 753 for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++) 754 debugfs_remove(priv->debugfs_events_files[i]); 755 756 debugfs_remove(priv->events_dir); 757 #ifdef PROC_DEBUG 758 debugfs_remove(priv->debugfs_debug); 759 #endif 760 for(i=0; i<ARRAY_SIZE(debugfs_files); i++) 761 debugfs_remove(priv->debugfs_files[i]); 762 debugfs_remove(priv->debugfs_dir); 763 } 764 765 766 767 /* debug entry */ 768 769 #ifdef PROC_DEBUG 770 771 #define item_size(n) (sizeof_field(struct lbs_private, n)) 772 #define item_addr(n) (offsetof(struct lbs_private, n)) 773 774 775 struct debug_data { 776 char name[32]; 777 u32 size; 778 size_t addr; 779 }; 780 781 /* To debug any member of struct lbs_private, simply add one line here. 782 */ 783 static struct debug_data items[] = { 784 {"psmode", item_size(psmode), item_addr(psmode)}, 785 {"psstate", item_size(psstate), item_addr(psstate)}, 786 }; 787 788 static int num_of_items = ARRAY_SIZE(items); 789 790 /** 791 * lbs_debugfs_read - proc read function 792 * 793 * @file: file to read 794 * @userbuf: pointer to buffer 795 * @count: number of bytes to read 796 * @ppos: read data starting position 797 * 798 * returns: amount of data read or negative error code 799 */ 800 static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, 801 size_t count, loff_t *ppos) 802 { 803 int val = 0; 804 size_t pos = 0; 805 ssize_t res; 806 char *p; 807 int i; 808 struct debug_data *d; 809 char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 810 if (!buf) 811 return -ENOMEM; 812 813 p = buf; 814 815 d = file->private_data; 816 817 for (i = 0; i < num_of_items; i++) { 818 if (d[i].size == 1) 819 val = *((u8 *) d[i].addr); 820 else if (d[i].size == 2) 821 val = *((u16 *) d[i].addr); 822 else if (d[i].size == 4) 823 val = *((u32 *) d[i].addr); 824 else if (d[i].size == 8) 825 val = *((u64 *) d[i].addr); 826 827 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); 828 } 829 830 res = simple_read_from_buffer(userbuf, count, ppos, p, pos); 831 832 kfree(buf); 833 return res; 834 } 835 836 /** 837 * lbs_debugfs_write - proc write function 838 * 839 * @f: file pointer 840 * @buf: pointer to data buffer 841 * @cnt: data number to write 842 * @ppos: file position 843 * 844 * returns: amount of data written 845 */ 846 static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, 847 size_t cnt, loff_t *ppos) 848 { 849 int r, i; 850 char *pdata; 851 char *p; 852 char *p0; 853 char *p1; 854 char *p2; 855 struct debug_data *d = f->private_data; 856 857 if (cnt == 0) 858 return 0; 859 860 pdata = memdup_user_nul(buf, cnt); 861 if (IS_ERR(pdata)) 862 return PTR_ERR(pdata); 863 864 p0 = pdata; 865 for (i = 0; i < num_of_items; i++) { 866 do { 867 p = strstr(p0, d[i].name); 868 if (p == NULL) 869 break; 870 p1 = strchr(p, '\n'); 871 if (p1 == NULL) 872 break; 873 p0 = p1++; 874 p2 = strchr(p, '='); 875 if (!p2) 876 break; 877 p2++; 878 r = simple_strtoul(p2, NULL, 0); 879 if (d[i].size == 1) 880 *((u8 *) d[i].addr) = (u8) r; 881 else if (d[i].size == 2) 882 *((u16 *) d[i].addr) = (u16) r; 883 else if (d[i].size == 4) 884 *((u32 *) d[i].addr) = (u32) r; 885 else if (d[i].size == 8) 886 *((u64 *) d[i].addr) = (u64) r; 887 break; 888 } while (1); 889 } 890 kfree(pdata); 891 892 return (ssize_t)cnt; 893 } 894 895 static const struct file_operations lbs_debug_fops = { 896 .owner = THIS_MODULE, 897 .open = simple_open, 898 .write = lbs_debugfs_write, 899 .read = lbs_debugfs_read, 900 .llseek = default_llseek, 901 }; 902 903 /** 904 * lbs_debug_init - create debug proc file 905 * 906 * @priv: pointer to &struct lbs_private 907 * 908 * returns: N/A 909 */ 910 static void lbs_debug_init(struct lbs_private *priv) 911 { 912 int i; 913 914 if (!priv->debugfs_dir) 915 return; 916 917 for (i = 0; i < num_of_items; i++) 918 items[i].addr += (size_t) priv; 919 920 priv->debugfs_debug = debugfs_create_file("debug", 0644, 921 priv->debugfs_dir, &items[0], 922 &lbs_debug_fops); 923 } 924 #endif 925