1aebdb1e2SAdrian Chadd /*-
2aebdb1e2SAdrian Chadd * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
3aebdb1e2SAdrian Chadd * All rights reserved.
4aebdb1e2SAdrian Chadd *
5aebdb1e2SAdrian Chadd * Redistribution and use in source and binary forms, with or without
6aebdb1e2SAdrian Chadd * modification, are permitted provided that the following conditions
7aebdb1e2SAdrian Chadd * are met:
8aebdb1e2SAdrian Chadd * 1. Redistributions of source code must retain the above copyright
9aebdb1e2SAdrian Chadd * notice, this list of conditions and the following disclaimer,
10aebdb1e2SAdrian Chadd * without modification.
11aebdb1e2SAdrian Chadd * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12aebdb1e2SAdrian Chadd * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13aebdb1e2SAdrian Chadd * redistribution must be conditioned upon including a substantially
14aebdb1e2SAdrian Chadd * similar Disclaimer requirement for further binary redistribution.
15aebdb1e2SAdrian Chadd *
16aebdb1e2SAdrian Chadd * NO WARRANTY
17aebdb1e2SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18aebdb1e2SAdrian Chadd * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19aebdb1e2SAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20aebdb1e2SAdrian Chadd * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21aebdb1e2SAdrian Chadd * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22aebdb1e2SAdrian Chadd * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23aebdb1e2SAdrian Chadd * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24aebdb1e2SAdrian Chadd * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25aebdb1e2SAdrian Chadd * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26aebdb1e2SAdrian Chadd * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27aebdb1e2SAdrian Chadd * THE POSSIBILITY OF SUCH DAMAGES.
28aebdb1e2SAdrian Chadd */
29aebdb1e2SAdrian Chadd
30aebdb1e2SAdrian Chadd #include <stdio.h>
31aebdb1e2SAdrian Chadd #include <stdlib.h>
32aebdb1e2SAdrian Chadd #include <unistd.h>
33aebdb1e2SAdrian Chadd #include <errno.h>
34aebdb1e2SAdrian Chadd #include <string.h>
35aebdb1e2SAdrian Chadd #include <err.h>
36aebdb1e2SAdrian Chadd #include <fcntl.h>
37aebdb1e2SAdrian Chadd #include <libgen.h>
38aebdb1e2SAdrian Chadd #include <sys/stat.h>
39aebdb1e2SAdrian Chadd #include <sys/param.h>
40aebdb1e2SAdrian Chadd
41aebdb1e2SAdrian Chadd #include <libusb.h>
42aebdb1e2SAdrian Chadd
43aebdb1e2SAdrian Chadd #include "ath3k_fw.h"
44aebdb1e2SAdrian Chadd #include "ath3k_hw.h"
45aebdb1e2SAdrian Chadd #include "ath3k_dbg.h"
46aebdb1e2SAdrian Chadd
47aebdb1e2SAdrian Chadd #define _DEFAULT_ATH3K_FIRMWARE_PATH "/usr/share/firmware/ath3k/"
48aebdb1e2SAdrian Chadd
49aebdb1e2SAdrian Chadd int ath3k_do_debug = 0;
50aebdb1e2SAdrian Chadd int ath3k_do_info = 0;
51aebdb1e2SAdrian Chadd
52aebdb1e2SAdrian Chadd struct ath3k_devid {
53aebdb1e2SAdrian Chadd uint16_t product_id;
54aebdb1e2SAdrian Chadd uint16_t vendor_id;
55aebdb1e2SAdrian Chadd int is_3012;
56aebdb1e2SAdrian Chadd };
57aebdb1e2SAdrian Chadd
58aebdb1e2SAdrian Chadd static struct ath3k_devid ath3k_list[] = {
59aebdb1e2SAdrian Chadd
60aebdb1e2SAdrian Chadd /* Atheros AR3012 with sflash firmware*/
61aebdb1e2SAdrian Chadd { .vendor_id = 0x0489, .product_id = 0xe04e, .is_3012 = 1 },
62aebdb1e2SAdrian Chadd { .vendor_id = 0x0489, .product_id = 0xe04d, .is_3012 = 1 },
63aebdb1e2SAdrian Chadd { .vendor_id = 0x0489, .product_id = 0xe056, .is_3012 = 1 },
64aebdb1e2SAdrian Chadd { .vendor_id = 0x0489, .product_id = 0xe057, .is_3012 = 1 },
65aebdb1e2SAdrian Chadd { .vendor_id = 0x0489, .product_id = 0xe05f, .is_3012 = 1 },
66aebdb1e2SAdrian Chadd { .vendor_id = 0x04c5, .product_id = 0x1330, .is_3012 = 1 },
67aebdb1e2SAdrian Chadd { .vendor_id = 0x04ca, .product_id = 0x3004, .is_3012 = 1 },
68aebdb1e2SAdrian Chadd { .vendor_id = 0x04ca, .product_id = 0x3005, .is_3012 = 1 },
69aebdb1e2SAdrian Chadd { .vendor_id = 0x04ca, .product_id = 0x3006, .is_3012 = 1 },
70aebdb1e2SAdrian Chadd { .vendor_id = 0x04ca, .product_id = 0x3008, .is_3012 = 1 },
71aebdb1e2SAdrian Chadd { .vendor_id = 0x04ca, .product_id = 0x300b, .is_3012 = 1 },
72aebdb1e2SAdrian Chadd { .vendor_id = 0x0930, .product_id = 0x0219, .is_3012 = 1 },
73aebdb1e2SAdrian Chadd { .vendor_id = 0x0930, .product_id = 0x0220, .is_3012 = 1 },
74aebdb1e2SAdrian Chadd { .vendor_id = 0x0b05, .product_id = 0x17d0, .is_3012 = 1 },
75aebdb1e2SAdrian Chadd { .vendor_id = 0x0CF3, .product_id = 0x0036, .is_3012 = 1 },
76aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0x3004, .is_3012 = 1 },
77aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0x3005, .is_3012 = 1 },
78aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0x3008, .is_3012 = 1 },
79aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0x311D, .is_3012 = 1 },
80aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0x311E, .is_3012 = 1 },
81aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0x311F, .is_3012 = 1 },
82aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0x3121, .is_3012 = 1 },
83aebdb1e2SAdrian Chadd { .vendor_id = 0x0CF3, .product_id = 0x817a, .is_3012 = 1 },
84aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0xe004, .is_3012 = 1 },
85aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0xe005, .is_3012 = 1 },
86aebdb1e2SAdrian Chadd { .vendor_id = 0x0cf3, .product_id = 0xe003, .is_3012 = 1 },
87aebdb1e2SAdrian Chadd { .vendor_id = 0x13d3, .product_id = 0x3362, .is_3012 = 1 },
88aebdb1e2SAdrian Chadd { .vendor_id = 0x13d3, .product_id = 0x3375, .is_3012 = 1 },
89aebdb1e2SAdrian Chadd { .vendor_id = 0x13d3, .product_id = 0x3393, .is_3012 = 1 },
90aebdb1e2SAdrian Chadd { .vendor_id = 0x13d3, .product_id = 0x3402, .is_3012 = 1 },
91aebdb1e2SAdrian Chadd
92aebdb1e2SAdrian Chadd /* Atheros AR5BBU22 with sflash firmware */
93aebdb1e2SAdrian Chadd { .vendor_id = 0x0489, .product_id = 0xE036, .is_3012 = 1 },
94aebdb1e2SAdrian Chadd { .vendor_id = 0x0489, .product_id = 0xE03C, .is_3012 = 1 },
95aebdb1e2SAdrian Chadd };
96aebdb1e2SAdrian Chadd
97aebdb1e2SAdrian Chadd static int
ath3k_is_3012(struct libusb_device_descriptor * d)98aebdb1e2SAdrian Chadd ath3k_is_3012(struct libusb_device_descriptor *d)
99aebdb1e2SAdrian Chadd {
100aebdb1e2SAdrian Chadd int i;
101aebdb1e2SAdrian Chadd
102aebdb1e2SAdrian Chadd /* Search looking for whether it's an AR3012 */
103aebdb1e2SAdrian Chadd for (i = 0; i < (int) nitems(ath3k_list); i++) {
104aebdb1e2SAdrian Chadd if ((ath3k_list[i].product_id == d->idProduct) &&
105aebdb1e2SAdrian Chadd (ath3k_list[i].vendor_id == d->idVendor)) {
106aebdb1e2SAdrian Chadd fprintf(stderr, "%s: found AR3012\n", __func__);
107aebdb1e2SAdrian Chadd return (ath3k_list[i].is_3012);
108aebdb1e2SAdrian Chadd }
109aebdb1e2SAdrian Chadd }
110aebdb1e2SAdrian Chadd
111aebdb1e2SAdrian Chadd /* Not found */
112aebdb1e2SAdrian Chadd return (0);
113aebdb1e2SAdrian Chadd }
114aebdb1e2SAdrian Chadd
115aebdb1e2SAdrian Chadd static libusb_device *
ath3k_find_device(libusb_context * ctx,int bus_id,int dev_id)116aebdb1e2SAdrian Chadd ath3k_find_device(libusb_context *ctx, int bus_id, int dev_id)
117aebdb1e2SAdrian Chadd {
118aebdb1e2SAdrian Chadd libusb_device **list, *dev = NULL, *found = NULL;
119aebdb1e2SAdrian Chadd ssize_t cnt, i;
120aebdb1e2SAdrian Chadd
121aebdb1e2SAdrian Chadd cnt = libusb_get_device_list(ctx, &list);
122aebdb1e2SAdrian Chadd if (cnt < 0) {
123aebdb1e2SAdrian Chadd ath3k_err("%s: libusb_get_device_list() failed: code %lld\n",
124aebdb1e2SAdrian Chadd __func__,
125aebdb1e2SAdrian Chadd (long long int) cnt);
126aebdb1e2SAdrian Chadd return (NULL);
127aebdb1e2SAdrian Chadd }
128aebdb1e2SAdrian Chadd
129aebdb1e2SAdrian Chadd /*
130aebdb1e2SAdrian Chadd * XXX TODO: match on the vendor/product id too!
131aebdb1e2SAdrian Chadd */
132aebdb1e2SAdrian Chadd for (i = 0; i < cnt; i++) {
133aebdb1e2SAdrian Chadd dev = list[i];
134aebdb1e2SAdrian Chadd if (bus_id == libusb_get_bus_number(dev) &&
135aebdb1e2SAdrian Chadd dev_id == libusb_get_device_address(dev)) {
136aebdb1e2SAdrian Chadd /*
137aebdb1e2SAdrian Chadd * Take a reference so it's not freed later on.
138aebdb1e2SAdrian Chadd */
139aebdb1e2SAdrian Chadd found = libusb_ref_device(dev);
140aebdb1e2SAdrian Chadd break;
141aebdb1e2SAdrian Chadd }
142aebdb1e2SAdrian Chadd }
143aebdb1e2SAdrian Chadd
144aebdb1e2SAdrian Chadd libusb_free_device_list(list, 1);
145aebdb1e2SAdrian Chadd return (found);
146aebdb1e2SAdrian Chadd }
147aebdb1e2SAdrian Chadd
148aebdb1e2SAdrian Chadd static int
ath3k_init_ar3012(libusb_device_handle * hdl,const char * fw_path)149aebdb1e2SAdrian Chadd ath3k_init_ar3012(libusb_device_handle *hdl, const char *fw_path)
150aebdb1e2SAdrian Chadd {
151aebdb1e2SAdrian Chadd int ret;
152aebdb1e2SAdrian Chadd
153aebdb1e2SAdrian Chadd ret = ath3k_load_patch(hdl, fw_path);
154aebdb1e2SAdrian Chadd if (ret < 0) {
155aebdb1e2SAdrian Chadd ath3k_err("Loading patch file failed\n");
156aebdb1e2SAdrian Chadd return (ret);
157aebdb1e2SAdrian Chadd }
158aebdb1e2SAdrian Chadd
159aebdb1e2SAdrian Chadd ret = ath3k_load_syscfg(hdl, fw_path);
160aebdb1e2SAdrian Chadd if (ret < 0) {
161aebdb1e2SAdrian Chadd ath3k_err("Loading sysconfig file failed\n");
162aebdb1e2SAdrian Chadd return (ret);
163aebdb1e2SAdrian Chadd }
164aebdb1e2SAdrian Chadd
165aebdb1e2SAdrian Chadd ret = ath3k_set_normal_mode(hdl);
166aebdb1e2SAdrian Chadd if (ret < 0) {
167aebdb1e2SAdrian Chadd ath3k_err("Set normal mode failed\n");
168aebdb1e2SAdrian Chadd return (ret);
169aebdb1e2SAdrian Chadd }
170aebdb1e2SAdrian Chadd
171aebdb1e2SAdrian Chadd ath3k_switch_pid(hdl);
172aebdb1e2SAdrian Chadd return (0);
173aebdb1e2SAdrian Chadd }
174aebdb1e2SAdrian Chadd
175aebdb1e2SAdrian Chadd static int
ath3k_init_firmware(libusb_device_handle * hdl,const char * file_prefix)176aebdb1e2SAdrian Chadd ath3k_init_firmware(libusb_device_handle *hdl, const char *file_prefix)
177aebdb1e2SAdrian Chadd {
178aebdb1e2SAdrian Chadd struct ath3k_firmware fw;
179aebdb1e2SAdrian Chadd char fwname[FILENAME_MAX];
180aebdb1e2SAdrian Chadd int ret;
181aebdb1e2SAdrian Chadd
182aebdb1e2SAdrian Chadd /* XXX path info? */
183aebdb1e2SAdrian Chadd snprintf(fwname, FILENAME_MAX, "%s/ath3k-1.fw", file_prefix);
184aebdb1e2SAdrian Chadd
185aebdb1e2SAdrian Chadd ath3k_debug("%s: loading ath3k-1.fw\n", __func__);
186aebdb1e2SAdrian Chadd
187aebdb1e2SAdrian Chadd /* Read in the firmware */
188aebdb1e2SAdrian Chadd if (ath3k_fw_read(&fw, fwname) <= 0) {
189aebdb1e2SAdrian Chadd fprintf(stderr, "%s: ath3k_fw_read() failed\n",
190aebdb1e2SAdrian Chadd __func__);
191aebdb1e2SAdrian Chadd return (-1);
192aebdb1e2SAdrian Chadd }
193aebdb1e2SAdrian Chadd
194aebdb1e2SAdrian Chadd /* Load in the firmware */
195aebdb1e2SAdrian Chadd ret = ath3k_load_fwfile(hdl, &fw);
196aebdb1e2SAdrian Chadd
197aebdb1e2SAdrian Chadd /* free it */
198aebdb1e2SAdrian Chadd ath3k_fw_free(&fw);
199aebdb1e2SAdrian Chadd
200*5f0bd291SJohn Baldwin return (ret);
201aebdb1e2SAdrian Chadd }
202aebdb1e2SAdrian Chadd
203aebdb1e2SAdrian Chadd /*
204aebdb1e2SAdrian Chadd * Parse ugen name and extract device's bus and address
205aebdb1e2SAdrian Chadd */
206aebdb1e2SAdrian Chadd
207aebdb1e2SAdrian Chadd static int
parse_ugen_name(char const * ugen,uint8_t * bus,uint8_t * addr)208aebdb1e2SAdrian Chadd parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
209aebdb1e2SAdrian Chadd {
210aebdb1e2SAdrian Chadd char *ep;
211aebdb1e2SAdrian Chadd
212aebdb1e2SAdrian Chadd if (strncmp(ugen, "ugen", 4) != 0)
213aebdb1e2SAdrian Chadd return (-1);
214aebdb1e2SAdrian Chadd
215aebdb1e2SAdrian Chadd *bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
216aebdb1e2SAdrian Chadd if (*ep != '.')
217aebdb1e2SAdrian Chadd return (-1);
218aebdb1e2SAdrian Chadd
219aebdb1e2SAdrian Chadd *addr = (uint8_t) strtoul(ep + 1, &ep, 10);
220aebdb1e2SAdrian Chadd if (*ep != '\0')
221aebdb1e2SAdrian Chadd return (-1);
222aebdb1e2SAdrian Chadd
223aebdb1e2SAdrian Chadd return (0);
224aebdb1e2SAdrian Chadd }
225aebdb1e2SAdrian Chadd
226aebdb1e2SAdrian Chadd static void
usage(void)227aebdb1e2SAdrian Chadd usage(void)
228aebdb1e2SAdrian Chadd {
229aebdb1e2SAdrian Chadd fprintf(stderr,
230aebdb1e2SAdrian Chadd "Usage: ath3kfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
231aebdb1e2SAdrian Chadd fprintf(stderr, " -D: enable debugging\n");
232aebdb1e2SAdrian Chadd fprintf(stderr, " -d: device to operate upon\n");
233aebdb1e2SAdrian Chadd fprintf(stderr, " -f: firmware path, if not default\n");
234aebdb1e2SAdrian Chadd fprintf(stderr, " -I: enable informational output\n");
235aebdb1e2SAdrian Chadd exit(127);
236aebdb1e2SAdrian Chadd }
237aebdb1e2SAdrian Chadd
238aebdb1e2SAdrian Chadd int
main(int argc,char * argv[])239aebdb1e2SAdrian Chadd main(int argc, char *argv[])
240aebdb1e2SAdrian Chadd {
241aebdb1e2SAdrian Chadd struct libusb_device_descriptor d;
242aebdb1e2SAdrian Chadd libusb_context *ctx;
243aebdb1e2SAdrian Chadd libusb_device *dev;
244aebdb1e2SAdrian Chadd libusb_device_handle *hdl;
245aebdb1e2SAdrian Chadd unsigned char state;
246aebdb1e2SAdrian Chadd struct ath3k_version ver;
247aebdb1e2SAdrian Chadd int r;
248aebdb1e2SAdrian Chadd uint8_t bus_id = 0, dev_id = 0;
249aebdb1e2SAdrian Chadd int devid_set = 0;
250aebdb1e2SAdrian Chadd int n;
251aebdb1e2SAdrian Chadd char *firmware_path = NULL;
252aebdb1e2SAdrian Chadd int is_3012 = 0;
253aebdb1e2SAdrian Chadd
254aebdb1e2SAdrian Chadd /* libusb setup */
255aebdb1e2SAdrian Chadd r = libusb_init(&ctx);
256aebdb1e2SAdrian Chadd if (r != 0) {
257aebdb1e2SAdrian Chadd ath3k_err("%s: libusb_init failed: code %d\n",
258aebdb1e2SAdrian Chadd argv[0],
259aebdb1e2SAdrian Chadd r);
260aebdb1e2SAdrian Chadd exit(127);
261aebdb1e2SAdrian Chadd }
262aebdb1e2SAdrian Chadd
263aebdb1e2SAdrian Chadd /* Enable debugging, just because */
264aebdb1e2SAdrian Chadd libusb_set_debug(ctx, 3);
265aebdb1e2SAdrian Chadd
266aebdb1e2SAdrian Chadd /* Parse command line arguments */
267aebdb1e2SAdrian Chadd while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
268aebdb1e2SAdrian Chadd switch (n) {
269aebdb1e2SAdrian Chadd case 'd': /* ugen device name */
270aebdb1e2SAdrian Chadd devid_set = 1;
271aebdb1e2SAdrian Chadd if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
272aebdb1e2SAdrian Chadd usage();
273aebdb1e2SAdrian Chadd break;
274aebdb1e2SAdrian Chadd case 'D':
275aebdb1e2SAdrian Chadd ath3k_do_debug = 1;
276aebdb1e2SAdrian Chadd break;
277aebdb1e2SAdrian Chadd case 'f': /* firmware path */
278aebdb1e2SAdrian Chadd if (firmware_path)
279aebdb1e2SAdrian Chadd free(firmware_path);
280aebdb1e2SAdrian Chadd firmware_path = strdup(optarg);
281aebdb1e2SAdrian Chadd break;
282aebdb1e2SAdrian Chadd case 'I':
283aebdb1e2SAdrian Chadd ath3k_do_info = 1;
284aebdb1e2SAdrian Chadd break;
285aebdb1e2SAdrian Chadd case 'h':
286aebdb1e2SAdrian Chadd default:
287aebdb1e2SAdrian Chadd usage();
288aebdb1e2SAdrian Chadd break;
289aebdb1e2SAdrian Chadd /* NOT REACHED */
290aebdb1e2SAdrian Chadd }
291aebdb1e2SAdrian Chadd }
292aebdb1e2SAdrian Chadd
293aebdb1e2SAdrian Chadd /* Ensure the devid was given! */
294aebdb1e2SAdrian Chadd if (devid_set == 0) {
295aebdb1e2SAdrian Chadd usage();
296aebdb1e2SAdrian Chadd /* NOTREACHED */
297aebdb1e2SAdrian Chadd }
298aebdb1e2SAdrian Chadd
299aebdb1e2SAdrian Chadd ath3k_debug("%s: opening dev %d.%d\n",
300aebdb1e2SAdrian Chadd basename(argv[0]),
301aebdb1e2SAdrian Chadd (int) bus_id,
302aebdb1e2SAdrian Chadd (int) dev_id);
303aebdb1e2SAdrian Chadd
304aebdb1e2SAdrian Chadd /* Find a device based on the bus/dev id */
305aebdb1e2SAdrian Chadd dev = ath3k_find_device(ctx, bus_id, dev_id);
306aebdb1e2SAdrian Chadd if (dev == NULL) {
307aebdb1e2SAdrian Chadd ath3k_err("%s: device not found\n", __func__);
308aebdb1e2SAdrian Chadd /* XXX cleanup? */
309aebdb1e2SAdrian Chadd exit(1);
310aebdb1e2SAdrian Chadd }
311aebdb1e2SAdrian Chadd
312aebdb1e2SAdrian Chadd /* Get the device descriptor for this device entry */
313aebdb1e2SAdrian Chadd r = libusb_get_device_descriptor(dev, &d);
314aebdb1e2SAdrian Chadd if (r != 0) {
315aebdb1e2SAdrian Chadd warn("%s: libusb_get_device_descriptor: %s\n",
316aebdb1e2SAdrian Chadd __func__,
317aebdb1e2SAdrian Chadd libusb_strerror(r));
318aebdb1e2SAdrian Chadd exit(1);
319aebdb1e2SAdrian Chadd }
320aebdb1e2SAdrian Chadd
321aebdb1e2SAdrian Chadd /* See if its an AR3012 */
322aebdb1e2SAdrian Chadd if (ath3k_is_3012(&d)) {
323aebdb1e2SAdrian Chadd is_3012 = 1;
324aebdb1e2SAdrian Chadd
325aebdb1e2SAdrian Chadd /* If it's bcdDevice > 1, don't attach */
326aebdb1e2SAdrian Chadd if (d.bcdDevice > 0x0001) {
327aebdb1e2SAdrian Chadd ath3k_debug("%s: AR3012; bcdDevice=%d, exiting\n",
328aebdb1e2SAdrian Chadd __func__,
329aebdb1e2SAdrian Chadd d.bcdDevice);
330aebdb1e2SAdrian Chadd exit(0);
331aebdb1e2SAdrian Chadd }
332aebdb1e2SAdrian Chadd }
333aebdb1e2SAdrian Chadd
334aebdb1e2SAdrian Chadd /* XXX enforce that bInterfaceNumber is 0 */
335aebdb1e2SAdrian Chadd
336aebdb1e2SAdrian Chadd /* XXX enforce the device/product id if they're non-zero */
337aebdb1e2SAdrian Chadd
338aebdb1e2SAdrian Chadd /* Grab device handle */
339aebdb1e2SAdrian Chadd r = libusb_open(dev, &hdl);
340aebdb1e2SAdrian Chadd if (r != 0) {
341aebdb1e2SAdrian Chadd ath3k_err("%s: libusb_open() failed: code %d\n", __func__, r);
342aebdb1e2SAdrian Chadd /* XXX cleanup? */
343aebdb1e2SAdrian Chadd exit(1);
344aebdb1e2SAdrian Chadd }
345aebdb1e2SAdrian Chadd
346aebdb1e2SAdrian Chadd /*
347aebdb1e2SAdrian Chadd * Get the initial NIC state.
348aebdb1e2SAdrian Chadd */
349aebdb1e2SAdrian Chadd r = ath3k_get_state(hdl, &state);
350aebdb1e2SAdrian Chadd if (r == 0) {
351aebdb1e2SAdrian Chadd ath3k_err("%s: ath3k_get_state() failed!\n", __func__);
352aebdb1e2SAdrian Chadd /* XXX cleanup? */
353aebdb1e2SAdrian Chadd exit(1);
354aebdb1e2SAdrian Chadd }
355aebdb1e2SAdrian Chadd ath3k_debug("%s: state=0x%02x\n",
356aebdb1e2SAdrian Chadd __func__,
357aebdb1e2SAdrian Chadd (int) state);
358aebdb1e2SAdrian Chadd
359aebdb1e2SAdrian Chadd /* And the version */
360aebdb1e2SAdrian Chadd r = ath3k_get_version(hdl, &ver);
361aebdb1e2SAdrian Chadd if (r == 0) {
362aebdb1e2SAdrian Chadd ath3k_err("%s: ath3k_get_version() failed!\n", __func__);
363aebdb1e2SAdrian Chadd /* XXX cleanup? */
364aebdb1e2SAdrian Chadd exit(1);
365aebdb1e2SAdrian Chadd }
366aebdb1e2SAdrian Chadd ath3k_info("ROM version: %d, build version: %d, ram version: %d, "
367aebdb1e2SAdrian Chadd "ref clock=%d\n",
368aebdb1e2SAdrian Chadd ver.rom_version,
369aebdb1e2SAdrian Chadd ver.build_version,
370aebdb1e2SAdrian Chadd ver.ram_version,
371aebdb1e2SAdrian Chadd ver.ref_clock);
372aebdb1e2SAdrian Chadd
373aebdb1e2SAdrian Chadd /* Default the firmware path */
374aebdb1e2SAdrian Chadd if (firmware_path == NULL)
375aebdb1e2SAdrian Chadd firmware_path = strdup(_DEFAULT_ATH3K_FIRMWARE_PATH);
376aebdb1e2SAdrian Chadd
377aebdb1e2SAdrian Chadd if (is_3012) {
378aebdb1e2SAdrian Chadd (void) ath3k_init_ar3012(hdl, firmware_path);
379aebdb1e2SAdrian Chadd } else {
380aebdb1e2SAdrian Chadd (void) ath3k_init_firmware(hdl, firmware_path);
381aebdb1e2SAdrian Chadd }
382aebdb1e2SAdrian Chadd
383aebdb1e2SAdrian Chadd /* Shutdown */
384aebdb1e2SAdrian Chadd libusb_close(hdl);
385aebdb1e2SAdrian Chadd hdl = NULL;
386aebdb1e2SAdrian Chadd
387aebdb1e2SAdrian Chadd libusb_unref_device(dev);
388aebdb1e2SAdrian Chadd dev = NULL;
389aebdb1e2SAdrian Chadd
390aebdb1e2SAdrian Chadd libusb_exit(ctx);
391aebdb1e2SAdrian Chadd ctx = NULL;
392aebdb1e2SAdrian Chadd }
393