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