Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/ath3kfw/main.c
105240 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 <libgen.h>
38
#include <sys/stat.h>
39
#include <sys/param.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 _DEFAULT_ATH3K_FIRMWARE_PATH "/usr/share/firmware/ath3k/"
48
49
int ath3k_do_debug = 0;
50
int ath3k_do_info = 0;
51
52
struct ath3k_devid {
53
uint16_t product_id;
54
uint16_t vendor_id;
55
int is_3012;
56
};
57
58
static struct ath3k_devid ath3k_list[] = {
59
60
/* Atheros AR3012 with sflash firmware*/
61
{ .vendor_id = 0x0489, .product_id = 0xe04e, .is_3012 = 1 },
62
{ .vendor_id = 0x0489, .product_id = 0xe04d, .is_3012 = 1 },
63
{ .vendor_id = 0x0489, .product_id = 0xe056, .is_3012 = 1 },
64
{ .vendor_id = 0x0489, .product_id = 0xe057, .is_3012 = 1 },
65
{ .vendor_id = 0x0489, .product_id = 0xe05f, .is_3012 = 1 },
66
{ .vendor_id = 0x04c5, .product_id = 0x1330, .is_3012 = 1 },
67
{ .vendor_id = 0x04ca, .product_id = 0x3004, .is_3012 = 1 },
68
{ .vendor_id = 0x04ca, .product_id = 0x3005, .is_3012 = 1 },
69
{ .vendor_id = 0x04ca, .product_id = 0x3006, .is_3012 = 1 },
70
{ .vendor_id = 0x04ca, .product_id = 0x3008, .is_3012 = 1 },
71
{ .vendor_id = 0x04ca, .product_id = 0x300b, .is_3012 = 1 },
72
{ .vendor_id = 0x0930, .product_id = 0x0219, .is_3012 = 1 },
73
{ .vendor_id = 0x0930, .product_id = 0x0220, .is_3012 = 1 },
74
{ .vendor_id = 0x0b05, .product_id = 0x17d0, .is_3012 = 1 },
75
{ .vendor_id = 0x0CF3, .product_id = 0x0036, .is_3012 = 1 },
76
{ .vendor_id = 0x0cf3, .product_id = 0x3004, .is_3012 = 1 },
77
{ .vendor_id = 0x0cf3, .product_id = 0x3005, .is_3012 = 1 },
78
{ .vendor_id = 0x0cf3, .product_id = 0x3008, .is_3012 = 1 },
79
{ .vendor_id = 0x0cf3, .product_id = 0x311D, .is_3012 = 1 },
80
{ .vendor_id = 0x0cf3, .product_id = 0x311E, .is_3012 = 1 },
81
{ .vendor_id = 0x0cf3, .product_id = 0x311F, .is_3012 = 1 },
82
{ .vendor_id = 0x0cf3, .product_id = 0x3121, .is_3012 = 1 },
83
{ .vendor_id = 0x0CF3, .product_id = 0x817a, .is_3012 = 1 },
84
{ .vendor_id = 0x0cf3, .product_id = 0xe004, .is_3012 = 1 },
85
{ .vendor_id = 0x0cf3, .product_id = 0xe005, .is_3012 = 1 },
86
{ .vendor_id = 0x0cf3, .product_id = 0xe003, .is_3012 = 1 },
87
{ .vendor_id = 0x13d3, .product_id = 0x3362, .is_3012 = 1 },
88
{ .vendor_id = 0x13d3, .product_id = 0x3375, .is_3012 = 1 },
89
{ .vendor_id = 0x13d3, .product_id = 0x3393, .is_3012 = 1 },
90
{ .vendor_id = 0x13d3, .product_id = 0x3402, .is_3012 = 1 },
91
92
/* Atheros AR5BBU22 with sflash firmware */
93
{ .vendor_id = 0x0489, .product_id = 0xE036, .is_3012 = 1 },
94
{ .vendor_id = 0x0489, .product_id = 0xE03C, .is_3012 = 1 },
95
};
96
97
static int
98
ath3k_is_3012(struct libusb_device_descriptor *d)
99
{
100
int i;
101
102
/* Search looking for whether it's an AR3012 */
103
for (i = 0; i < (int) nitems(ath3k_list); i++) {
104
if ((ath3k_list[i].product_id == d->idProduct) &&
105
(ath3k_list[i].vendor_id == d->idVendor)) {
106
fprintf(stderr, "%s: found AR3012\n", __func__);
107
return (ath3k_list[i].is_3012);
108
}
109
}
110
111
/* Not found */
112
return (0);
113
}
114
115
static libusb_device *
116
ath3k_find_device(libusb_context *ctx, int bus_id, int dev_id)
117
{
118
libusb_device **list, *dev = NULL, *found = NULL;
119
ssize_t cnt, i;
120
121
cnt = libusb_get_device_list(ctx, &list);
122
if (cnt < 0) {
123
ath3k_err("%s: libusb_get_device_list() failed: code %lld\n",
124
__func__,
125
(long long int) cnt);
126
return (NULL);
127
}
128
129
/*
130
* XXX TODO: match on the vendor/product id too!
131
*/
132
for (i = 0; i < cnt; i++) {
133
dev = list[i];
134
if (bus_id == libusb_get_bus_number(dev) &&
135
dev_id == libusb_get_device_address(dev)) {
136
/*
137
* Take a reference so it's not freed later on.
138
*/
139
found = libusb_ref_device(dev);
140
break;
141
}
142
}
143
144
libusb_free_device_list(list, 1);
145
return (found);
146
}
147
148
static int
149
ath3k_init_ar3012(libusb_device_handle *hdl, const char *fw_path)
150
{
151
int ret;
152
153
ret = ath3k_load_patch(hdl, fw_path);
154
if (ret < 0) {
155
ath3k_err("Loading patch file failed\n");
156
return (ret);
157
}
158
159
ret = ath3k_load_syscfg(hdl, fw_path);
160
if (ret < 0) {
161
ath3k_err("Loading sysconfig file failed\n");
162
return (ret);
163
}
164
165
ret = ath3k_set_normal_mode(hdl);
166
if (ret < 0) {
167
ath3k_err("Set normal mode failed\n");
168
return (ret);
169
}
170
171
ath3k_switch_pid(hdl);
172
return (0);
173
}
174
175
static int
176
ath3k_init_firmware(libusb_device_handle *hdl, const char *file_prefix)
177
{
178
struct ath3k_firmware fw;
179
char fwname[FILENAME_MAX];
180
int ret;
181
182
/* XXX path info? */
183
snprintf(fwname, FILENAME_MAX, "%s/ath3k-1.fw", file_prefix);
184
185
ath3k_debug("%s: loading ath3k-1.fw\n", __func__);
186
187
/* Read in the firmware */
188
if (ath3k_fw_read(&fw, fwname) <= 0) {
189
fprintf(stderr, "%s: ath3k_fw_read() failed\n",
190
__func__);
191
return (-1);
192
}
193
194
/* Load in the firmware */
195
ret = ath3k_load_fwfile(hdl, &fw);
196
197
/* free it */
198
ath3k_fw_free(&fw);
199
200
return (ret);
201
}
202
203
/*
204
* Parse ugen name and extract device's bus and address
205
*/
206
207
static int
208
parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
209
{
210
char *ep;
211
212
if (strncmp(ugen, "ugen", 4) != 0)
213
return (-1);
214
215
*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
216
if (*ep != '.')
217
return (-1);
218
219
*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
220
if (*ep != '\0')
221
return (-1);
222
223
return (0);
224
}
225
226
static void
227
usage(void)
228
{
229
fprintf(stderr,
230
"Usage: ath3kfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
231
fprintf(stderr, " -D: enable debugging\n");
232
fprintf(stderr, " -d: device to operate upon\n");
233
fprintf(stderr, " -f: firmware path, if not default\n");
234
fprintf(stderr, " -I: enable informational output\n");
235
exit(127);
236
}
237
238
int
239
main(int argc, char *argv[])
240
{
241
struct libusb_device_descriptor d;
242
libusb_context *ctx;
243
libusb_device *dev;
244
libusb_device_handle *hdl;
245
unsigned char state;
246
struct ath3k_version ver;
247
int r;
248
uint8_t bus_id = 0, dev_id = 0;
249
int devid_set = 0;
250
int n;
251
char *firmware_path = NULL;
252
int is_3012 = 0;
253
254
/* libusb setup */
255
r = libusb_init(&ctx);
256
if (r != 0) {
257
ath3k_err("%s: libusb_init failed: code %d\n",
258
argv[0],
259
r);
260
exit(127);
261
}
262
263
/* Enable debugging, just because */
264
libusb_set_debug(ctx, 3);
265
266
/* Parse command line arguments */
267
while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
268
switch (n) {
269
case 'd': /* ugen device name */
270
devid_set = 1;
271
if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
272
usage();
273
break;
274
case 'D':
275
ath3k_do_debug = 1;
276
break;
277
case 'f': /* firmware path */
278
if (firmware_path)
279
free(firmware_path);
280
firmware_path = strdup(optarg);
281
break;
282
case 'I':
283
ath3k_do_info = 1;
284
break;
285
case 'h':
286
default:
287
usage();
288
break;
289
/* NOT REACHED */
290
}
291
}
292
293
/* Ensure the devid was given! */
294
if (devid_set == 0) {
295
usage();
296
/* NOTREACHED */
297
}
298
299
ath3k_debug("%s: opening dev %d.%d\n",
300
basename(argv[0]),
301
(int) bus_id,
302
(int) dev_id);
303
304
/* Find a device based on the bus/dev id */
305
dev = ath3k_find_device(ctx, bus_id, dev_id);
306
if (dev == NULL) {
307
ath3k_err("%s: device not found\n", __func__);
308
/* XXX cleanup? */
309
exit(1);
310
}
311
312
/* Get the device descriptor for this device entry */
313
r = libusb_get_device_descriptor(dev, &d);
314
if (r != 0) {
315
warn("%s: libusb_get_device_descriptor: %s\n",
316
__func__,
317
libusb_strerror(r));
318
exit(1);
319
}
320
321
/* See if its an AR3012 */
322
if (ath3k_is_3012(&d)) {
323
is_3012 = 1;
324
325
/* If it's bcdDevice > 1, don't attach */
326
if (d.bcdDevice > 0x0001) {
327
ath3k_debug("%s: AR3012; bcdDevice=%d, exiting\n",
328
__func__,
329
d.bcdDevice);
330
exit(0);
331
}
332
}
333
334
/* XXX enforce that bInterfaceNumber is 0 */
335
336
/* XXX enforce the device/product id if they're non-zero */
337
338
/* Grab device handle */
339
r = libusb_open(dev, &hdl);
340
if (r != 0) {
341
ath3k_err("%s: libusb_open() failed: code %d\n", __func__, r);
342
/* XXX cleanup? */
343
exit(1);
344
}
345
346
/*
347
* Get the initial NIC state.
348
*/
349
r = ath3k_get_state(hdl, &state);
350
if (r == 0) {
351
ath3k_err("%s: ath3k_get_state() failed!\n", __func__);
352
/* XXX cleanup? */
353
exit(1);
354
}
355
ath3k_debug("%s: state=0x%02x\n",
356
__func__,
357
(int) state);
358
359
/* And the version */
360
r = ath3k_get_version(hdl, &ver);
361
if (r == 0) {
362
ath3k_err("%s: ath3k_get_version() failed!\n", __func__);
363
/* XXX cleanup? */
364
exit(1);
365
}
366
ath3k_info("ROM version: %d, build version: %d, ram version: %d, "
367
"ref clock=%d\n",
368
ver.rom_version,
369
ver.build_version,
370
ver.ram_version,
371
ver.ref_clock);
372
373
/* Default the firmware path */
374
if (firmware_path == NULL)
375
firmware_path = strdup(_DEFAULT_ATH3K_FIRMWARE_PATH);
376
377
if (is_3012) {
378
(void) ath3k_init_ar3012(hdl, firmware_path);
379
} else {
380
(void) ath3k_init_firmware(hdl, firmware_path);
381
}
382
383
/* Shutdown */
384
libusb_close(hdl);
385
hdl = NULL;
386
387
libusb_unref_device(dev);
388
dev = NULL;
389
390
libusb_exit(ctx);
391
ctx = NULL;
392
}
393
394