-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the driver for downloading the firmware to an Intel i1480 device. Signed-off-by: David Vrabel <david.vrabel@csr.com>
- Loading branch information
Inaky Perez-Gonzalez
authored and
David Vrabel
committed
Sep 17, 2008
1 parent
3b0c5a3
commit 1ba47da
Showing
10 changed files
with
1,898 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
obj-$(CONFIG_UWB_I1480U) += i1480-dfu-usb.o | ||
|
||
i1480-dfu-usb-objs := \ | ||
dfu.o \ | ||
mac.o \ | ||
phy.o \ | ||
usb.o | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
/* | ||
* Intel Wireless UWB Link 1480 | ||
* Main driver | ||
* | ||
* Copyright (C) 2005-2006 Intel Corporation | ||
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License version | ||
* 2 as published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
* 02110-1301, USA. | ||
* | ||
* | ||
* Common code for firmware upload used by the USB and PCI version; | ||
* i1480_fw_upload() takes a device descriptor and uses the function | ||
* pointers it provides to upload firmware and prepare the PHY. | ||
* | ||
* As well, provides common functions used by the rest of the code. | ||
*/ | ||
#include "i1480-dfu.h" | ||
#include <linux/errno.h> | ||
#include <linux/delay.h> | ||
#include <linux/pci.h> | ||
#include <linux/device.h> | ||
#include <linux/uwb.h> | ||
#include <linux/random.h> | ||
|
||
#define D_LOCAL 0 | ||
#include <linux/uwb/debug.h> | ||
|
||
/** @return 0 if If @evt is a valid reply event; otherwise complain */ | ||
int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb, | ||
const char *cmd, u8 context, | ||
unsigned expected_type, unsigned expected_event) | ||
{ | ||
int result = 0; | ||
struct device *dev = i1480->dev; | ||
if (rceb->bEventContext != context) { | ||
dev_err(dev, "%s: " | ||
"unexpected context id 0x%02x (expected 0x%02x)\n", | ||
cmd, rceb->bEventContext, context); | ||
result = -EINVAL; | ||
} | ||
if (rceb->bEventType != expected_type) { | ||
dev_err(dev, "%s: " | ||
"unexpected event type 0x%02x (expected 0x%02x)\n", | ||
cmd, rceb->bEventType, expected_type); | ||
result = -EINVAL; | ||
} | ||
if (le16_to_cpu(rceb->wEvent) != expected_event) { | ||
dev_err(dev, "%s: " | ||
"unexpected event 0x%04x (expected 0x%04x)\n", | ||
cmd, le16_to_cpu(rceb->wEvent), expected_event); | ||
result = -EINVAL; | ||
} | ||
return result; | ||
} | ||
EXPORT_SYMBOL_GPL(i1480_rceb_check); | ||
|
||
|
||
/** | ||
* Execute a Radio Control Command | ||
* | ||
* Command data has to be in i1480->cmd_buf. | ||
* | ||
* @returns size of the reply data filled in i1480->evt_buf or < 0 errno | ||
* code on error. | ||
*/ | ||
ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size, | ||
size_t reply_size) | ||
{ | ||
ssize_t result; | ||
struct uwb_rceb *reply = i1480->evt_buf; | ||
struct uwb_rccb *cmd = i1480->cmd_buf; | ||
u16 expected_event = reply->wEvent; | ||
u8 expected_type = reply->bEventType; | ||
u8 context; | ||
|
||
d_fnstart(3, i1480->dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size); | ||
init_completion(&i1480->evt_complete); | ||
i1480->evt_result = -EINPROGRESS; | ||
do { | ||
get_random_bytes(&context, 1); | ||
} while (context == 0x00 || context == 0xff); | ||
cmd->bCommandContext = context; | ||
result = i1480->cmd(i1480, cmd_name, cmd_size); | ||
if (result < 0) | ||
goto error; | ||
/* wait for the callback to report a event was received */ | ||
result = wait_for_completion_interruptible_timeout( | ||
&i1480->evt_complete, HZ); | ||
if (result == 0) { | ||
result = -ETIMEDOUT; | ||
goto error; | ||
} | ||
if (result < 0) | ||
goto error; | ||
result = i1480->evt_result; | ||
if (result < 0) { | ||
dev_err(i1480->dev, "%s: command reply reception failed: %zd\n", | ||
cmd_name, result); | ||
goto error; | ||
} | ||
if (result != reply_size) { | ||
dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n", | ||
cmd_name, result, reply_size); | ||
result = -EINVAL; | ||
goto error; | ||
} | ||
/* Verify we got the right event in response */ | ||
result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context, | ||
expected_type, expected_event); | ||
error: | ||
d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n", | ||
i1480, cmd_name, cmd_size, result); | ||
return result; | ||
} | ||
EXPORT_SYMBOL_GPL(i1480_cmd); | ||
|
||
|
||
/** | ||
* Get information about the MAC and PHY | ||
* | ||
* @wa: Wired adaptor | ||
* @neh: Notification/event handler | ||
* @reply: Pointer to the reply event buffer | ||
* @returns: 0 if ok, < 0 errno code on error. | ||
*/ | ||
static | ||
int i1480_cmd_get_mac_phy_info(struct i1480 *i1480) | ||
{ | ||
int result; | ||
struct uwb_rccb *cmd = i1480->cmd_buf; | ||
struct i1480_evt_confirm_GMPI *reply = i1480->evt_buf; | ||
|
||
cmd->bCommandType = i1480_CET_VS1; | ||
cmd->wCommand = cpu_to_le16(i1480_CMD_GET_MAC_PHY_INFO); | ||
reply->rceb.bEventType = i1480_CET_VS1; | ||
reply->rceb.wEvent = i1480_EVT_GET_MAC_PHY_INFO; | ||
result = i1480_cmd(i1480, "GET_MAC_PHY_INFO", sizeof(*cmd), | ||
sizeof(*reply)); | ||
if (result < 0) | ||
goto out; | ||
if (le16_to_cpu(reply->status) != 0x00) { | ||
dev_err(i1480->dev, | ||
"GET_MAC_PHY_INFO: command execution failed: %d\n", | ||
reply->status); | ||
result = -EIO; | ||
} | ||
out: | ||
return result; | ||
} | ||
|
||
|
||
/** | ||
* Get i1480's info and print it | ||
* | ||
* @wa: Wire Adapter | ||
* @neh: Notification/event handler | ||
* @returns: 0 if ok, < 0 errno code on error. | ||
*/ | ||
static | ||
int i1480_check_info(struct i1480 *i1480) | ||
{ | ||
struct i1480_evt_confirm_GMPI *reply = i1480->evt_buf; | ||
int result; | ||
unsigned mac_fw_rev; | ||
#if i1480_FW <= 0x00000302 | ||
unsigned phy_fw_rev; | ||
#endif | ||
if (i1480->quirk_no_check_info) { | ||
dev_err(i1480->dev, "firmware info check disabled\n"); | ||
return 0; | ||
} | ||
|
||
result = i1480_cmd_get_mac_phy_info(i1480); | ||
if (result < 0) { | ||
dev_err(i1480->dev, "Cannot get MAC & PHY information: %d\n", | ||
result); | ||
goto out; | ||
} | ||
mac_fw_rev = le16_to_cpu(reply->mac_fw_rev); | ||
#if i1480_FW > 0x00000302 | ||
dev_info(i1480->dev, | ||
"HW v%02hx " | ||
"MAC FW v%02hx.%02hx caps %04hx " | ||
"PHY type %02hx v%02hx caps %02hx %02hx %02hx\n", | ||
reply->hw_rev, mac_fw_rev >> 8, mac_fw_rev & 0xff, | ||
le16_to_cpu(reply->mac_caps), | ||
reply->phy_vendor, reply->phy_rev, | ||
reply->phy_caps[0], reply->phy_caps[1], reply->phy_caps[2]); | ||
#else | ||
phy_fw_rev = le16_to_cpu(reply->phy_fw_rev); | ||
dev_info(i1480->dev, "MAC FW v%02hx.%02hx caps %04hx " | ||
" PHY FW v%02hx.%02hx caps %04hx\n", | ||
mac_fw_rev >> 8, mac_fw_rev & 0xff, | ||
le16_to_cpu(reply->mac_caps), | ||
phy_fw_rev >> 8, phy_fw_rev & 0xff, | ||
le16_to_cpu(reply->phy_caps)); | ||
#endif | ||
dev_dbg(i1480->dev, | ||
"key-stores:%hu mcast-addr-stores:%hu sec-modes:%hu\n", | ||
(unsigned short) reply->key_stores, | ||
le16_to_cpu(reply->mcast_addr_stores), | ||
(unsigned short) reply->sec_mode_supported); | ||
/* FIXME: complain if fw version too low -- pending for | ||
* numbering to stabilize */ | ||
out: | ||
return result; | ||
} | ||
|
||
|
||
static | ||
int i1480_print_state(struct i1480 *i1480) | ||
{ | ||
int result; | ||
u32 *buf = (u32 *) i1480->cmd_buf; | ||
|
||
result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf)); | ||
if (result < 0) { | ||
dev_err(i1480->dev, "cannot read U & L states: %d\n", result); | ||
goto error; | ||
} | ||
dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]); | ||
error: | ||
return result; | ||
} | ||
|
||
|
||
/* | ||
* PCI probe, firmware uploader | ||
* | ||
* _mac_fw_upload() will call rc_setup(), which needs an rc_release(). | ||
*/ | ||
int i1480_fw_upload(struct i1480 *i1480) | ||
{ | ||
int result; | ||
|
||
result = i1480_pre_fw_upload(i1480); /* PHY pre fw */ | ||
if (result < 0 && result != -ENOENT) { | ||
i1480_print_state(i1480); | ||
goto error; | ||
} | ||
result = i1480_mac_fw_upload(i1480); /* MAC fw */ | ||
if (result < 0) { | ||
if (result == -ENOENT) | ||
dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n", | ||
i1480->mac_fw_name); | ||
else | ||
i1480_print_state(i1480); | ||
goto error; | ||
} | ||
result = i1480_phy_fw_upload(i1480); /* PHY fw */ | ||
if (result < 0 && result != -ENOENT) { | ||
i1480_print_state(i1480); | ||
goto error_rc_release; | ||
} | ||
result = i1480_check_info(i1480); | ||
if (result < 0) { | ||
dev_warn(i1480->dev, "Warning! Cannot check firmware info: %d\n", | ||
result); | ||
result = 0; | ||
} | ||
dev_info(i1480->dev, "firmware uploaded successfully\n"); | ||
error_rc_release: | ||
if (i1480->rc_release) | ||
i1480->rc_release(i1480); | ||
result = 0; | ||
error: | ||
return result; | ||
} | ||
EXPORT_SYMBOL_GPL(i1480_fw_upload); |
Oops, something went wrong.