linux/drivers/staging/rtl8723bs/os_dep/rtw_proc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/******************************************************************************
   3 *
   4 * Copyright(c) 2007 - 2013 Realtek Corporation. All rights reserved.
   5 *
   6 ******************************************************************************/
   7
   8#include <drv_types.h>
   9#include <rtw_debug.h>
  10#include "rtw_proc.h"
  11
  12#ifdef PROC_DEBUG
  13
  14static struct proc_dir_entry *rtw_proc;
  15
  16#define RTW_PROC_NAME "rtl8723bs"
  17
  18#define get_proc_net init_net.proc_net
  19
  20inline struct proc_dir_entry *rtw_proc_create_dir(const char *name, struct proc_dir_entry *parent, void *data)
  21{
  22        struct proc_dir_entry *entry;
  23
  24        entry = proc_mkdir_data(name, S_IRUGO|S_IXUGO, parent, data);
  25
  26        return entry;
  27}
  28
  29inline struct proc_dir_entry *rtw_proc_create_entry(const char *name, struct proc_dir_entry *parent,
  30        const struct file_operations *fops, void *data)
  31{
  32        struct proc_dir_entry *entry;
  33
  34        entry = proc_create_data(name,  S_IFREG|S_IRUGO, parent, fops, data);
  35
  36        return entry;
  37}
  38
  39static int proc_get_dummy(struct seq_file *m, void *v)
  40{
  41        return 0;
  42}
  43
  44static int proc_get_drv_version(struct seq_file *m, void *v)
  45{
  46        dump_drv_version(m);
  47        return 0;
  48}
  49
  50static int proc_get_log_level(struct seq_file *m, void *v)
  51{
  52        dump_log_level(m);
  53        return 0;
  54}
  55
  56static ssize_t proc_set_log_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
  57{
  58        char tmp[32];
  59        int log_level;
  60
  61        if (count < 1)
  62                return -EINVAL;
  63
  64        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
  65                sscanf(tmp, "%d ", &log_level);
  66                if (log_level >= _drv_always_ && log_level <= _drv_debug_) {
  67                        GlobalDebugLevel = log_level;
  68                        printk("%d\n", GlobalDebugLevel);
  69                }
  70        } else {
  71                return -EFAULT;
  72        }
  73
  74        return count;
  75}
  76
  77/*
  78* rtw_drv_proc:
  79* init/deinit when register/unregister driver
  80*/
  81static const struct rtw_proc_hdl drv_proc_hdls[] = {
  82        {"ver_info", proc_get_drv_version, NULL},
  83        {"log_level", proc_get_log_level, proc_set_log_level},
  84};
  85
  86static const int drv_proc_hdls_num = sizeof(drv_proc_hdls) / sizeof(struct rtw_proc_hdl);
  87
  88static int rtw_drv_proc_open(struct inode *inode, struct file *file)
  89{
  90        /* struct net_device *dev = proc_get_parent_data(inode); */
  91        ssize_t index = (ssize_t)PDE_DATA(inode);
  92        const struct rtw_proc_hdl *hdl = drv_proc_hdls+index;
  93
  94        return single_open(file, hdl->show, NULL);
  95}
  96
  97static ssize_t rtw_drv_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
  98{
  99        ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
 100        const struct rtw_proc_hdl *hdl = drv_proc_hdls+index;
 101        ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
 102
 103        if (write)
 104                return write(file, buffer, count, pos, NULL);
 105
 106        return -EROFS;
 107}
 108
 109static const struct file_operations rtw_drv_proc_fops = {
 110        .owner = THIS_MODULE,
 111        .open = rtw_drv_proc_open,
 112        .read = seq_read,
 113        .llseek = seq_lseek,
 114        .release = single_release,
 115        .write = rtw_drv_proc_write,
 116};
 117
 118int rtw_drv_proc_init(void)
 119{
 120        int ret = _FAIL;
 121        ssize_t i;
 122        struct proc_dir_entry *entry = NULL;
 123
 124        if (rtw_proc) {
 125                rtw_warn_on(1);
 126                goto exit;
 127        }
 128
 129        rtw_proc = rtw_proc_create_dir(RTW_PROC_NAME, get_proc_net, NULL);
 130
 131        if (!rtw_proc) {
 132                rtw_warn_on(1);
 133                goto exit;
 134        }
 135
 136        for (i = 0; i < drv_proc_hdls_num; i++) {
 137                entry = rtw_proc_create_entry(drv_proc_hdls[i].name, rtw_proc, &rtw_drv_proc_fops, (void *)i);
 138                if (!entry) {
 139                        rtw_warn_on(1);
 140                        goto exit;
 141                }
 142        }
 143
 144        ret = _SUCCESS;
 145
 146exit:
 147        return ret;
 148}
 149
 150void rtw_drv_proc_deinit(void)
 151{
 152        int i;
 153
 154        if (!rtw_proc)
 155                return;
 156
 157        for (i = 0; i < drv_proc_hdls_num; i++)
 158                remove_proc_entry(drv_proc_hdls[i].name, rtw_proc);
 159
 160        remove_proc_entry(RTW_PROC_NAME, get_proc_net);
 161        rtw_proc = NULL;
 162}
 163
 164static int proc_get_sd_f0_reg_dump(struct seq_file *m, void *v)
 165{
 166        struct net_device *dev = m->private;
 167        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 168
 169        sd_f0_reg_dump(m, adapter);
 170
 171        return 0;
 172}
 173
 174static int proc_get_mac_reg_dump(struct seq_file *m, void *v)
 175{
 176        struct net_device *dev = m->private;
 177        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 178
 179        mac_reg_dump(m, adapter);
 180
 181        return 0;
 182}
 183
 184static int proc_get_bb_reg_dump(struct seq_file *m, void *v)
 185{
 186        struct net_device *dev = m->private;
 187        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 188
 189        bb_reg_dump(m, adapter);
 190
 191        return 0;
 192}
 193
 194static int proc_get_rf_reg_dump(struct seq_file *m, void *v)
 195{
 196        struct net_device *dev = m->private;
 197        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 198
 199        rf_reg_dump(m, adapter);
 200
 201        return 0;
 202}
 203static int proc_get_linked_info_dump(struct seq_file *m, void *v)
 204{
 205        struct net_device *dev = m->private;
 206        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
 207
 208        if (padapter)
 209                DBG_871X_SEL_NL(m, "linked_info_dump :%s\n", (padapter->bLinkInfoDump)?"enable":"disable");
 210
 211        return 0;
 212}
 213
 214static ssize_t proc_set_linked_info_dump(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
 215{
 216        struct net_device *dev = data;
 217        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
 218
 219        char tmp[2];
 220        int mode = 0;
 221
 222        if (count < 1)
 223                return -EFAULT;
 224
 225        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
 226                if (padapter) {
 227                        /* padapter->bLinkInfoDump = mode; */
 228                        /* DBG_871X("linked_info_dump =%s\n", (padapter->bLinkInfoDump)?"enable":"disable"); */
 229                         linked_info_dump(padapter, mode);
 230                }
 231
 232        }
 233
 234        return count;
 235
 236}
 237
 238static int proc_get_rx_info(struct seq_file *m, void *v)
 239{
 240        struct net_device *dev = m->private;
 241        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
 242        struct dvobj_priv *psdpriv = padapter->dvobj;
 243        struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
 244
 245        /* Counts of packets whose seq_num is less than preorder_ctrl->indicate_seq, Ex delay, retransmission, redundant packets and so on */
 246        DBG_871X_SEL_NL(m,"Counts of Packets Whose Seq_Num Less Than Reorder Control Seq_Num: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_drop_count);
 247        /* How many times the Rx Reorder Timer is triggered. */
 248        DBG_871X_SEL_NL(m,"Rx Reorder Time-out Trigger Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_forced_indicate_count);
 249        /* Total counts of packets loss */
 250        DBG_871X_SEL_NL(m,"Rx Packet Loss Counts: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_loss_count);
 251        DBG_871X_SEL_NL(m,"Duplicate Management Frame Drop Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_dup_mgt_frame_drop_count);
 252        DBG_871X_SEL_NL(m,"AMPDU BA window shift Count: %llu\n", (unsigned long long)pdbgpriv->dbg_rx_ampdu_window_shift_cnt);
 253        return 0;
 254}
 255
 256
 257static ssize_t proc_reset_rx_info(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
 258{
 259        struct net_device *dev = data;
 260        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
 261        struct dvobj_priv *psdpriv = padapter->dvobj;
 262        struct debug_priv *pdbgpriv = &psdpriv->drv_dbg;
 263        char cmd[32];
 264        if (buffer && !copy_from_user(cmd, buffer, sizeof(cmd))) {
 265                if ('0' == cmd[0]) {
 266                        pdbgpriv->dbg_rx_ampdu_drop_count = 0;
 267                        pdbgpriv->dbg_rx_ampdu_forced_indicate_count = 0;
 268                        pdbgpriv->dbg_rx_ampdu_loss_count = 0;
 269                        pdbgpriv->dbg_rx_dup_mgt_frame_drop_count = 0;
 270                        pdbgpriv->dbg_rx_ampdu_window_shift_cnt = 0;
 271                }
 272        }
 273
 274        return count;
 275}
 276
 277static int proc_get_cam(struct seq_file *m, void *v)
 278{
 279        return 0;
 280}
 281
 282static ssize_t proc_set_cam(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
 283{
 284        struct net_device *dev = data;
 285        struct adapter *adapter;
 286
 287        char tmp[32];
 288        char cmd[5];
 289        u8 id;
 290
 291        adapter = (struct adapter *)rtw_netdev_priv(dev);
 292        if (!adapter)
 293                return -EFAULT;
 294
 295        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
 296
 297                /* c <id>: clear specific cam entry */
 298                /* wfc <id>: write specific cam entry from cam cache */
 299
 300                int num = sscanf(tmp, "%4s %hhu", cmd, &id);
 301
 302                if (num < 2)
 303                        return count;
 304                if (id >= TOTAL_CAM_ENTRY)
 305                        return -EINVAL;
 306
 307                if (strcmp("c", cmd) == 0) {
 308                        _clear_cam_entry(adapter, id);
 309                        adapter->securitypriv.hw_decrypted = false; /* temporarily set this for TX path to use SW enc */
 310                } else if (strcmp("wfc", cmd) == 0) {
 311                        write_cam_from_cache(adapter, id);
 312                }
 313        }
 314
 315        return count;
 316}
 317
 318static int proc_get_cam_cache(struct seq_file *m, void *v)
 319{
 320        struct net_device *dev = m->private;
 321        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 322        struct dvobj_priv *dvobj = adapter_to_dvobj(adapter);
 323        u8 i;
 324
 325        DBG_871X_SEL_NL(m, "cam bitmap:0x%016llx\n", dvobj->cam_ctl.bitmap);
 326
 327        DBG_871X_SEL_NL(m, "%-2s %-6s %-17s %-32s %-3s %-7s"
 328                /*  %-2s %-2s %-4s %-5s" */
 329                "\n"
 330                , "id", "ctrl", "addr", "key", "kid", "type"
 331                /*  "MK", "GK", "MFB", "valid" */
 332        );
 333
 334        for (i = 0; i < 32; i++) {
 335                if (dvobj->cam_cache[i].ctrl != 0)
 336                        DBG_871X_SEL_NL(m, "%2u 0x%04x "MAC_FMT" "KEY_FMT" %3u %-7s"
 337                                /*  %2u %2u 0x%02x %5u" */
 338                                "\n", i
 339                                , dvobj->cam_cache[i].ctrl
 340                                , MAC_ARG(dvobj->cam_cache[i].mac)
 341                                , KEY_ARG(dvobj->cam_cache[i].key)
 342                                , (dvobj->cam_cache[i].ctrl)&0x03
 343                                , security_type_str(((dvobj->cam_cache[i].ctrl)>>2)&0x07)
 344                                /*  ((dvobj->cam_cache[i].ctrl)>>5)&0x01 */
 345                                /*  ((dvobj->cam_cache[i].ctrl)>>6)&0x01 */
 346                                /*  ((dvobj->cam_cache[i].ctrl)>>8)&0x7f */
 347                                /*  ((dvobj->cam_cache[i].ctrl)>>15)&0x01 */
 348                        );
 349        }
 350
 351        return 0;
 352}
 353
 354/*
 355* rtw_adapter_proc:
 356* init/deinit when register/unregister net_device
 357*/
 358static const struct rtw_proc_hdl adapter_proc_hdls[] = {
 359        {"write_reg", proc_get_dummy, proc_set_write_reg},
 360        {"read_reg", proc_get_read_reg, proc_set_read_reg},
 361        {"fwstate", proc_get_fwstate, NULL},
 362        {"sec_info", proc_get_sec_info, NULL},
 363        {"mlmext_state", proc_get_mlmext_state, NULL},
 364        {"qos_option", proc_get_qos_option, NULL},
 365        {"ht_option", proc_get_ht_option, NULL},
 366        {"rf_info", proc_get_rf_info, NULL},
 367        {"survey_info", proc_get_survey_info, NULL},
 368        {"ap_info", proc_get_ap_info, NULL},
 369        {"adapter_state", proc_get_adapter_state, NULL},
 370        {"trx_info", proc_get_trx_info, NULL},
 371        {"rate_ctl", proc_get_rate_ctl, proc_set_rate_ctl},
 372        {"cam", proc_get_cam, proc_set_cam},
 373        {"cam_cache", proc_get_cam_cache, NULL},
 374        {"suspend_info", proc_get_suspend_resume_info, NULL},
 375        {"rx_info", proc_get_rx_info, proc_reset_rx_info},
 376
 377        {"roam_flags", proc_get_roam_flags, proc_set_roam_flags},
 378        {"roam_param", proc_get_roam_param, proc_set_roam_param},
 379        {"roam_tgt_addr", proc_get_dummy, proc_set_roam_tgt_addr},
 380
 381        {"sd_f0_reg_dump", proc_get_sd_f0_reg_dump, NULL},
 382
 383        {"fwdl_test_case", proc_get_dummy, proc_set_fwdl_test_case},
 384        {"wait_hiq_empty", proc_get_dummy, proc_set_wait_hiq_empty},
 385
 386        {"mac_reg_dump", proc_get_mac_reg_dump, NULL},
 387        {"bb_reg_dump", proc_get_bb_reg_dump, NULL},
 388        {"rf_reg_dump", proc_get_rf_reg_dump, NULL},
 389
 390        {"all_sta_info", proc_get_all_sta_info, NULL},
 391
 392        {"rx_signal", proc_get_rx_signal, proc_set_rx_signal},
 393        {"hw_info", proc_get_hw_status, NULL},
 394
 395        {"ht_enable", proc_get_ht_enable, proc_set_ht_enable},
 396        {"bw_mode", proc_get_bw_mode, proc_set_bw_mode},
 397        {"ampdu_enable", proc_get_ampdu_enable, proc_set_ampdu_enable},
 398        {"rx_stbc", proc_get_rx_stbc, proc_set_rx_stbc},
 399        {"rx_ampdu", proc_get_rx_ampdu, proc_set_rx_ampdu},
 400
 401        {"en_fwps", proc_get_en_fwps, proc_set_en_fwps},
 402
 403        /* path_rssi", proc_get_two_path_rssi, NULL}, */
 404        {"rssi_disp", proc_get_rssi_disp, proc_set_rssi_disp},
 405
 406        {"btcoex_dbg", proc_get_btcoex_dbg, proc_set_btcoex_dbg},
 407        {"btcoex", proc_get_btcoex_info, NULL},
 408
 409        {"linked_info_dump", proc_get_linked_info_dump, proc_set_linked_info_dump},
 410#ifdef CONFIG_DBG_COUNTER
 411        {"rx_logs", proc_get_rx_logs, NULL},
 412        {"tx_logs", proc_get_tx_logs, NULL},
 413        {"int_logs", proc_get_int_logs, NULL},
 414#endif
 415};
 416
 417static const int adapter_proc_hdls_num = sizeof(adapter_proc_hdls) / sizeof(struct rtw_proc_hdl);
 418
 419static int rtw_adapter_proc_open(struct inode *inode, struct file *file)
 420{
 421        ssize_t index = (ssize_t)PDE_DATA(inode);
 422        const struct rtw_proc_hdl *hdl = adapter_proc_hdls+index;
 423
 424        return single_open(file, hdl->show, proc_get_parent_data(inode));
 425}
 426
 427static ssize_t rtw_adapter_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
 428{
 429        ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
 430        const struct rtw_proc_hdl *hdl = adapter_proc_hdls+index;
 431        ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
 432
 433        if (write)
 434                return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private);
 435
 436        return -EROFS;
 437}
 438
 439static const struct file_operations rtw_adapter_proc_fops = {
 440        .owner = THIS_MODULE,
 441        .open = rtw_adapter_proc_open,
 442        .read = seq_read,
 443        .llseek = seq_lseek,
 444        .release = single_release,
 445        .write = rtw_adapter_proc_write,
 446};
 447
 448int proc_get_odm_dbg_comp(struct seq_file *m, void *v)
 449{
 450        struct net_device *dev = m->private;
 451        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 452
 453        rtw_odm_dbg_comp_msg(m, adapter);
 454
 455        return 0;
 456}
 457
 458ssize_t proc_set_odm_dbg_comp(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
 459{
 460        struct net_device *dev = data;
 461        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 462        char tmp[32];
 463
 464        u64 dbg_comp;
 465
 466        if (count < 1)
 467                return -EFAULT;
 468
 469        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
 470
 471                int num = sscanf(tmp, "%llx", &dbg_comp);
 472
 473                if (num != 1)
 474                        return count;
 475
 476                rtw_odm_dbg_comp_set(adapter, dbg_comp);
 477        }
 478
 479        return count;
 480}
 481
 482int proc_get_odm_dbg_level(struct seq_file *m, void *v)
 483{
 484        struct net_device *dev = m->private;
 485        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 486
 487        rtw_odm_dbg_level_msg(m, adapter);
 488
 489        return 0;
 490}
 491
 492ssize_t proc_set_odm_dbg_level(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
 493{
 494        struct net_device *dev = data;
 495        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 496        char tmp[32];
 497
 498        u32 dbg_level;
 499
 500        if (count < 1)
 501                return -EFAULT;
 502
 503        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
 504
 505                int num = sscanf(tmp, "%u", &dbg_level);
 506
 507                if (num != 1)
 508                        return count;
 509
 510                rtw_odm_dbg_level_set(adapter, dbg_level);
 511        }
 512
 513        return count;
 514}
 515
 516static int proc_get_odm_ability(struct seq_file *m, void *v)
 517{
 518        struct net_device *dev = m->private;
 519        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 520
 521        rtw_odm_ability_msg(m, adapter);
 522
 523        return 0;
 524}
 525
 526static ssize_t proc_set_odm_ability(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
 527{
 528        struct net_device *dev = data;
 529        struct adapter *adapter = (struct adapter *)rtw_netdev_priv(dev);
 530        char tmp[32];
 531
 532        u32 ability;
 533
 534        if (count < 1)
 535                return -EFAULT;
 536
 537        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
 538
 539                int num = sscanf(tmp, "%x", &ability);
 540
 541                if (num != 1)
 542                        return count;
 543
 544                rtw_odm_ability_set(adapter, ability);
 545        }
 546
 547        return count;
 548}
 549
 550int proc_get_odm_adaptivity(struct seq_file *m, void *v)
 551{
 552        struct net_device *dev = m->private;
 553        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
 554
 555        rtw_odm_adaptivity_parm_msg(m, padapter);
 556
 557        return 0;
 558}
 559
 560ssize_t proc_set_odm_adaptivity(struct file *file, const char __user *buffer, size_t count, loff_t *pos, void *data)
 561{
 562        struct net_device *dev = data;
 563        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
 564        char tmp[32];
 565        u32 TH_L2H_ini;
 566        s8 TH_EDCCA_HL_diff;
 567        u32 IGI_Base;
 568        int ForceEDCCA;
 569        u8 AdapEn_RSSI;
 570        u8 IGI_LowerBound;
 571
 572        if (count < 1)
 573                return -EFAULT;
 574
 575        if (buffer && !copy_from_user(tmp, buffer, sizeof(tmp))) {
 576
 577                int num = sscanf(tmp, "%x %hhd %x %d %hhu %hhu",
 578                        &TH_L2H_ini, &TH_EDCCA_HL_diff, &IGI_Base, &ForceEDCCA, &AdapEn_RSSI, &IGI_LowerBound);
 579
 580                if (num != 6)
 581                        return count;
 582
 583                rtw_odm_adaptivity_parm_set(padapter, (s8)TH_L2H_ini, TH_EDCCA_HL_diff, (s8)IGI_Base, (bool)ForceEDCCA, AdapEn_RSSI, IGI_LowerBound);
 584        }
 585
 586        return count;
 587}
 588
 589/*
 590* rtw_odm_proc:
 591* init/deinit when register/unregister net_device, along with rtw_adapter_proc
 592*/
 593static const struct rtw_proc_hdl odm_proc_hdls[] = {
 594        {"dbg_comp", proc_get_odm_dbg_comp, proc_set_odm_dbg_comp},
 595        {"dbg_level", proc_get_odm_dbg_level, proc_set_odm_dbg_level},
 596        {"ability", proc_get_odm_ability, proc_set_odm_ability},
 597        {"adaptivity", proc_get_odm_adaptivity, proc_set_odm_adaptivity},
 598};
 599
 600static const int odm_proc_hdls_num = sizeof(odm_proc_hdls) / sizeof(struct rtw_proc_hdl);
 601
 602static int rtw_odm_proc_open(struct inode *inode, struct file *file)
 603{
 604        ssize_t index = (ssize_t)PDE_DATA(inode);
 605        const struct rtw_proc_hdl *hdl = odm_proc_hdls+index;
 606
 607        return single_open(file, hdl->show, proc_get_parent_data(inode));
 608}
 609
 610static ssize_t rtw_odm_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
 611{
 612        ssize_t index = (ssize_t)PDE_DATA(file_inode(file));
 613        const struct rtw_proc_hdl *hdl = odm_proc_hdls+index;
 614        ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *, void *) = hdl->write;
 615
 616        if (write)
 617                return write(file, buffer, count, pos, ((struct seq_file *)file->private_data)->private);
 618
 619        return -EROFS;
 620}
 621
 622static const struct file_operations rtw_odm_proc_fops = {
 623        .owner = THIS_MODULE,
 624        .open = rtw_odm_proc_open,
 625        .read = seq_read,
 626        .llseek = seq_lseek,
 627        .release = single_release,
 628        .write = rtw_odm_proc_write,
 629};
 630
 631static struct proc_dir_entry *rtw_odm_proc_init(struct net_device *dev)
 632{
 633        struct proc_dir_entry *dir_odm = NULL;
 634        struct proc_dir_entry *entry = NULL;
 635        struct adapter  *adapter = rtw_netdev_priv(dev);
 636        ssize_t i;
 637
 638        if (!adapter->dir_dev) {
 639                rtw_warn_on(1);
 640                goto exit;
 641        }
 642
 643        if (adapter->dir_odm) {
 644                rtw_warn_on(1);
 645                goto exit;
 646        }
 647
 648        dir_odm = rtw_proc_create_dir("odm", adapter->dir_dev, dev);
 649        if (!dir_odm) {
 650                rtw_warn_on(1);
 651                goto exit;
 652        }
 653
 654        adapter->dir_odm = dir_odm;
 655
 656        for (i = 0; i < odm_proc_hdls_num; i++) {
 657                entry = rtw_proc_create_entry(odm_proc_hdls[i].name, dir_odm, &rtw_odm_proc_fops, (void *)i);
 658                if (!entry) {
 659                        rtw_warn_on(1);
 660                        goto exit;
 661                }
 662        }
 663
 664exit:
 665        return dir_odm;
 666}
 667
 668static void rtw_odm_proc_deinit(struct adapter  *adapter)
 669{
 670        struct proc_dir_entry *dir_odm = NULL;
 671        int i;
 672
 673        dir_odm = adapter->dir_odm;
 674
 675        if (!dir_odm) {
 676                rtw_warn_on(1);
 677                return;
 678        }
 679
 680        for (i = 0; i < odm_proc_hdls_num; i++)
 681                remove_proc_entry(odm_proc_hdls[i].name, dir_odm);
 682
 683        remove_proc_entry("odm", adapter->dir_dev);
 684
 685        adapter->dir_odm = NULL;
 686}
 687
 688struct proc_dir_entry *rtw_adapter_proc_init(struct net_device *dev)
 689{
 690        struct proc_dir_entry *drv_proc = rtw_proc;
 691        struct proc_dir_entry *dir_dev = NULL;
 692        struct proc_dir_entry *entry = NULL;
 693        struct adapter *adapter = rtw_netdev_priv(dev);
 694        ssize_t i;
 695
 696        if (!drv_proc) {
 697                rtw_warn_on(1);
 698                goto exit;
 699        }
 700
 701        if (adapter->dir_dev) {
 702                rtw_warn_on(1);
 703                goto exit;
 704        }
 705
 706        dir_dev = rtw_proc_create_dir(dev->name, drv_proc, dev);
 707        if (!dir_dev) {
 708                rtw_warn_on(1);
 709                goto exit;
 710        }
 711
 712        adapter->dir_dev = dir_dev;
 713
 714        for (i = 0; i < adapter_proc_hdls_num; i++) {
 715                entry = rtw_proc_create_entry(adapter_proc_hdls[i].name, dir_dev, &rtw_adapter_proc_fops, (void *)i);
 716                if (!entry) {
 717                        rtw_warn_on(1);
 718                        goto exit;
 719                }
 720        }
 721
 722        rtw_odm_proc_init(dev);
 723
 724exit:
 725        return dir_dev;
 726}
 727
 728void rtw_adapter_proc_deinit(struct net_device *dev)
 729{
 730        struct proc_dir_entry *drv_proc = rtw_proc;
 731        struct proc_dir_entry *dir_dev = NULL;
 732        struct adapter *adapter = rtw_netdev_priv(dev);
 733        int i;
 734
 735        dir_dev = adapter->dir_dev;
 736
 737        if (!dir_dev) {
 738                rtw_warn_on(1);
 739                return;
 740        }
 741
 742        for (i = 0; i < adapter_proc_hdls_num; i++)
 743                remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
 744
 745        rtw_odm_proc_deinit(adapter);
 746
 747        remove_proc_entry(dev->name, drv_proc);
 748
 749        adapter->dir_dev = NULL;
 750}
 751
 752void rtw_adapter_proc_replace(struct net_device *dev)
 753{
 754        struct proc_dir_entry *drv_proc = rtw_proc;
 755        struct proc_dir_entry *dir_dev = NULL;
 756        struct adapter *adapter = rtw_netdev_priv(dev);
 757        int i;
 758
 759        dir_dev = adapter->dir_dev;
 760
 761        if (!dir_dev) {
 762                rtw_warn_on(1);
 763                return;
 764        }
 765
 766        for (i = 0; i < adapter_proc_hdls_num; i++)
 767                remove_proc_entry(adapter_proc_hdls[i].name, dir_dev);
 768
 769        rtw_odm_proc_deinit(adapter);
 770
 771        remove_proc_entry(adapter->old_ifname, drv_proc);
 772
 773        adapter->dir_dev = NULL;
 774
 775        rtw_adapter_proc_init(dev);
 776
 777}
 778
 779#endif /* PROC_DEBUG */
 780