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