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

Commit 6ddf7c24 authored by Michael Sun's avatar Michael Sun
Browse files

interop: extended truncated report map for specific device

The HID specification allows report maps to exceed 512 bytes. However, the Bluetooth specification requires all GATT attributes to be 512 bytes or less. This creates an interoperability issue when a device manufacturer implements a HID report map as a single GATT characteristic. This change handles this edge case by extending the report map after receiving the initial 512 bytes. This ensures compatibility with both HID and Bluetooth standards.

As this workaround is currently implemented for one specific device, the extra bytes of the report map exist as static const arrays; if more devices need such workarounds, it is suggested to store the report map in a separate file which can be loaded from the file system.

Bug: 332761737
Tag: #floss
Test: mmm packages/modules/Bluetooth
Test: Manual test on Brya, Brydge keyboard working
Flag: EXEMPT, interop change and apply only to one and currently non-functioning device
Change-Id: If9eb2e5e2828d0dea17f486207421525ffcccffc
parent bb69ca6c
Loading
Loading
Loading
Loading
+30 −3
Original line number Diff line number Diff line
@@ -1258,16 +1258,43 @@ static void read_hid_info_cb(tCONN_ID /*conn_id*/, tGATT_STATUS status, uint16_t
  STREAM_TO_UINT8(p_dev_cb->dscp_info.flag, pp);
}

static void get_iop_device_rpt_map(tBTA_HH_LE_HID_SRVC* p_srvc, uint16_t* len, uint8_t* desc) {
  static const uint8_t residual_report_map[] = {
          0x31, 0x81, 0x02, 0xC0, 0x05, 0x0D, 0x09, 0x54, 0x25, 0x05, 0x75, 0x07, 0x95, 0x01,
          0x81, 0x02, 0x05, 0x01, 0x05, 0x09, 0x19, 0x01, 0x29, 0x01, 0x15, 0x00, 0x25, 0x01,
          0x75, 0x01, 0x95, 0x01, 0x81, 0x02, 0x05, 0x0D, 0x55, 0x0C, 0x66, 0x01, 0x10, 0x47,
          0xFF, 0xFF, 0x00, 0x00, 0x27, 0xFF, 0xFF, 0x00, 0x00, 0x75, 0x10, 0x95, 0x01, 0x09,
          0x56, 0x81, 0x02, 0x85, 0x12, 0x09, 0x55, 0x09, 0x59, 0x25, 0x0F, 0x75, 0x08, 0x95,
          0x01, 0xB1, 0x02, 0x06, 0x00, 0xFF, 0x85, 0x11, 0x09, 0xC5, 0x15, 0x00, 0x26, 0xFF,
          0x00, 0x75, 0x08, 0x96, 0x00, 0x01, 0xB1, 0x02, 0xC0};

  p_srvc->rpt_map = (uint8_t*)osi_malloc(*len + sizeof(residual_report_map));
  STREAM_TO_ARRAY(p_srvc->rpt_map, desc, *len);
  memcpy(&(p_srvc->rpt_map[*len]), residual_report_map, sizeof(residual_report_map));
  *len = *len + sizeof(residual_report_map);
}
void bta_hh_le_save_report_map(tBTA_HH_DEV_CB* p_dev_cb, uint16_t len, uint8_t* desc) {
  tBTA_HH_LE_HID_SRVC* p_srvc = &p_dev_cb->hid_srvc;

  osi_free_and_reset((void**)&p_srvc->rpt_map);

  if (len > 0) {
    // Workaround for HID report maps exceeding 512 bytes. The HID spec allows for large report
    // maps, but Bluetooth GATT attributes have a maximum size of 512 bytes. This interop workaround
    // extended a received truncated report map with stored values.
    // TODO: The workaround is specific to one device, if more devices need the similar interop
    // workaround in the future, the “cached” report mapped should be stored in a separate file.
    if (len == GATT_MAX_ATTR_LEN &&
        interop_match_vendor_product_ids(INTEROP_HOGP_LONG_REPORT, p_dev_cb->dscp_info.vendor_id,
                                         p_dev_cb->dscp_info.product_id)) {
      get_iop_device_rpt_map(p_srvc, &len, desc);
    } else {
      p_srvc->rpt_map = (uint8_t*)osi_malloc(len);

      uint8_t* pp = desc;
      STREAM_TO_ARRAY(p_srvc->rpt_map, pp, len);
    }

    p_srvc->descriptor.dl_len = len;
    p_srvc->descriptor.dsc_list = p_dev_cb->hid_srvc.rpt_map;
  }
+5 −0
Original line number Diff line number Diff line
@@ -867,3 +867,8 @@ BSK10 = Name_Based
# Peer can request proper latency based on its power state later.
[INTEROP_HID_PREF_CONN_ZERO_LATENCY]
00:15:9E = Address_Based

# Some HOGP devices have the report map longer than the maximum GATT attribute value length (512
# bytes).
[INTEROP_HOGP_LONG_REPORT]
0x03f6-0xa001 = Vndr_Prdt_Based
+4 −0
Original line number Diff line number Diff line
@@ -356,6 +356,10 @@ typedef enum {
  // Peer can request proper latency based on its power state later.
  INTEROP_HID_PREF_CONN_ZERO_LATENCY,

  // Some HOGP devices have the report map longer than the maximum GATT attribute value length (512
  // bytes).
  INTEROP_HOGP_LONG_REPORT,

  END_OF_INTEROP_LIST
} interop_feature_t;

+1 −0
Original line number Diff line number Diff line
@@ -393,6 +393,7 @@ static const char* interop_feature_string_(const interop_feature_t feature) {
    CASE_RETURN_STR(INTEROP_MULTIPLE_HOGP_SERVICE_CHOOSE_THIRD);
    CASE_RETURN_STR(INTEROP_A2DP_SKIP_SDP_DURING_RECONNECTION);
    CASE_RETURN_STR(INTEROP_HID_PREF_CONN_ZERO_LATENCY);
    CASE_RETURN_STR(INTEROP_HOGP_LONG_REPORT);
  }
  return UNKNOWN_INTEROP_FEATURE;
}