linux/drivers/staging/wilc1000/wilc_wlan_cfg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries.
   4 * All rights reserved.
   5 */
   6
   7#include "wilc_wlan_if.h"
   8#include "wilc_wlan.h"
   9#include "wilc_wlan_cfg.h"
  10#include "wilc_wfi_netdevice.h"
  11
  12enum cfg_cmd_type {
  13        CFG_BYTE_CMD    = 0,
  14        CFG_HWORD_CMD   = 1,
  15        CFG_WORD_CMD    = 2,
  16        CFG_STR_CMD     = 3,
  17        CFG_BIN_CMD     = 4
  18};
  19
  20static const struct wilc_cfg_byte g_cfg_byte[] = {
  21        {WID_STATUS, 0},
  22        {WID_RSSI, 0},
  23        {WID_LINKSPEED, 0},
  24        {WID_NIL, 0}
  25};
  26
  27static const struct wilc_cfg_hword g_cfg_hword[] = {
  28        {WID_NIL, 0}
  29};
  30
  31static const struct wilc_cfg_word g_cfg_word[] = {
  32        {WID_FAILED_COUNT, 0},
  33        {WID_RECEIVED_FRAGMENT_COUNT, 0},
  34        {WID_SUCCESS_FRAME_COUNT, 0},
  35        {WID_GET_INACTIVE_TIME, 0},
  36        {WID_NIL, 0}
  37
  38};
  39
  40static const struct wilc_cfg_str g_cfg_str[] = {
  41        {WID_FIRMWARE_VERSION, NULL},
  42        {WID_MAC_ADDR, NULL},
  43        {WID_ASSOC_RES_INFO, NULL},
  44        {WID_NIL, NULL}
  45};
  46
  47/********************************************
  48 *
  49 *      Configuration Functions
  50 *
  51 ********************************************/
  52
  53static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8)
  54{
  55        u8 *buf;
  56
  57        if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE)
  58                return 0;
  59
  60        buf = &frame[offset];
  61
  62        buf[0] = (u8)id;
  63        buf[1] = (u8)(id >> 8);
  64        buf[2] = 1;
  65        buf[3] = 0;
  66        buf[4] = val8;
  67        return 5;
  68}
  69
  70static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16)
  71{
  72        u8 *buf;
  73
  74        if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE)
  75                return 0;
  76
  77        buf = &frame[offset];
  78
  79        buf[0] = (u8)id;
  80        buf[1] = (u8)(id >> 8);
  81        buf[2] = 2;
  82        buf[3] = 0;
  83        buf[4] = (u8)val16;
  84        buf[5] = (u8)(val16 >> 8);
  85
  86        return 6;
  87}
  88
  89static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32)
  90{
  91        u8 *buf;
  92
  93        if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE)
  94                return 0;
  95
  96        buf = &frame[offset];
  97
  98        buf[0] = (u8)id;
  99        buf[1] = (u8)(id >> 8);
 100        buf[2] = 4;
 101        buf[3] = 0;
 102        buf[4] = (u8)val32;
 103        buf[5] = (u8)(val32 >> 8);
 104        buf[6] = (u8)(val32 >> 16);
 105        buf[7] = (u8)(val32 >> 24);
 106
 107        return 8;
 108}
 109
 110static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str,
 111                                 u32 size)
 112{
 113        u8 *buf;
 114
 115        if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE)
 116                return 0;
 117
 118        buf = &frame[offset];
 119
 120        buf[0] = (u8)id;
 121        buf[1] = (u8)(id >> 8);
 122        buf[2] = (u8)size;
 123        buf[3] = (u8)(size >> 8);
 124
 125        if (str && size != 0)
 126                memcpy(&buf[4], str, size);
 127
 128        return (size + 4);
 129}
 130
 131static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size)
 132{
 133        u8 *buf;
 134        u32 i;
 135        u8 checksum = 0;
 136
 137        if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE)
 138                return 0;
 139
 140        buf = &frame[offset];
 141        buf[0] = (u8)id;
 142        buf[1] = (u8)(id >> 8);
 143        buf[2] = (u8)size;
 144        buf[3] = (u8)(size >> 8);
 145
 146        if ((b) && size != 0) {
 147                memcpy(&buf[4], b, size);
 148                for (i = 0; i < size; i++)
 149                        checksum += buf[i + 4];
 150        }
 151
 152        buf[size + 4] = checksum;
 153
 154        return (size + 5);
 155}
 156
 157/********************************************
 158 *
 159 *      Configuration Response Functions
 160 *
 161 ********************************************/
 162
 163#define GET_WID_TYPE(wid)               (((wid) >> 12) & 0x7)
 164static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size)
 165{
 166        u16 wid;
 167        u32 len = 0, i = 0;
 168
 169        while (size > 0) {
 170                i = 0;
 171                wid = get_unaligned_le16(info);
 172
 173                switch (GET_WID_TYPE(wid)) {
 174                case WID_CHAR:
 175                        do {
 176                                if (wl->cfg.b[i].id == WID_NIL)
 177                                        break;
 178
 179                                if (wl->cfg.b[i].id == wid) {
 180                                        wl->cfg.b[i].val = info[4];
 181                                        break;
 182                                }
 183                                i++;
 184                        } while (1);
 185                        len = 3;
 186                        break;
 187
 188                case WID_SHORT:
 189                        do {
 190                                struct wilc_cfg_hword *hw = &wl->cfg.hw[i];
 191
 192                                if (hw->id == WID_NIL)
 193                                        break;
 194
 195                                if (hw->id == wid) {
 196                                        hw->val = get_unaligned_le16(&info[4]);
 197                                        break;
 198                                }
 199                                i++;
 200                        } while (1);
 201                        len = 4;
 202                        break;
 203
 204                case WID_INT:
 205                        do {
 206                                struct wilc_cfg_word *w = &wl->cfg.w[i];
 207
 208                                if (w->id == WID_NIL)
 209                                        break;
 210
 211                                if (w->id == wid) {
 212                                        w->val = get_unaligned_le32(&info[4]);
 213                                        break;
 214                                }
 215                                i++;
 216                        } while (1);
 217                        len = 6;
 218                        break;
 219
 220                case WID_STR:
 221                        do {
 222                                if (wl->cfg.s[i].id == WID_NIL)
 223                                        break;
 224
 225                                if (wl->cfg.s[i].id == wid) {
 226                                        memcpy(wl->cfg.s[i].str, &info[2],
 227                                               (info[2] + 2));
 228                                        break;
 229                                }
 230                                i++;
 231                        } while (1);
 232                        len = 2 + info[2];
 233                        break;
 234
 235                default:
 236                        break;
 237                }
 238                size -= (2 + len);
 239                info += (2 + len);
 240        }
 241}
 242
 243static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info)
 244{
 245        u32 wid, len;
 246
 247        wid = get_unaligned_le16(info);
 248
 249        len = info[2];
 250
 251        if (len == 1 && wid == WID_STATUS) {
 252                int i = 0;
 253
 254                do {
 255                        if (wl->cfg.b[i].id == WID_NIL)
 256                                break;
 257
 258                        if (wl->cfg.b[i].id == wid) {
 259                                wl->cfg.b[i].val = info[3];
 260                                break;
 261                        }
 262                        i++;
 263                } while (1);
 264        }
 265}
 266
 267/********************************************
 268 *
 269 *      Configuration Exported Functions
 270 *
 271 ********************************************/
 272
 273int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size)
 274{
 275        u8 type = (id >> 12) & 0xf;
 276        int ret = 0;
 277
 278        switch (type) {
 279        case CFG_BYTE_CMD:
 280                if (size >= 1)
 281                        ret = wilc_wlan_cfg_set_byte(frame, offset, id, *buf);
 282                break;
 283
 284        case CFG_HWORD_CMD:
 285                if (size >= 2)
 286                        ret = wilc_wlan_cfg_set_hword(frame, offset, id,
 287                                                      *((u16 *)buf));
 288                break;
 289
 290        case CFG_WORD_CMD:
 291                if (size >= 4)
 292                        ret = wilc_wlan_cfg_set_word(frame, offset, id,
 293                                                     *((u32 *)buf));
 294                break;
 295
 296        case CFG_STR_CMD:
 297                ret = wilc_wlan_cfg_set_str(frame, offset, id, buf, size);
 298                break;
 299
 300        case CFG_BIN_CMD:
 301                ret = wilc_wlan_cfg_set_bin(frame, offset, id, buf, size);
 302                break;
 303        }
 304
 305        return ret;
 306}
 307
 308int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id)
 309{
 310        u8 *buf;
 311
 312        if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE)
 313                return 0;
 314
 315        buf = &frame[offset];
 316
 317        buf[0] = (u8)id;
 318        buf[1] = (u8)(id >> 8);
 319
 320        return 2;
 321}
 322
 323int wilc_wlan_cfg_get_wid_value(struct wilc *wl, u16 wid, u8 *buffer,
 324                                u32 buffer_size)
 325{
 326        u32 type = (wid >> 12) & 0xf;
 327        int i, ret = 0;
 328
 329        i = 0;
 330        if (type == CFG_BYTE_CMD) {
 331                do {
 332                        if (wl->cfg.b[i].id == WID_NIL)
 333                                break;
 334
 335                        if (wl->cfg.b[i].id == wid) {
 336                                memcpy(buffer, &wl->cfg.b[i].val, 1);
 337                                ret = 1;
 338                                break;
 339                        }
 340                        i++;
 341                } while (1);
 342        } else if (type == CFG_HWORD_CMD) {
 343                do {
 344                        if (wl->cfg.hw[i].id == WID_NIL)
 345                                break;
 346
 347                        if (wl->cfg.hw[i].id == wid) {
 348                                memcpy(buffer, &wl->cfg.hw[i].val, 2);
 349                                ret = 2;
 350                                break;
 351                        }
 352                        i++;
 353                } while (1);
 354        } else if (type == CFG_WORD_CMD) {
 355                do {
 356                        if (wl->cfg.w[i].id == WID_NIL)
 357                                break;
 358
 359                        if (wl->cfg.w[i].id == wid) {
 360                                memcpy(buffer, &wl->cfg.w[i].val, 4);
 361                                ret = 4;
 362                                break;
 363                        }
 364                        i++;
 365                } while (1);
 366        } else if (type == CFG_STR_CMD) {
 367                do {
 368                        u32 id = wl->cfg.s[i].id;
 369
 370                        if (id == WID_NIL)
 371                                break;
 372
 373                        if (id == wid) {
 374                                u16 size = get_unaligned_le16(wl->cfg.s[i].str);
 375
 376                                if (buffer_size >= size) {
 377                                        memcpy(buffer, &wl->cfg.s[i].str[2],
 378                                               size);
 379                                        ret = size;
 380                                }
 381                                break;
 382                        }
 383                        i++;
 384                } while (1);
 385        }
 386        return ret;
 387}
 388
 389void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size,
 390                               struct wilc_cfg_rsp *rsp)
 391{
 392        u8 msg_type;
 393        u8 msg_id;
 394
 395        msg_type = frame[0];
 396        msg_id = frame[1];      /* seq no */
 397        frame += 4;
 398        size -= 4;
 399        rsp->type = 0;
 400
 401        /*
 402         * The valid types of response messages are
 403         * 'R' (Response),
 404         * 'I' (Information), and
 405         * 'N' (Network Information)
 406         */
 407
 408        switch (msg_type) {
 409        case 'R':
 410                wilc_wlan_parse_response_frame(wilc, frame, size);
 411                rsp->type = WILC_CFG_RSP;
 412                rsp->seq_no = msg_id;
 413                break;
 414
 415        case 'I':
 416                wilc_wlan_parse_info_frame(wilc, frame);
 417                rsp->type = WILC_CFG_RSP_STATUS;
 418                rsp->seq_no = msg_id;
 419                /*call host interface info parse as well*/
 420                wilc_gnrl_async_info_received(wilc, frame - 4, size + 4);
 421                break;
 422
 423        case 'N':
 424                wilc_network_info_received(wilc, frame - 4, size + 4);
 425                break;
 426
 427        case 'S':
 428                wilc_scan_complete_received(wilc, frame - 4, size + 4);
 429                break;
 430
 431        default:
 432                rsp->seq_no = msg_id;
 433                break;
 434        }
 435}
 436
 437int wilc_wlan_cfg_init(struct wilc *wl)
 438{
 439        struct wilc_cfg_str_vals *str_vals;
 440        int i = 0;
 441
 442        wl->cfg.b = kmemdup(g_cfg_byte, sizeof(g_cfg_byte), GFP_KERNEL);
 443        if (!wl->cfg.b)
 444                return -ENOMEM;
 445
 446        wl->cfg.hw = kmemdup(g_cfg_hword, sizeof(g_cfg_hword), GFP_KERNEL);
 447        if (!wl->cfg.hw)
 448                goto out_b;
 449
 450        wl->cfg.w = kmemdup(g_cfg_word, sizeof(g_cfg_word), GFP_KERNEL);
 451        if (!wl->cfg.w)
 452                goto out_hw;
 453
 454        wl->cfg.s = kmemdup(g_cfg_str, sizeof(g_cfg_str), GFP_KERNEL);
 455        if (!wl->cfg.s)
 456                goto out_w;
 457
 458        str_vals = kzalloc(sizeof(*str_vals), GFP_KERNEL);
 459        if (!str_vals)
 460                goto out_s;
 461
 462        wl->cfg.str_vals = str_vals;
 463        /* store the string cfg parameters */
 464        wl->cfg.s[i].id = WID_FIRMWARE_VERSION;
 465        wl->cfg.s[i].str = str_vals->firmware_version;
 466        i++;
 467        wl->cfg.s[i].id = WID_MAC_ADDR;
 468        wl->cfg.s[i].str = str_vals->mac_address;
 469        i++;
 470        wl->cfg.s[i].id = WID_ASSOC_RES_INFO;
 471        wl->cfg.s[i].str = str_vals->assoc_rsp;
 472        i++;
 473        wl->cfg.s[i].id = WID_NIL;
 474        wl->cfg.s[i].str = NULL;
 475        return 0;
 476
 477out_s:
 478        kfree(wl->cfg.s);
 479out_w:
 480        kfree(wl->cfg.w);
 481out_hw:
 482        kfree(wl->cfg.hw);
 483out_b:
 484        kfree(wl->cfg.b);
 485        return -ENOMEM;
 486}
 487
 488void wilc_wlan_cfg_deinit(struct wilc *wl)
 489{
 490        kfree(wl->cfg.b);
 491        kfree(wl->cfg.hw);
 492        kfree(wl->cfg.w);
 493        kfree(wl->cfg.s);
 494        kfree(wl->cfg.str_vals);
 495}
 496