linux/drivers/net/wireless/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 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