1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> 5 * Copyright (c) 2023 Future Crew LLC. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/endian.h> 31 #include <sys/stat.h> 32 33 #include <assert.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <stddef.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <time.h> 41 #include <unistd.h> 42 43 #include <libusb.h> 44 45 #include <netgraph/bluetooth/include/ng_hci.h> 46 47 #include "iwmbt_fw.h" 48 #include "iwmbt_hw.h" 49 #include "iwmbt_dbg.h" 50 51 #define XMIN(x, y) ((x) < (y) ? (x) : (y)) 52 53 static int 54 iwmbt_send_fragment(struct libusb_device_handle *hdl, 55 uint8_t fragment_type, const void *data, uint8_t len, int timeout) 56 { 57 int ret, transferred; 58 uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE]; 59 struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *) buf; 60 61 memset(buf, 0, sizeof(buf)); 62 cmd->opcode = htole16(0xfc09), 63 cmd->length = len + 1, 64 cmd->data[0] = fragment_type; 65 memcpy(cmd->data + 1, data, len); 66 67 ret = libusb_bulk_transfer(hdl, 68 IWMBT_BULK_OUT_ENDPOINT_ADDR, 69 (uint8_t *)cmd, 70 IWMBT_HCI_CMD_SIZE(cmd), 71 &transferred, 72 timeout); 73 74 if (ret < 0 || transferred != (int)IWMBT_HCI_CMD_SIZE(cmd)) { 75 iwmbt_err("libusb_bulk_transfer() failed: err=%s, size=%zu", 76 libusb_strerror(ret), 77 IWMBT_HCI_CMD_SIZE(cmd)); 78 return (-1); 79 } 80 81 ret = libusb_bulk_transfer(hdl, 82 IWMBT_BULK_IN_ENDPOINT_ADDR, 83 buf, 84 sizeof(buf), 85 &transferred, 86 timeout); 87 88 if (ret < 0) { 89 iwmbt_err("libusb_bulk_transfer() failed: err=%s", 90 libusb_strerror(ret)); 91 return (-1); 92 } 93 94 return (0); 95 } 96 97 static int 98 iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd, 99 void *event, int size, int *transferred, int timeout) 100 { 101 struct timespec to, now, remains; 102 int ret; 103 104 ret = libusb_control_transfer(hdl, 105 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, 106 0, 107 0, 108 0, 109 (uint8_t *)cmd, 110 IWMBT_HCI_CMD_SIZE(cmd), 111 timeout); 112 113 if (ret < 0) { 114 iwmbt_err("libusb_control_transfer() failed: err=%s", 115 libusb_strerror(ret)); 116 return (ret); 117 } 118 119 clock_gettime(CLOCK_MONOTONIC, &now); 120 to = IWMBT_MSEC2TS(timeout); 121 timespecadd(&to, &now, &to); 122 123 do { 124 timespecsub(&to, &now, &remains); 125 ret = libusb_interrupt_transfer(hdl, 126 IWMBT_INTERRUPT_ENDPOINT_ADDR, 127 event, 128 size, 129 transferred, 130 IWMBT_TS2MSEC(remains) + 1); 131 132 if (ret < 0) { 133 iwmbt_err("libusb_interrupt_transfer() failed: err=%s", 134 libusb_strerror(ret)); 135 return (ret); 136 } 137 138 switch (((struct iwmbt_hci_event *)event)->header.event) { 139 case NG_HCI_EVENT_COMMAND_COMPL: 140 if (*transferred < 141 (int)offsetof(struct iwmbt_hci_event_cmd_compl, data)) 142 break; 143 if (cmd->opcode != 144 ((struct iwmbt_hci_event_cmd_compl *)event)->opcode) 145 break; 146 /* FALLTHROUGH */ 147 case 0xFF: 148 return (0); 149 default: 150 break; 151 } 152 iwmbt_debug("Stray HCI event: %x", 153 ((struct iwmbt_hci_event *)event)->header.event); 154 } while (timespeccmp(&to, &now, >)); 155 156 iwmbt_err("libusb_interrupt_transfer() failed: err=%s", 157 libusb_strerror(LIBUSB_ERROR_TIMEOUT)); 158 159 return (LIBUSB_ERROR_TIMEOUT); 160 } 161 162 int 163 iwmbt_patch_fwfile(struct libusb_device_handle *hdl, 164 const struct iwmbt_firmware *fw) 165 { 166 int ret, transferred; 167 struct iwmbt_firmware fw_job = *fw; 168 uint16_t cmd_opcode; 169 uint8_t cmd_length; 170 struct iwmbt_hci_cmd *cmd_buf; 171 uint8_t evt_code; 172 uint8_t evt_length; 173 uint8_t evt_buf[IWMBT_HCI_MAX_EVENT_SIZE]; 174 int activate_patch = 0; 175 176 while (fw_job.len > 0) { 177 if (fw_job.len < 4) { 178 iwmbt_err("Invalid firmware, unexpected EOF in HCI " 179 "command header. Remains=%d", fw_job.len); 180 return (-1); 181 } 182 183 if (fw_job.buf[0] != 0x01) { 184 iwmbt_err("Invalid firmware, expected HCI command (%d)", 185 fw_job.buf[0]); 186 return (-1); 187 } 188 189 /* Advance by one. */ 190 fw_job.buf++; 191 fw_job.len--; 192 193 /* Load in the HCI command to perform. */ 194 cmd_opcode = le16dec(fw_job.buf); 195 cmd_length = fw_job.buf[2]; 196 cmd_buf = (struct iwmbt_hci_cmd *)fw_job.buf; 197 198 iwmbt_debug("opcode=%04x, len=%02x", cmd_opcode, cmd_length); 199 200 /* 201 * If there is a command that loads a patch in the 202 * firmware file, then activate the patch upon success, 203 * otherwise just disable the manufacturer mode. 204 */ 205 if (cmd_opcode == 0xfc8e) 206 activate_patch = 1; 207 208 /* Advance by three. */ 209 fw_job.buf += 3; 210 fw_job.len -= 3; 211 212 if (fw_job.len < cmd_length) { 213 iwmbt_err("Invalid firmware, unexpected EOF in HCI " 214 "command data. len=%d, remains=%d", 215 cmd_length, fw_job.len); 216 return (-1); 217 } 218 219 /* Advance by data length. */ 220 fw_job.buf += cmd_length; 221 fw_job.len -= cmd_length; 222 223 ret = libusb_control_transfer(hdl, 224 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, 225 0, 226 0, 227 0, 228 (uint8_t *)cmd_buf, 229 IWMBT_HCI_CMD_SIZE(cmd_buf), 230 IWMBT_HCI_CMD_TIMEOUT); 231 232 if (ret < 0) { 233 iwmbt_err("libusb_control_transfer() failed: err=%s", 234 libusb_strerror(ret)); 235 return (-1); 236 } 237 238 /* 239 * Every command has its associated event: data must match 240 * what is recorded in the firmware file. Perform that check 241 * now. 242 */ 243 244 while (fw_job.len > 0 && fw_job.buf[0] == 0x02) { 245 /* Is this the end of the file? */ 246 if (fw_job.len < 3) { 247 iwmbt_err("Invalid firmware, unexpected EOF in" 248 "event header. remains=%d", fw_job.len); 249 return (-1); 250 } 251 252 /* Advance by one. */ 253 fw_job.buf++; 254 fw_job.len--; 255 256 /* Load in the HCI event. */ 257 evt_code = fw_job.buf[0]; 258 evt_length = fw_job.buf[1]; 259 260 /* Advance by two. */ 261 fw_job.buf += 2; 262 fw_job.len -= 2; 263 264 /* Prepare HCI event buffer. */ 265 memset(evt_buf, 0, IWMBT_HCI_MAX_EVENT_SIZE); 266 267 iwmbt_debug("event=%04x, len=%02x", 268 evt_code, evt_length); 269 270 if (fw_job.len < evt_length) { 271 iwmbt_err("Invalid firmware, unexpected EOF in" 272 " event data. len=%d, remains=%d", 273 evt_length, fw_job.len); 274 return (-1); 275 } 276 277 ret = libusb_interrupt_transfer(hdl, 278 IWMBT_INTERRUPT_ENDPOINT_ADDR, 279 evt_buf, 280 IWMBT_HCI_MAX_EVENT_SIZE, 281 &transferred, 282 IWMBT_HCI_CMD_TIMEOUT); 283 284 if (ret < 0) { 285 iwmbt_err("libusb_interrupt_transfer() failed:" 286 " err=%s", libusb_strerror(ret)); 287 return (-1); 288 } 289 290 if ((int)evt_length + 2 != transferred || 291 memcmp(evt_buf + 2, fw_job.buf, evt_length) != 0) { 292 iwmbt_err("event does not match firmware"); 293 return (-1); 294 } 295 296 /* Advance by data length. */ 297 fw_job.buf += evt_length; 298 fw_job.len -= evt_length; 299 } 300 } 301 302 return (activate_patch); 303 } 304 305 #define IWMBT_SEND_FRAGMENT(fragment_type, size, msg) do { \ 306 iwmbt_debug("transferring %d bytes, offset %d", size, sent); \ 307 \ 308 ret = iwmbt_send_fragment(hdl, \ 309 fragment_type, \ 310 fw->buf + sent, \ 311 XMIN(size, fw->len - sent), \ 312 IWMBT_HCI_CMD_TIMEOUT); \ 313 \ 314 if (ret < 0) { \ 315 iwmbt_debug("Failed to send "msg": code=%d", ret); \ 316 return (-1); \ 317 } \ 318 sent += size; \ 319 } while (0) 320 321 int 322 iwmbt_load_rsa_header(struct libusb_device_handle *hdl, 323 const struct iwmbt_firmware *fw) 324 { 325 int ret, sent = 0; 326 327 IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment"); 328 IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 1"); 329 IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 2"); 330 331 /* skip 4 bytes */ 332 sent += 4; 333 334 IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 1"); 335 IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 2"); 336 337 return (0); 338 } 339 340 int 341 iwmbt_load_ecdsa_header(struct libusb_device_handle *hdl, 342 const struct iwmbt_firmware *fw) 343 { 344 int ret, sent = ECDSA_OFFSET; 345 346 IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment"); 347 IWMBT_SEND_FRAGMENT(0x03, 0x60, "public key"); 348 IWMBT_SEND_FRAGMENT(0x02, 0x60, "signature"); 349 350 return (0); 351 } 352 353 int 354 iwmbt_load_fwfile(struct libusb_device_handle *hdl, 355 const struct iwmbt_firmware *fw, uint32_t *boot_param, int offset) 356 { 357 int ready = 0, sent = offset; 358 int ret, transferred; 359 struct iwmbt_hci_cmd *cmd; 360 struct iwmbt_hci_event *event; 361 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 362 363 /* 364 * Send firmware chunks. Chunk len must be 4 byte aligned. 365 * multiple commands can be combined 366 */ 367 while (fw->len - sent - ready >= (int) sizeof(struct iwmbt_hci_cmd)) { 368 cmd = (struct iwmbt_hci_cmd *)(fw->buf + sent + ready); 369 /* Parse firmware for Intel Reset HCI command parameter */ 370 if (cmd->opcode == htole16(0xfc0e)) { 371 *boot_param = le32dec(cmd->data); 372 iwmbt_debug("boot_param=0x%08x", *boot_param); 373 } 374 ready += IWMBT_HCI_CMD_SIZE(cmd); 375 while (ready >= 0xFC) { 376 IWMBT_SEND_FRAGMENT(0x01, 0xFC, "firmware chunk"); 377 ready -= 0xFC; 378 } 379 if (ready > 0 && ready % 4 == 0) { 380 IWMBT_SEND_FRAGMENT(0x01, ready, "firmware chunk"); 381 ready = 0; 382 } 383 } 384 385 /* Wait for firmware download completion event */ 386 ret = libusb_interrupt_transfer(hdl, 387 IWMBT_INTERRUPT_ENDPOINT_ADDR, 388 buf, 389 sizeof(buf), 390 &transferred, 391 IWMBT_LOADCMPL_TIMEOUT); 392 393 if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) { 394 iwmbt_err("libusb_interrupt_transfer() failed: " 395 "err=%s, size=%d", 396 libusb_strerror(ret), 397 transferred); 398 return (-1); 399 } 400 401 /* Expect Vendor Specific Event 0x06 */ 402 event = (struct iwmbt_hci_event *)buf; 403 if (event->header.event != 0xFF || event->data[0] != 0x06) { 404 iwmbt_err("firmware download completion event missed"); 405 return (-1); 406 } 407 408 return (0); 409 } 410 411 int 412 iwmbt_enter_manufacturer(struct libusb_device_handle *hdl) 413 { 414 int ret, transferred; 415 static struct iwmbt_hci_cmd cmd = { 416 .opcode = htole16(0xfc11), 417 .length = 2, 418 .data = { 0x01, 0x00 }, 419 }; 420 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 421 422 ret = iwmbt_hci_command(hdl, 423 &cmd, 424 buf, 425 sizeof(buf), 426 &transferred, 427 IWMBT_HCI_CMD_TIMEOUT); 428 429 if (ret < 0) { 430 iwmbt_debug("Can't enter manufacturer mode: code=%d, size=%d", 431 ret, 432 transferred); 433 return (-1); 434 } 435 436 return (0); 437 } 438 439 int 440 iwmbt_exit_manufacturer(struct libusb_device_handle *hdl, int mode) 441 { 442 int ret, transferred; 443 static struct iwmbt_hci_cmd cmd = { 444 .opcode = htole16(0xfc11), 445 .length = 2, 446 .data = { 0x00, 0x00 }, 447 }; 448 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 449 450 /* 451 * The mode sets the type of reset we want to perform: 452 * 0x00: simply exit manufacturer mode without a reset. 453 * 0x01: exit manufacturer mode with a reset and patches disabled 454 * 0x02: exit manufacturer mode with a reset and patches enabled 455 */ 456 if (mode > 2) { 457 iwmbt_debug("iwmbt_exit_manufacturer(): unknown mode (%d)", 458 mode); 459 } 460 cmd.data[1] = mode; 461 462 ret = iwmbt_hci_command(hdl, 463 &cmd, 464 buf, 465 sizeof(buf), 466 &transferred, 467 IWMBT_HCI_CMD_TIMEOUT); 468 469 if (ret < 0) { 470 iwmbt_debug("Can't exit manufacturer mode: code=%d, size=%d", 471 ret, 472 transferred); 473 return (-1); 474 } 475 476 return (0); 477 } 478 479 int 480 iwmbt_get_version(struct libusb_device_handle *hdl, 481 struct iwmbt_version *version) 482 { 483 int ret, transferred; 484 struct iwmbt_hci_event_cmd_compl*event; 485 struct iwmbt_hci_cmd cmd = { 486 .opcode = htole16(0xfc05), 487 .length = 0, 488 }; 489 uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_version)]; 490 491 memset(buf, 0, sizeof(buf)); 492 493 ret = iwmbt_hci_command(hdl, 494 &cmd, 495 buf, 496 sizeof(buf), 497 &transferred, 498 IWMBT_HCI_CMD_TIMEOUT); 499 500 if (ret < 0 || transferred != sizeof(buf)) { 501 iwmbt_debug("Can't get version: : code=%d, size=%d", 502 ret, 503 transferred); 504 return (-1); 505 } 506 507 event = (struct iwmbt_hci_event_cmd_compl *)buf; 508 memcpy(version, event->data, sizeof(struct iwmbt_version)); 509 510 return (0); 511 } 512 513 int 514 iwmbt_get_version_tlv(struct libusb_device_handle *hdl, 515 struct iwmbt_version_tlv *version) 516 { 517 int ret, transferred; 518 struct iwmbt_hci_event_cmd_compl *event; 519 static struct iwmbt_hci_cmd cmd = { 520 .opcode = htole16(0xfc05), 521 .length = 1, 522 .data = { 0xff }, 523 }; 524 uint8_t status, datalen, type, len; 525 uint8_t *data; 526 uint8_t buf[255]; 527 528 memset(buf, 0, sizeof(buf)); 529 530 ret = iwmbt_hci_command(hdl, 531 &cmd, 532 buf, 533 sizeof(buf), 534 &transferred, 535 IWMBT_HCI_CMD_TIMEOUT); 536 537 if (ret < 0 || transferred < (int)IWMBT_HCI_EVT_COMPL_SIZE(uint16_t)) { 538 iwmbt_debug("Can't get version: code=%d, size=%d", 539 ret, 540 transferred); 541 return (-1); 542 } 543 544 event = (struct iwmbt_hci_event_cmd_compl *)buf; 545 memcpy(version, event->data, sizeof(struct iwmbt_version)); 546 547 datalen = event->header.length - IWMBT_HCI_EVENT_COMPL_HEAD_SIZE; 548 data = event->data; 549 status = *data++; 550 if (status != 0) 551 return (-1); 552 datalen--; 553 554 while (datalen >= 2) { 555 type = *data++; 556 len = *data++; 557 datalen -= 2; 558 559 if (datalen < len) 560 return (-1); 561 562 switch (type) { 563 case IWMBT_TLV_CNVI_TOP: 564 assert(len == 4); 565 version->cnvi_top = le32dec(data); 566 break; 567 case IWMBT_TLV_CNVR_TOP: 568 assert(len == 4); 569 version->cnvr_top = le32dec(data); 570 break; 571 case IWMBT_TLV_CNVI_BT: 572 assert(len == 4); 573 version->cnvi_bt = le32dec(data); 574 break; 575 case IWMBT_TLV_CNVR_BT: 576 assert(len == 4); 577 version->cnvr_bt = le32dec(data); 578 break; 579 case IWMBT_TLV_DEV_REV_ID: 580 assert(len == 2); 581 version->dev_rev_id = le16dec(data); 582 break; 583 case IWMBT_TLV_IMAGE_TYPE: 584 assert(len == 1); 585 version->img_type = *data; 586 break; 587 case IWMBT_TLV_TIME_STAMP: 588 assert(len == 2); 589 version->min_fw_build_cw = data[0]; 590 version->min_fw_build_yy = data[1]; 591 version->timestamp = le16dec(data); 592 break; 593 case IWMBT_TLV_BUILD_TYPE: 594 assert(len == 1); 595 version->build_type = *data; 596 break; 597 case IWMBT_TLV_BUILD_NUM: 598 assert(len == 4); 599 version->min_fw_build_nn = *data; 600 version->build_num = le32dec(data); 601 break; 602 case IWMBT_TLV_SECURE_BOOT: 603 assert(len == 1); 604 version->secure_boot = *data; 605 break; 606 case IWMBT_TLV_OTP_LOCK: 607 assert(len == 1); 608 version->otp_lock = *data; 609 break; 610 case IWMBT_TLV_API_LOCK: 611 assert(len == 1); 612 version->api_lock = *data; 613 break; 614 case IWMBT_TLV_DEBUG_LOCK: 615 assert(len == 1); 616 version->debug_lock = *data; 617 break; 618 case IWMBT_TLV_MIN_FW: 619 assert(len == 3); 620 version->min_fw_build_nn = data[0]; 621 version->min_fw_build_cw = data[1]; 622 version->min_fw_build_yy = data[2]; 623 break; 624 case IWMBT_TLV_LIMITED_CCE: 625 assert(len == 1); 626 version->limited_cce = *data; 627 break; 628 case IWMBT_TLV_SBE_TYPE: 629 assert(len == 1); 630 version->sbe_type = *data; 631 break; 632 case IWMBT_TLV_OTP_BDADDR: 633 memcpy(&version->otp_bd_addr, data, sizeof(bdaddr_t)); 634 break; 635 default: 636 /* Ignore other types */ 637 break; 638 } 639 640 datalen -= len; 641 data += len; 642 } 643 644 return (0); 645 } 646 647 int 648 iwmbt_get_boot_params(struct libusb_device_handle *hdl, 649 struct iwmbt_boot_params *params) 650 { 651 int ret, transferred = 0; 652 struct iwmbt_hci_event_cmd_compl *event; 653 struct iwmbt_hci_cmd cmd = { 654 .opcode = htole16(0xfc0d), 655 .length = 0, 656 }; 657 uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_boot_params)]; 658 659 memset(buf, 0, sizeof(buf)); 660 661 ret = iwmbt_hci_command(hdl, 662 &cmd, 663 buf, 664 sizeof(buf), 665 &transferred, 666 IWMBT_HCI_CMD_TIMEOUT); 667 668 if (ret < 0 || transferred != sizeof(buf)) { 669 iwmbt_debug("Can't get boot params: code=%d, size=%d", 670 ret, 671 transferred); 672 return (-1); 673 } 674 675 event = (struct iwmbt_hci_event_cmd_compl *)buf; 676 memcpy(params, event->data, sizeof(struct iwmbt_boot_params)); 677 678 return (0); 679 } 680 681 int 682 iwmbt_intel_reset(struct libusb_device_handle *hdl, uint32_t boot_param) 683 { 684 int ret, transferred = 0; 685 struct iwmbt_hci_event *event; 686 static struct iwmbt_hci_cmd cmd = { 687 .opcode = htole16(0xfc01), 688 .length = 8, 689 .data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }, 690 }; 691 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 692 693 le32enc(cmd.data + 4, boot_param); 694 memset(buf, 0, sizeof(buf)); 695 696 ret = iwmbt_hci_command(hdl, 697 &cmd, 698 buf, 699 sizeof(buf), 700 &transferred, 701 IWMBT_HCI_CMD_TIMEOUT); 702 703 if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) { 704 iwmbt_debug("Intel Reset command failed: code=%d, size=%d", 705 ret, 706 transferred); 707 return (ret); 708 } 709 710 /* expect Vendor Specific Event 0x02 */ 711 event = (struct iwmbt_hci_event *)buf; 712 if (event->header.event != 0xFF || event->data[0] != 0x02) { 713 iwmbt_err("Intel Reset completion event missed"); 714 return (-1); 715 } 716 717 return (0); 718 } 719 720 int 721 iwmbt_load_ddc(struct libusb_device_handle *hdl, 722 const struct iwmbt_firmware *ddc) 723 { 724 int size, sent = 0; 725 int ret, transferred; 726 uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE]; 727 uint8_t evt[IWMBT_HCI_MAX_CMD_SIZE]; 728 struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *)buf; 729 730 size = ddc->len; 731 732 iwmbt_debug("file=%s, size=%d", ddc->fwname, size); 733 734 while (size > 0) { 735 736 memset(buf, 0, sizeof(buf)); 737 cmd->opcode = htole16(0xfc8b); 738 cmd->length = ddc->buf[sent] + 1; 739 memcpy(cmd->data, ddc->buf + sent, XMIN(ddc->buf[sent], size)); 740 741 iwmbt_debug("transferring %d bytes, offset %d", 742 cmd->length, 743 sent); 744 745 size -= cmd->length; 746 sent += cmd->length; 747 748 ret = iwmbt_hci_command(hdl, 749 cmd, 750 evt, 751 sizeof(evt), 752 &transferred, 753 IWMBT_HCI_CMD_TIMEOUT); 754 755 if (ret < 0) { 756 iwmbt_debug("Intel Write DDC failed: code=%d", ret); 757 return (-1); 758 } 759 } 760 761 return (0); 762 } 763 764 int 765 iwmbt_set_event_mask(struct libusb_device_handle *hdl) 766 { 767 int ret, transferred = 0; 768 static struct iwmbt_hci_cmd cmd = { 769 .opcode = htole16(0xfc52), 770 .length = 8, 771 .data = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 772 }; 773 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 774 775 ret = iwmbt_hci_command(hdl, 776 &cmd, 777 buf, 778 sizeof(buf), 779 &transferred, 780 IWMBT_HCI_CMD_TIMEOUT); 781 782 if (ret < 0) 783 iwmbt_debug("Intel Set Event Mask failed: code=%d", ret); 784 785 return (ret); 786 } 787