1 /****************************************************************************** 2 * 3 * Copyright (C) 2016 The Android Open Source Project 4 * Copyright (C) 2002-2012 Broadcom Corporation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 ******************************************************************************/ 19 20 /****************************************************************************** 21 * 22 * This file contains the HID Device API entry points 23 * 24 ******************************************************************************/ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include "bt_types.h" 31 #include "btm_api.h" 32 #include "btu.h" 33 #include "hidd_api.h" 34 #include "hidd_int.h" 35 #include "hiddefs.h" 36 37 #if HID_DYNAMIC_MEMORY == FALSE 38 tHID_DEV_CTB hd_cb; 39 #endif 40 41 /******************************************************************************* 42 * 43 * Function HID_DevInit 44 * 45 * Description Initializes control block 46 * 47 * Returns void 48 * 49 ******************************************************************************/ 50 void HID_DevInit(void) { 51 uint8_t log_level = hd_cb.trace_level; 52 53 HIDD_TRACE_API("%s", __func__); 54 55 memset(&hd_cb, 0, sizeof(tHID_DEV_CTB)); 56 hd_cb.trace_level = log_level; 57 } 58 59 /******************************************************************************* 60 * 61 * Function HID_DevSetTraceLevel 62 * 63 * Description This function sets the trace level for HID Dev. If called 64 *with 65 * a value of 0xFF, it simply reads the current trace level. 66 * 67 * Returns the new (current) trace level 68 * 69 ******************************************************************************/ 70 uint8_t HID_DevSetTraceLevel(uint8_t new_level) { 71 if (new_level != 0xFF) hd_cb.trace_level = new_level; 72 73 return (hd_cb.trace_level); 74 } 75 76 /******************************************************************************* 77 * 78 * Function HID_DevRegister 79 * 80 * Description Registers HID device with lower layers 81 * 82 * Returns tHID_STATUS 83 * 84 ******************************************************************************/ 85 tHID_STATUS HID_DevRegister(tHID_DEV_HOST_CALLBACK* host_cback) { 86 tHID_STATUS st; 87 88 HIDD_TRACE_API("%s", __func__); 89 90 if (hd_cb.reg_flag) return HID_ERR_ALREADY_REGISTERED; 91 92 if (host_cback == NULL) return HID_ERR_INVALID_PARAM; 93 94 /* Register with L2CAP */ 95 st = hidd_conn_reg(); 96 if (st != HID_SUCCESS) return st; 97 98 hd_cb.callback = host_cback; 99 hd_cb.reg_flag = TRUE; 100 101 if (hd_cb.pending_data) { 102 osi_free(hd_cb.pending_data); 103 hd_cb.pending_data = NULL; 104 } 105 106 return (HID_SUCCESS); 107 } 108 109 /******************************************************************************* 110 * 111 * Function HID_DevDeregister 112 * 113 * Description Deregisters HID device with lower layers 114 * 115 * Returns tHID_STATUS 116 * 117 ******************************************************************************/ 118 tHID_STATUS HID_DevDeregister(void) { 119 HIDD_TRACE_API("%s", __func__); 120 121 if (!hd_cb.reg_flag) return (HID_ERR_NOT_REGISTERED); 122 123 hidd_conn_dereg(); 124 125 hd_cb.reg_flag = FALSE; 126 127 return (HID_SUCCESS); 128 } 129 130 tHID_STATUS HID_DevSetSecurityLevel(uint8_t sec_lvl) { 131 HIDD_TRACE_API("%s", __func__); 132 133 if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl, 134 HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) { 135 HIDD_TRACE_ERROR("Security Registration 1 failed"); 136 return (HID_ERR_NO_RESOURCES); 137 } 138 139 if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_SEC_CTRL, sec_lvl, 140 HID_PSM_CONTROL, BTM_SEC_PROTO_HID, HIDD_SEC_CHN)) { 141 HIDD_TRACE_ERROR("Security Registration 2 failed"); 142 return (HID_ERR_NO_RESOURCES); 143 } 144 145 if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL, 146 BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, 147 HIDD_NOSEC_CHN)) { 148 HIDD_TRACE_ERROR("Security Registration 3 failed"); 149 return (HID_ERR_NO_RESOURCES); 150 } 151 152 if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_NOSEC_CTRL, 153 BTM_SEC_NONE, HID_PSM_CONTROL, BTM_SEC_PROTO_HID, 154 HIDD_NOSEC_CHN)) { 155 HIDD_TRACE_ERROR("Security Registration 4 failed"); 156 return (HID_ERR_NO_RESOURCES); 157 } 158 159 if (!BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE, 160 HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) { 161 HIDD_TRACE_ERROR("Security Registration 5 failed"); 162 return (HID_ERR_NO_RESOURCES); 163 } 164 165 if (!BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HIDD_INTR, BTM_SEC_NONE, 166 HID_PSM_INTERRUPT, BTM_SEC_PROTO_HID, 0)) { 167 HIDD_TRACE_ERROR("Security Registration 6 failed"); 168 return (HID_ERR_NO_RESOURCES); 169 } 170 171 return (HID_SUCCESS); 172 } 173 174 /******************************************************************************* 175 * 176 * Function HID_DevAddRecord 177 * 178 * Description Creates SDP record for HID device 179 * 180 * Returns tHID_STATUS 181 * 182 ******************************************************************************/ 183 tHID_STATUS HID_DevAddRecord(uint32_t handle, char* p_name, char* p_description, 184 char* p_provider, uint16_t subclass, 185 uint16_t desc_len, uint8_t* p_desc_data) { 186 bool result = TRUE; 187 188 HIDD_TRACE_API("%s", __func__); 189 190 // Service Class ID List 191 if (result) { 192 uint16_t uuid = UUID_SERVCLASS_HUMAN_INTERFACE; 193 result &= SDP_AddServiceClassIdList(handle, 1, &uuid); 194 } 195 196 // Protocol Descriptor List 197 if (result) { 198 tSDP_PROTOCOL_ELEM proto_list[2]; 199 200 proto_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 201 proto_list[0].num_params = 1; 202 proto_list[0].params[0] = BT_PSM_HIDC; 203 204 proto_list[1].protocol_uuid = UUID_PROTOCOL_HIDP; 205 proto_list[1].num_params = 0; 206 207 result &= SDP_AddProtocolList(handle, 2, proto_list); 208 } 209 210 // Language Base Attribute ID List 211 if (result) { 212 result &= SDP_AddLanguageBaseAttrIDList(handle, LANG_ID_CODE_ENGLISH, 213 LANG_ID_CHAR_ENCODE_UTF8, 214 LANGUAGE_BASE_ID); 215 } 216 217 // Additional Protocol Descriptor List 218 if (result) { 219 tSDP_PROTO_LIST_ELEM add_proto_list; 220 221 add_proto_list.num_elems = 2; 222 add_proto_list.list_elem[0].protocol_uuid = UUID_PROTOCOL_L2CAP; 223 add_proto_list.list_elem[0].num_params = 1; 224 add_proto_list.list_elem[0].params[0] = BT_PSM_HIDI; 225 add_proto_list.list_elem[1].protocol_uuid = UUID_PROTOCOL_HIDP; 226 add_proto_list.list_elem[1].num_params = 0; 227 228 result &= SDP_AddAdditionProtoLists(handle, 1, &add_proto_list); 229 } 230 231 // Service Name (O) 232 // Service Description (O) 233 // Provider Name (O) 234 if (result) { 235 const char* srv_name = p_name; 236 const char* srv_desc = p_description; 237 const char* provider_name = p_provider; 238 239 result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE, 240 strlen(srv_name) + 1, (uint8_t*)srv_name); 241 242 result &= SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION, 243 TEXT_STR_DESC_TYPE, strlen(srv_desc) + 1, 244 (uint8_t*)srv_desc); 245 246 result &= 247 SDP_AddAttribute(handle, ATTR_ID_PROVIDER_NAME, TEXT_STR_DESC_TYPE, 248 strlen(provider_name) + 1, (uint8_t*)provider_name); 249 } 250 251 // Bluetooth Profile Descriptor List 252 if (result) { 253 const uint16_t profile_uuid = UUID_SERVCLASS_HUMAN_INTERFACE; 254 const uint16_t version = 0x0100; 255 256 result &= SDP_AddProfileDescriptorList(handle, profile_uuid, version); 257 } 258 259 // HID Parser Version 260 if (result) { 261 uint8_t* p; 262 const uint16_t rel_num = 0x0100; 263 const uint16_t parser_version = 0x0111; 264 const uint16_t prof_ver = 0x0100; 265 const uint8_t dev_subclass = subclass; 266 const uint8_t country_code = 0x21; 267 const uint8_t bool_false = 0x00; 268 const uint8_t bool_true = 0x01; 269 uint16_t temp; 270 271 p = (uint8_t*)&temp; 272 UINT16_TO_BE_STREAM(p, rel_num); 273 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_RELNUM, 274 UINT_DESC_TYPE, 2, (uint8_t*)&temp); 275 276 p = (uint8_t*)&temp; 277 UINT16_TO_BE_STREAM(p, parser_version); 278 result &= SDP_AddAttribute(handle, ATTR_ID_HID_PARSER_VERSION, 279 UINT_DESC_TYPE, 2, (uint8_t*)&temp); 280 281 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DEVICE_SUBCLASS, 282 UINT_DESC_TYPE, 1, (uint8_t*)&dev_subclass); 283 284 result &= SDP_AddAttribute(handle, ATTR_ID_HID_COUNTRY_CODE, UINT_DESC_TYPE, 285 1, (uint8_t*)&country_code); 286 287 result &= SDP_AddAttribute(handle, ATTR_ID_HID_VIRTUAL_CABLE, 288 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); 289 290 result &= SDP_AddAttribute(handle, ATTR_ID_HID_RECONNECT_INITIATE, 291 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); 292 293 { 294 static uint8_t cdt = 0x22; 295 uint8_t* p_buf; 296 uint8_t seq_len = 4 + desc_len; 297 298 p_buf = (uint8_t*)osi_malloc(2048); 299 300 if (p_buf == NULL) { 301 HIDD_TRACE_ERROR("%s: Buffer allocation failure for size = 2048 ", 302 __func__); 303 return HID_ERR_NOT_REGISTERED; 304 } 305 306 p = p_buf; 307 308 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 309 310 UINT8_TO_BE_STREAM(p, seq_len); 311 312 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_ONE_BYTE); 313 UINT8_TO_BE_STREAM(p, cdt); 314 315 UINT8_TO_BE_STREAM(p, (TEXT_STR_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 316 UINT8_TO_BE_STREAM(p, desc_len); 317 ARRAY_TO_BE_STREAM(p, p_desc_data, (int)desc_len); 318 319 result &= SDP_AddAttribute(handle, ATTR_ID_HID_DESCRIPTOR_LIST, 320 DATA_ELE_SEQ_DESC_TYPE, p - p_buf, p_buf); 321 322 osi_free(p_buf); 323 } 324 325 { 326 uint8_t lang_buf[8]; 327 p = lang_buf; 328 uint8_t seq_len = 6; 329 uint16_t lang_english = 0x0409; 330 UINT8_TO_BE_STREAM(p, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE); 331 UINT8_TO_BE_STREAM(p, seq_len); 332 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 333 UINT16_TO_BE_STREAM(p, lang_english); 334 UINT8_TO_BE_STREAM(p, (UINT_DESC_TYPE << 3) | SIZE_TWO_BYTES); 335 UINT16_TO_BE_STREAM(p, LANGUAGE_BASE_ID); 336 result &= 337 SDP_AddAttribute(handle, ATTR_ID_HID_LANGUAGE_ID_BASE, 338 DATA_ELE_SEQ_DESC_TYPE, p - lang_buf, lang_buf); 339 } 340 341 result &= SDP_AddAttribute(handle, ATTR_ID_HID_BATTERY_POWER, 342 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); 343 344 result &= SDP_AddAttribute(handle, ATTR_ID_HID_REMOTE_WAKE, 345 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_false); 346 347 result &= SDP_AddAttribute(handle, ATTR_ID_HID_NORMALLY_CONNECTABLE, 348 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); 349 350 result &= SDP_AddAttribute(handle, ATTR_ID_HID_BOOT_DEVICE, 351 BOOLEAN_DESC_TYPE, 1, (uint8_t*)&bool_true); 352 353 p = (uint8_t*)&temp; 354 UINT16_TO_BE_STREAM(p, prof_ver); 355 result &= SDP_AddAttribute(handle, ATTR_ID_HID_PROFILE_VERSION, 356 UINT_DESC_TYPE, 2, (uint8_t*)&temp); 357 } 358 359 if (result) { 360 uint16_t browse_group = UUID_SERVCLASS_PUBLIC_BROWSE_GROUP; 361 result &= SDP_AddUuidSequence(handle, ATTR_ID_BROWSE_GROUP_LIST, 1, 362 &browse_group); 363 } 364 365 if (!result) { 366 HIDD_TRACE_ERROR("%s: failed to complete SDP record", __func__); 367 368 return HID_ERR_NOT_REGISTERED; 369 } 370 371 return HID_SUCCESS; 372 } 373 374 /******************************************************************************* 375 * 376 * Function HID_DevSendReport 377 * 378 * Description Sends report 379 * 380 * Returns tHID_STATUS 381 * 382 ******************************************************************************/ 383 tHID_STATUS HID_DevSendReport(uint8_t channel, uint8_t type, uint8_t id, 384 uint16_t len, uint8_t* p_data) { 385 HIDD_TRACE_VERBOSE("%s: channel=%d type=%d id=%d len=%d", __func__, channel, 386 type, id, len); 387 388 if (channel == HID_CHANNEL_CTRL) { 389 return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, type, id, len, 390 p_data); 391 } 392 393 if (channel == HID_CHANNEL_INTR && type == HID_PAR_REP_TYPE_INPUT) { 394 // on INTR we can only send INPUT 395 return hidd_conn_send_data(HID_CHANNEL_INTR, HID_TRANS_DATA, 396 HID_PAR_REP_TYPE_INPUT, id, len, p_data); 397 } 398 399 return HID_ERR_INVALID_PARAM; 400 } 401 402 /******************************************************************************* 403 * 404 * Function HID_DevVirtualCableUnplug 405 * 406 * Description Sends Virtual Cable Unplug 407 * 408 * Returns tHID_STATUS 409 * 410 ******************************************************************************/ 411 tHID_STATUS HID_DevVirtualCableUnplug(void) { 412 HIDD_TRACE_API("%s", __func__); 413 414 return hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_CONTROL, 415 HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG, 0, 0, NULL); 416 } 417 418 /******************************************************************************* 419 * 420 * Function HID_DevPlugDevice 421 * 422 * Description Establishes virtual cable to given host 423 * 424 * Returns tHID_STATUS 425 * 426 ******************************************************************************/ 427 tHID_STATUS HID_DevPlugDevice(BD_ADDR addr) { 428 hd_cb.device.in_use = TRUE; 429 memcpy(hd_cb.device.addr, addr, sizeof(BD_ADDR)); 430 431 return HID_SUCCESS; 432 } 433 434 /******************************************************************************* 435 * 436 * Function HID_DevUnplugDevice 437 * 438 * Description Unplugs virtual cable from given host 439 * 440 * Returns tHID_STATUS 441 * 442 ******************************************************************************/ 443 tHID_STATUS HID_DevUnplugDevice(BD_ADDR addr) { 444 if (!memcmp(hd_cb.device.addr, addr, sizeof(BD_ADDR))) { 445 hd_cb.device.in_use = FALSE; 446 hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED; 447 hd_cb.device.conn.ctrl_cid = 0; 448 hd_cb.device.conn.intr_cid = 0; 449 } 450 451 return HID_SUCCESS; 452 } 453 454 /******************************************************************************* 455 * 456 * Function HID_DevConnect 457 * 458 * Description Connects to device 459 * 460 * Returns tHID_STATUS 461 * 462 ******************************************************************************/ 463 tHID_STATUS HID_DevConnect(void) { 464 if (!hd_cb.reg_flag) { 465 return HID_ERR_NOT_REGISTERED; 466 } 467 468 if (!hd_cb.device.in_use) { 469 return HID_ERR_INVALID_PARAM; 470 } 471 472 if (hd_cb.device.state != HIDD_DEV_NO_CONN) { 473 return HID_ERR_ALREADY_CONN; 474 } 475 476 return hidd_conn_initiate(); 477 } 478 479 /******************************************************************************* 480 * 481 * Function HID_DevDisconnect 482 * 483 * Description Disconnects from device 484 * 485 * Returns tHID_STATUS 486 * 487 ******************************************************************************/ 488 tHID_STATUS HID_DevDisconnect(void) { 489 if (!hd_cb.reg_flag) { 490 return HID_ERR_NOT_REGISTERED; 491 } 492 493 if (!hd_cb.device.in_use) { 494 return HID_ERR_INVALID_PARAM; 495 } 496 497 if (hd_cb.device.state == HIDD_DEV_NO_CONN) { 498 /* If we are still trying to connect, just close the connection. */ 499 if (hd_cb.device.conn.conn_state != HID_CONN_STATE_UNUSED) { 500 tHID_STATUS ret = hidd_conn_disconnect(); 501 hd_cb.device.conn.conn_state = HID_CONN_STATE_UNUSED; 502 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, 503 HID_ERR_DISCONNECTING, NULL); 504 return ret; 505 } 506 return HID_ERR_NO_CONNECTION; 507 } 508 509 return hidd_conn_disconnect(); 510 } 511 512 /******************************************************************************* 513 * 514 * Function HID_DevSetIncomingPolicy 515 * 516 * Description Sets policy for incoming connections (allowed/disallowed) 517 * 518 * Returns tHID_STATUS 519 * 520 ******************************************************************************/ 521 tHID_STATUS HID_DevSetIncomingPolicy(bool allow) { 522 hd_cb.allow_incoming = allow; 523 524 return HID_SUCCESS; 525 } 526 527 /******************************************************************************* 528 * 529 * Function HID_DevReportError 530 * 531 * Description Reports error for Set Report via HANDSHAKE 532 * 533 * Returns tHID_STATUS 534 * 535 ******************************************************************************/ 536 tHID_STATUS HID_DevReportError(uint8_t error) { 537 uint8_t handshake_param; 538 539 HIDD_TRACE_API("%s: error = %d", __func__, error); 540 541 switch (error) { 542 case HID_PAR_HANDSHAKE_RSP_SUCCESS: 543 case HID_PAR_HANDSHAKE_RSP_NOT_READY: 544 case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID: 545 case HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ: 546 case HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM: 547 case HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN: 548 case HID_PAR_HANDSHAKE_RSP_ERR_FATAL: 549 handshake_param = error; 550 break; 551 default: 552 handshake_param = HID_PAR_HANDSHAKE_RSP_ERR_UNKNOWN; 553 break; 554 } 555 556 return hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, handshake_param, 0, 0, 557 NULL); 558 } 559 560 /******************************************************************************* 561 * 562 * Function HID_DevGetDevice 563 * 564 * Description Returns the BD Address of virtually cabled device 565 * 566 * Returns tHID_STATUS 567 * 568 ******************************************************************************/ 569 tHID_STATUS HID_DevGetDevice(BD_ADDR* addr) { 570 HIDD_TRACE_API("%s", __func__); 571 572 if (hd_cb.device.in_use) { 573 memcpy(addr, hd_cb.device.addr, sizeof(BD_ADDR)); 574 } else { 575 return HID_ERR_NOT_REGISTERED; 576 } 577 578 return HID_SUCCESS; 579 } 580 581 /******************************************************************************* 582 * 583 * Function HID_DevSetIncomingQos 584 * 585 * Description Sets Incoming QoS values for Interrupt L2CAP Channel 586 * 587 * Returns tHID_STATUS 588 * 589 ******************************************************************************/ 590 tHID_STATUS HID_DevSetIncomingQos(uint8_t service_type, uint32_t token_rate, 591 uint32_t token_bucket_size, 592 uint32_t peak_bandwidth, uint32_t latency, 593 uint32_t delay_variation) { 594 HIDD_TRACE_API("%s", __func__); 595 596 hd_cb.use_in_qos = TRUE; 597 598 hd_cb.in_qos.service_type = service_type; 599 hd_cb.in_qos.token_rate = token_rate; 600 hd_cb.in_qos.token_bucket_size = token_bucket_size; 601 hd_cb.in_qos.peak_bandwidth = peak_bandwidth; 602 hd_cb.in_qos.latency = latency; 603 hd_cb.in_qos.delay_variation = delay_variation; 604 605 return HID_SUCCESS; 606 } 607 608 /******************************************************************************* 609 * 610 * Function HID_DevSetOutgoingQos 611 * 612 * Description Sets Outgoing QoS values for Interrupt L2CAP Channel 613 * 614 * Returns tHID_STATUS 615 * 616 ******************************************************************************/ 617 tHID_STATUS HID_DevSetOutgoingQos(uint8_t service_type, uint32_t token_rate, 618 uint32_t token_bucket_size, 619 uint32_t peak_bandwidth, uint32_t latency, 620 uint32_t delay_variation) { 621 HIDD_TRACE_API("%s", __func__); 622 623 hd_cb.l2cap_intr_cfg.qos_present = TRUE; 624 625 hd_cb.l2cap_intr_cfg.qos.service_type = service_type; 626 hd_cb.l2cap_intr_cfg.qos.token_rate = token_rate; 627 hd_cb.l2cap_intr_cfg.qos.token_bucket_size = token_bucket_size; 628 hd_cb.l2cap_intr_cfg.qos.peak_bandwidth = peak_bandwidth; 629 hd_cb.l2cap_intr_cfg.qos.latency = latency; 630 hd_cb.l2cap_intr_cfg.qos.delay_variation = delay_variation; 631 632 return HID_SUCCESS; 633 } 634