linux/drivers/staging/rtl8192e/rtllib_softmac_wx.c
<<
>>
Prefs
   1/* IEEE 802.11 SoftMAC layer
   2 * Copyright (c) 2005 Andrea Merello <andrea.merello@gmail.com>
   3 *
   4 * Mostly extracted from the rtl8180-sa2400 driver for the
   5 * in-kernel generic ieee802.11 stack.
   6 *
   7 * Some pieces of code might be stolen from ipw2100 driver
   8 * copyright of who own it's copyright ;-)
   9 *
  10 * PS wx handler mostly stolen from hostap, copyright who
  11 * own it's copyright ;-)
  12 *
  13 * released under the GPL
  14 */
  15
  16
  17#include <linux/etherdevice.h>
  18
  19#include "rtllib.h"
  20#include "dot11d.h"
  21/* FIXME: add A freqs */
  22
  23const long rtllib_wlan_frequencies[] = {
  24        2412, 2417, 2422, 2427,
  25        2432, 2437, 2442, 2447,
  26        2452, 2457, 2462, 2467,
  27        2472, 2484
  28};
  29EXPORT_SYMBOL(rtllib_wlan_frequencies);
  30
  31
  32int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
  33                             union iwreq_data *wrqu, char *b)
  34{
  35        int ret;
  36        struct iw_freq *fwrq = &wrqu->freq;
  37
  38        mutex_lock(&ieee->wx_mutex);
  39
  40        if (ieee->iw_mode == IW_MODE_INFRA) {
  41                ret = 0;
  42                goto out;
  43        }
  44
  45        /* if setting by freq convert to channel */
  46        if (fwrq->e == 1) {
  47                if ((fwrq->m >= (int) 2.412e8 &&
  48                     fwrq->m <= (int) 2.487e8)) {
  49                        int f = fwrq->m / 100000;
  50                        int c = 0;
  51
  52                        while ((c < 14) && (f != rtllib_wlan_frequencies[c]))
  53                                c++;
  54
  55                        /* hack to fall through */
  56                        fwrq->e = 0;
  57                        fwrq->m = c + 1;
  58                }
  59        }
  60
  61        if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) {
  62                ret = -EOPNOTSUPP;
  63                goto out;
  64
  65        } else { /* Set the channel */
  66
  67                if (ieee->active_channel_map[fwrq->m] != 1) {
  68                        ret = -EINVAL;
  69                        goto out;
  70                }
  71                ieee->current_network.channel = fwrq->m;
  72                ieee->set_chan(ieee->dev, ieee->current_network.channel);
  73
  74                if (ieee->iw_mode == IW_MODE_ADHOC ||
  75                    ieee->iw_mode == IW_MODE_MASTER)
  76                        if (ieee->state == RTLLIB_LINKED) {
  77                                rtllib_stop_send_beacons(ieee);
  78                                rtllib_start_send_beacons(ieee);
  79                        }
  80        }
  81
  82        ret = 0;
  83out:
  84        mutex_unlock(&ieee->wx_mutex);
  85        return ret;
  86}
  87EXPORT_SYMBOL(rtllib_wx_set_freq);
  88
  89
  90int rtllib_wx_get_freq(struct rtllib_device *ieee,
  91                             struct iw_request_info *a,
  92                             union iwreq_data *wrqu, char *b)
  93{
  94        struct iw_freq *fwrq = &wrqu->freq;
  95
  96        if (ieee->current_network.channel == 0)
  97                return -1;
  98        fwrq->m = rtllib_wlan_frequencies[ieee->current_network.channel-1] *
  99                  100000;
 100        fwrq->e = 1;
 101        return 0;
 102}
 103EXPORT_SYMBOL(rtllib_wx_get_freq);
 104
 105int rtllib_wx_get_wap(struct rtllib_device *ieee,
 106                            struct iw_request_info *info,
 107                            union iwreq_data *wrqu, char *extra)
 108{
 109        unsigned long flags;
 110
 111        wrqu->ap_addr.sa_family = ARPHRD_ETHER;
 112
 113        if (ieee->iw_mode == IW_MODE_MONITOR)
 114                return -1;
 115
 116        /* We want avoid to give to the user inconsistent infos*/
 117        spin_lock_irqsave(&ieee->lock, flags);
 118
 119        if (ieee->state != RTLLIB_LINKED &&
 120                ieee->state != RTLLIB_LINKED_SCANNING &&
 121                ieee->wap_set == 0)
 122
 123                eth_zero_addr(wrqu->ap_addr.sa_data);
 124        else
 125                memcpy(wrqu->ap_addr.sa_data,
 126                       ieee->current_network.bssid, ETH_ALEN);
 127
 128        spin_unlock_irqrestore(&ieee->lock, flags);
 129
 130        return 0;
 131}
 132EXPORT_SYMBOL(rtllib_wx_get_wap);
 133
 134
 135int rtllib_wx_set_wap(struct rtllib_device *ieee,
 136                         struct iw_request_info *info,
 137                         union iwreq_data *awrq,
 138                         char *extra)
 139{
 140
 141        int ret = 0;
 142        unsigned long flags;
 143
 144        short ifup = ieee->proto_started;
 145        struct sockaddr *temp = (struct sockaddr *)awrq;
 146
 147        rtllib_stop_scan_syncro(ieee);
 148
 149        mutex_lock(&ieee->wx_mutex);
 150        /* use ifconfig hw ether */
 151        if (ieee->iw_mode == IW_MODE_MASTER) {
 152                ret = -1;
 153                goto out;
 154        }
 155
 156        if (temp->sa_family != ARPHRD_ETHER) {
 157                ret = -EINVAL;
 158                goto out;
 159        }
 160
 161        if (is_zero_ether_addr(temp->sa_data)) {
 162                spin_lock_irqsave(&ieee->lock, flags);
 163                ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
 164                ieee->wap_set = 0;
 165                spin_unlock_irqrestore(&ieee->lock, flags);
 166                ret = -1;
 167                goto out;
 168        }
 169
 170
 171        if (ifup)
 172                rtllib_stop_protocol(ieee, true);
 173
 174        /* just to avoid to give inconsistent infos in the
 175         * get wx method. not really needed otherwise
 176         */
 177        spin_lock_irqsave(&ieee->lock, flags);
 178
 179        ieee->cannot_notify = false;
 180        ether_addr_copy(ieee->current_network.bssid, temp->sa_data);
 181        ieee->wap_set = !is_zero_ether_addr(temp->sa_data);
 182
 183        spin_unlock_irqrestore(&ieee->lock, flags);
 184
 185        if (ifup)
 186                rtllib_start_protocol(ieee);
 187out:
 188        mutex_unlock(&ieee->wx_mutex);
 189        return ret;
 190}
 191EXPORT_SYMBOL(rtllib_wx_set_wap);
 192
 193int rtllib_wx_get_essid(struct rtllib_device *ieee, struct iw_request_info *a,
 194                         union iwreq_data *wrqu, char *b)
 195{
 196        int len, ret = 0;
 197        unsigned long flags;
 198
 199        if (ieee->iw_mode == IW_MODE_MONITOR)
 200                return -1;
 201
 202        /* We want avoid to give to the user inconsistent infos*/
 203        spin_lock_irqsave(&ieee->lock, flags);
 204
 205        if (ieee->current_network.ssid[0] == '\0' ||
 206                ieee->current_network.ssid_len == 0) {
 207                ret = -1;
 208                goto out;
 209        }
 210
 211        if (ieee->state != RTLLIB_LINKED &&
 212                ieee->state != RTLLIB_LINKED_SCANNING &&
 213                ieee->ssid_set == 0) {
 214                ret = -1;
 215                goto out;
 216        }
 217        len = ieee->current_network.ssid_len;
 218        wrqu->essid.length = len;
 219        strncpy(b, ieee->current_network.ssid, len);
 220        wrqu->essid.flags = 1;
 221
 222out:
 223        spin_unlock_irqrestore(&ieee->lock, flags);
 224
 225        return ret;
 226
 227}
 228EXPORT_SYMBOL(rtllib_wx_get_essid);
 229
 230int rtllib_wx_set_rate(struct rtllib_device *ieee,
 231                             struct iw_request_info *info,
 232                             union iwreq_data *wrqu, char *extra)
 233{
 234
 235        u32 target_rate = wrqu->bitrate.value;
 236
 237        ieee->rate = target_rate/100000;
 238        return 0;
 239}
 240EXPORT_SYMBOL(rtllib_wx_set_rate);
 241
 242int rtllib_wx_get_rate(struct rtllib_device *ieee,
 243                             struct iw_request_info *info,
 244                             union iwreq_data *wrqu, char *extra)
 245{
 246        u32 tmp_rate;
 247
 248        tmp_rate = TxCountToDataRate(ieee,
 249                                     ieee->softmac_stats.CurrentShowTxate);
 250        wrqu->bitrate.value = tmp_rate * 500000;
 251
 252        return 0;
 253}
 254EXPORT_SYMBOL(rtllib_wx_get_rate);
 255
 256
 257int rtllib_wx_set_rts(struct rtllib_device *ieee,
 258                             struct iw_request_info *info,
 259                             union iwreq_data *wrqu, char *extra)
 260{
 261        if (wrqu->rts.disabled || !wrqu->rts.fixed)
 262                ieee->rts = DEFAULT_RTS_THRESHOLD;
 263        else {
 264                if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
 265                                wrqu->rts.value > MAX_RTS_THRESHOLD)
 266                        return -EINVAL;
 267                ieee->rts = wrqu->rts.value;
 268        }
 269        return 0;
 270}
 271EXPORT_SYMBOL(rtllib_wx_set_rts);
 272
 273int rtllib_wx_get_rts(struct rtllib_device *ieee,
 274                             struct iw_request_info *info,
 275                             union iwreq_data *wrqu, char *extra)
 276{
 277        wrqu->rts.value = ieee->rts;
 278        wrqu->rts.fixed = 0;    /* no auto select */
 279        wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
 280        return 0;
 281}
 282EXPORT_SYMBOL(rtllib_wx_get_rts);
 283
 284int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
 285                             union iwreq_data *wrqu, char *b)
 286{
 287        int set_mode_status = 0;
 288
 289        rtllib_stop_scan_syncro(ieee);
 290        mutex_lock(&ieee->wx_mutex);
 291        switch (wrqu->mode) {
 292        case IW_MODE_MONITOR:
 293        case IW_MODE_ADHOC:
 294        case IW_MODE_INFRA:
 295                break;
 296        case IW_MODE_AUTO:
 297                wrqu->mode = IW_MODE_INFRA;
 298                break;
 299        default:
 300                set_mode_status = -EINVAL;
 301                goto out;
 302        }
 303
 304        if (wrqu->mode == ieee->iw_mode)
 305                goto out;
 306
 307        if (wrqu->mode == IW_MODE_MONITOR) {
 308                ieee->dev->type = ARPHRD_IEEE80211;
 309                rtllib_EnableNetMonitorMode(ieee->dev, false);
 310        } else {
 311                ieee->dev->type = ARPHRD_ETHER;
 312                if (ieee->iw_mode == IW_MODE_MONITOR)
 313                        rtllib_DisableNetMonitorMode(ieee->dev, false);
 314        }
 315
 316        if (!ieee->proto_started) {
 317                ieee->iw_mode = wrqu->mode;
 318        } else {
 319                rtllib_stop_protocol(ieee, true);
 320                ieee->iw_mode = wrqu->mode;
 321                rtllib_start_protocol(ieee);
 322        }
 323
 324out:
 325        mutex_unlock(&ieee->wx_mutex);
 326        return set_mode_status;
 327}
 328EXPORT_SYMBOL(rtllib_wx_set_mode);
 329
 330void rtllib_wx_sync_scan_wq(void *data)
 331{
 332        struct rtllib_device *ieee = container_of_work_rsl(data,
 333                                     struct rtllib_device, wx_sync_scan_wq);
 334        short chan;
 335        enum ht_extchnl_offset chan_offset = 0;
 336        enum ht_channel_width bandwidth = 0;
 337        int b40M = 0;
 338
 339        if (!(ieee->softmac_features & IEEE_SOFTMAC_SCAN)) {
 340                rtllib_start_scan_syncro(ieee, 0);
 341                goto out;
 342        }
 343
 344        chan = ieee->current_network.channel;
 345
 346        if (ieee->LeisurePSLeave)
 347                ieee->LeisurePSLeave(ieee->dev);
 348        /* notify AP to be in PS mode */
 349        rtllib_sta_ps_send_null_frame(ieee, 1);
 350        rtllib_sta_ps_send_null_frame(ieee, 1);
 351
 352        rtllib_stop_all_queues(ieee);
 353
 354        if (ieee->data_hard_stop)
 355                ieee->data_hard_stop(ieee->dev);
 356        rtllib_stop_send_beacons(ieee);
 357        ieee->state = RTLLIB_LINKED_SCANNING;
 358        ieee->link_change(ieee->dev);
 359        /* wait for ps packet to be kicked out successfully */
 360        msleep(50);
 361
 362        if (ieee->ScanOperationBackupHandler)
 363                ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
 364
 365        if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT &&
 366            ieee->pHTInfo->bCurBW40MHz) {
 367                b40M = 1;
 368                chan_offset = ieee->pHTInfo->CurSTAExtChnlOffset;
 369                bandwidth = (enum ht_channel_width)ieee->pHTInfo->bCurBW40MHz;
 370                RT_TRACE(COMP_DBG, "Scan in 40M, force to 20M first:%d, %d\n",
 371                         chan_offset, bandwidth);
 372                ieee->SetBWModeHandler(ieee->dev, HT_CHANNEL_WIDTH_20,
 373                                       HT_EXTCHNL_OFFSET_NO_EXT);
 374        }
 375
 376        rtllib_start_scan_syncro(ieee, 0);
 377
 378        if (b40M) {
 379                RT_TRACE(COMP_DBG, "Scan in 20M, back to 40M\n");
 380                if (chan_offset == HT_EXTCHNL_OFFSET_UPPER)
 381                        ieee->set_chan(ieee->dev, chan + 2);
 382                else if (chan_offset == HT_EXTCHNL_OFFSET_LOWER)
 383                        ieee->set_chan(ieee->dev, chan - 2);
 384                else
 385                        ieee->set_chan(ieee->dev, chan);
 386                ieee->SetBWModeHandler(ieee->dev, bandwidth, chan_offset);
 387        } else {
 388                ieee->set_chan(ieee->dev, chan);
 389        }
 390
 391        if (ieee->ScanOperationBackupHandler)
 392                ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_RESTORE);
 393
 394        ieee->state = RTLLIB_LINKED;
 395        ieee->link_change(ieee->dev);
 396
 397        /* Notify AP that I wake up again */
 398        rtllib_sta_ps_send_null_frame(ieee, 0);
 399
 400        if (ieee->LinkDetectInfo.NumRecvBcnInPeriod == 0 ||
 401            ieee->LinkDetectInfo.NumRecvDataInPeriod == 0) {
 402                ieee->LinkDetectInfo.NumRecvBcnInPeriod = 1;
 403                ieee->LinkDetectInfo.NumRecvDataInPeriod = 1;
 404        }
 405
 406        if (ieee->data_hard_resume)
 407                ieee->data_hard_resume(ieee->dev);
 408
 409        if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER)
 410                rtllib_start_send_beacons(ieee);
 411
 412        rtllib_wake_all_queues(ieee);
 413
 414out:
 415        mutex_unlock(&ieee->wx_mutex);
 416
 417}
 418
 419int rtllib_wx_set_scan(struct rtllib_device *ieee, struct iw_request_info *a,
 420                             union iwreq_data *wrqu, char *b)
 421{
 422        int ret = 0;
 423
 424        mutex_lock(&ieee->wx_mutex);
 425
 426        if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) {
 427                ret = -1;
 428                goto out;
 429        }
 430
 431        if (ieee->state == RTLLIB_LINKED) {
 432                schedule_work(&ieee->wx_sync_scan_wq);
 433                /* intentionally forget to up sem */
 434                return 0;
 435        }
 436
 437out:
 438        mutex_unlock(&ieee->wx_mutex);
 439        return ret;
 440}
 441EXPORT_SYMBOL(rtllib_wx_set_scan);
 442
 443int rtllib_wx_set_essid(struct rtllib_device *ieee,
 444                        struct iw_request_info *a,
 445                        union iwreq_data *wrqu, char *extra)
 446{
 447
 448        int ret = 0, len, i;
 449        short proto_started;
 450        unsigned long flags;
 451
 452        rtllib_stop_scan_syncro(ieee);
 453        mutex_lock(&ieee->wx_mutex);
 454
 455        proto_started = ieee->proto_started;
 456
 457        len = min_t(__u16, wrqu->essid.length, IW_ESSID_MAX_SIZE);
 458
 459        if (ieee->iw_mode == IW_MODE_MONITOR) {
 460                ret = -1;
 461                goto out;
 462        }
 463
 464        for (i = 0; i < len; i++) {
 465                if (extra[i] < 0) {
 466                        ret = -1;
 467                        goto out;
 468                }
 469        }
 470
 471        if (proto_started)
 472                rtllib_stop_protocol(ieee, true);
 473
 474
 475        /* this is just to be sure that the GET wx callback
 476         * has consistent infos. not needed otherwise
 477         */
 478        spin_lock_irqsave(&ieee->lock, flags);
 479
 480        if (wrqu->essid.flags && wrqu->essid.length) {
 481                strncpy(ieee->current_network.ssid, extra, len);
 482                ieee->current_network.ssid_len = len;
 483                ieee->cannot_notify = false;
 484                ieee->ssid_set = 1;
 485        } else {
 486                ieee->ssid_set = 0;
 487                ieee->current_network.ssid[0] = '\0';
 488                ieee->current_network.ssid_len = 0;
 489        }
 490        spin_unlock_irqrestore(&ieee->lock, flags);
 491
 492        if (proto_started)
 493                rtllib_start_protocol(ieee);
 494out:
 495        mutex_unlock(&ieee->wx_mutex);
 496        return ret;
 497}
 498EXPORT_SYMBOL(rtllib_wx_set_essid);
 499
 500int rtllib_wx_get_mode(struct rtllib_device *ieee, struct iw_request_info *a,
 501                       union iwreq_data *wrqu, char *b)
 502{
 503        wrqu->mode = ieee->iw_mode;
 504        return 0;
 505}
 506EXPORT_SYMBOL(rtllib_wx_get_mode);
 507
 508int rtllib_wx_set_rawtx(struct rtllib_device *ieee,
 509                        struct iw_request_info *info,
 510                        union iwreq_data *wrqu, char *extra)
 511{
 512
 513        int *parms = (int *)extra;
 514        int enable = (parms[0] > 0);
 515        short prev = ieee->raw_tx;
 516
 517        mutex_lock(&ieee->wx_mutex);
 518
 519        if (enable)
 520                ieee->raw_tx = 1;
 521        else
 522                ieee->raw_tx = 0;
 523
 524        netdev_info(ieee->dev, "raw TX is %s\n",
 525                    ieee->raw_tx ? "enabled" : "disabled");
 526
 527        if (ieee->iw_mode == IW_MODE_MONITOR) {
 528                if (prev == 0 && ieee->raw_tx) {
 529                        if (ieee->data_hard_resume)
 530                                ieee->data_hard_resume(ieee->dev);
 531
 532                        netif_carrier_on(ieee->dev);
 533                }
 534
 535                if (prev && ieee->raw_tx == 1)
 536                        netif_carrier_off(ieee->dev);
 537        }
 538
 539        mutex_unlock(&ieee->wx_mutex);
 540
 541        return 0;
 542}
 543EXPORT_SYMBOL(rtllib_wx_set_rawtx);
 544
 545int rtllib_wx_get_name(struct rtllib_device *ieee,
 546                             struct iw_request_info *info,
 547                             union iwreq_data *wrqu, char *extra)
 548{
 549        strcpy(wrqu->name, "802.11");
 550
 551        if (ieee->modulation & RTLLIB_CCK_MODULATION)
 552                strcat(wrqu->name, "b");
 553        if (ieee->modulation & RTLLIB_OFDM_MODULATION)
 554                strcat(wrqu->name, "g");
 555        if (ieee->mode & (IEEE_N_24G | IEEE_N_5G))
 556                strcat(wrqu->name, "n");
 557        return 0;
 558}
 559EXPORT_SYMBOL(rtllib_wx_get_name);
 560
 561
 562/* this is mostly stolen from hostap */
 563int rtllib_wx_set_power(struct rtllib_device *ieee,
 564                                 struct iw_request_info *info,
 565                                 union iwreq_data *wrqu, char *extra)
 566{
 567        int ret = 0;
 568
 569        if ((!ieee->sta_wake_up) ||
 570            (!ieee->enter_sleep_state) ||
 571            (!ieee->ps_is_queue_empty)) {
 572                netdev_warn(ieee->dev,
 573                            "%s(): PS mode is tried to be use but driver missed a callback\n",
 574                            __func__);
 575                return -1;
 576        }
 577
 578        mutex_lock(&ieee->wx_mutex);
 579
 580        if (wrqu->power.disabled) {
 581                RT_TRACE(COMP_DBG, "===>%s(): power disable\n", __func__);
 582                ieee->ps = RTLLIB_PS_DISABLED;
 583                goto exit;
 584        }
 585        if (wrqu->power.flags & IW_POWER_TIMEOUT) {
 586                ieee->ps_timeout = wrqu->power.value / 1000;
 587                RT_TRACE(COMP_DBG, "===>%s():ps_timeout is %d\n", __func__,
 588                         ieee->ps_timeout);
 589        }
 590
 591        if (wrqu->power.flags & IW_POWER_PERIOD)
 592                ieee->ps_period = wrqu->power.value / 1000;
 593
 594        switch (wrqu->power.flags & IW_POWER_MODE) {
 595        case IW_POWER_UNICAST_R:
 596                ieee->ps = RTLLIB_PS_UNICAST;
 597                break;
 598        case IW_POWER_MULTICAST_R:
 599                ieee->ps = RTLLIB_PS_MBCAST;
 600                break;
 601        case IW_POWER_ALL_R:
 602                ieee->ps = RTLLIB_PS_UNICAST | RTLLIB_PS_MBCAST;
 603                break;
 604
 605        case IW_POWER_ON:
 606                break;
 607
 608        default:
 609                ret = -EINVAL;
 610                goto exit;
 611
 612        }
 613exit:
 614        mutex_unlock(&ieee->wx_mutex);
 615        return ret;
 616
 617}
 618EXPORT_SYMBOL(rtllib_wx_set_power);
 619
 620/* this is stolen from hostap */
 621int rtllib_wx_get_power(struct rtllib_device *ieee,
 622                                 struct iw_request_info *info,
 623                                 union iwreq_data *wrqu, char *extra)
 624{
 625        mutex_lock(&ieee->wx_mutex);
 626
 627        if (ieee->ps == RTLLIB_PS_DISABLED) {
 628                wrqu->power.disabled = 1;
 629                goto exit;
 630        }
 631
 632        wrqu->power.disabled = 0;
 633
 634        if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
 635                wrqu->power.flags = IW_POWER_TIMEOUT;
 636                wrqu->power.value = ieee->ps_timeout * 1000;
 637        } else {
 638                wrqu->power.flags = IW_POWER_PERIOD;
 639                wrqu->power.value = ieee->ps_period * 1000;
 640        }
 641
 642        if ((ieee->ps & (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST)) ==
 643            (RTLLIB_PS_MBCAST | RTLLIB_PS_UNICAST))
 644                wrqu->power.flags |= IW_POWER_ALL_R;
 645        else if (ieee->ps & RTLLIB_PS_MBCAST)
 646                wrqu->power.flags |= IW_POWER_MULTICAST_R;
 647        else
 648                wrqu->power.flags |= IW_POWER_UNICAST_R;
 649
 650exit:
 651        mutex_unlock(&ieee->wx_mutex);
 652        return 0;
 653
 654}
 655EXPORT_SYMBOL(rtllib_wx_get_power);
 656