diff options
author | Holger Schurig <h.schurig@mn-solutions.de> | 2007-12-05 11:58:11 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:06:04 -0500 |
commit | 675787e29fd97d08bf7e6253c89ab6de23bf7089 (patch) | |
tree | 81a51dd6696e5ba67a87e6b4bf2ee368854f23b7 /drivers/net/wireless/libertas/cmd.c | |
parent | 0d61d04210b617963c202a3c4dcbcd26a024d5d3 (diff) |
libertas: handy function to call firmware commands
Using an arbitrary firmware command was actually very painful. One
had to change big switch() statements in cmd.c, cmdresp.c, add
structs to the big union in "struct cmd_ds_command" and add the
define for the CMD_802_11_xxx to the proper place.
With this function, this is now much easier. For now, it implements
a blocking (a.k.a. CMD_OPTION_WAITFORRSP) way where one deals directly
with command requests and response buffers. You can do everything in
one place:
Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
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 54ef990a46cc..9064513aea0d 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) | |||
2007 | 2007 | ||
2008 | lbs_deb_leave(LBS_DEB_HOST); | 2008 | lbs_deb_leave(LBS_DEB_HOST); |
2009 | } | 2009 | } |
2010 | |||
2011 | |||
2012 | /** | ||
2013 | * @brief Simple way to call firmware functions | ||
2014 | * | ||
2015 | * @param priv A pointer to struct lbs_private structure | ||
2016 | * @param psmode one of the many CMD_802_11_xxxx | ||
2017 | * @param cmd pointer to the parameters structure for above command | ||
2018 | * (this should not include the command, size, sequence | ||
2019 | * and result fields from struct cmd_ds_gen) | ||
2020 | * @param cmd_size size structure pointed to by cmd | ||
2021 | * @param rsp pointer to an area where the result should be placed | ||
2022 | * @param rsp_size pointer to the size of the rsp area. If the firmware | ||
2023 | * returns fewer bytes, then this *rsp_size will be | ||
2024 | * changed to the actual size. | ||
2025 | * @return -1 in case of a higher level error, otherwise | ||
2026 | * the result code from the firmware | ||
2027 | */ | ||
2028 | int lbs_cmd(struct lbs_private *priv, | ||
2029 | u16 command, | ||
2030 | void *cmd, int cmd_size, | ||
2031 | void *rsp, int *rsp_size) | ||
2032 | { | ||
2033 | struct lbs_adapter *adapter = priv->adapter; | ||
2034 | struct cmd_ctrl_node *cmdnode; | ||
2035 | struct cmd_ds_gen *cmdptr; | ||
2036 | unsigned long flags; | ||
2037 | int ret = 0; | ||
2038 | |||
2039 | lbs_deb_enter(LBS_DEB_HOST); | ||
2040 | lbs_deb_host("rsp at %p, rsp_size at %p\n", rsp, rsp_size); | ||
2041 | |||
2042 | if (!adapter || !rsp_size) { | ||
2043 | lbs_deb_host("PREP_CMD: adapter is NULL\n"); | ||
2044 | ret = -1; | ||
2045 | goto done; | ||
2046 | } | ||
2047 | |||
2048 | if (adapter->surpriseremoved) { | ||
2049 | lbs_deb_host("PREP_CMD: card removed\n"); | ||
2050 | ret = -1; | ||
2051 | goto done; | ||
2052 | } | ||
2053 | |||
2054 | cmdnode = lbs_get_cmd_ctrl_node(priv); | ||
2055 | |||
2056 | if (cmdnode == NULL) { | ||
2057 | lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); | ||
2058 | |||
2059 | /* Wake up main thread to execute next command */ | ||
2060 | wake_up_interruptible(&priv->waitq); | ||
2061 | ret = -1; | ||
2062 | goto done; | ||
2063 | } | ||
2064 | |||
2065 | cmdptr = (struct cmd_ds_gen *)cmdnode->bufvirtualaddr; | ||
2066 | cmdnode->wait_option = CMD_OPTION_WAITFORRSP; | ||
2067 | cmdnode->pdata_buf = rsp; | ||
2068 | cmdnode->pdata_size = rsp_size; | ||
2069 | |||
2070 | /* Set sequence number, clean result, move to buffer */ | ||
2071 | adapter->seqnum++; | ||
2072 | cmdptr->command = cpu_to_le16(command); | ||
2073 | cmdptr->size = cmd_size + S_DS_GEN; | ||
2074 | cmdptr->seqnum = cpu_to_le16(adapter->seqnum); | ||
2075 | cmdptr->result = 0; | ||
2076 | memcpy(cmdptr->cmdresp, cmd, cmd_size); | ||
2077 | |||
2078 | lbs_deb_host("PREP_CMD: command 0x%04x\n", command); | ||
2079 | |||
2080 | /* here was the big old switch() statement, which is now obsolete, | ||
2081 | * because the caller of lbs_cmd() sets up all of *cmd for us. */ | ||
2082 | |||
2083 | cmdnode->cmdwaitqwoken = 0; | ||
2084 | lbs_queue_cmd(adapter, cmdnode, 1); | ||
2085 | wake_up_interruptible(&priv->waitq); | ||
2086 | |||
2087 | might_sleep(); | ||
2088 | wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken); | ||
2089 | |||
2090 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
2091 | if (adapter->cur_cmd_retcode) { | ||
2092 | lbs_deb_host("PREP_CMD: command failed with return code %d\n", | ||
2093 | adapter->cur_cmd_retcode); | ||
2094 | adapter->cur_cmd_retcode = 0; | ||
2095 | ret = -1; | ||
2096 | } | ||
2097 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
2098 | |||
2099 | done: | ||
2100 | lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); | ||
2101 | return ret; | ||
2102 | } | ||
2103 | EXPORT_SYMBOL_GPL(lbs_cmd); | ||
2104 | |||
2105 | |||