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