diff options
Diffstat (limited to 'drivers/net/wireless/libertas/cmd.c')
-rw-r--r-- | drivers/net/wireless/libertas/cmd.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 54ef990a46c..9064513aea0 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -2007,3 +2007,99 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode) lbs_deb_leave(LBS_DEB_HOST); } + + +/** + * @brief Simple way to call firmware functions + * + * @param priv A pointer to struct lbs_private structure + * @param psmode one of the many CMD_802_11_xxxx + * @param cmd pointer to the parameters structure for above command + * (this should not include the command, size, sequence + * and result fields from struct cmd_ds_gen) + * @param cmd_size size structure pointed to by cmd + * @param rsp pointer to an area where the result should be placed + * @param rsp_size pointer to the size of the rsp area. If the firmware + * returns fewer bytes, then this *rsp_size will be + * changed to the actual size. + * @return -1 in case of a higher level error, otherwise + * the result code from the firmware + */ +int lbs_cmd(struct lbs_private *priv, + u16 command, + void *cmd, int cmd_size, + void *rsp, int *rsp_size) +{ + struct lbs_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmdnode; + struct cmd_ds_gen *cmdptr; + unsigned long flags; + int ret = 0; + + lbs_deb_enter(LBS_DEB_HOST); + lbs_deb_host("rsp at %p, rsp_size at %p\n", rsp, rsp_size); + + if (!adapter || !rsp_size) { + lbs_deb_host("PREP_CMD: adapter is NULL\n"); + ret = -1; + goto done; + } + + if (adapter->surpriseremoved) { + lbs_deb_host("PREP_CMD: card removed\n"); + ret = -1; + goto done; + } + + cmdnode = lbs_get_cmd_ctrl_node(priv); + + if (cmdnode == NULL) { + lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); + + /* Wake up main thread to execute next command */ + wake_up_interruptible(&priv->waitq); + ret = -1; + goto done; + } + + cmdptr = (struct cmd_ds_gen *)cmdnode->bufvirtualaddr; + cmdnode->wait_option = CMD_OPTION_WAITFORRSP; + cmdnode->pdata_buf = rsp; + cmdnode->pdata_size = rsp_size; + + /* Set sequence number, clean result, move to buffer */ + adapter->seqnum++; + cmdptr->command = cpu_to_le16(command); + cmdptr->size = cmd_size + S_DS_GEN; + cmdptr->seqnum = cpu_to_le16(adapter->seqnum); + cmdptr->result = 0; + memcpy(cmdptr->cmdresp, cmd, cmd_size); + + lbs_deb_host("PREP_CMD: command 0x%04x\n", command); + + /* here was the big old switch() statement, which is now obsolete, + * because the caller of lbs_cmd() sets up all of *cmd for us. */ + + cmdnode->cmdwaitqwoken = 0; + lbs_queue_cmd(adapter, cmdnode, 1); + wake_up_interruptible(&priv->waitq); + + might_sleep(); + wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken); + + spin_lock_irqsave(&adapter->driver_lock, flags); + if (adapter->cur_cmd_retcode) { + lbs_deb_host("PREP_CMD: command failed with return code %d\n", + adapter->cur_cmd_retcode); + adapter->cur_cmd_retcode = 0; + ret = -1; + } + spin_unlock_irqrestore(&adapter->driver_lock, flags); + +done: + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(lbs_cmd); + + |