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