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 *
21 * This file contains the HID HOST API entry points
22 *
23 ******************************************************************************/
24
25 #define LOG_TAG "hidh"
26
27 #include "hidh_api.h"
28
29 #include <bluetooth/log.h>
30 #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "hiddefs.h"
35 #include "hidh_int.h"
36 #include "internal_include/bt_target.h"
37 #include "os/log.h"
38 #include "osi/include/allocator.h"
39 #include "stack/include/bt_hdr.h"
40 #include "stack/include/bt_uuid16.h"
41 #include "stack/include/sdpdefs.h"
42 #include "stack/include/stack_metrics_logging.h"
43 #include "types/bluetooth/uuid.h"
44 #include "types/raw_address.h"
45
46 using namespace bluetooth;
47 using namespace bluetooth::legacy::stack::sdp;
48 using bluetooth::Uuid;
49
50 tHID_HOST_CTB hh_cb;
51
52 static void hidh_search_callback(const RawAddress& bd_addr,
53 tSDP_RESULT sdp_result);
54
55 /*******************************************************************************
56 *
57 * Function HID_HostGetSDPRecord
58 *
59 * Description This function reads the device SDP record
60 *
61 * Returns tHID_STATUS
62 *
63 ******************************************************************************/
HID_HostGetSDPRecord(const RawAddress & addr,tSDP_DISCOVERY_DB * p_db,uint32_t db_len,tHID_HOST_SDP_CALLBACK * sdp_cback)64 tHID_STATUS HID_HostGetSDPRecord(const RawAddress& addr,
65 tSDP_DISCOVERY_DB* p_db, uint32_t db_len,
66 tHID_HOST_SDP_CALLBACK* sdp_cback) {
67 if (hh_cb.sdp_busy) {
68 log_counter_metrics(
69 android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_SDP_BUSY, 1);
70 return HID_ERR_SDP_BUSY;
71 }
72
73 hh_cb.p_sdp_db = p_db;
74 Uuid uuid_list = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
75 if (!get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb(
76 p_db, db_len, 1, &uuid_list, 0, NULL)) {
77 log::warn("Unable to initialize SDP service discovery db peer:{}", addr);
78 };
79
80 if (get_legacy_stack_sdp_api()->service.SDP_ServiceSearchRequest(
81 addr, p_db, hidh_search_callback)) {
82 hh_cb.sdp_cback = sdp_cback;
83 hh_cb.sdp_busy = true;
84 return HID_SUCCESS;
85 } else {
86 log::warn("Unable to start SDP service search request peer:{}", addr);
87 log_counter_metrics(
88 android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_NO_RESOURCES_SDP,
89 1);
90 return HID_ERR_NO_RESOURCES;
91 }
92 }
93
hidh_get_str_attr(tSDP_DISC_REC * p_rec,uint16_t attr_id,uint16_t max_len,char * str)94 void hidh_get_str_attr(tSDP_DISC_REC* p_rec, uint16_t attr_id, uint16_t max_len,
95 char* str) {
96 tSDP_DISC_ATTR* p_attr;
97 uint16_t name_len;
98
99 p_attr =
100 get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(p_rec, attr_id);
101 if (p_attr != NULL) {
102 if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == TEXT_STR_DESC_TYPE) {
103 name_len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
104 if (name_len < max_len) {
105 memcpy(str, (char*)p_attr->attr_value.v.array, name_len);
106 str[name_len] = '\0';
107 } else {
108 memcpy(str, (char*)p_attr->attr_value.v.array, max_len - 1);
109 str[max_len - 1] = '\0';
110 }
111 } else {
112 str[0] = '\0';
113 log::error("attr type not str!!");
114 }
115 } else
116 str[0] = '\0';
117 }
118
hidh_search_callback(const RawAddress &,tSDP_RESULT sdp_result)119 static void hidh_search_callback(const RawAddress& /* bd_addr */,
120 tSDP_RESULT sdp_result) {
121 tSDP_DISCOVERY_DB* p_db = hh_cb.p_sdp_db;
122 tSDP_DISC_REC* p_rec;
123 tSDP_DISC_ATTR *p_attr, *p_subattr1, *p_subattr2, *p_repdesc;
124 tHID_DEV_SDP_INFO* p_nvi = &hh_cb.sdp_rec;
125 uint16_t attr_mask = 0;
126
127
128 hh_cb.sdp_busy = false;
129
130 if (sdp_result != SDP_SUCCESS) {
131 hh_cb.sdp_cback(sdp_result, 0, NULL);
132 return;
133 }
134
135 Uuid hid_uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
136 p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceUUIDInDb(p_db, hid_uuid,
137 NULL);
138 if (p_rec == NULL) {
139 hh_cb.sdp_cback(HID_SDP_NO_SERV_UUID, 0, NULL);
140 return;
141 }
142
143 memset(&hh_cb.sdp_rec, 0, sizeof(tHID_DEV_SDP_INFO));
144
145 /* First, verify the mandatory fields we care about */
146 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
147 p_rec, ATTR_ID_HID_DESCRIPTOR_LIST)) == NULL) ||
148 (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) ||
149 ((p_subattr1 = p_attr->attr_value.v.p_sub_attr) == NULL) ||
150 (SDP_DISC_ATTR_TYPE(p_subattr1->attr_len_type) !=
151 DATA_ELE_SEQ_DESC_TYPE) ||
152 ((p_subattr2 = p_subattr1->attr_value.v.p_sub_attr) == NULL) ||
153 ((p_repdesc = p_subattr2->p_next_attr) == NULL) ||
154 (SDP_DISC_ATTR_TYPE(p_repdesc->attr_len_type) != TEXT_STR_DESC_TYPE)) {
155 hh_cb.sdp_cback(HID_SDP_MANDATORY_MISSING, 0, NULL);
156 return;
157 }
158
159 p_nvi->dscp_info.dl_len = SDP_DISC_ATTR_LEN(p_repdesc->attr_len_type);
160 if (p_nvi->dscp_info.dl_len != 0)
161 p_nvi->dscp_info.dsc_list = (uint8_t*)&p_repdesc->attr_value;
162
163 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
164 p_rec, ATTR_ID_HID_VIRTUAL_CABLE)) != NULL) &&
165 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE &&
166 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 &&
167 (p_attr->attr_value.v.u8)) {
168 attr_mask |= HID_VIRTUAL_CABLE;
169 }
170
171 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
172 p_rec, ATTR_ID_HID_RECONNECT_INITIATE)) != NULL) &&
173 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE &&
174 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 &&
175 (p_attr->attr_value.v.u8)) {
176 attr_mask |= HID_RECONN_INIT;
177 }
178
179 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
180 p_rec, ATTR_ID_HID_NORMALLY_CONNECTABLE)) != NULL) &&
181 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE &&
182 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 &&
183 (p_attr->attr_value.v.u8)) {
184 attr_mask |= HID_NORMALLY_CONNECTABLE;
185 }
186
187 // this attribute is deprecated, should we still keep it?
188 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
189 p_rec, ATTR_ID_HID_SDP_DISABLE)) != NULL) &&
190 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE &&
191 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 &&
192 (p_attr->attr_value.v.u8)) {
193 attr_mask |= HID_SDP_DISABLE;
194 }
195
196 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
197 p_rec, ATTR_ID_HID_BATTERY_POWER)) != NULL) &&
198 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE &&
199 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 &&
200 (p_attr->attr_value.v.u8)) {
201 attr_mask |= HID_BATTERY_POWER;
202 }
203
204 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
205 p_rec, ATTR_ID_HID_REMOTE_WAKE)) != NULL) &&
206 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == BOOLEAN_DESC_TYPE &&
207 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1 &&
208 (p_attr->attr_value.v.u8)) {
209 attr_mask |= HID_REMOTE_WAKE;
210 }
211
212 hidh_get_str_attr(p_rec, ATTR_ID_SERVICE_NAME, HID_MAX_SVC_NAME_LEN,
213 p_nvi->svc_name);
214 hidh_get_str_attr(p_rec, ATTR_ID_SERVICE_DESCRIPTION, HID_MAX_SVC_DESCR_LEN,
215 p_nvi->svc_descr);
216 hidh_get_str_attr(p_rec, ATTR_ID_PROVIDER_NAME, HID_MAX_PROV_NAME_LEN,
217 p_nvi->prov_name);
218
219 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
220 p_rec, ATTR_ID_HID_DEVICE_RELNUM)) != NULL) &&
221 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
222 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) {
223 p_nvi->rel_num = p_attr->attr_value.v.u16;
224 }
225
226 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
227 p_rec, ATTR_ID_HID_COUNTRY_CODE)) != NULL) &&
228 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
229 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) {
230 p_nvi->ctry_code = p_attr->attr_value.v.u8;
231 }
232
233 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
234 p_rec, ATTR_ID_HID_DEVICE_SUBCLASS)) != NULL) &&
235 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
236 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 1) {
237 p_nvi->sub_class = p_attr->attr_value.v.u8;
238 }
239
240 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
241 p_rec, ATTR_ID_HID_PARSER_VERSION)) != NULL) &&
242 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
243 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) {
244 p_nvi->hpars_ver = p_attr->attr_value.v.u16;
245 }
246
247 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
248 p_rec, ATTR_ID_HID_LINK_SUPERVISION_TO)) != NULL) &&
249 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
250 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) {
251 attr_mask |= HID_SUP_TOUT_AVLBL;
252 p_nvi->sup_timeout = p_attr->attr_value.v.u16;
253 }
254
255 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
256 p_rec, ATTR_ID_HID_SSR_HOST_MAX_LAT)) != NULL) &&
257 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
258 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) {
259 attr_mask |= HID_SSR_MAX_LATENCY;
260 p_nvi->ssr_max_latency = p_attr->attr_value.v.u16;
261 } else
262 p_nvi->ssr_max_latency = HID_SSR_PARAM_INVALID;
263
264 if (((p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
265 p_rec, ATTR_ID_HID_SSR_HOST_MIN_TOUT)) != NULL) &&
266 SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
267 SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) {
268 attr_mask |= HID_SSR_MIN_TOUT;
269 p_nvi->ssr_min_tout = p_attr->attr_value.v.u16;
270 } else
271 p_nvi->ssr_min_tout = HID_SSR_PARAM_INVALID;
272
273 hh_cb.sdp_rec.p_sdp_layer_rec = p_rec;
274 hh_cb.sdp_cback(SDP_SUCCESS, attr_mask, &hh_cb.sdp_rec);
275 }
276
277 /*******************************************************************************
278 *
279 * Function HID_HostInit
280 *
281 * Description This function initializes the control block and trace
282 * variable
283 *
284 * Returns void
285 *
286 ******************************************************************************/
HID_HostInit(void)287 void HID_HostInit(void) {
288 memset(&hh_cb, 0, sizeof(tHID_HOST_CTB));
289 }
290
291 /*******************************************************************************
292 *
293 * Function HID_HostRegister
294 *
295 * Description This function registers HID-Host with lower layers
296 *
297 * Returns tHID_STATUS
298 *
299 ******************************************************************************/
HID_HostRegister(tHID_HOST_DEV_CALLBACK * dev_cback)300 tHID_STATUS HID_HostRegister(tHID_HOST_DEV_CALLBACK* dev_cback) {
301 tHID_STATUS st;
302
303 if (hh_cb.reg_flag) {
304 log_counter_metrics(
305 android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_ALREADY_REGISTERED,
306 1);
307 return HID_ERR_ALREADY_REGISTERED;
308 }
309
310 if (dev_cback == NULL) {
311 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
312 HIDH_ERR_INVALID_PARAM_AT_HOST_REGISTER,
313 1);
314 return HID_ERR_INVALID_PARAM;
315 }
316
317 /* Register with L2CAP */
318 st = hidh_conn_reg();
319 if (st != HID_SUCCESS) {
320 return st;
321 }
322
323 hh_cb.callback = dev_cback;
324 hh_cb.reg_flag = true;
325
326 for (size_t i = 0; i < HID_HOST_MAX_DEVICES; i++) {
327 hh_cb.devices[i].conn.process_repage_timer =
328 alarm_new("hid_devices_conn.process_repage_timer");
329 }
330 return (HID_SUCCESS);
331 }
332
333 /*******************************************************************************
334 *
335 * Function HID_HostDeregister
336 *
337 * Description This function is called when the host is about power down.
338 *
339 * Returns tHID_STATUS
340 *
341 ******************************************************************************/
HID_HostDeregister(void)342 tHID_STATUS HID_HostDeregister(void) {
343 uint8_t i;
344
345 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
346
347 for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
348 HID_HostRemoveDev(i);
349 alarm_free(hh_cb.devices[i].conn.process_repage_timer);
350 hh_cb.devices[i].conn.process_repage_timer = NULL;
351 }
352
353 hidh_conn_dereg();
354 hh_cb.reg_flag = false;
355
356 return (HID_SUCCESS);
357 }
358
359 /*******************************************************************************
360 *
361 * Function HID_HostSDPDisable
362 *
363 * Description This is called to check if the device has the HIDSDPDisable
364 * attribute.
365 *
366 * Returns bool
367 *
368 ******************************************************************************/
HID_HostSDPDisable(const RawAddress & addr)369 bool HID_HostSDPDisable(const RawAddress& addr) {
370 for (int i = 0; i < HID_HOST_MAX_DEVICES; i++) {
371 if (hh_cb.devices[i].in_use && (hh_cb.devices[i].addr == addr)) {
372 return (hh_cb.devices[i].attr_mask & HID_SDP_DISABLE);
373 }
374 }
375 return false;
376 }
377
378 /*******************************************************************************
379 *
380 * Function HID_HostAddDev
381 *
382 * Description This is called so HID-host may manage this device.
383 *
384 * Returns tHID_STATUS
385 *
386 ******************************************************************************/
HID_HostAddDev(const RawAddress & addr,uint16_t attr_mask,uint8_t * handle)387 tHID_STATUS HID_HostAddDev(const RawAddress& addr, uint16_t attr_mask,
388 uint8_t* handle) {
389 int i;
390 /* Find an entry for this device in hh_cb.devices array */
391 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
392
393 for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
394 if ((hh_cb.devices[i].in_use) && addr == hh_cb.devices[i].addr) break;
395 }
396
397 if (i == HID_HOST_MAX_DEVICES) {
398 for (i = 0; i < HID_HOST_MAX_DEVICES; i++) {
399 if (!hh_cb.devices[i].in_use) break;
400 }
401 }
402
403 if (i == HID_HOST_MAX_DEVICES) {
404 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
405 HIDH_ERR_NO_RESOURCES_ADD_DEVICE,
406 1);
407 return HID_ERR_NO_RESOURCES;
408 }
409
410 if (!hh_cb.devices[i].in_use) {
411 hh_cb.devices[i].in_use = true;
412 hh_cb.devices[i].addr = addr;
413 hh_cb.devices[i].state = HID_DEV_NO_CONN;
414 hh_cb.devices[i].conn_tries = 0;
415 }
416
417 hh_cb.devices[i].attr_mask = attr_mask;
418
419 *handle = i;
420
421 return (HID_SUCCESS);
422 }
423
424 /*******************************************************************************
425 *
426 * Function HID_HostRemoveDev
427 *
428 * Description This removes the device from the list of devices that the
429 * host has to manage.
430 *
431 * Returns tHID_STATUS
432 *
433 ******************************************************************************/
HID_HostRemoveDev(uint8_t dev_handle)434 tHID_STATUS HID_HostRemoveDev(uint8_t dev_handle) {
435 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
436
437 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
438 (!hh_cb.devices[dev_handle].in_use)) {
439 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
440 HIDH_ERR_INVALID_PARAM_AT_HOST_REMOVE_DEV,
441 1);
442 return HID_ERR_INVALID_PARAM;
443 }
444
445 HID_HostCloseDev(dev_handle);
446 hh_cb.devices[dev_handle].in_use = false;
447 hh_cb.devices[dev_handle].conn.conn_state = HID_CONN_STATE_UNUSED;
448 hh_cb.devices[dev_handle].conn.ctrl_cid =
449 hh_cb.devices[dev_handle].conn.intr_cid = 0;
450 hh_cb.devices[dev_handle].attr_mask = 0;
451 return HID_SUCCESS;
452 }
453
454 /*******************************************************************************
455 *
456 * Function HID_HostOpenDev
457 *
458 * Description This function is called when the user wants to initiate a
459 * connection attempt to a device.
460 *
461 * Returns void
462 *
463 ******************************************************************************/
HID_HostOpenDev(uint8_t dev_handle)464 tHID_STATUS HID_HostOpenDev(uint8_t dev_handle) {
465 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
466
467 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
468 (!hh_cb.devices[dev_handle].in_use)) {
469 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
470 HIDH_ERR_INVALID_PARAM_AT_HOST_OPEN_DEV,
471 1);
472 return HID_ERR_INVALID_PARAM;
473 }
474
475 if (hh_cb.devices[dev_handle].state != HID_DEV_NO_CONN) {
476 log_counter_metrics(
477 android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_ALREADY_CONN, 1);
478 return HID_ERR_ALREADY_CONN;
479 }
480
481 hh_cb.devices[dev_handle].conn_tries = 1;
482 return hidh_conn_initiate(dev_handle);
483 }
484
485 /*******************************************************************************
486 *
487 * Function HID_HostWriteDev
488 *
489 * Description This function is called when the host has a report to send.
490 *
491 * report_id: is only used on GET_REPORT transaction if is
492 * specified. only valid when it is non-zero.
493 *
494 * Returns void
495 *
496 ******************************************************************************/
HID_HostWriteDev(uint8_t dev_handle,uint8_t t_type,uint8_t param,uint16_t data,uint8_t report_id,BT_HDR * pbuf)497 tHID_STATUS HID_HostWriteDev(uint8_t dev_handle, uint8_t t_type, uint8_t param,
498 uint16_t data, uint8_t report_id, BT_HDR* pbuf) {
499 tHID_STATUS status = HID_SUCCESS;
500
501 if (!hh_cb.reg_flag) {
502 log::error("HID_ERR_NOT_REGISTERED");
503 status = HID_ERR_NOT_REGISTERED;
504 }
505
506 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
507 (!hh_cb.devices[dev_handle].in_use)) {
508 log::error("HID_ERR_INVALID_PARAM");
509 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
510 HIDH_ERR_INVALID_PARAM_AT_HOST_WRITE_DEV,
511 1);
512 status = HID_ERR_INVALID_PARAM;
513 }
514
515 else if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) {
516 log::error("HID_ERR_NO_CONNECTION dev_handle {}", dev_handle);
517 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
518 HIDH_ERR_NO_CONNECTION_AT_HOST_WRITE_DEV,
519 1);
520 status = HID_ERR_NO_CONNECTION;
521 }
522
523 if (status != HID_SUCCESS)
524 osi_free(pbuf);
525 else
526 status =
527 hidh_conn_snd_data(dev_handle, t_type, param, data, report_id, pbuf);
528
529 return status;
530 }
531
532 /*******************************************************************************
533 *
534 * Function HID_HostCloseDev
535 *
536 * Description This function disconnects the device.
537 *
538 * Returns void
539 *
540 ******************************************************************************/
HID_HostCloseDev(uint8_t dev_handle)541 tHID_STATUS HID_HostCloseDev(uint8_t dev_handle) {
542 if (!hh_cb.reg_flag) return (HID_ERR_NOT_REGISTERED);
543
544 if ((dev_handle >= HID_HOST_MAX_DEVICES) ||
545 (!hh_cb.devices[dev_handle].in_use)) {
546 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
547 HIDH_ERR_INVALID_PARAM_AT_HOST_CLOSE_DEV,
548 1);
549 return HID_ERR_INVALID_PARAM;
550 }
551
552 if (hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED) {
553 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
554 HIDH_ERR_NO_CONNECTION_AT_HOST_CLOSE_DEV,
555 1);
556 return HID_ERR_NO_CONNECTION;
557 }
558
559 alarm_cancel(hh_cb.devices[dev_handle].conn.process_repage_timer);
560 hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY + 1;
561 return hidh_conn_disconnect(dev_handle);
562 }
563