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
51int	ath3k_do_debug = 0;
52int	ath3k_do_info = 0;
53
54struct ath3k_devid {
55	uint16_t product_id;
56	uint16_t vendor_id;
57	int is_3012;
58};
59
60static 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
99static int
100ath3k_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
117static libusb_device *
118ath3k_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
150static int
151ath3k_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
177static int
178ath3k_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
209static int
210parse_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
228static void
229usage(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
240int
241main(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