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