-
Notifications
You must be signed in to change notification settings - Fork 455
/
version_compat.c
237 lines (201 loc) · 7.76 KB
/
version_compat.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/**
* This file is part of the bladeRF project:
* http://www.github.com/nuand/bladeRF
*
* Copyright (C) 2014 Nuand LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "version_compat.h"
#include "bladerf_priv.h"
#include "rel_assert.h"
#include "log.h"
#define VERSION(major, minor, patch) { major, minor, patch, NULL }
#define OLDEST_SUPPORTED(tbl) (&tbl[ARRAY_SIZE(tbl) - 1].ver)
/* Firmware-FPGA compatibility tables
*
* This list should be kept in decending order, such that the most recent
* versions are first, and the last entry should contain the earliest version
* that libbladeRF supports.
*/
struct compat {
struct bladerf_version ver;
struct bladerf_version requires;
};
static const struct compat fw_compat_tbl[] = {
/* Firmware requires >= FPGA */
{ VERSION(1, 7, 1), VERSION(0, 0, 2) },
{ VERSION(1, 7, 0), VERSION(0, 0, 2) },
{ VERSION(1, 6, 1), VERSION(0, 0, 2) },
{ VERSION(1, 6, 0), VERSION(0, 0, 1) },
};
static const struct compat fpga_compat_tbl[] = {
/* FPGA requires >= Firmware */
{ VERSION(0, 0, 6), VERSION(1, 6, 1) },
{ VERSION(0, 0, 5), VERSION(1, 6, 1) },
{ VERSION(0, 0, 4), VERSION(1, 6, 1) },
{ VERSION(0, 0, 3), VERSION(1, 6, 1) },
{ VERSION(0, 0, 2), VERSION(1, 6, 1) },
{ VERSION(0, 0, 1), VERSION(1, 6, 0) },
};
static const struct compat * find_fw_match(const struct bladerf *dev)
{
size_t i;
const struct compat *newest_fw = &fw_compat_tbl[0];
/* Version is newer than what's in our table - complain */
if (version_less_than(&newest_fw->ver,
dev->fw_version.major,
dev->fw_version.minor,
dev->fw_version.patch)) {
log_warning("New firmware version (v%u.%u.%u) detected. "
"A developer needs to update the table in %s!\n",
dev->fw_version.major, dev->fw_version.minor,
dev->fw_version.patch, __FILE__);
return newest_fw;
}
for (i = 0; i < ARRAY_SIZE(fw_compat_tbl); i++) {
if (version_equal(&dev->fw_version, &fw_compat_tbl[i].ver)) {
return &fw_compat_tbl[i];
}
}
return NULL;
}
static const struct compat * find_fpga_match(const struct bladerf *dev)
{
size_t i;
const struct compat *newest_fpga = &fpga_compat_tbl[0];
/* Device's FPGA is newer than what's in our table - complain */
if (version_less_than(&newest_fpga->ver,
dev->fpga_version.major,
dev->fpga_version.minor,
dev->fpga_version.patch)) {
log_warning("New FPGA version (v%u.%u.%u) detected. "
"A developer needs to update the table in %s!\n",
dev->fpga_version.major, dev->fpga_version.minor,
dev->fpga_version.patch, __FILE__);
return newest_fpga;
}
for (i = 0; i < ARRAY_SIZE(fpga_compat_tbl); i++) {
if (version_equal(&dev->fpga_version, &fpga_compat_tbl[i].ver)) {
return &fpga_compat_tbl[i];
}
}
return NULL;
}
static inline void required_values(const struct compat *entry,
unsigned int *major,
unsigned int *minor,
unsigned int *patch)
{
*major = entry->requires.major;
*minor = entry->requires.minor;
*patch = entry->requires.patch;
}
int version_check_fw(const struct bladerf *dev)
{
static const struct bladerf_version *ver = OLDEST_SUPPORTED(fw_compat_tbl);
if (version_greater_or_equal(&dev->fw_version,
ver->major, ver->minor, ver->patch)) {
return 0;
} else {
return BLADERF_ERR_UPDATE_FW;
}
}
void version_required_fw(const struct bladerf *dev,
struct bladerf_version *version, bool by_fpga)
{
if (by_fpga) {
const struct compat *fpga = find_fpga_match(dev);
if (fpga == NULL) {
log_debug("%s is missing FPGA version compat table entry?",
__FUNCTION__);
memset(version, 0, sizeof(version[0]));
assert(!"BUG!");
} else {
memcpy(version, &fpga->requires, sizeof(version[0]));
}
} else {
const struct bladerf_version *required_version =
OLDEST_SUPPORTED(fw_compat_tbl);
memcpy(version, required_version, sizeof(version[0]));
}
}
int version_check_fpga(const struct bladerf *dev)
{
const struct compat *fw = find_fw_match(dev);
const struct compat *fpga = find_fpga_match(dev);
unsigned int major, minor, patch;
/* We didn't find a compatible firmware or FPGA versions in our list. */
if (fw == NULL) {
return BLADERF_ERR_UPDATE_FW;
} else if (fpga == NULL) {
return BLADERF_ERR_UPDATE_FPGA;
}
/* Check if the FPGA meets the minimum requirements dictated by the
* firmware version */
required_values(fw, &major, &minor, &patch);
if (version_less_than(&dev->fpga_version, major, minor, patch)) {
return BLADERF_ERR_UPDATE_FPGA;
}
/* Check if the firmware version meets the minimum requirements dictated
* by the FPGA version */
required_values(fpga, &major, &minor, &patch);
if (version_less_than(&dev->fw_version, major, minor, patch)) {
return BLADERF_ERR_UPDATE_FW;
}
return 0;
}
void version_required_fpga(struct bladerf *dev, struct bladerf_version *version)
{
const struct compat *entry = find_fw_match(dev);
if (entry == NULL) {
/* If this happens, someone didn't test the code before committing,
* and jynik will be forced to bring out the git blame bat. */
log_debug("%s called before FW version check?", __FUNCTION__);
memset(version, 0, sizeof(version[0]));
assert(!"BUG!");
} else {
memcpy(version, &entry->requires, sizeof(version[0]));
}
}
bool version_equal(const struct bladerf_version *v1,
const struct bladerf_version *v2)
{
return v1->major == v2->major &&
v1->minor == v2->minor &&
v1->patch == v2->patch;
}
bool version_greater_or_equal(const struct bladerf_version *version,
unsigned int major, unsigned int minor,
unsigned int patch)
{
if (version->major > major) {
return true;
} else if ( (version->major == major) && (version->minor > minor) ) {
return true;
} else if ((version->major == major) &&
(version->minor == minor) &&
(version->patch >= patch) ) {
return true;
} else {
return false;
}
}
bool version_less_than(const struct bladerf_version *version,
unsigned int major, unsigned int minor,
unsigned int patch)
{
return !version_greater_or_equal(version, major, minor, patch);
}