1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/endian.h> 32 #include <sys/stat.h> 33 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 <unistd.h> 41 42 #include <libusb.h> 43 44 #include "iwmbt_fw.h" 45 #include "iwmbt_hw.h" 46 #include "iwmbt_dbg.h" 47 48 #define XMIN(x, y) ((x) < (y) ? (x) : (y)) 49 50 static int 51 iwmbt_send_fragment(struct libusb_device_handle *hdl, 52 uint8_t fragment_type, const void *data, uint8_t len, int timeout) 53 { 54 int ret, transferred; 55 uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE]; 56 struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *) buf; 57 58 memset(buf, 0, sizeof(buf)); 59 cmd->opcode = htole16(0xfc09), 60 cmd->length = len + 1, 61 cmd->data[0] = fragment_type; 62 memcpy(cmd->data + 1, data, len); 63 64 ret = libusb_bulk_transfer(hdl, 65 IWMBT_BULK_OUT_ENDPOINT_ADDR, 66 (uint8_t *)cmd, 67 IWMBT_HCI_CMD_SIZE(cmd), 68 &transferred, 69 timeout); 70 71 if (ret < 0 || transferred != (int)IWMBT_HCI_CMD_SIZE(cmd)) { 72 iwmbt_err("libusb_bulk_transfer() failed: err=%s, size=%zu", 73 libusb_strerror(ret), 74 IWMBT_HCI_CMD_SIZE(cmd)); 75 return (-1); 76 } 77 78 ret = libusb_bulk_transfer(hdl, 79 IWMBT_BULK_IN_ENDPOINT_ADDR, 80 buf, 81 sizeof(buf), 82 &transferred, 83 timeout); 84 85 if (ret < 0) { 86 iwmbt_err("libusb_bulk_transfer() failed: err=%s", 87 libusb_strerror(ret)); 88 return (-1); 89 } 90 91 return (0); 92 } 93 94 static int 95 iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd, 96 void *event, int size, int *transferred, int timeout) 97 { 98 int ret; 99 100 ret = libusb_control_transfer(hdl, 101 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, 102 0, 103 0, 104 0, 105 (uint8_t *)cmd, 106 IWMBT_HCI_CMD_SIZE(cmd), 107 timeout); 108 109 if (ret < 0) { 110 iwmbt_err("libusb_control_transfer() failed: err=%s", 111 libusb_strerror(ret)); 112 return (ret); 113 } 114 115 ret = libusb_interrupt_transfer(hdl, 116 IWMBT_INTERRUPT_ENDPOINT_ADDR, 117 event, 118 size, 119 transferred, 120 timeout); 121 122 if (ret < 0) 123 iwmbt_err("libusb_interrupt_transfer() failed: err=%s", 124 libusb_strerror(ret)); 125 126 return (ret); 127 } 128 129 int 130 iwmbt_patch_fwfile(struct libusb_device_handle *hdl, 131 const struct iwmbt_firmware *fw) 132 { 133 int ret, transferred; 134 struct iwmbt_firmware fw_job = *fw; 135 uint16_t cmd_opcode; 136 uint8_t cmd_length; 137 uint8_t cmd_buf[IWMBT_HCI_MAX_CMD_SIZE]; 138 uint8_t evt_code; 139 uint8_t evt_length; 140 uint8_t evt_buf[IWMBT_HCI_MAX_EVENT_SIZE]; 141 int skip_patch = 0; 142 143 for (;;) { 144 skip_patch = 0; 145 146 if (fw_job.len < 4) 147 break; 148 149 if (fw_job.buf[0] != 0x01) { 150 iwmbt_err("Invalid firmware, expected HCI command (%d)", 151 fw_job.buf[0]); 152 return (-1); 153 } 154 155 /* Advance by one. */ 156 fw_job.buf++; 157 fw_job.len--; 158 159 /* Load in the HCI command to perform. */ 160 cmd_opcode = le16dec(fw_job.buf); 161 cmd_length = fw_job.buf[2]; 162 memcpy(cmd_buf, fw_job.buf, 3); 163 164 iwmbt_debug("opcode=%04x, len=%02x", cmd_opcode, cmd_length); 165 166 /* For some reason the command 0xfc2f hangs up my card. */ 167 if (cmd_opcode == 0xfc2f) 168 skip_patch = 1; 169 170 /* Advance by three. */ 171 fw_job.buf += 3; 172 fw_job.len -= 3; 173 174 if (fw_job.len < cmd_length) 175 cmd_length = fw_job.len; 176 177 /* Copy data to HCI command buffer. */ 178 memcpy(cmd_buf + 3, fw_job.buf, 179 MIN(cmd_length, IWMBT_HCI_MAX_CMD_SIZE - 3)); 180 181 /* Advance by data length. */ 182 fw_job.buf += cmd_length; 183 fw_job.len -= cmd_length; 184 185 /* 186 * Every command has its associated event: data must match 187 * what is recorded in the firmware file. Perform that check 188 * now. 189 * 190 * Some commands are mapped to more than one event sequence, 191 * in that case we can drop the non-patch commands, as we 192 * probably don't need them for operation of the card. 193 * 194 */ 195 196 for (;;) { 197 /* Is this the end of the file? */ 198 if (fw_job.len < 3) 199 break; 200 201 if (fw_job.buf[0] != 0x02) 202 break; 203 204 /* Advance by one. */ 205 fw_job.buf++; 206 fw_job.len--; 207 208 /* Load in the HCI event. */ 209 evt_code = fw_job.buf[0]; 210 evt_length = fw_job.buf[1]; 211 212 /* Advance by two. */ 213 fw_job.buf += 2; 214 fw_job.len -= 2; 215 216 /* Prepare HCI event buffer. */ 217 memset(evt_buf, 0, IWMBT_HCI_MAX_EVENT_SIZE); 218 219 iwmbt_debug("event=%04x, len=%02x", 220 evt_code, evt_length); 221 222 /* Advance by data length. */ 223 fw_job.buf += evt_length; 224 fw_job.len -= evt_length; 225 226 if (skip_patch == 0) { 227 ret = iwmbt_hci_command(hdl, 228 (struct iwmbt_hci_cmd *)cmd_buf, 229 evt_buf, 230 IWMBT_HCI_MAX_EVENT_SIZE, 231 &transferred, 232 IWMBT_HCI_CMD_TIMEOUT); 233 234 if (ret < 0) { 235 iwmbt_debug("Can't send patch: " 236 "code=%d, size=%d", 237 ret, 238 transferred); 239 return (-1); 240 } 241 } 242 } 243 } 244 245 return (0); 246 } 247 248 int 249 iwmbt_load_fwfile(struct libusb_device_handle *hdl, 250 const struct iwmbt_firmware *fw, uint32_t *boot_param) 251 { 252 int ready = 0, sent = 0; 253 int ret, transferred; 254 struct iwmbt_hci_cmd *cmd; 255 struct iwmbt_hci_event *event; 256 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 257 258 #define IWMBT_SEND_FRAGMENT(fragment_type, size, msg) do { \ 259 iwmbt_debug("transferring %d bytes, offset %d", size, sent); \ 260 \ 261 ret = iwmbt_send_fragment(hdl, \ 262 fragment_type, \ 263 fw->buf + sent, \ 264 XMIN(size, fw->len - sent), \ 265 IWMBT_HCI_CMD_TIMEOUT); \ 266 \ 267 if (ret < 0) { \ 268 iwmbt_debug("Failed to send "msg": code=%d", ret); \ 269 return (-1); \ 270 } \ 271 sent += size; \ 272 } while (0) 273 274 if (fw->len < 644) { 275 iwmbt_err("Invalid size of firmware file (%d)", fw->len); 276 return (-1); 277 } 278 279 iwmbt_debug("file=%s, size=%d", fw->fwname, fw->len); 280 281 IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment"); 282 IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 1"); 283 IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 2"); 284 285 /* skip 4 bytes */ 286 sent += 4; 287 288 IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 1"); 289 IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 2"); 290 291 /* 292 * Send firmware chunks. Chunk len must be 4 byte aligned. 293 * multiple commands can be combined 294 */ 295 while (fw->len - sent - ready >= (int) sizeof(struct iwmbt_hci_cmd)) { 296 cmd = (struct iwmbt_hci_cmd *)(fw->buf + sent + ready); 297 /* Parse firmware for Intel Reset HCI command parameter */ 298 if (cmd->opcode == htole16(0xfc0e)) { 299 *boot_param = le32dec(cmd->data); 300 iwmbt_debug("boot_param=0x%08x", *boot_param); 301 } 302 ready += IWMBT_HCI_CMD_SIZE(cmd); 303 while (ready >= 0xFC) { 304 IWMBT_SEND_FRAGMENT(0x01, 0xFC, "firmware chunk"); 305 ready -= 0xFC; 306 } 307 if (ready > 0 && ready % 4 == 0) { 308 IWMBT_SEND_FRAGMENT(0x01, ready, "firmware chunk"); 309 ready = 0; 310 } 311 } 312 313 /* Wait for firmware download completion event */ 314 ret = libusb_interrupt_transfer(hdl, 315 IWMBT_INTERRUPT_ENDPOINT_ADDR, 316 buf, 317 sizeof(buf), 318 &transferred, 319 IWMBT_LOADCMPL_TIMEOUT); 320 321 if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) { 322 iwmbt_err("libusb_interrupt_transfer() failed: " 323 "err=%s, size=%d", 324 libusb_strerror(ret), 325 transferred); 326 return (-1); 327 } 328 329 /* Expect Vendor Specific Event 0x06 */ 330 event = (struct iwmbt_hci_event *)buf; 331 if (event->header.event != 0xFF || event->data[0] != 0x06) { 332 iwmbt_err("firmware download completion event missed"); 333 return (-1); 334 } 335 336 return (0); 337 } 338 339 int 340 iwmbt_enter_manufacturer(struct libusb_device_handle *hdl) 341 { 342 int ret, transferred; 343 static struct iwmbt_hci_cmd cmd = { 344 .opcode = htole16(0xfc11), 345 .length = 2, 346 .data = { 0x01, 0x00 }, 347 }; 348 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 349 350 ret = iwmbt_hci_command(hdl, 351 &cmd, 352 buf, 353 sizeof(buf), 354 &transferred, 355 IWMBT_HCI_CMD_TIMEOUT); 356 357 if (ret < 0) { 358 iwmbt_debug("Can't enter manufacturer mode: code=%d, size=%d", 359 ret, 360 transferred); 361 return (-1); 362 } 363 364 return (0); 365 } 366 367 int 368 iwmbt_exit_manufacturer(struct libusb_device_handle *hdl, int mode) 369 { 370 int ret, transferred; 371 static struct iwmbt_hci_cmd cmd = { 372 .opcode = htole16(0xfc11), 373 .length = 2, 374 .data = { 0x00, 0x00 }, 375 }; 376 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 377 378 /* 379 * The mode sets the type of reset we want to perform: 380 * 0x00: simply exit manufacturer mode without a reset. 381 * 0x01: exit manufacturer mode with a reset and patches disabled 382 * 0x02: exit manufacturer mode with a reset and patches enabled 383 */ 384 if (mode > 2) { 385 iwmbt_debug("iwmbt_exit_manufacturer(): unknown mode (%d)", 386 mode); 387 } 388 cmd.data[1] = mode; 389 390 ret = iwmbt_hci_command(hdl, 391 &cmd, 392 buf, 393 sizeof(buf), 394 &transferred, 395 IWMBT_HCI_CMD_TIMEOUT); 396 397 if (ret < 0) { 398 iwmbt_debug("Can't exit manufacturer mode: code=%d, size=%d", 399 ret, 400 transferred); 401 return (-1); 402 } 403 404 return (0); 405 } 406 407 int 408 iwmbt_get_version(struct libusb_device_handle *hdl, 409 struct iwmbt_version *version) 410 { 411 int ret, transferred; 412 struct iwmbt_hci_event_cmd_compl*event; 413 struct iwmbt_hci_cmd cmd = { 414 .opcode = htole16(0xfc05), 415 .length = 0, 416 }; 417 uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_version)]; 418 419 memset(buf, 0, sizeof(buf)); 420 421 ret = iwmbt_hci_command(hdl, 422 &cmd, 423 buf, 424 sizeof(buf), 425 &transferred, 426 IWMBT_HCI_CMD_TIMEOUT); 427 428 if (ret < 0 || transferred != sizeof(buf)) { 429 iwmbt_debug("Can't get version: : code=%d, size=%d", 430 ret, 431 transferred); 432 return (-1); 433 } 434 435 event = (struct iwmbt_hci_event_cmd_compl *)buf; 436 memcpy(version, event->data, sizeof(struct iwmbt_version)); 437 438 return (0); 439 } 440 441 int 442 iwmbt_get_boot_params(struct libusb_device_handle *hdl, 443 struct iwmbt_boot_params *params) 444 { 445 int ret, transferred = 0; 446 struct iwmbt_hci_event_cmd_compl *event; 447 struct iwmbt_hci_cmd cmd = { 448 .opcode = htole16(0xfc0d), 449 .length = 0, 450 }; 451 uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_boot_params)]; 452 453 memset(buf, 0, sizeof(buf)); 454 455 ret = iwmbt_hci_command(hdl, 456 &cmd, 457 buf, 458 sizeof(buf), 459 &transferred, 460 IWMBT_HCI_CMD_TIMEOUT); 461 462 if (ret < 0 || transferred != sizeof(buf)) { 463 iwmbt_debug("Can't get boot params: code=%d, size=%d", 464 ret, 465 transferred); 466 return (-1); 467 } 468 469 event = (struct iwmbt_hci_event_cmd_compl *)buf; 470 memcpy(params, event->data, sizeof(struct iwmbt_boot_params)); 471 472 return (0); 473 } 474 475 int 476 iwmbt_intel_reset(struct libusb_device_handle *hdl, uint32_t boot_param) 477 { 478 int ret, transferred = 0; 479 struct iwmbt_hci_event *event; 480 static struct iwmbt_hci_cmd cmd = { 481 .opcode = htole16(0xfc01), 482 .length = 8, 483 .data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }, 484 }; 485 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 486 487 le32enc(cmd.data + 4, boot_param); 488 memset(buf, 0, sizeof(buf)); 489 490 ret = iwmbt_hci_command(hdl, 491 &cmd, 492 buf, 493 sizeof(buf), 494 &transferred, 495 IWMBT_HCI_CMD_TIMEOUT); 496 497 if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) { 498 iwmbt_debug("Intel Reset command failed: code=%d, size=%d", 499 ret, 500 transferred); 501 return (ret); 502 } 503 504 /* expect Vendor Specific Event 0x02 */ 505 event = (struct iwmbt_hci_event *)buf; 506 if (event->header.event != 0xFF || event->data[0] != 0x02) { 507 iwmbt_err("Intel Reset completion event missed"); 508 return (-1); 509 } 510 511 return (0); 512 } 513 514 int 515 iwmbt_load_ddc(struct libusb_device_handle *hdl, 516 const struct iwmbt_firmware *ddc) 517 { 518 int size, sent = 0; 519 int ret, transferred; 520 uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE]; 521 struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *)buf; 522 523 size = ddc->len; 524 525 iwmbt_debug("file=%s, size=%d", ddc->fwname, size); 526 527 while (size > 0) { 528 529 memset(buf, 0, sizeof(buf)); 530 cmd->opcode = htole16(0xfc8b); 531 cmd->length = ddc->buf[sent] + 1; 532 memcpy(cmd->data, ddc->buf + sent, XMIN(ddc->buf[sent], size)); 533 534 iwmbt_debug("transferring %d bytes, offset %d", 535 cmd->length, 536 sent); 537 538 size -= cmd->length; 539 sent += cmd->length; 540 541 ret = iwmbt_hci_command(hdl, 542 cmd, 543 buf, 544 sizeof(buf), 545 &transferred, 546 IWMBT_HCI_CMD_TIMEOUT); 547 548 if (ret < 0) { 549 iwmbt_debug("Intel Write DDC failed: code=%d", ret); 550 return (-1); 551 } 552 } 553 554 return (0); 555 } 556 557 int 558 iwmbt_set_event_mask(struct libusb_device_handle *hdl) 559 { 560 int ret, transferred = 0; 561 static struct iwmbt_hci_cmd cmd = { 562 .opcode = htole16(0xfc52), 563 .length = 8, 564 .data = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 565 }; 566 uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; 567 568 ret = iwmbt_hci_command(hdl, 569 &cmd, 570 buf, 571 sizeof(buf), 572 &transferred, 573 IWMBT_HCI_CMD_TIMEOUT); 574 575 if (ret < 0) 576 iwmbt_debug("Intel Set Event Mask failed: code=%d", ret); 577 578 return (ret); 579 } 580