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