xref: /freebsd/usr.sbin/bluetooth/ath3kfw/main.c (revision 5dae51da3da0cc94d17bd67b308fad304ebec7e0)
1 /*-
2  * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
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  * $FreeBSD$
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <err.h>
38 #include <fcntl.h>
39 #include <libgen.h>
40 #include <sys/stat.h>
41 #include <sys/param.h>
42 
43 #include <libusb.h>
44 
45 #include "ath3k_fw.h"
46 #include "ath3k_hw.h"
47 #include "ath3k_dbg.h"
48 
49 #define	_DEFAULT_ATH3K_FIRMWARE_PATH	"/usr/share/firmware/ath3k/"
50 
51 int	ath3k_do_debug = 0;
52 int	ath3k_do_info = 0;
53 
54 struct ath3k_devid {
55 	uint16_t product_id;
56 	uint16_t vendor_id;
57 	int is_3012;
58 };
59 
60 static struct ath3k_devid ath3k_list[] = {
61 
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 },
93 
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 },
97 };
98 
99 static int
100 ath3k_is_3012(struct libusb_device_descriptor *d)
101 {
102 	int i;
103 
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);
110 		}
111 	}
112 
113 	/* Not found */
114 	return (0);
115 }
116 
117 static libusb_device *
118 ath3k_find_device(libusb_context *ctx, int bus_id, int dev_id)
119 {
120 	libusb_device **list, *dev = NULL, *found = NULL;
121 	ssize_t cnt, i;
122 
123 	cnt = libusb_get_device_list(ctx, &list);
124 	if (cnt < 0) {
125 		ath3k_err("%s: libusb_get_device_list() failed: code %lld\n",
126 		    __func__,
127 		    (long long int) cnt);
128 		return (NULL);
129 	}
130 
131 	/*
132 	 * XXX TODO: match on the vendor/product id too!
133 	 */
134 	for (i = 0; i < cnt; i++) {
135 		dev = list[i];
136 		if (bus_id == libusb_get_bus_number(dev) &&
137 		    dev_id == libusb_get_device_address(dev)) {
138 			/*
139 			 * Take a reference so it's not freed later on.
140 			 */
141 			found = libusb_ref_device(dev);
142 			break;
143 		}
144 	}
145 
146 	libusb_free_device_list(list, 1);
147 	return (found);
148 }
149 
150 static int
151 ath3k_init_ar3012(libusb_device_handle *hdl, const char *fw_path)
152 {
153 	int ret;
154 
155 	ret = ath3k_load_patch(hdl, fw_path);
156 	if (ret < 0) {
157 		ath3k_err("Loading patch file failed\n");
158 	return (ret);
159 	}
160 
161 	ret = ath3k_load_syscfg(hdl, fw_path);
162 	if (ret < 0) {
163 		ath3k_err("Loading sysconfig file failed\n");
164 		return (ret);
165 	}
166 
167 	ret = ath3k_set_normal_mode(hdl);
168 	if (ret < 0) {
169 		ath3k_err("Set normal mode failed\n");
170 		return (ret);
171 	}
172 
173 	ath3k_switch_pid(hdl);
174 	return (0);
175 }
176 
177 static int
178 ath3k_init_firmware(libusb_device_handle *hdl, const char *file_prefix)
179 {
180 	struct ath3k_firmware fw;
181 	char fwname[FILENAME_MAX];
182 	int ret;
183 
184 	/* XXX path info? */
185 	snprintf(fwname, FILENAME_MAX, "%s/ath3k-1.fw", file_prefix);
186 
187 	ath3k_debug("%s: loading ath3k-1.fw\n", __func__);
188 
189 	/* Read in the firmware */
190 	if (ath3k_fw_read(&fw, fwname) <= 0) {
191 		fprintf(stderr, "%s: ath3k_fw_read() failed\n",
192 		    __func__);
193 		return (-1);
194 	}
195 
196 	/* Load in the firmware */
197 	ret = ath3k_load_fwfile(hdl, &fw);
198 
199 	/* free it */
200 	ath3k_fw_free(&fw);
201 
202 	return (0);
203 }
204 
205 /*
206  * Parse ugen name and extract device's bus and address
207  */
208 
209 static int
210 parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
211 {
212 	char *ep;
213 
214 	if (strncmp(ugen, "ugen", 4) != 0)
215 		return (-1);
216 
217 	*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
218 	if (*ep != '.')
219 		return (-1);
220 
221 	*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
222 	if (*ep != '\0')
223 		return (-1);
224 
225 	return (0);
226 }
227 
228 static void
229 usage(void)
230 {
231 	fprintf(stderr,
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");
237 	exit(127);
238 }
239 
240 int
241 main(int argc, char *argv[])
242 {
243 	struct libusb_device_descriptor d;
244 	libusb_context *ctx;
245 	libusb_device *dev;
246 	libusb_device_handle *hdl;
247 	unsigned char state;
248 	struct ath3k_version ver;
249 	int r;
250 	uint8_t bus_id = 0, dev_id = 0;
251 	int devid_set = 0;
252 	int n;
253 	char *firmware_path = NULL;
254 	int is_3012 = 0;
255 
256 	/* libusb setup */
257 	r = libusb_init(&ctx);
258 	if (r != 0) {
259 		ath3k_err("%s: libusb_init failed: code %d\n",
260 		    argv[0],
261 		    r);
262 		exit(127);
263 	}
264 
265 	/* Enable debugging, just because */
266 	libusb_set_debug(ctx, 3);
267 
268 	/* Parse command line arguments */
269 	while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
270 		switch (n) {
271 		case 'd': /* ugen device name */
272 			devid_set = 1;
273 			if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
274 				usage();
275 			break;
276 		case 'D':
277 			ath3k_do_debug = 1;
278 			break;
279 		case 'f': /* firmware path */
280 			if (firmware_path)
281 				free(firmware_path);
282 			firmware_path = strdup(optarg);
283 			break;
284 		case 'I':
285 			ath3k_do_info = 1;
286 			break;
287 		case 'h':
288 		default:
289 			usage();
290 			break;
291 			/* NOT REACHED */
292 		}
293 	}
294 
295 	/* Ensure the devid was given! */
296 	if (devid_set == 0) {
297 		usage();
298 		/* NOTREACHED */
299 	}
300 
301 	ath3k_debug("%s: opening dev %d.%d\n",
302 	    basename(argv[0]),
303 	    (int) bus_id,
304 	    (int) dev_id);
305 
306 	/* Find a device based on the bus/dev id */
307 	dev = ath3k_find_device(ctx, bus_id, dev_id);
308 	if (dev == NULL) {
309 		ath3k_err("%s: device not found\n", __func__);
310 		/* XXX cleanup? */
311 		exit(1);
312 	}
313 
314 	/* Get the device descriptor for this device entry */
315 	r = libusb_get_device_descriptor(dev, &d);
316 	if (r != 0) {
317 		warn("%s: libusb_get_device_descriptor: %s\n",
318 		    __func__,
319 		    libusb_strerror(r));
320 		exit(1);
321 	}
322 
323 	/* See if its an AR3012 */
324 	if (ath3k_is_3012(&d)) {
325 		is_3012 = 1;
326 
327 		/* If it's bcdDevice > 1, don't attach */
328 		if (d.bcdDevice > 0x0001) {
329 			ath3k_debug("%s: AR3012; bcdDevice=%d, exiting\n",
330 			    __func__,
331 			    d.bcdDevice);
332 			exit(0);
333 		}
334 	}
335 
336 	/* XXX enforce that bInterfaceNumber is 0 */
337 
338 	/* XXX enforce the device/product id if they're non-zero */
339 
340 	/* Grab device handle */
341 	r = libusb_open(dev, &hdl);
342 	if (r != 0) {
343 		ath3k_err("%s: libusb_open() failed: code %d\n", __func__, r);
344 		/* XXX cleanup? */
345 		exit(1);
346 	}
347 
348 	/*
349 	 * Get the initial NIC state.
350 	 */
351 	r = ath3k_get_state(hdl, &state);
352 	if (r == 0) {
353 		ath3k_err("%s: ath3k_get_state() failed!\n", __func__);
354 		/* XXX cleanup? */
355 		exit(1);
356 	}
357 	ath3k_debug("%s: state=0x%02x\n",
358 	    __func__,
359 	    (int) state);
360 
361 	/* And the version */
362 	r = ath3k_get_version(hdl, &ver);
363 	if (r == 0) {
364 		ath3k_err("%s: ath3k_get_version() failed!\n", __func__);
365 		/* XXX cleanup? */
366 		exit(1);
367 	}
368 	ath3k_info("ROM version: %d, build version: %d, ram version: %d, "
369 	    "ref clock=%d\n",
370 	    ver.rom_version,
371 	    ver.build_version,
372 	    ver.ram_version,
373 	    ver.ref_clock);
374 
375 	/* Default the firmware path */
376 	if (firmware_path == NULL)
377 		firmware_path = strdup(_DEFAULT_ATH3K_FIRMWARE_PATH);
378 
379 	if (is_3012) {
380 		(void) ath3k_init_ar3012(hdl, firmware_path);
381 	} else {
382 		(void) ath3k_init_firmware(hdl, firmware_path);
383 	}
384 
385 	/* Shutdown */
386 	libusb_close(hdl);
387 	hdl = NULL;
388 
389 	libusb_unref_device(dev);
390 	dev = NULL;
391 
392 	libusb_exit(ctx);
393 	ctx = NULL;
394 }
395