Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 1 | /* |
Gertjan van Wingerde | 9c9a0d1 | 2009-11-08 16:39:55 +0100 | [diff] [blame] | 2 | Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> |
| 3 | Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com> |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 4 | <http://rt2x00.serialmonkey.com> |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify |
| 7 | it under the terms of the GNU General Public License as published by |
| 8 | the Free Software Foundation; either version 2 of the License, or |
| 9 | (at your option) any later version. |
| 10 | |
| 11 | This program is distributed in the hope that it will be useful, |
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | GNU General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU General Public License |
Jeff Kirsher | a05b8c5 | 2013-12-06 03:32:11 -0800 | [diff] [blame] | 17 | along with this program; if not, see <http://www.gnu.org/licenses/>. |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 18 | */ |
| 19 | |
| 20 | /* |
| 21 | Module: rt2x00lib |
| 22 | Abstract: rt2x00 firmware loading routines. |
| 23 | */ |
| 24 | |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 25 | #include <linux/kernel.h> |
| 26 | #include <linux/module.h> |
| 27 | |
| 28 | #include "rt2x00.h" |
| 29 | #include "rt2x00lib.h" |
| 30 | |
| 31 | static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) |
| 32 | { |
| 33 | struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); |
| 34 | const struct firmware *fw; |
| 35 | char *fw_name; |
| 36 | int retval; |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 37 | |
| 38 | /* |
| 39 | * Read correct firmware from harddisk. |
| 40 | */ |
| 41 | fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev); |
| 42 | if (!fw_name) { |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 43 | rt2x00_err(rt2x00dev, |
| 44 | "Invalid firmware filename\n" |
| 45 | "Please file bug report to %s\n", DRV_PROJECT); |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 46 | return -EINVAL; |
| 47 | } |
| 48 | |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 49 | rt2x00_info(rt2x00dev, "Loading firmware file '%s'\n", fw_name); |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 50 | |
| 51 | retval = request_firmware(&fw, fw_name, device); |
| 52 | if (retval) { |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 53 | rt2x00_err(rt2x00dev, "Failed to request Firmware\n"); |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 54 | return retval; |
| 55 | } |
| 56 | |
| 57 | if (!fw || !fw->size || !fw->data) { |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 58 | rt2x00_err(rt2x00dev, "Failed to read Firmware\n"); |
Jesper Juhl | ccbd4d4 | 2011-01-11 00:47:44 +0100 | [diff] [blame] | 59 | release_firmware(fw); |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 60 | return -ENOENT; |
| 61 | } |
| 62 | |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 63 | rt2x00_info(rt2x00dev, "Firmware detected - version: %d.%d\n", |
| 64 | fw->data[fw->size - 4], fw->data[fw->size - 3]); |
John W. Linville | dd358c9 | 2010-07-29 13:50:39 -0400 | [diff] [blame] | 65 | snprintf(rt2x00dev->hw->wiphy->fw_version, |
| 66 | sizeof(rt2x00dev->hw->wiphy->fw_version), "%d.%d", |
| 67 | fw->data[fw->size - 4], fw->data[fw->size - 3]); |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 68 | |
Ivo van Doorn | 0cbe006 | 2009-01-28 00:33:47 +0100 | [diff] [blame] | 69 | retval = rt2x00dev->ops->lib->check_firmware(rt2x00dev, fw->data, fw->size); |
| 70 | switch (retval) { |
| 71 | case FW_OK: |
| 72 | break; |
| 73 | case FW_BAD_CRC: |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 74 | rt2x00_err(rt2x00dev, "Firmware checksum error\n"); |
Ivo van Doorn | 0cbe006 | 2009-01-28 00:33:47 +0100 | [diff] [blame] | 75 | goto exit; |
| 76 | case FW_BAD_LENGTH: |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 77 | rt2x00_err(rt2x00dev, "Invalid firmware file length (len=%zu)\n", |
| 78 | fw->size); |
Ivo van Doorn | 0cbe006 | 2009-01-28 00:33:47 +0100 | [diff] [blame] | 79 | goto exit; |
| 80 | case FW_BAD_VERSION: |
Joe Perches | ec9c498 | 2013-04-19 08:33:40 -0700 | [diff] [blame] | 81 | rt2x00_err(rt2x00dev, "Current firmware does not support detected chipset\n"); |
Ivo van Doorn | 0cbe006 | 2009-01-28 00:33:47 +0100 | [diff] [blame] | 82 | goto exit; |
Joe Perches | ee289b6 | 2010-05-17 22:47:34 -0700 | [diff] [blame] | 83 | } |
Ivo van Doorn | 0cbe006 | 2009-01-28 00:33:47 +0100 | [diff] [blame] | 84 | |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 85 | rt2x00dev->fw = fw; |
| 86 | |
| 87 | return 0; |
| 88 | |
| 89 | exit: |
| 90 | release_firmware(fw); |
| 91 | |
Ivo van Doorn | 0cbe006 | 2009-01-28 00:33:47 +0100 | [diff] [blame] | 92 | return -ENOENT; |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) |
| 96 | { |
| 97 | int retval; |
| 98 | |
Fred Chou | b9d305c | 2014-12-26 16:19:18 +0800 | [diff] [blame] | 99 | if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_FIRMWARE)) |
Ivo van Doorn | 9404ef3 | 2008-02-03 15:48:38 +0100 | [diff] [blame] | 100 | return 0; |
| 101 | |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 102 | if (!rt2x00dev->fw) { |
| 103 | retval = rt2x00lib_request_firmware(rt2x00dev); |
| 104 | if (retval) |
| 105 | return retval; |
| 106 | } |
| 107 | |
| 108 | /* |
| 109 | * Send firmware to the device. |
| 110 | */ |
| 111 | retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev, |
| 112 | rt2x00dev->fw->data, |
| 113 | rt2x00dev->fw->size); |
Ivo van Doorn | 4c9adaf | 2008-07-13 10:07:48 +0200 | [diff] [blame] | 114 | |
| 115 | /* |
| 116 | * When the firmware is uploaded to the hardware the LED |
| 117 | * association status might have been triggered, for correct |
| 118 | * LED handling it should now be reset. |
| 119 | */ |
| 120 | rt2x00leds_led_assoc(rt2x00dev, false); |
| 121 | |
Ivo van Doorn | 95ea362 | 2007-09-25 17:57:13 -0700 | [diff] [blame] | 122 | return retval; |
| 123 | } |
| 124 | |
| 125 | void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) |
| 126 | { |
| 127 | release_firmware(rt2x00dev->fw); |
| 128 | rt2x00dev->fw = NULL; |
| 129 | } |