diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00firmware.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00firmware.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c new file mode 100644 index 000000000000..236025f8b90f --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | Copyright (C) 2004 - 2007 rt2x00 SourceForge Project | ||
3 | <http://rt2x00.serialmonkey.com> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the | ||
17 | Free Software Foundation, Inc., | ||
18 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | Module: rt2x00lib | ||
23 | Abstract: rt2x00 firmware loading routines. | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * Set enviroment defines for rt2x00.h | ||
28 | */ | ||
29 | #define DRV_NAME "rt2x00lib" | ||
30 | |||
31 | #include <linux/crc-itu-t.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/module.h> | ||
34 | |||
35 | #include "rt2x00.h" | ||
36 | #include "rt2x00lib.h" | ||
37 | |||
38 | static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev) | ||
39 | { | ||
40 | struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); | ||
41 | const struct firmware *fw; | ||
42 | char *fw_name; | ||
43 | int retval; | ||
44 | u16 crc; | ||
45 | u16 tmp; | ||
46 | |||
47 | /* | ||
48 | * Read correct firmware from harddisk. | ||
49 | */ | ||
50 | fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev); | ||
51 | if (!fw_name) { | ||
52 | ERROR(rt2x00dev, | ||
53 | "Invalid firmware filename.\n" | ||
54 | "Please file bug report to %s.\n", DRV_PROJECT); | ||
55 | return -EINVAL; | ||
56 | } | ||
57 | |||
58 | INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name); | ||
59 | |||
60 | retval = request_firmware(&fw, fw_name, device); | ||
61 | if (retval) { | ||
62 | ERROR(rt2x00dev, "Failed to request Firmware.\n"); | ||
63 | return retval; | ||
64 | } | ||
65 | |||
66 | if (!fw || !fw->size || !fw->data) { | ||
67 | ERROR(rt2x00dev, "Failed to read Firmware.\n"); | ||
68 | return -ENOENT; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Validate the firmware using 16 bit CRC. | ||
73 | * The last 2 bytes of the firmware are the CRC | ||
74 | * so substract those 2 bytes from the CRC checksum, | ||
75 | * and set those 2 bytes to 0 when calculating CRC. | ||
76 | */ | ||
77 | tmp = 0; | ||
78 | crc = crc_itu_t(0, fw->data, fw->size - 2); | ||
79 | crc = crc_itu_t(crc, (u8 *)&tmp, 2); | ||
80 | |||
81 | if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) { | ||
82 | ERROR(rt2x00dev, "Firmware CRC error.\n"); | ||
83 | retval = -ENOENT; | ||
84 | goto exit; | ||
85 | } | ||
86 | |||
87 | INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n", | ||
88 | fw->data[fw->size - 4], fw->data[fw->size - 3]); | ||
89 | |||
90 | rt2x00dev->fw = fw; | ||
91 | |||
92 | return 0; | ||
93 | |||
94 | exit: | ||
95 | release_firmware(fw); | ||
96 | |||
97 | return retval; | ||
98 | } | ||
99 | |||
100 | int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev) | ||
101 | { | ||
102 | int retval; | ||
103 | |||
104 | if (!rt2x00dev->fw) { | ||
105 | retval = rt2x00lib_request_firmware(rt2x00dev); | ||
106 | if (retval) | ||
107 | return retval; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Send firmware to the device. | ||
112 | */ | ||
113 | retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev, | ||
114 | rt2x00dev->fw->data, | ||
115 | rt2x00dev->fw->size); | ||
116 | return retval; | ||
117 | } | ||
118 | |||
119 | void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) | ||
120 | { | ||
121 | release_firmware(rt2x00dev->fw); | ||
122 | rt2x00dev->fw = NULL; | ||
123 | } | ||
124 | |||