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