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