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 debugfs_remove(lbs_dir); 746} 747 748void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev) 749{ 750 int i; 751 const struct lbs_debugfs_files *files; 752 if (!lbs_dir) 753 goto exit; 754 755 priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir); 756 if (!priv->debugfs_dir) 757 goto exit; 758 759 for (i=0; i<ARRAY_SIZE(debugfs_files); i++) { 760 files = &debugfs_files[i]; 761 priv->debugfs_files[i] = debugfs_create_file(files->name, 762 files->perm, 763 priv->debugfs_dir, 764 priv, 765 &files->fops); 766 } 767 768 priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir); 769 if (!priv->events_dir) 770 goto exit; 771 772 for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) { 773 files = &debugfs_events_files[i]; 774 priv->debugfs_events_files[i] = debugfs_create_file(files->name, 775 files->perm, 776 priv->events_dir, 777 priv, 778 &files->fops); 779 } 780 781 priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir); 782 if (!priv->regs_dir) 783 goto exit; 784 785 for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) { 786 files = &debugfs_regs_files[i]; 787 priv->debugfs_regs_files[i] = debugfs_create_file(files->name, 788 files->perm, 789 priv->regs_dir, 790 priv, 791 &files->fops); 792 } 793 794#ifdef PROC_DEBUG 795 lbs_debug_init(priv); 796#endif 797exit: 798 return; 799} 800 801void lbs_debugfs_remove_one(struct lbs_private *priv) 802{ 803 int i; 804 805 for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) 806 debugfs_remove(priv->debugfs_regs_files[i]); 807 808 debugfs_remove(priv->regs_dir); 809 810 for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++) 811 debugfs_remove(priv->debugfs_events_files[i]); 812 813 debugfs_remove(priv->events_dir); 814#ifdef PROC_DEBUG 815 debugfs_remove(priv->debugfs_debug); 816#endif 817 for(i=0; i<ARRAY_SIZE(debugfs_files); i++) 818 debugfs_remove(priv->debugfs_files[i]); 819 debugfs_remove(priv->debugfs_dir); 820} 821 822 823 824/* debug entry */ 825 826#ifdef PROC_DEBUG 827 828#define item_size(n) (FIELD_SIZEOF(struct lbs_private, n)) 829#define item_addr(n) (offsetof(struct lbs_private, n)) 830 831 832struct debug_data { 833 char name[32]; 834 u32 size; 835 size_t addr; 836}; 837 838/* To debug any member of struct lbs_private, simply add one line here. 839 */ 840static struct debug_data items[] = { 841 {"psmode", item_size(psmode), item_addr(psmode)}, 842 {"psstate", item_size(psstate), item_addr(psstate)}, 843}; 844 845static int num_of_items = ARRAY_SIZE(items); 846 847/** 848 * lbs_debugfs_read - proc read function 849 * 850 * @file: file to read 851 * @userbuf: pointer to buffer 852 * @count: number of bytes to read 853 * @ppos: read data starting position 854 * 855 * returns: amount of data read or negative error code 856 */ 857static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, 858 size_t count, loff_t *ppos) 859{ 860 int val = 0; 861 size_t pos = 0; 862 ssize_t res; 863 char *p; 864 int i; 865 struct debug_data *d; 866 unsigned long addr = get_zeroed_page(GFP_KERNEL); 867 char *buf = (char *)addr; 868 if (!buf) 869 return -ENOMEM; 870 871 p = buf; 872 873 d = file->private_data; 874 875 for (i = 0; i < num_of_items; i++) { 876 if (d[i].size == 1) 877 val = *((u8 *) d[i].addr); 878 else if (d[i].size == 2) 879 val = *((u16 *) d[i].addr); 880 else if (d[i].size == 4) 881 val = *((u32 *) d[i].addr); 882 else if (d[i].size == 8) 883 val = *((u64 *) d[i].addr); 884 885 pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); 886 } 887 888 res = simple_read_from_buffer(userbuf, count, ppos, p, pos); 889 890 free_page(addr); 891 return res; 892} 893 894/** 895 * lbs_debugfs_write - proc write function 896 * 897 * @f: file pointer 898 * @buf: pointer to data buffer 899 * @cnt: data number to write 900 * @ppos: file position 901 * 902 * returns: amount of data written 903 */ 904static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, 905 size_t cnt, loff_t *ppos) 906{ 907 int r, i; 908 char *pdata; 909 char *p; 910 char *p0; 911 char *p1; 912 char *p2; 913 struct debug_data *d = f->private_data; 914 915 if (cnt == 0) 916 return 0; 917 918 pdata = kmalloc(cnt + 1, GFP_KERNEL); 919 if (pdata == NULL) 920 return 0; 921 922 if (copy_from_user(pdata, buf, cnt)) { 923 lbs_deb_debugfs("Copy from user failed\n"); 924 kfree(pdata); 925 return 0; 926 } 927 pdata[cnt] = '\0'; 928 929 p0 = pdata; 930 for (i = 0; i < num_of_items; i++) { 931 do { 932 p = strstr(p0, d[i].name); 933 if (p == NULL) 934 break; 935 p1 = strchr(p, '\n'); 936 if (p1 == NULL) 937 break; 938 p0 = p1++; 939 p2 = strchr(p, '='); 940 if (!p2) 941 break; 942 p2++; 943 r = simple_strtoul(p2, NULL, 0); 944 if (d[i].size == 1) 945 *((u8 *) d[i].addr) = (u8) r; 946 else if (d[i].size == 2) 947 *((u16 *) d[i].addr) = (u16) r; 948 else if (d[i].size == 4) 949 *((u32 *) d[i].addr) = (u32) r; 950 else if (d[i].size == 8) 951 *((u64 *) d[i].addr) = (u64) r; 952 break; 953 } while (1); 954 } 955 kfree(pdata); 956 957 return (ssize_t)cnt; 958} 959 960static const struct file_operations lbs_debug_fops = { 961 .owner = THIS_MODULE, 962 .open = simple_open, 963 .write = lbs_debugfs_write, 964 .read = lbs_debugfs_read, 965 .llseek = default_llseek, 966}; 967 968/** 969 * lbs_debug_init - create debug proc file 970 * 971 * @priv: pointer to &struct lbs_private 972 * 973 * returns: N/A 974 */ 975static void lbs_debug_init(struct lbs_private *priv) 976{ 977 int i; 978 979 if (!priv->debugfs_dir) 980 return; 981 982 for (i = 0; i < num_of_items; i++) 983 items[i].addr += (size_t) priv; 984 985 priv->debugfs_debug = debugfs_create_file("debug", 0644, 986 priv->debugfs_dir, &items[0], 987 &lbs_debug_fops); 988} 989#endif 990