aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb/i1480/dfu/dfu.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>2008-09-17 11:34:20 -0400
committerDavid Vrabel <dv02@dv02pc01.europe.root.pri>2008-09-17 11:54:28 -0400
commit1ba47da527121ff704f4e9f27a12c9f32db05022 (patch)
tree742d5db40e92ee7912cdcfaadcf7321b917498f7 /drivers/uwb/i1480/dfu/dfu.c
parent3b0c5a3818555988b6235144e0174b1a512719b7 (diff)
uwb: add the i1480 DFU driver
Add the driver for downloading the firmware to an Intel i1480 device. Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers/uwb/i1480/dfu/dfu.c')
-rw-r--r--drivers/uwb/i1480/dfu/dfu.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/drivers/uwb/i1480/dfu/dfu.c b/drivers/uwb/i1480/dfu/dfu.c
new file mode 100644
index 000000000000..ebffaf542153
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/dfu.c
@@ -0,0 +1,281 @@
1/*
2 * Intel Wireless UWB Link 1480
3 * Main driver
4 *
5 * Copyright (C) 2005-2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * Common code for firmware upload used by the USB and PCI version;
24 * i1480_fw_upload() takes a device descriptor and uses the function
25 * pointers it provides to upload firmware and prepare the PHY.
26 *
27 * As well, provides common functions used by the rest of the code.
28 */
29#include "i1480-dfu.h"
30#include <linux/errno.h>
31#include <linux/delay.h>
32#include <linux/pci.h>
33#include <linux/device.h>
34#include <linux/uwb.h>
35#include <linux/random.h>
36
37#define D_LOCAL 0
38#include <linux/uwb/debug.h>
39
40/** @return 0 if If @evt is a valid reply event; otherwise complain */
41int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
42 const char *cmd, u8 context,
43 unsigned expected_type, unsigned expected_event)
44{
45 int result = 0;
46 struct device *dev = i1480->dev;
47 if (rceb->bEventContext != context) {
48 dev_err(dev, "%s: "
49 "unexpected context id 0x%02x (expected 0x%02x)\n",
50 cmd, rceb->bEventContext, context);
51 result = -EINVAL;
52 }
53 if (rceb->bEventType != expected_type) {
54 dev_err(dev, "%s: "
55 "unexpected event type 0x%02x (expected 0x%02x)\n",
56 cmd, rceb->bEventType, expected_type);
57 result = -EINVAL;
58 }
59 if (le16_to_cpu(rceb->wEvent) != expected_event) {
60 dev_err(dev, "%s: "
61 "unexpected event 0x%04x (expected 0x%04x)\n",
62 cmd, le16_to_cpu(rceb->wEvent), expected_event);
63 result = -EINVAL;
64 }
65 return result;
66}
67EXPORT_SYMBOL_GPL(i1480_rceb_check);
68
69
70/**
71 * Execute a Radio Control Command
72 *
73 * Command data has to be in i1480->cmd_buf.
74 *
75 * @returns size of the reply data filled in i1480->evt_buf or < 0 errno
76 * code on error.
77 */
78ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
79 size_t reply_size)
80{
81 ssize_t result;
82 struct uwb_rceb *reply = i1480->evt_buf;
83 struct uwb_rccb *cmd = i1480->cmd_buf;
84 u16 expected_event = reply->wEvent;
85 u8 expected_type = reply->bEventType;
86 u8 context;
87
88 d_fnstart(3, i1480->dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size);
89 init_completion(&i1480->evt_complete);
90 i1480->evt_result = -EINPROGRESS;
91 do {
92 get_random_bytes(&context, 1);
93 } while (context == 0x00 || context == 0xff);
94 cmd->bCommandContext = context;
95 result = i1480->cmd(i1480, cmd_name, cmd_size);
96 if (result < 0)
97 goto error;
98 /* wait for the callback to report a event was received */
99 result = wait_for_completion_interruptible_timeout(
100 &i1480->evt_complete, HZ);
101 if (result == 0) {
102 result = -ETIMEDOUT;
103 goto error;
104 }
105 if (result < 0)
106 goto error;
107 result = i1480->evt_result;
108 if (result < 0) {
109 dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
110 cmd_name, result);
111 goto error;
112 }
113 if (result != reply_size) {
114 dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
115 cmd_name, result, reply_size);
116 result = -EINVAL;
117 goto error;
118 }
119 /* Verify we got the right event in response */
120 result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
121 expected_type, expected_event);
122error:
123 d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n",
124 i1480, cmd_name, cmd_size, result);
125 return result;
126}
127EXPORT_SYMBOL_GPL(i1480_cmd);
128
129
130/**
131 * Get information about the MAC and PHY
132 *
133 * @wa: Wired adaptor
134 * @neh: Notification/event handler
135 * @reply: Pointer to the reply event buffer
136 * @returns: 0 if ok, < 0 errno code on error.
137 */
138static
139int i1480_cmd_get_mac_phy_info(struct i1480 *i1480)
140{
141 int result;
142 struct uwb_rccb *cmd = i1480->cmd_buf;
143 struct i1480_evt_confirm_GMPI *reply = i1480->evt_buf;
144
145 cmd->bCommandType = i1480_CET_VS1;
146 cmd->wCommand = cpu_to_le16(i1480_CMD_GET_MAC_PHY_INFO);
147 reply->rceb.bEventType = i1480_CET_VS1;
148 reply->rceb.wEvent = i1480_EVT_GET_MAC_PHY_INFO;
149 result = i1480_cmd(i1480, "GET_MAC_PHY_INFO", sizeof(*cmd),
150 sizeof(*reply));
151 if (result < 0)
152 goto out;
153 if (le16_to_cpu(reply->status) != 0x00) {
154 dev_err(i1480->dev,
155 "GET_MAC_PHY_INFO: command execution failed: %d\n",
156 reply->status);
157 result = -EIO;
158 }
159out:
160 return result;
161}
162
163
164/**
165 * Get i1480's info and print it
166 *
167 * @wa: Wire Adapter
168 * @neh: Notification/event handler
169 * @returns: 0 if ok, < 0 errno code on error.
170 */
171static
172int i1480_check_info(struct i1480 *i1480)
173{
174 struct i1480_evt_confirm_GMPI *reply = i1480->evt_buf;
175 int result;
176 unsigned mac_fw_rev;
177#if i1480_FW <= 0x00000302
178 unsigned phy_fw_rev;
179#endif
180 if (i1480->quirk_no_check_info) {
181 dev_err(i1480->dev, "firmware info check disabled\n");
182 return 0;
183 }
184
185 result = i1480_cmd_get_mac_phy_info(i1480);
186 if (result < 0) {
187 dev_err(i1480->dev, "Cannot get MAC & PHY information: %d\n",
188 result);
189 goto out;
190 }
191 mac_fw_rev = le16_to_cpu(reply->mac_fw_rev);
192#if i1480_FW > 0x00000302
193 dev_info(i1480->dev,
194 "HW v%02hx "
195 "MAC FW v%02hx.%02hx caps %04hx "
196 "PHY type %02hx v%02hx caps %02hx %02hx %02hx\n",
197 reply->hw_rev, mac_fw_rev >> 8, mac_fw_rev & 0xff,
198 le16_to_cpu(reply->mac_caps),
199 reply->phy_vendor, reply->phy_rev,
200 reply->phy_caps[0], reply->phy_caps[1], reply->phy_caps[2]);
201#else
202 phy_fw_rev = le16_to_cpu(reply->phy_fw_rev);
203 dev_info(i1480->dev, "MAC FW v%02hx.%02hx caps %04hx "
204 " PHY FW v%02hx.%02hx caps %04hx\n",
205 mac_fw_rev >> 8, mac_fw_rev & 0xff,
206 le16_to_cpu(reply->mac_caps),
207 phy_fw_rev >> 8, phy_fw_rev & 0xff,
208 le16_to_cpu(reply->phy_caps));
209#endif
210 dev_dbg(i1480->dev,
211 "key-stores:%hu mcast-addr-stores:%hu sec-modes:%hu\n",
212 (unsigned short) reply->key_stores,
213 le16_to_cpu(reply->mcast_addr_stores),
214 (unsigned short) reply->sec_mode_supported);
215 /* FIXME: complain if fw version too low -- pending for
216 * numbering to stabilize */
217out:
218 return result;
219}
220
221
222static
223int i1480_print_state(struct i1480 *i1480)
224{
225 int result;
226 u32 *buf = (u32 *) i1480->cmd_buf;
227
228 result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
229 if (result < 0) {
230 dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
231 goto error;
232 }
233 dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
234error:
235 return result;
236}
237
238
239/*
240 * PCI probe, firmware uploader
241 *
242 * _mac_fw_upload() will call rc_setup(), which needs an rc_release().
243 */
244int i1480_fw_upload(struct i1480 *i1480)
245{
246 int result;
247
248 result = i1480_pre_fw_upload(i1480); /* PHY pre fw */
249 if (result < 0 && result != -ENOENT) {
250 i1480_print_state(i1480);
251 goto error;
252 }
253 result = i1480_mac_fw_upload(i1480); /* MAC fw */
254 if (result < 0) {
255 if (result == -ENOENT)
256 dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
257 i1480->mac_fw_name);
258 else
259 i1480_print_state(i1480);
260 goto error;
261 }
262 result = i1480_phy_fw_upload(i1480); /* PHY fw */
263 if (result < 0 && result != -ENOENT) {
264 i1480_print_state(i1480);
265 goto error_rc_release;
266 }
267 result = i1480_check_info(i1480);
268 if (result < 0) {
269 dev_warn(i1480->dev, "Warning! Cannot check firmware info: %d\n",
270 result);
271 result = 0;
272 }
273 dev_info(i1480->dev, "firmware uploaded successfully\n");
274error_rc_release:
275 if (i1480->rc_release)
276 i1480->rc_release(i1480);
277 result = 0;
278error:
279 return result;
280}
281EXPORT_SYMBOL_GPL(i1480_fw_upload);