Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135576259
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
index 05a851f9d85b..1efd24ecf9f6 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
@@ -1,752 +1,786 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
* Copyright (c) 2023 Future Crew LLC.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/endian.h>
#include <sys/stat.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include <libusb.h>
+#include <netgraph/bluetooth/include/ng_hci.h>
+
#include "iwmbt_fw.h"
#include "iwmbt_hw.h"
#include "iwmbt_dbg.h"
#define XMIN(x, y) ((x) < (y) ? (x) : (y))
static int
iwmbt_send_fragment(struct libusb_device_handle *hdl,
uint8_t fragment_type, const void *data, uint8_t len, int timeout)
{
int ret, transferred;
uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE];
struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *) buf;
memset(buf, 0, sizeof(buf));
cmd->opcode = htole16(0xfc09),
cmd->length = len + 1,
cmd->data[0] = fragment_type;
memcpy(cmd->data + 1, data, len);
ret = libusb_bulk_transfer(hdl,
IWMBT_BULK_OUT_ENDPOINT_ADDR,
(uint8_t *)cmd,
IWMBT_HCI_CMD_SIZE(cmd),
&transferred,
timeout);
if (ret < 0 || transferred != (int)IWMBT_HCI_CMD_SIZE(cmd)) {
iwmbt_err("libusb_bulk_transfer() failed: err=%s, size=%zu",
libusb_strerror(ret),
IWMBT_HCI_CMD_SIZE(cmd));
return (-1);
}
ret = libusb_bulk_transfer(hdl,
IWMBT_BULK_IN_ENDPOINT_ADDR,
buf,
sizeof(buf),
&transferred,
timeout);
if (ret < 0) {
iwmbt_err("libusb_bulk_transfer() failed: err=%s",
libusb_strerror(ret));
return (-1);
}
return (0);
}
static int
iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd,
void *event, int size, int *transferred, int timeout)
{
+ struct timespec to, now, remains;
int ret;
ret = libusb_control_transfer(hdl,
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
0,
0,
0,
(uint8_t *)cmd,
IWMBT_HCI_CMD_SIZE(cmd),
timeout);
if (ret < 0) {
iwmbt_err("libusb_control_transfer() failed: err=%s",
libusb_strerror(ret));
return (ret);
}
- ret = libusb_interrupt_transfer(hdl,
- IWMBT_INTERRUPT_ENDPOINT_ADDR,
- event,
- size,
- transferred,
- timeout);
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ to = IWMBT_MSEC2TS(timeout);
+ timespecadd(&to, &now, &to);
- if (ret < 0)
- iwmbt_err("libusb_interrupt_transfer() failed: err=%s",
- libusb_strerror(ret));
+ do {
+ timespecsub(&to, &now, &remains);
+ ret = libusb_interrupt_transfer(hdl,
+ IWMBT_INTERRUPT_ENDPOINT_ADDR,
+ event,
+ size,
+ transferred,
+ IWMBT_TS2MSEC(remains) + 1);
- return (ret);
+ if (ret < 0) {
+ iwmbt_err("libusb_interrupt_transfer() failed: err=%s",
+ libusb_strerror(ret));
+ return (ret);
+ }
+
+ switch (((struct iwmbt_hci_event *)event)->header.event) {
+ case NG_HCI_EVENT_COMMAND_COMPL:
+ if (*transferred <
+ (int)offsetof(struct iwmbt_hci_event_cmd_compl, data))
+ break;
+ if (cmd->opcode !=
+ ((struct iwmbt_hci_event_cmd_compl *)event)->opcode)
+ break;
+ /* FALLTHROUGH */
+ case 0xFF:
+ return (0);
+ default:
+ break;
+ }
+ iwmbt_debug("Stray HCI event: %x",
+ ((struct iwmbt_hci_event *)event)->header.event);
+ } while (timespeccmp(&to, &now, >));
+
+ iwmbt_err("libusb_interrupt_transfer() failed: err=%s",
+ libusb_strerror(LIBUSB_ERROR_TIMEOUT));
+
+ return (LIBUSB_ERROR_TIMEOUT);
}
int
iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw)
{
int ret, transferred;
struct iwmbt_firmware fw_job = *fw;
uint16_t cmd_opcode;
uint8_t cmd_length;
struct iwmbt_hci_cmd *cmd_buf;
uint8_t evt_code;
uint8_t evt_length;
uint8_t evt_buf[IWMBT_HCI_MAX_EVENT_SIZE];
int activate_patch = 0;
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)",
fw_job.buf[0]);
return (-1);
}
/* Advance by one. */
fw_job.buf++;
fw_job.len--;
/* Load in the HCI command to perform. */
cmd_opcode = le16dec(fw_job.buf);
cmd_length = fw_job.buf[2];
cmd_buf = (struct iwmbt_hci_cmd *)fw_job.buf;
iwmbt_debug("opcode=%04x, len=%02x", cmd_opcode, cmd_length);
/*
* 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) {
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.
*/
while (fw_job.len > 0 && fw_job.buf[0] == 0x02) {
/* Is this the end of the file? */
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++;
fw_job.len--;
/* Load in the HCI event. */
evt_code = fw_job.buf[0];
evt_length = fw_job.buf[1];
/* Advance by two. */
fw_job.buf += 2;
fw_job.len -= 2;
/* Prepare HCI event buffer. */
memset(evt_buf, 0, IWMBT_HCI_MAX_EVENT_SIZE);
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;
}
}
return (activate_patch);
}
#define IWMBT_SEND_FRAGMENT(fragment_type, size, msg) do { \
iwmbt_debug("transferring %d bytes, offset %d", size, sent); \
\
ret = iwmbt_send_fragment(hdl, \
fragment_type, \
fw->buf + sent, \
XMIN(size, fw->len - sent), \
IWMBT_HCI_CMD_TIMEOUT); \
\
if (ret < 0) { \
iwmbt_debug("Failed to send "msg": code=%d", ret); \
return (-1); \
} \
sent += size; \
} while (0)
int
iwmbt_load_rsa_header(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw)
{
int ret, sent = 0;
IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment");
IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 1");
IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 2");
/* skip 4 bytes */
sent += 4;
IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 1");
IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 2");
return (0);
}
int
iwmbt_load_ecdsa_header(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw)
{
int ret, sent = ECDSA_OFFSET;
IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment");
IWMBT_SEND_FRAGMENT(0x03, 0x60, "public key");
IWMBT_SEND_FRAGMENT(0x02, 0x60, "signature");
return (0);
}
int
iwmbt_load_fwfile(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw, uint32_t *boot_param, int offset)
{
int ready = 0, sent = offset;
int ret, transferred;
struct iwmbt_hci_cmd *cmd;
struct iwmbt_hci_event *event;
uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
/*
* Send firmware chunks. Chunk len must be 4 byte aligned.
* multiple commands can be combined
*/
while (fw->len - sent - ready >= (int) sizeof(struct iwmbt_hci_cmd)) {
cmd = (struct iwmbt_hci_cmd *)(fw->buf + sent + ready);
/* Parse firmware for Intel Reset HCI command parameter */
if (cmd->opcode == htole16(0xfc0e)) {
*boot_param = le32dec(cmd->data);
iwmbt_debug("boot_param=0x%08x", *boot_param);
}
ready += IWMBT_HCI_CMD_SIZE(cmd);
while (ready >= 0xFC) {
IWMBT_SEND_FRAGMENT(0x01, 0xFC, "firmware chunk");
ready -= 0xFC;
}
if (ready > 0 && ready % 4 == 0) {
IWMBT_SEND_FRAGMENT(0x01, ready, "firmware chunk");
ready = 0;
}
}
/* Wait for firmware download completion event */
ret = libusb_interrupt_transfer(hdl,
IWMBT_INTERRUPT_ENDPOINT_ADDR,
buf,
sizeof(buf),
&transferred,
IWMBT_LOADCMPL_TIMEOUT);
if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) {
iwmbt_err("libusb_interrupt_transfer() failed: "
"err=%s, size=%d",
libusb_strerror(ret),
transferred);
return (-1);
}
/* Expect Vendor Specific Event 0x06 */
event = (struct iwmbt_hci_event *)buf;
if (event->header.event != 0xFF || event->data[0] != 0x06) {
iwmbt_err("firmware download completion event missed");
return (-1);
}
return (0);
}
int
iwmbt_enter_manufacturer(struct libusb_device_handle *hdl)
{
int ret, transferred;
static struct iwmbt_hci_cmd cmd = {
.opcode = htole16(0xfc11),
.length = 2,
.data = { 0x01, 0x00 },
};
uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
ret = iwmbt_hci_command(hdl,
&cmd,
buf,
sizeof(buf),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0) {
iwmbt_debug("Can't enter manufacturer mode: code=%d, size=%d",
ret,
transferred);
return (-1);
}
return (0);
}
int
iwmbt_exit_manufacturer(struct libusb_device_handle *hdl, int mode)
{
int ret, transferred;
static struct iwmbt_hci_cmd cmd = {
.opcode = htole16(0xfc11),
.length = 2,
.data = { 0x00, 0x00 },
};
uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
/*
* The mode sets the type of reset we want to perform:
* 0x00: simply exit manufacturer mode without a reset.
* 0x01: exit manufacturer mode with a reset and patches disabled
* 0x02: exit manufacturer mode with a reset and patches enabled
*/
if (mode > 2) {
iwmbt_debug("iwmbt_exit_manufacturer(): unknown mode (%d)",
mode);
}
cmd.data[1] = mode;
ret = iwmbt_hci_command(hdl,
&cmd,
buf,
sizeof(buf),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0) {
iwmbt_debug("Can't exit manufacturer mode: code=%d, size=%d",
ret,
transferred);
return (-1);
}
return (0);
}
int
iwmbt_get_version(struct libusb_device_handle *hdl,
struct iwmbt_version *version)
{
int ret, transferred;
struct iwmbt_hci_event_cmd_compl*event;
struct iwmbt_hci_cmd cmd = {
.opcode = htole16(0xfc05),
.length = 0,
};
uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_version)];
memset(buf, 0, sizeof(buf));
ret = iwmbt_hci_command(hdl,
&cmd,
buf,
sizeof(buf),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0 || transferred != sizeof(buf)) {
iwmbt_debug("Can't get version: : code=%d, size=%d",
ret,
transferred);
return (-1);
}
event = (struct iwmbt_hci_event_cmd_compl *)buf;
memcpy(version, event->data, sizeof(struct iwmbt_version));
return (0);
}
int
iwmbt_get_version_tlv(struct libusb_device_handle *hdl,
struct iwmbt_version_tlv *version)
{
int ret, transferred;
struct iwmbt_hci_event_cmd_compl *event;
static struct iwmbt_hci_cmd cmd = {
.opcode = htole16(0xfc05),
.length = 1,
.data = { 0xff },
};
uint8_t status, datalen, type, len;
uint8_t *data;
uint8_t buf[255];
memset(buf, 0, sizeof(buf));
ret = iwmbt_hci_command(hdl,
&cmd,
buf,
sizeof(buf),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0 || transferred < (int)IWMBT_HCI_EVT_COMPL_SIZE(uint16_t)) {
iwmbt_debug("Can't get version: code=%d, size=%d",
ret,
transferred);
return (-1);
}
event = (struct iwmbt_hci_event_cmd_compl *)buf;
memcpy(version, event->data, sizeof(struct iwmbt_version));
datalen = event->header.length - IWMBT_HCI_EVENT_COMPL_HEAD_SIZE;
data = event->data;
status = *data++;
if (status != 0)
return (-1);
datalen--;
while (datalen >= 2) {
type = *data++;
len = *data++;
datalen -= 2;
if (datalen < len)
return (-1);
switch (type) {
case IWMBT_TLV_CNVI_TOP:
assert(len == 4);
version->cnvi_top = le32dec(data);
break;
case IWMBT_TLV_CNVR_TOP:
assert(len == 4);
version->cnvr_top = le32dec(data);
break;
case IWMBT_TLV_CNVI_BT:
assert(len == 4);
version->cnvi_bt = le32dec(data);
break;
case IWMBT_TLV_CNVR_BT:
assert(len == 4);
version->cnvr_bt = le32dec(data);
break;
case IWMBT_TLV_DEV_REV_ID:
assert(len == 2);
version->dev_rev_id = le16dec(data);
break;
case IWMBT_TLV_IMAGE_TYPE:
assert(len == 1);
version->img_type = *data;
break;
case IWMBT_TLV_TIME_STAMP:
assert(len == 2);
version->min_fw_build_cw = data[0];
version->min_fw_build_yy = data[1];
version->timestamp = le16dec(data);
break;
case IWMBT_TLV_BUILD_TYPE:
assert(len == 1);
version->build_type = *data;
break;
case IWMBT_TLV_BUILD_NUM:
assert(len == 4);
version->min_fw_build_nn = *data;
version->build_num = le32dec(data);
break;
case IWMBT_TLV_SECURE_BOOT:
assert(len == 1);
version->secure_boot = *data;
break;
case IWMBT_TLV_OTP_LOCK:
assert(len == 1);
version->otp_lock = *data;
break;
case IWMBT_TLV_API_LOCK:
assert(len == 1);
version->api_lock = *data;
break;
case IWMBT_TLV_DEBUG_LOCK:
assert(len == 1);
version->debug_lock = *data;
break;
case IWMBT_TLV_MIN_FW:
assert(len == 3);
version->min_fw_build_nn = data[0];
version->min_fw_build_cw = data[1];
version->min_fw_build_yy = data[2];
break;
case IWMBT_TLV_LIMITED_CCE:
assert(len == 1);
version->limited_cce = *data;
break;
case IWMBT_TLV_SBE_TYPE:
assert(len == 1);
version->sbe_type = *data;
break;
case IWMBT_TLV_OTP_BDADDR:
memcpy(&version->otp_bd_addr, data, sizeof(bdaddr_t));
break;
default:
/* Ignore other types */
break;
}
datalen -= len;
data += len;
}
return (0);
}
int
iwmbt_get_boot_params(struct libusb_device_handle *hdl,
struct iwmbt_boot_params *params)
{
int ret, transferred = 0;
struct iwmbt_hci_event_cmd_compl *event;
struct iwmbt_hci_cmd cmd = {
.opcode = htole16(0xfc0d),
.length = 0,
};
uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_boot_params)];
memset(buf, 0, sizeof(buf));
ret = iwmbt_hci_command(hdl,
&cmd,
buf,
sizeof(buf),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0 || transferred != sizeof(buf)) {
iwmbt_debug("Can't get boot params: code=%d, size=%d",
ret,
transferred);
return (-1);
}
event = (struct iwmbt_hci_event_cmd_compl *)buf;
memcpy(params, event->data, sizeof(struct iwmbt_boot_params));
return (0);
}
int
iwmbt_intel_reset(struct libusb_device_handle *hdl, uint32_t boot_param)
{
int ret, transferred = 0;
struct iwmbt_hci_event *event;
static struct iwmbt_hci_cmd cmd = {
.opcode = htole16(0xfc01),
.length = 8,
.data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 },
};
uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
le32enc(cmd.data + 4, boot_param);
memset(buf, 0, sizeof(buf));
ret = iwmbt_hci_command(hdl,
&cmd,
buf,
sizeof(buf),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) {
iwmbt_debug("Intel Reset command failed: code=%d, size=%d",
ret,
transferred);
return (ret);
}
/* expect Vendor Specific Event 0x02 */
event = (struct iwmbt_hci_event *)buf;
if (event->header.event != 0xFF || event->data[0] != 0x02) {
iwmbt_err("Intel Reset completion event missed");
return (-1);
}
return (0);
}
int
iwmbt_load_ddc(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *ddc)
{
int size, sent = 0;
int ret, transferred;
uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE];
+ uint8_t evt[IWMBT_HCI_MAX_CMD_SIZE];
struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *)buf;
size = ddc->len;
iwmbt_debug("file=%s, size=%d", ddc->fwname, size);
while (size > 0) {
memset(buf, 0, sizeof(buf));
cmd->opcode = htole16(0xfc8b);
cmd->length = ddc->buf[sent] + 1;
memcpy(cmd->data, ddc->buf + sent, XMIN(ddc->buf[sent], size));
iwmbt_debug("transferring %d bytes, offset %d",
cmd->length,
sent);
size -= cmd->length;
sent += cmd->length;
ret = iwmbt_hci_command(hdl,
cmd,
- buf,
- sizeof(buf),
+ evt,
+ sizeof(evt),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0) {
iwmbt_debug("Intel Write DDC failed: code=%d", ret);
return (-1);
}
}
return (0);
}
int
iwmbt_set_event_mask(struct libusb_device_handle *hdl)
{
int ret, transferred = 0;
static struct iwmbt_hci_cmd cmd = {
.opcode = htole16(0xfc52),
.length = 8,
.data = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
};
uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
ret = iwmbt_hci_command(hdl,
&cmd,
buf,
sizeof(buf),
&transferred,
IWMBT_HCI_CMD_TIMEOUT);
if (ret < 0)
iwmbt_debug("Intel Set Event Mask failed: code=%d", ret);
return (ret);
}
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
index 9467c3807a2a..89ee344fe587 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
@@ -1,101 +1,107 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
* Copyright (c) 2023 Future Crew LLC.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __IWMBT_HW_H__
#define __IWMBT_HW_H__
/* USB control request (HCI command) structure */
struct iwmbt_hci_cmd {
uint16_t opcode;
uint8_t length;
uint8_t data[];
} __attribute__ ((packed));
#define IWMBT_HCI_CMD_SIZE(cmd) \
((cmd)->length + offsetof(struct iwmbt_hci_cmd, data))
/* USB interrupt transfer HCI event header structure */
struct iwmbt_hci_evhdr {
uint8_t event;
uint8_t length;
} __attribute__ ((packed));
/* USB interrupt transfer (generic HCI event) structure */
struct iwmbt_hci_event {
struct iwmbt_hci_evhdr header;
uint8_t data[];
} __attribute__ ((packed));
/* USB interrupt transfer (HCI command completion event) structure */
struct iwmbt_hci_event_cmd_compl {
struct iwmbt_hci_evhdr header;
uint8_t numpkt;
uint16_t opcode;
uint8_t data[];
} __attribute__ ((packed));
#define IWMBT_HCI_EVT_COMPL_SIZE(payload) \
(offsetof(struct iwmbt_hci_event_cmd_compl, data) + sizeof(payload))
#define IWMBT_HCI_EVENT_COMPL_HEAD_SIZE \
(offsetof(struct iwmbt_hci_event_cmd_compl, data) - \
offsetof(struct iwmbt_hci_event_cmd_compl, numpkt))
#define IWMBT_CONTROL_ENDPOINT_ADDR 0x00
#define IWMBT_INTERRUPT_ENDPOINT_ADDR 0x81
#define IWMBT_BULK_IN_ENDPOINT_ADDR 0x82
#define IWMBT_BULK_OUT_ENDPOINT_ADDR 0x02
#define IWMBT_HCI_MAX_CMD_SIZE 256
#define IWMBT_HCI_MAX_EVENT_SIZE 16
+#define IWMBT_MSEC2TS(msec) \
+ (struct timespec) { \
+ .tv_sec = (msec) / 1000, \
+ .tv_nsec = ((msec) % 1000) * 1000000 \
+ };
+#define IWMBT_TS2MSEC(ts) ((ts).tv_sec * 1000 + (ts).tv_nsec / 1000000)
#define IWMBT_HCI_CMD_TIMEOUT 2000 /* ms */
#define IWMBT_LOADCMPL_TIMEOUT 5000 /* ms */
extern int iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw);
extern int iwmbt_load_rsa_header(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw);
extern int iwmbt_load_ecdsa_header(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw);
extern int iwmbt_load_fwfile(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw, uint32_t *boot_param, int offset);
extern int iwmbt_enter_manufacturer(struct libusb_device_handle *hdl);
extern int iwmbt_exit_manufacturer(struct libusb_device_handle *hdl,
int mode);
extern int iwmbt_get_version(struct libusb_device_handle *hdl,
struct iwmbt_version *version);
extern int iwmbt_get_version_tlv(struct libusb_device_handle *hdl,
struct iwmbt_version_tlv *version);
extern int iwmbt_get_boot_params(struct libusb_device_handle *hdl,
struct iwmbt_boot_params *params);
extern int iwmbt_intel_reset(struct libusb_device_handle *hdl,
uint32_t boot_param);
extern int iwmbt_load_ddc(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *ddc);
extern int iwmbt_set_event_mask(struct libusb_device_handle *hdl);
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Nov 12, 11:42 PM (9 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25184695
Default Alt Text
(24 KB)
Attached To
Mode
rG FreeBSD src repository
Attached
Detach File
Event Timeline
Log In to Comment