1 /******************************************************************************
3 * Copyright (C) 2002-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * this file contains the connection interface functions
23 ******************************************************************************/
46 static UINT8 find_conn_by_cid (UINT16 cid);
47 static void hidh_conn_retry (UINT8 dhandle);
49 /********************************************************************************/
50 /* L O C A L F U N C T I O N P R O T O T Y P E S */
51 /********************************************************************************/
52 static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid,
53 UINT16 psm, UINT8 l2cap_id);
54 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
55 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
56 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
57 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
58 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
59 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
60 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
62 static const tL2CAP_APPL_INFO hst_reg_info =
64 hidh_l2cif_connect_ind,
65 hidh_l2cif_connect_cfm,
67 hidh_l2cif_config_ind,
68 hidh_l2cif_config_cfm,
69 hidh_l2cif_disconnect_ind,
70 hidh_l2cif_disconnect_cfm,
74 NULL /* tL2CA_TX_COMPLETE_CB */
77 /*******************************************************************************
79 ** Function hidh_l2cif_reg
81 ** Description This function initializes the SDP unit.
85 *******************************************************************************/
86 tHID_STATUS hidh_conn_reg (void)
90 /* Initialize the L2CAP configuration. We only care about MTU and flush */
91 memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
93 hh_cb.l2cap_cfg.mtu_present = TRUE;
94 hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
95 hh_cb.l2cap_cfg.flush_to_present = TRUE;
96 hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
98 /* Now, register with L2CAP */
99 if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info))
101 HIDH_TRACE_ERROR ("HID-Host Control Registration failed");
102 return (HID_ERR_L2CAP_FAILED) ;
104 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) ;
111 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
113 hh_cb.devices[xx].in_use = FALSE ;
114 hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
117 return (HID_SUCCESS);
120 /*******************************************************************************
122 ** Function hidh_conn_disconnect
124 ** Description This function disconnects a connection.
126 ** Returns TRUE if disconnect started, FALSE if already disconnected
128 *******************************************************************************/
129 tHID_STATUS hidh_conn_disconnect (UINT8 dhandle)
131 tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
133 HIDH_TRACE_EVENT ("HID-Host disconnect");
135 if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
137 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
139 /* Set l2cap idle timeout to 0 (so ACL link is disconnected
140 * immediately after last channel is closed) */
141 L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, BT_TRANSPORT_BR_EDR);
142 /* Disconnect both interrupt and control channels */
143 if (p_hcon->intr_cid)
144 L2CA_DisconnectReq (p_hcon->intr_cid);
145 else if (p_hcon->ctrl_cid)
146 L2CA_DisconnectReq (p_hcon->ctrl_cid);
150 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
153 return (HID_SUCCESS);
156 /*******************************************************************************
158 ** Function hidh_sec_check_complete_term
160 ** Description HID security check complete callback function.
162 ** Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
163 ** send security block L2C connection response.
165 *******************************************************************************/
166 void hidh_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
168 tHID_HOST_DEV_CTB *p_dev= (tHID_HOST_DEV_CTB *) p_ref_data;
172 if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
174 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
176 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
178 /* Send response to the L2CAP layer. */
179 L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
181 /* Send a Configuration Request. */
182 L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
185 /* security check fail */
186 else if (res != BTM_SUCCESS)
188 p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
189 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
190 L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
194 /*******************************************************************************
196 ** Function hidh_l2cif_connect_ind
198 ** Description This function handles an inbound connection indication
199 ** from L2CAP. This is the case where we are acting as a
204 *******************************************************************************/
205 static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
208 BOOLEAN bAccept = TRUE;
209 UINT8 i = HID_HOST_MAX_DEVICES;
210 tHID_HOST_DEV_CTB *p_dev;
212 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, l2cap_cid);
214 /* always add incoming connection device into HID database by default */
215 if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS)
217 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
221 p_hcon = &hh_cb.devices[i].conn;
222 p_dev = &hh_cb.devices[i];
224 /* Check we are in the correct state for this */
225 if (psm == HID_PSM_INTERRUPT)
227 if (p_hcon->ctrl_cid == 0)
229 HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
232 if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
234 HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
239 else /* CTRL channel */
241 #if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
242 p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
243 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
245 if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
247 HIDH_TRACE_WARNING ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
256 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
260 if (psm == HID_PSM_CONTROL)
262 p_hcon->conn_flags = 0;
263 p_hcon->ctrl_cid = l2cap_cid;
264 p_hcon->ctrl_id = l2cap_id;
265 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to 'connection failure' */
267 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
268 if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
269 FALSE, BTM_SEC_PROTO_HID,
270 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
271 &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
273 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
279 /* Transition to the next appropriate state, configuration */
280 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
281 p_hcon->intr_cid = l2cap_cid;
283 /* Send response to the L2CAP layer. */
284 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
286 /* Send a Configuration Request. */
287 L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
289 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x",
293 /*******************************************************************************
295 ** Function hidh_proc_repage_timeout
297 ** Description This function handles timeout (to page device).
301 *******************************************************************************/
302 void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle)
304 hidh_conn_initiate( (UINT8) p_tle->param ) ;
305 hh_cb.devices[p_tle->param].conn_tries++;
306 hh_cb.callback( (UINT8) p_tle->param, hh_cb.devices[p_tle->param].addr,
307 HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
310 /*******************************************************************************
312 ** Function hidh_sec_check_complete_orig
314 ** Description This function checks to see if security procedures are being
315 ** carried out or not..
319 *******************************************************************************/
320 void hidh_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
322 tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
328 dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB);
329 if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
331 HIDH_TRACE_EVENT ("HID-Host Originator security pass.");
332 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
334 /* Transition to the next appropriate state, configuration */
335 p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
336 L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
337 HIDH_TRACE_EVENT ("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x", p_dev->conn.ctrl_cid);
341 if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
343 #if (HID_HOST_MAX_CONN_RETRY > 0)
344 if( res == BTM_DEVICE_TIMEOUT )
346 if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
348 hidh_conn_retry (dhandle);
353 p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
354 hidh_conn_disconnect(dhandle);
359 /*******************************************************************************
361 ** Function hidh_l2cif_connect_cfm
363 ** Description This function handles the connect confirm events
364 ** from L2CAP. This is the case when we are acting as a
365 ** client and have sent a connect request.
369 *******************************************************************************/
370 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
373 tHID_CONN *p_hcon = NULL;
375 tHID_HOST_DEV_CTB *p_dev = NULL;
377 /* Find CCB based on CID, and verify we are in a state to accept this message */
378 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
380 p_dev = &hh_cb.devices[dhandle];
381 p_hcon = &hh_cb.devices[dhandle].conn;
385 || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
386 || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
387 || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
388 && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING)))
390 HIDH_TRACE_WARNING ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
394 if (result != L2CAP_CONN_OK)
396 if (l2cap_cid == p_hcon->ctrl_cid)
397 p_hcon->ctrl_cid = 0;
399 p_hcon->intr_cid = 0;
401 hidh_conn_disconnect(dhandle);
403 #if (HID_HOST_MAX_CONN_RETRY > 0)
404 if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
405 (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
406 result == HCI_ERR_PAGE_TIMEOUT) )
408 hidh_conn_retry(dhandle);
413 reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
414 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
418 /* receive Control Channel connect confirmation */
419 if (l2cap_cid == p_hcon->ctrl_cid)
421 /* check security requirement */
422 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
423 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs before security is completed, then set CLOSE_EVT reason code to "connection failure" */
425 btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
426 TRUE, BTM_SEC_PROTO_HID,
427 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
428 &hidh_sec_check_complete_orig, p_dev);
432 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
433 /* Send a Configuration Request. */
434 L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
435 HIDH_TRACE_EVENT ("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
441 /*******************************************************************************
443 ** Function hidh_l2cif_config_ind
445 ** Description This function processes the L2CAP configuration indication
450 *******************************************************************************/
451 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
454 tHID_CONN *p_hcon = NULL;
457 /* Find CCB based on CID */
458 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
460 p_hcon = &hh_cb.devices[dhandle].conn;
465 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
469 HIDH_TRACE_EVENT ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
471 /* Remember the remote MTU size */
472 if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
473 p_hcon->rem_mtu_size = HID_HOST_MTU;
475 p_hcon->rem_mtu_size = p_cfg->mtu;
477 /* For now, always accept configuration from the other side */
478 p_cfg->flush_to_present = FALSE;
479 p_cfg->mtu_present = FALSE;
480 p_cfg->result = L2CAP_CFG_OK;
482 L2CA_ConfigRsp (l2cap_cid, p_cfg);
484 if (l2cap_cid == p_hcon->ctrl_cid)
486 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
487 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
488 (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE))
490 /* Connect interrupt channel */
491 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
492 if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
494 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
495 reason = HID_L2CAP_REQ_FAIL ;
496 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
497 hidh_conn_disconnect (dhandle);
498 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
503 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
504 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
509 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
511 /* If all configuration is complete, change state and tell management we are up */
512 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
513 && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
515 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
516 /* Reset disconnect reason to success, as connection successful */
517 p_hcon->disc_reason = HID_SUCCESS;
519 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
520 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
525 /*******************************************************************************
527 ** Function hidh_l2cif_config_cfm
529 ** Description This function processes the L2CAP configuration confirmation
534 *******************************************************************************/
535 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
538 tHID_CONN *p_hcon = NULL;
541 HIDH_TRACE_EVENT ("HID-Host Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
543 /* Find CCB based on CID */
544 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
545 p_hcon = &hh_cb.devices[dhandle].conn;
549 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
553 /* If configuration failed, disconnect the channel(s) */
554 if (p_cfg->result != L2CAP_CFG_OK)
556 hidh_conn_disconnect (dhandle);
557 reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
558 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
562 if (l2cap_cid == p_hcon->ctrl_cid)
564 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
565 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
566 (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE))
568 /* Connect interrupt channel */
569 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
570 if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
572 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
573 reason = HID_L2CAP_REQ_FAIL ;
574 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
575 hidh_conn_disconnect (dhandle);
576 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
581 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
582 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
587 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
589 /* If all configuration is complete, change state and tell management we are up */
590 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
591 && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
593 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
594 /* Reset disconnect reason to success, as connection successful */
595 p_hcon->disc_reason = HID_SUCCESS;
597 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
598 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
603 /*******************************************************************************
605 ** Function hidh_l2cif_disconnect_ind
607 ** Description This function handles a disconnect event from L2CAP. If
608 ** requested to, we ack the disconnect before dropping the CCB
612 *******************************************************************************/
613 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
616 tHID_CONN *p_hcon = NULL;
617 UINT16 disc_res = HCI_SUCCESS;
618 UINT16 hid_close_evt_reason;
620 /* Find CCB based on CID */
621 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
622 p_hcon = &hh_cb.devices[dhandle].conn;
626 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
631 L2CA_DisconnectRsp (l2cap_cid);
633 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
635 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
637 if (l2cap_cid == p_hcon->ctrl_cid)
638 p_hcon->ctrl_cid = 0;
640 p_hcon->intr_cid = 0;
642 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
644 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
645 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
648 disc_res = btm_get_acl_disc_reason_code();
650 #if (HID_HOST_MAX_CONN_RETRY > 0)
651 if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
652 (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
653 (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
655 hh_cb.devices[dhandle].conn_tries = 0;
656 hh_cb.devices[dhandle].conn.timer_entry.param = (UINT32) dhandle;
657 btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
658 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL);
663 /* Set reason code for HID_HDEV_EVT_CLOSE */
664 hid_close_evt_reason = p_hcon->disc_reason;
666 /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */
667 if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
668 (disc_res == HCI_ERR_KEY_MISSING) ||
669 (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
670 (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
671 (disc_res == HCI_ERR_UNIT_KEY_USED) ||
672 (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
673 (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
674 (disc_res == HCI_ERR_REPEATED_ATTEMPTS))
676 hid_close_evt_reason = HID_ERR_AUTH_FAILED;
679 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
685 /*******************************************************************************
687 ** Function hidh_l2cif_disconnect_cfm
689 ** Description This function handles a disconnect confirm event from L2CAP.
693 *******************************************************************************/
694 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
697 tHID_CONN *p_hcon = NULL;
700 /* Find CCB based on CID */
701 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
702 p_hcon = &hh_cb.devices[dhandle].conn;
706 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
710 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
712 if (l2cap_cid == p_hcon->ctrl_cid)
713 p_hcon->ctrl_cid = 0;
716 p_hcon->intr_cid = 0;
717 if (p_hcon->ctrl_cid)
719 HIDH_TRACE_EVENT ("HID-Host Initiating L2CAP Ctrl disconnection");
720 L2CA_DisconnectReq (p_hcon->ctrl_cid);
724 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
726 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
727 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
728 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
733 /*******************************************************************************
735 ** Function hidh_l2cif_cong_ind
737 ** Description This function handles a congestion status event from L2CAP.
741 *******************************************************************************/
742 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
745 tHID_CONN *p_hcon = NULL;
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;
753 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
757 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", l2cap_cid, congested);
760 p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
763 p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
769 /*******************************************************************************
771 ** Function hidh_l2cif_data_ind
773 ** Description This function is called when data is received from L2CAP.
774 ** if we are the originator of the connection, we are the SDP
775 ** client, and the received message is queued up for the client.
777 ** If we are the destination of the connection, we are the SDP
778 ** server, so the message is passed to the server processing
783 *******************************************************************************/
784 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
786 UINT8 *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
787 UINT8 ttype, param, rep_type, evt;
789 tHID_CONN *p_hcon = NULL;
791 HIDH_TRACE_DEBUG ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
793 /* Find CCB based on CID */
794 if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
795 p_hcon = &hh_cb.devices[dhandle].conn;
799 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
805 ttype = HID_GET_TRANS_FROM_HDR(*p_data);
806 param = HID_GET_PARAM_FROM_HDR(*p_data);
807 rep_type = param & HID_PAR_REP_TYPE_MASK;
810 /* Get rid of the data type */
816 case HID_TRANS_HANDSHAKE:
817 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
821 case HID_TRANS_CONTROL:
824 case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
825 hidh_conn_disconnect( dhandle ) ;
826 /* Device is unplugging from us. Tell USB */
827 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
838 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
839 HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
840 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
843 case HID_TRANS_DATAC:
844 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
845 HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
846 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
856 /*******************************************************************************
858 ** Function hidh_conn_snd_data
860 ** Description This function is sends out data.
862 ** Returns tHID_STATUS
864 *******************************************************************************/
865 tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
866 UINT16 data, UINT8 report_id, BT_HDR *buf)
868 tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
872 BOOLEAN seg_req = FALSE;
877 BOOLEAN blank_datc = FALSE;
879 if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, BT_TRANSPORT_BR_EDR))
882 GKI_freebuf ((void *)buf);
883 return( HID_ERR_NO_CONNECTION );
886 if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
889 GKI_freebuf ((void *)buf);
890 return( HID_ERR_CONGESTED );
895 case HID_TRANS_CONTROL:
896 case HID_TRANS_GET_REPORT:
897 case HID_TRANS_SET_REPORT:
898 case HID_TRANS_GET_PROTOCOL:
899 case HID_TRANS_SET_PROTOCOL:
900 case HID_TRANS_GET_IDLE:
901 case HID_TRANS_SET_IDLE:
902 cid = p_hcon->ctrl_cid;
903 pool_id = HID_CONTROL_POOL_ID;
906 cid = p_hcon->intr_cid;
907 pool_id = HID_INTERRUPT_POOL_ID;
910 return (HID_ERR_INVALID_PARAM) ;
913 if( trans_type == HID_TRANS_SET_IDLE )
915 else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
920 if ( buf == NULL || blank_datc )
922 if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
923 return (HID_ERR_NO_RESOURCES);
925 p_buf->offset = L2CAP_MIN_OFFSET;
931 else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
933 if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
934 return (HID_ERR_NO_RESOURCES);
936 p_buf->offset = L2CAP_MIN_OFFSET;
938 data_size = buf->len;
939 bytes_copied = p_hcon->rem_mtu_size - 1;
946 data_size = buf->len;
947 bytes_copied = buf->len;
950 p_out = (UINT8 *)(p_buf + 1) + p_buf->offset;
951 *p_out++ = HID_BUILD_HDR(trans_type, param);
953 /* If report ID required for this device */
954 if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
957 data_size = bytes_copied = 1;
963 memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
964 buf->offset += bytes_copied;
965 buf->len -= bytes_copied;
967 else if( use_data == 1)
969 *(p_out+bytes_copied) = data & 0xff;
971 else if( use_data == 2 )
973 *(p_out+bytes_copied) = data & 0xff;
974 *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
977 p_buf->len = bytes_copied + 1 + use_data;
978 data_size -= bytes_copied;
980 /* Send the buffer through L2CAP */
981 if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
982 return (HID_ERR_CONGESTED);
985 trans_type = HID_TRANS_DATAC;
986 else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
988 trans_type = HID_TRANS_DATAC;
992 } while ((data_size != 0) || blank_datc ) ;
994 return (HID_SUCCESS);
996 /*******************************************************************************
998 ** Function hidh_conn_initiate
1000 ** Description This function is called by the management to create a connection.
1004 *******************************************************************************/
1005 tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
1007 UINT8 service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
1008 UINT32 mx_chan_id = HID_NOSEC_CHN;
1010 tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
1012 if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
1013 return( HID_ERR_CONN_IN_PROCESS );
1015 p_dev->conn.ctrl_cid = 0;
1016 p_dev->conn.intr_cid = 0;
1017 p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
1019 /* We are the originator of this connection */
1020 p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
1022 if(p_dev->attr_mask & HID_SEC_REQUIRED)
1024 service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
1025 mx_chan_id = HID_SEC_CHN;
1027 BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
1029 /* Check if L2CAP started the connection process */
1030 if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
1032 HIDH_TRACE_WARNING ("HID-Host Originate failed");
1033 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
1034 HID_ERR_L2CAP_FAILED, NULL ) ;
1038 /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
1039 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
1042 return( HID_SUCCESS );
1046 /*******************************************************************************
1048 ** Function find_conn_by_cid
1050 ** Description This function finds a connection control block based on CID
1052 ** Returns address of control block, or NULL if not found
1054 *******************************************************************************/
1055 static UINT8 find_conn_by_cid (UINT16 cid)
1059 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
1061 if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
1062 && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
1069 void hidh_conn_dereg( void )
1071 L2CA_Deregister (HID_PSM_CONTROL);
1072 L2CA_Deregister (HID_PSM_INTERRUPT);
1075 /*******************************************************************************
1077 ** Function hidh_conn_retry
1079 ** Description This function is called to retry a failed connection.
1083 *******************************************************************************/
1084 static void hidh_conn_retry( UINT8 dhandle )
1086 tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
1088 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
1089 p_dev->conn.timer_entry.param = (UINT32) dhandle;
1090 #if (HID_HOST_REPAGE_WIN > 0)
1091 btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
1093 hidh_proc_repage_timeout( &(p_dev->conn.timer_entry) );