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