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