17f32f0e2SVladimir Kondratyev /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 37f32f0e2SVladimir Kondratyev * 47f32f0e2SVladimir Kondratyev * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org> 57f32f0e2SVladimir Kondratyev * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> 6c1643cedSVladimir Kondratyev * Copyright (c) 2023 Future Crew LLC. 77f32f0e2SVladimir Kondratyev * 87f32f0e2SVladimir Kondratyev * Redistribution and use in source and binary forms, with or without 97f32f0e2SVladimir Kondratyev * modification, are permitted provided that the following conditions 107f32f0e2SVladimir Kondratyev * are met: 117f32f0e2SVladimir Kondratyev * 1. Redistributions of source code must retain the above copyright 127f32f0e2SVladimir Kondratyev * notice, this list of conditions and the following disclaimer. 137f32f0e2SVladimir Kondratyev * 2. Redistributions in binary form must reproduce the above copyright 147f32f0e2SVladimir Kondratyev * notice, this list of conditions and the following disclaimer in the 157f32f0e2SVladimir Kondratyev * documentation and/or other materials provided with the distribution. 167f32f0e2SVladimir Kondratyev * 177f32f0e2SVladimir Kondratyev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 187f32f0e2SVladimir Kondratyev * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 197f32f0e2SVladimir Kondratyev * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 207f32f0e2SVladimir Kondratyev * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 217f32f0e2SVladimir Kondratyev * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 227f32f0e2SVladimir Kondratyev * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 237f32f0e2SVladimir Kondratyev * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 247f32f0e2SVladimir Kondratyev * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 257f32f0e2SVladimir Kondratyev * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 267f32f0e2SVladimir Kondratyev * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 277f32f0e2SVladimir Kondratyev * SUCH DAMAGE. 287f32f0e2SVladimir Kondratyev */ 297f32f0e2SVladimir Kondratyev 307f32f0e2SVladimir Kondratyev #include <sys/types.h> 317f32f0e2SVladimir Kondratyev #include <sys/endian.h> 327f32f0e2SVladimir Kondratyev #include <sys/stat.h> 337f32f0e2SVladimir Kondratyev 347f32f0e2SVladimir Kondratyev #include <err.h> 357f32f0e2SVladimir Kondratyev #include <errno.h> 367f32f0e2SVladimir Kondratyev #include <fcntl.h> 377f32f0e2SVladimir Kondratyev #include <stdio.h> 387f32f0e2SVladimir Kondratyev #include <stdlib.h> 397f32f0e2SVladimir Kondratyev #include <string.h> 407f32f0e2SVladimir Kondratyev #include <unistd.h> 417f32f0e2SVladimir Kondratyev 427f32f0e2SVladimir Kondratyev #include "iwmbt_fw.h" 437f32f0e2SVladimir Kondratyev #include "iwmbt_dbg.h" 447f32f0e2SVladimir Kondratyev 457f32f0e2SVladimir Kondratyev int 467f32f0e2SVladimir Kondratyev iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname) 477f32f0e2SVladimir Kondratyev { 487f32f0e2SVladimir Kondratyev int fd; 497f32f0e2SVladimir Kondratyev struct stat sb; 507f32f0e2SVladimir Kondratyev unsigned char *buf; 517f32f0e2SVladimir Kondratyev ssize_t r; 527f32f0e2SVladimir Kondratyev 537f32f0e2SVladimir Kondratyev fd = open(fwname, O_RDONLY); 547f32f0e2SVladimir Kondratyev if (fd < 0) { 557f32f0e2SVladimir Kondratyev warn("%s: open: %s", __func__, fwname); 567f32f0e2SVladimir Kondratyev return (0); 577f32f0e2SVladimir Kondratyev } 587f32f0e2SVladimir Kondratyev 597f32f0e2SVladimir Kondratyev if (fstat(fd, &sb) != 0) { 607f32f0e2SVladimir Kondratyev warn("%s: stat: %s", __func__, fwname); 617f32f0e2SVladimir Kondratyev close(fd); 627f32f0e2SVladimir Kondratyev return (0); 637f32f0e2SVladimir Kondratyev } 647f32f0e2SVladimir Kondratyev 657f32f0e2SVladimir Kondratyev buf = calloc(1, sb.st_size); 667f32f0e2SVladimir Kondratyev if (buf == NULL) { 677f32f0e2SVladimir Kondratyev warn("%s: calloc", __func__); 687f32f0e2SVladimir Kondratyev close(fd); 697f32f0e2SVladimir Kondratyev return (0); 707f32f0e2SVladimir Kondratyev } 717f32f0e2SVladimir Kondratyev 727f32f0e2SVladimir Kondratyev /* XXX handle partial reads */ 737f32f0e2SVladimir Kondratyev r = read(fd, buf, sb.st_size); 747f32f0e2SVladimir Kondratyev if (r < 0) { 757f32f0e2SVladimir Kondratyev warn("%s: read", __func__); 767f32f0e2SVladimir Kondratyev free(buf); 777f32f0e2SVladimir Kondratyev close(fd); 787f32f0e2SVladimir Kondratyev return (0); 797f32f0e2SVladimir Kondratyev } 807f32f0e2SVladimir Kondratyev 817f32f0e2SVladimir Kondratyev if (r != sb.st_size) { 827f32f0e2SVladimir Kondratyev iwmbt_err("read len %d != file size %d", 837f32f0e2SVladimir Kondratyev (int) r, 847f32f0e2SVladimir Kondratyev (int) sb.st_size); 857f32f0e2SVladimir Kondratyev free(buf); 867f32f0e2SVladimir Kondratyev close(fd); 877f32f0e2SVladimir Kondratyev return (0); 887f32f0e2SVladimir Kondratyev } 897f32f0e2SVladimir Kondratyev 907f32f0e2SVladimir Kondratyev /* We have everything, so! */ 917f32f0e2SVladimir Kondratyev 927f32f0e2SVladimir Kondratyev memset(fw, 0, sizeof(*fw)); 937f32f0e2SVladimir Kondratyev 947f32f0e2SVladimir Kondratyev fw->fwname = strdup(fwname); 957f32f0e2SVladimir Kondratyev fw->len = sb.st_size; 967f32f0e2SVladimir Kondratyev fw->buf = buf; 977f32f0e2SVladimir Kondratyev 987f32f0e2SVladimir Kondratyev close(fd); 997f32f0e2SVladimir Kondratyev return (1); 1007f32f0e2SVladimir Kondratyev } 1017f32f0e2SVladimir Kondratyev 1027f32f0e2SVladimir Kondratyev void 1037f32f0e2SVladimir Kondratyev iwmbt_fw_free(struct iwmbt_firmware *fw) 1047f32f0e2SVladimir Kondratyev { 1057f32f0e2SVladimir Kondratyev if (fw->fwname) 1067f32f0e2SVladimir Kondratyev free(fw->fwname); 1077f32f0e2SVladimir Kondratyev if (fw->buf) 1087f32f0e2SVladimir Kondratyev free(fw->buf); 1097f32f0e2SVladimir Kondratyev memset(fw, 0, sizeof(*fw)); 1107f32f0e2SVladimir Kondratyev } 1117f32f0e2SVladimir Kondratyev 1127f32f0e2SVladimir Kondratyev char * 1137f32f0e2SVladimir Kondratyev iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params, 1147f32f0e2SVladimir Kondratyev const char *prefix, const char *suffix) 1157f32f0e2SVladimir Kondratyev { 116da93a73fSVladimir Kondratyev struct stat sb; 1177f32f0e2SVladimir Kondratyev char *fwname; 1187f32f0e2SVladimir Kondratyev 1197f32f0e2SVladimir Kondratyev switch (ver->hw_variant) { 120fe70d7b2SPhilippe Michaud-Boudreault case 0x07: /* 7260 */ 121da93a73fSVladimir Kondratyev case 0x08: /* 7265 */ 122*06969db3SEygene Ryabinkin // NB: don't use params, they are NULL for 7xxx 123fe70d7b2SPhilippe Michaud-Boudreault asprintf(&fwname, "%s/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.%s", 124fe70d7b2SPhilippe Michaud-Boudreault prefix, 125fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->hw_platform), 126fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->hw_variant), 127fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->hw_revision), 128fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->fw_variant), 129fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->fw_revision), 130fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->fw_build_num), 131fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->fw_build_ww), 132fe70d7b2SPhilippe Michaud-Boudreault le16toh(ver->fw_build_yy), 133fe70d7b2SPhilippe Michaud-Boudreault suffix); 134da93a73fSVladimir Kondratyev /* 135da93a73fSVladimir Kondratyev * Fallback to the default firmware patch if 136da93a73fSVladimir Kondratyev * the correct firmware patch file is not found. 137da93a73fSVladimir Kondratyev */ 138da93a73fSVladimir Kondratyev if (stat(fwname, &sb) != 0 && errno == ENOENT) { 139da93a73fSVladimir Kondratyev free(fwname); 140da93a73fSVladimir Kondratyev asprintf(&fwname, "%s/ibt-hw-%x.%x.%s", 141da93a73fSVladimir Kondratyev prefix, 142da93a73fSVladimir Kondratyev le16toh(ver->hw_platform), 143da93a73fSVladimir Kondratyev le16toh(ver->hw_variant), 144da93a73fSVladimir Kondratyev suffix); 145da93a73fSVladimir Kondratyev } 146fe70d7b2SPhilippe Michaud-Boudreault break; 147fe70d7b2SPhilippe Michaud-Boudreault 1487f32f0e2SVladimir Kondratyev case 0x0b: /* 8260 */ 1497f32f0e2SVladimir Kondratyev case 0x0c: /* 8265 */ 1507f32f0e2SVladimir Kondratyev asprintf(&fwname, "%s/ibt-%u-%u.%s", 1517f32f0e2SVladimir Kondratyev prefix, 1527f32f0e2SVladimir Kondratyev le16toh(ver->hw_variant), 1537f32f0e2SVladimir Kondratyev le16toh(params->dev_revid), 1547f32f0e2SVladimir Kondratyev suffix); 1557f32f0e2SVladimir Kondratyev break; 1567f32f0e2SVladimir Kondratyev 1577f32f0e2SVladimir Kondratyev case 0x11: /* 9560 */ 1587f32f0e2SVladimir Kondratyev case 0x12: /* 9260 */ 1597f32f0e2SVladimir Kondratyev case 0x13: 1607f32f0e2SVladimir Kondratyev case 0x14: /* 22161 */ 1617f32f0e2SVladimir Kondratyev asprintf(&fwname, "%s/ibt-%u-%u-%u.%s", 1627f32f0e2SVladimir Kondratyev prefix, 1637f32f0e2SVladimir Kondratyev le16toh(ver->hw_variant), 1647f32f0e2SVladimir Kondratyev le16toh(ver->hw_revision), 1657f32f0e2SVladimir Kondratyev le16toh(ver->fw_revision), 1667f32f0e2SVladimir Kondratyev suffix); 1677f32f0e2SVladimir Kondratyev break; 1687f32f0e2SVladimir Kondratyev 1697f32f0e2SVladimir Kondratyev default: 1707f32f0e2SVladimir Kondratyev fwname = NULL; 1717f32f0e2SVladimir Kondratyev } 1727f32f0e2SVladimir Kondratyev 1737f32f0e2SVladimir Kondratyev return (fwname); 1747f32f0e2SVladimir Kondratyev } 175c1643cedSVladimir Kondratyev 176c1643cedSVladimir Kondratyev char * 177c1643cedSVladimir Kondratyev iwmbt_get_fwname_tlv(struct iwmbt_version_tlv *ver, const char *prefix, 178c1643cedSVladimir Kondratyev const char *suffix) 179c1643cedSVladimir Kondratyev { 180c1643cedSVladimir Kondratyev char *fwname; 181c1643cedSVladimir Kondratyev 182c1643cedSVladimir Kondratyev #define IWMBT_PACK_CNVX_TOP(cnvx_top) ((uint16_t)( \ 183c1643cedSVladimir Kondratyev ((cnvx_top) & 0x0f000000) >> 16 | \ 184c1643cedSVladimir Kondratyev ((cnvx_top) & 0x0000000f) << 12 | \ 185c1643cedSVladimir Kondratyev ((cnvx_top) & 0x00000ff0) >> 4)) 186c1643cedSVladimir Kondratyev 187c1643cedSVladimir Kondratyev asprintf(&fwname, "%s/ibt-%04x-%04x.%s", 188c1643cedSVladimir Kondratyev prefix, 189c1643cedSVladimir Kondratyev IWMBT_PACK_CNVX_TOP(ver->cnvi_top), 190c1643cedSVladimir Kondratyev IWMBT_PACK_CNVX_TOP(ver->cnvr_top), 191c1643cedSVladimir Kondratyev suffix); 192c1643cedSVladimir Kondratyev 193c1643cedSVladimir Kondratyev return (fwname); 194c1643cedSVladimir Kondratyev } 195