linux/drivers/net/wireless/mwifiex/debugfs.c
<<
>>
Prefs
   1/*
   2 * Marvell Wireless LAN device driver: debugfs
   3 *
   4 * Copyright (C) 2011, Marvell International Ltd.
   5 *
   6 * This software file (the "File") is distributed by Marvell International
   7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
   8 * (the "License").  You may use, redistribute and/or modify this File in
   9 * accordance with the terms and conditions of the License, a copy of which
  10 * is available by writing to the Free Software Foundation, Inc.,
  11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  13 *
  14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  16 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  17 * this warranty disclaimer.
  18 */
  19
  20#include <linux/debugfs.h>
  21
  22#include "main.h"
  23#include "11n.h"
  24
  25
  26static struct dentry *mwifiex_dfs_dir;
  27
  28static char *bss_modes[] = {
  29        "UNSPECIFIED",
  30        "ADHOC",
  31        "STATION",
  32        "AP",
  33        "AP_VLAN",
  34        "WDS",
  35        "MONITOR",
  36        "MESH_POINT",
  37        "P2P_CLIENT",
  38        "P2P_GO",
  39        "P2P_DEVICE",
  40};
  41
  42/* size/addr for mwifiex_debug_info */
  43#define item_size(n)            (FIELD_SIZEOF(struct mwifiex_debug_info, n))
  44#define item_addr(n)            (offsetof(struct mwifiex_debug_info, n))
  45
  46/* size/addr for struct mwifiex_adapter */
  47#define adapter_item_size(n)    (FIELD_SIZEOF(struct mwifiex_adapter, n))
  48#define adapter_item_addr(n)    (offsetof(struct mwifiex_adapter, n))
  49
  50struct mwifiex_debug_data {
  51        char name[32];          /* variable/array name */
  52        u32 size;               /* size of the variable/array */
  53        size_t addr;            /* address of the variable/array */
  54        int num;                /* number of variables in an array */
  55};
  56
  57static struct mwifiex_debug_data items[] = {
  58        {"int_counter", item_size(int_counter),
  59         item_addr(int_counter), 1},
  60        {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
  61         item_addr(packets_out[WMM_AC_VO]), 1},
  62        {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
  63         item_addr(packets_out[WMM_AC_VI]), 1},
  64        {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
  65         item_addr(packets_out[WMM_AC_BE]), 1},
  66        {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
  67         item_addr(packets_out[WMM_AC_BK]), 1},
  68        {"tx_buf_size", item_size(tx_buf_size),
  69         item_addr(tx_buf_size), 1},
  70        {"curr_tx_buf_size", item_size(curr_tx_buf_size),
  71         item_addr(curr_tx_buf_size), 1},
  72        {"ps_mode", item_size(ps_mode),
  73         item_addr(ps_mode), 1},
  74        {"ps_state", item_size(ps_state),
  75         item_addr(ps_state), 1},
  76        {"is_deep_sleep", item_size(is_deep_sleep),
  77         item_addr(is_deep_sleep), 1},
  78        {"wakeup_dev_req", item_size(pm_wakeup_card_req),
  79         item_addr(pm_wakeup_card_req), 1},
  80        {"wakeup_tries", item_size(pm_wakeup_fw_try),
  81         item_addr(pm_wakeup_fw_try), 1},
  82        {"hs_configured", item_size(is_hs_configured),
  83         item_addr(is_hs_configured), 1},
  84        {"hs_activated", item_size(hs_activated),
  85         item_addr(hs_activated), 1},
  86        {"num_tx_timeout", item_size(num_tx_timeout),
  87         item_addr(num_tx_timeout), 1},
  88        {"num_cmd_timeout", item_size(num_cmd_timeout),
  89         item_addr(num_cmd_timeout), 1},
  90        {"timeout_cmd_id", item_size(timeout_cmd_id),
  91         item_addr(timeout_cmd_id), 1},
  92        {"timeout_cmd_act", item_size(timeout_cmd_act),
  93         item_addr(timeout_cmd_act), 1},
  94        {"last_cmd_id", item_size(last_cmd_id),
  95         item_addr(last_cmd_id), DBG_CMD_NUM},
  96        {"last_cmd_act", item_size(last_cmd_act),
  97         item_addr(last_cmd_act), DBG_CMD_NUM},
  98        {"last_cmd_index", item_size(last_cmd_index),
  99         item_addr(last_cmd_index), 1},
 100        {"last_cmd_resp_id", item_size(last_cmd_resp_id),
 101         item_addr(last_cmd_resp_id), DBG_CMD_NUM},
 102        {"last_cmd_resp_index", item_size(last_cmd_resp_index),
 103         item_addr(last_cmd_resp_index), 1},
 104        {"last_event", item_size(last_event),
 105         item_addr(last_event), DBG_CMD_NUM},
 106        {"last_event_index", item_size(last_event_index),
 107         item_addr(last_event_index), 1},
 108        {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
 109         item_addr(num_cmd_host_to_card_failure), 1},
 110        {"num_cmd_sleep_cfm_fail",
 111         item_size(num_cmd_sleep_cfm_host_to_card_failure),
 112         item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
 113        {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
 114         item_addr(num_tx_host_to_card_failure), 1},
 115        {"num_evt_deauth", item_size(num_event_deauth),
 116         item_addr(num_event_deauth), 1},
 117        {"num_evt_disassoc", item_size(num_event_disassoc),
 118         item_addr(num_event_disassoc), 1},
 119        {"num_evt_link_lost", item_size(num_event_link_lost),
 120         item_addr(num_event_link_lost), 1},
 121        {"num_cmd_deauth", item_size(num_cmd_deauth),
 122         item_addr(num_cmd_deauth), 1},
 123        {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
 124         item_addr(num_cmd_assoc_success), 1},
 125        {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
 126         item_addr(num_cmd_assoc_failure), 1},
 127        {"cmd_sent", item_size(cmd_sent),
 128         item_addr(cmd_sent), 1},
 129        {"data_sent", item_size(data_sent),
 130         item_addr(data_sent), 1},
 131        {"cmd_resp_received", item_size(cmd_resp_received),
 132         item_addr(cmd_resp_received), 1},
 133        {"event_received", item_size(event_received),
 134         item_addr(event_received), 1},
 135
 136        /* variables defined in struct mwifiex_adapter */
 137        {"cmd_pending", adapter_item_size(cmd_pending),
 138         adapter_item_addr(cmd_pending), 1},
 139        {"tx_pending", adapter_item_size(tx_pending),
 140         adapter_item_addr(tx_pending), 1},
 141        {"rx_pending", adapter_item_size(rx_pending),
 142         adapter_item_addr(rx_pending), 1},
 143};
 144
 145static int num_of_items = ARRAY_SIZE(items);
 146
 147/*
 148 * Proc info file read handler.
 149 *
 150 * This function is called when the 'info' file is opened for reading.
 151 * It prints the following driver related information -
 152 *      - Driver name
 153 *      - Driver version
 154 *      - Driver extended version
 155 *      - Interface name
 156 *      - BSS mode
 157 *      - Media state (connected or disconnected)
 158 *      - MAC address
 159 *      - Total number of Tx bytes
 160 *      - Total number of Rx bytes
 161 *      - Total number of Tx packets
 162 *      - Total number of Rx packets
 163 *      - Total number of dropped Tx packets
 164 *      - Total number of dropped Rx packets
 165 *      - Total number of corrupted Tx packets
 166 *      - Total number of corrupted Rx packets
 167 *      - Carrier status (on or off)
 168 *      - Tx queue status (started or stopped)
 169 *
 170 * For STA mode drivers, it also prints the following extra -
 171 *      - ESSID
 172 *      - BSSID
 173 *      - Channel
 174 *      - Region code
 175 *      - Multicast count
 176 *      - Multicast addresses
 177 */
 178static ssize_t
 179mwifiex_info_read(struct file *file, char __user *ubuf,
 180                  size_t count, loff_t *ppos)
 181{
 182        struct mwifiex_private *priv =
 183                (struct mwifiex_private *) file->private_data;
 184        struct net_device *netdev = priv->netdev;
 185        struct netdev_hw_addr *ha;
 186        struct netdev_queue *txq;
 187        unsigned long page = get_zeroed_page(GFP_KERNEL);
 188        char *p = (char *) page, fmt[64];
 189        struct mwifiex_bss_info info;
 190        ssize_t ret;
 191        int i = 0;
 192
 193        if (!p)
 194                return -ENOMEM;
 195
 196        memset(&info, 0, sizeof(info));
 197        ret = mwifiex_get_bss_info(priv, &info);
 198        if (ret)
 199                goto free_and_exit;
 200
 201        mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
 202
 203        if (!priv->version_str[0])
 204                mwifiex_get_ver_ext(priv);
 205
 206        p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
 207        p += sprintf(p, "driver_version = %s", fmt);
 208        p += sprintf(p, "\nverext = %s", priv->version_str);
 209        p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
 210
 211        if (info.bss_mode >= ARRAY_SIZE(bss_modes))
 212                p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
 213        else
 214                p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
 215
 216        p += sprintf(p, "media_state=\"%s\"\n",
 217                     (!priv->media_connected ? "Disconnected" : "Connected"));
 218        p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
 219
 220        if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
 221                p += sprintf(p, "multicast_count=\"%d\"\n",
 222                             netdev_mc_count(netdev));
 223                p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
 224                p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
 225                p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
 226                p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
 227
 228                netdev_for_each_mc_addr(ha, netdev)
 229                        p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
 230                                        i++, ha->addr);
 231        }
 232
 233        p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
 234        p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
 235        p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
 236        p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
 237        p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
 238        p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
 239        p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
 240        p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
 241        p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
 242                                         ? "on" : "off"));
 243        p += sprintf(p, "tx queue");
 244        for (i = 0; i < netdev->num_tx_queues; i++) {
 245                txq = netdev_get_tx_queue(netdev, i);
 246                p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
 247                             "stopped" : "started");
 248        }
 249        p += sprintf(p, "\n");
 250
 251        ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
 252                                      (unsigned long) p - page);
 253
 254free_and_exit:
 255        free_page(page);
 256        return ret;
 257}
 258
 259/*
 260 * Proc getlog file read handler.
 261 *
 262 * This function is called when the 'getlog' file is opened for reading
 263 * It prints the following log information -
 264 *      - Number of multicast Tx frames
 265 *      - Number of failed packets
 266 *      - Number of Tx retries
 267 *      - Number of multicast Tx retries
 268 *      - Number of duplicate frames
 269 *      - Number of RTS successes
 270 *      - Number of RTS failures
 271 *      - Number of ACK failures
 272 *      - Number of fragmented Rx frames
 273 *      - Number of multicast Rx frames
 274 *      - Number of FCS errors
 275 *      - Number of Tx frames
 276 *      - WEP ICV error counts
 277 */
 278static ssize_t
 279mwifiex_getlog_read(struct file *file, char __user *ubuf,
 280                    size_t count, loff_t *ppos)
 281{
 282        struct mwifiex_private *priv =
 283                (struct mwifiex_private *) file->private_data;
 284        unsigned long page = get_zeroed_page(GFP_KERNEL);
 285        char *p = (char *) page;
 286        ssize_t ret;
 287        struct mwifiex_ds_get_stats stats;
 288
 289        if (!p)
 290                return -ENOMEM;
 291
 292        memset(&stats, 0, sizeof(stats));
 293        ret = mwifiex_get_stats_info(priv, &stats);
 294        if (ret)
 295                goto free_and_exit;
 296
 297        p += sprintf(p, "\n"
 298                     "mcasttxframe     %u\n"
 299                     "failed           %u\n"
 300                     "retry            %u\n"
 301                     "multiretry       %u\n"
 302                     "framedup         %u\n"
 303                     "rtssuccess       %u\n"
 304                     "rtsfailure       %u\n"
 305                     "ackfailure       %u\n"
 306                     "rxfrag           %u\n"
 307                     "mcastrxframe     %u\n"
 308                     "fcserror         %u\n"
 309                     "txframe          %u\n"
 310                     "wepicverrcnt-1   %u\n"
 311                     "wepicverrcnt-2   %u\n"
 312                     "wepicverrcnt-3   %u\n"
 313                     "wepicverrcnt-4   %u\n",
 314                     stats.mcast_tx_frame,
 315                     stats.failed,
 316                     stats.retry,
 317                     stats.multi_retry,
 318                     stats.frame_dup,
 319                     stats.rts_success,
 320                     stats.rts_failure,
 321                     stats.ack_failure,
 322                     stats.rx_frag,
 323                     stats.mcast_rx_frame,
 324                     stats.fcs_error,
 325                     stats.tx_frame,
 326                     stats.wep_icv_error[0],
 327                     stats.wep_icv_error[1],
 328                     stats.wep_icv_error[2],
 329                     stats.wep_icv_error[3]);
 330
 331
 332        ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
 333                                      (unsigned long) p - page);
 334
 335free_and_exit:
 336        free_page(page);
 337        return ret;
 338}
 339
 340static struct mwifiex_debug_info info;
 341
 342/*
 343 * Proc debug file read handler.
 344 *
 345 * This function is called when the 'debug' file is opened for reading
 346 * It prints the following log information -
 347 *      - Interrupt count
 348 *      - WMM AC VO packets count
 349 *      - WMM AC VI packets count
 350 *      - WMM AC BE packets count
 351 *      - WMM AC BK packets count
 352 *      - Maximum Tx buffer size
 353 *      - Tx buffer size
 354 *      - Current Tx buffer size
 355 *      - Power Save mode
 356 *      - Power Save state
 357 *      - Deep Sleep status
 358 *      - Device wakeup required status
 359 *      - Number of wakeup tries
 360 *      - Host Sleep configured status
 361 *      - Host Sleep activated status
 362 *      - Number of Tx timeouts
 363 *      - Number of command timeouts
 364 *      - Last timed out command ID
 365 *      - Last timed out command action
 366 *      - Last command ID
 367 *      - Last command action
 368 *      - Last command index
 369 *      - Last command response ID
 370 *      - Last command response index
 371 *      - Last event
 372 *      - Last event index
 373 *      - Number of host to card command failures
 374 *      - Number of sleep confirm command failures
 375 *      - Number of host to card data failure
 376 *      - Number of deauthentication events
 377 *      - Number of disassociation events
 378 *      - Number of link lost events
 379 *      - Number of deauthentication commands
 380 *      - Number of association success commands
 381 *      - Number of association failure commands
 382 *      - Number of commands sent
 383 *      - Number of data packets sent
 384 *      - Number of command responses received
 385 *      - Number of events received
 386 *      - Tx BA stream table (TID, RA)
 387 *      - Rx reorder table (TID, TA, Start window, Window size, Buffer)
 388 */
 389static ssize_t
 390mwifiex_debug_read(struct file *file, char __user *ubuf,
 391                   size_t count, loff_t *ppos)
 392{
 393        struct mwifiex_private *priv =
 394                (struct mwifiex_private *) file->private_data;
 395        struct mwifiex_debug_data *d = &items[0];
 396        unsigned long page = get_zeroed_page(GFP_KERNEL);
 397        char *p = (char *) page;
 398        ssize_t ret;
 399        size_t size, addr;
 400        long val;
 401        int i, j;
 402
 403        if (!p)
 404                return -ENOMEM;
 405
 406        ret = mwifiex_get_debug_info(priv, &info);
 407        if (ret)
 408                goto free_and_exit;
 409
 410        for (i = 0; i < num_of_items; i++) {
 411                p += sprintf(p, "%s=", d[i].name);
 412
 413                size = d[i].size / d[i].num;
 414
 415                if (i < (num_of_items - 3))
 416                        addr = d[i].addr + (size_t) &info;
 417                else /* The last 3 items are struct mwifiex_adapter variables */
 418                        addr = d[i].addr + (size_t) priv->adapter;
 419
 420                for (j = 0; j < d[i].num; j++) {
 421                        switch (size) {
 422                        case 1:
 423                                val = *((u8 *) addr);
 424                                break;
 425                        case 2:
 426                                val = *((u16 *) addr);
 427                                break;
 428                        case 4:
 429                                val = *((u32 *) addr);
 430                                break;
 431                        case 8:
 432                                val = *((long long *) addr);
 433                                break;
 434                        default:
 435                                val = -1;
 436                                break;
 437                        }
 438
 439                        p += sprintf(p, "%#lx ", val);
 440                        addr += size;
 441                }
 442
 443                p += sprintf(p, "\n");
 444        }
 445
 446        if (info.tx_tbl_num) {
 447                p += sprintf(p, "Tx BA stream table:\n");
 448                for (i = 0; i < info.tx_tbl_num; i++)
 449                        p += sprintf(p, "tid = %d, ra = %pM\n",
 450                                     info.tx_tbl[i].tid, info.tx_tbl[i].ra);
 451        }
 452
 453        if (info.rx_tbl_num) {
 454                p += sprintf(p, "Rx reorder table:\n");
 455                for (i = 0; i < info.rx_tbl_num; i++) {
 456                        p += sprintf(p, "tid = %d, ta = %pM, "
 457                                     "start_win = %d, "
 458                                     "win_size = %d, buffer: ",
 459                                     info.rx_tbl[i].tid,
 460                                     info.rx_tbl[i].ta,
 461                                     info.rx_tbl[i].start_win,
 462                                     info.rx_tbl[i].win_size);
 463
 464                        for (j = 0; j < info.rx_tbl[i].win_size; j++)
 465                                p += sprintf(p, "%c ",
 466                                             info.rx_tbl[i].buffer[j] ?
 467                                             '1' : '0');
 468
 469                        p += sprintf(p, "\n");
 470                }
 471        }
 472
 473        ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
 474                                      (unsigned long) p - page);
 475
 476free_and_exit:
 477        free_page(page);
 478        return ret;
 479}
 480
 481static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
 482
 483/*
 484 * Proc regrdwr file write handler.
 485 *
 486 * This function is called when the 'regrdwr' file is opened for writing
 487 *
 488 * This function can be used to write to a register.
 489 */
 490static ssize_t
 491mwifiex_regrdwr_write(struct file *file,
 492                      const char __user *ubuf, size_t count, loff_t *ppos)
 493{
 494        unsigned long addr = get_zeroed_page(GFP_KERNEL);
 495        char *buf = (char *) addr;
 496        size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
 497        int ret;
 498        u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
 499
 500        if (!buf)
 501                return -ENOMEM;
 502
 503
 504        if (copy_from_user(buf, ubuf, buf_size)) {
 505                ret = -EFAULT;
 506                goto done;
 507        }
 508
 509        sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
 510
 511        if (reg_type == 0 || reg_offset == 0) {
 512                ret = -EINVAL;
 513                goto done;
 514        } else {
 515                saved_reg_type = reg_type;
 516                saved_reg_offset = reg_offset;
 517                saved_reg_value = reg_value;
 518                ret = count;
 519        }
 520done:
 521        free_page(addr);
 522        return ret;
 523}
 524
 525/*
 526 * Proc regrdwr file read handler.
 527 *
 528 * This function is called when the 'regrdwr' file is opened for reading
 529 *
 530 * This function can be used to read from a register.
 531 */
 532static ssize_t
 533mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
 534                     size_t count, loff_t *ppos)
 535{
 536        struct mwifiex_private *priv =
 537                (struct mwifiex_private *) file->private_data;
 538        unsigned long addr = get_zeroed_page(GFP_KERNEL);
 539        char *buf = (char *) addr;
 540        int pos = 0, ret = 0;
 541        u32 reg_value;
 542
 543        if (!buf)
 544                return -ENOMEM;
 545
 546        if (!saved_reg_type) {
 547                /* No command has been given */
 548                pos += snprintf(buf, PAGE_SIZE, "0");
 549                goto done;
 550        }
 551        /* Set command has been given */
 552        if (saved_reg_value != UINT_MAX) {
 553                ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
 554                                        saved_reg_value);
 555
 556                pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
 557                                saved_reg_type, saved_reg_offset,
 558                                saved_reg_value);
 559
 560                ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
 561
 562                goto done;
 563        }
 564        /* Get command has been given */
 565        ret = mwifiex_reg_read(priv, saved_reg_type,
 566                               saved_reg_offset, &reg_value);
 567        if (ret) {
 568                ret = -EINVAL;
 569                goto done;
 570        }
 571
 572        pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
 573                        saved_reg_offset, reg_value);
 574
 575        ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
 576
 577done:
 578        free_page(addr);
 579        return ret;
 580}
 581
 582static u32 saved_offset = -1, saved_bytes = -1;
 583
 584/*
 585 * Proc rdeeprom file write handler.
 586 *
 587 * This function is called when the 'rdeeprom' file is opened for writing
 588 *
 589 * This function can be used to write to a RDEEPROM location.
 590 */
 591static ssize_t
 592mwifiex_rdeeprom_write(struct file *file,
 593                       const char __user *ubuf, size_t count, loff_t *ppos)
 594{
 595        unsigned long addr = get_zeroed_page(GFP_KERNEL);
 596        char *buf = (char *) addr;
 597        size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
 598        int ret = 0;
 599        int offset = -1, bytes = -1;
 600
 601        if (!buf)
 602                return -ENOMEM;
 603
 604
 605        if (copy_from_user(buf, ubuf, buf_size)) {
 606                ret = -EFAULT;
 607                goto done;
 608        }
 609
 610        sscanf(buf, "%d %d", &offset, &bytes);
 611
 612        if (offset == -1 || bytes == -1) {
 613                ret = -EINVAL;
 614                goto done;
 615        } else {
 616                saved_offset = offset;
 617                saved_bytes = bytes;
 618                ret = count;
 619        }
 620done:
 621        free_page(addr);
 622        return ret;
 623}
 624
 625/*
 626 * Proc rdeeprom read write handler.
 627 *
 628 * This function is called when the 'rdeeprom' file is opened for reading
 629 *
 630 * This function can be used to read from a RDEEPROM location.
 631 */
 632static ssize_t
 633mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
 634                      size_t count, loff_t *ppos)
 635{
 636        struct mwifiex_private *priv =
 637                (struct mwifiex_private *) file->private_data;
 638        unsigned long addr = get_zeroed_page(GFP_KERNEL);
 639        char *buf = (char *) addr;
 640        int pos = 0, ret = 0, i;
 641        u8 value[MAX_EEPROM_DATA];
 642
 643        if (!buf)
 644                return -ENOMEM;
 645
 646        if (saved_offset == -1) {
 647                /* No command has been given */
 648                pos += snprintf(buf, PAGE_SIZE, "0");
 649                goto done;
 650        }
 651
 652        /* Get command has been given */
 653        ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
 654                                  (u16) saved_bytes, value);
 655        if (ret) {
 656                ret = -EINVAL;
 657                goto done;
 658        }
 659
 660        pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
 661
 662        for (i = 0; i < saved_bytes; i++)
 663                pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]);
 664
 665        ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
 666
 667done:
 668        free_page(addr);
 669        return ret;
 670}
 671
 672
 673#define MWIFIEX_DFS_ADD_FILE(name) do {                                 \
 674        if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir,        \
 675                        priv, &mwifiex_dfs_##name##_fops))              \
 676                return;                                                 \
 677} while (0);
 678
 679#define MWIFIEX_DFS_FILE_OPS(name)                                      \
 680static const struct file_operations mwifiex_dfs_##name##_fops = {       \
 681        .read = mwifiex_##name##_read,                                  \
 682        .write = mwifiex_##name##_write,                                \
 683        .open = simple_open,                                            \
 684};
 685
 686#define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \
 687static const struct file_operations mwifiex_dfs_##name##_fops = {       \
 688        .read = mwifiex_##name##_read,                                  \
 689        .open = simple_open,                                            \
 690};
 691
 692#define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \
 693static const struct file_operations mwifiex_dfs_##name##_fops = {       \
 694        .write = mwifiex_##name##_write,                                \
 695        .open = simple_open,                                            \
 696};
 697
 698
 699MWIFIEX_DFS_FILE_READ_OPS(info);
 700MWIFIEX_DFS_FILE_READ_OPS(debug);
 701MWIFIEX_DFS_FILE_READ_OPS(getlog);
 702MWIFIEX_DFS_FILE_OPS(regrdwr);
 703MWIFIEX_DFS_FILE_OPS(rdeeprom);
 704
 705/*
 706 * This function creates the debug FS directory structure and the files.
 707 */
 708void
 709mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
 710{
 711        if (!mwifiex_dfs_dir || !priv)
 712                return;
 713
 714        priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
 715                                               mwifiex_dfs_dir);
 716
 717        if (!priv->dfs_dev_dir)
 718                return;
 719
 720        MWIFIEX_DFS_ADD_FILE(info);
 721        MWIFIEX_DFS_ADD_FILE(debug);
 722        MWIFIEX_DFS_ADD_FILE(getlog);
 723        MWIFIEX_DFS_ADD_FILE(regrdwr);
 724        MWIFIEX_DFS_ADD_FILE(rdeeprom);
 725}
 726
 727/*
 728 * This function removes the debug FS directory structure and the files.
 729 */
 730void
 731mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
 732{
 733        if (!priv)
 734                return;
 735
 736        debugfs_remove_recursive(priv->dfs_dev_dir);
 737}
 738
 739/*
 740 * This function creates the top level proc directory.
 741 */
 742void
 743mwifiex_debugfs_init(void)
 744{
 745        if (!mwifiex_dfs_dir)
 746                mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
 747}
 748
 749/*
 750 * This function removes the top level proc directory.
 751 */
 752void
 753mwifiex_debugfs_remove(void)
 754{
 755        if (mwifiex_dfs_dir)
 756                debugfs_remove(mwifiex_dfs_dir);
 757}
 758