Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/ath3kfw/ath3k_hw.c
107609 views
1
/*-
2
* Copyright (c) 2013 Adrian Chadd <[email protected]>
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer,
10
* without modification.
11
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
12
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13
* redistribution must be conditioned upon including a substantially
14
* similar Disclaimer requirement for further binary redistribution.
15
*
16
* NO WARRANTY
17
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27
* THE POSSIBILITY OF SUCH DAMAGES.
28
*/
29
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <unistd.h>
33
#include <errno.h>
34
#include <string.h>
35
#include <err.h>
36
#include <fcntl.h>
37
#include <sys/endian.h>
38
#include <sys/types.h>
39
#include <sys/stat.h>
40
41
#include <libusb.h>
42
43
#include "ath3k_fw.h"
44
#include "ath3k_hw.h"
45
#include "ath3k_dbg.h"
46
47
#define XMIN(x, y) ((x) < (y) ? (x) : (y))
48
49
int
50
ath3k_load_fwfile(struct libusb_device_handle *hdl,
51
const struct ath3k_firmware *fw)
52
{
53
int size, count, sent = 0;
54
int ret, r;
55
56
count = fw->len;
57
58
size = XMIN(count, FW_HDR_SIZE);
59
60
ath3k_debug("%s: file=%s, size=%d\n",
61
__func__, fw->fwname, count);
62
63
/*
64
* Flip the device over to configuration mode.
65
*/
66
ret = libusb_control_transfer(hdl,
67
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
68
ATH3K_DNLOAD,
69
0,
70
0,
71
fw->buf + sent,
72
size,
73
1000); /* XXX timeout */
74
75
if (ret != size) {
76
fprintf(stderr, "Can't switch to config mode; ret=%d\n",
77
ret);
78
return (-1);
79
}
80
81
sent += size;
82
count -= size;
83
84
/* Load in the rest of the data */
85
while (count) {
86
size = XMIN(count, BULK_SIZE);
87
ath3k_debug("%s: transferring %d bytes, offset %d\n",
88
__func__,
89
sent,
90
size);
91
92
ret = libusb_bulk_transfer(hdl,
93
0x2,
94
fw->buf + sent,
95
size,
96
&r,
97
1000);
98
99
if (ret < 0 || r != size) {
100
fprintf(stderr, "Can't load firmware: err=%s, size=%d\n",
101
libusb_strerror(ret),
102
size);
103
return (-1);
104
}
105
sent += size;
106
count -= size;
107
}
108
return (0);
109
}
110
111
int
112
ath3k_get_state(struct libusb_device_handle *hdl, unsigned char *state)
113
{
114
int ret;
115
116
ret = libusb_control_transfer(hdl,
117
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
118
ATH3K_GETSTATE,
119
0,
120
0,
121
state,
122
1,
123
1000); /* XXX timeout */
124
125
if (ret < 0) {
126
fprintf(stderr,
127
"%s: libusb_control_transfer() failed: code=%d\n",
128
__func__,
129
ret);
130
return (0);
131
}
132
133
return (ret == 1);
134
}
135
136
int
137
ath3k_get_version(struct libusb_device_handle *hdl,
138
struct ath3k_version *version)
139
{
140
int ret;
141
142
ret = libusb_control_transfer(hdl,
143
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
144
ATH3K_GETVERSION,
145
0,
146
0,
147
(unsigned char *) version,
148
sizeof(struct ath3k_version),
149
1000); /* XXX timeout */
150
151
if (ret < 0) {
152
fprintf(stderr,
153
"%s: libusb_control_transfer() failed: code=%d\n",
154
__func__,
155
ret);
156
return (0);
157
}
158
159
/* XXX endian fix! */
160
161
return (ret == sizeof(struct ath3k_version));
162
}
163
164
int
165
ath3k_load_patch(libusb_device_handle *hdl, const char *fw_path)
166
{
167
int ret;
168
unsigned char fw_state;
169
struct ath3k_version fw_ver, pt_ver;
170
char fwname[FILENAME_MAX];
171
struct ath3k_firmware fw;
172
uint32_t tmp;
173
174
ret = ath3k_get_state(hdl, &fw_state);
175
if (ret < 0) {
176
ath3k_err("%s: Can't get state\n", __func__);
177
return (ret);
178
}
179
180
if (fw_state & ATH3K_PATCH_UPDATE) {
181
ath3k_info("%s: Patch already downloaded\n",
182
__func__);
183
return (0);
184
}
185
186
ret = ath3k_get_version(hdl, &fw_ver);
187
if (ret < 0) {
188
ath3k_debug("%s: Can't get version\n", __func__);
189
return (ret);
190
}
191
192
/* XXX path info? */
193
snprintf(fwname, FILENAME_MAX, "%s/ar3k/AthrBT_0x%08x.dfu",
194
fw_path,
195
fw_ver.rom_version);
196
197
/* Read in the firmware */
198
if (ath3k_fw_read(&fw, fwname) <= 0) {
199
ath3k_debug("%s: ath3k_fw_read() failed\n",
200
__func__);
201
return (-1);
202
}
203
204
/*
205
* Extract the ROM/build version from the patch file.
206
*/
207
memcpy(&tmp, fw.buf + fw.len - 8, sizeof(tmp));
208
pt_ver.rom_version = le32toh(tmp);
209
memcpy(&tmp, fw.buf + fw.len - 4, sizeof(tmp));
210
pt_ver.build_version = le32toh(tmp);
211
212
ath3k_info("%s: file %s: rom_ver=%d, build_ver=%d\n",
213
__func__,
214
fwname,
215
(int) pt_ver.rom_version,
216
(int) pt_ver.build_version);
217
218
/* Check the ROM/build version against the firmware */
219
if ((pt_ver.rom_version != fw_ver.rom_version) ||
220
(pt_ver.build_version <= fw_ver.build_version)) {
221
ath3k_debug("Patch file version mismatch!\n");
222
ath3k_fw_free(&fw);
223
return (-1);
224
}
225
226
/* Load in the firmware */
227
ret = ath3k_load_fwfile(hdl, &fw);
228
229
/* free it */
230
ath3k_fw_free(&fw);
231
232
return (ret);
233
}
234
235
int
236
ath3k_load_syscfg(libusb_device_handle *hdl, const char *fw_path)
237
{
238
unsigned char fw_state;
239
char filename[FILENAME_MAX];
240
struct ath3k_firmware fw;
241
struct ath3k_version fw_ver;
242
int clk_value, ret;
243
244
ret = ath3k_get_state(hdl, &fw_state);
245
if (ret < 0) {
246
ath3k_err("Can't get state to change to load configuration err");
247
return (-EBUSY);
248
}
249
250
ret = ath3k_get_version(hdl, &fw_ver);
251
if (ret < 0) {
252
ath3k_err("Can't get version to change to load ram patch err");
253
return (ret);
254
}
255
256
switch (fw_ver.ref_clock) {
257
case ATH3K_XTAL_FREQ_26M:
258
clk_value = 26;
259
break;
260
case ATH3K_XTAL_FREQ_40M:
261
clk_value = 40;
262
break;
263
case ATH3K_XTAL_FREQ_19P2:
264
clk_value = 19;
265
break;
266
default:
267
clk_value = 0;
268
break;
269
}
270
271
snprintf(filename, FILENAME_MAX, "%s/ar3k/ramps_0x%08x_%d%s",
272
fw_path,
273
fw_ver.rom_version,
274
clk_value,
275
".dfu");
276
277
ath3k_info("%s: syscfg file = %s\n",
278
__func__,
279
filename);
280
281
/* Read in the firmware */
282
if (ath3k_fw_read(&fw, filename) <= 0) {
283
ath3k_err("%s: ath3k_fw_read() failed\n",
284
__func__);
285
return (-1);
286
}
287
288
ret = ath3k_load_fwfile(hdl, &fw);
289
290
ath3k_fw_free(&fw);
291
return (ret);
292
}
293
294
int
295
ath3k_set_normal_mode(libusb_device_handle *hdl)
296
{
297
int ret;
298
unsigned char fw_state;
299
300
ret = ath3k_get_state(hdl, &fw_state);
301
if (ret < 0) {
302
ath3k_err("%s: can't get state\n", __func__);
303
return (ret);
304
}
305
306
/*
307
* This isn't a fatal error - the device may have detached
308
* already.
309
*/
310
if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
311
ath3k_debug("%s: firmware is already in normal mode\n",
312
__func__);
313
return (0);
314
}
315
316
ret = libusb_control_transfer(hdl,
317
LIBUSB_REQUEST_TYPE_VENDOR, /* XXX out direction? */
318
ATH3K_SET_NORMAL_MODE,
319
0,
320
0,
321
NULL,
322
0,
323
1000); /* XXX timeout */
324
325
if (ret < 0) {
326
ath3k_err("%s: libusb_control_transfer() failed: code=%d\n",
327
__func__,
328
ret);
329
return (0);
330
}
331
332
return (ret == 0);
333
}
334
335
int
336
ath3k_switch_pid(libusb_device_handle *hdl)
337
{
338
int ret;
339
ret = libusb_control_transfer(hdl,
340
LIBUSB_REQUEST_TYPE_VENDOR, /* XXX set an out flag? */
341
USB_REG_SWITCH_VID_PID,
342
0,
343
0,
344
NULL,
345
0,
346
1000); /* XXX timeout */
347
348
if (ret < 0) {
349
ath3k_debug("%s: libusb_control_transfer() failed: code=%d\n",
350
__func__,
351
ret);
352
return (0);
353
}
354
355
return (ret == 0);
356
}
357
358