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