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