]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - drivers/uwb/i1480/dfu/dfu.c
uwb: add the i1480 DFU driver
[linux-2.6.git] / 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 /** @return 0 if If @evt is a valid reply event; otherwise complain */
41 int 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 }
67 EXPORT_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  */
78 ssize_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);
122 error:
123         d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n",
124                 i1480, cmd_name, cmd_size, result);
125         return result;
126 }
127 EXPORT_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  */
138 static
139 int 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         }
159 out:
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  */
171 static
172 int 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 */
217 out:
218         return result;
219 }
220
221
222 static
223 int 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]);
234 error:
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  */
244 int 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");
274 error_rc_release:
275         if (i1480->rc_release)
276                 i1480->rc_release(i1480);
277         result = 0;
278 error:
279         return result;
280 }
281 EXPORT_SYMBOL_GPL(i1480_fw_upload);