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