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 */ 52int 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} 81EXPORT_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 */ 92ssize_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); 149error: 150 return result; 151} 152EXPORT_SYMBOL_GPL(i1480_cmd); 153 154 155static 156int 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]); 167error: 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 */ 177int 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"); 205error_rc_release: 206 if (i1480->rc_release) 207 i1480->rc_release(i1480); 208 result = 0; 209error: 210 return result; 211} 212EXPORT_SYMBOL_GPL(i1480_fw_upload); 213