2 * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
41 #include <sys/param.h>
47 #include "ath3k_dbg.h"
49 #define _DEFAULT_ATH3K_FIRMWARE_PATH "/usr/share/firmware/ath3k/"
51 int ath3k_do_debug = 0;
52 int ath3k_do_info = 0;
60 static struct ath3k_devid ath3k_list[] = {
62 /* Atheros AR3012 with sflash firmware*/
63 { .vendor_id = 0x0489, .product_id = 0xe04e, .is_3012 = 1 },
64 { .vendor_id = 0x0489, .product_id = 0xe04d, .is_3012 = 1 },
65 { .vendor_id = 0x0489, .product_id = 0xe056, .is_3012 = 1 },
66 { .vendor_id = 0x0489, .product_id = 0xe057, .is_3012 = 1 },
67 { .vendor_id = 0x0489, .product_id = 0xe05f, .is_3012 = 1 },
68 { .vendor_id = 0x04c5, .product_id = 0x1330, .is_3012 = 1 },
69 { .vendor_id = 0x04ca, .product_id = 0x3004, .is_3012 = 1 },
70 { .vendor_id = 0x04ca, .product_id = 0x3005, .is_3012 = 1 },
71 { .vendor_id = 0x04ca, .product_id = 0x3006, .is_3012 = 1 },
72 { .vendor_id = 0x04ca, .product_id = 0x3008, .is_3012 = 1 },
73 { .vendor_id = 0x04ca, .product_id = 0x300b, .is_3012 = 1 },
74 { .vendor_id = 0x0930, .product_id = 0x0219, .is_3012 = 1 },
75 { .vendor_id = 0x0930, .product_id = 0x0220, .is_3012 = 1 },
76 { .vendor_id = 0x0b05, .product_id = 0x17d0, .is_3012 = 1 },
77 { .vendor_id = 0x0CF3, .product_id = 0x0036, .is_3012 = 1 },
78 { .vendor_id = 0x0cf3, .product_id = 0x3004, .is_3012 = 1 },
79 { .vendor_id = 0x0cf3, .product_id = 0x3005, .is_3012 = 1 },
80 { .vendor_id = 0x0cf3, .product_id = 0x3008, .is_3012 = 1 },
81 { .vendor_id = 0x0cf3, .product_id = 0x311D, .is_3012 = 1 },
82 { .vendor_id = 0x0cf3, .product_id = 0x311E, .is_3012 = 1 },
83 { .vendor_id = 0x0cf3, .product_id = 0x311F, .is_3012 = 1 },
84 { .vendor_id = 0x0cf3, .product_id = 0x3121, .is_3012 = 1 },
85 { .vendor_id = 0x0CF3, .product_id = 0x817a, .is_3012 = 1 },
86 { .vendor_id = 0x0cf3, .product_id = 0xe004, .is_3012 = 1 },
87 { .vendor_id = 0x0cf3, .product_id = 0xe005, .is_3012 = 1 },
88 { .vendor_id = 0x0cf3, .product_id = 0xe003, .is_3012 = 1 },
89 { .vendor_id = 0x13d3, .product_id = 0x3362, .is_3012 = 1 },
90 { .vendor_id = 0x13d3, .product_id = 0x3375, .is_3012 = 1 },
91 { .vendor_id = 0x13d3, .product_id = 0x3393, .is_3012 = 1 },
92 { .vendor_id = 0x13d3, .product_id = 0x3402, .is_3012 = 1 },
94 /* Atheros AR5BBU22 with sflash firmware */
95 { .vendor_id = 0x0489, .product_id = 0xE036, .is_3012 = 1 },
96 { .vendor_id = 0x0489, .product_id = 0xE03C, .is_3012 = 1 },
100 ath3k_is_3012(struct libusb_device_descriptor *d)
104 /* Search looking for whether it's an AR3012 */
105 for (i = 0; i < (int) nitems(ath3k_list); i++) {
106 if ((ath3k_list[i].product_id == d->idProduct) &&
107 (ath3k_list[i].vendor_id == d->idVendor)) {
108 fprintf(stderr, "%s: found AR3012\n", __func__);
109 return (ath3k_list[i].is_3012);
117 static libusb_device *
118 ath3k_find_device(libusb_context *ctx, int bus_id, int dev_id)
120 libusb_device **list, *dev = NULL, *found = NULL;
123 cnt = libusb_get_device_list(ctx, &list);
125 ath3k_err("%s: libusb_get_device_list() failed: code %lld\n",
127 (long long int) cnt);
132 * XXX TODO: match on the vendor/product id too!
134 for (i = 0; i < cnt; i++) {
136 if (bus_id == libusb_get_bus_number(dev) &&
137 dev_id == libusb_get_device_address(dev)) {
139 * Take a reference so it's not freed later on.
141 found = libusb_ref_device(dev);
146 libusb_free_device_list(list, 1);
151 ath3k_init_ar3012(libusb_device_handle *hdl, const char *fw_path)
155 ret = ath3k_load_patch(hdl, fw_path);
157 ath3k_err("Loading patch file failed\n");
161 ret = ath3k_load_syscfg(hdl, fw_path);
163 ath3k_err("Loading sysconfig file failed\n");
167 ret = ath3k_set_normal_mode(hdl);
169 ath3k_err("Set normal mode failed\n");
173 ath3k_switch_pid(hdl);
178 ath3k_init_firmware(libusb_device_handle *hdl, const char *file_prefix)
180 struct ath3k_firmware fw;
181 char fwname[FILENAME_MAX];
185 snprintf(fwname, FILENAME_MAX, "%s/ath3k-1.fw", file_prefix);
187 ath3k_debug("%s: loading ath3k-1.fw\n", __func__);
189 /* Read in the firmware */
190 if (ath3k_fw_read(&fw, fwname) <= 0) {
191 fprintf(stderr, "%s: ath3k_fw_read() failed\n",
196 /* Load in the firmware */
197 ret = ath3k_load_fwfile(hdl, &fw);
206 * Parse ugen name and extract device's bus and address
210 parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
214 if (strncmp(ugen, "ugen", 4) != 0)
217 *bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
221 *addr = (uint8_t) strtoul(ep + 1, &ep, 10);
232 "Usage: ath3kfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
233 fprintf(stderr, " -D: enable debugging\n");
234 fprintf(stderr, " -d: device to operate upon\n");
235 fprintf(stderr, " -f: firmware path, if not default\n");
236 fprintf(stderr, " -I: enable informational output\n");
241 main(int argc, char *argv[])
243 struct libusb_device_descriptor d;
246 libusb_device_handle *hdl;
248 struct ath3k_version ver;
250 uint8_t bus_id = 0, dev_id = 0;
253 char *firmware_path = NULL;
257 r = libusb_init(&ctx);
259 ath3k_err("%s: libusb_init failed: code %d\n",
265 /* Enable debugging, just because */
266 libusb_set_debug(ctx, 3);
268 /* Parse command line arguments */
269 while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
271 case 'd': /* ugen device name */
273 if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
279 case 'f': /* firmware path */
282 firmware_path = strdup(optarg);
295 /* Ensure the devid was given! */
296 if (devid_set == 0) {
301 ath3k_debug("%s: opening dev %d.%d\n",
306 /* Find a device based on the bus/dev id */
307 dev = ath3k_find_device(ctx, bus_id, dev_id);
309 ath3k_err("%s: device not found\n", __func__);
314 /* Get the device descriptor for this device entry */
315 r = libusb_get_device_descriptor(dev, &d);
317 warn("%s: libusb_get_device_descriptor: %s\n",
323 /* See if its an AR3012 */
324 if (ath3k_is_3012(&d)) {
327 /* If it's bcdDevice > 1, don't attach */
328 if (d.bcdDevice > 0x0001) {
329 ath3k_debug("%s: AR3012; bcdDevice=%d, exiting\n",
336 /* XXX enforce that bInterfaceNumber is 0 */
338 /* XXX enforce the device/product id if they're non-zero */
340 /* Grab device handle */
341 r = libusb_open(dev, &hdl);
343 ath3k_err("%s: libusb_open() failed: code %d\n", __func__, r);
349 * Get the initial NIC state.
351 r = ath3k_get_state(hdl, &state);
353 ath3k_err("%s: ath3k_get_state() failed!\n", __func__);
357 ath3k_debug("%s: state=0x%02x\n",
361 /* And the version */
362 r = ath3k_get_version(hdl, &ver);
364 ath3k_err("%s: ath3k_get_version() failed!\n", __func__);
368 ath3k_info("ROM version: %d, build version: %d, ram version: %d, "
375 /* Default the firmware path */
376 if (firmware_path == NULL)
377 firmware_path = strdup(_DEFAULT_ATH3K_FIRMWARE_PATH);
380 (void) ath3k_init_ar3012(hdl, firmware_path);
382 (void) ath3k_init_firmware(hdl, firmware_path);
389 libusb_unref_device(dev);