The branch main has been updated by wulf:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=da93a73f834612b659b37b513c8296e1178d249b

commit da93a73f834612b659b37b513c8296e1178d249b
Author:     Vladimir Kondratyev <[email protected]>
AuthorDate: 2021-05-31 19:32:08 +0000
Commit:     Vladimir Kondratyev <[email protected]>
CommitDate: 2021-05-31 19:32:08 +0000

    iwmbtfw(8): Improve Intel 7260/7265 adaptors handling
    
    - Allow firmware downloading for hw_variant #8;
    - Enter manufacturer mode for setting of event mask;
    - Handle multi-event response on HCI commands for 7260;
      This allows to remove kludge with skipping of 0xfc2f opcode.
    - Disable patch and exit manufacturer mode on downloading failure;
    - Use default firmware if correct firmware file is not found;
    
    Reviewed by:    Philippe Michaud-Boudreault <pitwuu_AT_gmail_DOT_com>
    MFC after:      1 week
    Tested by:      arrowd
    Differential revision:  https://reviews.freebsd.org/D30543
---
 usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c |  14 ++++
 usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c | 116 ++++++++++++++++++++--------------
 usr.sbin/bluetooth/iwmbtfw/main.c     |   9 ++-
 3 files changed, 91 insertions(+), 48 deletions(-)

diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c 
b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
index fc93ce094adc..963d5d5d9008 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
@@ -116,10 +116,12 @@ char *
 iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
     const char *prefix, const char *suffix)
 {
+       struct stat sb;
        char *fwname;
 
        switch (ver->hw_variant) {
        case 0x07:      /* 7260 */
+       case 0x08:      /* 7265 */
                asprintf(&fwname, "%s/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.%s",
                    prefix,
                    le16toh(ver->hw_platform),
@@ -131,6 +133,18 @@ iwmbt_get_fwname(struct iwmbt_version *ver, struct 
iwmbt_boot_params *params,
                    le16toh(ver->fw_build_ww),
                    le16toh(ver->fw_build_yy),
                    suffix);
+               /*
+                * Fallback to the default firmware patch if
+                * the correct firmware patch file is not found.
+                */
+               if (stat(fwname, &sb) != 0 && errno == ENOENT) {
+                       free(fwname);
+                       asprintf(&fwname, "%s/ibt-hw-%x.%x.%s",
+                           prefix,
+                           le16toh(ver->hw_platform),
+                           le16toh(ver->hw_variant),
+                           suffix);
+               }
                break;
 
        case 0x0b:      /* 8260 */
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c 
b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
index f4272548d560..218fd28b74a2 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
@@ -134,17 +134,18 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
        struct iwmbt_firmware fw_job = *fw;
        uint16_t cmd_opcode;
        uint8_t cmd_length;
-       uint8_t cmd_buf[IWMBT_HCI_MAX_CMD_SIZE];
+       struct iwmbt_hci_cmd *cmd_buf;
        uint8_t evt_code;
        uint8_t evt_length;
        uint8_t evt_buf[IWMBT_HCI_MAX_EVENT_SIZE];
-       int skip_patch = 0;
+       int activate_patch = 0;
 
-       for (;;) {
-               skip_patch = 0;
-
-               if (fw_job.len < 4)
-                       break;
+       while (fw_job.len > 0) {
+               if (fw_job.len < 4) {
+                       iwmbt_err("Invalid firmware, unexpected EOF in HCI "
+                           "command header. Remains=%d", fw_job.len);
+                       return (-1);
+               }
 
                if (fw_job.buf[0] != 0x01) {
                        iwmbt_err("Invalid firmware, expected HCI command (%d)",
@@ -159,47 +160,61 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
                /* Load in the HCI command to perform. */
                cmd_opcode = le16dec(fw_job.buf);
                cmd_length = fw_job.buf[2];
-               memcpy(cmd_buf, fw_job.buf, 3);
+               cmd_buf = (struct iwmbt_hci_cmd *)fw_job.buf;
 
                iwmbt_debug("opcode=%04x, len=%02x", cmd_opcode, cmd_length);
 
-               /* For some reason the command 0xfc2f hangs up my card. */
-               if (cmd_opcode == 0xfc2f)
-                       skip_patch = 1;
+               /*
+                * If there is a command that loads a patch in the
+                * firmware file, then activate the patch upon success,
+                * otherwise just disable the manufacturer mode.
+                */
+               if (cmd_opcode == 0xfc8e)
+                       activate_patch = 1;
 
                /* Advance by three. */
                fw_job.buf += 3;
                fw_job.len -= 3;
 
-               if (fw_job.len < cmd_length)
-                       cmd_length = fw_job.len;
-
-               /* Copy data to HCI command buffer. */
-               memcpy(cmd_buf + 3, fw_job.buf,
-                   MIN(cmd_length, IWMBT_HCI_MAX_CMD_SIZE - 3));
+               if (fw_job.len < cmd_length) {
+                       iwmbt_err("Invalid firmware, unexpected EOF in HCI "
+                           "command data. len=%d, remains=%d",
+                           cmd_length, fw_job.len);
+                       return (-1);
+               }
 
                /* Advance by data length. */
                fw_job.buf += cmd_length;
                fw_job.len -= cmd_length;
 
+               ret = libusb_control_transfer(hdl,
+                   LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
+                   0,
+                   0,
+                   0,
+                   (uint8_t *)cmd_buf,
+                   IWMBT_HCI_CMD_SIZE(cmd_buf),
+                   IWMBT_HCI_CMD_TIMEOUT);
+
+               if (ret < 0) {
+                       iwmbt_err("libusb_control_transfer() failed: err=%s",
+                           libusb_strerror(ret));
+                       return (-1);
+               }
+
                /*
                 * Every command has its associated event: data must match
                 * what is recorded in the firmware file. Perform that check
                 * now.
-                *
-                * Some commands are mapped to more than one event sequence,
-                * in that case we can drop the non-patch commands, as we
-                * probably don't need them for operation of the card.
-                *
                 */
 
-               for (;;) {
+               while (fw_job.len > 0 && fw_job.buf[0] == 0x02) {
                        /* Is this the end of the file? */
-                       if (fw_job.len < 3)
-                               break;
-
-                       if (fw_job.buf[0] != 0x02)
-                               break;
+                       if (fw_job.len < 3) {
+                               iwmbt_err("Invalid firmware, unexpected EOF in"
+                                   "event header. remains=%d", fw_job.len);
+                               return (-1);
+                       }
 
                        /* Advance by one. */
                        fw_job.buf++;
@@ -219,30 +234,39 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
                        iwmbt_debug("event=%04x, len=%02x",
                                        evt_code, evt_length);
 
+                       if (fw_job.len < evt_length) {
+                               iwmbt_err("Invalid firmware, unexpected EOF in"
+                                   " event data. len=%d, remains=%d",
+                                   evt_length, fw_job.len);
+                               return (-1);
+                       }
+
+                       ret = libusb_interrupt_transfer(hdl,
+                           IWMBT_INTERRUPT_ENDPOINT_ADDR,
+                           evt_buf,
+                           IWMBT_HCI_MAX_EVENT_SIZE,
+                           &transferred,
+                           IWMBT_HCI_CMD_TIMEOUT);
+
+                       if (ret < 0) {
+                               iwmbt_err("libusb_interrupt_transfer() failed:"
+                                   " err=%s", libusb_strerror(ret));
+                               return (-1);
+                       }
+
+                       if ((int)evt_length + 2 != transferred ||
+                           memcmp(evt_buf + 2, fw_job.buf, evt_length) != 0) {
+                               iwmbt_err("event does not match firmware");
+                               return (-1);
+                       }
+
                        /* Advance by data length. */
                        fw_job.buf += evt_length;
                        fw_job.len -= evt_length;
-
-                       if (skip_patch == 0) {
-                               ret = iwmbt_hci_command(hdl,
-                                   (struct iwmbt_hci_cmd *)cmd_buf,
-                                   evt_buf,
-                                   IWMBT_HCI_MAX_EVENT_SIZE,
-                                   &transferred,
-                                   IWMBT_HCI_CMD_TIMEOUT);
-
-                               if (ret < 0) {
-                                       iwmbt_debug("Can't send patch: "
-                                           "code=%d, size=%d",
-                                           ret,
-                                           transferred);
-                                        return (-1);
-                               }
-                       }
                }
        }
 
-       return (0);
+       return (activate_patch);
 }
 
 int
diff --git a/usr.sbin/bluetooth/iwmbtfw/main.c 
b/usr.sbin/bluetooth/iwmbtfw/main.c
index 3476e3fcd613..202894740805 100644
--- a/usr.sbin/bluetooth/iwmbtfw/main.c
+++ b/usr.sbin/bluetooth/iwmbtfw/main.c
@@ -441,13 +441,15 @@ main(int argc, char *argv[])
                /* Download firmware and parse it for magic Intel Reset 
parameter */
                r = iwmbt_patch_firmware(hdl, firmware_path);
                free(firmware_path);
-               if (r < 0)
+               if (r < 0) {
+                       (void)iwmbt_exit_manufacturer(hdl, 0x01);
                        goto shutdown;
+               }
 
                iwmbt_info("Firmware download complete");
 
                /* Exit manufacturer mode */
-               r = iwmbt_exit_manufacturer(hdl, 0x02);
+               r = iwmbt_exit_manufacturer(hdl, r == 0 ? 0x00 : 0x02);
                if (r < 0) {
                        iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", 
r);
                        goto shutdown;
@@ -462,9 +464,12 @@ main(int argc, char *argv[])
                        iwmbt_dump_version(&ver);
 
                /* Set Intel Event mask */
+               if (iwmbt_enter_manufacturer(hdl) < 0)
+                       goto reset;
                r = iwmbt_set_event_mask(hdl);
                if (r == 0)
                        iwmbt_info("Intel Event Mask is set");
+               (void)iwmbt_exit_manufacturer(hdl, 0x00);
 
        } else {
 
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to