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