Path: blob/main/usr.sbin/bluetooth/ath3kfw/ath3k_hw.c
107609 views
/*-1* Copyright (c) 2013 Adrian Chadd <[email protected]>2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer,9* without modification.10* 2. Redistributions in binary form must reproduce at minimum a disclaimer11* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any12* redistribution must be conditioned upon including a substantially13* similar Disclaimer requirement for further binary redistribution.14*15* NO WARRANTY16* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS17* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT18* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY19* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL20* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,21* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF22* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS23* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER24* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)25* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF26* THE POSSIBILITY OF SUCH DAMAGES.27*/2829#include <stdio.h>30#include <stdlib.h>31#include <unistd.h>32#include <errno.h>33#include <string.h>34#include <err.h>35#include <fcntl.h>36#include <sys/endian.h>37#include <sys/types.h>38#include <sys/stat.h>3940#include <libusb.h>4142#include "ath3k_fw.h"43#include "ath3k_hw.h"44#include "ath3k_dbg.h"4546#define XMIN(x, y) ((x) < (y) ? (x) : (y))4748int49ath3k_load_fwfile(struct libusb_device_handle *hdl,50const struct ath3k_firmware *fw)51{52int size, count, sent = 0;53int ret, r;5455count = fw->len;5657size = XMIN(count, FW_HDR_SIZE);5859ath3k_debug("%s: file=%s, size=%d\n",60__func__, fw->fwname, count);6162/*63* Flip the device over to configuration mode.64*/65ret = libusb_control_transfer(hdl,66LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,67ATH3K_DNLOAD,680,690,70fw->buf + sent,71size,721000); /* XXX timeout */7374if (ret != size) {75fprintf(stderr, "Can't switch to config mode; ret=%d\n",76ret);77return (-1);78}7980sent += size;81count -= size;8283/* Load in the rest of the data */84while (count) {85size = XMIN(count, BULK_SIZE);86ath3k_debug("%s: transferring %d bytes, offset %d\n",87__func__,88sent,89size);9091ret = libusb_bulk_transfer(hdl,920x2,93fw->buf + sent,94size,95&r,961000);9798if (ret < 0 || r != size) {99fprintf(stderr, "Can't load firmware: err=%s, size=%d\n",100libusb_strerror(ret),101size);102return (-1);103}104sent += size;105count -= size;106}107return (0);108}109110int111ath3k_get_state(struct libusb_device_handle *hdl, unsigned char *state)112{113int ret;114115ret = libusb_control_transfer(hdl,116LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,117ATH3K_GETSTATE,1180,1190,120state,1211,1221000); /* XXX timeout */123124if (ret < 0) {125fprintf(stderr,126"%s: libusb_control_transfer() failed: code=%d\n",127__func__,128ret);129return (0);130}131132return (ret == 1);133}134135int136ath3k_get_version(struct libusb_device_handle *hdl,137struct ath3k_version *version)138{139int ret;140141ret = libusb_control_transfer(hdl,142LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,143ATH3K_GETVERSION,1440,1450,146(unsigned char *) version,147sizeof(struct ath3k_version),1481000); /* XXX timeout */149150if (ret < 0) {151fprintf(stderr,152"%s: libusb_control_transfer() failed: code=%d\n",153__func__,154ret);155return (0);156}157158/* XXX endian fix! */159160return (ret == sizeof(struct ath3k_version));161}162163int164ath3k_load_patch(libusb_device_handle *hdl, const char *fw_path)165{166int ret;167unsigned char fw_state;168struct ath3k_version fw_ver, pt_ver;169char fwname[FILENAME_MAX];170struct ath3k_firmware fw;171uint32_t tmp;172173ret = ath3k_get_state(hdl, &fw_state);174if (ret < 0) {175ath3k_err("%s: Can't get state\n", __func__);176return (ret);177}178179if (fw_state & ATH3K_PATCH_UPDATE) {180ath3k_info("%s: Patch already downloaded\n",181__func__);182return (0);183}184185ret = ath3k_get_version(hdl, &fw_ver);186if (ret < 0) {187ath3k_debug("%s: Can't get version\n", __func__);188return (ret);189}190191/* XXX path info? */192snprintf(fwname, FILENAME_MAX, "%s/ar3k/AthrBT_0x%08x.dfu",193fw_path,194fw_ver.rom_version);195196/* Read in the firmware */197if (ath3k_fw_read(&fw, fwname) <= 0) {198ath3k_debug("%s: ath3k_fw_read() failed\n",199__func__);200return (-1);201}202203/*204* Extract the ROM/build version from the patch file.205*/206memcpy(&tmp, fw.buf + fw.len - 8, sizeof(tmp));207pt_ver.rom_version = le32toh(tmp);208memcpy(&tmp, fw.buf + fw.len - 4, sizeof(tmp));209pt_ver.build_version = le32toh(tmp);210211ath3k_info("%s: file %s: rom_ver=%d, build_ver=%d\n",212__func__,213fwname,214(int) pt_ver.rom_version,215(int) pt_ver.build_version);216217/* Check the ROM/build version against the firmware */218if ((pt_ver.rom_version != fw_ver.rom_version) ||219(pt_ver.build_version <= fw_ver.build_version)) {220ath3k_debug("Patch file version mismatch!\n");221ath3k_fw_free(&fw);222return (-1);223}224225/* Load in the firmware */226ret = ath3k_load_fwfile(hdl, &fw);227228/* free it */229ath3k_fw_free(&fw);230231return (ret);232}233234int235ath3k_load_syscfg(libusb_device_handle *hdl, const char *fw_path)236{237unsigned char fw_state;238char filename[FILENAME_MAX];239struct ath3k_firmware fw;240struct ath3k_version fw_ver;241int clk_value, ret;242243ret = ath3k_get_state(hdl, &fw_state);244if (ret < 0) {245ath3k_err("Can't get state to change to load configuration err");246return (-EBUSY);247}248249ret = ath3k_get_version(hdl, &fw_ver);250if (ret < 0) {251ath3k_err("Can't get version to change to load ram patch err");252return (ret);253}254255switch (fw_ver.ref_clock) {256case ATH3K_XTAL_FREQ_26M:257clk_value = 26;258break;259case ATH3K_XTAL_FREQ_40M:260clk_value = 40;261break;262case ATH3K_XTAL_FREQ_19P2:263clk_value = 19;264break;265default:266clk_value = 0;267break;268}269270snprintf(filename, FILENAME_MAX, "%s/ar3k/ramps_0x%08x_%d%s",271fw_path,272fw_ver.rom_version,273clk_value,274".dfu");275276ath3k_info("%s: syscfg file = %s\n",277__func__,278filename);279280/* Read in the firmware */281if (ath3k_fw_read(&fw, filename) <= 0) {282ath3k_err("%s: ath3k_fw_read() failed\n",283__func__);284return (-1);285}286287ret = ath3k_load_fwfile(hdl, &fw);288289ath3k_fw_free(&fw);290return (ret);291}292293int294ath3k_set_normal_mode(libusb_device_handle *hdl)295{296int ret;297unsigned char fw_state;298299ret = ath3k_get_state(hdl, &fw_state);300if (ret < 0) {301ath3k_err("%s: can't get state\n", __func__);302return (ret);303}304305/*306* This isn't a fatal error - the device may have detached307* already.308*/309if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {310ath3k_debug("%s: firmware is already in normal mode\n",311__func__);312return (0);313}314315ret = libusb_control_transfer(hdl,316LIBUSB_REQUEST_TYPE_VENDOR, /* XXX out direction? */317ATH3K_SET_NORMAL_MODE,3180,3190,320NULL,3210,3221000); /* XXX timeout */323324if (ret < 0) {325ath3k_err("%s: libusb_control_transfer() failed: code=%d\n",326__func__,327ret);328return (0);329}330331return (ret == 0);332}333334int335ath3k_switch_pid(libusb_device_handle *hdl)336{337int ret;338ret = libusb_control_transfer(hdl,339LIBUSB_REQUEST_TYPE_VENDOR, /* XXX set an out flag? */340USB_REG_SWITCH_VID_PID,3410,3420,343NULL,3440,3451000); /* XXX timeout */346347if (ret < 0) {348ath3k_debug("%s: libusb_control_transfer() failed: code=%d\n",349__func__,350ret);351return (0);352}353354return (ret == 0);355}356357358