aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb/i1480/dfu/dfu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/uwb/i1480/dfu/dfu.c')
-rw-r--r--drivers/uwb/i1480/dfu/dfu.c217
1 files changed, 217 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..9097b3b30385
--- /dev/null
+++ b/drivers/uwb/i1480/dfu/dfu.c
@@ -0,0 +1,217 @@
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/**
41 * i1480_rceb_check - Check RCEB for expected field values
42 * @i1480: pointer to device for which RCEB is being checked
43 * @rceb: RCEB being checked
44 * @cmd: which command the RCEB is related to
45 * @context: expected context
46 * @expected_type: expected event type
47 * @expected_event: expected event
48 *
49 * If @cmd is NULL, do not print error messages, but still return an error
50 * code.
51 *
52 * Return 0 if @rceb matches the expected values, -EINVAL otherwise.
53 */
54int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
55 const char *cmd, u8 context, u8 expected_type,
56 unsigned expected_event)
57{
58 int result = 0;
59 struct device *dev = i1480->dev;
60 if (rceb->bEventContext != context) {
61 if (cmd)
62 dev_err(dev, "%s: unexpected context id 0x%02x "
63 "(expected 0x%02x)\n", cmd,
64 rceb->bEventContext, context);
65 result = -EINVAL;
66 }
67 if (rceb->bEventType != expected_type) {
68 if (cmd)
69 dev_err(dev, "%s: unexpected event type 0x%02x "
70 "(expected 0x%02x)\n", cmd,
71 rceb->bEventType, expected_type);
72 result = -EINVAL;
73 }
74 if (le16_to_cpu(rceb->wEvent) != expected_event) {
75 if (cmd)
76 dev_err(dev, "%s: unexpected event 0x%04x "
77 "(expected 0x%04x)\n", cmd,
78 le16_to_cpu(rceb->wEvent), expected_event);
79 result = -EINVAL;
80 }
81 return result;
82}
83EXPORT_SYMBOL_GPL(i1480_rceb_check);
84
85
86/**
87 * Execute a Radio Control Command
88 *
89 * Command data has to be in i1480->cmd_buf.
90 *
91 * @returns size of the reply data filled in i1480->evt_buf or < 0 errno
92 * code on error.
93 */
94ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
95 size_t reply_size)
96{
97 ssize_t result;
98 struct uwb_rceb *reply = i1480->evt_buf;
99 struct uwb_rccb *cmd = i1480->cmd_buf;
100 u16 expected_event = reply->wEvent;
101 u8 expected_type = reply->bEventType;
102 u8 context;
103
104 d_fnstart(3, i1480->dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size);
105 init_completion(&i1480->evt_complete);
106 i1480->evt_result = -EINPROGRESS;
107 do {
108 get_random_bytes(&context, 1);
109 } while (context == 0x00 || context == 0xff);
110 cmd->bCommandContext = context;
111 result = i1480->cmd(i1480, cmd_name, cmd_size);
112 if (result < 0)
113 goto error;
114 /* wait for the callback to report a event was received */
115 result = wait_for_completion_interruptible_timeout(
116 &i1480->evt_complete, HZ);
117 if (result == 0) {
118 result = -ETIMEDOUT;
119 goto error;
120 }
121 if (result < 0)
122 goto error;
123 result = i1480->evt_result;
124 if (result < 0) {
125 dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
126 cmd_name, result);
127 goto error;
128 }
129 /*
130 * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a
131 * spurious notification after firmware is downloaded. So check whether
132 * the receibed RCEB is such notification before assuming that the
133 * command has failed.
134 */
135 if (i1480_rceb_check(i1480, i1480->evt_buf, NULL,
136 0, 0xfd, 0x0022) == 0) {
137 /* Now wait for the actual RCEB for this command. */
138 result = i1480->wait_init_done(i1480);
139 if (result < 0)
140 goto error;
141 result = i1480->evt_result;
142 }
143 if (result != reply_size) {
144 dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
145 cmd_name, result, reply_size);
146 result = -EINVAL;
147 goto error;
148 }
149 /* Verify we got the right event in response */
150 result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
151 expected_type, expected_event);
152error:
153 d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n",
154 i1480, cmd_name, cmd_size, result);
155 return result;
156}
157EXPORT_SYMBOL_GPL(i1480_cmd);
158
159
160static
161int i1480_print_state(struct i1480 *i1480)
162{
163 int result;
164 u32 *buf = (u32 *) i1480->cmd_buf;
165
166 result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
167 if (result < 0) {
168 dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
169 goto error;
170 }
171 dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
172error:
173 return result;
174}
175
176
177/*
178 * PCI probe, firmware uploader
179 *
180 * _mac_fw_upload() will call rc_setup(), which needs an rc_release().
181 */
182int i1480_fw_upload(struct i1480 *i1480)
183{
184 int result;
185
186 result = i1480_pre_fw_upload(i1480); /* PHY pre fw */
187 if (result < 0 && result != -ENOENT) {
188 i1480_print_state(i1480);
189 goto error;
190 }
191 result = i1480_mac_fw_upload(i1480); /* MAC fw */
192 if (result < 0) {
193 if (result == -ENOENT)
194 dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
195 i1480->mac_fw_name);
196 else
197 i1480_print_state(i1480);
198 goto error;
199 }
200 result = i1480_phy_fw_upload(i1480); /* PHY fw */
201 if (result < 0 && result != -ENOENT) {
202 i1480_print_state(i1480);
203 goto error_rc_release;
204 }
205 /*
206 * FIXME: find some reliable way to check whether firmware is running
207 * properly. Maybe use some standard request that has no side effects?
208 */
209 dev_info(i1480->dev, "firmware uploaded successfully\n");
210error_rc_release:
211 if (i1480->rc_release)
212 i1480->rc_release(i1480);
213 result = 0;
214error:
215 return result;
216}
217EXPORT_SYMBOL_GPL(i1480_fw_upload);