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