aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHolger Schurig <h.schurig@mn-solutions.de>2007-12-05 11:58:11 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:06:04 -0500
commit675787e29fd97d08bf7e6253c89ab6de23bf7089 (patch)
tree81a51dd6696e5ba67a87e6b4bf2ee368854f23b7 /drivers
parent0d61d04210b617963c202a3c4dcbcd26a024d5d3 (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')
-rw-r--r--drivers/net/wireless/libertas/cmd.c96
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c23
-rw-r--r--drivers/net/wireless/libertas/decl.h6
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h11
4 files changed, 126 insertions, 10 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 */
2028int 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
2099done:
2100 lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
2101 return ret;
2102}
2103EXPORT_SYMBOL_GPL(lbs_cmd);
2104
2105
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index cbd28ee7c5b8..6a43de772aa0 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -799,7 +799,7 @@ int lbs_process_rx_command(struct lbs_private *priv)
799 } 799 }
800 800
801 /* Store the response code to cur_cmd_retcode. */ 801 /* Store the response code to cur_cmd_retcode. */
802 adapter->cur_cmd_retcode = result;; 802 adapter->cur_cmd_retcode = result;
803 803
804 if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { 804 if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
805 struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; 805 struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
@@ -880,11 +880,22 @@ int lbs_process_rx_command(struct lbs_private *priv)
880 goto done; 880 goto done;
881 } 881 }
882 882
883 spin_unlock_irqrestore(&adapter->driver_lock, flags); 883 if (adapter->cur_cmd->pdata_size) {
884 884 struct cmd_ds_gen *r = (struct cmd_ds_gen *)resp;
885 ret = handle_cmd_response(respcmd, resp, priv); 885 u16 sz = cpu_to_le16(resp->size);
886 886 if (sz > *adapter->cur_cmd->pdata_size) {
887 spin_lock_irqsave(&adapter->driver_lock, flags); 887 lbs_pr_err("response 0x%04x doesn't fit into "
888 "buffer (%d > %d)\n", respcmd,
889 sz, *adapter->cur_cmd->pdata_size);
890 sz = *adapter->cur_cmd->pdata_size;
891 }
892 memcpy(adapter->cur_cmd->pdata_buf, r->cmdresp, sz);
893 *adapter->cur_cmd->pdata_size = sz;
894 } else {
895 spin_unlock_irqrestore(&adapter->driver_lock, flags);
896 ret = handle_cmd_response(respcmd, resp, priv);
897 spin_lock_irqsave(&adapter->driver_lock, flags);
898 }
888 if (adapter->cur_cmd) { 899 if (adapter->cur_cmd) {
889 /* Clean up and Put current command back to cmdfreeq */ 900 /* Clean up and Put current command back to cmdfreeq */
890 __lbs_cleanup_and_insert_cmd(priv, adapter->cur_cmd); 901 __lbs_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 0856cc96f513..6f47ff089622 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -16,6 +16,7 @@ struct lbs_adapter;
16struct sk_buff; 16struct sk_buff;
17struct net_device; 17struct net_device;
18struct cmd_ctrl_node; 18struct cmd_ctrl_node;
19struct cmd_ds_command;
19 20
20int lbs_set_mac_packet_filter(struct lbs_private *priv); 21int lbs_set_mac_packet_filter(struct lbs_private *priv);
21 22
@@ -23,6 +24,11 @@ void lbs_send_tx_feedback(struct lbs_private *priv);
23 24
24int lbs_free_cmd_buffer(struct lbs_private *priv); 25int lbs_free_cmd_buffer(struct lbs_private *priv);
25 26
27int lbs_cmd(struct lbs_private *priv,
28 u16 command,
29 void *cmd, int cmd_size,
30 void *resp, int *resp_size);
31
26int lbs_prepare_and_send_command(struct lbs_private *priv, 32int lbs_prepare_and_send_command(struct lbs_private *priv,
27 u16 cmd_no, 33 u16 cmd_no,
28 u16 cmd_action, 34 u16 cmd_action,
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index f096d995194a..be69ae652923 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -66,13 +66,13 @@ struct rxpd {
66}; 66};
67 67
68struct cmd_ctrl_node { 68struct cmd_ctrl_node {
69 /* CMD link list */
70 struct list_head list; 69 struct list_head list;
71 /*CMD wait option: wait for finish or no wait */ 70 /* wait for finish or not */
72 u16 wait_option; 71 u16 wait_option;
73 /* command parameter */ 72 /* command response */
74 void *pdata_buf; 73 void *pdata_buf;
75 /*command data */ 74 int *pdata_size;
75 /* command data */
76 u8 *bufvirtualaddr; 76 u8 *bufvirtualaddr;
77 /* wait queue */ 77 /* wait queue */
78 u16 cmdwaitqwoken; 78 u16 cmdwaitqwoken;
@@ -100,9 +100,12 @@ struct cmd_ds_gen {
100 __le16 size; 100 __le16 size;
101 __le16 seqnum; 101 __le16 seqnum;
102 __le16 result; 102 __le16 result;
103 void *cmdresp[0];
103}; 104};
104 105
105#define S_DS_GEN sizeof(struct cmd_ds_gen) 106#define S_DS_GEN sizeof(struct cmd_ds_gen)
107
108
106/* 109/*
107 * Define data structure for CMD_GET_HW_SPEC 110 * Define data structure for CMD_GET_HW_SPEC
108 * This structure defines the response for the GET_HW_SPEC command 111 * This structure defines the response for the GET_HW_SPEC command