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 <sys/endian.h>
40#include <sys/types.h>
41#include <sys/stat.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	XMIN(x, y)	((x) < (y) ? (x) : (y))
50
51int
52ath3k_load_fwfile(struct libusb_device_handle *hdl,
53    const struct ath3k_firmware *fw)
54{
55	int size, count, sent = 0;
56	int ret, r;
57
58	count = fw->len;
59
60	size = XMIN(count, FW_HDR_SIZE);
61
62	ath3k_debug("%s: file=%s, size=%d\n",
63	    __func__, fw->fwname, count);
64
65	/*
66	 * Flip the device over to configuration mode.
67	 */
68	ret = libusb_control_transfer(hdl,
69	    LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
70	    ATH3K_DNLOAD,
71	    0,
72	    0,
73	    fw->buf + sent,
74	    size,
75	    1000);	/* XXX timeout */
76
77	if (ret != size) {
78		fprintf(stderr, "Can't switch to config mode; ret=%d\n",
79		    ret);
80		return (-1);
81	}
82
83	sent += size;
84	count -= size;
85
86	/* Load in the rest of the data */
87	while (count) {
88		size = XMIN(count, BULK_SIZE);
89		ath3k_debug("%s: transferring %d bytes, offset %d\n",
90		    __func__,
91		    sent,
92		    size);
93
94		ret = libusb_bulk_transfer(hdl,
95		    0x2,
96		    fw->buf + sent,
97		    size,
98		    &r,
99		    1000);
100
101		if (ret < 0 || r != size) {
102			fprintf(stderr, "Can't load firmware: err=%s, size=%d\n",
103			    libusb_strerror(ret),
104			    size);
105			return (-1);
106		}
107		sent  += size;
108		count -= size;
109	}
110	return (0);
111}
112
113int
114ath3k_get_state(struct libusb_device_handle *hdl, unsigned char *state)
115{
116	int ret;
117
118	ret = libusb_control_transfer(hdl,
119	    LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
120	    ATH3K_GETSTATE,
121	    0,
122	    0,
123	    state,
124	    1,
125	    1000);	/* XXX timeout */
126
127	if (ret < 0) {
128		fprintf(stderr,
129		    "%s: libusb_control_transfer() failed: code=%d\n",
130		    __func__,
131		    ret);
132		return (0);
133	}
134
135	return (ret == 1);
136}
137
138int
139ath3k_get_version(struct libusb_device_handle *hdl,
140    struct ath3k_version *version)
141{
142	int ret;
143
144	ret = libusb_control_transfer(hdl,
145	    LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
146	    ATH3K_GETVERSION,
147	    0,
148	    0,
149	    (unsigned char *) version,
150	    sizeof(struct ath3k_version),
151	    1000);	/* XXX timeout */
152
153	if (ret < 0) {
154		fprintf(stderr,
155		    "%s: libusb_control_transfer() failed: code=%d\n",
156		    __func__,
157		    ret);
158		return (0);
159	}
160
161	/* XXX endian fix! */
162
163	return (ret == sizeof(struct ath3k_version));
164}
165
166int
167ath3k_load_patch(libusb_device_handle *hdl, const char *fw_path)
168{
169	int ret;
170	unsigned char fw_state;
171	struct ath3k_version fw_ver, pt_ver;
172	char fwname[FILENAME_MAX];
173	struct ath3k_firmware fw;
174	uint32_t tmp;
175
176	ret = ath3k_get_state(hdl, &fw_state);
177	if (ret < 0) {
178		ath3k_err("%s: Can't get state\n", __func__);
179		return (ret);
180	}
181
182	if (fw_state & ATH3K_PATCH_UPDATE) {
183		ath3k_info("%s: Patch already downloaded\n",
184		    __func__);
185		return (0);
186	}
187
188	ret = ath3k_get_version(hdl, &fw_ver);
189	if (ret < 0) {
190		ath3k_debug("%s: Can't get version\n", __func__);
191		return (ret);
192	}
193
194	/* XXX path info? */
195	snprintf(fwname, FILENAME_MAX, "%s/ar3k/AthrBT_0x%08x.dfu",
196	    fw_path,
197	    fw_ver.rom_version);
198
199	/* Read in the firmware */
200	if (ath3k_fw_read(&fw, fwname) <= 0) {
201		ath3k_debug("%s: ath3k_fw_read() failed\n",
202		    __func__);
203		return (-1);
204	}
205
206	/*
207	 * Extract the ROM/build version from the patch file.
208	 */
209	memcpy(&tmp, fw.buf + fw.len - 8, sizeof(tmp));
210	pt_ver.rom_version = le32toh(tmp);
211	memcpy(&tmp, fw.buf + fw.len - 4, sizeof(tmp));
212	pt_ver.build_version = le32toh(tmp);
213
214	ath3k_info("%s: file %s: rom_ver=%d, build_ver=%d\n",
215	    __func__,
216	    fwname,
217	    (int) pt_ver.rom_version,
218	    (int) pt_ver.build_version);
219
220	/* Check the ROM/build version against the firmware */
221	if ((pt_ver.rom_version != fw_ver.rom_version) ||
222	    (pt_ver.build_version <= fw_ver.build_version)) {
223		ath3k_debug("Patch file version mismatch!\n");
224		ath3k_fw_free(&fw);
225		return (-1);
226	}
227
228	/* Load in the firmware */
229	ret = ath3k_load_fwfile(hdl, &fw);
230
231	/* free it */
232	ath3k_fw_free(&fw);
233
234	return (ret);
235}
236
237int
238ath3k_load_syscfg(libusb_device_handle *hdl, const char *fw_path)
239{
240	unsigned char fw_state;
241	char filename[FILENAME_MAX];
242	struct ath3k_firmware fw;
243	struct ath3k_version fw_ver;
244	int clk_value, ret;
245
246	ret = ath3k_get_state(hdl, &fw_state);
247	if (ret < 0) {
248		ath3k_err("Can't get state to change to load configuration err");
249		return (-EBUSY);
250	}
251
252	ret = ath3k_get_version(hdl, &fw_ver);
253	if (ret < 0) {
254		ath3k_err("Can't get version to change to load ram patch err");
255		return (ret);
256	}
257
258	switch (fw_ver.ref_clock) {
259	case ATH3K_XTAL_FREQ_26M:
260		clk_value = 26;
261		break;
262	case ATH3K_XTAL_FREQ_40M:
263		clk_value = 40;
264		break;
265	case ATH3K_XTAL_FREQ_19P2:
266		clk_value = 19;
267		break;
268	default:
269		clk_value = 0;
270		break;
271}
272
273	snprintf(filename, FILENAME_MAX, "%s/ar3k/ramps_0x%08x_%d%s",
274	    fw_path,
275	    fw_ver.rom_version,
276	    clk_value,
277	    ".dfu");
278
279	ath3k_info("%s: syscfg file = %s\n",
280	    __func__,
281	    filename);
282
283	/* Read in the firmware */
284	if (ath3k_fw_read(&fw, filename) <= 0) {
285		ath3k_err("%s: ath3k_fw_read() failed\n",
286		    __func__);
287		return (-1);
288	}
289
290	ret = ath3k_load_fwfile(hdl, &fw);
291
292	ath3k_fw_free(&fw);
293	return (ret);
294}
295
296int
297ath3k_set_normal_mode(libusb_device_handle *hdl)
298{
299	int ret;
300	unsigned char fw_state;
301
302	ret = ath3k_get_state(hdl, &fw_state);
303	if (ret < 0) {
304		ath3k_err("%s: can't get state\n", __func__);
305		return (ret);
306	}
307
308	/*
309	 * This isn't a fatal error - the device may have detached
310	 * already.
311	 */
312	if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
313		ath3k_debug("%s: firmware is already in normal mode\n",
314		    __func__);
315		return (0);
316	}
317
318	ret = libusb_control_transfer(hdl,
319	    LIBUSB_REQUEST_TYPE_VENDOR,		/* XXX out direction? */
320	    ATH3K_SET_NORMAL_MODE,
321	    0,
322	    0,
323	    NULL,
324	    0,
325	    1000);	/* XXX timeout */
326
327	if (ret < 0) {
328		ath3k_err("%s: libusb_control_transfer() failed: code=%d\n",
329		    __func__,
330		    ret);
331		return (0);
332	}
333
334	return (ret == 0);
335}
336
337int
338ath3k_switch_pid(libusb_device_handle *hdl)
339{
340	int ret;
341	ret = libusb_control_transfer(hdl,
342	    LIBUSB_REQUEST_TYPE_VENDOR,		/* XXX set an out flag? */
343	    USB_REG_SWITCH_VID_PID,
344	    0,
345	    0,
346	    NULL,
347	    0,
348	    1000);	/* XXX timeout */
349
350	if (ret < 0) {
351		ath3k_debug("%s: libusb_control_transfer() failed: code=%d\n",
352		    __func__,
353		    ret);
354		return (0);
355	}
356
357	return (ret == 0);
358}
359