1/******************************************************************************
2 *
3 *  Copyright (C) 2005-2012 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18#include <string.h>
19
20#include "bt_target.h"
21#if (BTA_HH_INCLUDED == TRUE)
22
23#include "bta_hh_int.h"
24#include "osi/include/osi.h"
25
26/* if SSR max latency is not defined by remote device, set the default value
27   as half of the link supervision timeout */
28#define BTA_HH_GET_DEF_SSR_MAX_LAT(x) ((x) >> 1)
29
30/*****************************************************************************
31 *  Constants
32 ****************************************************************************/
33#define BTA_HH_KB_CTRL_MASK 0x11
34#define BTA_HH_KB_SHIFT_MASK 0x22
35#define BTA_HH_KB_ALT_MASK 0x44
36#define BTA_HH_KB_GUI_MASK 0x88
37
38#define BTA_HH_KB_CAPS_LOCK 0x39 /* caps lock */
39#define BTA_HH_KB_NUM_LOCK 0x53  /* num lock */
40
41#define BTA_HH_MAX_RPT_CHARS 8
42
43static const uint8_t bta_hh_mod_key_mask[BTA_HH_MOD_MAX_KEY] = {
44    BTA_HH_KB_CTRL_MASK, BTA_HH_KB_SHIFT_MASK, BTA_HH_KB_ALT_MASK,
45    BTA_HH_KB_GUI_MASK};
46
47/*******************************************************************************
48 *
49 * Function         bta_hh_find_cb
50 *
51 * Description      Find best available control block according to BD address.
52 *
53 *
54 * Returns          void
55 *
56 ******************************************************************************/
57uint8_t bta_hh_find_cb(const RawAddress& bda) {
58  uint8_t xx;
59
60  /* See how many active devices there are. */
61  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
62    /* check if any active/known devices is a match */
63    if ((bda == bta_hh_cb.kdev[xx].addr && !bda.IsEmpty())) {
64#if (BTA_HH_DEBUG == TRUE)
65      APPL_TRACE_DEBUG("found kdev_cb[%d] hid_handle = %d ", xx,
66                       bta_hh_cb.kdev[xx].hid_handle)
67#endif
68      return xx;
69    }
70#if (BTA_HH_DEBUG == TRUE)
71    else
72      APPL_TRACE_DEBUG("in_use ? [%d] kdev[%d].hid_handle = %d state = [%d]",
73                       bta_hh_cb.kdev[xx].in_use, xx,
74                       bta_hh_cb.kdev[xx].hid_handle, bta_hh_cb.kdev[xx].state);
75#endif
76  }
77
78  /* if no active device match, find a spot for it */
79  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
80    if (!bta_hh_cb.kdev[xx].in_use) {
81      bta_hh_cb.kdev[xx].addr = bda;
82      break;
83    }
84  }
85/* If device list full, report BTA_HH_IDX_INVALID */
86#if (BTA_HH_DEBUG == TRUE)
87  APPL_TRACE_DEBUG("bta_hh_find_cb:: index = %d while max = %d", xx,
88                   BTA_HH_MAX_DEVICE);
89#endif
90
91  if (xx == BTA_HH_MAX_DEVICE) xx = BTA_HH_IDX_INVALID;
92
93  return xx;
94}
95
96/*******************************************************************************
97 *
98 * Function         bta_hh_clean_up_kdev
99 *
100 * Description      Clean up device control block when device is removed from
101 *                  manitainace list, and update control block index map.
102 *
103 * Returns          void
104 *
105 ******************************************************************************/
106void bta_hh_clean_up_kdev(tBTA_HH_DEV_CB* p_cb) {
107  uint8_t index;
108
109  if (p_cb->hid_handle != BTA_HH_INVALID_HANDLE) {
110#if (BTA_HH_LE_INCLUDED == TRUE)
111    if (p_cb->is_le_device)
112      bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(p_cb->hid_handle)] =
113          BTA_HH_IDX_INVALID;
114    else
115#endif
116      bta_hh_cb.cb_index[p_cb->hid_handle] = BTA_HH_IDX_INVALID;
117  }
118
119  /* reset device control block */
120  index = p_cb->index; /* Preserve index for this control block */
121
122  /* Free buffer for report descriptor info */
123  osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);
124
125  memset(p_cb, 0, sizeof(tBTA_HH_DEV_CB)); /* Reset control block */
126
127  p_cb->index = index; /* Restore index for this control block */
128  p_cb->state = BTA_HH_IDLE_ST;
129  p_cb->hid_handle = BTA_HH_INVALID_HANDLE;
130}
131/*******************************************************************************
132 *
133 * Function         bta_hh_update_di_info
134 *
135 * Description      Maintain a known device list for BTA HH.
136 *
137 * Returns          void
138 *
139 ******************************************************************************/
140void bta_hh_update_di_info(tBTA_HH_DEV_CB* p_cb, uint16_t vendor_id,
141                           uint16_t product_id, uint16_t version,
142#if (BTA_HH_LE_INCLUDED == TRUE)
143                           uint8_t flag)
144#else
145                           UNUSED_ATTR uint8_t flag)
146#endif
147{
148#if (BTA_HH_DEBUG == TRUE)
149  APPL_TRACE_DEBUG("vendor_id = 0x%2x product_id = 0x%2x version = 0x%2x",
150                   vendor_id, product_id, version);
151#endif
152  p_cb->dscp_info.vendor_id = vendor_id;
153  p_cb->dscp_info.product_id = product_id;
154  p_cb->dscp_info.version = version;
155#if (BTA_HH_LE_INCLUDED == TRUE)
156  p_cb->dscp_info.flag = flag;
157#endif
158}
159/*******************************************************************************
160 *
161 * Function         bta_hh_add_device_to_list
162 *
163 * Description      Maintain a known device list for BTA HH.
164 *
165 * Returns          void
166 *
167 ******************************************************************************/
168void bta_hh_add_device_to_list(tBTA_HH_DEV_CB* p_cb, uint8_t handle,
169                               uint16_t attr_mask,
170                               tHID_DEV_DSCP_INFO* p_dscp_info,
171                               uint8_t sub_class, uint16_t ssr_max_latency,
172                               uint16_t ssr_min_tout, uint8_t app_id) {
173#if (BTA_HH_DEBUG == TRUE)
174  APPL_TRACE_DEBUG("subclass = 0x%2x", sub_class);
175#endif
176
177  p_cb->hid_handle = handle;
178  p_cb->in_use = true;
179  p_cb->attr_mask = attr_mask;
180
181  p_cb->sub_class = sub_class;
182  p_cb->app_id = app_id;
183
184  p_cb->dscp_info.ssr_max_latency = ssr_max_latency;
185  p_cb->dscp_info.ssr_min_tout = ssr_min_tout;
186
187  /* store report descriptor info */
188  if (p_dscp_info) {
189    osi_free_and_reset((void**)&p_cb->dscp_info.descriptor.dsc_list);
190
191    if (p_dscp_info->dl_len) {
192      p_cb->dscp_info.descriptor.dsc_list =
193          (uint8_t*)osi_malloc(p_dscp_info->dl_len);
194      p_cb->dscp_info.descriptor.dl_len = p_dscp_info->dl_len;
195      memcpy(p_cb->dscp_info.descriptor.dsc_list, p_dscp_info->dsc_list,
196             p_dscp_info->dl_len);
197    }
198  }
199}
200
201/*******************************************************************************
202 *
203 * Function         bta_hh_tod_spt
204 *
205 * Description      Check to see if this type of device is supported
206 *
207 * Returns
208 *
209 ******************************************************************************/
210bool bta_hh_tod_spt(tBTA_HH_DEV_CB* p_cb, uint8_t sub_class) {
211  uint8_t xx;
212  uint8_t cod = (sub_class >> 2); /* lower two bits are reserved */
213
214  for (xx = 0; xx < p_bta_hh_cfg->max_devt_spt; xx++) {
215    if (cod == (uint8_t)p_bta_hh_cfg->p_devt_list[xx].tod) {
216      p_cb->app_id = p_bta_hh_cfg->p_devt_list[xx].app_id;
217#if (BTA_HH_DEBUG == TRUE)
218      APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x supported", sub_class);
219#endif
220      return true;
221    }
222  }
223#if (BTA_HH_DEBUG == TRUE)
224  APPL_TRACE_EVENT("bta_hh_tod_spt sub_class:0x%x NOT supported", sub_class);
225#endif
226  return false;
227}
228
229/*******************************************************************************
230 *
231 * Function         bta_hh_parse_keybd_rpt
232 *
233 * Description      This utility function parse a boot mode keyboard report.
234 *
235 * Returns          void
236 *
237 ******************************************************************************/
238void bta_hh_parse_keybd_rpt(tBTA_HH_BOOT_RPT* p_kb_data, uint8_t* p_report,
239                            uint16_t report_len) {
240  tBTA_HH_KB_CB* p_kb = &bta_hh_cb.kb_cb;
241  tBTA_HH_KEYBD_RPT* p_data = &p_kb_data->data_rpt.keybd_rpt;
242
243  uint8_t this_char, ctl_shift;
244  uint16_t xx, yy, key_idx = 0;
245  uint8_t this_report[BTA_HH_MAX_RPT_CHARS];
246
247#if (BTA_HH_DEBUG == TRUE)
248  APPL_TRACE_DEBUG("bta_hh_parse_keybd_rpt:  (report=%p, report_len=%d) called",
249                   p_report, report_len);
250#endif
251
252  if (report_len < 2) return;
253
254  ctl_shift = *p_report++;
255  report_len--;
256
257  if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
258
259  memset(this_report, 0, BTA_HH_MAX_RPT_CHARS);
260  memset(p_data, 0, sizeof(tBTA_HH_KEYBD_RPT));
261  memcpy(this_report, p_report, report_len);
262
263  /* Take care of shift, control, GUI and alt, modifier keys  */
264  for (xx = 0; xx < BTA_HH_MOD_MAX_KEY; xx++) {
265    if (ctl_shift & bta_hh_mod_key_mask[xx]) {
266      APPL_TRACE_DEBUG("Mod Key[%02x] pressed", bta_hh_mod_key_mask[xx]);
267      p_kb->mod_key[xx] = true;
268    } else if (p_kb->mod_key[xx]) {
269      p_kb->mod_key[xx] = false;
270    }
271    /* control key flag is set */
272    p_data->mod_key[xx] = p_kb->mod_key[xx];
273  }
274
275  /***************************************************************************/
276  /*  First step is to remove all characters we saw in the last report       */
277  /***************************************************************************/
278  for (xx = 0; xx < report_len; xx++) {
279    for (yy = 0; yy < BTA_HH_MAX_RPT_CHARS; yy++) {
280      if (this_report[xx] == p_kb->last_report[yy]) {
281        this_report[xx] = 0;
282      }
283    }
284  }
285  /***************************************************************************/
286  /*  Now, process all the characters in the report, up to 6 keycodes        */
287  /***************************************************************************/
288  for (xx = 0; xx < report_len; xx++) {
289#if (BTA_HH_DEBUG == TRUE)
290    APPL_TRACE_DEBUG("this_char = %02x", this_report[xx]);
291#endif
292    this_char = this_report[xx];
293    if (this_char == 0) continue;
294    /* take the key code as the report data */
295    if (this_report[xx] == BTA_HH_KB_CAPS_LOCK)
296      p_kb->caps_lock = p_kb->caps_lock ? false : true;
297    else if (this_report[xx] == BTA_HH_KB_NUM_LOCK)
298      p_kb->num_lock = p_kb->num_lock ? false : true;
299    else
300      p_data->this_char[key_idx++] = this_char;
301
302#if (BTA_HH_DEBUG == TRUE)
303    APPL_TRACE_DEBUG("found keycode %02x ", this_report[xx]);
304#endif
305    p_data->caps_lock = p_kb->caps_lock;
306    p_data->num_lock = p_kb->num_lock;
307  }
308
309  memset(p_kb->last_report, 0, BTA_HH_MAX_RPT_CHARS);
310  memcpy(p_kb->last_report, p_report, report_len);
311
312  return;
313}
314
315/*******************************************************************************
316 *
317 * Function         bta_hh_parse_mice_rpt
318 *
319 * Description      This utility function parse a boot mode mouse report.
320 *
321 * Returns          void
322 *
323 ******************************************************************************/
324void bta_hh_parse_mice_rpt(tBTA_HH_BOOT_RPT* p_mice_data, uint8_t* p_report,
325                           uint16_t report_len) {
326  tBTA_HH_MICE_RPT* p_data = &p_mice_data->data_rpt.mice_rpt;
327#if (BTA_HH_DEBUG == TRUE)
328  uint8_t xx;
329
330  APPL_TRACE_DEBUG(
331      "bta_hh_parse_mice_rpt:  bta_keybd_rpt_rcvd(report=%p, \
332                report_len=%d) called",
333      p_report, report_len);
334#endif
335
336  if (report_len < 3) return;
337
338  if (report_len > BTA_HH_MAX_RPT_CHARS) report_len = BTA_HH_MAX_RPT_CHARS;
339
340#if (BTA_HH_DEBUG == TRUE)
341  for (xx = 0; xx < report_len; xx++) {
342    APPL_TRACE_DEBUG("this_char = %02x", p_report[xx]);
343  }
344#endif
345
346  /* only first bytes lower 3 bits valid */
347  p_data->mouse_button = (p_report[0] & 0x07);
348
349  /* x displacement */
350  p_data->delta_x = p_report[1];
351
352  /* y displacement */
353  p_data->delta_y = p_report[2];
354
355#if (BTA_HH_DEBUG == TRUE)
356  APPL_TRACE_DEBUG("mice button: 0x%2x", p_data->mouse_button);
357  APPL_TRACE_DEBUG("mice move: x = %d y = %d", p_data->delta_x,
358                   p_data->delta_y);
359#endif
360
361  return;
362}
363
364/*******************************************************************************
365 *
366 * Function         bta_hh_read_ssr_param
367 *
368 * Description      Read the SSR Parameter for the remote device
369 *
370 * Returns          tBTA_HH_STATUS  operation status
371 *
372 ******************************************************************************/
373tBTA_HH_STATUS bta_hh_read_ssr_param(const RawAddress& bd_addr,
374                                     uint16_t* p_max_ssr_lat,
375                                     uint16_t* p_min_ssr_tout) {
376  tBTA_HH_STATUS status = BTA_HH_ERR;
377  tBTA_HH_CB* p_cb = &bta_hh_cb;
378  uint8_t i;
379  uint16_t ssr_max_latency;
380  for (i = 0; i < BTA_HH_MAX_KNOWN; i++) {
381    if (p_cb->kdev[i].addr == bd_addr) {
382      /* if remote device does not have HIDSSRHostMaxLatency attribute in SDP,
383      set SSR max latency default value here.  */
384      if (p_cb->kdev[i].dscp_info.ssr_max_latency == HID_SSR_PARAM_INVALID) {
385        /* The default is calculated as half of link supervision timeout.*/
386
387        BTM_GetLinkSuperTout(p_cb->kdev[i].addr, &ssr_max_latency);
388        ssr_max_latency = BTA_HH_GET_DEF_SSR_MAX_LAT(ssr_max_latency);
389
390        /* per 1.1 spec, if the newly calculated max latency is greater than
391        BTA_HH_SSR_MAX_LATENCY_DEF which is 500ms, use
392        BTA_HH_SSR_MAX_LATENCY_DEF */
393        if (ssr_max_latency > BTA_HH_SSR_MAX_LATENCY_DEF)
394          ssr_max_latency = BTA_HH_SSR_MAX_LATENCY_DEF;
395
396        *p_max_ssr_lat = ssr_max_latency;
397      } else
398        *p_max_ssr_lat = p_cb->kdev[i].dscp_info.ssr_max_latency;
399
400      if (p_cb->kdev[i].dscp_info.ssr_min_tout == HID_SSR_PARAM_INVALID)
401        *p_min_ssr_tout = BTA_HH_SSR_MIN_TOUT_DEF;
402      else
403        *p_min_ssr_tout = p_cb->kdev[i].dscp_info.ssr_min_tout;
404
405      status = BTA_HH_OK;
406
407      break;
408    }
409  }
410
411  return status;
412}
413
414/*******************************************************************************
415 *
416 * Function         bta_hh_cleanup_disable
417 *
418 * Description      when disable finished, cleanup control block and send
419 *                  callback
420 *
421 *
422 * Returns          void
423 *
424 ******************************************************************************/
425void bta_hh_cleanup_disable(tBTA_HH_STATUS status) {
426  uint8_t xx;
427  /* free buffer in CB holding report descriptors */
428  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
429    osi_free_and_reset(
430        (void**)&bta_hh_cb.kdev[xx].dscp_info.descriptor.dsc_list);
431  }
432
433  if (bta_hh_cb.p_disc_db) {
434    /* Cancel SDP if it had been started. */
435    (void)SDP_CancelServiceSearch (bta_hh_cb.p_disc_db);
436    osi_free_and_reset((void**)&bta_hh_cb.p_disc_db);
437  }
438
439  if (bta_hh_cb.p_cback) {
440    (*bta_hh_cb.p_cback)(BTA_HH_DISABLE_EVT, (tBTA_HH*)&status);
441    /* all connections are down, no waiting for diconnect */
442    memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB));
443  }
444}
445
446/*******************************************************************************
447 *
448 * Function         bta_hh_dev_handle_to_cb_idx
449 *
450 * Description      convert a HID device handle to the device control block
451 *                  index.
452 *
453 *
454 * Returns          uint8_t: index of the device control block.
455 *
456 ******************************************************************************/
457uint8_t bta_hh_dev_handle_to_cb_idx(uint8_t dev_handle) {
458  uint8_t index = BTA_HH_IDX_INVALID;
459
460#if (BTA_HH_LE_INCLUDED == TRUE)
461  if (BTA_HH_IS_LE_DEV_HDL(dev_handle)) {
462    if (BTA_HH_IS_LE_DEV_HDL_VALID(dev_handle))
463      index = bta_hh_cb.le_cb_index[BTA_HH_GET_LE_CB_IDX(dev_handle)];
464#if (BTA_HH_DEBUG == TRUE)
465    APPL_TRACE_DEBUG("bta_hh_dev_handle_to_cb_idx dev_handle = %d index = %d",
466                     dev_handle, index);
467#endif
468  } else
469#endif
470      /* regular HID device checking */
471      if (dev_handle < BTA_HH_MAX_KNOWN)
472    index = bta_hh_cb.cb_index[dev_handle];
473
474  return index;
475}
476#if (BTA_HH_DEBUG == TRUE)
477/*******************************************************************************
478 *
479 * Function         bta_hh_trace_dev_db
480 *
481 * Description      Check to see if this type of device is supported
482 *
483 * Returns
484 *
485 ******************************************************************************/
486void bta_hh_trace_dev_db(void) {
487  uint8_t xx;
488
489  APPL_TRACE_DEBUG("bta_hh_trace_dev_db:: Device DB list********************");
490
491  for (xx = 0; xx < BTA_HH_MAX_DEVICE; xx++) {
492    APPL_TRACE_DEBUG("kdev[%d] in_use[%d]  handle[%d] ", xx,
493                     bta_hh_cb.kdev[xx].in_use, bta_hh_cb.kdev[xx].hid_handle);
494
495    APPL_TRACE_DEBUG(
496        "\t\t\t attr_mask[%04x] state [%d] sub_class[%02x] index = %d",
497        bta_hh_cb.kdev[xx].attr_mask, bta_hh_cb.kdev[xx].state,
498        bta_hh_cb.kdev[xx].sub_class, bta_hh_cb.kdev[xx].index);
499  }
500  APPL_TRACE_DEBUG("*********************************************************");
501}
502#endif
503#endif /* HL_INCLUDED */
504