linux/drivers/net/wireless/libertas_tf/cmd.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2008, cozybit Inc.
   3 *  Copyright (C) 2003-2006, Marvell International Ltd.
   4 *
   5 *  This program is free software; you can redistribute it and/or modify
   6 *  it under the terms of the GNU General Public License as published by
   7 *  the Free Software Foundation; either version 2 of the License, or (at
   8 *  your option) any later version.
   9 */
  10#include "libertas_tf.h"
  11
  12static const struct channel_range channel_ranges[] = {
  13        { LBTF_REGDOMAIN_US,            1, 12 },
  14        { LBTF_REGDOMAIN_CA,            1, 12 },
  15        { LBTF_REGDOMAIN_EU,            1, 14 },
  16        { LBTF_REGDOMAIN_JP,            1, 14 },
  17        { LBTF_REGDOMAIN_SP,            1, 14 },
  18        { LBTF_REGDOMAIN_FR,            1, 14 },
  19};
  20
  21static u16 lbtf_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
  22{
  23        LBTF_REGDOMAIN_US, LBTF_REGDOMAIN_CA, LBTF_REGDOMAIN_EU,
  24        LBTF_REGDOMAIN_SP, LBTF_REGDOMAIN_FR, LBTF_REGDOMAIN_JP,
  25};
  26
  27static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv);
  28
  29
  30/**
  31 *  lbtf_cmd_copyback - Simple callback that copies response back into command
  32 *
  33 *  @priv       A pointer to struct lbtf_private structure
  34 *  @extra      A pointer to the original command structure for which
  35 *              'resp' is a response
  36 *  @resp       A pointer to the command response
  37 *
  38 *  Returns: 0 on success, error on failure
  39 */
  40int lbtf_cmd_copyback(struct lbtf_private *priv, unsigned long extra,
  41                     struct cmd_header *resp)
  42{
  43        struct cmd_header *buf = (void *)extra;
  44        uint16_t copy_len;
  45
  46        copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size));
  47        memcpy(buf, resp, copy_len);
  48        return 0;
  49}
  50EXPORT_SYMBOL_GPL(lbtf_cmd_copyback);
  51
  52#define CHAN_TO_IDX(chan) ((chan) - 1)
  53
  54static void lbtf_geo_init(struct lbtf_private *priv)
  55{
  56        const struct channel_range *range = channel_ranges;
  57        u8 ch;
  58        int i;
  59
  60        for (i = 0; i < ARRAY_SIZE(channel_ranges); i++)
  61                if (channel_ranges[i].regdomain == priv->regioncode) {
  62                        range = &channel_ranges[i];
  63                        break;
  64                }
  65
  66        for (ch = priv->range.start; ch < priv->range.end; ch++)
  67                priv->channels[CHAN_TO_IDX(ch)].flags = 0;
  68}
  69
  70/**
  71 *  lbtf_update_hw_spec: Updates the hardware details.
  72 *
  73 *  @priv       A pointer to struct lbtf_private structure
  74 *
  75 *  Returns: 0 on success, error on failure
  76 */
  77int lbtf_update_hw_spec(struct lbtf_private *priv)
  78{
  79        struct cmd_ds_get_hw_spec cmd;
  80        int ret = -1;
  81        u32 i;
  82
  83        memset(&cmd, 0, sizeof(cmd));
  84        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
  85        memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
  86        ret = lbtf_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd);
  87        if (ret)
  88                goto out;
  89
  90        priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo);
  91
  92        /* The firmware release is in an interesting format: the patch
  93         * level is in the most significant nibble ... so fix that: */
  94        priv->fwrelease = le32_to_cpu(cmd.fwrelease);
  95        priv->fwrelease = (priv->fwrelease << 8) |
  96                (priv->fwrelease >> 24 & 0xff);
  97
  98        printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n",
  99                cmd.permanentaddr,
 100                priv->fwrelease >> 24 & 0xff,
 101                priv->fwrelease >> 16 & 0xff,
 102                priv->fwrelease >>  8 & 0xff,
 103                priv->fwrelease       & 0xff,
 104                priv->fwcapinfo);
 105
 106        /* Clamp region code to 8-bit since FW spec indicates that it should
 107         * only ever be 8-bit, even though the field size is 16-bit.  Some
 108         * firmware returns non-zero high 8 bits here.
 109         */
 110        priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF;
 111
 112        for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
 113                /* use the region code to search for the index */
 114                if (priv->regioncode == lbtf_region_code_to_index[i])
 115                        break;
 116        }
 117
 118        /* if it's unidentified region code, use the default (USA) */
 119        if (i >= MRVDRV_MAX_REGION_CODE)
 120                priv->regioncode = 0x10;
 121
 122        if (priv->current_addr[0] == 0xff)
 123                memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
 124
 125        SET_IEEE80211_PERM_ADDR(priv->hw, priv->current_addr);
 126
 127        lbtf_geo_init(priv);
 128out:
 129        return ret;
 130}
 131
 132/**
 133 *  lbtf_set_channel: Set the radio channel
 134 *
 135 *  @priv       A pointer to struct lbtf_private structure
 136 *  @channel    The desired channel, or 0 to clear a locked channel
 137 *
 138 *  Returns: 0 on success, error on failure
 139 */
 140int lbtf_set_channel(struct lbtf_private *priv, u8 channel)
 141{
 142        struct cmd_ds_802_11_rf_channel cmd;
 143
 144        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 145        cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
 146        cmd.channel = cpu_to_le16(channel);
 147
 148        return lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
 149}
 150
 151int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
 152{
 153        struct cmd_ds_802_11_beacon_set cmd;
 154        int size;
 155
 156        if (beacon->len > MRVL_MAX_BCN_SIZE)
 157                return -1;
 158        size =  sizeof(cmd) - sizeof(cmd.beacon) + beacon->len;
 159        cmd.hdr.size = cpu_to_le16(size);
 160        cmd.len = cpu_to_le16(beacon->len);
 161        memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len);
 162
 163        lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size);
 164        return 0;
 165}
 166
 167int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
 168                     int beacon_int) {
 169        struct cmd_ds_802_11_beacon_control cmd;
 170
 171        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 172        cmd.action = cpu_to_le16(CMD_ACT_SET);
 173        cmd.beacon_enable = cpu_to_le16(beacon_enable);
 174        cmd.beacon_period = cpu_to_le16(beacon_int);
 175
 176        lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd));
 177        return 0;
 178}
 179
 180static void lbtf_queue_cmd(struct lbtf_private *priv,
 181                          struct cmd_ctrl_node *cmdnode)
 182{
 183        unsigned long flags;
 184
 185        if (!cmdnode)
 186                return;
 187
 188        if (!cmdnode->cmdbuf->size)
 189                return;
 190
 191        cmdnode->result = 0;
 192        spin_lock_irqsave(&priv->driver_lock, flags);
 193        list_add_tail(&cmdnode->list, &priv->cmdpendingq);
 194        spin_unlock_irqrestore(&priv->driver_lock, flags);
 195}
 196
 197static void lbtf_submit_command(struct lbtf_private *priv,
 198                               struct cmd_ctrl_node *cmdnode)
 199{
 200        unsigned long flags;
 201        struct cmd_header *cmd;
 202        uint16_t cmdsize;
 203        uint16_t command;
 204        int timeo = 5 * HZ;
 205        int ret;
 206
 207        cmd = cmdnode->cmdbuf;
 208
 209        spin_lock_irqsave(&priv->driver_lock, flags);
 210        priv->cur_cmd = cmdnode;
 211        cmdsize = le16_to_cpu(cmd->size);
 212        command = le16_to_cpu(cmd->command);
 213        ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
 214        spin_unlock_irqrestore(&priv->driver_lock, flags);
 215
 216        if (ret)
 217                /* Let the timer kick in and retry, and potentially reset
 218                   the whole thing if the condition persists */
 219                timeo = HZ;
 220
 221        /* Setup the timer after transmit command */
 222        mod_timer(&priv->command_timer, jiffies + timeo);
 223}
 224
 225/**
 226 *  This function inserts command node to cmdfreeq
 227 *  after cleans it. Requires priv->driver_lock held.
 228 */
 229static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
 230                                         struct cmd_ctrl_node *cmdnode)
 231{
 232        if (!cmdnode)
 233                return;
 234
 235        cmdnode->callback = NULL;
 236        cmdnode->callback_arg = 0;
 237
 238        memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
 239
 240        list_add_tail(&cmdnode->list, &priv->cmdfreeq);
 241}
 242
 243static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
 244        struct cmd_ctrl_node *ptempcmd)
 245{
 246        unsigned long flags;
 247
 248        spin_lock_irqsave(&priv->driver_lock, flags);
 249        __lbtf_cleanup_and_insert_cmd(priv, ptempcmd);
 250        spin_unlock_irqrestore(&priv->driver_lock, flags);
 251}
 252
 253void lbtf_complete_command(struct lbtf_private *priv, struct cmd_ctrl_node *cmd,
 254                          int result)
 255{
 256        cmd->result = result;
 257        cmd->cmdwaitqwoken = 1;
 258        wake_up_interruptible(&cmd->cmdwait_q);
 259
 260        if (!cmd->callback)
 261                __lbtf_cleanup_and_insert_cmd(priv, cmd);
 262        priv->cur_cmd = NULL;
 263}
 264
 265int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv)
 266{
 267        struct cmd_ds_mac_multicast_addr cmd;
 268
 269        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 270        cmd.action = cpu_to_le16(CMD_ACT_SET);
 271
 272        cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
 273        memcpy(cmd.maclist, priv->multicastlist,
 274               priv->nr_of_multicastmacaddr * ETH_ALEN);
 275
 276        lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd));
 277        return 0;
 278}
 279
 280void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode)
 281{
 282        struct cmd_ds_set_mode cmd;
 283
 284        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 285        cmd.mode = cpu_to_le16(mode);
 286        lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd));
 287}
 288
 289void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
 290{
 291        struct cmd_ds_set_bssid cmd;
 292
 293        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 294        cmd.activate = activate ? 1 : 0;
 295        if (activate)
 296                memcpy(cmd.bssid, bssid, ETH_ALEN);
 297
 298        lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd));
 299}
 300
 301int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
 302{
 303        struct cmd_ds_802_11_mac_address cmd;
 304
 305        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 306        cmd.action = cpu_to_le16(CMD_ACT_SET);
 307
 308        memcpy(cmd.macadd, mac_addr, ETH_ALEN);
 309
 310        lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd));
 311        return 0;
 312}
 313
 314int lbtf_set_radio_control(struct lbtf_private *priv)
 315{
 316        int ret = 0;
 317        struct cmd_ds_802_11_radio_control cmd;
 318
 319        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 320        cmd.action = cpu_to_le16(CMD_ACT_SET);
 321
 322        switch (priv->preamble) {
 323        case CMD_TYPE_SHORT_PREAMBLE:
 324                cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE);
 325                break;
 326
 327        case CMD_TYPE_LONG_PREAMBLE:
 328                cmd.control = cpu_to_le16(SET_LONG_PREAMBLE);
 329                break;
 330
 331        case CMD_TYPE_AUTO_PREAMBLE:
 332        default:
 333                cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE);
 334                break;
 335        }
 336
 337        if (priv->radioon)
 338                cmd.control |= cpu_to_le16(TURN_ON_RF);
 339        else
 340                cmd.control &= cpu_to_le16(~TURN_ON_RF);
 341
 342        ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
 343        return ret;
 344}
 345
 346void lbtf_set_mac_control(struct lbtf_private *priv)
 347{
 348        struct cmd_ds_mac_control cmd;
 349        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
 350        cmd.action = cpu_to_le16(priv->mac_control);
 351        cmd.reserved = 0;
 352
 353        lbtf_cmd_async(priv, CMD_MAC_CONTROL,
 354                &cmd.hdr, sizeof(cmd));
 355}
 356
 357/**
 358 *  lbtf_allocate_cmd_buffer - Allocates cmd buffer, links it to free cmd queue
 359 *
 360 *  @priv       A pointer to struct lbtf_private structure
 361 *
 362 *  Returns: 0 on success.
 363 */
 364int lbtf_allocate_cmd_buffer(struct lbtf_private *priv)
 365{
 366        u32 bufsize;
 367        u32 i;
 368        struct cmd_ctrl_node *cmdarray;
 369
 370        /* Allocate and initialize the command array */
 371        bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
 372        cmdarray = kzalloc(bufsize, GFP_KERNEL);
 373        if (!cmdarray)
 374                return -1;
 375        priv->cmd_array = cmdarray;
 376
 377        /* Allocate and initialize each command buffer in the command array */
 378        for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
 379                cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
 380                if (!cmdarray[i].cmdbuf)
 381                        return -1;
 382        }
 383
 384        for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
 385                init_waitqueue_head(&cmdarray[i].cmdwait_q);
 386                lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]);
 387        }
 388        return 0;
 389}
 390
 391/**
 392 *  lbtf_free_cmd_buffer - Frees the cmd buffer.
 393 *
 394 *  @priv       A pointer to struct lbtf_private structure
 395 *
 396 *  Returns: 0
 397 */
 398int lbtf_free_cmd_buffer(struct lbtf_private *priv)
 399{
 400        struct cmd_ctrl_node *cmdarray;
 401        unsigned int i;
 402
 403        /* need to check if cmd array is allocated or not */
 404        if (priv->cmd_array == NULL)
 405                return 0;
 406
 407        cmdarray = priv->cmd_array;
 408
 409        /* Release shared memory buffers */
 410        for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
 411                kfree(cmdarray[i].cmdbuf);
 412                cmdarray[i].cmdbuf = NULL;
 413        }
 414
 415        /* Release cmd_ctrl_node */
 416        kfree(priv->cmd_array);
 417        priv->cmd_array = NULL;
 418
 419        return 0;
 420}
 421
 422/**
 423 *  lbtf_get_cmd_ctrl_node - Gets free cmd node from free cmd queue.
 424 *
 425 *  @priv               A pointer to struct lbtf_private structure
 426 *
 427 *  Returns: pointer to a struct cmd_ctrl_node or NULL if none available.
 428 */
 429static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
 430{
 431        struct cmd_ctrl_node *tempnode;
 432        unsigned long flags;
 433
 434        if (!priv)
 435                return NULL;
 436
 437        spin_lock_irqsave(&priv->driver_lock, flags);
 438
 439        if (!list_empty(&priv->cmdfreeq)) {
 440                tempnode = list_first_entry(&priv->cmdfreeq,
 441                                            struct cmd_ctrl_node, list);
 442                list_del(&tempnode->list);
 443        } else
 444                tempnode = NULL;
 445
 446        spin_unlock_irqrestore(&priv->driver_lock, flags);
 447
 448        return tempnode;
 449}
 450
 451/**
 452 *  lbtf_execute_next_command: execute next command in cmd pending queue.
 453 *
 454 *  @priv     A pointer to struct lbtf_private structure
 455 *
 456 *  Returns: 0 on success.
 457 */
 458int lbtf_execute_next_command(struct lbtf_private *priv)
 459{
 460        struct cmd_ctrl_node *cmdnode = NULL;
 461        struct cmd_header *cmd;
 462        unsigned long flags;
 463
 464        /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
 465         * only caller to us is lbtf_thread() and we get even when a
 466         * data packet is received */
 467
 468        spin_lock_irqsave(&priv->driver_lock, flags);
 469
 470        if (priv->cur_cmd) {
 471                spin_unlock_irqrestore(&priv->driver_lock, flags);
 472                return -1;
 473        }
 474
 475        if (!list_empty(&priv->cmdpendingq)) {
 476                cmdnode = list_first_entry(&priv->cmdpendingq,
 477                                           struct cmd_ctrl_node, list);
 478        }
 479
 480        if (cmdnode) {
 481                cmd = cmdnode->cmdbuf;
 482
 483                list_del(&cmdnode->list);
 484                spin_unlock_irqrestore(&priv->driver_lock, flags);
 485                lbtf_submit_command(priv, cmdnode);
 486        } else
 487                spin_unlock_irqrestore(&priv->driver_lock, flags);
 488        return 0;
 489}
 490
 491static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
 492        uint16_t command, struct cmd_header *in_cmd, int in_cmd_size,
 493        int (*callback)(struct lbtf_private *, unsigned long,
 494                        struct cmd_header *),
 495        unsigned long callback_arg)
 496{
 497        struct cmd_ctrl_node *cmdnode;
 498
 499        if (priv->surpriseremoved)
 500                return ERR_PTR(-ENOENT);
 501
 502        cmdnode = lbtf_get_cmd_ctrl_node(priv);
 503        if (cmdnode == NULL) {
 504                /* Wake up main thread to execute next command */
 505                queue_work(lbtf_wq, &priv->cmd_work);
 506                return ERR_PTR(-ENOBUFS);
 507        }
 508
 509        cmdnode->callback = callback;
 510        cmdnode->callback_arg = callback_arg;
 511
 512        /* Copy the incoming command to the buffer */
 513        memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
 514
 515        /* Set sequence number, clean result, move to buffer */
 516        priv->seqnum++;
 517        cmdnode->cmdbuf->command = cpu_to_le16(command);
 518        cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
 519        cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
 520        cmdnode->cmdbuf->result  = 0;
 521        cmdnode->cmdwaitqwoken = 0;
 522        lbtf_queue_cmd(priv, cmdnode);
 523        queue_work(lbtf_wq, &priv->cmd_work);
 524
 525        return cmdnode;
 526}
 527
 528void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
 529        struct cmd_header *in_cmd, int in_cmd_size)
 530{
 531        __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0);
 532}
 533
 534int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
 535              struct cmd_header *in_cmd, int in_cmd_size,
 536              int (*callback)(struct lbtf_private *,
 537                              unsigned long, struct cmd_header *),
 538              unsigned long callback_arg)
 539{
 540        struct cmd_ctrl_node *cmdnode;
 541        unsigned long flags;
 542        int ret = 0;
 543
 544        cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
 545                                  callback, callback_arg);
 546        if (IS_ERR(cmdnode))
 547                return PTR_ERR(cmdnode);
 548
 549        might_sleep();
 550        ret = wait_event_interruptible(cmdnode->cmdwait_q,
 551                                       cmdnode->cmdwaitqwoken);
 552       if (ret) {
 553                printk(KERN_DEBUG
 554                       "libertastf: command 0x%04x interrupted by signal",
 555                       command);
 556                return ret;
 557        }
 558
 559        spin_lock_irqsave(&priv->driver_lock, flags);
 560        ret = cmdnode->result;
 561        if (ret)
 562                printk(KERN_DEBUG "libertastf: command 0x%04x failed: %d\n",
 563                            command, ret);
 564
 565        __lbtf_cleanup_and_insert_cmd(priv, cmdnode);
 566        spin_unlock_irqrestore(&priv->driver_lock, flags);
 567
 568        return ret;
 569}
 570EXPORT_SYMBOL_GPL(__lbtf_cmd);
 571
 572/* Call holding driver_lock */
 573void lbtf_cmd_response_rx(struct lbtf_private *priv)
 574{
 575        priv->cmd_response_rxed = 1;
 576        queue_work(lbtf_wq, &priv->cmd_work);
 577}
 578EXPORT_SYMBOL_GPL(lbtf_cmd_response_rx);
 579
 580int lbtf_process_rx_command(struct lbtf_private *priv)
 581{
 582        uint16_t respcmd, curcmd;
 583        struct cmd_header *resp;
 584        int ret = 0;
 585        unsigned long flags;
 586        uint16_t result;
 587
 588        mutex_lock(&priv->lock);
 589        spin_lock_irqsave(&priv->driver_lock, flags);
 590
 591        if (!priv->cur_cmd) {
 592                ret = -1;
 593                spin_unlock_irqrestore(&priv->driver_lock, flags);
 594                goto done;
 595        }
 596
 597        resp = (void *)priv->cmd_resp_buff;
 598        curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
 599        respcmd = le16_to_cpu(resp->command);
 600        result = le16_to_cpu(resp->result);
 601
 602        if (net_ratelimit())
 603                printk(KERN_DEBUG "libertastf: cmd response 0x%04x, seq %d, size %d\n",
 604                        respcmd, le16_to_cpu(resp->seqnum),
 605                        le16_to_cpu(resp->size));
 606
 607        if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
 608                spin_unlock_irqrestore(&priv->driver_lock, flags);
 609                ret = -1;
 610                goto done;
 611        }
 612        if (respcmd != CMD_RET(curcmd)) {
 613                spin_unlock_irqrestore(&priv->driver_lock, flags);
 614                ret = -1;
 615                goto done;
 616        }
 617
 618        if (resp->result == cpu_to_le16(0x0004)) {
 619                /* 0x0004 means -EAGAIN. Drop the response, let it time out
 620                   and be resubmitted */
 621                spin_unlock_irqrestore(&priv->driver_lock, flags);
 622                ret = -1;
 623                goto done;
 624        }
 625
 626        /* Now we got response from FW, cancel the command timer */
 627        del_timer(&priv->command_timer);
 628        priv->cmd_timed_out = 0;
 629        if (priv->nr_retries)
 630                priv->nr_retries = 0;
 631
 632        /* If the command is not successful, cleanup and return failure */
 633        if ((result != 0 || !(respcmd & 0x8000))) {
 634                /*
 635                 * Handling errors here
 636                 */
 637                switch (respcmd) {
 638                case CMD_RET(CMD_GET_HW_SPEC):
 639                case CMD_RET(CMD_802_11_RESET):
 640                        printk(KERN_DEBUG "libertastf: reset failed\n");
 641                        break;
 642
 643                }
 644                lbtf_complete_command(priv, priv->cur_cmd, result);
 645                spin_unlock_irqrestore(&priv->driver_lock, flags);
 646
 647                ret = -1;
 648                goto done;
 649        }
 650
 651        spin_unlock_irqrestore(&priv->driver_lock, flags);
 652
 653        if (priv->cur_cmd && priv->cur_cmd->callback) {
 654                ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg,
 655                                resp);
 656        }
 657        spin_lock_irqsave(&priv->driver_lock, flags);
 658
 659        if (priv->cur_cmd) {
 660                /* Clean up and Put current command back to cmdfreeq */
 661                lbtf_complete_command(priv, priv->cur_cmd, result);
 662        }
 663        spin_unlock_irqrestore(&priv->driver_lock, flags);
 664
 665done:
 666        mutex_unlock(&priv->lock);
 667        return ret;
 668}
 669