xref: /freebsd/usr.sbin/bluetooth/ath3kfw/ath3k_hw.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1*aebdb1e2SAdrian Chadd /*-
2*aebdb1e2SAdrian Chadd  * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
3*aebdb1e2SAdrian Chadd  * All rights reserved.
4*aebdb1e2SAdrian Chadd  *
5*aebdb1e2SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
6*aebdb1e2SAdrian Chadd  * modification, are permitted provided that the following conditions
7*aebdb1e2SAdrian Chadd  * are met:
8*aebdb1e2SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
9*aebdb1e2SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
10*aebdb1e2SAdrian Chadd  *    without modification.
11*aebdb1e2SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12*aebdb1e2SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13*aebdb1e2SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
14*aebdb1e2SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
15*aebdb1e2SAdrian Chadd  *
16*aebdb1e2SAdrian Chadd  * NO WARRANTY
17*aebdb1e2SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*aebdb1e2SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*aebdb1e2SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20*aebdb1e2SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21*aebdb1e2SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22*aebdb1e2SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*aebdb1e2SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*aebdb1e2SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*aebdb1e2SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*aebdb1e2SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27*aebdb1e2SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
28*aebdb1e2SAdrian Chadd  */
29*aebdb1e2SAdrian Chadd 
30*aebdb1e2SAdrian Chadd #include <stdio.h>
31*aebdb1e2SAdrian Chadd #include <stdlib.h>
32*aebdb1e2SAdrian Chadd #include <unistd.h>
33*aebdb1e2SAdrian Chadd #include <errno.h>
34*aebdb1e2SAdrian Chadd #include <string.h>
35*aebdb1e2SAdrian Chadd #include <err.h>
36*aebdb1e2SAdrian Chadd #include <fcntl.h>
37*aebdb1e2SAdrian Chadd #include <sys/endian.h>
38*aebdb1e2SAdrian Chadd #include <sys/types.h>
39*aebdb1e2SAdrian Chadd #include <sys/stat.h>
40*aebdb1e2SAdrian Chadd 
41*aebdb1e2SAdrian Chadd #include <libusb.h>
42*aebdb1e2SAdrian Chadd 
43*aebdb1e2SAdrian Chadd #include "ath3k_fw.h"
44*aebdb1e2SAdrian Chadd #include "ath3k_hw.h"
45*aebdb1e2SAdrian Chadd #include "ath3k_dbg.h"
46*aebdb1e2SAdrian Chadd 
47*aebdb1e2SAdrian Chadd #define	XMIN(x, y)	((x) < (y) ? (x) : (y))
48*aebdb1e2SAdrian Chadd 
49*aebdb1e2SAdrian Chadd int
ath3k_load_fwfile(struct libusb_device_handle * hdl,const struct ath3k_firmware * fw)50*aebdb1e2SAdrian Chadd ath3k_load_fwfile(struct libusb_device_handle *hdl,
51*aebdb1e2SAdrian Chadd     const struct ath3k_firmware *fw)
52*aebdb1e2SAdrian Chadd {
53*aebdb1e2SAdrian Chadd 	int size, count, sent = 0;
54*aebdb1e2SAdrian Chadd 	int ret, r;
55*aebdb1e2SAdrian Chadd 
56*aebdb1e2SAdrian Chadd 	count = fw->len;
57*aebdb1e2SAdrian Chadd 
58*aebdb1e2SAdrian Chadd 	size = XMIN(count, FW_HDR_SIZE);
59*aebdb1e2SAdrian Chadd 
60*aebdb1e2SAdrian Chadd 	ath3k_debug("%s: file=%s, size=%d\n",
61*aebdb1e2SAdrian Chadd 	    __func__, fw->fwname, count);
62*aebdb1e2SAdrian Chadd 
63*aebdb1e2SAdrian Chadd 	/*
64*aebdb1e2SAdrian Chadd 	 * Flip the device over to configuration mode.
65*aebdb1e2SAdrian Chadd 	 */
66*aebdb1e2SAdrian Chadd 	ret = libusb_control_transfer(hdl,
67*aebdb1e2SAdrian Chadd 	    LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
68*aebdb1e2SAdrian Chadd 	    ATH3K_DNLOAD,
69*aebdb1e2SAdrian Chadd 	    0,
70*aebdb1e2SAdrian Chadd 	    0,
71*aebdb1e2SAdrian Chadd 	    fw->buf + sent,
72*aebdb1e2SAdrian Chadd 	    size,
73*aebdb1e2SAdrian Chadd 	    1000);	/* XXX timeout */
74*aebdb1e2SAdrian Chadd 
75*aebdb1e2SAdrian Chadd 	if (ret != size) {
76*aebdb1e2SAdrian Chadd 		fprintf(stderr, "Can't switch to config mode; ret=%d\n",
77*aebdb1e2SAdrian Chadd 		    ret);
78*aebdb1e2SAdrian Chadd 		return (-1);
79*aebdb1e2SAdrian Chadd 	}
80*aebdb1e2SAdrian Chadd 
81*aebdb1e2SAdrian Chadd 	sent += size;
82*aebdb1e2SAdrian Chadd 	count -= size;
83*aebdb1e2SAdrian Chadd 
84*aebdb1e2SAdrian Chadd 	/* Load in the rest of the data */
85*aebdb1e2SAdrian Chadd 	while (count) {
86*aebdb1e2SAdrian Chadd 		size = XMIN(count, BULK_SIZE);
87*aebdb1e2SAdrian Chadd 		ath3k_debug("%s: transferring %d bytes, offset %d\n",
88*aebdb1e2SAdrian Chadd 		    __func__,
89*aebdb1e2SAdrian Chadd 		    sent,
90*aebdb1e2SAdrian Chadd 		    size);
91*aebdb1e2SAdrian Chadd 
92*aebdb1e2SAdrian Chadd 		ret = libusb_bulk_transfer(hdl,
93*aebdb1e2SAdrian Chadd 		    0x2,
94*aebdb1e2SAdrian Chadd 		    fw->buf + sent,
95*aebdb1e2SAdrian Chadd 		    size,
96*aebdb1e2SAdrian Chadd 		    &r,
97*aebdb1e2SAdrian Chadd 		    1000);
98*aebdb1e2SAdrian Chadd 
99*aebdb1e2SAdrian Chadd 		if (ret < 0 || r != size) {
100*aebdb1e2SAdrian Chadd 			fprintf(stderr, "Can't load firmware: err=%s, size=%d\n",
101*aebdb1e2SAdrian Chadd 			    libusb_strerror(ret),
102*aebdb1e2SAdrian Chadd 			    size);
103*aebdb1e2SAdrian Chadd 			return (-1);
104*aebdb1e2SAdrian Chadd 		}
105*aebdb1e2SAdrian Chadd 		sent  += size;
106*aebdb1e2SAdrian Chadd 		count -= size;
107*aebdb1e2SAdrian Chadd 	}
108*aebdb1e2SAdrian Chadd 	return (0);
109*aebdb1e2SAdrian Chadd }
110*aebdb1e2SAdrian Chadd 
111*aebdb1e2SAdrian Chadd int
ath3k_get_state(struct libusb_device_handle * hdl,unsigned char * state)112*aebdb1e2SAdrian Chadd ath3k_get_state(struct libusb_device_handle *hdl, unsigned char *state)
113*aebdb1e2SAdrian Chadd {
114*aebdb1e2SAdrian Chadd 	int ret;
115*aebdb1e2SAdrian Chadd 
116*aebdb1e2SAdrian Chadd 	ret = libusb_control_transfer(hdl,
117*aebdb1e2SAdrian Chadd 	    LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
118*aebdb1e2SAdrian Chadd 	    ATH3K_GETSTATE,
119*aebdb1e2SAdrian Chadd 	    0,
120*aebdb1e2SAdrian Chadd 	    0,
121*aebdb1e2SAdrian Chadd 	    state,
122*aebdb1e2SAdrian Chadd 	    1,
123*aebdb1e2SAdrian Chadd 	    1000);	/* XXX timeout */
124*aebdb1e2SAdrian Chadd 
125*aebdb1e2SAdrian Chadd 	if (ret < 0) {
126*aebdb1e2SAdrian Chadd 		fprintf(stderr,
127*aebdb1e2SAdrian Chadd 		    "%s: libusb_control_transfer() failed: code=%d\n",
128*aebdb1e2SAdrian Chadd 		    __func__,
129*aebdb1e2SAdrian Chadd 		    ret);
130*aebdb1e2SAdrian Chadd 		return (0);
131*aebdb1e2SAdrian Chadd 	}
132*aebdb1e2SAdrian Chadd 
133*aebdb1e2SAdrian Chadd 	return (ret == 1);
134*aebdb1e2SAdrian Chadd }
135*aebdb1e2SAdrian Chadd 
136*aebdb1e2SAdrian Chadd int
ath3k_get_version(struct libusb_device_handle * hdl,struct ath3k_version * version)137*aebdb1e2SAdrian Chadd ath3k_get_version(struct libusb_device_handle *hdl,
138*aebdb1e2SAdrian Chadd     struct ath3k_version *version)
139*aebdb1e2SAdrian Chadd {
140*aebdb1e2SAdrian Chadd 	int ret;
141*aebdb1e2SAdrian Chadd 
142*aebdb1e2SAdrian Chadd 	ret = libusb_control_transfer(hdl,
143*aebdb1e2SAdrian Chadd 	    LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
144*aebdb1e2SAdrian Chadd 	    ATH3K_GETVERSION,
145*aebdb1e2SAdrian Chadd 	    0,
146*aebdb1e2SAdrian Chadd 	    0,
147*aebdb1e2SAdrian Chadd 	    (unsigned char *) version,
148*aebdb1e2SAdrian Chadd 	    sizeof(struct ath3k_version),
149*aebdb1e2SAdrian Chadd 	    1000);	/* XXX timeout */
150*aebdb1e2SAdrian Chadd 
151*aebdb1e2SAdrian Chadd 	if (ret < 0) {
152*aebdb1e2SAdrian Chadd 		fprintf(stderr,
153*aebdb1e2SAdrian Chadd 		    "%s: libusb_control_transfer() failed: code=%d\n",
154*aebdb1e2SAdrian Chadd 		    __func__,
155*aebdb1e2SAdrian Chadd 		    ret);
156*aebdb1e2SAdrian Chadd 		return (0);
157*aebdb1e2SAdrian Chadd 	}
158*aebdb1e2SAdrian Chadd 
159*aebdb1e2SAdrian Chadd 	/* XXX endian fix! */
160*aebdb1e2SAdrian Chadd 
161*aebdb1e2SAdrian Chadd 	return (ret == sizeof(struct ath3k_version));
162*aebdb1e2SAdrian Chadd }
163*aebdb1e2SAdrian Chadd 
164*aebdb1e2SAdrian Chadd int
ath3k_load_patch(libusb_device_handle * hdl,const char * fw_path)165*aebdb1e2SAdrian Chadd ath3k_load_patch(libusb_device_handle *hdl, const char *fw_path)
166*aebdb1e2SAdrian Chadd {
167*aebdb1e2SAdrian Chadd 	int ret;
168*aebdb1e2SAdrian Chadd 	unsigned char fw_state;
169*aebdb1e2SAdrian Chadd 	struct ath3k_version fw_ver, pt_ver;
170*aebdb1e2SAdrian Chadd 	char fwname[FILENAME_MAX];
171*aebdb1e2SAdrian Chadd 	struct ath3k_firmware fw;
172*aebdb1e2SAdrian Chadd 	uint32_t tmp;
173*aebdb1e2SAdrian Chadd 
174*aebdb1e2SAdrian Chadd 	ret = ath3k_get_state(hdl, &fw_state);
175*aebdb1e2SAdrian Chadd 	if (ret < 0) {
176*aebdb1e2SAdrian Chadd 		ath3k_err("%s: Can't get state\n", __func__);
177*aebdb1e2SAdrian Chadd 		return (ret);
178*aebdb1e2SAdrian Chadd 	}
179*aebdb1e2SAdrian Chadd 
180*aebdb1e2SAdrian Chadd 	if (fw_state & ATH3K_PATCH_UPDATE) {
181*aebdb1e2SAdrian Chadd 		ath3k_info("%s: Patch already downloaded\n",
182*aebdb1e2SAdrian Chadd 		    __func__);
183*aebdb1e2SAdrian Chadd 		return (0);
184*aebdb1e2SAdrian Chadd 	}
185*aebdb1e2SAdrian Chadd 
186*aebdb1e2SAdrian Chadd 	ret = ath3k_get_version(hdl, &fw_ver);
187*aebdb1e2SAdrian Chadd 	if (ret < 0) {
188*aebdb1e2SAdrian Chadd 		ath3k_debug("%s: Can't get version\n", __func__);
189*aebdb1e2SAdrian Chadd 		return (ret);
190*aebdb1e2SAdrian Chadd 	}
191*aebdb1e2SAdrian Chadd 
192*aebdb1e2SAdrian Chadd 	/* XXX path info? */
193*aebdb1e2SAdrian Chadd 	snprintf(fwname, FILENAME_MAX, "%s/ar3k/AthrBT_0x%08x.dfu",
194*aebdb1e2SAdrian Chadd 	    fw_path,
195*aebdb1e2SAdrian Chadd 	    fw_ver.rom_version);
196*aebdb1e2SAdrian Chadd 
197*aebdb1e2SAdrian Chadd 	/* Read in the firmware */
198*aebdb1e2SAdrian Chadd 	if (ath3k_fw_read(&fw, fwname) <= 0) {
199*aebdb1e2SAdrian Chadd 		ath3k_debug("%s: ath3k_fw_read() failed\n",
200*aebdb1e2SAdrian Chadd 		    __func__);
201*aebdb1e2SAdrian Chadd 		return (-1);
202*aebdb1e2SAdrian Chadd 	}
203*aebdb1e2SAdrian Chadd 
204*aebdb1e2SAdrian Chadd 	/*
205*aebdb1e2SAdrian Chadd 	 * Extract the ROM/build version from the patch file.
206*aebdb1e2SAdrian Chadd 	 */
207*aebdb1e2SAdrian Chadd 	memcpy(&tmp, fw.buf + fw.len - 8, sizeof(tmp));
208*aebdb1e2SAdrian Chadd 	pt_ver.rom_version = le32toh(tmp);
209*aebdb1e2SAdrian Chadd 	memcpy(&tmp, fw.buf + fw.len - 4, sizeof(tmp));
210*aebdb1e2SAdrian Chadd 	pt_ver.build_version = le32toh(tmp);
211*aebdb1e2SAdrian Chadd 
212*aebdb1e2SAdrian Chadd 	ath3k_info("%s: file %s: rom_ver=%d, build_ver=%d\n",
213*aebdb1e2SAdrian Chadd 	    __func__,
214*aebdb1e2SAdrian Chadd 	    fwname,
215*aebdb1e2SAdrian Chadd 	    (int) pt_ver.rom_version,
216*aebdb1e2SAdrian Chadd 	    (int) pt_ver.build_version);
217*aebdb1e2SAdrian Chadd 
218*aebdb1e2SAdrian Chadd 	/* Check the ROM/build version against the firmware */
219*aebdb1e2SAdrian Chadd 	if ((pt_ver.rom_version != fw_ver.rom_version) ||
220*aebdb1e2SAdrian Chadd 	    (pt_ver.build_version <= fw_ver.build_version)) {
221*aebdb1e2SAdrian Chadd 		ath3k_debug("Patch file version mismatch!\n");
222*aebdb1e2SAdrian Chadd 		ath3k_fw_free(&fw);
223*aebdb1e2SAdrian Chadd 		return (-1);
224*aebdb1e2SAdrian Chadd 	}
225*aebdb1e2SAdrian Chadd 
226*aebdb1e2SAdrian Chadd 	/* Load in the firmware */
227*aebdb1e2SAdrian Chadd 	ret = ath3k_load_fwfile(hdl, &fw);
228*aebdb1e2SAdrian Chadd 
229*aebdb1e2SAdrian Chadd 	/* free it */
230*aebdb1e2SAdrian Chadd 	ath3k_fw_free(&fw);
231*aebdb1e2SAdrian Chadd 
232*aebdb1e2SAdrian Chadd 	return (ret);
233*aebdb1e2SAdrian Chadd }
234*aebdb1e2SAdrian Chadd 
235*aebdb1e2SAdrian Chadd int
ath3k_load_syscfg(libusb_device_handle * hdl,const char * fw_path)236*aebdb1e2SAdrian Chadd ath3k_load_syscfg(libusb_device_handle *hdl, const char *fw_path)
237*aebdb1e2SAdrian Chadd {
238*aebdb1e2SAdrian Chadd 	unsigned char fw_state;
239*aebdb1e2SAdrian Chadd 	char filename[FILENAME_MAX];
240*aebdb1e2SAdrian Chadd 	struct ath3k_firmware fw;
241*aebdb1e2SAdrian Chadd 	struct ath3k_version fw_ver;
242*aebdb1e2SAdrian Chadd 	int clk_value, ret;
243*aebdb1e2SAdrian Chadd 
244*aebdb1e2SAdrian Chadd 	ret = ath3k_get_state(hdl, &fw_state);
245*aebdb1e2SAdrian Chadd 	if (ret < 0) {
246*aebdb1e2SAdrian Chadd 		ath3k_err("Can't get state to change to load configuration err");
247*aebdb1e2SAdrian Chadd 		return (-EBUSY);
248*aebdb1e2SAdrian Chadd 	}
249*aebdb1e2SAdrian Chadd 
250*aebdb1e2SAdrian Chadd 	ret = ath3k_get_version(hdl, &fw_ver);
251*aebdb1e2SAdrian Chadd 	if (ret < 0) {
252*aebdb1e2SAdrian Chadd 		ath3k_err("Can't get version to change to load ram patch err");
253*aebdb1e2SAdrian Chadd 		return (ret);
254*aebdb1e2SAdrian Chadd 	}
255*aebdb1e2SAdrian Chadd 
256*aebdb1e2SAdrian Chadd 	switch (fw_ver.ref_clock) {
257*aebdb1e2SAdrian Chadd 	case ATH3K_XTAL_FREQ_26M:
258*aebdb1e2SAdrian Chadd 		clk_value = 26;
259*aebdb1e2SAdrian Chadd 		break;
260*aebdb1e2SAdrian Chadd 	case ATH3K_XTAL_FREQ_40M:
261*aebdb1e2SAdrian Chadd 		clk_value = 40;
262*aebdb1e2SAdrian Chadd 		break;
263*aebdb1e2SAdrian Chadd 	case ATH3K_XTAL_FREQ_19P2:
264*aebdb1e2SAdrian Chadd 		clk_value = 19;
265*aebdb1e2SAdrian Chadd 		break;
266*aebdb1e2SAdrian Chadd 	default:
267*aebdb1e2SAdrian Chadd 		clk_value = 0;
268*aebdb1e2SAdrian Chadd 		break;
269*aebdb1e2SAdrian Chadd }
270*aebdb1e2SAdrian Chadd 
271*aebdb1e2SAdrian Chadd 	snprintf(filename, FILENAME_MAX, "%s/ar3k/ramps_0x%08x_%d%s",
272*aebdb1e2SAdrian Chadd 	    fw_path,
273*aebdb1e2SAdrian Chadd 	    fw_ver.rom_version,
274*aebdb1e2SAdrian Chadd 	    clk_value,
275*aebdb1e2SAdrian Chadd 	    ".dfu");
276*aebdb1e2SAdrian Chadd 
277*aebdb1e2SAdrian Chadd 	ath3k_info("%s: syscfg file = %s\n",
278*aebdb1e2SAdrian Chadd 	    __func__,
279*aebdb1e2SAdrian Chadd 	    filename);
280*aebdb1e2SAdrian Chadd 
281*aebdb1e2SAdrian Chadd 	/* Read in the firmware */
282*aebdb1e2SAdrian Chadd 	if (ath3k_fw_read(&fw, filename) <= 0) {
283*aebdb1e2SAdrian Chadd 		ath3k_err("%s: ath3k_fw_read() failed\n",
284*aebdb1e2SAdrian Chadd 		    __func__);
285*aebdb1e2SAdrian Chadd 		return (-1);
286*aebdb1e2SAdrian Chadd 	}
287*aebdb1e2SAdrian Chadd 
288*aebdb1e2SAdrian Chadd 	ret = ath3k_load_fwfile(hdl, &fw);
289*aebdb1e2SAdrian Chadd 
290*aebdb1e2SAdrian Chadd 	ath3k_fw_free(&fw);
291*aebdb1e2SAdrian Chadd 	return (ret);
292*aebdb1e2SAdrian Chadd }
293*aebdb1e2SAdrian Chadd 
294*aebdb1e2SAdrian Chadd int
ath3k_set_normal_mode(libusb_device_handle * hdl)295*aebdb1e2SAdrian Chadd ath3k_set_normal_mode(libusb_device_handle *hdl)
296*aebdb1e2SAdrian Chadd {
297*aebdb1e2SAdrian Chadd 	int ret;
298*aebdb1e2SAdrian Chadd 	unsigned char fw_state;
299*aebdb1e2SAdrian Chadd 
300*aebdb1e2SAdrian Chadd 	ret = ath3k_get_state(hdl, &fw_state);
301*aebdb1e2SAdrian Chadd 	if (ret < 0) {
302*aebdb1e2SAdrian Chadd 		ath3k_err("%s: can't get state\n", __func__);
303*aebdb1e2SAdrian Chadd 		return (ret);
304*aebdb1e2SAdrian Chadd 	}
305*aebdb1e2SAdrian Chadd 
306*aebdb1e2SAdrian Chadd 	/*
307*aebdb1e2SAdrian Chadd 	 * This isn't a fatal error - the device may have detached
308*aebdb1e2SAdrian Chadd 	 * already.
309*aebdb1e2SAdrian Chadd 	 */
310*aebdb1e2SAdrian Chadd 	if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
311*aebdb1e2SAdrian Chadd 		ath3k_debug("%s: firmware is already in normal mode\n",
312*aebdb1e2SAdrian Chadd 		    __func__);
313*aebdb1e2SAdrian Chadd 		return (0);
314*aebdb1e2SAdrian Chadd 	}
315*aebdb1e2SAdrian Chadd 
316*aebdb1e2SAdrian Chadd 	ret = libusb_control_transfer(hdl,
317*aebdb1e2SAdrian Chadd 	    LIBUSB_REQUEST_TYPE_VENDOR,		/* XXX out direction? */
318*aebdb1e2SAdrian Chadd 	    ATH3K_SET_NORMAL_MODE,
319*aebdb1e2SAdrian Chadd 	    0,
320*aebdb1e2SAdrian Chadd 	    0,
321*aebdb1e2SAdrian Chadd 	    NULL,
322*aebdb1e2SAdrian Chadd 	    0,
323*aebdb1e2SAdrian Chadd 	    1000);	/* XXX timeout */
324*aebdb1e2SAdrian Chadd 
325*aebdb1e2SAdrian Chadd 	if (ret < 0) {
326*aebdb1e2SAdrian Chadd 		ath3k_err("%s: libusb_control_transfer() failed: code=%d\n",
327*aebdb1e2SAdrian Chadd 		    __func__,
328*aebdb1e2SAdrian Chadd 		    ret);
329*aebdb1e2SAdrian Chadd 		return (0);
330*aebdb1e2SAdrian Chadd 	}
331*aebdb1e2SAdrian Chadd 
332*aebdb1e2SAdrian Chadd 	return (ret == 0);
333*aebdb1e2SAdrian Chadd }
334*aebdb1e2SAdrian Chadd 
335*aebdb1e2SAdrian Chadd int
ath3k_switch_pid(libusb_device_handle * hdl)336*aebdb1e2SAdrian Chadd ath3k_switch_pid(libusb_device_handle *hdl)
337*aebdb1e2SAdrian Chadd {
338*aebdb1e2SAdrian Chadd 	int ret;
339*aebdb1e2SAdrian Chadd 	ret = libusb_control_transfer(hdl,
340*aebdb1e2SAdrian Chadd 	    LIBUSB_REQUEST_TYPE_VENDOR,		/* XXX set an out flag? */
341*aebdb1e2SAdrian Chadd 	    USB_REG_SWITCH_VID_PID,
342*aebdb1e2SAdrian Chadd 	    0,
343*aebdb1e2SAdrian Chadd 	    0,
344*aebdb1e2SAdrian Chadd 	    NULL,
345*aebdb1e2SAdrian Chadd 	    0,
346*aebdb1e2SAdrian Chadd 	    1000);	/* XXX timeout */
347*aebdb1e2SAdrian Chadd 
348*aebdb1e2SAdrian Chadd 	if (ret < 0) {
349*aebdb1e2SAdrian Chadd 		ath3k_debug("%s: libusb_control_transfer() failed: code=%d\n",
350*aebdb1e2SAdrian Chadd 		    __func__,
351*aebdb1e2SAdrian Chadd 		    ret);
352*aebdb1e2SAdrian Chadd 		return (0);
353*aebdb1e2SAdrian Chadd 	}
354*aebdb1e2SAdrian Chadd 
355*aebdb1e2SAdrian Chadd 	return (ret == 0);
356*aebdb1e2SAdrian Chadd }
357