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