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, 441 enum iwmbt_mm_exit mode) 442 { 443 int ret, transferred; 444 static struct iwmbt_hci_cmd cmd = { 445 .opcode = htole16(0xfc11), 446 .length = 2, 447 .data = { 0x00, 0x00 }, 448 }; 449 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 450 451 cmd.data[1] = (uint8_t)mode; 452 453 ret = iwmbt_hci_command(hdl, 454 &cmd, 455 buf, 456 sizeof(buf), 457 &transferred, 458 IWMBT_HCI_CMD_TIMEOUT); 459 460 if (ret < 0) { 461 iwmbt_debug("Can't exit manufacturer mode: code=%d, size=%d", 462 ret, 463 transferred); 464 return (-1); 465 } 466 467 return (0); 468 } 469 470 int 471 iwmbt_get_version(struct libusb_device_handle *hdl, 472 struct iwmbt_version *version) 473 { 474 int ret, transferred; 475 struct iwmbt_hci_event_cmd_compl*event; 476 struct iwmbt_hci_cmd cmd = { 477 .opcode = htole16(0xfc05), 478 .length = 0, 479 }; 480 uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_version)]; 481 482 memset(buf, 0, sizeof(buf)); 483 484 ret = iwmbt_hci_command(hdl, 485 &cmd, 486 buf, 487 sizeof(buf), 488 &transferred, 489 IWMBT_HCI_CMD_TIMEOUT); 490 491 if (ret < 0 || transferred != sizeof(buf)) { 492 iwmbt_debug("Can't get version: : code=%d, size=%d", 493 ret, 494 transferred); 495 return (-1); 496 } 497 498 event = (struct iwmbt_hci_event_cmd_compl *)buf; 499 memcpy(version, event->data, sizeof(struct iwmbt_version)); 500 501 return (0); 502 } 503 504 int 505 iwmbt_get_version_tlv(struct libusb_device_handle *hdl, 506 struct iwmbt_version_tlv *version) 507 { 508 int ret, transferred; 509 struct iwmbt_hci_event_cmd_compl *event; 510 static struct iwmbt_hci_cmd cmd = { 511 .opcode = htole16(0xfc05), 512 .length = 1, 513 .data = { 0xff }, 514 }; 515 uint8_t status, datalen, type, len; 516 uint8_t *data; 517 uint8_t buf[255]; 518 519 memset(buf, 0, sizeof(buf)); 520 521 ret = iwmbt_hci_command(hdl, 522 &cmd, 523 buf, 524 sizeof(buf), 525 &transferred, 526 IWMBT_HCI_CMD_TIMEOUT); 527 528 if (ret < 0 || transferred < (int)IWMBT_HCI_EVT_COMPL_SIZE(uint16_t)) { 529 iwmbt_debug("Can't get version: code=%d, size=%d", 530 ret, 531 transferred); 532 return (-1); 533 } 534 535 event = (struct iwmbt_hci_event_cmd_compl *)buf; 536 memcpy(version, event->data, sizeof(struct iwmbt_version)); 537 538 datalen = event->header.length - IWMBT_HCI_EVENT_COMPL_HEAD_SIZE; 539 data = event->data; 540 status = *data++; 541 if (status != 0) 542 return (-1); 543 datalen--; 544 545 while (datalen >= 2) { 546 type = *data++; 547 len = *data++; 548 datalen -= 2; 549 550 if (datalen < len) 551 return (-1); 552 553 switch (type) { 554 case IWMBT_TLV_CNVI_TOP: 555 assert(len == 4); 556 version->cnvi_top = le32dec(data); 557 break; 558 case IWMBT_TLV_CNVR_TOP: 559 assert(len == 4); 560 version->cnvr_top = le32dec(data); 561 break; 562 case IWMBT_TLV_CNVI_BT: 563 assert(len == 4); 564 version->cnvi_bt = le32dec(data); 565 break; 566 case IWMBT_TLV_CNVR_BT: 567 assert(len == 4); 568 version->cnvr_bt = le32dec(data); 569 break; 570 case IWMBT_TLV_DEV_REV_ID: 571 assert(len == 2); 572 version->dev_rev_id = le16dec(data); 573 break; 574 case IWMBT_TLV_IMAGE_TYPE: 575 assert(len == 1); 576 version->img_type = *data; 577 break; 578 case IWMBT_TLV_TIME_STAMP: 579 assert(len == 2); 580 version->min_fw_build_cw = data[0]; 581 version->min_fw_build_yy = data[1]; 582 version->timestamp = le16dec(data); 583 break; 584 case IWMBT_TLV_BUILD_TYPE: 585 assert(len == 1); 586 version->build_type = *data; 587 break; 588 case IWMBT_TLV_BUILD_NUM: 589 assert(len == 4); 590 version->min_fw_build_nn = *data; 591 version->build_num = le32dec(data); 592 break; 593 case IWMBT_TLV_SECURE_BOOT: 594 assert(len == 1); 595 version->secure_boot = *data; 596 break; 597 case IWMBT_TLV_OTP_LOCK: 598 assert(len == 1); 599 version->otp_lock = *data; 600 break; 601 case IWMBT_TLV_API_LOCK: 602 assert(len == 1); 603 version->api_lock = *data; 604 break; 605 case IWMBT_TLV_DEBUG_LOCK: 606 assert(len == 1); 607 version->debug_lock = *data; 608 break; 609 case IWMBT_TLV_MIN_FW: 610 assert(len == 3); 611 version->min_fw_build_nn = data[0]; 612 version->min_fw_build_cw = data[1]; 613 version->min_fw_build_yy = data[2]; 614 break; 615 case IWMBT_TLV_LIMITED_CCE: 616 assert(len == 1); 617 version->limited_cce = *data; 618 break; 619 case IWMBT_TLV_SBE_TYPE: 620 assert(len == 1); 621 version->sbe_type = *data; 622 break; 623 case IWMBT_TLV_OTP_BDADDR: 624 memcpy(&version->otp_bd_addr, data, sizeof(bdaddr_t)); 625 break; 626 default: 627 /* Ignore other types */ 628 break; 629 } 630 631 datalen -= len; 632 data += len; 633 } 634 635 return (0); 636 } 637 638 int 639 iwmbt_get_boot_params(struct libusb_device_handle *hdl, 640 struct iwmbt_boot_params *params) 641 { 642 int ret, transferred = 0; 643 struct iwmbt_hci_event_cmd_compl *event; 644 struct iwmbt_hci_cmd cmd = { 645 .opcode = htole16(0xfc0d), 646 .length = 0, 647 }; 648 uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_boot_params)]; 649 650 memset(buf, 0, sizeof(buf)); 651 652 ret = iwmbt_hci_command(hdl, 653 &cmd, 654 buf, 655 sizeof(buf), 656 &transferred, 657 IWMBT_HCI_CMD_TIMEOUT); 658 659 if (ret < 0 || transferred != sizeof(buf)) { 660 iwmbt_debug("Can't get boot params: code=%d, size=%d", 661 ret, 662 transferred); 663 return (-1); 664 } 665 666 event = (struct iwmbt_hci_event_cmd_compl *)buf; 667 memcpy(params, event->data, sizeof(struct iwmbt_boot_params)); 668 669 return (0); 670 } 671 672 int 673 iwmbt_intel_reset(struct libusb_device_handle *hdl, uint32_t boot_param) 674 { 675 int ret, transferred = 0; 676 struct iwmbt_hci_event *event; 677 static struct iwmbt_hci_cmd cmd = { 678 .opcode = htole16(0xfc01), 679 .length = 8, 680 .data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }, 681 }; 682 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 683 684 le32enc(cmd.data + 4, boot_param); 685 memset(buf, 0, sizeof(buf)); 686 687 ret = iwmbt_hci_command(hdl, 688 &cmd, 689 buf, 690 sizeof(buf), 691 &transferred, 692 IWMBT_HCI_CMD_TIMEOUT); 693 694 if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) { 695 iwmbt_debug("Intel Reset command failed: code=%d, size=%d", 696 ret, 697 transferred); 698 return (ret); 699 } 700 701 /* expect Vendor Specific Event 0x02 */ 702 event = (struct iwmbt_hci_event *)buf; 703 if (event->header.event != 0xFF || event->data[0] != 0x02) { 704 iwmbt_err("Intel Reset completion event missed"); 705 return (-1); 706 } 707 708 return (0); 709 } 710 711 int 712 iwmbt_load_ddc(struct libusb_device_handle *hdl, 713 const struct iwmbt_firmware *ddc) 714 { 715 int size, sent = 0; 716 int ret, transferred; 717 uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE]; 718 uint8_t evt[IWMBT_HCI_MAX_CMD_SIZE]; 719 struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *)buf; 720 721 size = ddc->len; 722 723 iwmbt_debug("file=%s, size=%d", ddc->fwname, size); 724 725 while (size > 0) { 726 727 memset(buf, 0, sizeof(buf)); 728 cmd->opcode = htole16(0xfc8b); 729 cmd->length = ddc->buf[sent] + 1; 730 memcpy(cmd->data, ddc->buf + sent, XMIN(ddc->buf[sent], size)); 731 732 iwmbt_debug("transferring %d bytes, offset %d", 733 cmd->length, 734 sent); 735 736 size -= cmd->length; 737 sent += cmd->length; 738 739 ret = iwmbt_hci_command(hdl, 740 cmd, 741 evt, 742 sizeof(evt), 743 &transferred, 744 IWMBT_HCI_CMD_TIMEOUT); 745 746 if (ret < 0) { 747 iwmbt_debug("Intel Write DDC failed: code=%d", ret); 748 return (-1); 749 } 750 } 751 752 return (0); 753 } 754 755 int 756 iwmbt_set_event_mask(struct libusb_device_handle *hdl) 757 { 758 int ret, transferred = 0; 759 static struct iwmbt_hci_cmd cmd = { 760 .opcode = htole16(0xfc52), 761 .length = 8, 762 .data = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 763 }; 764 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 765 766 ret = iwmbt_hci_command(hdl, 767 &cmd, 768 buf, 769 sizeof(buf), 770 &transferred, 771 IWMBT_HCI_CMD_TIMEOUT); 772 773 if (ret < 0) 774 iwmbt_debug("Intel Set Event Mask failed: code=%d", ret); 775 776 return (ret); 777 } 778