• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/uwb/i1480/dfu/
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 */
51int 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}
80EXPORT_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 */
91ssize_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);
148error:
149	return result;
150}
151EXPORT_SYMBOL_GPL(i1480_cmd);
152
153
154static
155int 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]);
166error:
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 */
176int 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	dev_info(i1480->dev, "firmware uploaded successfully\n");
200error_rc_release:
201	if (i1480->rc_release)
202		i1480->rc_release(i1480);
203	result = 0;
204error:
205	return result;
206}
207EXPORT_SYMBOL_GPL(i1480_fw_upload);
208