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

Commit 38e7b075 authored by Kim Low's avatar Kim Low Committed by Andre Eisenbach
Browse files

Add UHID GET_REPORT functionality

GET_REPORT wasn't supported previously. >=4.10 hid-sony driver
requires this feature to get the calibration data for DualShock4.

To be backwards compatible with kernel 3.10, UHID_FEATURE and
UHID_FEATURE_ANSWER are used instead of UHID_GET_REPORT and
UHID_GET_REPORT_REPLY. Also, UHID_SET_REPORT functionality cannot
be supported since it's not implemented in kernel 3.10.

Test: Load >=4.10 hid-sony driver, connect a DualShock4, and check
      that the DualShock4 LED turns blue, which confirms both
      get feature report and output data report working.
Bug: 38511270
Change-Id: Ic28760f423cc09754fd32a107a499be6677ca747
parent 37f02365
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -632,7 +632,7 @@ void bta_hh_data_act(tBTA_HH_DEV_CB* p_cb, tBTA_HH_DATA* p_data) {
 *
 * Function         bta_hh_handsk_act
 *
 * Description      HID Host process a handshake acknoledgement.
 * Description      HID Host process a handshake acknowledgement.
 *
 *
 * Returns          void
@@ -659,7 +659,9 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, 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;
@@ -671,6 +673,9 @@ void bta_hh_handsk_act(tBTA_HH_DEV_CB* p_cb, 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;
@@ -726,6 +731,8 @@ void bta_hh_ctrl_dat_act(tBTA_HH_DEV_CB* p_cb, 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 −0
Original line number Diff line number Diff line
@@ -77,6 +77,31 @@ extern void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
 ******************************************************************************/
extern void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id);

/*******************************************************************************
 *
 * Function         bta_hh_co_set_rpt_rsp
 *
 * Description      This callout function is executed by HH when Set Report
 *                  Response is received on Control Channel.
 *
 * Returns          void.
 *
 ******************************************************************************/
extern void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status);

/*******************************************************************************
 *
 * Function         bta_hh_co_get_rpt_rsp
 *
 * Description      This callout function is executed by HH when Get Report
 *                  Response is received on Control Channel.
 *
 * Returns          void.
 *
 ******************************************************************************/
extern void bta_hh_co_get_rpt_rsp(uint8_t dev_handle, uint8_t status,
                                  uint8_t* p_rpt, uint16_t len);

#if (BTA_HH_LE_INCLUDED == TRUE)
/*******************************************************************************
 *
+92 −6
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ const char* dev_path = "/dev/uhid";
#define BTA_HH_NV_LOAD_MAX 16
static tBTA_HH_RPT_CACHE_ENTRY sReportCache[BTA_HH_NV_LOAD_MAX];
#endif
#define GET_RPT_RSP_OFFSET 9

void uhid_set_non_blocking(int fd) {
  int opts = fcntl(fd, F_GETFL);
@@ -128,8 +129,8 @@ static int uhid_read_event(btif_hh_device_t* p_dev) {
        btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT, ev.u.output.size,
                          ev.u.output.data);
      else
        btif_hh_setreport(p_dev, BTHH_INPUT_REPORT, ev.u.output.size,
                          ev.u.output.data);
        APPL_TRACE_ERROR("%s: UHID_OUTPUT: Invalid report type = %d", __func__,
                         ev.u.output.rtype);
      break;
    case UHID_OUTPUT_EV:
      if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.output_ev))) {
@@ -141,10 +142,24 @@ 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:
      APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
      break;
    case UHID_FEATURE_ANSWER:
      APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
      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));
        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;
        fixed_queue_enqueue(p_dev->get_rpt_id_queue, (void*)get_rpt_id);
      }
      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;

    default:
@@ -337,6 +352,9 @@ void bta_hh_co_open(uint8_t dev_handle, uint8_t sub_class,
  }

  p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
  p_dev->get_rpt_id_queue = fixed_queue_new(SIZE_MAX);
  CHECK(p_dev->get_rpt_id_queue);

  APPL_TRACE_DEBUG("%s: Return device status %d", __func__, p_dev->dev_status);
}

@@ -366,6 +384,9 @@ void bta_hh_co_close(uint8_t dev_handle, uint8_t app_id) {

  for (i = 0; i < BTIF_HH_MAX_HID; i++) {
    p_dev = &btif_hh_cb.devices[i];
    fixed_queue_flush(p_dev->get_rpt_id_queue, osi_free);
    fixed_queue_free(p_dev->get_rpt_id_queue, NULL);
    p_dev->get_rpt_id_queue = NULL;
    if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN &&
        p_dev->dev_handle == dev_handle) {
      APPL_TRACE_WARNING(
@@ -493,6 +514,71 @@ void bta_hh_co_send_hid_info(btif_hh_device_t* p_dev, const char* dev_name,
  }
}

/*******************************************************************************
 *
 * Function         bta_hh_co_set_rpt_rsp
 *
 * Description      This callout function is executed by HH when Set Report
 *                  Response is received on Control Channel.
 *
 * Returns          void.
 *
 ******************************************************************************/
void bta_hh_co_set_rpt_rsp(uint8_t dev_handle, uint8_t status) {
  APPL_TRACE_ERROR("%s: Error: UHID_SET_REPORT_REPLY not supported", __func__);
}

/*******************************************************************************
 *
 * Function         bta_hh_co_get_rpt_rsp
 *
 * Description      This callout function is executed by HH when Get Report
 *                  Response is received on Control Channel.
 *
 * 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;
  btif_hh_device_t* p_dev;

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

  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);
    return;
  }

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

  // Send the HID report to the kernel.
  if (p_dev->fd >= 0 && p_dev->get_rpt_snt--) {
    uint32_t* get_rpt_id =
        (uint32_t*)fixed_queue_dequeue(p_dev->get_rpt_id_queue);
    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__);
        return;
      }
      memcpy(ev.u.feature_answer.data, p_rpt + GET_RPT_RSP_OFFSET, len);
      uhid_write(p_dev->fd, &ev);
    }
  }
}

#if (BTA_HH_LE_INCLUDED == TRUE)
/*******************************************************************************
 *
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <stdint.h>
#include "bta_hh_api.h"
#include "btu.h"
#include "osi/include/fixed_queue.h"

/*******************************************************************************
 *  Constants & Macros
@@ -67,6 +68,8 @@ typedef struct {
  pthread_t hh_poll_thread_id;
  uint8_t hh_keep_polling;
  alarm_t* vup_timer;
  fixed_queue_t* get_rpt_id_queue;
  uint8_t get_rpt_snt;
  bool local_vup;  // Indicated locally initiated VUP
} btif_hh_device_t;

@@ -106,6 +109,9 @@ extern void btif_hh_disconnect(RawAddress* bd_addr);
extern void btif_hh_setreport(btif_hh_device_t* p_dev,
                              bthh_report_type_t r_type, uint16_t size,
                              uint8_t* report);
extern void btif_hh_getreport(btif_hh_device_t* p_dev,
                              bthh_report_type_t r_type, uint8_t reportId,
                              uint16_t bufferSize);
extern void btif_hh_service_registration(bool enable);

#endif
+15 −0
Original line number Diff line number Diff line
@@ -682,6 +682,21 @@ void btif_hh_service_registration(bool enable) {
  }
}

/*******************************************************************************
 *
 *
 * Function         btif_hh_getreport
 *
 * Description      getreport initiated from the BTIF thread context
 *
 * Returns          void
 *
 ******************************************************************************/
void btif_hh_getreport(btif_hh_device_t* p_dev, bthh_report_type_t r_type,
                       uint8_t reportId, uint16_t bufferSize) {
  BTA_HhGetReport(p_dev->dev_handle, r_type, reportId, bufferSize);
}

/*****************************************************************************
 *   Section name (Group of functions)
 ****************************************************************************/