Home | History | Annotate | Download | only in hid
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2002-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 
     19 /******************************************************************************
     20  *
     21  *  this file contains the connection interface functions
     22  *
     23  ******************************************************************************/
     24 
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <stdio.h>
     28 
     29 
     30 #include "gki.h"
     31 #include "bt_types.h"
     32 
     33 #include "l2cdefs.h"
     34 #include "l2c_api.h"
     35 
     36 #include "btu.h"
     37 #include "btm_api.h"
     38 #include "btm_int.h"
     39 
     40 #include "hiddefs.h"
     41 
     42 #include "hidh_api.h"
     43 #include "hidh_int.h"
     44 #include "bt_utils.h"
     45 
     46 static UINT8 find_conn_by_cid (UINT16 cid);
     47 static void hidh_conn_retry (UINT8 dhandle);
     48 
     49 /********************************************************************************/
     50 /*              L O C A L    F U N C T I O N     P R O T O T Y P E S            */
     51 /********************************************************************************/
     52 static void hidh_l2cif_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid,
     53                                     UINT16 psm, UINT8 l2cap_id);
     54 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
     55 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     56 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
     57 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
     58 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
     59 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
     60 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
     61 
     62 static const tL2CAP_APPL_INFO hst_reg_info =
     63 {
     64     hidh_l2cif_connect_ind,
     65     hidh_l2cif_connect_cfm,
     66     NULL,
     67     hidh_l2cif_config_ind,
     68     hidh_l2cif_config_cfm,
     69     hidh_l2cif_disconnect_ind,
     70     hidh_l2cif_disconnect_cfm,
     71     NULL,
     72     hidh_l2cif_data_ind,
     73     hidh_l2cif_cong_ind,
     74     NULL                        /* tL2CA_TX_COMPLETE_CB */
     75 };
     76 
     77 /*******************************************************************************
     78 **
     79 ** Function         hidh_l2cif_reg
     80 **
     81 ** Description      This function initializes the SDP unit.
     82 **
     83 ** Returns          void
     84 **
     85 *******************************************************************************/
     86 tHID_STATUS hidh_conn_reg (void)
     87 {
     88     int xx;
     89 
     90     /* Initialize the L2CAP configuration. We only care about MTU and flush */
     91     memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
     92 
     93     hh_cb.l2cap_cfg.mtu_present          = TRUE;
     94     hh_cb.l2cap_cfg.mtu                  = HID_HOST_MTU;
     95     hh_cb.l2cap_cfg.flush_to_present     = TRUE;
     96     hh_cb.l2cap_cfg.flush_to             = HID_HOST_FLUSH_TO;
     97 
     98     /* Now, register with L2CAP */
     99     if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info))
    100     {
    101         HIDH_TRACE_ERROR ("HID-Host Control Registration failed");
    102         return (HID_ERR_L2CAP_FAILED) ;
    103     }
    104     if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &hst_reg_info))
    105     {
    106         L2CA_Deregister( HID_PSM_CONTROL ) ;
    107         HIDH_TRACE_ERROR ("HID-Host Interrupt Registration failed");
    108         return (HID_ERR_L2CAP_FAILED) ;
    109     }
    110 
    111     for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
    112     {
    113         hh_cb.devices[xx].in_use = FALSE ;
    114         hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
    115     }
    116 
    117     return (HID_SUCCESS);
    118 }
    119 
    120 /*******************************************************************************
    121 **
    122 ** Function         hidh_conn_disconnect
    123 **
    124 ** Description      This function disconnects a connection.
    125 **
    126 ** Returns          TRUE if disconnect started, FALSE if already disconnected
    127 **
    128 *******************************************************************************/
    129 tHID_STATUS hidh_conn_disconnect (UINT8 dhandle)
    130 {
    131     tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
    132 
    133     HIDH_TRACE_EVENT ("HID-Host disconnect");
    134 
    135     if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
    136     {
    137         p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
    138 
    139         /* Set l2cap idle timeout to 0 (so ACL link is disconnected
    140          * immediately after last channel is closed) */
    141         L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0);
    142         /* Disconnect both interrupt and control channels */
    143         if (p_hcon->intr_cid)
    144             L2CA_DisconnectReq (p_hcon->intr_cid);
    145         else if (p_hcon->ctrl_cid)
    146             L2CA_DisconnectReq (p_hcon->ctrl_cid);
    147     }
    148     else
    149     {
    150         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    151     }
    152 
    153     return (HID_SUCCESS);
    154 }
    155 
    156 /*******************************************************************************
    157 **
    158 ** Function         hidh_sec_check_complete_term
    159 **
    160 ** Description      HID security check complete callback function.
    161 **
    162 ** Returns          Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
    163 **                  send security block L2C connection response.
    164 **
    165 *******************************************************************************/
    166 void hidh_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
    167 {
    168     tHID_HOST_DEV_CTB *p_dev= (tHID_HOST_DEV_CTB *) p_ref_data;
    169     UNUSED(bd_addr);
    170     UNUSED (transport);
    171 
    172     if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
    173     {
    174         p_dev->conn.disc_reason = HID_SUCCESS;  /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
    175 
    176         p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
    177 
    178         /* Send response to the L2CAP layer. */
    179         L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
    180 
    181         /* Send a Configuration Request. */
    182         L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
    183 
    184     }
    185     /* security check fail */
    186     else if (res != BTM_SUCCESS)
    187     {
    188         p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;      /* Save reason for disconnecting */
    189         p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
    190         L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
    191     }
    192 }
    193 
    194 /*******************************************************************************
    195 **
    196 ** Function         hidh_l2cif_connect_ind
    197 **
    198 ** Description      This function handles an inbound connection indication
    199 **                  from L2CAP. This is the case where we are acting as a
    200 **                  server.
    201 **
    202 ** Returns          void
    203 **
    204 *******************************************************************************/
    205 static void hidh_l2cif_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
    206 {
    207     tHID_CONN    *p_hcon;
    208     BOOLEAN      bAccept = TRUE;
    209     UINT8        i = HID_HOST_MAX_DEVICES;
    210     tHID_HOST_DEV_CTB *p_dev;
    211 
    212     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x  CID 0x%x", psm, l2cap_cid);
    213 
    214     /* always add incoming connection device into HID database by default */
    215     if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS)
    216     {
    217         L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
    218         return;
    219     }
    220 
    221     p_hcon = &hh_cb.devices[i].conn;
    222     p_dev  = &hh_cb.devices[i];
    223 
    224     /* Check we are in the correct state for this */
    225     if (psm == HID_PSM_INTERRUPT)
    226     {
    227         if (p_hcon->ctrl_cid == 0)
    228         {
    229             HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
    230             bAccept = FALSE;
    231         }
    232         if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
    233         {
    234             HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
    235                                  p_hcon->conn_state);
    236             bAccept = FALSE;
    237         }
    238     }
    239     else /* CTRL channel */
    240     {
    241 #if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
    242         p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
    243         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    244 #else
    245         if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
    246         {
    247             HIDH_TRACE_WARNING ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
    248                                  p_hcon->conn_state);
    249             bAccept = FALSE;
    250         }
    251 #endif
    252     }
    253 
    254     if (!bAccept)
    255     {
    256         L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
    257         return;
    258     }
    259 
    260     if (psm == HID_PSM_CONTROL)
    261     {
    262         p_hcon->conn_flags = 0;
    263         p_hcon->ctrl_cid   = l2cap_cid;
    264         p_hcon->ctrl_id    = l2cap_id;
    265         p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */
    266 
    267         p_hcon->conn_state = HID_CONN_STATE_SECURITY;
    268         if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
    269             FALSE, BTM_SEC_PROTO_HID,
    270             (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
    271             &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
    272         {
    273             L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
    274         }
    275 
    276         return;
    277     }
    278 
    279     /* Transition to the next appropriate state, configuration */
    280     p_hcon->conn_state = HID_CONN_STATE_CONFIG;
    281     p_hcon->intr_cid   = l2cap_cid;
    282 
    283     /* Send response to the L2CAP layer. */
    284     L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
    285 
    286     /* Send a Configuration Request. */
    287     L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
    288 
    289     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x  CID 0x%x",
    290                        psm, l2cap_cid);
    291 }
    292 
    293 /*******************************************************************************
    294 **
    295 ** Function         hidh_proc_repage_timeout
    296 **
    297 ** Description      This function handles timeout (to page device).
    298 **
    299 ** Returns          void
    300 **
    301 *******************************************************************************/
    302 void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle)
    303 {
    304     hidh_conn_initiate( (UINT8) p_tle->param ) ;
    305     hh_cb.devices[p_tle->param].conn_tries++;
    306     hh_cb.callback( (UINT8) p_tle->param, hh_cb.devices[p_tle->param].addr,
    307                     HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
    308 }
    309 
    310 /*******************************************************************************
    311 **
    312 ** Function         hidh_sec_check_complete_orig
    313 **
    314 ** Description      This function checks to see if security procedures are being
    315 **                  carried out or not..
    316 **
    317 ** Returns          void
    318 **
    319 *******************************************************************************/
    320 void hidh_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
    321 {
    322     tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
    323     UINT8 dhandle;
    324 #if (HID_HOST_MAX_CONN_RETRY > 0)
    325     UINT32 cb_res = HID_ERR_AUTH_FAILED;
    326 #endif
    327     UINT32 reason;
    328     UNUSED(bd_addr);
    329     UNUSED (transport);
    330 
    331     dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB);
    332     if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
    333     {
    334         HIDH_TRACE_EVENT ("HID-Host Originator security pass.");
    335         p_dev->conn.disc_reason = HID_SUCCESS;  /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
    336 
    337         /* Transition to the next appropriate state, configuration */
    338         p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
    339         L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
    340         HIDH_TRACE_EVENT ("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x", p_dev->conn.ctrl_cid);
    341 
    342     }
    343 
    344     if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
    345     {
    346 #if (HID_HOST_MAX_CONN_RETRY > 0)
    347         if( res == BTM_DEVICE_TIMEOUT )
    348         {
    349             if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
    350             {
    351                 hidh_conn_retry (dhandle);
    352                 return;
    353             }
    354             else
    355                 cb_res = HID_L2CAP_CONN_FAIL | HCI_ERR_PAGE_TIMEOUT ;
    356         }
    357 #endif
    358         p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;      /* Save reason for disconnecting */
    359         hidh_conn_disconnect(dhandle);
    360     }
    361 
    362 }
    363 
    364 /*******************************************************************************
    365 **
    366 ** Function         hidh_l2cif_connect_cfm
    367 **
    368 ** Description      This function handles the connect confirm events
    369 **                  from L2CAP. This is the case when we are acting as a
    370 **                  client and have sent a connect request.
    371 **
    372 ** Returns          void
    373 **
    374 *******************************************************************************/
    375 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
    376 {
    377     UINT8 dhandle;
    378     tHID_CONN    *p_hcon = NULL;
    379     UINT32  reason;
    380     tHID_HOST_DEV_CTB *p_dev = NULL;
    381 
    382     /* Find CCB based on CID, and verify we are in a state to accept this message */
    383     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
    384     {
    385         p_dev = &hh_cb.devices[dhandle];
    386         p_hcon = &hh_cb.devices[dhandle].conn;
    387     }
    388 
    389     if ((p_hcon == NULL)
    390      || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
    391      || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
    392      || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
    393      && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING)))
    394     {
    395         HIDH_TRACE_WARNING ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
    396         return;
    397     }
    398 
    399     if (result != L2CAP_CONN_OK)
    400     {
    401         if (l2cap_cid == p_hcon->ctrl_cid)
    402             p_hcon->ctrl_cid = 0;
    403         else
    404             p_hcon->intr_cid = 0;
    405 
    406         hidh_conn_disconnect(dhandle);
    407 
    408 #if (HID_HOST_MAX_CONN_RETRY > 0)
    409         if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
    410             (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
    411              result == HCI_ERR_PAGE_TIMEOUT) )
    412         {
    413             hidh_conn_retry(dhandle);
    414         }
    415         else
    416 #endif
    417         {
    418             reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
    419             hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
    420         }
    421         return;
    422     }
    423     /* receive Control Channel connect confirmation */
    424     if (l2cap_cid == p_hcon->ctrl_cid)
    425     {
    426         /* check security requirement */
    427         p_hcon->conn_state = HID_CONN_STATE_SECURITY;
    428         p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to "connection failure" */
    429 
    430         btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
    431             TRUE, BTM_SEC_PROTO_HID,
    432             (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
    433             &hidh_sec_check_complete_orig, p_dev);
    434     }
    435     else
    436     {
    437         p_hcon->conn_state = HID_CONN_STATE_CONFIG;
    438         /* Send a Configuration Request. */
    439         L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
    440         HIDH_TRACE_EVENT ("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
    441     }
    442 
    443     return;
    444 }
    445 
    446 /*******************************************************************************
    447 **
    448 ** Function         hidh_l2cif_config_ind
    449 **
    450 ** Description      This function processes the L2CAP configuration indication
    451 **                  event.
    452 **
    453 ** Returns          void
    454 **
    455 *******************************************************************************/
    456 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
    457 {
    458     UINT8 dhandle;
    459     tHID_CONN    *p_hcon = NULL;
    460     tHID_HOST_DEV_CTB *p_dev;
    461     UINT32  reason;
    462 
    463     /* Find CCB based on CID */
    464     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
    465     {
    466         p_dev = &hh_cb.devices[dhandle];
    467         p_hcon = &hh_cb.devices[dhandle].conn;
    468     }
    469 
    470     if (p_hcon == NULL)
    471     {
    472         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
    473         return;
    474     }
    475 
    476     HIDH_TRACE_EVENT ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
    477 
    478     /* Remember the remote MTU size */
    479     if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
    480         p_hcon->rem_mtu_size = HID_HOST_MTU;
    481     else
    482         p_hcon->rem_mtu_size = p_cfg->mtu;
    483 
    484     /* For now, always accept configuration from the other side */
    485     p_cfg->flush_to_present = FALSE;
    486     p_cfg->mtu_present      = FALSE;
    487     p_cfg->result           = L2CAP_CFG_OK;
    488 
    489     L2CA_ConfigRsp (l2cap_cid, p_cfg);
    490 
    491     if (l2cap_cid == p_hcon->ctrl_cid)
    492     {
    493         p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
    494         if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
    495            (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE))
    496         {
    497             /* Connect interrupt channel */
    498             p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;	/* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
    499             if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
    500             {
    501                 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
    502                 reason = HID_L2CAP_REQ_FAIL ;
    503                 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    504                 hidh_conn_disconnect (dhandle);
    505                 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
    506                 return;
    507             }
    508             else
    509             {
    510                 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
    511                 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
    512             }
    513         }
    514     }
    515     else
    516         p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
    517 
    518     /* If all configuration is complete, change state and tell management we are up */
    519     if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
    520      && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
    521     {
    522         p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
    523         /* Reset disconnect reason to success, as connection successful */
    524         p_hcon->disc_reason = HID_SUCCESS;
    525 
    526         hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
    527         hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
    528     }
    529 }
    530 
    531 
    532 /*******************************************************************************
    533 **
    534 ** Function         hidh_l2cif_config_cfm
    535 **
    536 ** Description      This function processes the L2CAP configuration confirmation
    537 **                  event.
    538 **
    539 ** Returns          void
    540 **
    541 *******************************************************************************/
    542 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
    543 {
    544     UINT8 dhandle;
    545     tHID_CONN    *p_hcon = NULL;
    546     UINT32  reason;
    547 
    548     HIDH_TRACE_EVENT ("HID-Host Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
    549 
    550     /* Find CCB based on CID */
    551     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
    552         p_hcon = &hh_cb.devices[dhandle].conn;
    553 
    554     if (p_hcon == NULL)
    555     {
    556         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
    557         return;
    558     }
    559 
    560     /* If configuration failed, disconnect the channel(s) */
    561     if (p_cfg->result != L2CAP_CFG_OK)
    562     {
    563         hidh_conn_disconnect (dhandle);
    564         reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
    565         hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
    566         return;
    567     }
    568 
    569     if (l2cap_cid == p_hcon->ctrl_cid)
    570     {
    571         p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
    572         if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
    573            (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE))
    574         {
    575             /* Connect interrupt channel */
    576             p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
    577             if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
    578             {
    579                 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
    580                 reason = HID_L2CAP_REQ_FAIL ;
    581                 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    582                 hidh_conn_disconnect (dhandle);
    583                 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
    584                 return;
    585             }
    586             else
    587             {
    588                 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
    589                 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
    590             }
    591         }
    592     }
    593     else
    594         p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
    595 
    596     /* If all configuration is complete, change state and tell management we are up */
    597     if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
    598      && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
    599     {
    600         p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
    601         /* Reset disconnect reason to success, as connection successful */
    602         p_hcon->disc_reason = HID_SUCCESS;
    603 
    604         hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
    605         hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
    606     }
    607 }
    608 
    609 
    610 /*******************************************************************************
    611 **
    612 ** Function         hidh_l2cif_disconnect_ind
    613 **
    614 ** Description      This function handles a disconnect event from L2CAP. If
    615 **                  requested to, we ack the disconnect before dropping the CCB
    616 **
    617 ** Returns          void
    618 **
    619 *******************************************************************************/
    620 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
    621 {
    622     UINT8 dhandle;
    623     tHID_CONN    *p_hcon = NULL;
    624     UINT16 disc_res = HCI_SUCCESS;
    625     UINT16 hid_close_evt_reason;
    626 
    627     /* Find CCB based on CID */
    628     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
    629         p_hcon = &hh_cb.devices[dhandle].conn;
    630 
    631     if (p_hcon == NULL)
    632     {
    633         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
    634         return;
    635     }
    636 
    637     if (ack_needed)
    638         L2CA_DisconnectRsp (l2cap_cid);
    639 
    640     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
    641 
    642     p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
    643 
    644     if (l2cap_cid == p_hcon->ctrl_cid)
    645         p_hcon->ctrl_cid = 0;
    646     else
    647         p_hcon->intr_cid = 0;
    648 
    649     if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
    650     {
    651         hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
    652         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    653 
    654         if( !ack_needed )
    655             disc_res = btm_get_acl_disc_reason_code();
    656 
    657 #if (HID_HOST_MAX_CONN_RETRY > 0)
    658         if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
    659             (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
    660             (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
    661         {
    662             hh_cb.devices[dhandle].conn_tries = 0;
    663             hh_cb.devices[dhandle].conn.timer_entry.param = (UINT32) dhandle;
    664             btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
    665             hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL);
    666         }
    667         else
    668 #endif
    669         {
    670             /* Set reason code for HID_HDEV_EVT_CLOSE */
    671             hid_close_evt_reason = p_hcon->disc_reason;
    672 
    673             /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */
    674             if ((disc_res == HCI_ERR_AUTH_FAILURE)                        ||
    675                 (disc_res == HCI_ERR_KEY_MISSING)                         ||
    676                 (disc_res == HCI_ERR_HOST_REJECT_SECURITY)                ||
    677                 (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED)                 ||
    678                 (disc_res == HCI_ERR_UNIT_KEY_USED)                       ||
    679                 (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
    680                 (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE)           ||
    681                 (disc_res == HCI_ERR_REPEATED_ATTEMPTS))
    682             {
    683                 hid_close_evt_reason = HID_ERR_AUTH_FAILED;
    684             }
    685 
    686             hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
    687         }
    688     }
    689 }
    690 
    691 
    692 /*******************************************************************************
    693 **
    694 ** Function         hidh_l2cif_disconnect_cfm
    695 **
    696 ** Description      This function handles a disconnect confirm event from L2CAP.
    697 **
    698 ** Returns          void
    699 **
    700 *******************************************************************************/
    701 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
    702 {
    703     UINT8 dhandle;
    704     tHID_CONN    *p_hcon = NULL;
    705     UNUSED(result);
    706 
    707     /* Find CCB based on CID */
    708     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
    709         p_hcon = &hh_cb.devices[dhandle].conn;
    710 
    711     if (p_hcon == NULL)
    712     {
    713         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
    714         return;
    715     }
    716 
    717     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
    718 
    719     if (l2cap_cid == p_hcon->ctrl_cid)
    720         p_hcon->ctrl_cid = 0;
    721     else
    722     {
    723         p_hcon->intr_cid = 0;
    724         if (p_hcon->ctrl_cid)
    725         {
    726             HIDH_TRACE_EVENT ("HID-Host Initiating L2CAP Ctrl disconnection");
    727             L2CA_DisconnectReq (p_hcon->ctrl_cid);
    728         }
    729     }
    730 
    731     if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
    732     {
    733         hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
    734         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    735         hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
    736     }
    737 }
    738 
    739 
    740 /*******************************************************************************
    741 **
    742 ** Function         hidh_l2cif_cong_ind
    743 **
    744 ** Description      This function handles a congestion status event from L2CAP.
    745 **
    746 ** Returns          void
    747 **
    748 *******************************************************************************/
    749 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
    750 {
    751     UINT8 dhandle;
    752     tHID_CONN    *p_hcon = NULL;
    753 
    754     /* Find CCB based on CID */
    755     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
    756         p_hcon = &hh_cb.devices[dhandle].conn;
    757 
    758     if (p_hcon == NULL)
    759     {
    760         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
    761         return;
    762     }
    763 
    764     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x  Cong: %d", l2cap_cid, congested);
    765 
    766     if (congested)
    767         p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
    768     else
    769     {
    770         p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
    771 
    772     }
    773 }
    774 
    775 
    776 /*******************************************************************************
    777 **
    778 ** Function         hidh_l2cif_data_ind
    779 **
    780 ** Description      This function is called when data is received from L2CAP.
    781 **                  if we are the originator of the connection, we are the SDP
    782 **                  client, and the received message is queued up for the client.
    783 **
    784 **                  If we are the destination of the connection, we are the SDP
    785 **                  server, so the message is passed to the server processing
    786 **                  function.
    787 **
    788 ** Returns          void
    789 **
    790 *******************************************************************************/
    791 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
    792 {
    793     UINT8           *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
    794     UINT8           ttype, param, rep_type, evt;
    795     UINT8 dhandle;
    796     tHID_CONN    *p_hcon = NULL;
    797 
    798     HIDH_TRACE_DEBUG ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
    799 
    800     /* Find CCB based on CID */
    801      if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
    802         p_hcon = &hh_cb.devices[dhandle].conn;
    803 
    804     if (p_hcon == NULL)
    805     {
    806         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
    807         GKI_freebuf (p_msg);
    808         return;
    809     }
    810 
    811 
    812     ttype    = HID_GET_TRANS_FROM_HDR(*p_data);
    813     param    = HID_GET_PARAM_FROM_HDR(*p_data);
    814     rep_type = param & HID_PAR_REP_TYPE_MASK;
    815     p_data++;
    816 
    817     /* Get rid of the data type */
    818     p_msg->len--;
    819     p_msg->offset++;
    820 
    821     switch (ttype)
    822     {
    823     case HID_TRANS_HANDSHAKE:
    824         hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
    825         GKI_freebuf (p_msg);
    826         break;
    827 
    828     case HID_TRANS_CONTROL:
    829         switch (param)
    830         {
    831         case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
    832             hidh_conn_disconnect( dhandle ) ;
    833             /* Device is unplugging from us. Tell USB */
    834             hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
    835             break;
    836 
    837         default:
    838             break;
    839         }
    840         GKI_freebuf (p_msg);
    841         break;
    842 
    843 
    844     case HID_TRANS_DATA:
    845         evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
    846                     HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
    847         hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
    848         break;
    849 
    850     case HID_TRANS_DATAC:
    851         evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
    852                     HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
    853         hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
    854         break;
    855 
    856     default:
    857         GKI_freebuf (p_msg);
    858         break;
    859     }
    860 
    861 }
    862 
    863 /*******************************************************************************
    864 **
    865 ** Function         hidh_conn_snd_data
    866 **
    867 ** Description      This function is sends out data.
    868 **
    869 ** Returns          tHID_STATUS
    870 **
    871 *******************************************************************************/
    872 tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
    873                                 UINT16 data, UINT8 report_id, BT_HDR *buf)
    874 {
    875     tHID_CONN   *p_hcon = &hh_cb.devices[dhandle].conn;
    876     BT_HDR      *p_buf;
    877     UINT8       *p_out;
    878     UINT16      bytes_copied;
    879     BOOLEAN     seg_req = FALSE;
    880     UINT16      data_size;
    881     UINT16      cid;
    882     UINT8       pool_id;
    883     UINT8       use_data = 0 ;
    884     BOOLEAN     blank_datc = FALSE;
    885 
    886     if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, BT_TRANSPORT_BR_EDR))
    887     {
    888         if (buf)
    889             GKI_freebuf ((void *)buf);
    890         return( HID_ERR_NO_CONNECTION );
    891     }
    892 
    893     if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
    894     {
    895         if (buf)
    896             GKI_freebuf ((void *)buf);
    897         return( HID_ERR_CONGESTED );
    898     }
    899 
    900     switch( trans_type )
    901     {
    902     case HID_TRANS_CONTROL:
    903     case HID_TRANS_GET_REPORT:
    904     case HID_TRANS_SET_REPORT:
    905     case HID_TRANS_GET_PROTOCOL:
    906     case HID_TRANS_SET_PROTOCOL:
    907     case HID_TRANS_GET_IDLE:
    908     case HID_TRANS_SET_IDLE:
    909         cid = p_hcon->ctrl_cid;
    910         pool_id = HID_CONTROL_POOL_ID;
    911         break;
    912     case HID_TRANS_DATA:
    913         cid = p_hcon->intr_cid;
    914         pool_id = HID_INTERRUPT_POOL_ID;
    915         break;
    916     default:
    917         return (HID_ERR_INVALID_PARAM) ;
    918     }
    919 
    920     if( trans_type == HID_TRANS_SET_IDLE )
    921         use_data = 1;
    922     else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
    923         use_data = 2;
    924 
    925     do
    926     {
    927         if ( buf == NULL || blank_datc )
    928         {
    929             if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
    930                 return (HID_ERR_NO_RESOURCES);
    931 
    932             p_buf->offset = L2CAP_MIN_OFFSET;
    933             seg_req = FALSE;
    934             data_size = 0;
    935             bytes_copied = 0;
    936             blank_datc = FALSE;
    937         }
    938         else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
    939         {
    940             if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
    941                 return (HID_ERR_NO_RESOURCES);
    942 
    943             p_buf->offset = L2CAP_MIN_OFFSET;
    944             seg_req = TRUE;
    945             data_size = buf->len;
    946             bytes_copied = p_hcon->rem_mtu_size - 1;
    947         }
    948         else
    949         {
    950             p_buf = buf ;
    951             p_buf->offset -= 1;
    952             seg_req = FALSE;
    953             data_size = buf->len;
    954             bytes_copied = buf->len;
    955         }
    956 
    957         p_out         = (UINT8 *)(p_buf + 1) + p_buf->offset;
    958         *p_out++      = HID_BUILD_HDR(trans_type, param);
    959 
    960         /* If report ID required for this device */
    961         if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
    962         {
    963             *p_out = report_id;
    964             data_size = bytes_copied = 1;
    965         }
    966 
    967 
    968         if (seg_req)
    969         {
    970             memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
    971             buf->offset += bytes_copied;
    972             buf->len -= bytes_copied;
    973         }
    974         else if( use_data == 1)
    975         {
    976             *(p_out+bytes_copied) = data & 0xff;
    977         }
    978         else if( use_data == 2 )
    979         {
    980             *(p_out+bytes_copied) = data & 0xff;
    981             *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
    982         }
    983 
    984         p_buf->len   = bytes_copied + 1 + use_data;
    985         data_size    -= bytes_copied;
    986 
    987         /* Send the buffer through L2CAP */
    988         if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
    989             return (HID_ERR_CONGESTED);
    990 
    991         if (data_size)
    992             trans_type = HID_TRANS_DATAC;
    993         else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
    994         {
    995             trans_type = HID_TRANS_DATAC;
    996             blank_datc = TRUE;
    997         }
    998 
    999     } while ((data_size != 0) || blank_datc ) ;
   1000 
   1001     return (HID_SUCCESS);
   1002 }
   1003 /*******************************************************************************
   1004 **
   1005 ** Function         hidh_conn_initiate
   1006 **
   1007 ** Description      This function is called by the management to create a connection.
   1008 **
   1009 ** Returns          void
   1010 **
   1011 *******************************************************************************/
   1012 tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
   1013 {
   1014     UINT8   service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
   1015     UINT32  mx_chan_id = HID_NOSEC_CHN;
   1016 
   1017     tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
   1018 
   1019     if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
   1020         return( HID_ERR_CONN_IN_PROCESS );
   1021 
   1022     p_dev->conn.ctrl_cid = 0;
   1023     p_dev->conn.intr_cid = 0;
   1024     p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;  /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
   1025 
   1026     /* We are the originator of this connection */
   1027     p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
   1028 
   1029     if(p_dev->attr_mask & HID_SEC_REQUIRED)
   1030     {
   1031         service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
   1032         mx_chan_id = HID_SEC_CHN;
   1033     }
   1034     BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
   1035 
   1036     /* Check if L2CAP started the connection process */
   1037     if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
   1038     {
   1039         HIDH_TRACE_WARNING ("HID-Host Originate failed");
   1040         hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
   1041                                 HID_ERR_L2CAP_FAILED, NULL ) ;
   1042     }
   1043     else
   1044     {
   1045         /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
   1046         p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
   1047     }
   1048 
   1049     return( HID_SUCCESS );
   1050 }
   1051 
   1052 
   1053 /*******************************************************************************
   1054 **
   1055 ** Function         find_conn_by_cid
   1056 **
   1057 ** Description      This function finds a connection control block based on CID
   1058 **
   1059 ** Returns          address of control block, or NULL if not found
   1060 **
   1061 *******************************************************************************/
   1062 static UINT8 find_conn_by_cid (UINT16 cid)
   1063 {
   1064     UINT8      xx;
   1065 
   1066     for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
   1067     {
   1068         if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
   1069             && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
   1070             break;
   1071     }
   1072 
   1073     return (xx);
   1074 }
   1075 
   1076 void hidh_conn_dereg( void )
   1077 {
   1078     L2CA_Deregister (HID_PSM_CONTROL);
   1079     L2CA_Deregister (HID_PSM_INTERRUPT);
   1080 }
   1081 
   1082 /*******************************************************************************
   1083 **
   1084 ** Function         hidh_conn_retry
   1085 **
   1086 ** Description      This function is called to retry a failed connection.
   1087 **
   1088 ** Returns          void
   1089 **
   1090 *******************************************************************************/
   1091 static void hidh_conn_retry(  UINT8 dhandle )
   1092 {
   1093     tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
   1094 
   1095     p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
   1096     p_dev->conn.timer_entry.param = (UINT32) dhandle;
   1097 #if (HID_HOST_REPAGE_WIN > 0)
   1098     btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
   1099 #else
   1100     hidh_proc_repage_timeout( &(p_dev->conn.timer_entry) );
   1101 #endif
   1102 }
   1103