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