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, BT_TRANSPORT_BR_EDR);
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     UINT32 reason;
325     UNUSED(bd_addr);
326     UNUSED (transport);
327 
328     dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB);
329     if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
330     {
331         HIDH_TRACE_EVENT ("HID-Host Originator security pass.");
332         p_dev->conn.disc_reason = HID_SUCCESS;  /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
333 
334         /* Transition to the next appropriate state, configuration */
335         p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
336         L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
337         HIDH_TRACE_EVENT ("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x", p_dev->conn.ctrl_cid);
338 
339     }
340 
341     if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
342     {
343 #if (HID_HOST_MAX_CONN_RETRY > 0)
344         if( res == BTM_DEVICE_TIMEOUT )
345         {
346             if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
347             {
348                 hidh_conn_retry (dhandle);
349                 return;
350             }
351         }
352 #endif
353         p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;      /* Save reason for disconnecting */
354         hidh_conn_disconnect(dhandle);
355     }
356 
357 }
358 
359 /*******************************************************************************
360 **
361 ** Function         hidh_l2cif_connect_cfm
362 **
363 ** Description      This function handles the connect confirm events
364 **                  from L2CAP. This is the case when we are acting as a
365 **                  client and have sent a connect request.
366 **
367 ** Returns          void
368 **
369 *******************************************************************************/
hidh_l2cif_connect_cfm(UINT16 l2cap_cid,UINT16 result)370 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
371 {
372     UINT8 dhandle;
373     tHID_CONN    *p_hcon = NULL;
374     UINT32  reason;
375     tHID_HOST_DEV_CTB *p_dev = NULL;
376 
377     /* Find CCB based on CID, and verify we are in a state to accept this message */
378     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
379     {
380         p_dev = &hh_cb.devices[dhandle];
381         p_hcon = &hh_cb.devices[dhandle].conn;
382     }
383 
384     if ((p_hcon == NULL)
385      || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
386      || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
387      || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
388      && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING)))
389     {
390         HIDH_TRACE_WARNING ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
391         return;
392     }
393 
394     if (result != L2CAP_CONN_OK)
395     {
396         if (l2cap_cid == p_hcon->ctrl_cid)
397             p_hcon->ctrl_cid = 0;
398         else
399             p_hcon->intr_cid = 0;
400 
401         hidh_conn_disconnect(dhandle);
402 
403 #if (HID_HOST_MAX_CONN_RETRY > 0)
404         if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
405             (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
406              result == HCI_ERR_PAGE_TIMEOUT) )
407         {
408             hidh_conn_retry(dhandle);
409         }
410         else
411 #endif
412         {
413             reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
414             hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
415         }
416         return;
417     }
418     /* receive Control Channel connect confirmation */
419     if (l2cap_cid == p_hcon->ctrl_cid)
420     {
421         /* check security requirement */
422         p_hcon->conn_state = HID_CONN_STATE_SECURITY;
423         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" */
424 
425         btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
426             TRUE, BTM_SEC_PROTO_HID,
427             (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
428             &hidh_sec_check_complete_orig, p_dev);
429     }
430     else
431     {
432         p_hcon->conn_state = HID_CONN_STATE_CONFIG;
433         /* Send a Configuration Request. */
434         L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
435         HIDH_TRACE_EVENT ("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
436     }
437 
438     return;
439 }
440 
441 /*******************************************************************************
442 **
443 ** Function         hidh_l2cif_config_ind
444 **
445 ** Description      This function processes the L2CAP configuration indication
446 **                  event.
447 **
448 ** Returns          void
449 **
450 *******************************************************************************/
hidh_l2cif_config_ind(UINT16 l2cap_cid,tL2CAP_CFG_INFO * p_cfg)451 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
452 {
453     UINT8 dhandle;
454     tHID_CONN    *p_hcon = NULL;
455     UINT32  reason;
456 
457     /* Find CCB based on CID */
458     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
459     {
460         p_hcon = &hh_cb.devices[dhandle].conn;
461     }
462 
463     if (p_hcon == NULL)
464     {
465         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
466         return;
467     }
468 
469     HIDH_TRACE_EVENT ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
470 
471     /* Remember the remote MTU size */
472     if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
473         p_hcon->rem_mtu_size = HID_HOST_MTU;
474     else
475         p_hcon->rem_mtu_size = p_cfg->mtu;
476 
477     /* For now, always accept configuration from the other side */
478     p_cfg->flush_to_present = FALSE;
479     p_cfg->mtu_present      = FALSE;
480     p_cfg->result           = L2CAP_CFG_OK;
481 
482     L2CA_ConfigRsp (l2cap_cid, p_cfg);
483 
484     if (l2cap_cid == p_hcon->ctrl_cid)
485     {
486         p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
487         if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
488            (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE))
489         {
490             /* Connect interrupt channel */
491             p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;	/* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
492             if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
493             {
494                 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
495                 reason = HID_L2CAP_REQ_FAIL ;
496                 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
497                 hidh_conn_disconnect (dhandle);
498                 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
499                 return;
500             }
501             else
502             {
503                 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
504                 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
505             }
506         }
507     }
508     else
509         p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
510 
511     /* If all configuration is complete, change state and tell management we are up */
512     if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
513      && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
514     {
515         p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
516         /* Reset disconnect reason to success, as connection successful */
517         p_hcon->disc_reason = HID_SUCCESS;
518 
519         hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
520         hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
521     }
522 }
523 
524 
525 /*******************************************************************************
526 **
527 ** Function         hidh_l2cif_config_cfm
528 **
529 ** Description      This function processes the L2CAP configuration confirmation
530 **                  event.
531 **
532 ** Returns          void
533 **
534 *******************************************************************************/
hidh_l2cif_config_cfm(UINT16 l2cap_cid,tL2CAP_CFG_INFO * p_cfg)535 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
536 {
537     UINT8 dhandle;
538     tHID_CONN    *p_hcon = NULL;
539     UINT32  reason;
540 
541     HIDH_TRACE_EVENT ("HID-Host Rcvd cfg cfm, CID: 0x%x  Result: %d", l2cap_cid, p_cfg->result);
542 
543     /* Find CCB based on CID */
544     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
545         p_hcon = &hh_cb.devices[dhandle].conn;
546 
547     if (p_hcon == NULL)
548     {
549         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
550         return;
551     }
552 
553     /* If configuration failed, disconnect the channel(s) */
554     if (p_cfg->result != L2CAP_CFG_OK)
555     {
556         hidh_conn_disconnect (dhandle);
557         reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
558         hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
559         return;
560     }
561 
562     if (l2cap_cid == p_hcon->ctrl_cid)
563     {
564         p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
565         if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
566            (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE))
567         {
568             /* Connect interrupt channel */
569             p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;  /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
570             if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
571             {
572                 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
573                 reason = HID_L2CAP_REQ_FAIL ;
574                 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
575                 hidh_conn_disconnect (dhandle);
576                 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
577                 return;
578             }
579             else
580             {
581                 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
582                 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
583             }
584         }
585     }
586     else
587         p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
588 
589     /* If all configuration is complete, change state and tell management we are up */
590     if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
591      && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
592     {
593         p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
594         /* Reset disconnect reason to success, as connection successful */
595         p_hcon->disc_reason = HID_SUCCESS;
596 
597         hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
598         hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
599     }
600 }
601 
602 
603 /*******************************************************************************
604 **
605 ** Function         hidh_l2cif_disconnect_ind
606 **
607 ** Description      This function handles a disconnect event from L2CAP. If
608 **                  requested to, we ack the disconnect before dropping the CCB
609 **
610 ** Returns          void
611 **
612 *******************************************************************************/
hidh_l2cif_disconnect_ind(UINT16 l2cap_cid,BOOLEAN ack_needed)613 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
614 {
615     UINT8 dhandle;
616     tHID_CONN    *p_hcon = NULL;
617     UINT16 disc_res = HCI_SUCCESS;
618     UINT16 hid_close_evt_reason;
619 
620     /* Find CCB based on CID */
621     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
622         p_hcon = &hh_cb.devices[dhandle].conn;
623 
624     if (p_hcon == NULL)
625     {
626         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
627         return;
628     }
629 
630     if (ack_needed)
631         L2CA_DisconnectRsp (l2cap_cid);
632 
633     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
634 
635     p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
636 
637     if (l2cap_cid == p_hcon->ctrl_cid)
638         p_hcon->ctrl_cid = 0;
639     else
640         p_hcon->intr_cid = 0;
641 
642     if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
643     {
644         hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
645         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
646 
647         if( !ack_needed )
648             disc_res = btm_get_acl_disc_reason_code();
649 
650 #if (HID_HOST_MAX_CONN_RETRY > 0)
651         if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
652             (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
653             (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
654         {
655             hh_cb.devices[dhandle].conn_tries = 0;
656             hh_cb.devices[dhandle].conn.timer_entry.param = (UINT32) dhandle;
657             btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
658             hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL);
659         }
660         else
661 #endif
662         {
663             /* Set reason code for HID_HDEV_EVT_CLOSE */
664             hid_close_evt_reason = p_hcon->disc_reason;
665 
666             /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */
667             if ((disc_res == HCI_ERR_AUTH_FAILURE)                        ||
668                 (disc_res == HCI_ERR_KEY_MISSING)                         ||
669                 (disc_res == HCI_ERR_HOST_REJECT_SECURITY)                ||
670                 (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED)                 ||
671                 (disc_res == HCI_ERR_UNIT_KEY_USED)                       ||
672                 (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
673                 (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE)           ||
674                 (disc_res == HCI_ERR_REPEATED_ATTEMPTS))
675             {
676                 hid_close_evt_reason = HID_ERR_AUTH_FAILED;
677             }
678 
679             hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
680         }
681     }
682 }
683 
684 
685 /*******************************************************************************
686 **
687 ** Function         hidh_l2cif_disconnect_cfm
688 **
689 ** Description      This function handles a disconnect confirm event from L2CAP.
690 **
691 ** Returns          void
692 **
693 *******************************************************************************/
hidh_l2cif_disconnect_cfm(UINT16 l2cap_cid,UINT16 result)694 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
695 {
696     UINT8 dhandle;
697     tHID_CONN    *p_hcon = NULL;
698     UNUSED(result);
699 
700     /* Find CCB based on CID */
701     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
702         p_hcon = &hh_cb.devices[dhandle].conn;
703 
704     if (p_hcon == NULL)
705     {
706         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
707         return;
708     }
709 
710     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
711 
712     if (l2cap_cid == p_hcon->ctrl_cid)
713         p_hcon->ctrl_cid = 0;
714     else
715     {
716         p_hcon->intr_cid = 0;
717         if (p_hcon->ctrl_cid)
718         {
719             HIDH_TRACE_EVENT ("HID-Host Initiating L2CAP Ctrl disconnection");
720             L2CA_DisconnectReq (p_hcon->ctrl_cid);
721         }
722     }
723 
724     if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
725     {
726         hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
727         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
728         hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
729     }
730 }
731 
732 
733 /*******************************************************************************
734 **
735 ** Function         hidh_l2cif_cong_ind
736 **
737 ** Description      This function handles a congestion status event from L2CAP.
738 **
739 ** Returns          void
740 **
741 *******************************************************************************/
hidh_l2cif_cong_ind(UINT16 l2cap_cid,BOOLEAN congested)742 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
743 {
744     UINT8 dhandle;
745     tHID_CONN    *p_hcon = NULL;
746 
747     /* Find CCB based on CID */
748     if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
749         p_hcon = &hh_cb.devices[dhandle].conn;
750 
751     if (p_hcon == NULL)
752     {
753         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
754         return;
755     }
756 
757     HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x  Cong: %d", l2cap_cid, congested);
758 
759     if (congested)
760         p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
761     else
762     {
763         p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
764 
765     }
766 }
767 
768 
769 /*******************************************************************************
770 **
771 ** Function         hidh_l2cif_data_ind
772 **
773 ** Description      This function is called when data is received from L2CAP.
774 **                  if we are the originator of the connection, we are the SDP
775 **                  client, and the received message is queued up for the client.
776 **
777 **                  If we are the destination of the connection, we are the SDP
778 **                  server, so the message is passed to the server processing
779 **                  function.
780 **
781 ** Returns          void
782 **
783 *******************************************************************************/
hidh_l2cif_data_ind(UINT16 l2cap_cid,BT_HDR * p_msg)784 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
785 {
786     UINT8           *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
787     UINT8           ttype, param, rep_type, evt;
788     UINT8 dhandle;
789     tHID_CONN    *p_hcon = NULL;
790 
791     HIDH_TRACE_DEBUG ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
792 
793     /* Find CCB based on CID */
794      if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
795         p_hcon = &hh_cb.devices[dhandle].conn;
796 
797     if (p_hcon == NULL)
798     {
799         HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
800         GKI_freebuf (p_msg);
801         return;
802     }
803 
804 
805     ttype    = HID_GET_TRANS_FROM_HDR(*p_data);
806     param    = HID_GET_PARAM_FROM_HDR(*p_data);
807     rep_type = param & HID_PAR_REP_TYPE_MASK;
808     p_data++;
809 
810     /* Get rid of the data type */
811     p_msg->len--;
812     p_msg->offset++;
813 
814     switch (ttype)
815     {
816     case HID_TRANS_HANDSHAKE:
817         hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
818         GKI_freebuf (p_msg);
819         break;
820 
821     case HID_TRANS_CONTROL:
822         switch (param)
823         {
824         case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
825             hidh_conn_disconnect( dhandle ) ;
826             /* Device is unplugging from us. Tell USB */
827             hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
828             break;
829 
830         default:
831             break;
832         }
833         GKI_freebuf (p_msg);
834         break;
835 
836 
837     case HID_TRANS_DATA:
838         evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
839                     HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
840         hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
841         break;
842 
843     case HID_TRANS_DATAC:
844         evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
845                     HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
846         hh_cb.callback(dhandle,  hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
847         break;
848 
849     default:
850         GKI_freebuf (p_msg);
851         break;
852     }
853 
854 }
855 
856 /*******************************************************************************
857 **
858 ** Function         hidh_conn_snd_data
859 **
860 ** Description      This function is sends out data.
861 **
862 ** Returns          tHID_STATUS
863 **
864 *******************************************************************************/
hidh_conn_snd_data(UINT8 dhandle,UINT8 trans_type,UINT8 param,UINT16 data,UINT8 report_id,BT_HDR * buf)865 tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
866                                 UINT16 data, UINT8 report_id, BT_HDR *buf)
867 {
868     tHID_CONN   *p_hcon = &hh_cb.devices[dhandle].conn;
869     BT_HDR      *p_buf;
870     UINT8       *p_out;
871     UINT16      bytes_copied;
872     BOOLEAN     seg_req = FALSE;
873     UINT16      data_size;
874     UINT16      cid;
875     UINT8       pool_id;
876     UINT8       use_data = 0 ;
877     BOOLEAN     blank_datc = FALSE;
878 
879     if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, BT_TRANSPORT_BR_EDR))
880     {
881         if (buf)
882             GKI_freebuf ((void *)buf);
883         return( HID_ERR_NO_CONNECTION );
884     }
885 
886     if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
887     {
888         if (buf)
889             GKI_freebuf ((void *)buf);
890         return( HID_ERR_CONGESTED );
891     }
892 
893     switch( trans_type )
894     {
895     case HID_TRANS_CONTROL:
896     case HID_TRANS_GET_REPORT:
897     case HID_TRANS_SET_REPORT:
898     case HID_TRANS_GET_PROTOCOL:
899     case HID_TRANS_SET_PROTOCOL:
900     case HID_TRANS_GET_IDLE:
901     case HID_TRANS_SET_IDLE:
902         cid = p_hcon->ctrl_cid;
903         pool_id = HID_CONTROL_POOL_ID;
904         break;
905     case HID_TRANS_DATA:
906         cid = p_hcon->intr_cid;
907         pool_id = HID_INTERRUPT_POOL_ID;
908         break;
909     default:
910         return (HID_ERR_INVALID_PARAM) ;
911     }
912 
913     if( trans_type == HID_TRANS_SET_IDLE )
914         use_data = 1;
915     else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
916         use_data = 2;
917 
918     do
919     {
920         if ( buf == NULL || blank_datc )
921         {
922             if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
923                 return (HID_ERR_NO_RESOURCES);
924 
925             p_buf->offset = L2CAP_MIN_OFFSET;
926             seg_req = FALSE;
927             data_size = 0;
928             bytes_copied = 0;
929             blank_datc = FALSE;
930         }
931         else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
932         {
933             if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
934                 return (HID_ERR_NO_RESOURCES);
935 
936             p_buf->offset = L2CAP_MIN_OFFSET;
937             seg_req = TRUE;
938             data_size = buf->len;
939             bytes_copied = p_hcon->rem_mtu_size - 1;
940         }
941         else
942         {
943             p_buf = buf ;
944             p_buf->offset -= 1;
945             seg_req = FALSE;
946             data_size = buf->len;
947             bytes_copied = buf->len;
948         }
949 
950         p_out         = (UINT8 *)(p_buf + 1) + p_buf->offset;
951         *p_out++      = HID_BUILD_HDR(trans_type, param);
952 
953         /* If report ID required for this device */
954         if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
955         {
956             *p_out = report_id;
957             data_size = bytes_copied = 1;
958         }
959 
960 
961         if (seg_req)
962         {
963             memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
964             buf->offset += bytes_copied;
965             buf->len -= bytes_copied;
966         }
967         else if( use_data == 1)
968         {
969             *(p_out+bytes_copied) = data & 0xff;
970         }
971         else if( use_data == 2 )
972         {
973             *(p_out+bytes_copied) = data & 0xff;
974             *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
975         }
976 
977         p_buf->len   = bytes_copied + 1 + use_data;
978         data_size    -= bytes_copied;
979 
980         /* Send the buffer through L2CAP */
981         if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
982             return (HID_ERR_CONGESTED);
983 
984         if (data_size)
985             trans_type = HID_TRANS_DATAC;
986         else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
987         {
988             trans_type = HID_TRANS_DATAC;
989             blank_datc = TRUE;
990         }
991 
992     } while ((data_size != 0) || blank_datc ) ;
993 
994     return (HID_SUCCESS);
995 }
996 /*******************************************************************************
997 **
998 ** Function         hidh_conn_initiate
999 **
1000 ** Description      This function is called by the management to create a connection.
1001 **
1002 ** Returns          void
1003 **
1004 *******************************************************************************/
hidh_conn_initiate(UINT8 dhandle)1005 tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
1006 {
1007     UINT8   service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
1008     UINT32  mx_chan_id = HID_NOSEC_CHN;
1009 
1010     tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
1011 
1012     if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
1013         return( HID_ERR_CONN_IN_PROCESS );
1014 
1015     p_dev->conn.ctrl_cid = 0;
1016     p_dev->conn.intr_cid = 0;
1017     p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;  /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
1018 
1019     /* We are the originator of this connection */
1020     p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
1021 
1022     if(p_dev->attr_mask & HID_SEC_REQUIRED)
1023     {
1024         service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
1025         mx_chan_id = HID_SEC_CHN;
1026     }
1027     BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
1028 
1029     /* Check if L2CAP started the connection process */
1030     if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
1031     {
1032         HIDH_TRACE_WARNING ("HID-Host Originate failed");
1033         hh_cb.callback( dhandle,  hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
1034                                 HID_ERR_L2CAP_FAILED, NULL ) ;
1035     }
1036     else
1037     {
1038         /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
1039         p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
1040     }
1041 
1042     return( HID_SUCCESS );
1043 }
1044 
1045 
1046 /*******************************************************************************
1047 **
1048 ** Function         find_conn_by_cid
1049 **
1050 ** Description      This function finds a connection control block based on CID
1051 **
1052 ** Returns          address of control block, or NULL if not found
1053 **
1054 *******************************************************************************/
find_conn_by_cid(UINT16 cid)1055 static UINT8 find_conn_by_cid (UINT16 cid)
1056 {
1057     UINT8      xx;
1058 
1059     for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
1060     {
1061         if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
1062             && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
1063             break;
1064     }
1065 
1066     return (xx);
1067 }
1068 
hidh_conn_dereg(void)1069 void hidh_conn_dereg( void )
1070 {
1071     L2CA_Deregister (HID_PSM_CONTROL);
1072     L2CA_Deregister (HID_PSM_INTERRUPT);
1073 }
1074 
1075 /*******************************************************************************
1076 **
1077 ** Function         hidh_conn_retry
1078 **
1079 ** Description      This function is called to retry a failed connection.
1080 **
1081 ** Returns          void
1082 **
1083 *******************************************************************************/
hidh_conn_retry(UINT8 dhandle)1084 static void hidh_conn_retry(  UINT8 dhandle )
1085 {
1086     tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
1087 
1088     p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
1089     p_dev->conn.timer_entry.param = (UINT32) dhandle;
1090 #if (HID_HOST_REPAGE_WIN > 0)
1091     btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
1092 #else
1093     hidh_proc_repage_timeout( &(p_dev->conn.timer_entry) );
1094 #endif
1095 }
1096