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/param.h> 317f32f0e2SVladimir Kondratyev #include <sys/stat.h> 327f32f0e2SVladimir Kondratyev #include <sys/endian.h> 337f32f0e2SVladimir Kondratyev 347f32f0e2SVladimir Kondratyev #include <err.h> 357f32f0e2SVladimir Kondratyev #include <errno.h> 367f32f0e2SVladimir Kondratyev #include <fcntl.h> 377f32f0e2SVladimir Kondratyev #include <libgen.h> 387f32f0e2SVladimir Kondratyev #include <stdio.h> 397f32f0e2SVladimir Kondratyev #include <stdlib.h> 407f32f0e2SVladimir Kondratyev #include <string.h> 417f32f0e2SVladimir Kondratyev #include <unistd.h> 427f32f0e2SVladimir Kondratyev 437f32f0e2SVladimir Kondratyev #include <libusb.h> 447f32f0e2SVladimir Kondratyev 457f32f0e2SVladimir Kondratyev #include "iwmbt_fw.h" 467f32f0e2SVladimir Kondratyev #include "iwmbt_hw.h" 477f32f0e2SVladimir Kondratyev #include "iwmbt_dbg.h" 487f32f0e2SVladimir Kondratyev 497f32f0e2SVladimir Kondratyev #define _DEFAULT_IWMBT_FIRMWARE_PATH "/usr/share/firmware/intel" 507f32f0e2SVladimir Kondratyev 517f32f0e2SVladimir Kondratyev int iwmbt_do_debug = 0; 527f32f0e2SVladimir Kondratyev int iwmbt_do_info = 0; 537f32f0e2SVladimir Kondratyev 54c1643cedSVladimir Kondratyev enum iwmbt_device { 55c1643cedSVladimir Kondratyev IWMBT_DEVICE_UNKNOWN, 56c1643cedSVladimir Kondratyev IWMBT_DEVICE_7260, 57c1643cedSVladimir Kondratyev IWMBT_DEVICE_8260, 58c1643cedSVladimir Kondratyev IWMBT_DEVICE_9260, 59c1643cedSVladimir Kondratyev }; 60c1643cedSVladimir Kondratyev 617f32f0e2SVladimir Kondratyev struct iwmbt_devid { 627f32f0e2SVladimir Kondratyev uint16_t product_id; 637f32f0e2SVladimir Kondratyev uint16_t vendor_id; 64c1643cedSVladimir Kondratyev enum iwmbt_device device; 657f32f0e2SVladimir Kondratyev }; 667f32f0e2SVladimir Kondratyev 67c1643cedSVladimir Kondratyev static struct iwmbt_devid iwmbt_list[] = { 68fe70d7b2SPhilippe Michaud-Boudreault 69fe70d7b2SPhilippe Michaud-Boudreault /* Intel Wireless 7260/7265 and successors */ 70c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x07dc, .device = IWMBT_DEVICE_7260 }, 71c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0a2a, .device = IWMBT_DEVICE_7260 }, 72c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0aa7, .device = IWMBT_DEVICE_7260 }, 737f32f0e2SVladimir Kondratyev 747f32f0e2SVladimir Kondratyev /* Intel Wireless 8260/8265 and successors */ 75c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0a2b, .device = IWMBT_DEVICE_8260 }, 76c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0aaa, .device = IWMBT_DEVICE_8260 }, 77c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0025, .device = IWMBT_DEVICE_8260 }, 78c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0026, .device = IWMBT_DEVICE_8260 }, 79c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0029, .device = IWMBT_DEVICE_8260 }, 80c1643cedSVladimir Kondratyev 81c1643cedSVladimir Kondratyev /* Intel Wireless 9260/9560 and successors */ 82c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0032, .device = IWMBT_DEVICE_9260 }, 83c1643cedSVladimir Kondratyev { .vendor_id = 0x8087, .product_id = 0x0033, .device = IWMBT_DEVICE_9260 }, 847f32f0e2SVladimir Kondratyev }; 857f32f0e2SVladimir Kondratyev 86c1643cedSVladimir Kondratyev static enum iwmbt_device 87c1643cedSVladimir Kondratyev iwmbt_is_supported(struct libusb_device_descriptor *d) 88fe70d7b2SPhilippe Michaud-Boudreault { 89fe70d7b2SPhilippe Michaud-Boudreault int i; 90fe70d7b2SPhilippe Michaud-Boudreault 91fe70d7b2SPhilippe Michaud-Boudreault /* Search looking for whether it's an 7260/7265 */ 92c1643cedSVladimir Kondratyev for (i = 0; i < (int) nitems(iwmbt_list); i++) { 93c1643cedSVladimir Kondratyev if ((iwmbt_list[i].product_id == d->idProduct) && 94c1643cedSVladimir Kondratyev (iwmbt_list[i].vendor_id == d->idVendor)) { 95c1643cedSVladimir Kondratyev iwmbt_info("found iwmbtfw compatible"); 96c1643cedSVladimir Kondratyev return (iwmbt_list[i].device); 97fe70d7b2SPhilippe Michaud-Boudreault } 98fe70d7b2SPhilippe Michaud-Boudreault } 99fe70d7b2SPhilippe Michaud-Boudreault 100fe70d7b2SPhilippe Michaud-Boudreault /* Not found */ 101c1643cedSVladimir Kondratyev return (IWMBT_DEVICE_UNKNOWN); 1027f32f0e2SVladimir Kondratyev } 1037f32f0e2SVladimir Kondratyev 1047f32f0e2SVladimir Kondratyev static libusb_device * 105fe70d7b2SPhilippe Michaud-Boudreault iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id, 106c1643cedSVladimir Kondratyev enum iwmbt_device *iwmbt_device) 1077f32f0e2SVladimir Kondratyev { 1087f32f0e2SVladimir Kondratyev libusb_device **list, *dev = NULL, *found = NULL; 1097f32f0e2SVladimir Kondratyev struct libusb_device_descriptor d; 110c1643cedSVladimir Kondratyev enum iwmbt_device device; 1117f32f0e2SVladimir Kondratyev ssize_t cnt, i; 1127f32f0e2SVladimir Kondratyev int r; 1137f32f0e2SVladimir Kondratyev 1147f32f0e2SVladimir Kondratyev cnt = libusb_get_device_list(ctx, &list); 1157f32f0e2SVladimir Kondratyev if (cnt < 0) { 1167f32f0e2SVladimir Kondratyev iwmbt_err("libusb_get_device_list() failed: code %lld", 1177f32f0e2SVladimir Kondratyev (long long int) cnt); 1187f32f0e2SVladimir Kondratyev return (NULL); 1197f32f0e2SVladimir Kondratyev } 1207f32f0e2SVladimir Kondratyev 1217f32f0e2SVladimir Kondratyev /* 1227f32f0e2SVladimir Kondratyev * Scan through USB device list. 1237f32f0e2SVladimir Kondratyev */ 1247f32f0e2SVladimir Kondratyev for (i = 0; i < cnt; i++) { 1257f32f0e2SVladimir Kondratyev dev = list[i]; 1267f32f0e2SVladimir Kondratyev if (bus_id == libusb_get_bus_number(dev) && 1277f32f0e2SVladimir Kondratyev dev_id == libusb_get_device_address(dev)) { 1287f32f0e2SVladimir Kondratyev /* Get the device descriptor for this device entry */ 1297f32f0e2SVladimir Kondratyev r = libusb_get_device_descriptor(dev, &d); 1307f32f0e2SVladimir Kondratyev if (r != 0) { 1317f32f0e2SVladimir Kondratyev iwmbt_err("libusb_get_device_descriptor: %s", 1327f32f0e2SVladimir Kondratyev libusb_strerror(r)); 1337f32f0e2SVladimir Kondratyev break; 1347f32f0e2SVladimir Kondratyev } 1357f32f0e2SVladimir Kondratyev 1367f32f0e2SVladimir Kondratyev /* Match on the vendor/product id */ 137c1643cedSVladimir Kondratyev device = iwmbt_is_supported(&d); 138c1643cedSVladimir Kondratyev if (device != IWMBT_DEVICE_UNKNOWN) { 139fe70d7b2SPhilippe Michaud-Boudreault /* 140fe70d7b2SPhilippe Michaud-Boudreault * Take a reference so it's not freed later on. 141fe70d7b2SPhilippe Michaud-Boudreault */ 142fe70d7b2SPhilippe Michaud-Boudreault found = libusb_ref_device(dev); 143c1643cedSVladimir Kondratyev *iwmbt_device = device; 1447f32f0e2SVladimir Kondratyev break; 1457f32f0e2SVladimir Kondratyev } 1467f32f0e2SVladimir Kondratyev } 1477f32f0e2SVladimir Kondratyev } 1487f32f0e2SVladimir Kondratyev 1497f32f0e2SVladimir Kondratyev libusb_free_device_list(list, 1); 1507f32f0e2SVladimir Kondratyev return (found); 1517f32f0e2SVladimir Kondratyev } 1527f32f0e2SVladimir Kondratyev 1537f32f0e2SVladimir Kondratyev static void 1547f32f0e2SVladimir Kondratyev iwmbt_dump_version(struct iwmbt_version *ver) 1557f32f0e2SVladimir Kondratyev { 1567f32f0e2SVladimir Kondratyev iwmbt_info("status 0x%02x", ver->status); 1577f32f0e2SVladimir Kondratyev iwmbt_info("hw_platform 0x%02x", ver->hw_platform); 1587f32f0e2SVladimir Kondratyev iwmbt_info("hw_variant 0x%02x", ver->hw_variant); 1597f32f0e2SVladimir Kondratyev iwmbt_info("hw_revision 0x%02x", ver->hw_revision); 1607f32f0e2SVladimir Kondratyev iwmbt_info("fw_variant 0x%02x", ver->fw_variant); 1617f32f0e2SVladimir Kondratyev iwmbt_info("fw_revision 0x%02x", ver->fw_revision); 1627f32f0e2SVladimir Kondratyev iwmbt_info("fw_build_num 0x%02x", ver->fw_build_num); 1637f32f0e2SVladimir Kondratyev iwmbt_info("fw_build_ww 0x%02x", ver->fw_build_ww); 1647f32f0e2SVladimir Kondratyev iwmbt_info("fw_build_yy 0x%02x", ver->fw_build_yy); 1657f32f0e2SVladimir Kondratyev iwmbt_info("fw_patch_num 0x%02x", ver->fw_patch_num); 1667f32f0e2SVladimir Kondratyev } 1677f32f0e2SVladimir Kondratyev 1687f32f0e2SVladimir Kondratyev static void 1697f32f0e2SVladimir Kondratyev iwmbt_dump_boot_params(struct iwmbt_boot_params *params) 1707f32f0e2SVladimir Kondratyev { 1717f32f0e2SVladimir Kondratyev iwmbt_info("Device revision: %u", le16toh(params->dev_revid)); 1727f32f0e2SVladimir Kondratyev iwmbt_info("Secure Boot: %s", params->secure_boot ? "on" : "off"); 1737f32f0e2SVladimir Kondratyev iwmbt_info("OTP lock: %s", params->otp_lock ? "on" : "off"); 1747f32f0e2SVladimir Kondratyev iwmbt_info("API lock: %s", params->api_lock ? "on" : "off"); 1757f32f0e2SVladimir Kondratyev iwmbt_info("Debug lock: %s", params->debug_lock ? "on" : "off"); 1767f32f0e2SVladimir Kondratyev iwmbt_info("Minimum firmware build %u week %u year %u", 1777f32f0e2SVladimir Kondratyev params->min_fw_build_nn, 1787f32f0e2SVladimir Kondratyev params->min_fw_build_cw, 1797f32f0e2SVladimir Kondratyev 2000 + params->min_fw_build_yy); 1807f32f0e2SVladimir Kondratyev iwmbt_info("OTC BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x", 1817f32f0e2SVladimir Kondratyev params->otp_bdaddr[5], 1827f32f0e2SVladimir Kondratyev params->otp_bdaddr[4], 1837f32f0e2SVladimir Kondratyev params->otp_bdaddr[3], 1847f32f0e2SVladimir Kondratyev params->otp_bdaddr[2], 1857f32f0e2SVladimir Kondratyev params->otp_bdaddr[1], 1867f32f0e2SVladimir Kondratyev params->otp_bdaddr[0]); 1877f32f0e2SVladimir Kondratyev } 1887f32f0e2SVladimir Kondratyev 189c1643cedSVladimir Kondratyev static void 190c1643cedSVladimir Kondratyev iwmbt_dump_version_tlv(struct iwmbt_version_tlv *ver) 191c1643cedSVladimir Kondratyev { 192c1643cedSVladimir Kondratyev iwmbt_info("cnvi_top 0x%08x", ver->cnvi_top); 193c1643cedSVladimir Kondratyev iwmbt_info("cnvr_top 0x%08x", ver->cnvr_top); 194c1643cedSVladimir Kondratyev iwmbt_info("cnvi_bt 0x%08x", ver->cnvi_bt); 195c1643cedSVladimir Kondratyev iwmbt_info("cnvr_bt 0x%08x", ver->cnvr_bt); 196c1643cedSVladimir Kondratyev iwmbt_info("dev_rev_id 0x%04x", ver->dev_rev_id); 197c1643cedSVladimir Kondratyev iwmbt_info("img_type 0x%02x", ver->img_type); 198c1643cedSVladimir Kondratyev iwmbt_info("timestamp 0x%04x", ver->timestamp); 199c1643cedSVladimir Kondratyev iwmbt_info("build_type 0x%02x", ver->build_type); 200c1643cedSVladimir Kondratyev iwmbt_info("build_num 0x%08x", ver->build_num); 201c1643cedSVladimir Kondratyev iwmbt_info("Secure Boot: %s", ver->secure_boot ? "on" : "off"); 202c1643cedSVladimir Kondratyev iwmbt_info("OTP lock: %s", ver->otp_lock ? "on" : "off"); 203c1643cedSVladimir Kondratyev iwmbt_info("API lock: %s", ver->api_lock ? "on" : "off"); 204c1643cedSVladimir Kondratyev iwmbt_info("Debug lock: %s", ver->debug_lock ? "on" : "off"); 205c1643cedSVladimir Kondratyev iwmbt_info("Minimum firmware build %u week %u year %u", 206c1643cedSVladimir Kondratyev ver->min_fw_build_nn, 207c1643cedSVladimir Kondratyev ver->min_fw_build_cw, 208c1643cedSVladimir Kondratyev 2000 + ver->min_fw_build_yy); 209c1643cedSVladimir Kondratyev iwmbt_info("limited_cce 0x%02x", ver->limited_cce); 210c1643cedSVladimir Kondratyev iwmbt_info("sbe_type 0x%02x", ver->sbe_type); 211c1643cedSVladimir Kondratyev iwmbt_info("OTC BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x", 212c1643cedSVladimir Kondratyev ver->otp_bd_addr.b[5], 213c1643cedSVladimir Kondratyev ver->otp_bd_addr.b[4], 214c1643cedSVladimir Kondratyev ver->otp_bd_addr.b[3], 215c1643cedSVladimir Kondratyev ver->otp_bd_addr.b[2], 216c1643cedSVladimir Kondratyev ver->otp_bd_addr.b[1], 217c1643cedSVladimir Kondratyev ver->otp_bd_addr.b[0]); 21806969db3SEygene Ryabinkin if (ver->img_type == TLV_IMG_TYPE_BOOTLOADER || 21906969db3SEygene Ryabinkin ver->img_type == TLV_IMG_TYPE_OPERATIONAL) 220c1643cedSVladimir Kondratyev iwmbt_info("%s timestamp %u.%u buildtype %u build %u", 22106969db3SEygene Ryabinkin (ver->img_type == TLV_IMG_TYPE_BOOTLOADER ? 22206969db3SEygene Ryabinkin "Bootloader" : "Firmware"), 223c1643cedSVladimir Kondratyev 2000 + (ver->timestamp >> 8), 224c1643cedSVladimir Kondratyev ver->timestamp & 0xff, 225c1643cedSVladimir Kondratyev ver->build_type, 226c1643cedSVladimir Kondratyev ver->build_num); 227c1643cedSVladimir Kondratyev } 228c1643cedSVladimir Kondratyev 229fe70d7b2SPhilippe Michaud-Boudreault 230fe70d7b2SPhilippe Michaud-Boudreault static int 2317f32f0e2SVladimir Kondratyev iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path, 232c1643cedSVladimir Kondratyev uint32_t *boot_param, uint8_t hw_variant, uint8_t sbe_type) 2337f32f0e2SVladimir Kondratyev { 2347f32f0e2SVladimir Kondratyev struct iwmbt_firmware fw; 235c1643cedSVladimir Kondratyev int header_len, ret = -1; 2367f32f0e2SVladimir Kondratyev 2377f32f0e2SVladimir Kondratyev iwmbt_debug("loading %s", firmware_path); 2387f32f0e2SVladimir Kondratyev 2397f32f0e2SVladimir Kondratyev /* Read in the firmware */ 2407f32f0e2SVladimir Kondratyev if (iwmbt_fw_read(&fw, firmware_path) <= 0) { 2417f32f0e2SVladimir Kondratyev iwmbt_debug("iwmbt_fw_read() failed"); 2427f32f0e2SVladimir Kondratyev return (-1); 2437f32f0e2SVladimir Kondratyev } 2447f32f0e2SVladimir Kondratyev 245c1643cedSVladimir Kondratyev iwmbt_debug("Firmware file size=%d", fw.len); 2467f32f0e2SVladimir Kondratyev 247c1643cedSVladimir Kondratyev if (hw_variant <= 0x14) { 248c1643cedSVladimir Kondratyev /* 249c1643cedSVladimir Kondratyev * Hardware variants 0x0b, 0x0c, 0x11 - 0x14 .sfi file have 250c1643cedSVladimir Kondratyev * a RSA header of 644 bytes followed by Command Buffer. 251c1643cedSVladimir Kondratyev */ 252c1643cedSVladimir Kondratyev header_len = RSA_HEADER_LEN; 253c1643cedSVladimir Kondratyev if (fw.len < header_len) { 254c1643cedSVladimir Kondratyev iwmbt_err("Invalid size of firmware file (%d)", fw.len); 255c1643cedSVladimir Kondratyev ret = -1; 256c1643cedSVladimir Kondratyev goto exit; 257c1643cedSVladimir Kondratyev } 258c1643cedSVladimir Kondratyev 259c1643cedSVladimir Kondratyev /* Check if the CSS Header version is RSA(0x00010000) */ 260c1643cedSVladimir Kondratyev if (le32dec(fw.buf + CSS_HEADER_OFFSET) != 0x00010000) { 261c1643cedSVladimir Kondratyev iwmbt_err("Invalid CSS Header version"); 262c1643cedSVladimir Kondratyev ret = -1; 263c1643cedSVladimir Kondratyev goto exit; 264c1643cedSVladimir Kondratyev } 265c1643cedSVladimir Kondratyev 266c1643cedSVladimir Kondratyev /* Only RSA secure boot engine supported */ 267c1643cedSVladimir Kondratyev if (sbe_type != 0x00) { 268c1643cedSVladimir Kondratyev iwmbt_err("Invalid SBE type for hardware variant (%d)", 269c1643cedSVladimir Kondratyev hw_variant); 270c1643cedSVladimir Kondratyev ret = -1; 271c1643cedSVladimir Kondratyev goto exit; 272c1643cedSVladimir Kondratyev } 273c1643cedSVladimir Kondratyev 274c1643cedSVladimir Kondratyev } else if (hw_variant >= 0x17) { 275c1643cedSVladimir Kondratyev /* 276c1643cedSVladimir Kondratyev * Hardware variants 0x17, 0x18 onwards support both RSA and 277c1643cedSVladimir Kondratyev * ECDSA secure boot engine. As a result, the corresponding sfi 278c1643cedSVladimir Kondratyev * file will have RSA header of 644, ECDSA header of 320 bytes 279c1643cedSVladimir Kondratyev * followed by Command Buffer. 280c1643cedSVladimir Kondratyev */ 281c1643cedSVladimir Kondratyev header_len = ECDSA_OFFSET + ECDSA_HEADER_LEN; 282c1643cedSVladimir Kondratyev if (fw.len < header_len) { 283c1643cedSVladimir Kondratyev iwmbt_err("Invalid size of firmware file (%d)", fw.len); 284c1643cedSVladimir Kondratyev ret = -1; 285c1643cedSVladimir Kondratyev goto exit; 286c1643cedSVladimir Kondratyev } 287c1643cedSVladimir Kondratyev 288c1643cedSVladimir Kondratyev /* Check if CSS header for ECDSA follows the RSA header */ 289c1643cedSVladimir Kondratyev if (fw.buf[ECDSA_OFFSET] != 0x06) { 290c1643cedSVladimir Kondratyev ret = -1; 291c1643cedSVladimir Kondratyev goto exit; 292c1643cedSVladimir Kondratyev } 293c1643cedSVladimir Kondratyev 294c1643cedSVladimir Kondratyev /* Check if the CSS Header version is ECDSA(0x00020000) */ 295c1643cedSVladimir Kondratyev if (le32dec(fw.buf + ECDSA_OFFSET + CSS_HEADER_OFFSET) != 0x00020000) { 296c1643cedSVladimir Kondratyev iwmbt_err("Invalid CSS Header version"); 297c1643cedSVladimir Kondratyev ret = -1; 298c1643cedSVladimir Kondratyev goto exit; 299c1643cedSVladimir Kondratyev } 300c1643cedSVladimir Kondratyev } 301c1643cedSVladimir Kondratyev 302c1643cedSVladimir Kondratyev /* Load in the CSS header */ 303c1643cedSVladimir Kondratyev if (sbe_type == 0x00) 304c1643cedSVladimir Kondratyev ret = iwmbt_load_rsa_header(hdl, &fw); 305c1643cedSVladimir Kondratyev else if (sbe_type == 0x01) 306c1643cedSVladimir Kondratyev ret = iwmbt_load_ecdsa_header(hdl, &fw); 307c1643cedSVladimir Kondratyev if (ret < 0) 308c1643cedSVladimir Kondratyev goto exit; 309c1643cedSVladimir Kondratyev 310c1643cedSVladimir Kondratyev /* Load in the Command Buffer */ 311c1643cedSVladimir Kondratyev ret = iwmbt_load_fwfile(hdl, &fw, boot_param, header_len); 312c1643cedSVladimir Kondratyev 313c1643cedSVladimir Kondratyev exit: 314c1643cedSVladimir Kondratyev /* free firmware */ 3157f32f0e2SVladimir Kondratyev iwmbt_fw_free(&fw); 3167f32f0e2SVladimir Kondratyev 3177f32f0e2SVladimir Kondratyev return (ret); 3187f32f0e2SVladimir Kondratyev } 3197f32f0e2SVladimir Kondratyev 3207f32f0e2SVladimir Kondratyev static int 3217f32f0e2SVladimir Kondratyev iwmbt_init_ddc(libusb_device_handle *hdl, const char *ddc_path) 3227f32f0e2SVladimir Kondratyev { 3237f32f0e2SVladimir Kondratyev struct iwmbt_firmware ddc; 3247f32f0e2SVladimir Kondratyev int ret; 3257f32f0e2SVladimir Kondratyev 3267f32f0e2SVladimir Kondratyev iwmbt_debug("loading %s", ddc_path); 3277f32f0e2SVladimir Kondratyev 3287f32f0e2SVladimir Kondratyev /* Read in the DDC file */ 3297f32f0e2SVladimir Kondratyev if (iwmbt_fw_read(&ddc, ddc_path) <= 0) { 3307f32f0e2SVladimir Kondratyev iwmbt_debug("iwmbt_fw_read() failed"); 3317f32f0e2SVladimir Kondratyev return (-1); 3327f32f0e2SVladimir Kondratyev } 3337f32f0e2SVladimir Kondratyev 3347f32f0e2SVladimir Kondratyev /* Load in the DDC file */ 3357f32f0e2SVladimir Kondratyev ret = iwmbt_load_ddc(hdl, &ddc); 3367f32f0e2SVladimir Kondratyev if (ret < 0) 3377f32f0e2SVladimir Kondratyev iwmbt_debug("Loading DDC file failed"); 3387f32f0e2SVladimir Kondratyev 3397f32f0e2SVladimir Kondratyev /* free it */ 3407f32f0e2SVladimir Kondratyev iwmbt_fw_free(&ddc); 3417f32f0e2SVladimir Kondratyev 3427f32f0e2SVladimir Kondratyev return (ret); 3437f32f0e2SVladimir Kondratyev } 3447f32f0e2SVladimir Kondratyev 3457f32f0e2SVladimir Kondratyev /* 3467f32f0e2SVladimir Kondratyev * Parse ugen name and extract device's bus and address 3477f32f0e2SVladimir Kondratyev */ 3487f32f0e2SVladimir Kondratyev 3497f32f0e2SVladimir Kondratyev static int 3507f32f0e2SVladimir Kondratyev parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr) 3517f32f0e2SVladimir Kondratyev { 3527f32f0e2SVladimir Kondratyev char *ep; 3537f32f0e2SVladimir Kondratyev 3547f32f0e2SVladimir Kondratyev if (strncmp(ugen, "ugen", 4) != 0) 3557f32f0e2SVladimir Kondratyev return (-1); 3567f32f0e2SVladimir Kondratyev 3577f32f0e2SVladimir Kondratyev *bus = (uint8_t) strtoul(ugen + 4, &ep, 10); 3587f32f0e2SVladimir Kondratyev if (*ep != '.') 3597f32f0e2SVladimir Kondratyev return (-1); 3607f32f0e2SVladimir Kondratyev 3617f32f0e2SVladimir Kondratyev *addr = (uint8_t) strtoul(ep + 1, &ep, 10); 3627f32f0e2SVladimir Kondratyev if (*ep != '\0') 3637f32f0e2SVladimir Kondratyev return (-1); 3647f32f0e2SVladimir Kondratyev 3657f32f0e2SVladimir Kondratyev return (0); 3667f32f0e2SVladimir Kondratyev } 3677f32f0e2SVladimir Kondratyev 3687f32f0e2SVladimir Kondratyev static void 3697f32f0e2SVladimir Kondratyev usage(void) 3707f32f0e2SVladimir Kondratyev { 3717f32f0e2SVladimir Kondratyev fprintf(stderr, 372*0feaf865SEygene Ryabinkin "Usage: iwmbtfw [-DI] -d ugenX.Y [-f firmware path]\n"); 3737f32f0e2SVladimir Kondratyev fprintf(stderr, " -D: enable debugging\n"); 3747f32f0e2SVladimir Kondratyev fprintf(stderr, " -d: device to operate upon\n"); 375*0feaf865SEygene Ryabinkin fprintf(stderr, " -f: firmware path (defaults to %s)\n", 376*0feaf865SEygene Ryabinkin _DEFAULT_IWMBT_FIRMWARE_PATH); 3777f32f0e2SVladimir Kondratyev fprintf(stderr, " -I: enable informational output\n"); 3787f32f0e2SVladimir Kondratyev exit(127); 3797f32f0e2SVladimir Kondratyev } 3807f32f0e2SVladimir Kondratyev 38106969db3SEygene Ryabinkin 382ff411631SEygene Ryabinkin 38306969db3SEygene Ryabinkin /* 38406969db3SEygene Ryabinkin * Returns 0 on success. 38506969db3SEygene Ryabinkin */ 38606969db3SEygene Ryabinkin static int 38706969db3SEygene Ryabinkin handle_7260(libusb_device_handle *hdl, char *firmware_dir) 38806969db3SEygene Ryabinkin { 38906969db3SEygene Ryabinkin int r; 390ff411631SEygene Ryabinkin char *firmware_path; 39106969db3SEygene Ryabinkin struct iwmbt_version ver; 392ff411631SEygene Ryabinkin struct iwmbt_firmware fw; 39306969db3SEygene Ryabinkin 39406969db3SEygene Ryabinkin r = iwmbt_get_version(hdl, &ver); 39506969db3SEygene Ryabinkin if (r < 0) { 39606969db3SEygene Ryabinkin iwmbt_debug("iwmbt_get_version() failed code %d", r); 39706969db3SEygene Ryabinkin return 1; 39806969db3SEygene Ryabinkin } 39906969db3SEygene Ryabinkin iwmbt_dump_version(&ver); 40006969db3SEygene Ryabinkin iwmbt_debug("fw_patch_num=0x%02x", (int) ver.fw_patch_num); 40106969db3SEygene Ryabinkin 40206969db3SEygene Ryabinkin /* fw_patch_num = >0 operational mode */ 40306969db3SEygene Ryabinkin if (ver.fw_patch_num > 0x00) { 40406969db3SEygene Ryabinkin iwmbt_info("Firmware has already been downloaded"); 40506969db3SEygene Ryabinkin return 0; 40606969db3SEygene Ryabinkin } 40706969db3SEygene Ryabinkin 40806969db3SEygene Ryabinkin firmware_path = iwmbt_get_fwname(&ver, NULL, firmware_dir, "bseq"); 40906969db3SEygene Ryabinkin if (firmware_path == NULL) 41006969db3SEygene Ryabinkin return 1; 41106969db3SEygene Ryabinkin iwmbt_debug("firmware_path = %s", firmware_path); 41206969db3SEygene Ryabinkin 413ff411631SEygene Ryabinkin r = iwmbt_fw_read(&fw, firmware_path); 414ff411631SEygene Ryabinkin free(firmware_path); 415ff411631SEygene Ryabinkin if (r <= 0) { 416ff411631SEygene Ryabinkin iwmbt_debug("iwmbt_fw_read() failed"); 417ff411631SEygene Ryabinkin return 1; 418ff411631SEygene Ryabinkin } 419ff411631SEygene Ryabinkin 42006969db3SEygene Ryabinkin r = iwmbt_enter_manufacturer(hdl); 42106969db3SEygene Ryabinkin if (r < 0) { 42206969db3SEygene Ryabinkin iwmbt_debug("iwmbt_enter_manufacturer() failed code %d", r); 423ff411631SEygene Ryabinkin iwmbt_fw_free(&fw); 42406969db3SEygene Ryabinkin return 1; 42506969db3SEygene Ryabinkin } 42606969db3SEygene Ryabinkin 42706969db3SEygene Ryabinkin /* Download firmware */ 428ff411631SEygene Ryabinkin r = iwmbt_patch_fwfile(hdl, &fw); 429ff411631SEygene Ryabinkin iwmbt_fw_free(&fw); 43006969db3SEygene Ryabinkin if (r < 0) { 431ff411631SEygene Ryabinkin iwmbt_debug("Loading firmware file failed"); 43206969db3SEygene Ryabinkin (void)iwmbt_exit_manufacturer(hdl, IWMBT_MM_EXIT_COLD_RESET); 43306969db3SEygene Ryabinkin return 1; 43406969db3SEygene Ryabinkin } 43506969db3SEygene Ryabinkin 43606969db3SEygene Ryabinkin iwmbt_info("Firmware download complete"); 43706969db3SEygene Ryabinkin 43806969db3SEygene Ryabinkin r = iwmbt_exit_manufacturer(hdl, 43906969db3SEygene Ryabinkin (r == 0 ? IWMBT_MM_EXIT_ONLY : IWMBT_MM_EXIT_WARM_RESET)); 44006969db3SEygene Ryabinkin if (r < 0) { 44106969db3SEygene Ryabinkin iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", r); 44206969db3SEygene Ryabinkin return 1; 44306969db3SEygene Ryabinkin } 44406969db3SEygene Ryabinkin 44506969db3SEygene Ryabinkin /* Once device is running in operational mode we can ignore failures */ 44606969db3SEygene Ryabinkin 44706969db3SEygene Ryabinkin /* Dump actual controller version */ 44806969db3SEygene Ryabinkin r = iwmbt_get_version(hdl, &ver); 44906969db3SEygene Ryabinkin if (r == 0) 45006969db3SEygene Ryabinkin iwmbt_dump_version(&ver); 45106969db3SEygene Ryabinkin 45206969db3SEygene Ryabinkin if (iwmbt_enter_manufacturer(hdl) < 0) 45306969db3SEygene Ryabinkin return 0; 45406969db3SEygene Ryabinkin r = iwmbt_set_event_mask(hdl); 45506969db3SEygene Ryabinkin if (r == 0) 45606969db3SEygene Ryabinkin iwmbt_info("Intel Event Mask is set"); 45706969db3SEygene Ryabinkin (void)iwmbt_exit_manufacturer(hdl, IWMBT_MM_EXIT_ONLY); 45806969db3SEygene Ryabinkin 45906969db3SEygene Ryabinkin return 0; 46006969db3SEygene Ryabinkin } 46106969db3SEygene Ryabinkin 46206969db3SEygene Ryabinkin 46306969db3SEygene Ryabinkin /* 46406969db3SEygene Ryabinkin * Returns 0 on success. 46506969db3SEygene Ryabinkin */ 46606969db3SEygene Ryabinkin static int 46706969db3SEygene Ryabinkin handle_8260(libusb_device_handle *hdl, char *firmware_dir) 46806969db3SEygene Ryabinkin { 46906969db3SEygene Ryabinkin int r; 47006969db3SEygene Ryabinkin uint32_t boot_param; 47106969db3SEygene Ryabinkin struct iwmbt_version ver; 47206969db3SEygene Ryabinkin struct iwmbt_boot_params params; 47306969db3SEygene Ryabinkin char *firmware_path = NULL; 47406969db3SEygene Ryabinkin 47506969db3SEygene Ryabinkin r = iwmbt_get_version(hdl, &ver); 47606969db3SEygene Ryabinkin if (r < 0) { 47706969db3SEygene Ryabinkin iwmbt_debug("iwmbt_get_version() failed code %d", r); 47806969db3SEygene Ryabinkin return 1; 47906969db3SEygene Ryabinkin } 48006969db3SEygene Ryabinkin iwmbt_dump_version(&ver); 48106969db3SEygene Ryabinkin iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant); 48206969db3SEygene Ryabinkin 48306969db3SEygene Ryabinkin if (ver.fw_variant == FW_VARIANT_OPERATIONAL) { 48406969db3SEygene Ryabinkin iwmbt_info("Firmware has already been downloaded"); 48506969db3SEygene Ryabinkin return 0; 48606969db3SEygene Ryabinkin } 48706969db3SEygene Ryabinkin 48806969db3SEygene Ryabinkin if (ver.fw_variant != FW_VARIANT_BOOTLOADER){ 48906969db3SEygene Ryabinkin iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant); 49006969db3SEygene Ryabinkin return 1; 49106969db3SEygene Ryabinkin } 49206969db3SEygene Ryabinkin 49306969db3SEygene Ryabinkin /* Read Intel Secure Boot Params */ 49406969db3SEygene Ryabinkin r = iwmbt_get_boot_params(hdl, ¶ms); 49506969db3SEygene Ryabinkin if (r < 0) { 49606969db3SEygene Ryabinkin iwmbt_debug("iwmbt_get_boot_params() failed!"); 49706969db3SEygene Ryabinkin return 1; 49806969db3SEygene Ryabinkin } 49906969db3SEygene Ryabinkin iwmbt_dump_boot_params(¶ms); 50006969db3SEygene Ryabinkin 50106969db3SEygene Ryabinkin /* Check if firmware fragments are ACKed with a cmd complete event */ 50206969db3SEygene Ryabinkin if (params.limited_cce != 0x00) { 50306969db3SEygene Ryabinkin iwmbt_err("Unsupported Intel firmware loading method (%u)", 50406969db3SEygene Ryabinkin params.limited_cce); 50506969db3SEygene Ryabinkin return 1; 50606969db3SEygene Ryabinkin } 50706969db3SEygene Ryabinkin 50806969db3SEygene Ryabinkin firmware_path = iwmbt_get_fwname(&ver, ¶ms, firmware_dir, "sfi"); 50906969db3SEygene Ryabinkin if (firmware_path == NULL) 51006969db3SEygene Ryabinkin return 1; 51106969db3SEygene Ryabinkin iwmbt_debug("firmware_path = %s", firmware_path); 51206969db3SEygene Ryabinkin 51306969db3SEygene Ryabinkin /* Download firmware and parse it for magic Intel Reset parameter */ 51406969db3SEygene Ryabinkin r = iwmbt_init_firmware(hdl, firmware_path, &boot_param, 0, 0); 51506969db3SEygene Ryabinkin free(firmware_path); 51606969db3SEygene Ryabinkin if (r < 0) 51706969db3SEygene Ryabinkin return 1; 51806969db3SEygene Ryabinkin 51906969db3SEygene Ryabinkin iwmbt_info("Firmware download complete"); 52006969db3SEygene Ryabinkin 52106969db3SEygene Ryabinkin r = iwmbt_intel_reset(hdl, boot_param); 52206969db3SEygene Ryabinkin if (r < 0) { 52306969db3SEygene Ryabinkin iwmbt_debug("iwmbt_intel_reset() failed!"); 52406969db3SEygene Ryabinkin return 1; 52506969db3SEygene Ryabinkin } 52606969db3SEygene Ryabinkin 52706969db3SEygene Ryabinkin iwmbt_info("Firmware operational"); 52806969db3SEygene Ryabinkin 52906969db3SEygene Ryabinkin /* Once device is running in operational mode we can ignore failures */ 53006969db3SEygene Ryabinkin 53106969db3SEygene Ryabinkin /* Dump actual controller version */ 53206969db3SEygene Ryabinkin r = iwmbt_get_version(hdl, &ver); 53306969db3SEygene Ryabinkin if (r == 0) 53406969db3SEygene Ryabinkin iwmbt_dump_version(&ver); 53506969db3SEygene Ryabinkin 53606969db3SEygene Ryabinkin /* Apply the device configuration (DDC) parameters */ 53706969db3SEygene Ryabinkin firmware_path = iwmbt_get_fwname(&ver, ¶ms, firmware_dir, "ddc"); 53806969db3SEygene Ryabinkin iwmbt_debug("ddc_path = %s", firmware_path); 53906969db3SEygene Ryabinkin if (firmware_path != NULL) { 54006969db3SEygene Ryabinkin r = iwmbt_init_ddc(hdl, firmware_path); 54106969db3SEygene Ryabinkin if (r == 0) 54206969db3SEygene Ryabinkin iwmbt_info("DDC download complete"); 54306969db3SEygene Ryabinkin free(firmware_path); 54406969db3SEygene Ryabinkin } 54506969db3SEygene Ryabinkin 54606969db3SEygene Ryabinkin r = iwmbt_set_event_mask(hdl); 54706969db3SEygene Ryabinkin if (r == 0) 54806969db3SEygene Ryabinkin iwmbt_info("Intel Event Mask is set"); 54906969db3SEygene Ryabinkin 55006969db3SEygene Ryabinkin return 0; 55106969db3SEygene Ryabinkin } 55206969db3SEygene Ryabinkin 55306969db3SEygene Ryabinkin 55406969db3SEygene Ryabinkin static int 55506969db3SEygene Ryabinkin handle_9260(libusb_device_handle *hdl, char *firmware_dir) 55606969db3SEygene Ryabinkin { 55706969db3SEygene Ryabinkin int r; 55806969db3SEygene Ryabinkin uint32_t boot_param; 55906969db3SEygene Ryabinkin struct iwmbt_version vl; 56006969db3SEygene Ryabinkin struct iwmbt_version_tlv vt; 56106969db3SEygene Ryabinkin char *firmware_path = NULL; 56206969db3SEygene Ryabinkin 56306969db3SEygene Ryabinkin r = iwmbt_get_version_tlv(hdl, &vt); 56406969db3SEygene Ryabinkin if (r < 0) { 56506969db3SEygene Ryabinkin iwmbt_debug("iwmbt_get_version_tlv() failed code %d", r); 56606969db3SEygene Ryabinkin return 1; 56706969db3SEygene Ryabinkin } 56806969db3SEygene Ryabinkin iwmbt_dump_version_tlv(&vt); 56906969db3SEygene Ryabinkin iwmbt_debug("img_type=0x%02x", (int) vt.img_type); 57006969db3SEygene Ryabinkin 57106969db3SEygene Ryabinkin if (vt.img_type == TLV_IMG_TYPE_OPERATIONAL) { 57206969db3SEygene Ryabinkin iwmbt_info("Firmware has already been downloaded"); 57306969db3SEygene Ryabinkin return 0; 57406969db3SEygene Ryabinkin } 57506969db3SEygene Ryabinkin 57606969db3SEygene Ryabinkin if (vt.img_type != TLV_IMG_TYPE_BOOTLOADER) { 57706969db3SEygene Ryabinkin iwmbt_err("unknown img_type 0x%02x", (int) vt.img_type); 57806969db3SEygene Ryabinkin return 1; 57906969db3SEygene Ryabinkin } 58006969db3SEygene Ryabinkin 58106969db3SEygene Ryabinkin /* Check if firmware fragments are ACKed with a cmd complete event */ 58206969db3SEygene Ryabinkin if (vt.limited_cce != 0x00) { 58306969db3SEygene Ryabinkin iwmbt_err("Unsupported Intel firmware loading method (%u)", 58406969db3SEygene Ryabinkin vt.limited_cce); 58506969db3SEygene Ryabinkin return 1; 58606969db3SEygene Ryabinkin } 58706969db3SEygene Ryabinkin 58806969db3SEygene Ryabinkin /* Check if secure boot engine is supported: 1 (ECDSA) or 0 (RSA) */ 58906969db3SEygene Ryabinkin if (vt.sbe_type > 0x01) { 59006969db3SEygene Ryabinkin iwmbt_err("Unsupported secure boot engine (%u)", 59106969db3SEygene Ryabinkin vt.sbe_type); 59206969db3SEygene Ryabinkin return 1; 59306969db3SEygene Ryabinkin } 59406969db3SEygene Ryabinkin 59506969db3SEygene Ryabinkin firmware_path = iwmbt_get_fwname_tlv(&vt, firmware_dir, "sfi"); 59606969db3SEygene Ryabinkin if (firmware_path == NULL) 59706969db3SEygene Ryabinkin return 1; 59806969db3SEygene Ryabinkin iwmbt_debug("firmware_path = %s", firmware_path); 59906969db3SEygene Ryabinkin 60006969db3SEygene Ryabinkin /* Download firmware and parse it for magic Intel Reset parameter */ 60106969db3SEygene Ryabinkin r = iwmbt_init_firmware(hdl, firmware_path, &boot_param, 60206969db3SEygene Ryabinkin vt.cnvi_bt >> 16 & 0x3f, vt.sbe_type); 60306969db3SEygene Ryabinkin free(firmware_path); 60406969db3SEygene Ryabinkin if (r < 0) 60506969db3SEygene Ryabinkin return 1; 60606969db3SEygene Ryabinkin 60706969db3SEygene Ryabinkin iwmbt_info("Firmware download complete"); 60806969db3SEygene Ryabinkin 60906969db3SEygene Ryabinkin r = iwmbt_intel_reset(hdl, boot_param); 61006969db3SEygene Ryabinkin if (r < 0) { 61106969db3SEygene Ryabinkin iwmbt_debug("iwmbt_intel_reset() failed!"); 61206969db3SEygene Ryabinkin return 1; 61306969db3SEygene Ryabinkin } 61406969db3SEygene Ryabinkin 61506969db3SEygene Ryabinkin iwmbt_info("Firmware operational"); 61606969db3SEygene Ryabinkin 61706969db3SEygene Ryabinkin /* Once device is running in operational mode we can ignore failures */ 61806969db3SEygene Ryabinkin 61906969db3SEygene Ryabinkin r = iwmbt_get_version(hdl, &vl); 62006969db3SEygene Ryabinkin if (r == 0) 62106969db3SEygene Ryabinkin iwmbt_dump_version(&vl); 62206969db3SEygene Ryabinkin 62306969db3SEygene Ryabinkin /* Apply the device configuration (DDC) parameters */ 62406969db3SEygene Ryabinkin firmware_path = iwmbt_get_fwname_tlv(&vt, firmware_dir, "ddc"); 62506969db3SEygene Ryabinkin iwmbt_debug("ddc_path = %s", firmware_path); 62606969db3SEygene Ryabinkin if (firmware_path != NULL) { 62706969db3SEygene Ryabinkin r = iwmbt_init_ddc(hdl, firmware_path); 62806969db3SEygene Ryabinkin if (r == 0) 62906969db3SEygene Ryabinkin iwmbt_info("DDC download complete"); 63006969db3SEygene Ryabinkin free(firmware_path); 63106969db3SEygene Ryabinkin } 63206969db3SEygene Ryabinkin 63306969db3SEygene Ryabinkin r = iwmbt_set_event_mask(hdl); 63406969db3SEygene Ryabinkin if (r == 0) 63506969db3SEygene Ryabinkin iwmbt_info("Intel Event Mask is set"); 63606969db3SEygene Ryabinkin 63706969db3SEygene Ryabinkin return 0; 63806969db3SEygene Ryabinkin } 63906969db3SEygene Ryabinkin 64006969db3SEygene Ryabinkin 6417f32f0e2SVladimir Kondratyev int 6427f32f0e2SVladimir Kondratyev main(int argc, char *argv[]) 6437f32f0e2SVladimir Kondratyev { 6447f32f0e2SVladimir Kondratyev libusb_context *ctx = NULL; 6457f32f0e2SVladimir Kondratyev libusb_device *dev = NULL; 6467f32f0e2SVladimir Kondratyev libusb_device_handle *hdl = NULL; 6477f32f0e2SVladimir Kondratyev int r; 6487f32f0e2SVladimir Kondratyev uint8_t bus_id = 0, dev_id = 0; 6497f32f0e2SVladimir Kondratyev int devid_set = 0; 6507f32f0e2SVladimir Kondratyev int n; 6517f32f0e2SVladimir Kondratyev char *firmware_dir = NULL; 6527f32f0e2SVladimir Kondratyev int retcode = 1; 653c1643cedSVladimir Kondratyev enum iwmbt_device iwmbt_device; 6547f32f0e2SVladimir Kondratyev 6557f32f0e2SVladimir Kondratyev /* Parse command line arguments */ 656*0feaf865SEygene Ryabinkin while ((n = getopt(argc, argv, "Dd:f:hI")) != -1) { 6577f32f0e2SVladimir Kondratyev switch (n) { 6587f32f0e2SVladimir Kondratyev case 'd': /* ugen device name */ 6597f32f0e2SVladimir Kondratyev devid_set = 1; 6607f32f0e2SVladimir Kondratyev if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0) 6617f32f0e2SVladimir Kondratyev usage(); 6627f32f0e2SVladimir Kondratyev break; 6637f32f0e2SVladimir Kondratyev case 'D': 6647f32f0e2SVladimir Kondratyev iwmbt_do_debug = 1; 6657f32f0e2SVladimir Kondratyev break; 6667f32f0e2SVladimir Kondratyev case 'f': /* firmware dir */ 6677f32f0e2SVladimir Kondratyev if (firmware_dir) 6687f32f0e2SVladimir Kondratyev free(firmware_dir); 6697f32f0e2SVladimir Kondratyev firmware_dir = strdup(optarg); 6707f32f0e2SVladimir Kondratyev break; 6717f32f0e2SVladimir Kondratyev case 'I': 6727f32f0e2SVladimir Kondratyev iwmbt_do_info = 1; 6737f32f0e2SVladimir Kondratyev break; 6747f32f0e2SVladimir Kondratyev case 'h': 6757f32f0e2SVladimir Kondratyev default: 6767f32f0e2SVladimir Kondratyev usage(); 6777f32f0e2SVladimir Kondratyev break; 6787f32f0e2SVladimir Kondratyev /* NOT REACHED */ 6797f32f0e2SVladimir Kondratyev } 6807f32f0e2SVladimir Kondratyev } 6817f32f0e2SVladimir Kondratyev 6827f32f0e2SVladimir Kondratyev /* Ensure the devid was given! */ 6837f32f0e2SVladimir Kondratyev if (devid_set == 0) { 6847f32f0e2SVladimir Kondratyev usage(); 6857f32f0e2SVladimir Kondratyev /* NOTREACHED */ 6867f32f0e2SVladimir Kondratyev } 6877f32f0e2SVladimir Kondratyev 688f466ba4cSEygene Ryabinkin /* Default the firmware path */ 689f466ba4cSEygene Ryabinkin if (firmware_dir == NULL) 690f466ba4cSEygene Ryabinkin firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH); 691f466ba4cSEygene Ryabinkin 6927f32f0e2SVladimir Kondratyev /* libusb setup */ 6937f32f0e2SVladimir Kondratyev r = libusb_init(&ctx); 6947f32f0e2SVladimir Kondratyev if (r != 0) { 6957f32f0e2SVladimir Kondratyev iwmbt_err("libusb_init failed: code %d", r); 6967f32f0e2SVladimir Kondratyev exit(127); 6977f32f0e2SVladimir Kondratyev } 6987f32f0e2SVladimir Kondratyev 6997f32f0e2SVladimir Kondratyev iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id); 7007f32f0e2SVladimir Kondratyev 7017f32f0e2SVladimir Kondratyev /* Find a device based on the bus/dev id */ 702c1643cedSVladimir Kondratyev dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_device); 7037f32f0e2SVladimir Kondratyev if (dev == NULL) { 7047f32f0e2SVladimir Kondratyev iwmbt_err("device not found"); 7057f32f0e2SVladimir Kondratyev goto shutdown; 7067f32f0e2SVladimir Kondratyev } 7077f32f0e2SVladimir Kondratyev 7087f32f0e2SVladimir Kondratyev /* XXX enforce that bInterfaceNumber is 0 */ 7097f32f0e2SVladimir Kondratyev 7107f32f0e2SVladimir Kondratyev /* XXX enforce the device/product id if they're non-zero */ 7117f32f0e2SVladimir Kondratyev 7127f32f0e2SVladimir Kondratyev /* Grab device handle */ 7137f32f0e2SVladimir Kondratyev r = libusb_open(dev, &hdl); 7147f32f0e2SVladimir Kondratyev if (r != 0) { 7157f32f0e2SVladimir Kondratyev iwmbt_err("libusb_open() failed: code %d", r); 7167f32f0e2SVladimir Kondratyev goto shutdown; 7177f32f0e2SVladimir Kondratyev } 7187f32f0e2SVladimir Kondratyev 7197f32f0e2SVladimir Kondratyev /* Check if ng_ubt is attached */ 7207f32f0e2SVladimir Kondratyev r = libusb_kernel_driver_active(hdl, 0); 7217f32f0e2SVladimir Kondratyev if (r < 0) { 7227f32f0e2SVladimir Kondratyev iwmbt_err("libusb_kernel_driver_active() failed: code %d", r); 7237f32f0e2SVladimir Kondratyev goto shutdown; 7247f32f0e2SVladimir Kondratyev } 7257f32f0e2SVladimir Kondratyev if (r > 0) { 7267f32f0e2SVladimir Kondratyev iwmbt_info("Firmware has already been downloaded"); 7277f32f0e2SVladimir Kondratyev retcode = 0; 7287f32f0e2SVladimir Kondratyev goto shutdown; 7297f32f0e2SVladimir Kondratyev } 7307f32f0e2SVladimir Kondratyev 73106969db3SEygene Ryabinkin switch(iwmbt_device) { 73206969db3SEygene Ryabinkin case IWMBT_DEVICE_7260: 73306969db3SEygene Ryabinkin retcode = handle_7260(hdl, firmware_dir); 73406969db3SEygene Ryabinkin break; 73506969db3SEygene Ryabinkin case IWMBT_DEVICE_8260: 73606969db3SEygene Ryabinkin retcode = handle_8260(hdl, firmware_dir); 73706969db3SEygene Ryabinkin break; 73806969db3SEygene Ryabinkin case IWMBT_DEVICE_9260: 73906969db3SEygene Ryabinkin retcode = handle_9260(hdl, firmware_dir); 74006969db3SEygene Ryabinkin break; 74106969db3SEygene Ryabinkin default: 74206969db3SEygene Ryabinkin iwmbt_err("FIXME: unknown iwmbt type %d", (int)iwmbt_device); 74306969db3SEygene Ryabinkin retcode = 1; 744fe70d7b2SPhilippe Michaud-Boudreault } 745fe70d7b2SPhilippe Michaud-Boudreault 74606969db3SEygene Ryabinkin if (retcode == 0) { 7477f32f0e2SVladimir Kondratyev /* Ask kernel driver to probe and attach device again */ 7487f32f0e2SVladimir Kondratyev r = libusb_reset_device(hdl); 7497f32f0e2SVladimir Kondratyev if (r != 0) 7507f32f0e2SVladimir Kondratyev iwmbt_err("libusb_reset_device() failed: %s", 7517f32f0e2SVladimir Kondratyev libusb_strerror(r)); 75206969db3SEygene Ryabinkin } 7537f32f0e2SVladimir Kondratyev 7547f32f0e2SVladimir Kondratyev shutdown: 7557f32f0e2SVladimir Kondratyev if (hdl != NULL) 7567f32f0e2SVladimir Kondratyev libusb_close(hdl); 7577f32f0e2SVladimir Kondratyev 7587f32f0e2SVladimir Kondratyev if (dev != NULL) 7597f32f0e2SVladimir Kondratyev libusb_unref_device(dev); 7607f32f0e2SVladimir Kondratyev 7617f32f0e2SVladimir Kondratyev if (ctx != NULL) 7627f32f0e2SVladimir Kondratyev libusb_exit(ctx); 7637f32f0e2SVladimir Kondratyev 7647f32f0e2SVladimir Kondratyev if (retcode == 0) 76540bb52c8SGordon Bergling iwmbt_info("Firmware download is successful!"); 7667f32f0e2SVladimir Kondratyev else 7677f32f0e2SVladimir Kondratyev iwmbt_err("Firmware download failed!"); 7687f32f0e2SVladimir Kondratyev 7697f32f0e2SVladimir Kondratyev return (retcode); 7707f32f0e2SVladimir Kondratyev } 771