Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/dvrabel/uwb
[linux-2.6] / drivers / uwb / i1480 / dfu / dfu.c
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  */
54 int 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 }
83 EXPORT_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  */
94 ssize_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);
152 error:
153         d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n",
154                 i1480, cmd_name, cmd_size, result);
155         return result;
156 }
157 EXPORT_SYMBOL_GPL(i1480_cmd);
158
159
160 static
161 int 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]);
172 error:
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  */
182 int 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");
210 error_rc_release:
211         if (i1480->rc_release)
212                 i1480->rc_release(i1480);
213         result = 0;
214 error:
215         return result;
216 }
217 EXPORT_SYMBOL_GPL(i1480_fw_upload);