hidh_conn.cc 37 KB

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