Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f5a83593 authored by Himanshu Rawat's avatar Himanshu Rawat Committed by Automerger Merge Worker
Browse files

Merge "Support Get Report and Set Report procedures" am: 916a8e56 am: d989c6da am: fe30c4f0

parents 8482afb6 fe30c4f0
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -659,9 +659,6 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
      bta_hh.hs_data.status = bta_hh_get_trans_status(p_data->hid_cback.data);
      if (bta_hh.hs_data.status == BTA_HH_OK)
        bta_hh.hs_data.status = BTA_HH_HS_TRANS_NOT_SPT;
      if (p_cb->w4_evt == BTA_HH_GET_RPT_EVT)
        bta_hh_co_get_rpt_rsp(bta_hh.dev_status.handle, bta_hh.hs_data.status,
                              NULL, 0);
      (*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
      p_cb->w4_evt = 0;
      break;
@@ -673,9 +670,6 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
      bta_hh.dev_status.handle = p_cb->hid_handle;
      bta_hh.dev_status.status =
          bta_hh_get_trans_status(p_data->hid_cback.data);
      if (p_cb->w4_evt == BTA_HH_SET_RPT_EVT)
        bta_hh_co_set_rpt_rsp(bta_hh.dev_status.handle,
                              bta_hh.dev_status.status);
      (*bta_hh_cb.p_cback)(p_cb->w4_evt, &bta_hh);
      p_cb->w4_evt = 0;
      break;
@@ -732,8 +726,6 @@ void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, const tBTA_HH_DATA* p_data) {
      break;
    case BTA_HH_GET_RPT_EVT:
      hs_data.rsp_data.p_rpt_data = pdata;
      bta_hh_co_get_rpt_rsp(hs_data.handle, hs_data.status, pdata->data,
                            pdata->len);
      break;
    case BTA_HH_GET_PROTO_EVT:
      /* match up BTE/BTA report/boot mode def*/
+25 −29
Original line number Diff line number Diff line
@@ -1726,56 +1726,53 @@ void bta_hh_le_api_disc_act(tBTA_HH_DEV_CB* p_cb) {
static void read_report_cb(uint16_t conn_id, tGATT_STATUS status,
                           uint16_t handle, uint16_t len, uint8_t* value,
                           void* data) {
  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
  if (p_dev_cb->w4_evt != BTA_HH_GET_RPT_EVT) {
    LOG_WARN("Unexpected Read response, w4_evt = %d", p_dev_cb->w4_evt);
    return;
  }

  const gatt::Characteristic* p_char =
      BTA_GATTC_GetCharacteristic(conn_id, handle);

  if (p_char == NULL) return;

  uint16_t char_uuid = p_char->uuid.As16Bit();

  if (char_uuid != GATT_UUID_HID_REPORT &&
      char_uuid != GATT_UUID_HID_BT_KB_INPUT &&
      char_uuid != GATT_UUID_HID_BT_KB_OUTPUT &&
      char_uuid != GATT_UUID_HID_BT_MOUSE_INPUT &&
      char_uuid != GATT_UUID_BATTERY_LEVEL) {
    APPL_TRACE_ERROR("%s: Unexpected Read UUID: 0x%04x", __func__, char_uuid);
  if (p_char == nullptr) {
    LOG_ERROR("Unknown handle");
    return;
  }

  tBTA_HH_DEV_CB* p_dev_cb = (tBTA_HH_DEV_CB*)data;
  if (p_dev_cb->w4_evt != BTA_HH_GET_RPT_EVT) {
    APPL_TRACE_ERROR("Unexpected READ cmpl, w4_evt = %d", p_dev_cb->w4_evt);
  uint16_t char_uuid = p_char->uuid.As16Bit();
  switch (char_uuid) {
    case GATT_UUID_HID_REPORT:
    case GATT_UUID_HID_BT_KB_INPUT:
    case GATT_UUID_HID_BT_KB_OUTPUT:
    case GATT_UUID_HID_BT_MOUSE_INPUT:
    case GATT_UUID_BATTERY_LEVEL:
      break;
    default:
      LOG_ERROR("Unexpected Read UUID: 0x%04x", char_uuid);
      return;
  }

  /* GET_REPORT */
  BT_HDR* p_buf = NULL;
  tBTA_HH_LE_RPT* p_rpt;
  tBTA_HH_HSDATA hs_data;
  uint8_t* pp;

  memset(&hs_data, 0, sizeof(hs_data));
  tBTA_HH_HSDATA hs_data = {};
  hs_data.status = BTA_HH_ERR;
  hs_data.handle = p_dev_cb->hid_handle;

  if (status == GATT_SUCCESS) {
    tBTA_HH_LE_RPT* p_rpt;
    const gatt::Service* p_svc =
        BTA_GATTC_GetOwningService(conn_id, p_char->value_handle);

    p_rpt = bta_hh_le_find_report_entry(p_dev_cb, p_svc->handle, char_uuid,
                                        p_char->value_handle);

    if (p_rpt != NULL && len) {
      p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + len + 1);
    if (p_rpt != nullptr && len) {
      BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + len + 1);
      /* pack data send to app */
      hs_data.status = BTA_HH_OK;
      p_buf->len = len + 1;
      p_buf->layer_specific = 0;
      p_buf->offset = 0;

      uint8_t* pp = (uint8_t*)(p_buf + 1);
      /* attach report ID as the first byte of the report before sending it to
       * USB HID driver */
      pp = (uint8_t*)(p_buf + 1);
      UINT8_TO_STREAM(pp, p_rpt->rpt_id);
      memcpy(pp, value, len);

@@ -1785,8 +1782,7 @@ static void read_report_cb(uint16_t conn_id, tGATT_STATUS status,

  p_dev_cb->w4_evt = 0;
  (*bta_hh_cb.p_cback)(BTA_HH_GET_RPT_EVT, (tBTA_HH*)&hs_data);

  osi_free_and_reset((void**)&p_buf);
  osi_free(hs_data.rsp_data.p_rpt_data);
}

/*******************************************************************************
+1 −1
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ extern void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status);
 *
 ******************************************************************************/
extern void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status,
                                  uint8_t* p_rpt, uint16_t len);
                                  const uint8_t* p_rpt, uint16_t len);

/*******************************************************************************
 *
+1 −2
Original line number Diff line number Diff line
@@ -104,6 +104,5 @@ TEST_F(BtaHhTest, bta_hh_ctrl_dat_act__BTA_HH_GET_RPT_EVT) {
  };

  bta_hh_ctrl_dat_act(&cb, &data);

  ASSERT_EQ(get_func_call_count("bta_hh_co_get_rpt_rsp"), 1);
  ASSERT_EQ(cb.w4_evt, 0);
}
+136 −100
Original line number Diff line number Diff line
@@ -45,11 +45,13 @@ const char* dev_path = "/dev/uhid";
#include "btif_config.h"
#define BTA_HH_NV_LOAD_MAX 16
static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
#define GET_RPT_RSP_OFFSET 9
#define BTA_HH_CACHE_REPORT_VERSION 1
#define THREAD_NORMAL_PRIORITY 0
#define BT_HH_THREAD "bt_hh_thread"

static const bthh_report_type_t map_rtype_uhid_hh[] = {
    BTHH_FEATURE_REPORT, BTHH_OUTPUT_REPORT, BTHH_INPUT_REPORT};

void uhid_set_non_blocking(int fd) {
  int opts = fcntl(fd, F_GETFL);
  if (opts < 0)
@@ -63,6 +65,62 @@ void uhid_set_non_blocking(int fd) {
                     strerror(errno));
}

static bool uhid_feature_req_handler(btif_hh_device_t* p_dev,
                                     struct uhid_feature_req& req) {
  LOG_DEBUG("Report type = %d, id = %d", req.rtype, req.rnum);

  if (req.rtype > UHID_INPUT_REPORT) {
    LOG_ERROR("Invalid report type %d", req.rtype);
    return false;
  }

  if (p_dev->get_rpt_id_queue == nullptr) {
    LOG_ERROR("Queue is not initialized");
    return false;
  }

  uint32_t* context = (uint32_t*)osi_malloc(sizeof(uint32_t));
  *context = req.id;

  if (!fixed_queue_try_enqueue(p_dev->get_rpt_id_queue, (void*)context)) {
    osi_free(context);
    LOG_ERROR("Queue is full, dropping event %d", req.id);
    return false;
  }

  btif_hh_getreport(p_dev, map_rtype_uhid_hh[req.rtype], req.rnum, 0);
  return true;
}

#if ENABLE_UHID_SET_REPORT
static bool uhid_set_report_req_handler(btif_hh_device_t* p_dev,
                                        struct uhid_set_report_req& req) {
  LOG_DEBUG("Report type = %d, id = %d", req.rtype, req.rnum);

  if (req.rtype > UHID_INPUT_REPORT) {
    LOG_ERROR("Invalid report type %d", req.rtype);
    return false;
  }

  if (p_dev->set_rpt_id_queue == nullptr) {
    LOG_ERROR("Queue is not initialized");
    return false;
  }

  uint32_t* context = (uint32_t*)osi_malloc(sizeof(uint32_t));
  *context = req.id;

  if (!fixed_queue_try_enqueue(p_dev->set_rpt_id_queue, (void*)context)) {
    osi_free(context);
    LOG_ERROR("Queue is full, dropping event %d", req.id);
    return false;
  }

  btif_hh_setreport(p_dev, map_rtype_uhid_hh[req.rtype], req.size, req.data);
  return true;
}
#endif  // ENABLE_UHID_SET_REPORT

/*Internal function to perform UHID write and error checking*/
static int uhid_write(int fd, const struct uhid_event* ev) {
  ssize_t ret;
@@ -146,74 +204,37 @@ static int uhid_read_event(btif_hh_device_t* p_dev) {
      }
      APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
      break;
    case UHID_FEATURE:

    case UHID_FEATURE:  // UHID_GET_REPORT
      if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.feature))) {
        APPL_TRACE_ERROR(
            "%s: UHID_FEATURE: Invalid size read from uhid-dev: %zd < %zu",
            __func__, ret, sizeof(ev.type) + sizeof(ev.u.feature));
        LOG_ERROR("UHID_GET_REPORT: Invalid size read from uhid-dev: %zd < %zu",
                  ret, sizeof(ev.type) + sizeof(ev.u.feature));
        return -EFAULT;
      }
      APPL_TRACE_DEBUG("UHID_FEATURE: Report type = %d", ev.u.feature.rtype);
      p_dev->get_rpt_snt++;
      if (p_dev->get_rpt_id_queue) {
        uint32_t* get_rpt_id = (uint32_t*)osi_malloc(sizeof(uint32_t));
        *get_rpt_id = ev.u.feature.id;
        auto ok = fixed_queue_try_enqueue(p_dev->get_rpt_id_queue, (void*)get_rpt_id);
        if (!ok) {
            LOG_ERROR("get_rpt_id_queue is full, dropping event %d", *get_rpt_id);
            osi_free(get_rpt_id);

      if (!uhid_feature_req_handler(p_dev, ev.u.feature)) {
        return -EFAULT;
      }
      }
      if (ev.u.feature.rtype == UHID_FEATURE_REPORT)
        btif_hh_getreport(p_dev, BTHH_FEATURE_REPORT, ev.u.feature.rnum, 0);
      else
        APPL_TRACE_ERROR("%s: UHID_FEATURE: Invalid report type = %d", __func__,
                         ev.u.feature.rtype);

      break;

#if ENABLE_UHID_SET_REPORT
    case UHID_SET_REPORT: {
      bool sent = true;

      if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.set_report))) {
        LOG_ERROR("Invalid size read from uhid-dev: %zd < %zu", ret,
                  sizeof(ev.type) + sizeof(ev.u.set_report));
        LOG_ERROR("UHID_SET_REPORT: Invalid size read from uhid-dev: %zd < %zu",
                  ret, sizeof(ev.type) + sizeof(ev.u.set_report));
        return -EFAULT;
      }

      LOG_DEBUG("UHID_SET_REPORT: Report type = %d, report_size = %d",
                ev.u.set_report.rtype, ev.u.set_report.size);

      if (ev.u.set_report.rtype == UHID_FEATURE_REPORT) {
        btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT, ev.u.set_report.size,
                          ev.u.set_report.data);
      } else if (ev.u.set_report.rtype == UHID_OUTPUT_REPORT) {
        btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT, ev.u.set_report.size,
                          ev.u.set_report.data);
      } else if (ev.u.set_report.rtype == UHID_INPUT_REPORT) {
        btif_hh_setreport(p_dev, BTHH_INPUT_REPORT, ev.u.set_report.size,
                          ev.u.set_report.data);
      } else {
        LOG_ERROR("UHID_SET_REPORT: Invalid Report type = %d",
                  ev.u.set_report.rtype);
        sent = false;
      }

      if (sent && p_dev->set_rpt_id_queue) {
        uint32_t* set_rpt_id = (uint32_t*)osi_malloc(sizeof(uint32_t));
        *set_rpt_id = ev.u.set_report.id;
        auto ok = fixed_queue_try_enqueue(p_dev->set_rpt_id_queue, (void*)set_rpt_id);
        if (!ok) {
            LOG_ERROR("set_rpt_id_queue is full, dropping event %d", *set_rpt_id);
            osi_free(set_rpt_id);
      if (!uhid_set_report_req_handler(p_dev, ev.u.set_report)) {
        return -EFAULT;
      }
      }
      break;
    }
#endif  // ENABLE_UHID_SET_REPORT

    default:
      APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
      LOG_ERROR("Invalid event from uhid-dev: %u\n", ev.type);
  }

  return 0;
@@ -612,33 +633,42 @@ void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status) {

  btif_hh_device_t* p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
  if (p_dev == nullptr) {
    LOG_WARN("Error: unknown HID device handle %d", dev_handle);
    LOG_WARN("Unknown HID device handle %d", dev_handle);
    return;
  }

  if (!p_dev->set_rpt_id_queue) {
    LOG_WARN("Error: missing UHID_SET_REPORT id queue");
    LOG_WARN("Missing UHID_SET_REPORT id queue");
    return;
  }

  // Send the HID set report reply to the kernel.
  if (p_dev->fd >= 0) {
    uint32_t* set_rpt_id =
        (uint32_t*)fixed_queue_try_dequeue(p_dev->set_rpt_id_queue);
    if (set_rpt_id) {
      struct uhid_event ev = {};

      ev.type = UHID_SET_REPORT_REPLY;
      ev.u.set_report_reply.id = *set_rpt_id;
      ev.u.set_report_reply.err = status;
      osi_free(set_rpt_id);
      uhid_write(p_dev->fd, &ev);
    } else {
      LOG_VERBOSE("No pending UHID_SET_REPORT");
  if (p_dev->fd < 0) {
    LOG_ERROR("Unexpected Set Report response");
    return;
  }

  uint32_t* context = (uint32_t*)fixed_queue_try_dequeue(p_dev->set_rpt_id_queue);

  if (context == nullptr) {
    LOG_WARN("No pending UHID_SET_REPORT");
    return;
  }

  struct uhid_event ev = {
      .type = UHID_SET_REPORT_REPLY,
      .u = {
          .set_report_reply = {
              .id = *context,
              .err = status,
          },
      },
  };
  uhid_write(p_dev->fd, &ev);
  osi_free(context);

#else
  LOG_ERROR("Error: UHID_SET_REPORT_REPLY not supported");
  LOG_ERROR("UHID_SET_REPORT_REPLY not supported");
#endif  // ENABLE_UHID_SET_REPORT
}

@@ -652,49 +682,55 @@ void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status) {
 * Returns          void.
 *
 ******************************************************************************/
void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status, uint8_t* p_rpt,
                           uint16_t len) {
  struct uhid_event ev;
void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status,
                           const uint8_t* p_rpt, uint16_t len) {
  btif_hh_device_t* p_dev;

  APPL_TRACE_VERBOSE("%s: dev_handle = %d", __func__, dev_handle);
  LOG_VERBOSE("dev_handle = %d, status = %d", dev_handle, status);

  p_dev = btif_hh_find_connected_dev_by_handle(dev_handle);
  if (p_dev == NULL) {
    APPL_TRACE_WARNING("%s: Error: unknown HID device handle %d", __func__,
                       dev_handle);
  if (p_dev == nullptr) {
    LOG_WARN("Unknown HID device handle %d", dev_handle);
    return;
  }

  if (!p_dev->get_rpt_id_queue) {
    APPL_TRACE_WARNING("%s: Error: missing UHID_GET_REPORT id queue", __func__);
    LOG_WARN("Missing UHID_GET_REPORT id queue");
    return;
  }

  // Send the HID report to the kernel.
  if (p_dev->fd >= 0 && p_dev->get_rpt_snt > 0 && p_dev->get_rpt_snt--) {
    uint32_t* get_rpt_id =
        (uint32_t*)fixed_queue_try_dequeue(p_dev->get_rpt_id_queue);
    if (get_rpt_id == nullptr) {
      APPL_TRACE_WARNING("%s: Error: UHID_GET_REPORT queue is empty", __func__);
  if (p_dev->fd < 0) {
    LOG_WARN("Unexpected Get Report response");
    return;
  }
    memset(&ev, 0, sizeof(ev));
    ev.type = UHID_FEATURE_ANSWER;
    ev.u.feature_answer.id = *get_rpt_id;
    ev.u.feature_answer.err = status;
    ev.u.feature_answer.size = len;
    osi_free(get_rpt_id);
    if (len > 0) {
      if (len > UHID_DATA_MAX) {
        APPL_TRACE_WARNING("%s: Report size greater than allowed size",
                           __func__);

  uint32_t* context = (uint32_t*)fixed_queue_try_dequeue(p_dev->get_rpt_id_queue);

  if (context == nullptr) {
    LOG_WARN("No pending UHID_GET_REPORT");
    return;
  }
      memcpy(ev.u.feature_answer.data, p_rpt + GET_RPT_RSP_OFFSET, len);
      uhid_write(p_dev->fd, &ev);
    }

  if (len == 0 || len > UHID_DATA_MAX) {
    LOG_WARN("Invalid report size = %d", len);
    return;
  }

  struct uhid_event ev = {
      .type = UHID_FEATURE_ANSWER,
      .u = {
          .feature_answer = {
              .id = *context,
              .err = status,
              .size = len,
          },
      },
  };
  memcpy(ev.u.feature_answer.data, p_rpt, len);

  uhid_write(p_dev->fd, &ev);
  osi_free(context);
}

/*******************************************************************************
Loading